diff --git a/.clang-format b/.clang-format index 74975cc3c..153f0e4a3 100644 --- a/.clang-format +++ b/.clang-format @@ -84,7 +84,6 @@ PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left -QualifierAlignment: Left ReflowComments: true SortIncludes: true SortUsingDeclarations: true diff --git a/.claude/skills/reviewing-openmc-code/SKILL.md b/.claude/skills/reviewing-openmc-code/SKILL.md deleted file mode 100644 index 28b4c189b..000000000 --- a/.claude/skills/reviewing-openmc-code/SKILL.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -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 --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 ...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 diff --git a/.claude/tools/openmc_mcp_server.py b/.claude/tools/openmc_mcp_server.py deleted file mode 100644 index 37917abc1..000000000 --- a/.claude/tools/openmc_mcp_server.py +++ /dev/null @@ -1,250 +0,0 @@ -#!/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() diff --git a/.claude/tools/rag/chunker.py b/.claude/tools/rag/chunker.py deleted file mode 100644 index b28ddb0f8..000000000 --- a/.claude/tools/rag/chunker.py +++ /dev/null @@ -1,105 +0,0 @@ -"""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 diff --git a/.claude/tools/rag/embeddings.py b/.claude/tools/rag/embeddings.py deleted file mode 100644 index 1fe85b50d..000000000 --- a/.claude/tools/rag/embeddings.py +++ /dev/null @@ -1,120 +0,0 @@ -"""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() diff --git a/.claude/tools/rag/indexer.py b/.claude/tools/rag/indexer.py deleted file mode 100644 index 34613092b..000000000 --- a/.claude/tools/rag/indexer.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/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() diff --git a/.claude/tools/rag/openmc_search.py b/.claude/tools/rag/openmc_search.py deleted file mode 100644 index 4125ee966..000000000 --- a/.claude/tools/rag/openmc_search.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/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() diff --git a/.claude/tools/requirements.txt b/.claude/tools/requirements.txt deleted file mode 100644 index bd5d38d6c..000000000 --- a/.claude/tools/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -# MCP server -mcp>=1.0.0 - -# Vector database -lancedb>=0.15.0 - -# Embeddings (local, no API key) -sentence-transformers>=2.7.0 diff --git a/.claude/tools/start_server.sh b/.claude/tools/start_server.sh deleted file mode 100755 index c111dd73e..000000000 --- a/.claude/tools/start_server.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/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" diff --git a/.git_archival.txt b/.git_archival.txt deleted file mode 100644 index f2f118c0d..000000000 --- a/.git_archival.txt +++ /dev/null @@ -1,3 +0,0 @@ -commit: $Format:%H$ -commit-date: $Format:%cI$ -describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 82bf71c1c..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -.git_archival.txt export-subst \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 99ba77a6f..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Bug report -about: Report a bug that is preventing proper operation -title: '' -labels: Bugs -assignees: '' - ---- - - - -## Bug Description - - - -## Steps to Reproduce - - - -## Environment - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 40e40338b..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Troubleshooting and User Support - url: https://openmc.discourse.group/ - about: For user support and troubleshooting, please use our Discourse forum diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md deleted file mode 100644 index 04ecb8cf9..000000000 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Documentation improvement -about: Found something incomplete or incorrect in our documentation? -title: '' -labels: Documentation -assignees: '' - ---- - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 3b13abdbc..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Feature or enhancement request -about: Suggest a new feature or enhancement to existing capabilities -title: '' -labels: '' -assignees: '' - ---- - -## Description - - - -## Alternatives - - - -## Compatibility - diff --git a/.github/agents/Review.agent.md b/.github/agents/Review.agent.md deleted file mode 100644 index 39b2085f4..000000000 --- a/.github/agents/Review.agent.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -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. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index e1f71b83f..000000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1 +0,0 @@ -When reviewing code changes in this repository, use the `reviewing-openmc-code` skill. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 958cc21fd..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,24 +0,0 @@ - - -# Description - -Please include a summary of the change and which issue is fixed if applicable. Please also include relevant motivation and context. - -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 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) - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3da79c04..050c8e287 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Tests and Coverage +name: CI on: # allows us to run workflows manually @@ -21,64 +21,49 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: - filter-changes: - runs-on: ubuntu-latest - outputs: - source_changed: ${{ steps.filter.outputs.source_changed }} - steps: - - name: Check out the repository - uses: actions/checkout@v6 - - name: Examine changed files - id: filter - uses: dorny/paths-filter@v4 - with: - filters: | - source_changed: - - '!docs/**' - - '!**/*.md' - predicate-quantifier: 'every' main: - needs: filter-changes - if: ${{ needs.filter-changes.outputs.source_changed == 'true' }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-20.04 strategy: matrix: - python-version: ["3.12"] + python-version: [3.8] mpi: [n, y] omp: [n, y] dagmc: [n] libmesh: [n] event: [n] + vectfit: [n] include: - - python-version: "3.13" + - python-version: 3.6 omp: n mpi: n - - python-version: "3.14" - omp: n - mpi: n - - python-version: "3.14t" + - python-version: 3.7 omp: n mpi: n - dagmc: y - python-version: "3.12" + python-version: 3.8 mpi: y omp: y - libmesh: y - python-version: "3.12" + python-version: 3.8 mpi: y omp: y - libmesh: y - python-version: "3.12" + python-version: 3.8 mpi: n omp: y - event: y - python-version: "3.12" + python-version: 3.8 omp: y mpi: n + - vectfit: y + python-version: 3.8 + omp: n + mpi: y name: "Python ${{ matrix.python-version }} (omp=${{ matrix.omp }}, mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }}, - libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }}" + libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }} + vectfit=${{ matrix.vectfit }})" env: MPI: ${{ matrix.mpi }} @@ -86,62 +71,34 @@ 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 - PYTEST_ADDOPTS: --cov=openmc --cov-report=lcov:coverage-python.lcov - # libfabric complains about fork() as a result of using Python multiprocessing. - # We can work around it with RDMAV_FORK_SAFE=1 in libfabric < 1.13 and with - # FI_EFA_FORK_SAFE=1 in more recent versions. - RDMAV_FORK_SAFE: 1 steps: - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v2 - with: - cmake-version: '3.31' - - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 + - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Environment Variables run: | + echo "DAGMC_ROOT=$HOME/DAGMC" echo "OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml" >> $GITHUB_ENV echo "OPENMC_ENDF_DATA=$HOME/endf-b-vii.1" >> $GITHUB_ENV - # get the sha of the last branch commit - # for push and workflow_dispatch events, use the current reference head - BRANCH_SHA=HEAD - # for a pull_request event, use the last reference of the parents of the merge commit - if [ "${{ github.event_name }}" == "pull_request" ]; then - BRANCH_SHA=$(git rev-list --parents -n 1 HEAD | rev | cut -d" " -f 1 | rev) - fi - COMMIT_MESSAGE=$(git log $BRANCH_SHA -1 --pretty=%B | tr '\n' ' ') - echo ${COMMIT_MESSAGE} - echo "COMMIT_MESSAGE=${COMMIT_MESSAGE}" >> $GITHUB_ENV - name: Apt dependencies shell: bash run: | sudo apt -y update sudo apt install -y libpng-dev \ + libmpich-dev \ libnetcdf-dev \ libpnetcdf-dev \ libhdf5-serial-dev \ + libhdf5-mpich-dev \ libeigen3-dev - - - name: Optional apt dependencies for MPI - shell: bash - if: ${{ matrix.mpi == 'y' }} - run: | - sudo apt install -y libhdf5-mpich-dev \ - libmpich-dev sudo update-alternatives --set mpi /usr/bin/mpicc.mpich 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 @@ -152,97 +109,26 @@ jobs: echo "$HOME/NJOY2016/build" >> $GITHUB_PATH $GITHUB_WORKSPACE/tools/ci/gha-install.sh - - name: display-config - shell: bash - run: | - openmc -v - - - name: cache-xs - uses: actions/cache@v5 - with: - path: | - ~/nndc_hdf5 - ~/endf-b-vii.1 - key: ${{ runner.os }}-build-xs-cache-${{ hashFiles(format('{0}/tools/ci/download-xs.sh', github.workspace)) }} - - name: before shell: bash run: $GITHUB_WORKSPACE/tools/ci/gha-before-script.sh - name: test shell: bash - run: | - CTEST_OUTPUT_ON_FAILURE=1 make test -C $GITHUB_WORKSPACE/build/ - $GITHUB_WORKSPACE/tools/ci/gha-script.sh + run: $GITHUB_WORKSPACE/tools/ci/gha-script.sh - - name: Setup tmate debug session - continue-on-error: true - if: ${{ failure() && contains(env.COMMIT_MESSAGE, '[gha-debug]') }} - uses: mxschmitt/action-tmate@v3 - timeout-minutes: 10 - - - name: Generate C++ coverage (gcovr) + - name: after_success shell: bash run: | - # Produce LCOV directly from gcov data in the build tree - gcovr \ - --root "$GITHUB_WORKSPACE" \ - --object-directory "$GITHUB_WORKSPACE/build" \ - --filter "$GITHUB_WORKSPACE/src" \ - --filter "$GITHUB_WORKSPACE/include" \ - --exclude "$GITHUB_WORKSPACE/src/external/.*" \ - --exclude "$GITHUB_WORKSPACE/src/include/openmc/external/.*" \ - --gcov-ignore-errors source_not_found \ - --gcov-ignore-errors output_error \ - --gcov-ignore-parse-errors suspicious_hits.warn \ - --merge-mode-functions=separate \ - --print-summary \ - --lcov -o coverage-cpp.lcov || true + cpp-coveralls -i src -i include -e src/external --exclude-pattern "/usr/*" --dump cpp_cov.json + coveralls --merge=cpp_cov.json --service=github - - name: Merge C++ and Python coverage - shell: bash - run: | - # Merge C++ and Python LCOV into a single file for upload - cat coverage-cpp.lcov coverage-python.lcov > coverage.lcov - - - name: Upload coverage to Coveralls - if: ${{ hashFiles('coverage.lcov') != '' }} - uses: coverallsapp/github-action@v2 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - parallel: true - flag-name: C++ and Python - path-to-lcov: coverage.lcov - fail-on-error: false - - coverage: - needs: [filter-changes, main] - if: ${{ always() }} + finish: + needs: main runs-on: ubuntu-latest steps: - name: Coveralls Finished - if: ${{ needs.filter-changes.outputs.source_changed == 'true' }} - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@master with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.github_token }} parallel-finished: true - fail-on-error: false - - ci-pass: - needs: [filter-changes, main, coverage] - name: Check CI status - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Check CI status - run: | - if [[ "${{ needs.filter-changes.outputs.source_changed }}" == "false" ]]; then - echo "Documentation-only change - CI skipped successfully" - exit 0 - fi - if [[ "${{ needs.main.result }}" == "success" && "${{ needs.coverage.result }}" == "success" ]]; then - echo "CI passed" - exit 0 - fi - echo "CI failed" - exit 1 diff --git a/.github/workflows/dockerhub-publish-dagmc-libmesh.yml b/.github/workflows/dockerhub-publish-dagmc-libmesh.yml index e3e476150..3336c653e 100644 --- a/.github/workflows/dockerhub-publish-dagmc-libmesh.yml +++ b/.github/workflows/dockerhub-publish-dagmc-libmesh.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-latest-dagmc-libmesh on: push: - branches: - - master + branches: master jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:latest-dagmc-libmesh diff --git a/.github/workflows/dockerhub-publish-dagmc.yml b/.github/workflows/dockerhub-publish-dagmc.yml index 317cfc0e8..663e1fd17 100644 --- a/.github/workflows/dockerhub-publish-dagmc.yml +++ b/.github/workflows/dockerhub-publish-dagmc.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-latest-dagmc on: push: - branches: - - master + branches: master jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:latest-dagmc diff --git a/.github/workflows/dockerhub-publish-dev.yml b/.github/workflows/dockerhub-publish-dev.yml index 7c78c6c99..a08d13e5a 100644 --- a/.github/workflows/dockerhub-publish-dev.yml +++ b/.github/workflows/dockerhub-publish-dev.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-develop on: push: - branches: - - develop + branches: develop jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:develop diff --git a/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml b/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml index 33a3a3b06..0c90d8796 100644 --- a/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml +++ b/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-develop-dagmc-libmesh on: push: - branches: - - develop + branches: develop jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:develop-dagmc-libmesh diff --git a/.github/workflows/dockerhub-publish-develop-dagmc.yml b/.github/workflows/dockerhub-publish-develop-dagmc.yml index 1d6051a70..b98b3dff6 100644 --- a/.github/workflows/dockerhub-publish-develop-dagmc.yml +++ b/.github/workflows/dockerhub-publish-develop-dagmc.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-develop-dagmc on: push: - branches: - - develop + branches: develop jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:develop-dagmc diff --git a/.github/workflows/dockerhub-publish-develop-libmesh.yml b/.github/workflows/dockerhub-publish-develop-libmesh.yml index 2c53636bd..e42ba0b27 100644 --- a/.github/workflows/dockerhub-publish-develop-libmesh.yml +++ b/.github/workflows/dockerhub-publish-develop-libmesh.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-develop-libmesh on: push: - branches: - - develop + branches: develop jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:develop-libmesh diff --git a/.github/workflows/dockerhub-publish-libmesh.yml b/.github/workflows/dockerhub-publish-libmesh.yml index 12fbfa579..a861c5c9c 100644 --- a/.github/workflows/dockerhub-publish-libmesh.yml +++ b/.github/workflows/dockerhub-publish-libmesh.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-latest-libmesh on: push: - branches: - - master + branches: master jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:latest-libmesh diff --git a/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml b/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml index 26de24e59..b8a152aef 100644 --- a/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml +++ b/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml @@ -2,32 +2,31 @@ name: dockerhub-publish-release-dagmc-libmesh on: push: - tags: - - 'v*.*.*' + tags: 'v*.*.*' jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v2 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:${{ env.RELEASE_VERSION }}-dagmc-libmesh diff --git a/.github/workflows/dockerhub-publish-release-dagmc.yml b/.github/workflows/dockerhub-publish-release-dagmc.yml index 4a6c5ff26..927e91212 100644 --- a/.github/workflows/dockerhub-publish-release-dagmc.yml +++ b/.github/workflows/dockerhub-publish-release-dagmc.yml @@ -2,32 +2,31 @@ name: dockerhub-publish-release-dagmc on: push: - tags: - - 'v*.*.*' + tags: 'v*.*.*' jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v2 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:${{ env.RELEASE_VERSION }}-dagmc diff --git a/.github/workflows/dockerhub-publish-release-libmesh.yml b/.github/workflows/dockerhub-publish-release-libmesh.yml index f3194833f..1907eef46 100644 --- a/.github/workflows/dockerhub-publish-release-libmesh.yml +++ b/.github/workflows/dockerhub-publish-release-libmesh.yml @@ -2,32 +2,31 @@ name: dockerhub-publish-release-libmesh on: push: - tags: - - 'v*.*.*' + tags: 'v*.*.*' jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v2 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:${{ env.RELEASE_VERSION }}-libmesh diff --git a/.github/workflows/dockerhub-publish-release.yml b/.github/workflows/dockerhub-publish-release.yml index ef9faf00c..c94a50c0d 100644 --- a/.github/workflows/dockerhub-publish-release.yml +++ b/.github/workflows/dockerhub-publish-release.yml @@ -2,32 +2,31 @@ name: dockerhub-publish-release on: push: - tags: - - 'v*.*.*' + tags: 'v*.*.*' jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v2 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:${{ env.RELEASE_VERSION }} diff --git a/.github/workflows/dockerhub-publish.yml b/.github/workflows/dockerhub-publish.yml index a5c8f711b..6bd0c4dc6 100644 --- a/.github/workflows/dockerhub-publish.yml +++ b/.github/workflows/dockerhub-publish.yml @@ -2,8 +2,7 @@ name: dockerhub-publish-latest on: push: - branches: - - master + branches: master jobs: main: @@ -11,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v2 with: push: true tags: openmc/openmc:latest diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml deleted file mode 100644 index 7d7d46ed9..000000000 --- a/.github/workflows/format-check.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: C++ Format Check - -on: - # allow workflow to be run manually - workflow_dispatch: - - pull_request: - types: - - opened - - synchronize - - reopened - - labeled - - unlabeled - branches: - - develop - - master - -jobs: - cpp-linter: - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - uses: actions/checkout@v6 - - uses: cpp-linter/cpp-linter-action@v2 - id: linter - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - style: file - files-changed-only: true - tidy-checks: '-*' - 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." - echo "See job summary and file annotations for details." - exit 1 diff --git a/.gitignore b/.gitignore index 32ef7919a..3b2a24a4d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,13 +25,12 @@ examples/**/*.xml # Documentation builds docs/build -docs/doxygen/xml docs/source/_images/*.pdf docs/source/_images/*.aux docs/source/pythonapi/generated/ # Source build -build*/ +build # build from src/utils/setup.py src/utils/build @@ -105,8 +104,5 @@ CMakeSettings.json # Visual Studio Code configuration files .vscode/ -# Claude Code agent tools (cached/generated artifacts) -.claude/cache/ - # Python pickle files *.pkl diff --git a/.gitmodules b/.gitmodules index 2bc123894..ff9120010 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,15 @@ [submodule "vendor/pugixml"] path = vendor/pugixml url = https://github.com/zeux/pugixml.git +[submodule "vendor/gsl-lite"] + path = vendor/gsl-lite + url = https://github.com/martinmoene/gsl-lite.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 -[submodule "vendor/Catch2"] - path = vendor/Catch2 - url = https://github.com/catchorg/Catch2.git diff --git a/.mcp.json b/.mcp.json deleted file mode 100644 index bdfaa538e..000000000 --- a/.mcp.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "mcpServers": { - "openmc-code-tools": { - "type": "stdio", - "command": "bash", - "args": [".claude/tools/start_server.sh"] - } - } -} diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7594ed5f2..98ca8b581 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,23 +1,13 @@ version: 2 build: - os: "ubuntu-24.04" + os: "ubuntu-20.04" tools: - python: "3.12" - jobs: - post_checkout: - - git fetch --unshallow || true - - cd docs/doxygen && doxygen && cd - + python: "3.9" sphinx: configuration: docs/source/conf.py -formats: - - pdf - python: install: - - method: pip - path: . - extra_requirements: - - docs + - requirements: docs/requirements-rtd.txt diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 19abba7d9..000000000 --- a/AGENTS.md +++ /dev/null @@ -1,348 +0,0 @@ -# OpenMC AI Coding Agent Instructions - -## Project Overview - -OpenMC is a Monte Carlo particle transport code for simulating nuclear reactors, -fusion devices, or other systems with neutron/photon radiation. It's a hybrid -C++17/Python codebase where: -- **C++ core** (`src/`, `include/openmc/`) handles the computationally intensive transport simulation -- **Python API** (`openmc/`) provides user-facing model building, post-processing, and depletion capabilities -- **C API bindings** (`openmc/lib/`) wrap the C++ library via ctypes for runtime control - -## Architecture & Key Components - -### C++ Component Structure -- **Global vectors of unique_ptrs**: Core objects like `model::cells`, `model::universes`, `nuclides` are stored as `vector>` in nested namespaces (`openmc::model`, `openmc::simulation`, `openmc::settings`, `openmc::data`) -- **Custom container types**: OpenMC provides its own `vector`, `array`, `unique_ptr`, and `make_unique` in the `openmc::` namespace (defined in `vector.h`, `array.h`, `memory.h`). These are currently typedefs to `std::` equivalents but may become custom implementations for accelerator support. Always use `openmc::vector`, not `std::vector`. -- **Geometry systems**: - - **CSG (default)**: Arbitrarily complex Constructive Solid Geometry using `Surface`, `Region`, `Cell`, `Universe`, `Lattice` - - **DAGMC**: CAD-based geometry via Direct Accelerated Geometry Monte Carlo (optional, requires `OPENMC_USE_DAGMC`) - - **Unstructured mesh**: libMesh-based geometry (optional, requires `OPENMC_USE_LIBMESH`) -- **Particle tracking**: `Particle` class with `GeometryState` manages particle transport through geometry -- **Tallies**: Score quantities during simulation via `Filter` and `Tally` objects -- **Random ray solver**: Alternative deterministic method in `src/random_ray/` -- **Optional features**: DAGMC (CAD geometry), libMesh (unstructured mesh), MPI, all controlled by `#ifdef OPENMC_MPI`, etc. - -### Python Component Structure -- **ID management**: All geometry objects (Cell, Surface, Material, etc.) inherit from `IDManagerMixin` which auto-assigns unique integer IDs and tracks them via class-level `used_ids` and `next_id` -- **Input validation**: Extensive use of `openmc.checkvalue` module functions (`check_type`, `check_value`, `check_length`) for all setters -- **XML I/O**: Most classes implement `to_xml_element()` and `from_xml_element()` for serialization to OpenMC's XML input format -- **HDF5 output**: Post-simulation data in statepoint files read via `openmc.StatePoint` -- **Depletion**: `openmc.deplete` implements burnup via operator-splitting with various integrators (Predictor, CECM, etc.) -- **Nuclear Data**: `openmc.data` provides programmatic access to nuclear data files (ENDF, ACE, HDF5) - -## Git Branching Workflow - -OpenMC uses a git flow branching model with two primary branches: - -- **`develop` branch**: The main development branch where all ongoing development takes place. This is the **primary branch against which pull requests are submitted and merged**. This branch is not guaranteed to be stable and may contain work-in-progress features. -- **`master` branch**: The stable release branch containing the latest stable release of OpenMC. This branch only receives merges from `develop` when the development team decides a release should occur. - -### Instructions for Code Review - -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 - -1. Create a feature/bugfix branch off `develop` -2. Make changes and commit to the feature branch -3. Open a pull request to merge the feature branch into `develop` -4. A committer reviews and merges the PR into `develop` - -## Critical Build & Test Workflows - -### Build Dependencies -- **C++17 compiler**: GCC, Clang, or Intel -- **CMake** (3.16+): Required for configuring and building the C++ library -- **HDF5**: Required for cross section data and output file formats -- **libpng**: Used for generating visualization when OpenMC is run in plotting mode - -Without CMake and HDF5, OpenMC cannot be compiled. - -### Building the C++ Library -```bash -# Configure with CMake (from build/ directory) -cmake .. -DOPENMC_USE_MPI=ON -DOPENMC_USE_OPENMP=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo - -# Available CMake options (all default OFF except OPENMC_USE_OPENMP and OPENMC_BUILD_TESTS): -# -DOPENMC_USE_OPENMP=ON/OFF # OpenMP parallelism -# -DOPENMC_USE_MPI=ON/OFF # MPI support -# -DOPENMC_USE_DAGMC=ON/OFF # CAD geometry support -# -DOPENMC_USE_LIBMESH=ON/OFF # Unstructured mesh -# -DOPENMC_ENABLE_PROFILE=ON/OFF # Profiling flags -# -DOPENMC_ENABLE_COVERAGE=ON/OFF # Coverage analysis - -# Build -make -j - -# C++ unit tests (uses Catch2) -ctest -``` - -### Python Development -```bash -# Install in development mode (requires building C++ library first) -pip install -e . - -# Python tests (uses pytest) -pytest tests/unit_tests/ # Fast unit tests -pytest tests/regression_tests/ # Full regression suite (requires nuclear data) -``` - -### Nuclear Data Setup (CRITICAL for Running OpenMC) -Most tests require the NNDC HDF5 nuclear cross-section library. - -**Important**: Check if `OPENMC_CROSS_SECTIONS` is already set in the user's -environment before downloading, as many users already have nuclear data -installed. Though do note that if this variable is present that it may point to -different cross section data and that the NNDC data is required for tests to -pass. - -**If not already configured, download and setup:** -```bash -# Download NNDC HDF5 cross section library (~800 MB compressed) -wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr95p.xz | tar -C $HOME -xJ - -# Set environment variable (add to ~/.bashrc or ~/.zshrc for persistence) -export OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml -``` - -**Alternative**: Use the provided download script (checks if data exists before downloading): -```bash -bash tools/ci/download-xs.sh # Downloads both NNDC HDF5 and ENDF/B-VII.1 data -``` - -Without this data, regression tests will fail with "No cross_sections.xml file -found" errors, or, in the case that alternative cross section data is configured -the tests will execute but will not pass. The `cross_sections.xml` file is an -index listing paths to individual HDF5 nuclear data files for each nuclide. - -## Testing Expectations - -### Environment Requirements - - - **Data**: As described above, OpenMC's test suite requires OpenMC to be configured with NNDC data. - - **OpenMP Settings**: OpenMC's tests may fail is more than two OpenMP threads are used. The environment variable `OMP_NUM_THREADS=2` should be set to avoid sporadic test failures. - - **Executable configuration**: The OpenMC executable should compiled with debug symbols enabled. - -### C++ Tests -Located in `tests/cpp_unit_tests/`, use Catch2 framework. Run via `ctest` after building with `-DOPENMC_BUILD_TESTS=ON`. - -### Python Unit Tests -Located in `tests/unit_tests/`, these are fast, standalone tests that verify Python API functionality without running full simulations. Use standard pytest patterns: - -**Categories**: -- **API validation**: Test object creation, property setters/getters, XML serialization (e.g., `test_material.py`, `test_cell.py`, `test_source.py`) -- **Data processing**: Test nuclear data handling, cross sections, depletion chains (e.g., `test_data_neutron.py`, `test_deplete_chain.py`) -- **Library bindings**: Test `openmc.lib` ctypes interface with `model.init_lib()`/`model.finalize_lib()` (e.g., `test_lib.py`) -- **Geometry operations**: Test bounding boxes, containment, lattice generation (e.g., `test_bounding_box.py`, `test_lattice.py`) - -**Common patterns**: -- Use fixtures from `tests/unit_tests/conftest.py` (e.g., `uo2`, `water`, `sphere_model`) -- Test invalid inputs with `pytest.raises(ValueError)` or `pytest.raises(TypeError)` -- Use `run_in_tmpdir` fixture for tests that create files -- Tests with `openmc.lib` require calling `model.init_lib()` in try/finally with `model.finalize_lib()` - -**Example**: -```python -def test_material_properties(): - m = openmc.Material() - m.add_nuclide('U235', 1.0) - assert 'U235' in m.nuclides - - with pytest.raises(TypeError): - m.add_nuclide('H1', '1.0') # Invalid type -``` - -Unit tests should be fast. For tests requiring simulation output, use regression tests instead. - -### Python Regression Tests -Regression tests compare OpenMC output against reference data. **Prefer using existing models from `openmc.examples` or those found in tests/unit_tests/conftest.py** (like `pwr_pin_cell()`, `pwr_assembly()`, `slab_mg()`) rather than building from scratch. - -**Test Harness Types** (in `tests/testing_harness.py`): -- **PyAPITestHarness**: Standard harness for Python API tests. Compares `inputs_true.dat` (XML hash) and `results_true.dat` (statepoint k-eff and tally values). Requires `model.xml` generation. -- **HashedPyAPITestHarness**: Like PyAPITestHarness but hashes the results for compact comparison -- **TolerantPyAPITestHarness**: For tests with floating-point non-associativity (e.g., random ray solver with single precision). Uses relative tolerance comparisons. -- **WeightWindowPyAPITestHarness**: Compares weight window bounds from `weight_windows.h5` -- **CollisionTrackTestHarness**: Compares collision track data from `collision_track.h5` against `collision_track_true.h5` -- **TestHarness**: Base harness for XML-based tests (no Python model building) -- **PlotTestHarness**: Compares plot output files (PNG or voxel HDF5) -- **CMFDTestHarness**: Specialized for CMFD acceleration tests -- **ParticleRestartTestHarness**: Tests particle restart functionality - -Almost all cases use either `PyAPITestHarness` or `HashedPyAPITestHarness` - -**Example Test**: -```python -from openmc.examples import pwr_pin_cell -from tests.testing_harness import PyAPITestHarness - -def test_my_feature(): - model = pwr_pin_cell() - model.settings.particles = 1000 # Modify to exercise feature - harness = PyAPITestHarness('statepoint.10.h5', model) - 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 `-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. - -### Test Configuration - -`pytest.ini` sets: `python_files = test*.py`, `python_classes = NoThanks` (disables class-based test collection). - -### Testing Options - -For builds of OpenMC with MPI enabled, the `--mpi` flag should be passed to the test suite to ensure that appropriate tests are executed using two MPI processes. - -The entire test suite can be executed with OpenMC running in event-based mode (instead of the default history-based mode) by providing the `--event` flag to the `pytest` command. - -## Cross-Language Boundaries - -The C API (defined in `include/openmc/capi.h`) exposes C++ functionality to Python via ctypes bindings in `openmc/lib/`. Example: -```cpp -// C++ API in capi.h -extern "C" int openmc_run(); - -// Python binding in openmc/lib/core.py -_dll.openmc_run.restype = c_int -def run(): - _dll.openmc_run() -``` - -When modifying C++ public APIs, update corresponding ctypes signatures in `openmc/lib/*.py`. - -## Code Style & Conventions - -### C++ Style (enforced by .clang-format) - OpenMC generally tries to follow C++ core guidelines where possible - (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) and follow - modern C++ practices (e.g. RAII) whenever possible. - -- **Naming**: - - Classes: `CamelCase` (e.g., `HexLattice`) - - Functions/methods: `snake_case` (e.g., `get_indices`) - - Variables: `snake_case` with trailing underscore for class members (e.g., `n_particles_`, `energy_`) - - Constants: `UPPER_SNAKE_CASE` (e.g., `SQRT_PI`) -- **Namespaces**: All code in `openmc::` namespace, global state in sub-namespaces -- **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 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, endf). Other packages must be optional -- **Python version**: Minimum 3.11 (as of Nov 2025) - -### ID Management Pattern (Python) -When creating geometry objects, IDs can be auto-assigned or explicit: -```python -# Auto-assigned ID -cell = openmc.Cell() # Gets next available ID - -# Explicit ID -cell = openmc.Cell(id=10) # Warning if ID already used - -# Reset all IDs (useful in test fixtures) -openmc.reset_auto_ids() -``` - -### Input Validation Pattern (Python) -All setters use checkvalue functions: -```python -import openmc.checkvalue as cv - -@property -def temperature(self): - return self._temperature - -@temperature.setter -def temperature(self, temp): - cv.check_type('temperature', temp, Real) - cv.check_greater_than('temperature', temp, 0.0) - self._temperature = temp -``` - -### Working with HDF5 Files -C++ uses custom HDF5 wrappers in `src/hdf5_interface.cpp`. Python uses h5py directly. Statepoint format version is `VERSION_STATEPOINT` in `include/openmc/constants.h`. - -### Conditional Compilation -Check for optional features: -```cpp -#ifdef OPENMC_MPI - // MPI-specific code -#endif - -#ifdef OPENMC_DAGMC - // DAGMC-specific code -#endif -``` - -## Documentation - -- **User docs**: Sphinx documentation in `docs/source/` hosted at https://docs.openmc.org -- **C++ docs**: Doxygen-style comments with `\brief`, `\param` tags -- **Python docs**: numpydoc format docstrings - -## Common Pitfalls - -1. **Forgetting nuclear data**: Tests fail without `OPENMC_CROSS_SECTIONS` environment variable -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 18; other versions may produce different formatting diff --git a/CITATION.cff b/CITATION.cff deleted file mode 100644 index ab27d89b8..000000000 --- a/CITATION.cff +++ /dev/null @@ -1,68 +0,0 @@ -cff-version: 1.2.0 -message: "If you use this software, please cite it as below." -title: OpenMC -authors: -- family-names: Romano - given-names: Paul K. - orcid: "https://orcid.org/0000-0002-1147-045X" -- family-names: Shriwise - given-names: Patrick C. - orcid: "https://orcid.org/0000-0002-3979-7665" -- family-names: Shimwell - given-names: Jonathan - orcid: "https://orcid.org/0000-0001-6909-0946" -- family-names: Harper - given-names: Sterling -- family-names: Boyd - given-names: Will -- family-names: Nelson - given-names: Adam G. - orcid: "https://orcid.org/0000-0002-3614-0676" -- family-names: Tramm - given-names: John R. - orcid: "https://orcid.org/0000-0002-5397-4402" -- family-names: Ridley - given-names: Gavin - orcid: "https://orcid.org/0000-0003-1635-8042" -- family-names: Johnson - given-names: Andrew - orcid: "https://orcid.org/0000-0003-2125-8775" -- family-names: Peterson - given-names: Ethan E. - orcid: "https://orcid.org/0000-0002-5694-7194" -- family-names: Herman - given-names: Bryan R. -preferred-citation: - authors: - - family-names: Romano - given-names: Paul K. - orcid: "https://orcid.org/0000-0002-1147-045X" - - family-names: Horelik - given-names: Nicholas E. - - family-names: Herman - given-names: Bryan R. - - family-names: Nelson - given-names: Adam G. - orcid: "https://orcid.org/0000-0002-3614-0676" - - family-names: Forget - given-names: Benoit - orcid: "https://orcid.org/0000-0003-1459-7672" - - family-names: Smith - given-names: Kord - contact: - - family-names: Romano - given-names: Paul K. - orcid: "https://orcid.org/0000-0002-1147-045X" - doi: 10.1016/j.anucene.2014.07.048 - issn: 0306-4549 - volume: 82 - journal: Annals of Nuclear Energy - publisher: - name: Elsevier - start: 90 - end: 97 - year: 2015 - month: 8 - title: "OpenMC: A state-of-the-art Monte Carlo code for research and development" - type: article - url: "https://doi.org/10.1016/j.anucene.2014.07.048" diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 9538b5ddc..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,14 +0,0 @@ -## 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. diff --git a/CMakeLists.txt b/CMakeLists.txt index 61d2cc6c5..5e949070c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,11 @@ -cmake_minimum_required(VERSION 3.16 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc C CXX) -# Set module path -set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) - -include(GetVersionFromGit) - -# Output version information -message(STATUS "OpenMC version: ${OPENMC_VERSION}") -message(STATUS "OpenMC dev state: ${OPENMC_DEV_STATE}") -message(STATUS "OpenMC commit hash: ${OPENMC_COMMIT_HASH}") -message(STATUS "OpenMC commit count: ${OPENMC_COMMIT_COUNT}") - -# Generate version.h +# Set version numbers +set(OPENMC_VERSION_MAJOR 0) +set(OPENMC_VERSION_MINOR 13) +set(OPENMC_VERSION_RELEASE 1) +set(OPENMC_VERSION ${OPENMC_VERSION_MAJOR}.${OPENMC_VERSION_MINOR}.${OPENMC_VERSION_RELEASE}) configure_file(include/openmc/version.h.in "${CMAKE_BINARY_DIR}/include/openmc/version.h" @ONLY) # Setup output directories @@ -20,9 +13,12 @@ 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) +# Set module path +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) + +# Allow user to specify _ROOT variables +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) + cmake_policy(SET CMP0074 NEW) endif() # Enable correct usage of CXX_EXTENSIONS @@ -35,26 +31,11 @@ endif() #=============================================================================== option(OPENMC_USE_OPENMP "Enable shared-memory parallelism with OpenMP" ON) -option(OPENMC_BUILD_TESTS "Build tests" ON) option(OPENMC_ENABLE_PROFILE "Compile with profiling flags" OFF) option(OPENMC_ENABLE_COVERAGE "Compile with coverage analysis flags" OFF) option(OPENMC_USE_DAGMC "Enable support for DAGMC (CAD) geometry" OFF) option(OPENMC_USE_LIBMESH "Enable support for libMesh unstructured mesh tallies" OFF) 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}") -message(STATUS "OPENMC_ENABLE_PROFILE ${OPENMC_ENABLE_PROFILE}") -message(STATUS "OPENMC_ENABLE_COVERAGE ${OPENMC_ENABLE_COVERAGE}") -message(STATUS "OPENMC_USE_DAGMC ${OPENMC_USE_DAGMC}") -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") @@ -96,27 +77,6 @@ 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!) -#=============================================================================== - -if(OPENMC_USE_OPENMP) - find_package(OpenMP REQUIRED) -endif() - #=============================================================================== # MPI for distributed-memory parallelism #=============================================================================== @@ -145,14 +105,8 @@ endmacro() if(OPENMC_USE_DAGMC) find_package(DAGMC REQUIRED PATH_SUFFIXES lib/cmake) if (${DAGMC_VERSION} VERSION_LESS 3.2.0) - message(FATAL_ERROR "Discovered DAGMC Version: ${DAGMC_VERSION}." - "Please update DAGMC to version 3.2.0 or greater.") - endif() - message(STATUS "Found DAGMC: ${DAGMC_DIR} (version ${DAGMC_VERSION})") - - # Check if UWUW is needed and available - if(OPENMC_USE_UWUW AND NOT DAGMC_BUILD_UWUW) - message(FATAL_ERROR "UWUW is enabled but DAGMC was not configured with UWUW.") + message(FATAL_ERROR "Discovered DAGMC Version: ${DAGMC_VERSION}. \ + Please update DAGMC to version 3.2.0 or greater.") endif() endif() @@ -188,16 +142,11 @@ if(NOT DEFINED HDF5_PREFER_PARALLEL) endif() find_package(HDF5 REQUIRED COMPONENTS C HL) - -# Remove HDF5 transitive dependencies that are system libraries -list(FILTER HDF5_LIBRARIES EXCLUDE REGEX ".*lib(pthread|dl|m).*") -message(STATUS "HDF5 Libraries: ${HDF5_LIBRARIES}") - if(HDF5_IS_PARALLEL) if(NOT OPENMC_USE_MPI) - message(FATAL_ERROR "Parallel HDF5 was detected, but MPI was not enabled.\ - To use parallel HDF5, OpenMC needs to be built with MPI support by passing\ - -DOPENMC_USE_MPI=ON when calling cmake.") + message(FATAL_ERROR "Parallel HDF5 was detected, but the detected compiler,\ + ${CMAKE_CXX_COMPILER}, does not support MPI. An MPI-capable compiler must \ + be used with parallel HDF5.") endif() message(STATUS "Using parallel HDF5") endif() @@ -213,29 +162,18 @@ 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) +if(OPENMC_USE_OPENMP) + find_package(OpenMP) + if(OPENMP_FOUND) + # In CMake 3.9+, can use the OpenMP::OpenMP_CXX imported target + list(APPEND cxxflags ${OpenMP_CXX_FLAGS}) + list(APPEND ldflags ${OpenMP_CXX_FLAGS}) + endif() +endif() + set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(OPENMC_ENABLE_PROFILE) @@ -256,6 +194,8 @@ endif() #=============================================================================== # Update git submodules as needed #=============================================================================== + +find_package(Git) if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") option(GIT_SUBMODULE "Check submodules during build" ON) if(GIT_SUBMODULE) @@ -280,45 +220,49 @@ endif() # pugixml library #=============================================================================== -if(OPENMC_FORCE_VENDORED_LIBS) +find_package_write_status(pugixml) +if (NOT pugixml_FOUND) add_subdirectory(vendor/pugixml) set_target_properties(pugixml PROPERTIES CXX_STANDARD 14 CXX_EXTENSIONS OFF) -else() - find_package_write_status(pugixml) - if (NOT pugixml_FOUND) - add_subdirectory(vendor/pugixml) - set_target_properties(pugixml PROPERTIES CXX_STANDARD 14 CXX_EXTENSIONS OFF) - endif() endif() #=============================================================================== # {fmt} library #=============================================================================== -if(OPENMC_FORCE_VENDORED_LIBS) +find_package_write_status(fmt) +if (NOT fmt_FOUND) set(FMT_INSTALL ON CACHE BOOL "Generate the install target.") add_subdirectory(vendor/fmt) -else() - find_package_write_status(fmt) - if (NOT fmt_FOUND) - set(FMT_INSTALL ON CACHE BOOL "Generate the install target.") - add_subdirectory(vendor/fmt) - endif() endif() #=============================================================================== -# Catch2 library +# xtensor header-only library #=============================================================================== -if(OPENMC_BUILD_TESTS) - if (OPENMC_FORCE_VENDORED_LIBS) - add_subdirectory(vendor/Catch2) - else() - find_package_write_status(Catch2) - if (NOT Catch2_FOUND) - add_subdirectory(vendor/Catch2) - endif() - endif() +# CMake 3.13+ will complain about policy CMP0079 unless it is set explicitly +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) + cmake_policy(SET CMP0079 NEW) +endif() + +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() + +#=============================================================================== +# GSL header-only library +#=============================================================================== + +find_package_write_status(gsl-lite) +if (NOT gsl-lite_FOUND) + add_subdirectory(vendor/gsl-lite) + + # Make sure contract violations throw exceptions + target_compile_definitions(gsl-lite-v1 INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) + target_compile_definitions(gsl-lite-v1 INTERFACE gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=1) endif() #=============================================================================== @@ -355,16 +299,13 @@ endif() #=============================================================================== list(APPEND libopenmc_SOURCES - src/atomic_mass.cpp src/bank.cpp src/boundary_condition.cpp src/bremsstrahlung.cpp - src/cell.cpp - src/chain.cpp - src/cmfd_solver.cpp - src/collision_track.cpp - src/cross_sections.cpp src/dagmc.cpp + src/cell.cpp + src/cmfd_solver.cpp + src/cross_sections.cpp src/distribution.cpp src/distribution_angle.cpp src/distribution_energy.cpp @@ -374,29 +315,23 @@ list(APPEND libopenmc_SOURCES src/endf.cpp src/error.cpp src/event.cpp - src/file_utils.cpp + src/initialize.cpp src/finalize.cpp src/geometry.cpp src/geometry_aux.cpp src/hdf5_interface.cpp - src/ifp.cpp - src/initialize.cpp src/lattice.cpp src/material.cpp src/math_functions.cpp - src/mcpl_interface.cpp src/mesh.cpp src/message_passing.cpp src/mgxs.cpp src/mgxs_interface.cpp - src/ncrystal_interface.cpp - src/ncrystal_load.cpp src/nuclide.cpp src/output.cpp 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 @@ -406,13 +341,6 @@ list(APPEND libopenmc_SOURCES src/progress_bar.cpp src/random_dist.cpp src/random_lcg.cpp - src/random_ray/random_ray_simulation.cpp - src/random_ray/random_ray.cpp - src/random_ray/flat_source_domain.cpp - 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 @@ -431,41 +359,33 @@ list(APPEND libopenmc_SOURCES src/tallies/derivative.cpp src/tallies/filter.cpp src/tallies/filter_azimuthal.cpp - src/tallies/filter_cell.cpp - src/tallies/filter_cell_instance.cpp src/tallies/filter_cellborn.cpp src/tallies/filter_cellfrom.cpp - src/tallies/filter_collision.cpp + src/tallies/filter_cell.cpp + src/tallies/filter_cell_instance.cpp src/tallies/filter_delayedgroup.cpp src/tallies/filter_distribcell.cpp - src/tallies/filter_energy.cpp src/tallies/filter_energyfunc.cpp + src/tallies/filter_energy.cpp + src/tallies/filter_collision.cpp src/tallies/filter_legendre.cpp src/tallies/filter_material.cpp - src/tallies/filter_materialfrom.cpp src/tallies/filter_mesh.cpp - src/tallies/filter_meshborn.cpp - src/tallies/filter_meshmaterial.cpp src/tallies/filter_meshsurface.cpp src/tallies/filter_mu.cpp - 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 src/tallies/filter_time.cpp src/tallies/filter_universe.cpp - src/tallies/filter_weight.cpp src/tallies/filter_zernike.cpp src/tallies/tally.cpp src/tallies/tally_scoring.cpp src/tallies/trigger.cpp - src/thermal.cpp src/timer.cpp + src/thermal.cpp src/track_output.cpp src/universe.cpp src/urr.cpp @@ -520,10 +440,22 @@ if (OPENMC_USE_MPI) target_compile_definitions(libopenmc PUBLIC -DOPENMC_MPI) endif() +# Set git SHA1 hash as a compile definition +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SHA1_SUCCESS + OUTPUT_VARIABLE GIT_SHA1 + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(GIT_SHA1_SUCCESS EQUAL 0) + target_compile_definitions(libopenmc PRIVATE -DGIT_SHA1="${GIT_SHA1}") + endif() +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} - fmt::fmt ${CMAKE_DL_LIBS}) + xtensor gsl::gsl-lite-v1 fmt::fmt) if(TARGET pugixml::pugixml) target_link_libraries(libopenmc pugixml::pugixml) @@ -532,20 +464,12 @@ else() endif() if(OPENMC_USE_DAGMC) - target_compile_definitions(libopenmc PUBLIC OPENMC_DAGMC_ENABLED) - target_link_libraries(libopenmc dagmc-shared) - - if(OPENMC_USE_UWUW) - target_compile_definitions(libopenmc PRIVATE OPENMC_UWUW_ENABLED) - target_link_libraries(libopenmc uwuw-shared) - endif() -elseif(OPENMC_USE_UWUW) - set(OPENMC_USE_UWUW OFF) - message(FATAL_ERROR "DAGMC must be enabled when UWUW is enabled.") + target_compile_definitions(libopenmc PRIVATE DAGMC) + target_link_libraries(libopenmc dagmc-shared uwuw-shared) endif() if(OPENMC_USE_LIBMESH) - target_compile_definitions(libopenmc PRIVATE OPENMC_LIBMESH_ENABLED) + target_compile_definitions(libopenmc PRIVATE LIBMESH) target_link_libraries(libopenmc PkgConfig::LIBMESH) endif() @@ -554,36 +478,10 @@ if (PNG_FOUND) target_link_libraries(libopenmc PNG::PNG) endif() -if (OPENMC_USE_OPENMP) - target_link_libraries(libopenmc OpenMP::OpenMP_CXX) -endif() - if (OPENMC_USE_MPI) target_link_libraries(libopenmc MPI::MPI_CXX) endif() -if (OPENMC_BUILD_TESTS) - # Add cpp tests directory - include(CTest) - add_subdirectory(tests/cpp_unit_tests) -endif() - -#=============================================================================== -# Log build info that this executable can report later -#=============================================================================== -target_compile_definitions(libopenmc PRIVATE BUILD_TYPE=${CMAKE_BUILD_TYPE}) -target_compile_definitions(libopenmc PRIVATE COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) -target_compile_definitions(libopenmc PRIVATE COMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION}) -if (OPENMC_ENABLE_PROFILE) - target_compile_definitions(libopenmc PRIVATE PROFILINGBUILD) -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 #=============================================================================== @@ -593,9 +491,9 @@ target_compile_options(openmc PRIVATE ${cxxflags}) target_include_directories(openmc PRIVATE ${CMAKE_BINARY_DIR}/include) target_link_libraries(openmc libopenmc) -# Ensure C++17 standard is used and turn off GNU extensions -target_compile_features(openmc PUBLIC cxx_std_17) -target_compile_features(libopenmc PUBLIC cxx_std_17) +# Ensure C++14 standard is used and turn off GNU extensions +target_compile_features(openmc PUBLIC cxx_std_14) +target_compile_features(libopenmc PUBLIC cxx_std_14) set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) #=============================================================================== @@ -611,7 +509,9 @@ add_custom_command(TARGET libopenmc POST_BUILD #=============================================================================== # Install executable, scripts, manpage, license #=============================================================================== -include(CMakePackageConfigHelpers) + +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) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) install(TARGETS openmc libopenmc @@ -625,24 +525,11 @@ 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(DIRECTORY src/relaxng DESTINATION ${CMAKE_INSTALL_DATADIR}/openmc) 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}) diff --git a/CODEOWNERS b/CODEOWNERS index c77366de7..1b5130e0b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,9 +5,9 @@ openmc/data/ @paulromano openmc/lib/ @paulromano # Depletion -openmc/deplete/ @paulromano -tests/regression_tests/deplete/ @paulromano -tests/unit_tests/test_deplete_*.py @paulromano +openmc/deplete/ @drewejohnson +tests/regression_tests/deplete/ @drewejohnson +tests/unit_tests/test_deplete_*.py @drewejohnson # MG-related functionality openmc/mgxs_library.py @nelsonag @@ -26,12 +26,6 @@ src/dagmc.cpp @pshriwise tests/regression_tests/dagmc/ @pshriwise tests/unit_tests/dagmc/ @pshriwise -# Weight windows -openmc/weight_windows.py @pshriwise -openmc/lib/weight_windows.py @pshriwise -src/weight_windows.py @pshriwise -tests/unit_tests/weightwindows/ @pshriwise - # Photon transport openmc/data/BREMX.DAT @amandalund openmc/data/compton_profiles.h5 @amandalund @@ -55,13 +49,3 @@ openmc/data/resonance_covariance.py @icmeyer # Docker Dockerfile @shimwell - -# Random ray -src/random_ray/ @jtramm - -# NCrystal interface -src/ncrystal_interface.cpp @marquezj @tkittel -src/ncrystal_load.cpp @marquezj @tkittel - -# MCPL interface -src/mcpl_interface.cpp @ebknudsen diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 184c522d4..378ca346a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ openmc@anl.gov. ## Resources - [GitHub Repository](https://github.com/openmc-dev/openmc) -- [Documentation](https://docs.openmc.org/en/latest) +- [Documentation](http://docs.openmc.org/en/latest) - [Discussion Forum](https://openmc.discourse.group) - [Slack Community](https://openmc.slack.com/signup) (If you don't see your domain listed, contact openmc@anl.gov) diff --git a/Dockerfile b/Dockerfile index 688e5a370..d408b9de5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ ARG compile_cores=1 ARG build_dagmc=off ARG build_libmesh=off -FROM ubuntu:24.04 AS dependencies +FROM debian:bullseye-slim AS dependencies ARG compile_cores ARG build_dagmc @@ -33,31 +33,35 @@ ARG build_libmesh # Set default value of HOME to /root ENV HOME=/root +# Embree variables +ENV EMBREE_TAG='v3.12.2' +ENV EMBREE_REPO='https://github.com/embree/embree' +ENV EMBREE_INSTALL_DIR=$HOME/EMBREE/ + # MOAB variables -ENV MOAB_TAG='5.5.1' +ENV MOAB_TAG='5.3.0' ENV MOAB_REPO='https://bitbucket.org/fathomteam/moab/' # Double-Down variables -ENV DD_TAG='v1.1.0' +ENV DD_TAG='v1.0.0' ENV DD_REPO='https://github.com/pshriwise/double-down' ENV DD_INSTALL_DIR=$HOME/Double_down # DAGMC variables -ENV DAGMC_BRANCH='v3.2.4' +ENV DAGMC_BRANCH='v3.2.1' ENV DAGMC_REPO='https://github.com/svalinn/DAGMC' ENV DAGMC_INSTALL_DIR=$HOME/DAGMC/ # LIBMESH variables -ENV LIBMESH_TAG='v1.7.1' +ENV LIBMESH_TAG='v1.6.0' 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 @@ -67,19 +71,15 @@ 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 libpugixml-dev libfmt-dev catch2 python3-venv && \ + libpng-dev && \ apt-get autoremove -# create virtual enviroment to avoid externally managed environment error -RUN python3 -m venv openmc_venv -ENV PATH=/openmc_venv/bin:$PATH - # Update system-provided pip RUN pip install --upgrade pip # Clone and install NJOY2016 RUN cd $HOME \ - && git clone --single-branch -b ${NJOY_TAG} --depth 1 ${NJOY_REPO} \ + && git clone --single-branch --depth 1 ${NJOY_REPO} \ && cd NJOY2016 \ && mkdir build \ && cd build \ @@ -90,21 +90,28 @@ 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 libembree-dev \ - && pip install --upgrade numpy \ - && pip install --no-cache-dir setuptools cython \ + apt-get -y install libeigen3-dev libnetcdf-dev libtbb-dev libglfw3-dev \ + && pip install --upgrade numpy 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 \ - -DENABLE_HDF5=ON \ + && cmake ../moab -DENABLE_HDF5=ON \ -DENABLE_NETCDF=ON \ -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 \ @@ -120,7 +127,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=/usr \ + -DEMBREE_DIR=${EMBREE_INSTALL_DIR} \ && make 2>/dev/null -j${compile_cores} install \ && rm -rf ${DD_INSTALL_DIR}/build ${DD_INSTALL_DIR}/double-down ; \ # Clone and install DAGMC @@ -134,7 +141,6 @@ 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 @@ -183,7 +189,7 @@ ENV LIBMESH_INSTALL_DIR=$HOME/LIBMESH # clone and install openmc RUN mkdir -p ${HOME}/OpenMC && cd ${HOME}/OpenMC \ - && git clone --shallow-submodules --recurse-submodules --single-branch -b ${openmc_branch} ${OPENMC_REPO} \ + && git clone --shallow-submodules --recurse-submodules --single-branch -b ${openmc_branch} --depth=1 ${OPENMC_REPO} \ && mkdir build && cd build ; \ if [ ${build_dagmc} = "on" ] && [ ${build_libmesh} = "on" ]; then \ cmake ../openmc \ diff --git a/LICENSE b/LICENSE index b5dfd1748..7fb6e3f27 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2026 Massachusetts Institute of Technology, UChicago Argonne +Copyright (c) 2011-2022 Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/MANIFEST.in b/MANIFEST.in index cdc7e2abc..d59628325 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -23,9 +23,10 @@ recursive-include examples *.cpp recursive-include examples *.py recursive-include examples *.xml recursive-include include *.h -recursive-include include *.h.in recursive-include include *.hh recursive-include man *.1 +recursive-include openmc *.pyx +recursive-include openmc *.c recursive-include src *.cc recursive-include src *.cpp recursive-include src *.rnc @@ -43,5 +44,6 @@ recursive-include vendor *.hh recursive-include vendor *.hpp recursive-include vendor *.pc.in recursive-include vendor *.natvis +include vendor/gsl-lite/include/gsl/gsl prune docs/build prune docs/source/pythonapi/generated/ diff --git a/README.md b/README.md index 6539ec3c7..bd7a8479a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # OpenMC Monte Carlo Particle Transport Code [![License](https://img.shields.io/badge/license-MIT-green)](https://docs.openmc.org/en/latest/license.html) -[![GitHub Actions build status (Linux)](https://github.com/openmc-dev/openmc/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/openmc-dev/openmc/actions/workflows/ci.yml) +[![GitHub Actions build status (Linux)](https://github.com/openmc-dev/openmc/workflows/CI/badge.svg?branch=develop)](https://github.com/openmc-dev/openmc/actions?query=workflow%3ACI) [![Code Coverage](https://coveralls.io/repos/github/openmc-dev/openmc/badge.svg?branch=develop)](https://coveralls.io/github/openmc-dev/openmc?branch=develop) [![dockerhub-publish-develop-dagmc](https://github.com/openmc-dev/openmc/workflows/dockerhub-publish-develop-dagmc/badge.svg)](https://github.com/openmc-dev/openmc/actions?query=workflow%3Adockerhub-publish-develop-dagmc) [![dockerhub-publish-develop](https://github.com/openmc-dev/openmc/workflows/dockerhub-publish-develop/badge.svg)](https://github.com/openmc-dev/openmc/actions?query=workflow%3Adockerhub-publish-develop) @@ -15,8 +15,7 @@ project started under the Computational Reactor Physics Group at MIT. Complete documentation on the usage of OpenMC is hosted on Read the Docs (both for the [latest release](https://docs.openmc.org/en/stable/) and [developmental](https://docs.openmc.org/en/latest/) version). If you are -interested in the project, or would like to help and contribute, please get in -touch on the OpenMC [discussion forum](https://openmc.discourse.group/). +interested in the project, or would like to help and contribute, please get in touch on the OpenMC [discussion forum](https://openmc.discourse.group/). ## Installation @@ -37,21 +36,20 @@ citing the following publication: ## Troubleshooting If you run into problems compiling, installing, or running OpenMC, first check -the [Troubleshooting -section](https://docs.openmc.org/en/stable/usersguide/troubleshoot.html) in the -User's Guide. If you are not able to find a solution to your problem there, +the [Troubleshooting section](https://docs.openmc.org/en/stable/usersguide/troubleshoot.html) in +the User's Guide. If you are not able to find a solution to your problem there, please post to the [discussion forum](https://openmc.discourse.group/). ## Reporting Bugs OpenMC is hosted on GitHub and all bugs are reported and tracked through the -[Issues](https://github.com/openmc-dev/openmc/issues) feature on GitHub. -However, GitHub Issues should not be used for common troubleshooting purposes. -If you are having trouble installing the code or getting your model to run -properly, you should first send a message to the [discussion -forum](https://openmc.discourse.group/). If it turns out your issue really is a -bug in the code, an issue will then be created on GitHub. If you want to request -that a feature be added to the code, you may create an Issue on github. +[Issues](https://github.com/openmc-dev/openmc/issues) feature on GitHub. However, +GitHub Issues should not be used for common troubleshooting purposes. If you are +having trouble installing the code or getting your model to run properly, you +should first send a message to the User's Group mailing list. If it turns out +your issue really is a bug in the code, an issue will then be created on +GitHub. If you want to request that a feature be added to the code, you may +create an Issue on github. ## License diff --git a/cmake/Modules/FindLIBMESH.cmake b/cmake/Modules/FindLIBMESH.cmake index df9208c18..82d806343 100644 --- a/cmake/Modules/FindLIBMESH.cmake +++ b/cmake/Modules/FindLIBMESH.cmake @@ -14,8 +14,8 @@ if(DEFINED ENV{METHOD}) message(STATUS "Using environment variable METHOD to determine libMesh build: ${LIBMESH_PC_FILE}") endif() -find_package(PkgConfig REQUIRED) - -set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH TRUE) -pkg_check_modules(LIBMESH REQUIRED ${LIBMESH_PC_FILE}>=1.7.0 IMPORTED_TARGET) -pkg_get_variable(LIBMESH_PREFIX ${LIBMESH_PC_FILE} prefix) +include(FindPkgConfig) +set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${LIBMESH_PC}") +set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH True) +pkg_check_modules(LIBMESH REQUIRED ${LIBMESH_PC_FILE}>=1.6.0 IMPORTED_TARGET) +pkg_get_variable(LIBMESH_PREFIX ${LIBMESH_PC_FILE} prefix) \ No newline at end of file diff --git a/cmake/Modules/GetVersionFromGit.cmake b/cmake/Modules/GetVersionFromGit.cmake deleted file mode 100644 index 3736955ff..000000000 --- a/cmake/Modules/GetVersionFromGit.cmake +++ /dev/null @@ -1,120 +0,0 @@ -# GetVersionFromGit.cmake -# Standalone script to retrieve versioning information from Git or .git_archival.txt. -# Customizable for any project by setting variables before including this file. - -# Configurable variables: -# - VERSION_PREFIX: Prefix for version tags (default: "v"). -# - VERSION_SUFFIX: Suffix for version tags (default: "[~+-]([a-zA-Z0-9]+)"). -# - VERSION_REGEX: Regex to extract version (default: "(?[0-9]+\\.[0-9]+\\.[0-9]+)"). -# - ARCHIVAL_FILE: Path to .git_archival.txt (default: "${CMAKE_SOURCE_DIR}/.git_archival.txt"). -# - DESCRIBE_NAME_KEY: Key for describe name in .git_archival.txt (default: "describe-name: "). -# - COMMIT_HASH_KEY: Key for commit hash in .git_archival.txt (default: "commit: "). - -# Default Format Example: -# 1.2.3 v1.2.3 v1.2.3-rc1 - -set(VERSION_PREFIX "v" CACHE STRING "Prefix used in version tags") -set(VERSION_SUFFIX "[~+-]([a-zA-Z0-9]+)" CACHE STRING "Suffix used in version tags") -set(VERSION_REGEX "?([0-9]+\\.[0-9]+\\.[0-9]+)" CACHE STRING "Regex for extracting version") -set(ARCHIVAL_FILE "${CMAKE_SOURCE_DIR}/.git_archival.txt" CACHE STRING "Path to .git_archival.txt") -set(DESCRIBE_NAME_KEY "describe-name: " CACHE STRING "Key for describe name in .git_archival.txt") -set(COMMIT_HASH_KEY "commit: " CACHE STRING "Key for commit hash in .git_archival.txt") - - -# Combine prefix and regex -set(VERSION_REGEX_WITH_PREFIX "^${VERSION_PREFIX}${VERSION_REGEX}") - -# Find Git -find_package(Git) - -# Attempt to retrieve version from Git -if(EXISTS "${CMAKE_SOURCE_DIR}/.git" AND GIT_FOUND) - message(STATUS "Using git describe for versioning") - - # Extract the version string - execute_process( - COMMAND git describe --tags --dirty - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE VERSION_STRING - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) - - # If no tags are found, set version to 0 and show a warning - if(VERSION_STRING STREQUAL "") - set(VERSION_STRING "0.0.0") - message(WARNING - "No git tags found. Version set to 0.0.0.\n" - "Run 'git fetch --tags' to ensure proper versioning.\n" - "For more information, see OpenMC developer documentation." - ) - endif() - - # Extract the commit hash - execute_process( - COMMAND git rev-parse HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -else() - message(STATUS "Using archival file for versioning: ${ARCHIVAL_FILE}") - if(EXISTS "${ARCHIVAL_FILE}") - file(READ "${ARCHIVAL_FILE}" ARCHIVAL_CONTENT) - - # Extract the describe-name line - string(REGEX MATCH "${DESCRIBE_NAME_KEY}([^\\n]+)" VERSION_STRING "${ARCHIVAL_CONTENT}") - if(VERSION_STRING MATCHES "${DESCRIBE_NAME_KEY}(.*)") - set(VERSION_STRING "${CMAKE_MATCH_1}") - else() - message(FATAL_ERROR "Could not extract version from ${ARCHIVAL_FILE}") - endif() - - # Extract the commit hash - string(REGEX MATCH "${COMMIT_HASH_KEY}([a-f0-9]+)" COMMIT_HASH "${ARCHIVAL_CONTENT}") - if(COMMIT_HASH MATCHES "${COMMIT_HASH_KEY}([a-f0-9]+)") - set(COMMIT_HASH "${CMAKE_MATCH_1}") - else() - message(FATAL_ERROR "Could not extract commit hash from ${ARCHIVAL_FILE}") - endif() - else() - message(FATAL_ERROR "Neither git describe nor ${ARCHIVAL_FILE} is available for versioning.") - endif() -endif() - -# Ensure version string format -if(VERSION_STRING MATCHES "${VERSION_REGEX_WITH_PREFIX}") - set(VERSION_NO_SUFFIX "${CMAKE_MATCH_1}") -else() - message(FATAL_ERROR "Invalid version format: Missing base version in ${VERSION_STRING}") -endif() - -# Check for development state -if(VERSION_STRING MATCHES "-([0-9]+)-g([0-9a-f]+)") - set(DEV_STATE "true") - set(COMMIT_COUNT "${CMAKE_MATCH_1}") - string(REGEX REPLACE "-([0-9]+)-g([0-9a-f]+)" "" VERSION_WITHOUT_META "${VERSION_STRING}") -else() - set(DEV_STATE "false") - set(VERSION_WITHOUT_META "${VERSION_STRING}") -endif() - -# Split and set version components -string(REPLACE "." ";" VERSION_LIST "${VERSION_NO_SUFFIX}") -list(GET VERSION_LIST 0 VERSION_MAJOR) -list(GET VERSION_LIST 1 VERSION_MINOR) -list(GET VERSION_LIST 2 VERSION_PATCH) - -# Increment patch number for dev versions -if(DEV_STATE) - math(EXPR VERSION_PATCH "${VERSION_PATCH} + 1") -endif() - -# Export variables -set(OPENMC_VERSION_MAJOR "${VERSION_MAJOR}") -set(OPENMC_VERSION_MINOR "${VERSION_MINOR}") -set(OPENMC_VERSION_PATCH "${VERSION_PATCH}") -set(OPENMC_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") -set(OPENMC_COMMIT_HASH "${COMMIT_HASH}") -set(OPENMC_DEV_STATE "${DEV_STATE}") -set(OPENMC_COMMIT_COUNT "${COMMIT_COUNT}") diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index 0e15060a3..3279e5ba8 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -1,45 +1,27 @@ -@PACKAGE_INIT@ - -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}) +get_filename_component(OpenMC_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) +find_package(fmt REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../fmt) +find_package(gsl-lite REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../gsl-lite) +find_package(pugixml REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../pugixml) +find_package(xtl REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtl) +find_package(xtensor REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtensor) if(@OPENMC_USE_DAGMC@) - find_dependency(DAGMC REQUIRED HINTS @DAGMC_DIR@) + find_package(DAGMC REQUIRED HINTS @DAGMC_DIR@) endif() if(@OPENMC_USE_LIBMESH@) include(FindPkgConfig) list(APPEND CMAKE_PREFIX_PATH @LIBMESH_PREFIX@) set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH True) - pkg_check_modules(LIBMESH REQUIRED @LIBMESH_PC_FILE@>=1.7.0 IMPORTED_TARGET) + pkg_check_modules(LIBMESH REQUIRED @LIBMESH_PC_FILE@>=1.6.0 IMPORTED_TARGET) endif() -if("@PNG_FOUND@") - find_dependency(PNG) +find_package(PNG) + +if(NOT TARGET OpenMC::libopenmc) + include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake") endif() if(@OPENMC_USE_MPI@) - find_dependency(MPI REQUIRED) -endif() - -if(@OPENMC_USE_OPENMP@) - 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})") + find_package(MPI REQUIRED) endif() diff --git a/cmake/OpenMCConfigVersion.cmake.in b/cmake/OpenMCConfigVersion.cmake.in new file mode 100644 index 000000000..90d345de4 --- /dev/null +++ b/cmake/OpenMCConfigVersion.cmake.in @@ -0,0 +1,11 @@ +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() diff --git a/docs/Makefile b/docs/Makefile index e320432a2..a93338df3 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -45,7 +45,6 @@ help: clean: -rm -rf $(BUILDDIR)/* -rm -rf source/pythonapi/generated/ - -rm -rf doxygen/xml html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile deleted file mode 100644 index 75702eff7..000000000 --- a/docs/doxygen/Doxyfile +++ /dev/null @@ -1,13 +0,0 @@ -# Doxyfile 1.9.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. - -# Difference with default Doxyfile 1.9.1 -PROJECT_NAME = OpenMC -QUIET = YES -WARN_IF_UNDOCUMENTED = NO -INPUT = ../../include/openmc/capi.h -GENERATE_HTML = NO -GENERATE_LATEX = NO -GENERATE_XML = YES diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt new file mode 100644 index 000000000..9591d482f --- /dev/null +++ b/docs/requirements-rtd.txt @@ -0,0 +1,12 @@ +sphinx==5.0.2 +sphinx_rtd_theme==1.0.0 +sphinx-numfig +jupyter +sphinxcontrib-katex +sphinxcontrib-svg2pdfconverter +numpy +scipy +h5py +pandas +uncertainties +matplotlib diff --git a/docs/source/_images/2x2_fsrs.jpeg b/docs/source/_images/2x2_fsrs.jpeg deleted file mode 100644 index 1c8e474d0..000000000 Binary files a/docs/source/_images/2x2_fsrs.jpeg and /dev/null differ diff --git a/docs/source/_images/2x2_materials.jpeg b/docs/source/_images/2x2_materials.jpeg deleted file mode 100644 index b76607eca..000000000 Binary files a/docs/source/_images/2x2_materials.jpeg and /dev/null differ diff --git a/docs/source/_images/2x2_sr_mesh.png b/docs/source/_images/2x2_sr_mesh.png deleted file mode 100644 index 5cdc684d3..000000000 Binary files a/docs/source/_images/2x2_sr_mesh.png and /dev/null differ diff --git a/docs/source/_images/hexlat_anim.gif b/docs/source/_images/hexlat_anim.gif deleted file mode 100644 index fceedc010..000000000 Binary files a/docs/source/_images/hexlat_anim.gif and /dev/null differ diff --git a/docs/source/_images/phong_triso.png b/docs/source/_images/phong_triso.png deleted file mode 100644 index 7f1ac61ca..000000000 Binary files a/docs/source/_images/phong_triso.png and /dev/null differ diff --git a/docs/source/_images/plotmeshtally.png b/docs/source/_images/plotmeshtally.png new file mode 100644 index 000000000..d874b4906 Binary files /dev/null and b/docs/source/_images/plotmeshtally.png differ diff --git a/docs/source/_images/sphere-mesh-vtk.png b/docs/source/_images/sphere-mesh-vtk.png deleted file mode 100644 index 73b412bdd..000000000 Binary files a/docs/source/_images/sphere-mesh-vtk.png and /dev/null differ diff --git a/docs/source/capi/index.rst b/docs/source/capi/index.rst index e924aa6e2..52c0b2406 100644 --- a/docs/source/capi/index.rst +++ b/docs/source/capi/index.rst @@ -46,29 +46,41 @@ Type Definitions Functions --------- -.. - Once documentation is complete in capi.h, use: - .. doxygenfile:: capi.h - to populate this documentation without using - .. doxygenfunction:: - for every function. +.. c:function:: int openmc_calculate_volumes() -.. doxygenfunction:: openmc_calculate_volumes + Run a stochastic volume calculation -.. doxygenfunction:: openmc_cell_get_fill + :return: Return status (negative if an error occurred) + :rtype: int -.. doxygenfunction:: openmc_cell_get_id +.. c:function:: int openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) -.. doxygenfunction:: openmc_cell_get_temperature - -.. c:function:: int openmc_cell_get_density(int32_t index, const int32_t* instance, double* density) - - Get the density of a cell + Get the fill for a cell :param int32_t index: Index in the cells array - :param int32_t* instance: Which instance of the cell. If a null pointer is passed, the density - multiplier of the first instance is returned. - :param double* density: Density of the cell in [g/cm3] + :param int* type: Type of the fill + :param int32_t** indices: Array of material indices for cell + :param int32_t* n: Length of indices array + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_cell_get_id(int32_t index, int32_t* id) + + Get the ID of a cell + + :param int32_t index: Index in the cells array + :param int32_t* id: ID of the cell + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_cell_get_temperature(int32_t index, const int32_t* instance, double* T) + + Get the temperature of a cell + + :param int32_t index: Index in the cells array + :param int32_t* instance: Which instance of the cell. If a null pointer is passed, the temperature + of the first instance is returned. + :param double* T: temperature of the cell :return: Return status (negative if an error occurred) :rtype: int @@ -101,22 +113,8 @@ Functions :param double T: Temperature in Kelvin :param instance: Which instance of the cell. To set the temperature for all instances, pass a null pointer. - :param bool set_contained: If the cell is not filled by a material, whether - to set the temperatures of all filled cells - :type instance: const int32_t* - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_cell_set_density(index index, double density, const int32_t* instance, bool set_contained) - - Set the density of a cell. - - :param int32_t index: Index in the cells array - :param double density: Density of the cell in [g/cm3] - :param instance: Which instance of the cell. To set the density multiplier for all - instances, pass a null pointer. - :param bool set_contained: If the cell is not filled by a material, whether - to set the density multiplier of all filled cells + :param set_contained: If the cell is not filled by a material, whether to set the temperatures + of all filled cells :type instance: const int32_t* :return: Return status (negative if an error occurred) :rtype: int @@ -422,16 +420,6 @@ Functions :return: Return status (negative if an error occurred) :rtype: int -.. c:function:: int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh) - - Get the mesh for a mesh filter - - :param int32_t index: Index in the filters array - :param index_mesh: Index in the meshes array - :type index_mesh: int32_t* - :return: Return status (negative if an error occurred) - :rtype: int - .. c:function:: int openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh) Set the mesh for a mesh filter @@ -441,98 +429,6 @@ Functions :return: Return status (negative if an error occurred) :rtype: int -.. c:function:: int openmc_mesh_filter_get_translation(int32_t index, double translation[3]) - - Get the 3-D translation coordinates for a mesh filter - - :param int32_t index: Index in the filters array - :param double[3] translation: 3-D translation coordinates - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_mesh_filter_set_translation(int32_t index, double translation[3]) - - Set the 3-D translation coordinates for a mesh filter - - :param int32_t index: Index in the filters array - :param double[3] translation: 3-D translation coordinates - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshborn_filter_get_mesh(int32_t index, int32_t* index_mesh) - - Get the mesh for a meshborn filter - - :param int32_t index: Index in the filters array - :param index_mesh: Index in the meshes array - :type index_mesh: int32_t* - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshborn_filter_set_mesh(int32_t index, int32_t index_mesh) - - Set the mesh for a meshborn filter - - :param int32_t index: Index in the filters array - :param int32_t index_mesh: Index in the meshes array - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshborn_filter_get_translation(int32_t index, double translation[3]) - - Get the 3-D translation coordinates for a meshborn filter - - :param int32_t index: Index in the filters array - :param double[3] translation: 3-D translation coordinates - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshborn_filter_set_translation(int32_t index, double translation[3]) - - Set the 3-D translation coordinates for a meshborn filter - - :param int32_t index: Index in the filters array - :param double[3] translation: 3-D translation coordinates - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh) - - Get the mesh for a mesh surface filter - - :param int32_t index: Index in the filters array - :param index_mesh: Index in the meshes array - :type index_mesh: int32_t* - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh) - - Set the mesh for a mesh surface filter - - :param int32_t index: Index in the filters array - :param int32_t index_mesh: Index in the meshes array - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshsurface_filter_get_translation(int32_t index, double translation[3]) - - Get the 3-D translation coordinates for a mesh surface filter - - :param int32_t index: Index in the filters array - :param double[3] translation: 3-D translation coordinates - :return: Return status (negative if an error occurred) - :rtype: int - -.. c:function:: int openmc_meshsurface_filter_set_translation(int32_t index, double translation[3]) - - Set the 3-D translation coordinates for a mesh surface filter - - :param int32_t index: Index in the filters array - :param double[3] translation: 3-D translation coordinates - :return: Return status (negative if an error occurred) - :rtype: int - .. c:function:: int openmc_next_batch() Simulate next batch of particles. Must be called after openmc_simulation_init(). @@ -557,279 +453,6 @@ 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 @@ -851,10 +474,6 @@ 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 diff --git a/docs/source/conf.py b/docs/source/conf.py index 61740239b..4f88314f6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,10 +11,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import os -from pathlib import Path -import subprocess -import sys +import sys, os # Determine if we're on Read the Docs server on_rtd = os.environ.get('READTHEDOCS', None) == 'True' @@ -40,7 +37,6 @@ sys.path.insert(0, os.path.abspath('../..')) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'breathe', 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', @@ -51,14 +47,12 @@ extensions = [ ] if not on_rtd: extensions.append('sphinxcontrib.rsvgconverter') - doxygen_dir = Path(__file__).parents[1] / 'doxygen' - subprocess.run(['doxygen'], cwd=doxygen_dir, check=True) # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. -source_suffix = {'.rst': 'restructuredtext'} +source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' @@ -68,17 +62,16 @@ master_doc = 'index' # General information about the project. project = 'OpenMC' -copyright = '2011-2026, Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors' +copyright = '2011-2022, 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 # built documents. # - -import openmc - +# The short X.Y version. +version = "0.13" # The full version, including alpha/beta/rc tags. -version = release = openmc.__version__ +release = "0.13.1" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -123,17 +116,14 @@ pygments_style = 'tango' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] -# -- Options breathe + doxygen ------------------------------------------------- - -breathe_projects = {"OpenMC": "../doxygen/xml"} -breathe_default_project = "OpenMC" -breathe_domain_by_file_pattern = {"*capi.h": "c"} # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages -html_theme = 'sphinx_rtd_theme' -html_baseurl = "https://docs.openmc.org/en/stable/" +if not on_rtd: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_logo = '_images/openmc_logo.png' @@ -257,7 +247,7 @@ napoleon_use_ivar = True intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), 'numpy': ('https://numpy.org/doc/stable/', None), - 'scipy': ('https://docs.scipy.org/doc/scipy/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), - 'matplotlib': ('https://matplotlib.org/stable/', None) + 'matplotlib': ('https://matplotlib.org/', None) } diff --git a/docs/source/devguide/agentic-tools.rst b/docs/source/devguide/agentic-tools.rst deleted file mode 100644 index fed377cc0..000000000 --- a/docs/source/devguide/agentic-tools.rst +++ /dev/null @@ -1,104 +0,0 @@ -.. _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. diff --git a/docs/source/devguide/contributing.rst b/docs/source/devguide/contributing.rst index 5199c9438..c08b1a362 100644 --- a/docs/source/devguide/contributing.rst +++ b/docs/source/devguide/contributing.rst @@ -109,10 +109,9 @@ Leadership Team The TC consists of the following individuals: - `Paul Romano `_ -- `Patrick Shriwise `_ +- `Sterling Harper `_ - `Adam Nelson `_ -- `Jonathan Shimwell `_ -- `John Tramm `_ +- `Benoit Forget `_ The Project Lead is Paul Romano. diff --git a/docs/source/devguide/docbuild.rst b/docs/source/devguide/docbuild.rst index cda0307ca..38ef628df 100644 --- a/docs/source/devguide/docbuild.rst +++ b/docs/source/devguide/docbuild.rst @@ -5,19 +5,21 @@ Building Sphinx Documentation ============================= In order to build the documentation in the ``docs`` directory, you will need to -have the several third-party Python packages installed, including `Sphinx -`_. To install the necessary -prerequisites, provide the optional "docs" dependencies when installing OpenMC's -Python API. That is, from the root directory of the OpenMC repository: +have the `Sphinx `_ third-party Python +package. The easiest way to install Sphinx is via pip: .. code-block:: sh - python -m pip install ".[docs]" + pip install sphinx -The OpenMC documentation also uses Doxygen to automatically generate its -C/C++ API documentation directly from the docstrings available in the source -code. You will need to have a working installation of Doxygen to generate the -documentation locally. +Additionally, you will need several Sphinx extensions that can be installed +directly with pip: + +.. code-block:: sh + + pip install sphinx-numfig + pip install sphinxcontrib-katex + pip install sphinxcontrib-svg2pdfconverter ----------------------------------- Building Documentation as a Webpage diff --git a/docs/source/devguide/docker.rst b/docs/source/devguide/docker.rst index 50ff29bd2..0b2191168 100644 --- a/docs/source/devguide/docker.rst +++ b/docs/source/devguide/docker.rst @@ -45,11 +45,12 @@ Now you can run the following to create a `Docker container`_ called This command will open an interactive shell running from within the Docker container where you have access to use OpenMC. -.. note:: The ``docker run`` command supports many options_ +.. note:: The ``docker run`` command supports many + `options `_ for spawning containers -- including `mounting volumes`_ from the host filesystem -- which many users will find useful. -.. _Docker image: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-an-image/ +.. _Docker image: https://docs.docker.com/engine/reference/commandline/images/ .. _Docker container: https://www.docker.com/resources/what-container -.. _options: https://docs.docker.com/reference/cli/docker/container/run/ -.. _mounting volumes: https://docs.docker.com/engine/storage/volumes/ +.. _options: https://docs.docker.com/engine/reference/commandline/run/ +.. _mounting volumes: https://docs.docker.com/storage/volumes/ diff --git a/docs/source/devguide/index.rst b/docs/source/devguide/index.rst index 53b9f5853..d100fdcdf 100644 --- a/docs/source/devguide/index.rst +++ b/docs/source/devguide/index.rst @@ -14,9 +14,7 @@ other related topics. contributing workflow - agentic-tools styleguide - policies tests user-input docbuild diff --git a/docs/source/devguide/policies.rst b/docs/source/devguide/policies.rst deleted file mode 100644 index 3644ae822..000000000 --- a/docs/source/devguide/policies.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _devguide_policies: - -======== -Policies -======== - ---------------------- -Python Version Policy ---------------------- - -OpenMC follows the Scientific Python Ecosystem Coordination guidelines `SPEC 0 -`_ on minimum supported -versions, which recommends that support for Python versions be dropped 3 years -after their initial release. - -------------------- -C++ Standard Policy -------------------- - -C++ code in OpenMC must conform to the most recent C++ standard that is fully -supported in the `version of the gcc compiler -`_ that is distributed with the -oldest version of Ubuntu that is still within its `standard support period -`_. Ubuntu 22.04 LTS will be supported -through April 2027 and is distributed with gcc 11.4.0, which fully supports the -C++17 standard. - --------------------- -CMake Version Policy --------------------- - -Similar to the C++ standard policy, the minimum supported version of CMake -corresponds to whatever version is distributed with the oldest version of Ubuntu -still within its standard support period. Ubuntu 22.04 LTS is distributed with -CMake 3.22. diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index a5599566e..44d80915e 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -29,10 +29,6 @@ whenever a file is saved. For example, `Visual Studio Code `_ includes support for running clang-format. -.. note:: - 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 ------------- @@ -40,15 +36,14 @@ Follow the `C++ Core Guidelines`_ except when they conflict with another guideline listed here. For convenience, many important guidelines from that list are repeated here. -Conform to the C++17 standard. +Conform to the C++14 standard. Always use C++-style comments (``//``) as opposed to C-style (``/**/``). (It is more difficult to comment out a large section of code that uses C-style comments.) Do not use C-style casting. Always use the C++-style casts ``static_cast``, -``const_cast``, or ``reinterpret_cast``. (See `ES.49 -`_) +``const_cast``, or ``reinterpret_cast``. (See `ES.49 `_) Source Files ------------ @@ -56,7 +51,7 @@ Source Files Use a ``.cpp`` suffix for code files and ``.h`` for header files. Header files should always use include guards with the following style (See -`SF.8 `_): +`SF.8 `_): .. code-block:: C++ @@ -147,7 +142,7 @@ Style for Python code should follow PEP8_. Docstrings for functions and methods should follow numpydoc_ style. -Python code should work with Python 3.8+. +Python code should work with Python 3.6+. Use of third-party Python packages should be limited to numpy_, scipy_, matplotlib_, pandas_, and h5py_. Use of other third-party packages must be @@ -157,11 +152,11 @@ Prefer pathlib_ when working with filesystem paths over functions in the os_ module or other standard-library modules. Functions that accept arguments that represent a filesystem path should work with both strings and Path_ objects. -.. _C++ Core Guidelines: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines -.. _PEP8: https://peps.python.org/pep-0008/ +.. _C++ Core Guidelines: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ .. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html .. _numpy: https://numpy.org/ -.. _scipy: https://scipy.org/ +.. _scipy: https://www.scipy.org/ .. _matplotlib: https://matplotlib.org/ .. _pandas: https://pandas.pydata.org/ .. _h5py: https://www.h5py.org/ diff --git a/docs/source/devguide/tests.rst b/docs/source/devguide/tests.rst index 8627cbde2..d55713062 100644 --- a/docs/source/devguide/tests.rst +++ b/docs/source/devguide/tests.rst @@ -23,28 +23,25 @@ Prerequisites OpenMC in development/editable mode. With setuptools, this is accomplished by running:: - python -m pip install -e .[test] + python setup.py develop + + or using pip (recommended):: + + pip install -e .[test] - The test suite requires a specific set of cross section data in order for tests to pass. A download URL for the data that OpenMC expects can be found - within ``tools/ci/download-xs.sh``. Once the tarball is downloaded and - unpacked, set the :envvar:`OPENMC_CROSS_SECTIONS` environment variable to the - path of the ``cross_sections.xml`` file within the unpacked data. + within ``tools/ci/download-xs.sh``. - In addition to the HDF5 data, some tests rely on ENDF files. A download URL - for those can also be found in ``tools/ci/download-xs.sh``. Once the tarball - is downloaded and unpacked, set the :envvar:`OPENMC_ENDF_DATA` environment - variable to the top-level directory of the unpacked tarball. + for those can also be found in ``tools/ci/download-xs.sh``. - Some tests require `NJOY `_ 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 ------------- -To execute the Python test suite, go to the ``tests/`` directory and run:: +To execute the test suite, go to the ``tests/`` directory and run:: pytest @@ -54,65 +51,6 @@ installed and run:: pytest --cov=../openmc --cov-report=html -To execute the C++ test suite, go to your build directory and run:: - - ctest - -If you want to view testing output on failure run:: - - ctest --output-on-failure - -Possible Reasons for Test Failures ----------------------------------- - -You may find that when you run the test suite, not everything passes. First, -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 - ``-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). - Thus, if you are running on a CPU with many cores, you may need to limit the - number of OpenMP threads used. It is recommended to set the - :envvar:`OMP_NUM_THREADS` environment variable to 2. -- Recent versions of NumPy use instruction dispatch that may generate different - results depending the particular ISA that you are running on. To avoid issues, - you may need to disable AVX512 instructions. This can be done by setting the - :envvar:`NPY_DISABLE_CPU_FEATURES` environment variable to "AVX512F - AVX512_SKX". When NumPy/SciPy are built against OpenBLAS, you may also need to - limit the number of threads that OpenBLAS uses internally; this can be done by - setting the :envvar:`OPENBLAS_NUM_THREADS` environment variable to 1. - -Debugging Tests in CI ---------------------- - -Tests can be debugged in CI using a feature called -`tmate `_. -CI debugging can be -enabled by including "[gha-debug]" in the commit message. When the test fails, a -link similar to the one shown below will be provided in the GitHub Actions -output after failure occurs. Logging into the provided link will allow you to -debug the test in the CI environment. The following is an example of the output -shown in the CI log that provides the link to the tmate session: - -.. code-block:: text - :linenos: - - Created new session successfully - ssh 2VcykjU7vNdvAzEjQcc839GM2@nyc1.tmate.io - https://tmate.io/t/2VcykjU7vNdvAzEjQcc839GM2 - Entering main loop - Web shell: https://tmate.io/t/2VcykjU7vNdvAzEjQcc839GM2 - SSH: ssh 2VcykjU7vNdvAzEjQcc839GM2@nyc1.tmate.io - ... - - Generating XML Inputs --------------------- @@ -124,23 +62,6 @@ run:: pytest --build-inputs -Adding C++ Unit Tests ---------------------- - -The C++ test suite uses Catch2 integrated with CTest. Each header file should -have a corresponding test file in ``tests/cpp_unit_tests/``. If the test file -does not exist run:: - - touch test_.cpp - -The file must be added to the CMake build system in -``tests/cpp_unit_tests/CMakeLists.txt``. ``test_`` should -be added to ``TEST_NAMES``. - -To add a test case to ``test_.cpp`` ensure -``catch2/catch_test_macros.hpp`` is included. A unit test can then be added -using the ``TEST_CASE`` macro and the ``REQUIRE`` assertion from Catch2. - Adding Tests to the Regression Suite ------------------------------------ @@ -163,12 +84,6 @@ following files to your new test directory: compiler options during openmc configuration and build (e.g., no MPI, no debug/optimization). -For tests using the Python API, both the **inputs_true.dat** and -**results_true.dat** files can be generated automatically in the correct format -via:: - - pytest --update - In addition to this description, please see the various types of tests that are already included in the test suite to see how to create them. If all is implemented correctly, the new test will automatically be discovered by pytest. diff --git a/docs/source/devguide/user-input.rst b/docs/source/devguide/user-input.rst index bbae3b715..0bde0fb05 100644 --- a/docs/source/devguide/user-input.rst +++ b/docs/source/devguide/user-input.rst @@ -49,12 +49,23 @@ following steps should be followed to make changes to user input: written out to the statepoint or summary files and that the :class:`openmc.StatePoint` and :class:`openmc.Summary` classes read them in. +7. Finally, a set of `RELAX NG`_ schemas exists that enables validation of input + files. You should modify the RELAX NG schema for the file you changed. The + easiest way to do this is to change the `compact syntax`_ file + (e.g. ``src/relaxng/geometry.rnc``) and then convert it to regular XML syntax + using trang_:: + + trang geometry.rnc geometry.rng + For most user input additions and changes, it is simple enough to follow a "monkey see, monkey do" approach. When in doubt, contact your nearest OpenMC developer or send a message to the `developers mailing list`_. .. _property attribute: https://docs.python.org/3.6/library/functions.html#property -.. _XML Schema Part 2: https://www.w3.org/TR/xmlschema-2/ -.. _boolean: https://www.w3.org/TR/xmlschema-2/#boolean +.. _XML Schema Part 2: http://www.w3.org/TR/xmlschema-2/ +.. _boolean: http://www.w3.org/TR/xmlschema-2/#boolean +.. _RELAX NG: https://relaxng.org/ +.. _compact syntax: https://relaxng.org/compact-tutorial-20030326.html +.. _trang: https://relaxng.org/jclark/trang.html .. _developers mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-dev diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index c49326a20..6b5ec63cb 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -91,30 +91,6 @@ features and bug fixes. The general steps for contributing are as follows: 6. After the pull request has been thoroughly vetted, it is merged back into the *develop* branch of openmc-dev/openmc. -Setting Up Upstream Tracking (Required for Versioning) ------------------------------------------------------- - -By default, your fork **does not** include tags from the upstream OpenMC repository. -OpenMC relies on `git describe --tags` for versioning in source builds, and missing tags can lead -to incorrect version detection (i.e., ``0.0.0``). To ensure proper versioning, follow these steps: - -1. **Add the Upstream Repository** - This allows you to fetch updates from the main OpenMC repository. - - .. code-block:: sh - - git remote add upstream https://github.com/openmc-dev/openmc.git - -2. **Fetch and Push Tags** - Retrieve tags from the upstream repository and update your fork: - - .. code-block:: sh - - git fetch --tags upstream - git push --tags origin - -This ensures that both your **local** and **remote** fork have the correct versioning information. - Private Development ------------------- @@ -140,7 +116,7 @@ pip_. From the root directory of the OpenMC repository, run: .. code-block:: sh - python -m pip install -e .[test] + pip install -e .[test] This installs the OpenMC Python package in `"editable" mode `_ so that 1) @@ -150,10 +126,10 @@ reinstalling it). While the same effect can be achieved using the :envvar:`PYTHONPATH` environment variable, this is generally discouraged as it can interfere with virtual environments. -.. _git: https://git-scm.com/ +.. _git: http://git-scm.com/ .. _GitHub: https://github.com/ .. _git flow: https://nvie.com/git-model -.. _valgrind: https://valgrind.org/ +.. _valgrind: https://www.valgrind.org/ .. _style guide: https://docs.openmc.org/en/latest/devguide/styleguide.html .. _pull request: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests .. _openmc-dev/openmc: https://github.com/openmc-dev/openmc diff --git a/docs/source/index.rst b/docs/source/index.rst index 97666e7c3..a01055374 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,7 +12,7 @@ files produced by NJOY. Parallelism is enabled via a hybrid MPI and OpenMP programming model. OpenMC was originally developed by members of the `Computational Reactor Physics -Group `_ at the `Massachusetts Institute of Technology +Group `_ at the `Massachusetts Institute of Technology `_ starting in 2011. Various universities, laboratories, and other organizations now contribute to the development of OpenMC. For more information on OpenMC, feel free to post a message on the `OpenMC Discourse diff --git a/docs/source/io_formats/collision_track.rst b/docs/source/io_formats/collision_track.rst deleted file mode 100644 index 4123fdac6..000000000 --- a/docs/source/io_formats/collision_track.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. _io_collision_track: - -=========================== -Collision Track File Format -=========================== - -When collision tracking is enabled with ``mcpl=false`` (the default), OpenMC -writes binary data to an HDF5 file named ``collision_track.h5``. The same data -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.2. - -**/** - -:Attributes: - - **filetype** (*char[]*) -- String indicating the type of file. - For collision-track files the value is ``"collision_track"``. - -:Datasets: - - - **collision_track_bank** (Compound type) -- Collision information - for each stored event. Each entry in the dataset corresponds to one - collision and contains the following fields: - - - ``r`` (*double[3]*) -- Position of the collision in [cm]. - - ``u`` (*double[3]*) -- Direction unit vector immediately after the collision. - - ``E`` (*double*) -- Incident particle energy before the collision in [eV]. - - ``dE`` (*double*) -- Energy loss over the collision (:math:`E_\text{before} - E_\text{after}`) in [eV]. - - ``time`` (*double*) -- Time of the collision in [s]. - - ``wgt`` (*double*) -- Particle weight at the collision. - - ``event_mt`` (*int*) -- ENDF MT number identifying the reaction. - - ``delayed_group`` (*int*) -- Delayed neutron group index (non-zero for delayed events). - - ``cell_id`` (*int*) -- ID of the cell in which the collision occurred. - - ``nuclide_id`` (*int*) -- PDG number of the nuclide (100ZZZAAAM). - - ``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`` (*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 -as though it were produced serially. diff --git a/docs/source/io_formats/depletion_chain.rst b/docs/source/io_formats/depletion_chain.rst index 74413e7b6..89c76525f 100644 --- a/docs/source/io_formats/depletion_chain.rst +++ b/docs/source/io_formats/depletion_chain.rst @@ -56,27 +56,6 @@ attributes: .. _io_chain_reaction: --------------------- -```` Element --------------------- - -The ```` element represents photon and electron sources associated with -the decay of a nuclide and contains information to construct an -:class:`openmc.stats.Univariate` object that represents this emission as an -energy distribution. This element has the following attributes: - - :type: - The type of :class:`openmc.stats.Univariate` source term. - - :particle: - The type of particle emitted, e.g., 'photon' or 'electron' - - :parameters: - The parameters of the source term, e.g., for a - :class:`openmc.stats.Discrete` source, the energies (in [eV]) at which the - particles are emitted and their relative intensities in [Bq/atom] (in other - words, decay constants). - ---------------------- ```` Element ---------------------- diff --git a/docs/source/io_formats/depletion_results.rst b/docs/source/io_formats/depletion_results.rst index 856993db6..172c17ae6 100644 --- a/docs/source/io_formats/depletion_results.rst +++ b/docs/source/io_formats/depletion_results.rst @@ -4,7 +4,7 @@ Depletion Results File Format ============================= -The current version of the depletion results file format is 1.3. +The current version of the depletion results file format is 1.1. **/** @@ -12,31 +12,30 @@ The current version of the depletion results file format is 1.3. - **version** (*int[2]*) -- Major and minor version of the statepoint file format. -:Datasets: - **eigenvalues** (*double[][2]*) -- k-eigenvalues at each timestep. - This array has shape (number of timesteps, 2). The second axis - contains the eigenvalue and its associated uncertainty. - - **number** (*double[][][]*) -- Total number of atoms at each - timestep. This array has shape (number of timesteps, number of +:Datasets: - **eigenvalues** (*double[][][2]*) -- k-eigenvalues at each + time/stage. This array has shape (number of timesteps, number of + stages, value). The last axis contains the eigenvalue and the + associated uncertainty + - **number** (*double[][][][]*) -- Total number of atoms. This array + has shape (number of timesteps, number of stages, number of materials, number of nuclides). - - **reaction rates** (*double[][][][]*) -- Reaction rates at each - timestep. This array has shape (number of timesteps, number of - materials, number of nuclides, number of reactions). Only stored if - write_rates=True. + - **reaction rates** (*double[][][][][]*) -- Reaction rates used to + build depletion matrices. This array has shape (number of + timesteps, number of stages, number of materials, number of + nuclides, number of reactions). - **time** (*double[][2]*) -- Time in [s] at beginning/end of each step. - - **source_rate** (*double[]*) -- Power in [W] or source rate in - [neutron/sec] for each timestep. + - **source_rate** (*double[][]*) -- Power in [W] or source rate in + [neutron/sec]. This array has shape (number of timesteps, number + of stages). - **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//** :Attributes: - **index** (*int*) -- Index used in results for this material - **volume** (*double*) -- Volume of this material in [cm^3] - - **name** (*char[]*) -- Name of this material **/nuclides//** @@ -48,3 +47,10 @@ The current version of the depletion results file format is 1.3. **/reactions//** :Attributes: - **index** (*int*) -- Index user in results for this reaction + +.. note:: + + The reaction rates for some isotopes not originally present may + be non-zero, but should be negligible compared to other atoms. + This can be controlled by changing the + :class:`openmc.deplete.Operator` ``dilute_initial`` attribute. diff --git a/docs/source/io_formats/geometry.rst b/docs/source/io_formats/geometry.rst index 5cd18bef1..ac48e48d2 100644 --- a/docs/source/io_formats/geometry.rst +++ b/docs/source/io_formats/geometry.rst @@ -38,9 +38,11 @@ Each ```` element can have the following attributes or sub-elements: :boundary: The boundary condition for the surface. This can be "transmission", - "vacuum", "reflective", or "periodic". Specify which planes are - periodic and the code will automatically identify which planes are - paired together. + "vacuum", "reflective", or "periodic". Periodic boundary conditions can + only be applied to x-, y-, and z-planes. Only axis-aligned periodicity is + supported, i.e., x-planes can only be paired with x-planes. Specify which + planes are periodic and the code will automatically identify which planes + are paired together. *Default*: "transmission" @@ -316,10 +318,9 @@ the following attributes or sub-elements: *Default*: None :orientation: - The orientation of the hexagonal lattice. The string "x" indicates that each - lattice element has two faces that are perpendicular to the x-axis, whereas - the string "y" indicates that each lattice element has two faces that are - perpendicular to the y-axis. + The orientation of the hexagonal lattice. The string "x" indicates that two + sides of the lattice are parallel to the x-axis, whereas the string "y" + indicates that two sides are parallel to the y-axis. *Default*: "y" @@ -406,64 +407,13 @@ Each ```` element can have the following attributes or sub-eleme *Default*: None - :cell: - Zero or more ```` sub-elements may appear to override properties of - individual DAGMC volumes. Each ```` element supports the following - attributes and sub-elements: - :id: - The integer cell ID in the DAGMC geometry to override. Required. + .. note:: A geometry.xml file containing only a DAGMC model for a file named `dagmc.h5m` (no CSG) + looks as follows - :name: - An optional string label for the cell. + .. code-block:: xml - *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 greater than or equal - to 0. Multiple space-separated values may be given. - - *Default*: None - - :density: - Density in [g/cm³] to assign to the cell. Must be greater than 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 ```` attributes are **not** supported inside - ```` and will raise an error if present: ``region``, - ``fill``, ``universe``, ``translation``, ``rotation``. - - .. deprecated:: - The ```` sub-element (containing ```` - children with ````) is deprecated. A deprecation warning is - emitted and the overrides are converted to the ```` format at parse - time. It is an error to specify both ```` and - ```` sub-elements on the same ````. - - *Default*: None - -.. note:: A geometry.xml file containing only a DAGMC model for a file named - `dagmc.h5m` (no CSG) looks as follows: - - .. code-block:: xml - - - - - + + + + diff --git a/docs/source/io_formats/index.rst b/docs/source/io_formats/index.rst index 5b4efea66..8c89bd2a1 100644 --- a/docs/source/io_formats/index.rst +++ b/docs/source/io_formats/index.rst @@ -44,7 +44,6 @@ Output Files statepoint source - collision_track summary properties depletion_results @@ -52,4 +51,3 @@ Output Files track voxel volume - weight_windows diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 8a26311d1..f7f5387a4 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -133,10 +133,6 @@ Temperature-dependent data, provided for temperature 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. **//K/scatter_data/** diff --git a/docs/source/io_formats/particle_restart.rst b/docs/source/io_formats/particle_restart.rst index e0fe76b9d..53f86735f 100644 --- a/docs/source/io_formats/particle_restart.rst +++ b/docs/source/io_formats/particle_restart.rst @@ -4,7 +4,7 @@ Particle Restart File Format ============================ -The current version of the particle restart file format is 2.1. +The current version of the particle restart file format is 2.0. **/** @@ -26,7 +26,6 @@ The current version of the particle restart file format is 2.1. - **run_mode** (*char[]*) -- Run mode used, either 'fixed source', 'eigenvalue', or 'particle restart'. - **id** (*int8_t*) -- Unique identifier of the particle. - - **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 diff --git a/docs/source/io_formats/plots.rst b/docs/source/io_formats/plots.rst index 1a42a4281..e6b75eafc 100644 --- a/docs/source/io_formats/plots.rst +++ b/docs/source/io_formats/plots.rst @@ -7,18 +7,13 @@ Geometry Plotting Specification -- plots.xml Basic plotting capabilities are available in OpenMC by creating a plots.xml file and subsequently running with the ``--plot`` command-line flag. The root element of the plots.xml is simply ```` and any number output plots can be -defined with ```` sub-elements. Four plot types are currently implemented +defined with ```` sub-elements. Two plot types are currently implemented in openMC: * ``slice`` 2D pixel plot along one of the major axes. Produces a PNG image file. * ``voxel`` 3D voxel data dump. Produces an HDF5 file containing voxel xyz position and cell or material id. -* ``wireframe_raytrace`` 2D pixel plot of a three-dimensional view of a - geometry using wireframes around cells or materials and coloring by depth - through each material. -* ``solid_raytrace`` 2D pixel plot of a three-dimensional view of a geometry - with solid colored surfaces of a set of cells or materials. ------------------ @@ -71,22 +66,21 @@ sub-elements: *Default*: None - Required entry :type: - Keyword for type of plot to be produced. Currently "slice", "voxel", - "wireframe_raytrace", and "solid_raytrace" plots are implemented. The - "slice" plot type creates 2D pixel maps saved in the PNG file format. The - "voxel" plot type produces a binary datafile containing voxel grid - positioning and the cell or material (specified by the ``color`` tag) at the - center of each voxel. Voxel plot files can be processed into VTK files using - the :func:`openmc.voxel_to_vtk` function and subsequently viewed with a 3D - viewer such as VISIT or Paraview. See :ref:`io_voxel` for information about - the datafile structure. + Keyword for type of plot to be produced. Currently only "slice" and "voxel" + plots are implemented. The "slice" plot type creates 2D pixel maps saved in + the PNG file format. The "voxel" plot type produces a binary datafile + containing voxel grid positioning and the cell or material (specified by the + ``color`` tag) at the center of each voxel. Voxel plot files can be + processed into VTK files using the :ref:`scripts_voxel` script provided with + OpenMC and subsequently viewed with a 3D viewer such as VISIT or Paraview. + See the :ref:`io_voxel` for information about the datafile structure. .. note:: High-resolution voxel files produced by OpenMC can be quite large, but the equivalent VTK files will be significantly smaller. *Default*: "slice" -All ```` elements must contain the ``pixels`` +```` elements of ``type`` "slice" and "voxel" must contain the ``pixels`` attribute or sub-element: :pixels: @@ -102,7 +96,7 @@ attribute or sub-element: ``width``/``pixels`` along that basis direction may not appear in the plot. - *Default*: None - Required entry for all plots + *Default*: None - Required entry for "slice" and "voxel" plots ```` elements of ``type`` "slice" can also contain the following attributes or sub-elements. These are not used in "voxel" plots: @@ -131,11 +125,6 @@ attributes or sub-elements. These are not used in "voxel" plots: Specifies the custom color for the cell or material. Should be 3 integers separated by spaces. - :xs: - The attenuation coefficient for volume rendering of color in units of - inverse centimeters. Zero corresponds to transparency. Only for plot type - "wireframe_raytrace". - As an example, if your plot is colored by material and you want material 23 to be blue, the corresponding ``color`` element would look like: @@ -162,18 +151,6 @@ attributes or sub-elements. These are not used in "voxel" plots: *Default*: 255 255 255 (white) - :show_overlaps: - Indicates whether overlapping regions of different cells are shown. - - *Default*: None - - :overlap_color: - Specifies the RGB color of overlapping regions of different cells. Does not - do anything if ``show_overlaps`` is "false" or not specified. Should be 3 - integers separated by spaces. - - *Default*: 255 0 0 (red) - :meshlines: The ``meshlines`` sub-element allows for plotting the boundaries of a regular mesh on top of a plot. Only one ``meshlines`` element is allowed per @@ -202,80 +179,3 @@ attributes or sub-elements. These are not used in "voxel" plots: *Default*: 0 0 0 (black) *Default*: None - -```` elements of ``type`` "wireframe_raytrace" or "solid_raytrace" can contain the -following attributes or sub-elements. - - :camera_position: - Location in 3D Cartesian space the camera is at. - - - *Default*: None - Required for all ``wireframe_raytrace`` or - ``solid_raytrace`` plots - - :look_at: - Location in 3D Cartesian space the camera is looking at. - - - *Default*: None - Required for all ``wireframe_raytrace`` or - ``solid_raytrace`` plots - - :field_of_view: - The horizontal field of view in degrees. Defaults to roughly the same value - as for the human eye. - - *Default*: 70 - - :orthographic_width: - If set to a nonzero value, an orthographic rather than perspective - projection for the camera is employed. An orthographic projection puts out - parallel rays from the camera of a width prescribed here in the horizontal - direction, with the width in the vertical direction decided by the pixel - aspect ratio. - - *Default*: 0 - -```` elements of ``type`` "solid_raytrace" can contain the following attributes or -sub-elements. - - :opaque_ids: - List of integer IDs of cells or materials to be treated as visible in the - plot. Whether the integers are interpreted as cell or material IDs depends - on ``color_by``. - - *Default*: None - Required for all phong plots - - :light_position: - Location in 3D Cartesian space of the light. - - - *Default*: Same location as ``camera_position`` - - :diffuse_fraction: - Fraction of light originating from non-directional sources. If set to one, - the coloring is not influenced by surface curvature, and no shadows appear. - If set to zero, only regions illuminated by the light are not black. - - - *Default*: 0.1 - -```` elements of ``type`` "wireframe_raytrace" can contain the following -attributes or sub-elements. - - :wireframe_color: - RGB value of the wireframe's color - - *Default*: 0, 0, 0 (black) - - :wireframe_thickness: - Integer number of pixels that the wireframe takes up. The value is a radius - of the wireframe. Setting to zero removes any wireframing. - - *Default*: 0 - - :wireframe_ids: - Integer IDs of cells or materials of regions to draw wireframes around. - Whether the integers are interpreted as cell or material IDs depends on - ``color_by``. - - *Default*: None diff --git a/docs/source/io_formats/properties.rst b/docs/source/io_formats/properties.rst index 4cc5da379..5030e78f3 100644 --- a/docs/source/io_formats/properties.rst +++ b/docs/source/io_formats/properties.rst @@ -4,7 +4,7 @@ Properties File Format ====================== -The current version of the properties file format is 1.1. +The current version of the properties file format is 1.0. **/** @@ -25,7 +25,6 @@ The current version of the properties file format is 1.1. **/geometry/cells/cell /** :Datasets: - **temperature** (*double[]*) -- Temperature of the cell in [K]. - - **density** (*double[]*) -- Density of the cell in [g/cm3]. **/materials/** diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 7091757f2..1a8f63716 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -7,19 +7,6 @@ Settings Specification -- settings.xml All simulation parameters and miscellaneous options are specified in the settings.xml file. -------------------------------- -```` Element -------------------------------- - -The ```` 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 - --------------------- ```` Element --------------------- @@ -33,90 +20,6 @@ source neutrons. *Default*: None ------------------------------ -```` Element ------------------------------ - -The ```` element indicates to track information about particle -collisions based on a set of criteria and store these events in a file named -``collision_track.h5``. This file records details such as the position of the -interaction, direction of the incoming particle, incident energy and deposited -energy, weight, time of the interaction, and the delayed neutron group (0 for -prompt neutrons). Additional information such as the cell ID, material ID, -universe ID, nuclide ZAID, particle type, and event MT number are also stored. -Users can specify one or more criterion to filter collisions. If no criteria are -specified, it defaults to tracking all collisions across the model. - -.. warning:: - Storing all collisions can be very memory intensive. For more targeted - tracking, users can employ a variety of parameters such as ``cell_ids``, - ``reactions``, ``universe_ids``, ``material_ids``, ``nuclides``, and - ``deposited_E_threshold`` to refine the selection of particle interactions - to be banked. - -This element can contain one or more of the following attributes or -sub-elements: - - :max_collisions: - An integer indicating the maximum number of collisions to be banked per file. - - *Default*: 1000 - - :max_collision_track_files: - An integer indicating the number of collision_track files to be used. - - *Default*: 1 - - :mcpl: - An optional boolean to enable MCPL_-format instead of the native HDF5-based - format. If activated, the output file name and type is changed to - ``collision_track.mcpl``. - - *Default*: false - - .. _MCPL: https://mctools.github.io/mcpl/mcpl.pdf - - :cell_ids: - A list of integers representing cell IDs to define specific cells in which - collisions are to be banked. - - *Default*: None - - :universe_ids: - A list of integers representing the universe IDs to define specific - universes in which collisions are to be banked. - - *Default*: None - - :material_ids: - A list of integers representing the material IDs to define specific - materials in which collisions are to be banked. - - *Default*: None - - :nuclides: - A list of strings representing the nuclide, to define specific - define specific target nuclide collisions to be banked. - - .. note:: - Electron and positron collision-track events are not associated with - a specific nuclide. If a ``nuclides`` entry is specified, these events - are omitted. - - *Default*: None - - :reactions: - A list of integers representing the ENDF-6 format MT numbers or strings - (e.g. (n,fission)) to define specific reaction types to be banked. - - *Default*: None - - :deposited_E_threshold: - A float defining the minimum deposited energy per collision (in eV) to - trigger banking. - - *Default*: 0.0 - ---------------------------------- ```` Element ---------------------------------- @@ -129,17 +32,6 @@ standard deviation. *Default*: false -------------------------------------- -```` Element -------------------------------------- - -The ```` element indicates whether delayed neutrons -are created in fission. If this element is set to "true", delayed neutrons -will be created in fission events; otherwise only prompt neutrons will be -created. - - *Default*: true - ------------------------------------- ```` Element ------------------------------------- @@ -157,15 +49,13 @@ fission. ```` Element -------------------- -The ```` element indicates three kinds of cutoffs. The first is the -weight cutoff used below which particles undergo Russian roulette. Surviving -particles are assigned a user-determined weight. Note that weight cutoffs and -Russian rouletting are not turned on by default. The second is the energy cutoff -which is used to kill particles under certain energy. The energy cutoff should -not be used unless you know particles under the energy are of no importance to -results you care. The third is the time cutoff used to kill particles whose time -exceeds a specific cutoff. Particles will be killed exactly at the specified -time. +The ```` element indicates two kinds of cutoffs. The first is the weight +cutoff used below which particles undergo Russian roulette. Surviving particles +are assigned a user-determined weight. Note that weight cutoffs and Russian +rouletting are not turned on by default. The second is the energy cutoff which +is used to kill particles under certain energy. The energy cutoff should not be +used unless you know particles under the energy are of no importance to results +you care. This element has the following attributes/sub-elements: :weight: The weight below which particles undergo Russian roulette. @@ -178,13 +68,6 @@ time. *Default*: 1.0 - :survival_normalization: - If this element is set to "true", this will enable the use of survival - biasing source normalization, whereby the weight parameters, weight and - weight_avg, are multiplied per history by the start weight of said history. - - *Default*: false - :energy_neutron: The energy under which neutrons will be killed. @@ -205,26 +88,6 @@ time. *Default*: 0.0 - :time_neutron - The time above which neutrons will be killed. - - *Default*: Infinity - - :time_photon - The time above which photons will be killed. - - *Default*: Infinity - - :time_electron - The time above which electrons will be killed. - - *Default*: Infinity - - :time_positron - The time above which positorns will be killed. - - *Default*: Infinity - ---------------------------- ```` ---------------------------- @@ -275,16 +138,6 @@ history-based parallelism. *Default*: false --------------------------------- -```` Element --------------------------------- - -The ```` element specifies the energy multiplier, expressed -in units of :math:`kT`, that determines when the free gas scattering approach is -used for elastic scattering. Values must be positive. - - *Default*: 400.0 - ----------------------------------- ```` Element ----------------------------------- @@ -295,15 +148,6 @@ ignored for all run modes other than "eigenvalue". *Default*: 1 ------------------------------- -```` Element ------------------------------- - -The ```` element indicates the number of generations to -consider for the Iterated Fission Probability method. - - *Default*: 10 - ---------------------- ```` Element ---------------------- @@ -361,7 +205,7 @@ based on the recommended value in LA-UR-14-24530_. .. note:: This element is not used in the multi-group :ref:`energy_mode`. -.. _LA-UR-14-24530: https://mcnp.lanl.gov/pdf_files/TechReport_2014_LANL_LA-UR-14-24530_Brown.pdf +.. _LA-UR-14-24530: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-14-24530.pdf --------------------------- ```` @@ -375,45 +219,19 @@ to false. *Default*: true --------------------------------- -```` Element --------------------------------- - -This element indicates the maximum number of lost particles. - - *Default*: 10 - ------------------------------------- -```` Element ------------------------------------- - - -This element indicates the maximum number of lost particles, relative to the -total number of particles. - - *Default*: 1.0e-6 - -------------------------------------- +---------------------------------------- ```` Element -------------------------------------- +---------------------------------------- -This element indicates the number of particles to run in flight concurrently +This element indicates the number of neutrons to run in flight concurrently when using event-based parallelism. A higher value uses more memory, but may be more efficient computationally. *Default*: 100000 ---------------------------------- -```` Element ---------------------------------- - -This element indicates the maximum number of events a particle can undergo. - - *Default*: 1000000 - ------------------------ +--------------------------- ```` Element ------------------------ +--------------------------- The ```` element allows the user to set a maximum scattering order to apply to every nuclide/material in the problem. That is, if the data @@ -425,41 +243,6 @@ then, OpenMC will only use up to the :math:`P_1` data. .. note:: This element is not used in the continuous-energy :ref:`energy_mode`. --------------------------------- -```` Element --------------------------------- - -The ```` element indicates the number of times a particle -can split during a history. - - *Default*: 1000 - ------------------------------ -```` Element ------------------------------ - -The ```` element indicates the maximum secondary bank size. - - *Default*: 10000 - ------------------------- -```` Element ------------------------- - -The ```` element indicates the maximum number of tracks written to a -track file (per MPI process). - - *Default*: 1000 - --------------------------------------- -```` Element --------------------------------------- - -This ```` element indicates the maximum number of -particle restart files (per MPI process) to write for lost particles. - - *Default*: None - .. _mesh_element: ------------------ @@ -551,27 +334,6 @@ either "false" or "true". *Default*: false ------------------------ -```` Element ------------------------ - -The ```` element is used to set the seed for the pseudorandom number -generator during generation of colors in plots. - - *Default*: 1 - -.. _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 - --------------------- ```` Element --------------------- @@ -584,93 +346,6 @@ or sub-elements and can be set to either "false" or "true". .. note:: This element is not used in the multi-group :ref:`energy_mode`. ------------------------- -```` Element ------------------------- - -The ```` element enables random ray mode and contains a number of -settings relevant to the solver. Tips for selecting these parameters can be -found in the :ref:`random ray user guide `. - - :distance_inactive: - The inactive ray length (dead zone length) in [cm]. - - *Default*: None - - :distance_active: - The active ray length in [cm]. - - *Default*: None - - :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 - is only used to sample integrating ray starting locations and directions. - - *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". - - *Default*: prng - - :source_region_meshes: - Relates meshes to spatial domains for subdividing source regions with each domain. - - :mesh: - Contains an ``id`` attribute and one or more ```` sub-elements. - - :id: - The unique identifier for the mesh. - - :domain: - Each domain element has an ``id`` attribute and a ``type`` attribute. - - :id: - The unique identifier for the domain. - - :type: - The type of the domain. Can be ``material``, ``cell``, or ``universe``. - - :diagonal_stabilization_rho: - The rho factor for use with diagonal stabilization. This technique is - applied when negative diagonal (in-group) elements are detected in - the scattering matrix of input MGXS data, which is a common feature - of transport corrected MGXS data. - - *Default*: 1.0 - ---------------------------------- ```` Element ---------------------------------- @@ -746,19 +421,6 @@ pseudo-random number generator. *Default*: 1 ------------------------------------ -```` Element ------------------------------------ - - 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: - -------------------- ```` Element -------------------- @@ -776,32 +438,24 @@ attributes/sub-elements: *Default*: 1.0 - :type: - Indicator of source type. One of ``independent``, ``file``, ``compiled``, - ``mesh``, or ``tokamak``. The type of the source will be determined by this - attribute if it is present. - :particle: - 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``). + The source particle type, either ``neutron`` or ``photon``. *Default*: neutron :file: - If this attribute is given, it indicates that the source type is ``file``, - meaning particles are to be read from a binary source file whose path is - given by the value of this element. + If this attribute is given, it indicates that the source is to be read from + a binary source file whose path is given by the value of this element. Note, + the number of source sites needs to be the same as the number of particles + simulated in a fission source generation. *Default*: None :library: - If this attribute is given, it indicates that the source type is - ``compiled``, meaning that particles are instantiated from an externally - compiled source function. This source can be completely customized as needed - to define the source for your problem. The library has a few basic - requirements: + If this attribute is given, it indicates that the source is to be + instantiated from an externally compiled source function. This source can be + as complex as is required to define the source for your problem. The library + has a few basic requirements: * It must contain a class that inherits from ``openmc::Source``; * The class must implement a function called ``sample()``; @@ -809,15 +463,16 @@ attributes/sub-elements: as a unique pointer. This function can be used to pass parameters through to the source from the XML, if needed. - More documentation on how to build sources can be found in - :ref:`compiled_source`. + More documentation on how to build sources can be found in :ref:`custom_source`. + + *Default*: None :parameters: - If this attribute is given, it indicated that the source type is - ``compiled``. Its value provides the parameters to pass through to the class - generated using the ``library`` parameter. More documentation on how to - build parametrized sources can be found in - :ref:`parameterized_compiled_source`. + If this attribute is given, it provides the parameters to pass through to the + class generated using the ``library`` parameter . More documentation on how to + build parametrized sources can be found in :ref:`parameterized_custom_source`. + + *Default*: None :space: An element specifying the spatial distribution of source sites. This element @@ -825,37 +480,20 @@ attributes/sub-elements: :type: The type of spatial distribution. Valid options are "box", "fission", - "point", "cartesian", "cylindrical", "spherical", "mesh", and "cloud". - - A "box" spatial distribution has coordinates sampled uniformly in a - parallelepiped. - - A "fission" spatial distribution samples locations from a "box" + "point", "cartesian", "cylindrical", and "spherical". A "box" spatial + distribution has coordinates sampled uniformly in a parallelepiped. A + "fission" spatial distribution samples locations from a "box" distribution but only locations in fissionable materials are accepted. - A "point" spatial distribution has coordinates specified by a triplet. - A "cartesian" spatial distribution specifies independent distributions of - x-, y-, and z-coordinates. - - A "cylindrical" spatial distribution specifies independent distributions - of r-, phi-, and z-coordinates where phi is the azimuthal angle and the - origin for the cylindrical coordinate system is specified by origin. - - A "spherical" spatial distribution specifies independent distributions of - r-, cos_theta-, and phi-coordinates where cos_theta is the cosine of the - angle with respect to the z-axis, phi is the azimuthal angle, and the - sphere is centered on the coordinate (x0,y0,z0). - - A "mesh" spatial distribution samples source sites from a mesh element - based on the relative strengths provided in the node. Source locations - within an element are sampled isotropically. If no strengths are provided, - the space within the mesh is uniformly sampled. - - A "cloud" spatial distribution samples source sites from a list of spatial - positions provided in the node, based on the relative strengths provided - in the node. If no strengths are provided, the positions are uniformly - sampled. + x-, y-, and z-coordinates. A "cylindrical" spatial distribution specifies + independent distributions of r-, phi-, and z-coordinates where phi is the + azimuthal angle and the origin for the cylindrical coordinate system is + specified by origin. A "spherical" spatial distribution specifies + independent distributions of r-, cos_theta-, and phi-coordinates where + cos_theta is the cosine of the angle with respect to the z-axis, phi is + the azimuthal angle, and the sphere is centered on the coordinate + (x0,y0,z0). *Default*: None @@ -875,7 +513,6 @@ 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. @@ -907,10 +544,6 @@ 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 @@ -923,39 +556,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. - :mesh_id: - For "mesh" spatial distributions, this element specifies which mesh ID to - use for the geometric description of the mesh. - - :coords: - For "cloud" distributions, this element specifies a list of coordinates - for each of the points in the cloud. - - :strengths: - For "mesh" and "cloud" spatial distributions, this element specifies the - relative source strength of each mesh element or each point in the cloud. - - :volume_normalized: - For "mesh" spatial distributions, this optional boolean element specifies - whether the vector of relative strengths should be multiplied by the mesh - element volume. This is most common if the strengths represent a source - per unit volume. - - *Default*: false - - :bias: - For "mesh" and "cloud" spatial distributions, this optional element - specifies floating point values corresponding to alternative probabilities - for each value/component to use for biased sampling. - :angle: An element specifying the angular distribution of source sites. This element has the following attributes: @@ -988,10 +592,6 @@ attributes/sub-elements: are those of a univariate probability distribution (see the description in :ref:`univariate`). - :bias: - For "isotropic" angular distributions, this optional element specifies a - "mu-phi" angular distribution used for biased sampling. - :energy: An element specifying the energy distribution of source sites. The necessary sub-elements/attributes are those of a univariate probability distribution @@ -1007,125 +607,6 @@ attributes/sub-elements: *Default*: false - :mesh: - For mesh sources, this indicates the ID of the corresponding mesh. - - :source: - For mesh sources, this sub-element specifies the source for an individual - mesh element and follows the format for :ref:`source_element`. The number of - ```` sub-elements should correspond to the number of mesh elements. - - For a source with ``type="tokamak"``, the spatial distribution is described by - a Miller-style flux-surface parameterization and the following sub-elements - are used instead of the ``space`` element: - - :major_radius: - The major radius :math:`R_0` of the plasma in [cm]. - - :minor_radius: - The minor radius :math:`a` of the plasma in [cm]. Must be smaller than - ``major_radius``. - - :elongation: - The plasma elongation :math:`\kappa` (must be > 0). - - :triangularity: - The plasma triangularity :math:`\delta` (must be in [-1, 1]). Negative - values describe negative-triangularity plasmas. - - :shafranov_shift: - The Shafranov shift :math:`\Delta` in [cm] (must be >= 0 and less than - ``minor_radius``/2). - - :r_over_a: - A list of normalized minor-radius grid points :math:`r/a`. Must be strictly - increasing, start at 0, and end at 1. - - :emission_density: - A list of neutron emission densities :math:`S(r)` evaluated at each - ``r_over_a`` grid point (arbitrary units, must be non-negative). Only the - shape matters, since the profile is normalized internally. Values are - interpolated linearly between grid points and the profile is refined on an - internal grid for radial sampling. Must have the same length as - ``r_over_a`` and contain at least one positive value. - - :phi_start: - The starting toroidal angle in [rad]. - - *Default*: 0.0 - - :phi_extent: - The toroidal angle extent in [rad]. The source is sampled uniformly in - :math:`[\phi_\text{start},\ \phi_\text{start} + \phi_\text{extent}]`. - - *Default*: :math:`2\pi` - - :n_alpha: - The number of poloidal-angle grid points used to build the sampling CDFs - (must be > 2). Larger values reduce discretization bias; values below 51 - produce a warning. - - *Default*: 101 - - :vertical_shift: - A vertical shift of the plasma center in [cm]. - - *Default*: 0.0 - - :energy: - For a tokamak source, one or more ``energy`` sub-elements specify the - neutron energy distribution(s). Either a single distribution is given (used - at all radii) or exactly one distribution per ``r_over_a`` grid point is - given, in which case the energy is sampled from one of the two - distributions bracketing the sampled radius, selected stochastically with - probability proportional to the proximity of the radius to each grid point - (stochastic interpolation). Each follows the format of a univariate - probability distribution (see :ref:`univariate`). - - :time: - An optional ``time`` sub-element specifying the time distribution of source - particles, following the format of a univariate probability distribution - (see :ref:`univariate`). - - *Default*: particles are born at :math:`t=0` - - .. note:: Biased sampling can be applied to the spatial and energy distributions - of a source by using the ```` sub-element (see - :ref:`univariate` for details on how to specify bias distributions). - - :constraints: - This sub-element indicates the presence of constraints on sampled source - sites (see :ref:`usersguide_source_constraints` for details). It may have - the following sub-elements: - - :domain_ids: - The unique IDs of domains for which source sites must be within. - - *Default*: None - - :domain_type: - The type of each domain for source rejection ("cell", "material", or - "universe"). - - *Default*: None - - :fissionable: - A boolean indicating whether source sites must be sampled within a - material that is fissionable in order to be accepted. - - :time_bounds: - A pair of times in [s] indicating the lower and upper bound for a time - interval that source particles must be within. - - :energy_bounds: - A pair of energies in [eV] indicating the lower and upper bound for an - energy interval that source particles must be within. - - :rejection_strategy: - Either "resample", indicating that source sites should be resampled when - one is rejected, or "kill", indicating that a rejected source site is - assigned zero weight. - .. _univariate: Univariate Probability Distributions @@ -1139,19 +620,17 @@ variable and whose sub-elements/attributes are as follows: :type: The type of the distribution. Valid options are "uniform", "discrete", - "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 + "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 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. The - "decay_spectrum" option produces photon energies sampled from decay photon - spectra in a depletion chain (only used for energies). + fission spectrum (only used for energies). The "mixture" option produces samples + from univariate sub-distributions with given probabilities. *Default*: None @@ -1169,10 +648,6 @@ 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`. @@ -1191,51 +666,30 @@ variable and whose sub-elements/attributes are as follows: *Default*: histogram :pair: - For a "mixture" distribution, this element provides a distribution and its - corresponding probability. + For a "mixture" distribution, this element provides a distribution and its corresponding probability. :probability: - An attribute or ``pair`` that provides the probability of a univariate - distribution within a "mixture" distribution. + An attribute or ``pair`` that provides the probability of a univariate distribution within a "mixture" distribution. :dist: - This sub-element of a ``pair`` element provides information on the - corresponding univariate distribution. + 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. +------------------------- +```` Element +------------------------- -: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. +The ```` 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 ```` element. This element has the +following attributes/sub-elements: -:bias: - This optional element specifies a biased distribution for importance sampling. - For continuous distributions, the ``bias`` element should contain another - univariate distribution with the same support (interval) as the parent - distribution. For discrete distributions, the ``bias`` element should contain - floating point values corresponding to alternative probabilities for each - value/component to be used for biased sampling. + :batches: + A list of integers separated by spaces indicating at what batches a state + point file should be written. - *Default*: None - ---------------------------------------- -```` Element ---------------------------------------- - -The ```` element specifies the minimum fraction of -external source sites that must be accepted when applying rejection sampling -based on constraints. - - *Default*: 0.05 + *Default*: Last batch only -------------------------- ```` Element @@ -1278,40 +732,6 @@ attributes/sub-elements: *Default*: false - :mcpl: - If this element is set to "true", the source point file containing the - source bank will be written as an MCPL_ file name ``source.mcpl`` instead of - an HDF5 file. This option is only applicable if the ```` element - is set to true. - - *Default*: false - -------------------------- -```` Element -------------------------- - -The ```` 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 ```` 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 - --------------------- -```` Element --------------------- - -The ``stride`` element is used to specify how many random numbers are allocated -for each source particle history. - - *Default*: 152,917 - ------------------------------ ```` Element ------------------------------ @@ -1331,12 +751,7 @@ attributes/sub-elements: The ```` element triggers OpenMC to bank particles crossing certain surfaces and write out the source bank in a separate file called -``surface_source.h5``. One or multiple surface IDs and one cell ID can be used -to select the surfaces of interest. If no surface IDs are declared, every surface -of the model is eligible to bank particles. In that case, a cell ID (using -either the ``cell``, ``cellfrom`` or ``cellto`` attributes) can be used to select -every surface of a specific cell. This element has the following -attributes/sub-elements: +``surface_source.h5``. This element has the following attributes/sub-elements: :surface_ids: A list of integers separated by spaces indicating the unique IDs of surfaces @@ -1352,70 +767,6 @@ attributes/sub-elements: *Default*: None - :max_source_files: - An integer value indicating the number of surface source files to be written - containing the maximum number of particles each. The surface source bank - will be cleared in simulation memory each time a surface source file is - written. By default a ``surface_source.h5`` file will be created when the - maximum number of saved particles is reached. - - *Default*: 1 - - :mcpl: - An optional boolean which indicates if the banked particles should be - written to a file in the MCPL_-format instead of the native HDF5-based - format. If activated the output file name is changed to - ``surface_source.mcpl``. - - *Default*: false - - .. _MCPL: https://mctools.github.io/mcpl/mcpl.pdf - - :cell: - An integer representing the cell ID used to determine if particles crossing - identified surfaces are to be banked. Particles coming from or going to this - declared cell will be banked if they cross the identified surfaces. - - *Default*: None - - :cellfrom: - An integer representing the cell ID used to determine if particles crossing - identified surfaces are to be banked. Particles coming from this declared - cell will be banked if they cross the identified surfaces. - - *Default*: None - - :cellto: - An integer representing the cell ID used to determine if particles crossing - identified surfaces are to be banked. Particles going to this declared cell - will be banked if they cross the identified surfaces. - - *Default*: None - -.. note:: The ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be - used simultaneously. - -.. note:: Surfaces with boundary conditions that are not "transmission" or "vacuum" - are not eligible to store any particles when using ``cell``, ``cellfrom`` - or ``cellto`` attributes. It is recommended to use surface IDs instead. - ------------------------------------- -```` Element ------------------------------------- - -The ```` element specifies the surface flux cosine cutoff. - - *Default*: 0.001 - ------------------------------------ -```` Element ------------------------------------ - -The ```` element specifies the surface flux cosine -substitution ratio. - - *Default*: 0.5 - ------------------------------ ```` Element ------------------------------ @@ -1481,9 +832,7 @@ cell, the nearest temperature at which cross sections are given is to be applied, within a given tolerance (see :ref:`temperature_tolerance`). A value of "interpolation" indicates that cross sections are to be linear-linear interpolated between temperatures at which nuclear data are present (see -:ref:`temperature_treatment`). With the "interpolation" method, temperatures -outside of the bounds of the nuclear data may be accepted, provided they still -fall within the tolerance (see :ref:`temperature_tolerance`). +:ref:`temperature_treatment`). *Default*: "nearest" @@ -1522,12 +871,7 @@ The ```` element specifies a tolerance in Kelvin that is to be applied when the "nearest" temperature method is used. For example, if a cell temperature is 340 K and the tolerance is 15 K, then the closest temperature in the range of 325 K to 355 K will be used to evaluate cross -sections. If the ```` is "interpolation", the tolerance -specified applies to cell temperatures outside of the data bounds. For example, -if a cell is specified at 695K, a tolerance of 15K and data is only available -at 700K and 1000K, the cell's cross sections will be evaluated at 700K, since -the desired temperature of 695K is within the tolerance of the actual data -despite not being bounded on both sides. +sections. *Default*: 10 K @@ -1599,15 +943,6 @@ has the following attributes/sub-elements: for fixed source and small criticality calculations, but is very optimistic for highly coupled full-core reactor problems. -------------------------------------- -```` Element -------------------------------------- - -The ```` element indicates whether to sample among -multiple sources uniformly, applying their strengths as weights to sampled -particles. - - *Default*: False ------------------------ ```` Element @@ -1620,16 +955,6 @@ Agency Monte Carlo Performance Benchmark Problem," Proceedings of *Physor 2012*, Knoxville, TN (2012). The mesh should cover all possible fissionable materials in the problem and is specified using a :ref:`mesh_element`. -------------------------------- -```` Element -------------------------------- - -The ```` element indicates whether to produce decay photons -from neutron reactions instead of prompt photons. This is used in conjunction -with the direct 1-step method for shutdown dose rate calculations. - - *Default*: False - .. _verbosity: ----------------------- @@ -1661,14 +986,8 @@ The ```` element indicates that a stochastic volume calculation should be run at the beginning of the simulation. This element has the following sub-elements/attributes: - :domain_type: - The type of each domain for the volume calculation ("cell", "material", or - "universe"). - - *Default*: None - - :domain_ids: - The unique IDs of domains for which the volume should be estimated. + :cells: + The unique IDs of cells for which the volume should be estimated. *Default*: None @@ -1678,41 +997,16 @@ sub-elements/attributes: *Default*: None :lower_left: - The lower-left Cartesian coordinates of a bounding box that is used to - sample points within. + The lower-left Cartesian coordinates of a bounding box that is used to + sample points within. - *Default*: None + *Default*: None :upper_right: - The upper-right Cartesian coordinates of a bounding box that is used to - sample points within. + The upper-right Cartesian coordinates of a bounding box that is used to + sample points within. - *Default*: None - - :threshold: - Presence of a ```` sub-element indicates that the volume - calculation will be halted based on a threshold on the error. It has the - following sub-elements/attributes: - - :type: - The type of the trigger. Accepted options are "variance", "std_dev", - and "rel_err". - - :variance: - Variance of the mean, :math:`\sigma^2` - - :std_dev: - Standard deviation of the mean, :math:`\sigma` - - :rel_err: - Relative error of the mean, :math:`\frac{\sigma}{\mu}` - - *Default*: None - - :threshold: - The trigger's convergence criterion for the given type. - - *Default*: None + *Default*: None ---------------------------- ```` Element @@ -1731,10 +1025,9 @@ sub-elements/attributes: *Default*: None :particle_type: - The particle that the weight windows will apply to, specified as a PDG - code or string (e.g., ``neutron``). + The particle that the weight windows will apply to (e.g., 'neutron') - *Default*: 'neutron' + *Default*: None :energy_bins: Monotonically increasing list of bounding energies in [eV] to be used for @@ -1772,119 +1065,3 @@ sub-elements/attributes: Threshold below which particles will be terminated *Default*: :math:`10^{-38}` - --------------------------------------- -```` Element --------------------------------------- - -The ```` element provides information for creating a set of -mesh-based weight windows. - - :mesh: - ID of a mesh that is to be used for the weight windows spatial bins - - *Default*: None - - :energy_bounds: - The weight window energy bounds. If not present, the max/min energy of the - cross section data is applied as a single energy bin. - - *Default*: None - - :particle_type: - The particle that the weight windows will apply to, specified as a PDG - code or string (e.g., ``neutron``). - - *Default*: neutron - - :max_realizations: - The number of tally realizations after which the weight windows will stop updating. - - *Default*: 1 - - :update_interval: - The number of tally realizations between weight window updates. - - *Default*: 1 - - :on_the_fly: - Controls whether or not the tally results are reset after a weight window update. - - *Default*: true - - :method: - Method used to update weight window values (one of 'magic' or 'fw_cadis') - - *Default*: magic - - :update_parameters: - Method-specific update parameters used when generating/updating weight windows. - - For MAGIC: - - :value: - The type of tally value to use when creating weight windows (one of 'mean' or 'rel_err') - - *Default*: 'mean' - - :threshold: - The relative error threshold above which tally results will be ignored. - - *Default*: 1.0 - - :ratio: - 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 - ---------------------------------------- -```` Element ---------------------------------------- - -The ```` element indicates the checkpoints for weight -window split/roulette (surface, collision or both). This element has the -following sub-elements/attributes: - - :surface: - If set to "true", weight window checks will be performed at surface - crossings. - - *Default*: False - - :collision: - If set to "true", weight window checks will be performed at collisions. - - *Default*: True - --------------------------------------- -```` Element --------------------------------------- - - The ``weight_windows_file`` element has no attributes and contains the path to - a weight windows HDF5 file to load during simulation initialization. - -------------------------------- -```` Element -------------------------------- - - The ``weight_windows_on`` element indicates whether weight windows are - enabled. - - *Default*: False - ----------------------------------- -```` Element ----------------------------------- - - The ``write_initial_source`` element indicates whether to write the initial - source distribution to file. - - *Default*: False diff --git a/docs/source/io_formats/source.rst b/docs/source/io_formats/source.rst index 2e81e0a3f..4ce2229ed 100644 --- a/docs/source/io_formats/source.rst +++ b/docs/source/io_formats/source.rst @@ -15,8 +15,6 @@ 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: @@ -24,5 +22,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 (PDG number), - respectively. + delayed group, surface ID, and particle type (0=neutron, 1=photon, + 2=electron, 3=positron), respectively. diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 7d7765b84..c1598f2c3 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -4,7 +4,7 @@ State Point File Format ======================= -The current version of the statepoint file format is 18.2. +The current version of the statepoint file format is 17.0. **/** @@ -23,7 +23,6 @@ The current version of the statepoint file format is 18.2. bank is present (1) or not (0). :Datasets: - **seed** (*int8_t*) -- Pseudo-random number generator seed. - - **stride** (*uint64_t*) -- Pseudo-random number generator stride. - **energy_mode** (*char[]*) -- Energy mode of the run, either 'continuous-energy' or 'multi-group'. - **run_mode** (*char[]*) -- Run mode used, either 'eigenvalue' or @@ -56,8 +55,8 @@ The current version of the statepoint file format is 18.2. ``time``, ``wgt``, ``delayed_group``, ``surf_id``, and ``particle``, which represent the position, direction, energy, time, weight, delayed group, surface ID, and particle type - (PDG number), respectively. Only present when `run_mode` is - 'eigenvalue'. + (0=neutron, 1=photon, 2=electron, 3=positron), respectively. Only + present when `run_mode` is 'eigenvalue'. **/tallies/** @@ -69,39 +68,21 @@ The current version of the statepoint file format is 18.2. :Attributes: - **n_meshes** (*int*) -- Number of meshes in the problem. - **ids** (*int[]*) -- User-defined unique ID of each mesh. -.. _mesh-spec-hdf5: - **/tallies/meshes/mesh /** -:Attributes: - **id** (*int*) -- ID of the mesh - -:Datasets: - **name** (*char[]*) -- Name of the mesh. - - **type** (*char[]*) -- Type of mesh. +:Datasets: - **type** (*char[]*) -- Type of mesh. - **dimension** (*int*) -- Number of mesh cells in each dimension. - - **Regular Mesh Only:** - - **lower_left** (*double[]*) -- Coordinates of lower-left corner of - mesh. - - **upper_right** (*double[]*) -- Coordinates of upper-right corner - of mesh. - - **width** (*double[]*) -- Width of each mesh cell in each - dimension. - - **Rectilinear Mesh Only:** - - **x_grid** (*double[]*) -- Mesh divisions along the x-axis. - - **y_grid** (*double[]*) -- Mesh divisions along the y-axis. - - **z_grid** (*double[]*) -- Mesh divisions along the z-axis. - - **Cylindrical & Spherical Mesh Only:** - - **r_grid** (*double[]*) -- The mesh divisions along the r-axis. - - **phi_grid** (*double[]*) -- The mesh divisions along the phi-axis. - - **origin** (*double[]*) -- The origin in cartesian coordinates. - - **Spherical Mesh Only:** - - **theta_grid** (*double[]*) -- The mesh divisions along the theta-axis. + - **lower_left** (*double[]*) -- Coordinates of lower-left corner of + mesh. + - **upper_right** (*double[]*) -- Coordinates of upper-right corner + of mesh. + - **width** (*double[]*) -- Width of each mesh cell in each + dimension. - **Unstructured Mesh Only:** - **filename** (*char[]*) -- Name of the mesh file. - - **library** (*char[]*) -- Mesh library used to represent the + - **library** (*char[]*) -- Mesh library used to represent the mesh ("moab" or "libmesh"). - **length_multiplier** (*double*) Scaling factor applied to the mesh. - - **options** (*char[]*) -- Special options that control spatial - search data structures used. - **volumes** (*double[]*) -- Volume of each mesh cell. - **vertices** (*double[]*) -- x, y, z values of the mesh vertices. - **connectivity** (*int[]*) -- Connectivity array for the mesh @@ -128,10 +109,6 @@ The current version of the statepoint file format is 18.2. - **y** (*double[]*) -- Interpolant values for energyfunction interpolation. Only used for 'energyfunction' filters. - :Attributes: - - **interpolation** (*int*) -- Interpolation type. Only used for - 'energyfunction' filters. - **/tallies/derivatives/derivative /** :Datasets: - **independent variable** (*char[]*) -- Independent variable of @@ -147,10 +124,6 @@ The current version of the statepoint file format is 18.2. - **internal** (*int*) -- Flag indicating the presence of tally data (0) or absence of tally data (1). All user defined tallies will have a value of 0 unless otherwise instructed. - - **multiply_density** (*int*) -- Flag indicating whether reaction - rates should be multiplied by atom density (1) or not (0). - - **higher_moments** (*int*) -- Flag indicating whether - higher-order tally moments are enabled (1) or not (0). :Datasets: - **n_realizations** (*int*) -- Number of realizations. - **n_filters** (*int*) -- Number of filters used. diff --git a/docs/source/io_formats/summary.rst b/docs/source/io_formats/summary.rst index 64ca68b9c..c140d98ae 100644 --- a/docs/source/io_formats/summary.rst +++ b/docs/source/io_formats/summary.rst @@ -4,7 +4,7 @@ Summary File Format =================== -The current version of the summary file format is 6.1. +The current version of the summary file format is 6.0. **/** @@ -38,7 +38,6 @@ The current version of the summary file format is 6.1. is an array if the cell uses distributed materials, otherwise it is a scalar. - **temperature** (*double[]*) -- Temperature of the cell in Kelvin. - - **density** (*double[]*) -- Density of the cell in [g/cm3]. - **translation** (*double[3]*) -- Translation applied to the fill universe. This dataset is present only if fill_type is set to 'universe'. @@ -61,11 +60,9 @@ The current version of the summary file format is 6.1. - **coefficients** (*double[]*) -- Array of coefficients that define the surface. See :ref:`surface_element` for what coefficients are defined for each surface type. - - **boundary_type** (*char[]*) -- Boundary condition applied to - the surface. Can be 'transmission', 'vacuum', 'reflective', - 'periodic', or 'white'. - - **albedo** (*double*) -- Boundary albedo as a positive multiplier - of particle weight. If absent, it is assumed to be 1.0. + - **boundary_condition** (*char[]*) -- Boundary condition applied to + the surface. Can be 'transmission', 'vacuum', 'reflective', or + 'periodic'. - **geom_type** (*char[]*) -- Type of geometry used to create the cell. Either 'csg' or 'dagmc'. diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index dc57e5775..8594bb11c 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -69,12 +69,6 @@ The ```` element accepts the following sub-elements: list of valid scores can be found in the :ref:`user's guide `. - :multiply_density: - A boolean that indicates whether reaction rate scores should be computed by - multiplying by the atom density of a nuclide present in a material. - - *Default*: true - :trigger: Precision trigger applied to all filter bins and nuclides for this tally. It must specify the trigger's type, threshold and scores to which it will @@ -100,18 +94,6 @@ The ```` element accepts the following sub-elements: *Default*: None - :ignore_zeros: - Whether to allow zero tally bins to be ignored when assessing the - convergece of the precision trigger. If True, only nonzero tally scores - will be compared to the trigger's threshold. - - .. note:: The ``ignore_zeros`` option can cause the tally trigger to fire - prematurely if there are no hits in any bins at the first - evalulation. It is the user's responsibility to specify enough - particles per batch to get a nonzero score in at least one bin. - - *Default*: False - :scores: The score(s) in this tally to which the trigger should be applied. @@ -142,9 +124,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", "particle", and "particleproduction". + "cellborn", "surface", "material", "universe", "energy", "energyout", "mu", + "polar", "azimuthal", "mesh", "distribcell", "delayedgroup", + "energyfunction", and "particle". :bins: A description of the bins for each type of filter can be found in @@ -318,34 +300,8 @@ should be set to: they use ``energy`` and ``y``. :particle: - 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 - - - photon neutron - 0.0 1.0e5 1.0e6 20.0e6 - + A list of integers indicating the type of particles to tally ('neutron' = 1, + 'photon' = 2, 'electron' = 3, 'positron' = 4). ------------------ ```` Element @@ -355,11 +311,6 @@ If a mesh is desired as a filter for a tally, it must be specified in a separate element with the tag name ````. This element has the following attributes/sub-elements: - :name: - An optional string name to identify the mesh in output files. - - *Default*: "" - :type: The type of mesh. This can be either "regular", "rectilinear", "cylindrical", "spherical", or "unstructured". @@ -400,17 +351,10 @@ attributes/sub-elements: :theta_grid: The mesh divisions along the theta-axis. (For spherical mesh only.) - :origin: - The origin in cartesian coordinates. (For cylindrical and spherical meshes only.) - :library: The mesh library used to represent an unstructured mesh. This can be either "moab" or "libmesh". (For unstructured mesh only.) - :options: - Special options that control spatial search data structures used. (For - unstructured mesh using MOAB only) - :filename: The name of the mesh file to be loaded at runtime. (For unstructured mesh only.) diff --git a/docs/source/io_formats/track.rst b/docs/source/io_formats/track.rst index 9c05ac4c3..a97d75e58 100644 --- a/docs/source/io_formats/track.rst +++ b/docs/source/io_formats/track.rst @@ -4,7 +4,7 @@ Track File Format ================= -The current revision of the particle track file format is 3.1. +The current revision of the particle track file format is 3.0. **/** @@ -32,5 +32,6 @@ The current revision of the particle track file format is 3.1. the array for each primary/secondary particle. The last offset should match the total size of the array. - - **particles** (*int32_t[]*) -- Particle type for - each primary/secondary particle (PDG number). + - **particles** (*int[]*) -- Particle type for each + primary/secondary particle (0=neutron, 1=photon, + 2=electron, 3=positron). diff --git a/docs/source/io_formats/weight_windows.rst b/docs/source/io_formats/weight_windows.rst deleted file mode 100644 index 302e89318..000000000 --- a/docs/source/io_formats/weight_windows.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. _io_weight_windows: - -==================== -Weight Window Format -==================== - -The current revision of the weight window file format is 1.0. - -**/** - -:Attributes: - **filetype** (*char[]*) -- String indicating the type of file. - - **version** (*int[2]*) -- Major and minor version of the weight - window file format. - -**/weight_windows/** - -:Attributes: - **n_weight_windows** (*int*) -- Number of weight window objects in the file. - - **ids** (*int[]*) -- Unique IDs of weight window objects in the file. - -**/weight_windows/weight_windows_/** - -:Datasets: - **mesh** (*int*) -- ID of the mesh associated with the weight window object. - - **particle_type** (*char[]*) -- Particle type to which the weight windows apply. - - **energy_bounds** (*double[]*) -- Energy bounds of the weight windows in [eV] - - **lower_ww_bounds** (*double[]*) -- Weight window lower bounds. - - **upper_ww_bounds** (*double[]*) -- Weight window upper bounds. - - **survival_ratio** (*double*) -- Weight window survival ratio. - - **max_lower_bound_ratio** (*double*) -- Maximum particle weight to lower weight window bound ratio. - - **max_split** (*int*) -- Maximum number of splits per weight window check. - - **weight_cutoff** (*double*) -- Particle weight cutoff. - -**/meshes/** - -:Attributes: - **n_meshes** (*int*) -- Number of meshes in the file. - - **ids** (*int[]*) -- User-defined unique ID of each mesh. - -**/meshes/mesh /** - -Please see the section on **/tallies/meshes/** in the :doc:`statepoint`. diff --git a/docs/source/license.rst b/docs/source/license.rst index 1ec9fc04a..9d2638bfb 100644 --- a/docs/source/license.rst +++ b/docs/source/license.rst @@ -4,7 +4,7 @@ License Agreement ================= -Copyright © 2011-2026 Massachusetts Institute of Technology, UChicago Argonne +Copyright © 2011-2022 Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/docs/source/methods/charged_particles_physics.rst b/docs/source/methods/charged_particles_physics.rst deleted file mode 100644 index 5d763074f..000000000 --- a/docs/source/methods/charged_particles_physics.rst +++ /dev/null @@ -1,362 +0,0 @@ -.. _methods_charged_particle_physics: - -======================== -Charged Particle Physics -======================== - -OpenMC neglects the spatial transport of charged particles (electrons and -positrons), assuming they deposit all their energy locally and produce -bremsstrahlung photons at their birth location. This approximation, called -thick-target bremsstrahlung (TTB) approximation is justified by the fact that -charged particles have much shorter stopping ranges compared to neutrons and -photons, especially in high-density materials. - ------------------------------ -Charged Particle Interactions ------------------------------ - -Bremsstrahlung --------------- - -When a charged particle is decelerated in the field of an atom, some of its -kinetic energy is converted into electromagnetic radiation known as -bremsstrahlung, or 'braking radiation'. In each event, an electron or positron -with kinetic energy :math:`T` generates a photon with an energy :math:`E` -between :math:`0` and :math:`T`. Bremsstrahlung is described by a cross section -that is differential in photon energy, in the direction of the emitted photon, -and in the final direction of the charged particle. However, in Monte Carlo -simulations it is typical to integrate over the angular variables to obtain a -single differential cross section with respect to photon energy, which is often -expressed in the form - -.. math:: - :label: bremsstrahlung-dcs - - \frac{d\sigma_{\text{br}}}{dE} = \frac{Z^2}{\beta^2} \frac{1}{E} - \chi(Z, T, \kappa), - -where :math:`\kappa = E/T` is the reduced photon energy and :math:`\chi(Z, T, -\kappa)` is the scaled bremsstrahlung cross section, which is experimentally -measured. - -Because electrons are attracted to atomic nuclei whereas positrons are -repulsed, the cross section for positrons is smaller, though it approaches that -of electrons in the high energy limit. To obtain the positron cross section, we -multiply :eq:`bremsstrahlung-dcs` by the :math:`\kappa`-independent factor used -in Salvat_, - -.. math:: - :label: positron-factor - - \begin{aligned} - F_{\text{p}}(Z,T) = - & 1 - \text{exp}(-1.2359\times 10^{-1}t + 6.1274\times 10^{-2}t^2 - 3.1516\times 10^{-2}t^3 \\ - & + 7.7446\times 10^{-3}t^4 - 1.0595\times 10^{-3}t^5 + 7.0568\times 10^{-5}t^6 \\ - & - 1.8080\times 10^{-6}t^7), - \end{aligned} - -where - -.. math:: - :label: positron-factor-t - - t = \ln\left(1 + \frac{10^6}{Z^2}\frac{T}{\text{m}_\text{e}c^2} \right). - -:math:`F_{\text{p}}(Z,T)` is the ratio of the radiative stopping powers for -positrons and electrons. Stopping power describes the average energy loss per -unit path length of a charged particle as it passes through matter: - -.. math:: - :label: stopping-power - - -\frac{dT}{ds} = n \int E \frac{d\sigma}{dE} dE \equiv S(T), - -where :math:`n` is the number density of the material and :math:`d\sigma/dE` is -the cross section differential in energy loss. The total stopping power -:math:`S(T)` can be separated into two components: the radiative stopping -power :math:`S_{\text{rad}}(T)`, which refers to energy loss due to -bremsstrahlung, and the collision stopping power :math:`S_{\text{col}}(T)`, -which refers to the energy loss due to inelastic collisions with bound -electrons in the material that result in ionization and excitation. The -radiative stopping power for electrons is given by - -.. math:: - :label: radiative-stopping-power - - S_{\text{rad}}(T) = n \frac{Z^2}{\beta^2} T \int_0^1 \chi(Z,T,\kappa) - d\kappa. - - -To obtain the radiative stopping power for positrons, -:eq:`radiative-stopping-power` is multiplied by :eq:`positron-factor`. - -While the models for photon interactions with matter described above can safely -assume interactions occur with free atoms, sampling the target atom based on -the macroscopic cross sections, molecular effects cannot necessarily be -disregarded for charged particle treatment. For compounds and mixtures, the -bremsstrahlung cross section is calculated using Bragg's additivity rule as - -.. math:: - :label: material-bremsstrahlung-dcs - - \frac{d\sigma_{\text{br}}}{dE} = \frac{1}{\beta^2 E} \sum_i \gamma_i Z^2_i - \chi(Z_i, T, \kappa), - -where the sum is over the constituent elements and :math:`\gamma_i` is the -atomic fraction of the :math:`i`-th element. Similarly, the radiative stopping -power is calculated using Bragg's additivity rule as - -.. math:: - :label: material-radiative-stopping-power - - S_{\text{rad}}(T) = \sum_i w_i S_{\text{rad},i}(T), - -where :math:`w_i` is the mass fraction of the :math:`i`-th element and -:math:`S_{\text{rad},i}(T)` is found for element :math:`i` using -:eq:`radiative-stopping-power`. The collision stopping power, however, is a -function of certain quantities such as the mean excitation energy :math:`I` and -the density effect correction :math:`\delta_F` that depend on molecular -properties. These quantities cannot simply be summed over constituent elements -in a compound, but should instead be calculated for the material. The Bethe -formula can be used to find the collision stopping power of the material: - -.. math:: - :label: material-collision-stopping-power - - S_{\text{col}}(T) = \frac{2 \pi r_e^2 m_e c^2}{\beta^2} N_A \frac{Z}{A_M} - [\ln(T^2/I^2) + \ln(1 + \tau/2) + F(\tau) - \delta_F(T)], - -where :math:`N_A` is Avogadro's number, :math:`A_M` is the molar mass, -:math:`\tau = T/m_e`, and :math:`F(\tau)` depends on the particle type. For -electrons, - -.. math:: - :label: F-electron - - F_{-}(\tau) = (1 - \beta^2)[1 + \tau^2/8 - (2\tau + 1) \ln2], - -while for positrons - -.. math:: - :label: F-positron - - F_{+}(\tau) = 2\ln2 - (\beta^2/12)[23 + 14/(\tau + 2) + 10/(\tau + 2)^2 + - 4/(\tau + 2)^3]. - -The density effect correction :math:`\delta_F` takes into account the reduction -of the collision stopping power due to the polarization of the material the -charged particle is passing through by the electric field of the particle. -It can be evaluated using the method described by Sternheimer_, where the -equation for :math:`\delta_F` is - -.. math:: - :label: density-effect-correction - - \delta_F(\beta) = \sum_{i=1}^n f_i \ln[(l_i^2 + l^2)/l_i^2] - - l^2(1-\beta^2). - -Here, :math:`f_i` is the oscillator strength of the :math:`i`-th transition, -given by :math:`f_i = n_i/Z`, where :math:`n_i` is the number of electrons in -the :math:`i`-th subshell. The frequency :math:`l` is the solution of the -equation - -.. math:: - :label: density-effect-l - - \frac{1}{\beta^2} - 1 = \sum_{i=1}^{n} \frac{f_i}{\bar{\nu}_i^2 + l^2}, - -where :math:`\bar{v}_i` is defined as - -.. math:: - :label: density-effect-nubar - - \bar{\nu}_i = h\nu_i \rho / h\nu_p. - -The plasma energy :math:`h\nu_p` of the medium is given by - -.. math:: - :label: plasma-frequency - - h\nu_p = \sqrt{\frac{(hc)^2 r_e \rho_m N_A Z}{\pi A}}, - -where :math:`A` is the atomic weight and :math:`\rho_m` is the density of the -material. In :eq:`density-effect-nubar`, :math:`h\nu_i` is the oscillator -energy, and :math:`\rho` is an adjustment factor introduced to give agreement -between the experimental values of the oscillator energies and the mean -excitation energy. The :math:`l_i` in :eq:`density-effect-correction` are -defined as - -.. math:: - :label: density-effect-li - - \begin{aligned} - l_i &= (\bar{\nu}_i^2 + 2/3f_i)^{1/2} ~~~~&\text{for}~~ \bar{\nu}_i > 0 \\ - l_n &= f_n^{1/2} ~~~~&\text{for}~~ \bar{\nu}_n = 0, - \end{aligned} - -where the second case applies to conduction electrons. For a conductor, -:math:`f_n` is given by :math:`n_c/Z`, where :math:`n_c` is the effective -number of conduction electrons, and :math:`v_n = 0`. The adjustment factor -:math:`\rho` is determined using the equation for the mean excitation energy: - -.. math:: - :label: mean-excitation-energy - - \ln I = \sum_{i=1}^{n-1} f_i \ln[(h\nu_i\rho)^2 + 2/3f_i(h\nu_p)^2]^{1/2} + - f_n \ln (h\nu_pf_n^{1/2}). - -.. _ttb: - - -Thick-Target Bremsstrahlung Approximation -+++++++++++++++++++++++++++++++++++++++++ - -Since charged particles lose their energy on a much shorter distance scale than -neutral particles, not much error should be introduced by neglecting to -transport electrons. However, the bremsstrahlung emitted from high energy -electrons and positrons can travel far from the interaction site. Thus, even -without a full electron transport mode it is necessary to model bremsstrahlung. -We use a thick-target bremsstrahlung (TTB) approximation based on the models in -Salvat_ and Kaltiaisenaho_ for generating bremsstrahlung photons, which assumes -the charged particle loses all its energy in a single homogeneous material -region. - -To model bremsstrahlung using the TTB approximation, we need to know the number -of photons emitted by the charged particle and the energy distribution of the -photons. These quantities can be calculated using the continuous slowing down -approximation (CSDA). The CSDA assumes charged particles lose energy -continuously along their trajectory with a rate of energy loss equal to the -total stopping power, ignoring fluctuations in the energy loss. The -approximation is useful for expressing average quantities that describe how -charged particles slow down in matter. For example, the CSDA range approximates -the average path length a charged particle travels as it slows to rest: - -.. math:: - :label: csda-range - - R(T) = \int^T_0 \frac{dT'}{S(T')}. - -Actual path lengths will fluctuate around :math:`R(T)`. The average number of -photons emitted per unit path length is given by the inverse bremsstrahlung -mean free path: - -.. math:: - :label: inverse-bremsstrahlung-mfp - - \lambda_{\text{br}}^{-1}(T,E_{\text{cut}}) - = n\int_{E_{\text{cut}}}^T\frac{d\sigma_{\text{br}}}{dE}dE - = n\frac{Z^2}{\beta^2}\int_{\kappa_{\text{cut}}}^1\frac{1}{\kappa} - \chi(Z,T,\kappa)d\kappa. - -The lower limit of the integral in :eq:`inverse-bremsstrahlung-mfp` is non-zero -because the bremsstrahlung differential cross section diverges for small photon -energies but is finite for photon energies above some cutoff energy -:math:`E_{\text{cut}}`. The mean free path -:math:`\lambda_{\text{br}}^{-1}(T,E_{\text{cut}})` is used to calculate the -photon number yield, defined as the average number of photons emitted with -energy greater than :math:`E_{\text{cut}}` as the charged particle slows down -from energy :math:`T` to :math:`E_{\text{cut}}`. The photon number yield is -given by - -.. math:: - :label: photon-number-yield - - Y(T,E_{\text{cut}}) = \int^{R(T)}_{R(E_{\text{cut}})} - \lambda_{\text{br}}^{-1}(T',E_{\text{cut}})ds = \int_{E_{\text{cut}}}^T - \frac{\lambda_{\text{br}}^{-1}(T',E_{\text{cut}})}{S(T')}dT'. - -:math:`Y(T,E_{\text{cut}})` can be used to construct the energy spectrum of -bremsstrahlung photons: the number of photons created with energy between -:math:`E_1` and :math:`E_2` by a charged particle with initial kinetic energy -:math:`T` as it comes to rest is given by :math:`Y(T,E_1) - Y(T,E_2)`. - -To simulate the emission of bremsstrahlung photons, the total stopping power -and bremsstrahlung differential cross section for positrons and electrons must -be calculated for a given material using :eq:`material-bremsstrahlung-dcs` and -:eq:`material-radiative-stopping-power`. These quantities are used to build the -tabulated bremsstrahlung energy PDF and CDF for that material for each incident -energy :math:`T_k` on the energy grid. The following algorithm is then applied -to sample the photon energies: - -1. For an incident charged particle with energy :math:`T`, sample the number of - emitted photons as - - .. math:: - - N = \lfloor Y(T,E_{\text{cut}}) + \xi_1 \rfloor. - -2. Rather than interpolate the PDF between indices :math:`k` and :math:`k+1` - for which :math:`T_k < T < T_{k+1}`, which is computationally expensive, use - the composition method and sample from the PDF at either :math:`k` or - :math:`k+1`. Using linear interpolation on a logarithmic scale, the PDF can - be expressed as - - .. math:: - - p_{\text{br}}(T,E) = \pi_k p_{\text{br}}(T_k,E) + \pi_{k+1} - p_{\text{br}}(T_{k+1},E), - - where the interpolation weights are - - .. math:: - - \pi_k = \frac{\ln T_{k+1} - \ln T}{\ln T_{k+1} - \ln T_k},~~~ - \pi_{k+1} = \frac{\ln T - \ln T_k}{\ln T_{k+1} - \ln T_k}. - - Sample either the index :math:`i = k` or :math:`i = k+1` according to the - point probabilities :math:`\pi_{k}` and :math:`\pi_{k+1}`. - -3. Determine the maximum value of the CDF :math:`P_{\text{br,max}}`. - -3. Sample the photon energies using the inverse transform method with the - tabulated CDF :math:`P_{\text{br}}(T_i, E)` i.e., - - .. math:: - - E = E_j \left[ (1 + a_j) \frac{\xi_2 P_{\text{br,max}} - - P_{\text{br}}(T_i, E_j)} {E_j p_{\text{br}}(T_i, E_j)} + 1 - \right]^{\frac{1}{1 + a_j}} - - where the interpolation factor :math:`a_j` is given by - - .. math:: - - a_j = \frac{\ln p_{\text{br}}(T_i,E_{j+1}) - \ln p_{\text{br}}(T_i,E_j)} - {\ln E_{j+1} - \ln E_j} - - and :math:`P_{\text{br}}(T_i, E_j) \le \xi_2 P_{\text{br,max}} \le - P_{\text{br}}(T_i, E_{j+1})`. - -We ignore the range of the electron or positron, i.e., the bremsstrahlung -photons are produced in the same location that the charged particle was -created. The direction of the photons is assumed to be the same as the -direction of the incident charged particle, which is a reasonable approximation -at higher energies when the bremsstrahlung radiation is emitted at small -angles. - - -Electron-Positron Annihilation ------------------------------- - -When a positron collides with an electron, both particles are annihilated and -generally two photons with equal energy are created. If the kinetic energy of -the positron is high enough, the two photons can have different energies, and -the higher-energy photon is emitted preferentially in the direction of flight -of the positron. It is also possible to produce a single photon if the -interaction occurs with a bound electron, and in some cases three (or, rarely, -even more) photons can be emitted. However, the annihilation cross section is -largest for low-energy positrons, and as the positron energy decreases, the -angular distribution of the emitted photons becomes isotropic. - -In OpenMC, we assume the most likely case in which a low-energy positron (which -has already lost most of its energy to bremsstrahlung radiation) interacts with -an electron which is free and at rest. Two photons with energy equal to the -electron rest mass energy :math:`m_e c^2 = 0.511` MeV are emitted isotropically -in opposite directions. - - -.. _Kaltiaisenaho: https://aaltodoc.aalto.fi/bitstream/handle/123456789/21004/master_Kaltiaisenaho_Toni_2016.pdf - -.. _Salvat: https://doi.org/10.1787/32da5043-en - -.. _Sternheimer: https://doi.org/10.1103/PhysRevB.26.6067 diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 764c4c628..3396d7f25 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -178,27 +178,6 @@ been selected. There are three methods available: section data is loaded for a single temperature and is used in the unresolved resonance and fast energy ranges. ------------------- -NCrystal materials ------------------- - -As an alternative of the standard thermal scattering treatment using -:math:`S(\alpha,\beta)` tables, OpenMC allows to create materials using -NCrystal_. In addition to the regular thermal elastic, and thermal inelastic -processes, NCrystal allows the generation of models for materials that cannot -currently included in ACE files such as oriented single crystals (see the -`NCrystal paper`_), and further extend the physics `using plugins`_. Thermal -scattering kernels are generated on the fly from dynamic and structural data, or -loaded from :math:`S(\alpha,\beta)` tables converted from ENDF6 evaluations. -These kernels are sampled in a direct way using a fast `rejection algorithm`_ -that does not require previous processing. A `large library`_ of materials is -already included in the NCrystal distribution, and new materials can be easily -defined from scratch in the `NCMAT format`_ or `combining existing files`_. - -The compositions of the materials defined in NCrystal are passed on to OpenMC -all other reactions except for thermal neutron scattering are handled by -continuous energy ACE libraries. - ---------------- Multi-Group Data ---------------- @@ -289,63 +268,14 @@ 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 + https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-14-24530.pdf .. _Hwang: https://doi.org/10.13182/NSE87-A16381 .. _Josey: https://doi.org/10.1016/j.jcp.2015.08.013 .. _WMP Library: https://github.com/mit-crpg/WMP_Library .. _MCNP: https://mcnp.lanl.gov -.. _Serpent: https://serpent.vtt.fi -.. _NJOY: https://www.njoy21.io/ +.. _Serpent: http://montecarlo.vtt.fi +.. _NJOY: https://www.njoy21.io/NJOY21/ .. _ENDF/B data: https://www.nndc.bnl.gov/endf-b8.0/ .. _Leppanen: https://doi.org/10.1016/j.anucene.2009.03.019 -.. _algorithms: http://ab-initio.mit.edu/faddeeva/ -.. _NCrystal: https://github.com/mctools/ncrystal -.. _NCrystal paper: https://doi.org/10.1016/j.cpc.2019.07.015 -.. _using plugins: https://doi.org/10.1016/j.cpc.2021.108082 -.. _rejection algorithm: https://doi.org/10.1016/j.jcp.2018.11.043 -.. _large library: https://github.com/mctools/ncrystal/wiki/Data-library -.. _NCMAT format: https://github.com/mctools/ncrystal/wiki/NCMAT-format -.. _combining existing files: https://github.com/mctools/ncrystal/wiki/Announcement-Release3.0.0#2-multiphase-materials +.. _algorithms: http://ab-initio.mit.edu/wiki/index.php/Faddeeva_Package diff --git a/docs/source/methods/depletion.rst b/docs/source/methods/depletion.rst index edcf2c3f5..1b131bed5 100644 --- a/docs/source/methods/depletion.rst +++ b/docs/source/methods/depletion.rst @@ -114,7 +114,7 @@ The predictor method only requires one evaluation and its error converges as twice as expensive as the predictor method, but achieves an error of :math:`\mathcal{O}(h^2)`. An exhaustive description of time integration methods and their merits can be found in the `thesis of Colin Josey -`_. +`_. OpenMC does not rely on a single time integration method but rather has several classes that implement different algorithms. For example, the @@ -257,85 +257,3 @@ choose one of two methods for estimating the heating rate, including: The method for normalization can be chosen through the ``normalization_mode`` argument to the :class:`openmc.deplete.CoupledOperator` class. - --------------- -Transfer Rates --------------- - -OpenMC allows continuous removal or feed of nuclides by adding an -extra transfer rate term to the depletion matrix. An application of this feature -is the chemical processing of Molten Salt Reactors (MSRs), where one can -model the removal of fission products or feeding fresh fuel into the system. - -A transfer rate as defined here is the rate at which nuclides are -continuously removed/fed from/to a material. - -.. note:: - - A transfer rate can be positive or negative, indicating removal or feed - respectively. - -Mathematically, it can be thought of as an additional term :math:`\mathbf{T}` -in the depletion equation that is proportional to the nuclide density, which can be written as: - -.. math:: - - \begin{aligned}\frac{dN_i(t)}{dt} = &\underbrace{\sum\limits_j f_{j\rightarrow i} - \int_0^\infty dE \; \sigma_j (E,t) \phi(E,t) N_j(t) - \int_0^\infty dE \; \sigma_i(E,t) - \phi(E,t) N_i(t)}_\textbf{R} \\ - &+ \underbrace{\sum_j \left [ \lambda_{j\rightarrow i} N_j(t) - \lambda_{i\rightarrow j} N_i(t) \right ]}_\textbf{D} \\ - &- \underbrace{t_i N_i(t)}_\textbf{T} \end{aligned} - -where the reaction term :math:`\mathbf{R}`, the decay term :math:`\mathbf{D}` -and the new transfer term :math:`\mathbf{T}` have been grouped together so that -:math:`\mathbf{A} = \mathbf{R}+\mathbf{D}-\mathbf{T}`. -The transfer rate coefficient :math:`t_i` defines the continuous transfer of the -nuclide :math:`i`, which behaves similar to radioactive decay. -:math:`t_i` can also be defined as the reciprocal of a cycle time -:math:`T_{cyc}`, intended as the time needed to process the whole inventory. - -Note that this formulation assumes homogeneous distribution of nuclide -:math:`i` throughout the material. - -A more rigorous description of removal rate and its implementation can be found -in the paper by `Hombourger -`_. - -The resulting burnup matrix can be solved with the same integration algorithms -that are used in the absence of the transfer term. - -.. note:: - - If no ``destination_material`` is specified, nuclides that are removed - or fed will not be tracked afterwards. - -Coupling materials ------------------- - -To keep track of removed nuclides or to feed nuclides from one depletable material -to another, the respective depletion equations have to be coupled. This can be -achieved by defining one block matrix, with diagonal blocks corresponding to -depletion matrices :math:`\mathbf{A_{ii}}`, where the index :math:`i` indicates -the depletable material id, and off-diagonal blocks corresponding to inter-material -coupling matrices :math:`\mathbf{T_{ij}}`, positioned so that that the indices :math:`i` and -:math:`j` indicate the nuclides receiving and losing materials, respectively. -The nuclide vectors are assembled together in one single vector and the resulting -system is solved with the same integration algorithms seen before. - -As an example, consider the case of two depletable materials and one -transfer defined from material 1 to material 2. The final system will look like: - -.. math:: - - \begin{aligned}\frac{d}{dt}\begin{pmatrix}\vec{N_1}\\ \vec{N_2}\end{pmatrix} &= - \begin{pmatrix}\mathbf{A_{11}} & \mathbf{0}\\ \mathbf{T_{21}} & \mathbf{A_{22 }} - \end{pmatrix} \begin{pmatrix}\vec{N_1}\\ \vec{N_2}\end{pmatrix} \end{aligned} - -where: - -:math:`\mathbf{A_{11}} = \mathbf{R_{11}}+\mathbf{D_{11}}-\mathbf{T_{21}}`, and - -:math:`\mathbf{A_{22}} = \mathbf{R_{22}}+\mathbf{D_{22}}`. - -Note that mass conservation is guaranteed by transferring the number -of atoms directly. diff --git a/docs/source/methods/eigenvalue.rst b/docs/source/methods/eigenvalue.rst index 8abcc0957..41bf86549 100644 --- a/docs/source/methods/eigenvalue.rst +++ b/docs/source/methods/eigenvalue.rst @@ -55,17 +55,15 @@ in :ref:`fission-bank-algorithms`. Source Convergence Issues ------------------------- -.. _methods-shannon-entropy: - Diagnosing Convergence with Shannon Entropy ------------------------------------------- As discussed earlier, it is necessary to converge both :math:`k_{eff}` and the source distribution before any tallies can begin. Moreover, the convergence rate -of the source distribution is in general slower than that of :math:`k_{eff}`. -One should thus examine not only the convergence of :math:`k_{eff}` but also the -convergence of the source distribution in order to make decisions on when to -start active batches. +of the source distribution is in general slower than that of +:math:`k_{eff}`. One should thus examine not only the convergence of +:math:`k_{eff}` but also the convergence of the source distribution in order to +make decisions on when to start active batches. However, the representation of the source distribution makes it a bit more difficult to analyze its convergence. Since :math:`k_{eff}` is a scalar @@ -110,13 +108,6 @@ at plots of :math:`k_{eff}` and the Shannon entropy. A number of methods have been proposed (see e.g. [Romano]_, [Ueki]_), but each of these is not without problems. -Shannon entropy is calculated differently for the random ray solver, as -described :ref:`in the random ray theory section -`. Additionally, as the Shannon entropy only -serves as a diagnostic tool for convergence of the fission source distribution, -there is currently no diagnostic to determine if the scattering source -distribution in random ray is converged. - --------------------------- Uniform Fission Site Method --------------------------- @@ -151,7 +142,7 @@ than unity. By ensuring that the expected number of fission sites in each mesh cell is constant, the collision density across all cells, and hence the variance of tallies, is more uniform than it would be otherwise. -.. _Shannon entropy: https://mcnp.lanl.gov/pdf_files/TechReport_2006_LANL_LA-UR-06-3737_Brown.pdf +.. _Shannon entropy: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-06-3737.pdf .. [Lieberoth] J. Lieberoth, "A Monte Carlo Technique to Solve the Static Eigenvalue Problem of the Boltzmann Transport Equation," *Nukleonik*, **11**, diff --git a/docs/source/methods/energy_deposition.rst b/docs/source/methods/energy_deposition.rst index c43ee64ac..4675aee3f 100644 --- a/docs/source/methods/energy_deposition.rst +++ b/docs/source/methods/energy_deposition.rst @@ -25,38 +25,19 @@ KERMA (Kinetic Energy Release in Materials) [Mack97]_ coefficients for reaction :math:`\times` cross-section (e.g., eV-barn) and can be used much like a reaction cross section for the purpose of tallying energy deposition. -KERMA coefficients can be computed using the energy-balance method with a -nuclear data processing code like NJOY, which estimates the KERMA coefficients -using the following equation: +KERMA coefficients can be computed using the energy-balance method with +a nuclear data processing code like NJOY, which performs the following +iteration over all reactions :math:`r` for all isotopes :math:`i` +requested .. math:: - k_{i, r}(E) = \left(E + Q_{i, r} - \sum\limits_x \bar{E}_{i, r, x} - \right)\sigma_{i, r}(E), - -where the summation is over each secondary particle type :math:`x`. This -equation states that the energy deposited is equal to the energy of the incident -particle plus the reaction :math:`Q` value less the energy of secondary -particles that are transported away from the reaction site. For neutron -interactions, the energy-balance KERMA coefficient is - -.. math:: - - k_{i, r}(E) = \left(E + Q_{i, r} - \sum\limits_x \bar{E}_{i, r, n} + k_{i, r}(E) = \left(E + Q_{i, r} - \bar{E}_{i, r, n} - \bar{E}_{i, r, \gamma}\right)\sigma_{i, r}(E), -where :math:`\bar{E}_{i, r, n}` is the average energy of secondary neutrons and -:math:`\bar{E}_{i, r, \gamma}` is the average energy of secondary photons. For -photon and charged particle interactions the KERMA coefficient is - -.. math:: - :label: energy-balance-photon - - k_{i, r}(E) = \left(E + Q_{i, r} - \sum\limits_x \bar{E}_{i, r, x} - \right)\sigma_{i, r}(E). - -where the :math:`Q` value is zero for all interactions except for pair -production and positron annihilation. +removing the energy of neutral particles (neutrons and photons) that are +transported away from the reaction site :math:`\bar{E}`, and the reaction +:math:`Q` value. ------- Fission @@ -139,7 +120,7 @@ run with :math:`N918` reflecting fission heating computed from NJOY. This modified heating data is stored as the MT=901 reaction and will be scored if ``heating-local`` is included in :attr:`openmc.Tally.scores`. -Coupled Neutron-Photon Transport +Coupled neutron-photon transport -------------------------------- Here, OpenMC instructs ``heatr`` to assume that energy from photons is not @@ -157,50 +138,6 @@ Let :math:`N301` represent the total heating number returned from this This modified heating data is stored as the MT=301 reaction and will be scored if ``heating`` is included in :attr:`openmc.Tally.scores`. -Photons and Charged Particles ------------------------------ - -In OpenMC, energy deposition from photons or charged particles is scored using -the energy balance method based on Equation :eq:`energy-balance-photon`. Special -consideration is given to electrons and positrons as described below. - -+++++++++++++++++ -Charged Particles -+++++++++++++++++ - -OpenMC tracks photons interaction by interaction so the energy deposited in each -collision is easily attributed back to the nuclide and reaction for which the -photon interacted with. Charged particles (electrons and photons) aren't tracked -in the same way. For charged particles, OpenMC assumes that all their energy -(less the energy of bremsstrahlung radiation) is deposited in the material in -which they were born. In this way it is harder to trace how much energy should -be attributed in each nuclide. - -According to the CSDA approximation (see :ref:`ttb`) the energy deposited by a -charged particle with kinetic energy :math:`T` in the :math:`i`-th element can -be calculated as: - -.. math:: - - E_{i} = \int_{0}^{R(T)} w_{i}S_{\text{col,i}} dx - -where :math:`R(T)` is the CSDA range of the charged particle, -:math:`S_{\text{col},i}` is the collision stopping power of the charged particle -in the :math:`i`-th element and :math:`w_i` is the mass fraction of the -:math:`i`-th element. According to the Bethe formula the collision stopping -power of the :math:`i`-th element is proportional to :math:`Z_i/A_i`, so the -fractional collision stopping power from the :math:`i`-th element is: - -.. math:: - - \frac{w_{i}S_{\text{col},i}(T)}{S_{\text{col}}(T)} = - \frac{\frac{w_{i}Z_{i}}{A_{i}}}{\sum_{i}\frac{w_{i}Z_{i}}{A_{i}}} = - \frac{\gamma_i Z_{i}}{\sum_{i}\gamma_i Z_{i}}. - -where :math:`\gamma_i` is the atomic fraction of the :math:`i`-th element. -Therefore, the energy deposited by charged particles should be attributed to -a given element according to its fractional charge density. - ---------- References ---------- diff --git a/docs/source/methods/geometry.rst b/docs/source/methods/geometry.rst index 05cda4b64..b282ffdee 100644 --- a/docs/source/methods/geometry.rst +++ b/docs/source/methods/geometry.rst @@ -1066,5 +1066,5 @@ surface is known as in :ref:`reflection`. .. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry .. _surfaces: https://en.wikipedia.org/wiki/Surface .. _MCNP: https://mcnp.lanl.gov -.. _Serpent: https://serpent.vtt.fi +.. _Serpent: http://montecarlo.vtt.fi .. _Monte Carlo Performance benchmark: https://github.com/mit-crpg/benchmarks/tree/master/mc-performance/openmc diff --git a/docs/source/methods/index.rst b/docs/source/methods/index.rst index 121d04b1d..59892ac27 100644 --- a/docs/source/methods/index.rst +++ b/docs/source/methods/index.rst @@ -14,12 +14,9 @@ Theory and Methodology random_numbers neutron_physics photon_physics - charged_particles_physics tallies eigenvalue depletion energy_deposition parallelization cmfd - variance_reduction - random_ray diff --git a/docs/source/methods/neutron_physics.rst b/docs/source/methods/neutron_physics.rst index 2b797e3db..f1b0a5bde 100644 --- a/docs/source/methods/neutron_physics.rst +++ b/docs/source/methods/neutron_physics.rst @@ -91,7 +91,7 @@ inelastic scattering reactions. The specific multi-group scattering implementation is discussed in the :ref:`multi-group-scatter` section. Elastic scattering refers to the process by which a neutron scatters off a -nucleus and does not leave it in an excited state. It is referred to as "elastic" +nucleus and does not leave it in an excited. It is referred to as "elastic" because in the center-of-mass system, the neutron does not actually lose energy. However, in lab coordinates, the neutron does indeed lose energy. Elastic scattering can be treated exactly in a Monte Carlo code thanks @@ -290,10 +290,7 @@ create and store fission sites for the following generation. First, the average number of prompt and delayed neutrons must be determined to decide whether the secondary neutrons will be prompt or delayed. This is important because delayed neutrons have a markedly different spectrum from prompt neutrons, one that has a -lower average energy of emission. Furthermore, in simulations where tracking -time of neutrons is important, we need to consider the emission time delay of -the secondary neutrons, which is dependent on the decay constant of the -delayed neutron precursor. The total number of neutrons emitted +lower average energy of emission. The total number of neutrons emitted :math:`\nu_t` is given as a function of incident energy in the ENDF format. Two representations exist for :math:`\nu_t`. The first is a polynomial of order :math:`N` with coefficients :math:`c_0,c_1,\dots,c_N`. If :math:`\nu_t` has this @@ -309,8 +306,8 @@ interpolation law. The number of prompt neutrons released per fission event :math:`\nu_p` is also given as a function of incident energy and can be specified in a polynomial or tabular format. The number of delayed neutrons released per fission event :math:`\nu_d` can only be specified in a tabular -format. In practice, we only need to determine :math:`\nu_t` and -:math:`\nu_d`. Once these have been determined, we can calculate the delayed +format. In practice, we only need to determine :math:`nu_t` and +:math:`nu_d`. Once these have been determined, we can calculated the delayed neutron fraction .. math:: @@ -338,14 +335,8 @@ neutrons. Otherwise, we produce :math:`\lfloor \nu \rfloor + 1` neutrons. Then, for each fission site produced, we sample the outgoing angle and energy according to the algorithms given in :ref:`sample-angle` and :ref:`sample-energy` respectively. If the neutron is to be born delayed, then -there is an extra step of sampling a delayed neutron precursor group to get the -associated secondary energy distribution and the decay constant -:math:`\lambda`, which is needed to sample the emission delay time :math:`t_d`: - -.. math:: - :label: sample-delay-time - - t_d = -\frac{\ln \xi}{\lambda}. +there is an extra step of sampling a delayed neutron precursor group since they +each have an associated secondary energy distribution. The sampled outgoing angle and energy of fission neutrons along with the position of the collision site are stored in an array called the fission @@ -1752,19 +1743,19 @@ types. .. _Watt fission spectrum: https://doi.org/10.1103/PhysRev.87.1037 -.. _Foderaro: https://dspace.mit.edu/handle/1721.1/1716 +.. _Foderaro: http://hdl.handle.net/1721.1/1716 .. _OECD: https://www.oecd-nea.org/tools/abstract/detail/NEA-1792 .. _NJOY: https://www.njoy21.io/NJOY2016/ -.. _PREPRO: https://www-nds.iaea.org/public/endf/prepro/ +.. _PREPRO: https://www-nds.iaea.org/ndspub/endf/prepro/ .. _ENDF-6 Format: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf -.. _Monte Carlo Sampler: https://mcnp.lanl.gov/pdf_files/TechReport_1983_LANL_LA-9721-MS_EverettCashwell.pdf +.. _Monte Carlo Sampler: https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-09721-MS -.. _LA-UR-14-27694: https://www.osti.gov/biblio/1159204 +.. _LA-UR-14-27694: https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-UR-14-27694 .. _MC21: https://www.osti.gov/biblio/903083 @@ -1772,4 +1763,6 @@ types. .. _Sutton and Brown: https://www.osti.gov/biblio/307911 -.. _lectures: https://mcnp.lanl.gov/pdf_files/TechReport_2005_LANL_LA-UR-05-4983_Brown.pdf +.. _lectures: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-05-4983.pdf + +.. _MCNP Manual: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-03-1987.pdf diff --git a/docs/source/methods/parallelization.rst b/docs/source/methods/parallelization.rst index 87ac48590..d9fc15c9f 100644 --- a/docs/source/methods/parallelization.rst +++ b/docs/source/methods/parallelization.rst @@ -609,17 +609,17 @@ is actually independent of the number of nodes: .. _first paper: https://doi.org/10.2307/2280232 -.. _work of Forrest Brown: https://deepblue.lib.umich.edu/handle/2027.42/24996 +.. _work of Forrest Brown: http://hdl.handle.net/2027.42/24996 .. _Brissenden and Garlick: https://doi.org/10.1016/0306-4549(86)90095-2 -.. _MPICH: https://www.mpich.org +.. _MPICH: http://www.mpich.org .. _binomial tree: https://www.mcs.anl.gov/~thakur/papers/ijhpca-coll.pdf .. _Geary: https://doi.org/10.2307/2342070 -.. _Barnett: https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.7772 +.. _Barnett: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.7772 .. _single-instruction multiple-data: https://en.wikipedia.org/wiki/SIMD diff --git a/docs/source/methods/photon_physics.rst b/docs/source/methods/photon_physics.rst index d2bd3ac76..bc912b943 100644 --- a/docs/source/methods/photon_physics.rst +++ b/docs/source/methods/photon_physics.rst @@ -667,6 +667,342 @@ and Auger electrons: 5. Repeat from step 1 for vacancy left by the transition electron. +Electron-Positron Annihilation +------------------------------ + +When a positron collides with an electron, both particles are annihilated and +generally two photons with equal energy are created. If the kinetic energy of +the positron is high enough, the two photons can have different energies, and +the higher-energy photon is emitted preferentially in the direction of flight +of the positron. It is also possible to produce a single photon if the +interaction occurs with a bound electron, and in some cases three (or, rarely, +even more) photons can be emitted. However, the annihilation cross section is +largest for low-energy positrons, and as the positron energy decreases, the +angular distribution of the emitted photons becomes isotropic. + +In OpenMC, we assume the most likely case in which a low-energy positron (which +has already lost most of its energy to bremsstrahlung radiation) interacts with +an electron which is free and at rest. Two photons with energy equal to the +electron rest mass energy :math:`m_e c^2 = 0.511` MeV are emitted isotropically +in opposite directions. + +Bremsstrahlung +-------------- + +When a charged particle is decelerated in the field of an atom, some of its +kinetic energy is converted into electromagnetic radiation known as +bremsstrahlung, or 'braking radiation'. In each event, an electron or positron +with kinetic energy :math:`T` generates a photon with an energy :math:`E` +between :math:`0` and :math:`T`. Bremsstrahlung is described by a cross section +that is differential in photon energy, in the direction of the emitted photon, +and in the final direction of the charged particle. However, in Monte Carlo +simulations it is typical to integrate over the angular variables to obtain a +single differential cross section with respect to photon energy, which is often +expressed in the form + +.. math:: + :label: bremsstrahlung-dcs + + \frac{d\sigma_{\text{br}}}{dE} = \frac{Z^2}{\beta^2} \frac{1}{E} + \chi(Z, T, \kappa), + +where :math:`\kappa = E/T` is the reduced photon energy and :math:`\chi(Z, T, +\kappa)` is the scaled bremsstrahlung cross section, which is experimentally +measured. + +Because electrons are attracted to atomic nuclei whereas positrons are +repulsed, the cross section for positrons is smaller, though it approaches that +of electrons in the high energy limit. To obtain the positron cross section, we +multiply :eq:`bremsstrahlung-dcs` by the :math:`\kappa`-independent factor used +in Salvat_, + +.. math:: + :label: positron-factor + + \begin{aligned} + F_{\text{p}}(Z,T) = + & 1 - \text{exp}(-1.2359\times 10^{-1}t + 6.1274\times 10^{-2}t^2 - 3.1516\times 10^{-2}t^3 \\ + & + 7.7446\times 10^{-3}t^4 - 1.0595\times 10^{-3}t^5 + 7.0568\times 10^{-5}t^6 \\ + & - 1.8080\times 10^{-6}t^7), + \end{aligned} + +where + +.. math:: + :label: positron-factor-t + + t = \ln\left(1 + \frac{10^6}{Z^2}\frac{T}{\text{m}_\text{e}c^2} \right). + +:math:`F_{\text{p}}(Z,T)` is the ratio of the radiative stopping powers for +positrons and electrons. Stopping power describes the average energy loss per +unit path length of a charged particle as it passes through matter: + +.. math:: + :label: stopping-power + + -\frac{dT}{ds} = n \int E \frac{d\sigma}{dE} dE \equiv S(T), + +where :math:`n` is the number density of the material and :math:`d\sigma/dE` is +the cross section differential in energy loss. The total stopping power +:math:`S(T)` can be separated into two components: the radiative stopping +power :math:`S_{\text{rad}}(T)`, which refers to energy loss due to +bremsstrahlung, and the collision stopping power :math:`S_{\text{col}}(T)`, +which refers to the energy loss due to inelastic collisions with bound +electrons in the material that result in ionization and excitation. The +radiative stopping power for electrons is given by + +.. math:: + :label: radiative-stopping-power + + S_{\text{rad}}(T) = n \frac{Z^2}{\beta^2} T \int_0^1 \chi(Z,T,\kappa) + d\kappa. + + +To obtain the radiative stopping power for positrons, +:eq:`radiative-stopping-power` is multiplied by :eq:`positron-factor`. + +While the models for photon interactions with matter described above can safely +assume interactions occur with free atoms, sampling the target atom based on +the macroscopic cross sections, molecular effects cannot necessarily be +disregarded for charged particle treatment. For compounds and mixtures, the +bremsstrahlung cross section is calculated using Bragg's additivity rule as + +.. math:: + :label: material-bremsstrahlung-dcs + + \frac{d\sigma_{\text{br}}}{dE} = \frac{1}{\beta^2 E} \sum_i \gamma_i Z^2_i + \chi(Z_i, T, \kappa), + +where the sum is over the constituent elements and :math:`\gamma_i` is the +atomic fraction of the :math:`i`-th element. Similarly, the radiative stopping +power is calculated using Bragg's additivity rule as + +.. math:: + :label: material-radiative-stopping-power + + S_{\text{rad}}(T) = \sum_i w_i S_{\text{rad},i}(T), + +where :math:`w_i` is the mass fraction of the :math:`i`-th element and +:math:`S_{\text{rad},i}(T)` is found for element :math:`i` using +:eq:`radiative-stopping-power`. The collision stopping power, however, is a +function of certain quantities such as the mean excitation energy :math:`I` and +the density effect correction :math:`\delta_F` that depend on molecular +properties. These quantities cannot simply be summed over constituent elements +in a compound, but should instead be calculated for the material. The Bethe +formula can be used to find the collision stopping power of the material: + +.. math:: + :label: material-collision-stopping-power + + S_{\text{col}}(T) = \frac{2 \pi r_e^2 m_e c^2}{\beta^2} N_A \frac{Z}{A_M} + [\ln(T^2/I^2) + \ln(1 + \tau/2) + F(\tau) - \delta_F(T)], + +where :math:`N_A` is Avogadro's number, :math:`A_M` is the molar mass, +:math:`\tau = T/m_e`, and :math:`F(\tau)` depends on the particle type. For +electrons, + +.. math:: + :label: F-electron + + F_{-}(\tau) = (1 - \beta^2)[1 + \tau^2/8 - (2\tau + 1) \ln2], + +while for positrons + +.. math:: + :label: F-positron + + F_{+}(\tau) = 2\ln2 - (\beta^2/12)[23 + 14/(\tau + 2) + 10/(\tau + 2)^2 + + 4/(\tau + 2)^3]. + +The density effect correction :math:`\delta_F` takes into account the reduction +of the collision stopping power due to the polarization of the material the +charged particle is passing through by the electric field of the particle. +It can be evaluated using the method described by Sternheimer_, where the +equation for :math:`\delta_F` is + +.. math:: + :label: density-effect-correction + + \delta_F(\beta) = \sum_{i=1}^n f_i \ln[(l_i^2 + l^2)/l_i^2] - + l^2(1-\beta^2). + +Here, :math:`f_i` is the oscillator strength of the :math:`i`-th transition, +given by :math:`f_i = n_i/Z`, where :math:`n_i` is the number of electrons in +the :math:`i`-th subshell. The frequency :math:`l` is the solution of the +equation + +.. math:: + :label: density-effect-l + + \frac{1}{\beta^2} - 1 = \sum_{i=1}^{n} \frac{f_i}{\bar{\nu}_i^2 + l^2}, + +where :math:`\bar{v}_i` is defined as + +.. math:: + :label: density-effect-nubar + + \bar{\nu}_i = h\nu_i \rho / h\nu_p. + +The plasma energy :math:`h\nu_p` of the medium is given by + +.. math:: + :label: plasma-frequency + + h\nu_p = \sqrt{\frac{(hc)^2 r_e \rho_m N_A Z}{\pi A}}, + +where :math:`A` is the atomic weight and :math:`\rho_m` is the density of the +material. In :eq:`density-effect-nubar`, :math:`h\nu_i` is the oscillator +energy, and :math:`\rho` is an adjustment factor introduced to give agreement +between the experimental values of the oscillator energies and the mean +excitation energy. The :math:`l_i` in :eq:`density-effect-correction` are +defined as + +.. math:: + :label: density-effect-li + + \begin{aligned} + l_i &= (\bar{\nu}_i^2 + 2/3f_i)^{1/2} ~~~~&\text{for}~~ \bar{\nu}_i > 0 \\ + l_n &= f_n^{1/2} ~~~~&\text{for}~~ \bar{\nu}_n = 0, + \end{aligned} + +where the second case applies to conduction electrons. For a conductor, +:math:`f_n` is given by :math:`n_c/Z`, where :math:`n_c` is the effective +number of conduction electrons, and :math:`v_n = 0`. The adjustment factor +:math:`\rho` is determined using the equation for the mean excitation energy: + +.. math:: + :label: mean-excitation-energy + + \ln I = \sum_{i=1}^{n-1} f_i \ln[(h\nu_i\rho)^2 + 2/3f_i(h\nu_p)^2]^{1/2} + + f_n \ln (h\nu_pf_n^{1/2}). + +.. _ttb: + +Thick-Target Bremsstrahlung Approximation ++++++++++++++++++++++++++++++++++++++++++ + +Since charged particles lose their energy on a much shorter distance scale than +neutral particles, not much error should be introduced by neglecting to +transport electrons. However, the bremsstrahlung emitted from high energy +electrons and positrons can travel far from the interaction site. Thus, even +without a full electron transport mode it is necessary to model bremsstrahlung. +We use a thick-target bremsstrahlung (TTB) approximation based on the models in +Salvat_ and Kaltiaisenaho_ for generating bremsstrahlung photons, which assumes +the charged particle loses all its energy in a single homogeneous material +region. + +To model bremsstrahlung using the TTB approximation, we need to know the number +of photons emitted by the charged particle and the energy distribution of the +photons. These quantities can be calculated using the continuous slowing down +approximation (CSDA). The CSDA assumes charged particles lose energy +continuously along their trajectory with a rate of energy loss equal to the +total stopping power, ignoring fluctuations in the energy loss. The +approximation is useful for expressing average quantities that describe how +charged particles slow down in matter. For example, the CSDA range approximates +the average path length a charged particle travels as it slows to rest: + +.. math:: + :label: csda-range + + R(T) = \int^T_0 \frac{dT'}{S(T')}. + +Actual path lengths will fluctuate around :math:`R(T)`. The average number of +photons emitted per unit path length is given by the inverse bremsstrahlung +mean free path: + +.. math:: + :label: inverse-bremsstrahlung-mfp + + \lambda_{\text{br}}^{-1}(T,E_{\text{cut}}) + = n\int_{E_{\text{cut}}}^T\frac{d\sigma_{\text{br}}}{dE}dE + = n\frac{Z^2}{\beta^2}\int_{\kappa_{\text{cut}}}^1\frac{1}{\kappa} + \chi(Z,T,\kappa)d\kappa. + +The lower limit of the integral in :eq:`inverse-bremsstrahlung-mfp` is non-zero +because the bremsstrahlung differential cross section diverges for small photon +energies but is finite for photon energies above some cutoff energy +:math:`E_{\text{cut}}`. The mean free path +:math:`\lambda_{\text{br}}^{-1}(T,E_{\text{cut}})` is used to calculate the +photon number yield, defined as the average number of photons emitted with +energy greater than :math:`E_{\text{cut}}` as the charged particle slows down +from energy :math:`T` to :math:`E_{\text{cut}}`. The photon number yield is +given by + +.. math:: + :label: photon-number-yield + + Y(T,E_{\text{cut}}) = \int^{R(T)}_{R(E_{\text{cut}})} + \lambda_{\text{br}}^{-1}(T',E_{\text{cut}})ds = \int_{E_{\text{cut}}}^T + \frac{\lambda_{\text{br}}^{-1}(T',E_{\text{cut}})}{S(T')}dT'. + +:math:`Y(T,E_{\text{cut}})` can be used to construct the energy spectrum of +bremsstrahlung photons: the number of photons created with energy between +:math:`E_1` and :math:`E_2` by a charged particle with initial kinetic energy +:math:`T` as it comes to rest is given by :math:`Y(T,E_1) - Y(T,E_2)`. + +To simulate the emission of bremsstrahlung photons, the total stopping power +and bremsstrahlung differential cross section for positrons and electrons must +be calculated for a given material using :eq:`material-bremsstrahlung-dcs` and +:eq:`material-radiative-stopping-power`. These quantities are used to build the +tabulated bremsstrahlung energy PDF and CDF for that material for each incident +energy :math:`T_k` on the energy grid. The following algorithm is then applied +to sample the photon energies: + +1. For an incident charged particle with energy :math:`T`, sample the number of + emitted photons as + + .. math:: + + N = \lfloor Y(T,E_{\text{cut}}) + \xi_1 \rfloor. + +2. Rather than interpolate the PDF between indices :math:`k` and :math:`k+1` + for which :math:`T_k < T < T_{k+1}`, which is computationally expensive, use + the composition method and sample from the PDF at either :math:`k` or + :math:`k+1`. Using linear interpolation on a logarithmic scale, the PDF can + be expressed as + + .. math:: + + p_{\text{br}}(T,E) = \pi_k p_{\text{br}}(T_k,E) + \pi_{k+1} + p_{\text{br}}(T_{k+1},E), + + where the interpolation weights are + + .. math:: + + \pi_k = \frac{\ln T_{k+1} - \ln T}{\ln T_{k+1} - \ln T_k},~~~ + \pi_{k+1} = \frac{\ln T - \ln T_k}{\ln T_{k+1} - \ln T_k}. + + Sample either the index :math:`i = k` or :math:`i = k+1` according to the + point probabilities :math:`\pi_{k}` and :math:`\pi_{k+1}`. + +3. Determine the maximum value of the CDF :math:`P_{\text{br,max}}`. + +3. Sample the photon energies using the inverse transform method with the + tabulated CDF :math:`P_{\text{br}}(T_i, E)` i.e., + + .. math:: + + E = E_j \left[ (1 + a_j) \frac{\xi_2 P_{\text{br,max}} - + P_{\text{br}}(T_i, E_j)} {E_j p_{\text{br}}(T_i, E_j)} + 1 + \right]^{\frac{1}{1 + a_j}} + + where the interpolation factor :math:`a_j` is given by + + .. math:: + + a_j = \frac{\ln p_{\text{br}}(T_i,E_{j+1}) - \ln p_{\text{br}}(T_i,E_j)} + {\ln E_{j+1} - \ln E_j} + + and :math:`P_{\text{br}}(T_i, E_j) \le \xi_2 P_{\text{br,max}} \le + P_{\text{br}}(T_i, E_{j+1})`. + +We ignore the range of the electron or positron, i.e., the bremsstrahlung +photons are produced in the same location that the charged particle was +created. The direction of the photons is assumed to be the same as the +direction of the incident charged particle, which is a reasonable approximation +at higher energies when the bremsstrahlung radiation is emitted at small +angles. .. _photon_production: @@ -723,14 +1059,16 @@ emitted photon. .. _anomalous scattering: http://pd.chem.ucl.ac.uk/pdnn/diff1/anomscat.htm -.. _Kahn's rejection method: https://doi.org/10.2172/4353680 +.. _Kahn's rejection method: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/aecu-3259_kahn.pdf .. _Klein-Nishina: https://en.wikipedia.org/wiki/Klein%E2%80%93Nishina_formula -.. _LA-UR-04-0487: https://mcnp.lanl.gov/pdf_files/TechReport_2004_LANL_LA-UR-04-0487_Sood.pdf +.. _LA-UR-04-0487: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-04-0487.pdf -.. _LA-UR-04-0488: https://mcnp.lanl.gov/pdf_files/TechReport_2004_LANL_LA-UR-04-0488_SoodWhite.pdf +.. _LA-UR-04-0488: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-04-0488.pdf .. _Kaltiaisenaho: https://aaltodoc.aalto.fi/bitstream/handle/123456789/21004/master_Kaltiaisenaho_Toni_2016.pdf -.. _Salvat: https://doi.org/10.1787/32da5043-en +.. _Salvat: https://www.oecd-nea.org/globalsearch/download.php?doc=77434 + +.. _Sternheimer: https://doi.org/10.1103/PhysRevB.26.6067 diff --git a/docs/source/methods/random_numbers.rst b/docs/source/methods/random_numbers.rst index 4376bbdb0..0cefc9156 100644 --- a/docs/source/methods/random_numbers.rst +++ b/docs/source/methods/random_numbers.rst @@ -7,7 +7,7 @@ Random Number Generation In order to sample probability distributions, one must be able to produce random numbers. The standard technique to do this is to generate numbers on the interval :math:`[0,1)` from a deterministic sequence that has properties that -make it appear to be random, e.g., being uniformly distributed and not exhibiting +make it appear to be random, e.g. being uniformly distributed and not exhibiting correlation between successive terms. Since the numbers produced this way are not truly "random" in a strict sense, they are typically referred to as pseudorandom numbers, and the techniques used to generate them are pseudorandom @@ -15,11 +15,6 @@ number generators (PRNGs). Numbers sampled on the unit interval can then be transformed for the purpose of sampling other continuous or discrete probability distributions. -There are many different algorithms for pseudorandom number generation. OpenMC -currently uses `permuted congruential generator`_ (PCG), which builds on top of -the simpler linear congruential generator (LCG). Both algorithms are described -below. - ------------------------------ Linear Congruential Generators ------------------------------ @@ -42,8 +37,8 @@ be generated with a method chosen at random. Some theory should be used." Typically, :math:`M` is chosen to be a power of two as this enables :math:`x \mod M` to be performed using the bitwise AND operator with a bit mask. The constants for the linear congruential generator used by default in OpenMC are -:math:`g = 2806196910506780709`, :math:`c = 1`, and :math:`M = 2^{63}` (from -`L'Ecuyer `_). +:math:`g = 2806196910506780709`, :math:`c = 1`, and :math:`M = 2^{63}` (see +`L'Ecuyer`_). Skip-ahead Capability --------------------- @@ -55,8 +50,7 @@ want to skip ahead :math:`N` random numbers and :math:`N` is large, the cost of sampling :math:`N` random numbers to get to that position may be prohibitively expensive. Fortunately, algorithms have been developed that allow us to skip ahead in :math:`O(\log_2 N)` operations instead of :math:`O(N)`. One algorithm -to do so is described in a `paper by Brown -`_. This algorithm relies on the following +to do so is described in a paper by Brown_. This algorithm relies on the following relationship: .. math:: @@ -64,26 +58,15 @@ relationship: \xi_{i+k} = g^k \xi_i + c \frac{g^k - 1}{g - 1} \mod M -Note that equation :eq:`lcg-skipahead` has the same general form as equation -:eq:`lcg`, so the idea is to determine the new multiplicative and additive -constants in :math:`O(\log_2 N)` operations. +Note that equation :eq:`lcg-skipahead` has the same general form as equation :eq:`lcg`, so +the idea is to determine the new multiplicative and additive constants in +:math:`O(\log_2 N)` operations. + +.. only:: html + + .. rubric:: References --------------------------------- -Permuted Congruential Generators --------------------------------- - -The `permuted congruential generator`_ (PCG) algorithm aims to improve upon the -LCG algorithm by permuting the output. The algorithm works on the basic -principle of first advancing the generator state using the LCG algorithm and -then applying a permutation function on the LCG state to obtain the output. This -results in increased statistical quality as measured by common statistical tests -while exhibiting a very small performance overhead relative to the LCG algorithm -and an equivalent memory footprint. For further details, see the original -technical report by `O'Neill -`_. OpenMC uses the -PCG-RXS-M-XS variant with a 64-bit state and 64-bit output. - +.. _L'Ecuyer: https://doi.org/10.1090/S0025-5718-99-00996-5 +.. _Brown: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/anl-rn-arb-stride.pdf .. _linear congruential generator: https://en.wikipedia.org/wiki/Linear_congruential_generator - -.. _permuted congruential generator: https://en.wikipedia.org/wiki/Permuted_congruential_generator diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst deleted file mode 100644 index 8bc2a0a1b..000000000 --- a/docs/source/methods/random_ray.rst +++ /dev/null @@ -1,1172 +0,0 @@ -.. _methods_random_ray: - -========== -Random Ray -========== - -.. _methods_random_ray_intro: - -------------------- -What is Random Ray? -------------------- - -`Random ray `_ is a stochastic transport method, closely related to -the deterministic Method of Characteristics (MOC) [Askew-1972]_. Rather than -each ray representing a single neutron as in Monte Carlo, it represents a -characteristic line through the simulation geometry upon which the transport -equation can be written as an ordinary differential equation that can be solved -analytically (although with discretization required in energy, making it a -multigroup method). The behavior of the governing transport equation can be -approximated by solving along many characteristic tracks (rays) through the -system. Unlike particles in Monte Carlo, rays in random ray or MOC are not -affected by the material characteristics of the simulated problem---rays are -selected so as to explore the full simulation problem with a statistically equal -distribution in space and angle. - -.. raw:: html - - - -The above animation is an example of the random ray integration process at work, -showing a series of random rays being sampled and transported through the -geometry. In the following sections, we will discuss how the random ray solver -works. - ----------------------------------------------- -Why is a Random Ray Solver Included in OpenMC? ----------------------------------------------- - -* One area that Monte Carlo struggles with is maintaining numerical efficiency - in regions of low physical particle flux. Random ray, on the other hand, has - approximately even variance throughout the entire global simulation domain, - such that areas with low neutron flux are no less well known that areas of - high neutron flux. Absent weight windows in MC, random ray can be several - orders of magnitude faster than multigroup Monte Carlo in classes of problems - where areas with low physical neutron flux need to be resolved. While MC - uncertainty can be greatly improved with variance reduction techniques, they - add some user complexity, and weight windows can often be expensive to - generate via MC transport alone (e.g., via the `MAGIC method - `_). The random ray solver - may be used in future versions of OpenMC as a fast way to generate weight - windows for subsequent usage by the MC solver in OpenMC. - -* In practical implementation terms, random ray is mechanically very similar to - how Monte Carlo works, in terms of the process of ray tracing on constructive - solid geometry (CSG) and handling stochastic convergence, etc. In the original - 1972 paper by Askew that introduces MOC (which random ray is a variant of), he - stated: - - .. epigraph:: - - "One of the features of the method proposed [MoC] is that ... the - tracking process needed to perform this operation is common to the - proposed method ... and to Monte Carlo methods. Thus a single tracking - routine capable of recognizing a geometric arrangement could be utilized - to service all types of solution, choice being made depending which was - more appropriate to the problem size and required accuracy." - - -- Askew [Askew-1972]_ - - This prediction holds up---the additional requirements needed in OpenMC to - handle random ray transport turned out to be fairly small. - -* It amortizes the code complexity in OpenMC for representing multigroup cross - sections. There is a significant amount of interface code, documentation, and - complexity in allowing OpenMC to generate and use multigroup XS data in its - MGMC mode. Random ray allows the same multigroup data to be used, making full - reuse of these existing capabilities. - -------------------------------- -Random Ray Numerical Derivation -------------------------------- - -In this section, we will derive the numerical basis for the random ray solver -mode in OpenMC. The derivation of random ray is also discussed in several papers -(`1 `_, `2 `_, `3 `_), and some of those -derivations are reproduced here verbatim. Several extensions are also made to -add clarity, particularly on the topic of OpenMC's treatment of cell volumes in -the random ray solver. - -~~~~~~~~~~~~~~~~~~~~~~~~~ -Method of Characteristics -~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Boltzmann neutron transport equation is a partial differential equation -(PDE) that describes the angular flux within a system. It is a balance equation, -with the streaming and absorption terms typically appearing on the left hand -side, which are balanced by the scattering source, fission, and fixed source -terms on the right hand side. - -.. math:: - :label: transport - - \begin{aligned} - \mathbf{\Omega} \cdot \mathbf{\nabla} \psi(\mathbf{r},\mathbf{\Omega},E) & + \Sigma_t(\mathbf{r},E) \psi(\mathbf{r},\mathbf{\Omega},E) = \\ - & \int_0^\infty d E^\prime \int_{4\pi} d \Omega^{\prime} \Sigma_s(\mathbf{r},\mathbf{\Omega}^\prime \rightarrow \mathbf{\Omega}, E^\prime \rightarrow E) \psi(\mathbf{r},\mathbf{\Omega}^\prime, E^\prime) \\ - & + \frac{\chi(\mathbf{r}, E)}{4\pi k_{eff}} \int_0^\infty dE^\prime \nu \Sigma_f(\mathbf{r},E^\prime) \int_{4\pi}d \Omega^\prime \psi(\mathbf{r},\mathbf{\Omega}^\prime,E^\prime) - \end{aligned} - -In Equation :eq:`transport`, :math:`\psi` is the angular neutron flux. This -parameter represents the total distance traveled by all neutrons in a particular -direction inside of a control volume per second, and is often given in units of -:math:`1/(\text{cm}^{2} \text{s})`. The angular direction unit vector, -:math:`\mathbf{\Omega}`, represents the direction of travel for the neutron. The -spatial position vector, :math:`\mathbf{r}`, represents the location within the -simulation. The neutron energy, :math:`E`, or speed in continuous space, is -often given in units of electron volts. The total macroscopic neutron cross -section is :math:`\Sigma_t`. This value represents the total probability of -interaction between a neutron traveling at a certain speed (i.e., neutron energy -:math:`E`) and a target nucleus (i.e., the material through which the neutron is -traveling) per unit path length, typically given in units of -:math:`1/\text{cm}`. Macroscopic cross section data is a combination of -empirical data and quantum mechanical modeling employed in order to generate an -evaluation represented either in pointwise form or resonance parameters for each -target isotope of interest in a material, as well as the density of the -material, and is provided as input to a simulation. The scattering neutron cross -section, :math:`\Sigma_s`, is similar to the total cross section but only -measures scattering interactions between the neutron and the target nucleus, and -depends on the change in angle and energy the neutron experiences as a result of -the interaction. Several additional reactions like (n,2n) and (n,3n) are -included in the scattering transfer cross section. The fission neutron cross -section, :math:`\Sigma_f`, is also similar to the total cross section but only -measures the fission interaction between a neutron and a target nucleus. The -energy spectrum for neutrons born from fission, :math:`\chi`, represents a known -distribution of outgoing neutron energies based on the material that fissioned, -which is taken as input data to a computation. The average number of neutrons -born per fission is :math:`\nu`. The eigenvalue of the equation, -:math:`k_{eff}`, represents the effective neutron multiplication factor. If the -right hand side of Equation :eq:`transport` is condensed into a single term, -represented by the total neutron source term :math:`Q(\mathbf{r}, \mathbf{\Omega},E)`, -the form given in Equation :eq:`transport_simple` is reached. - -.. math:: - :label: transport_simple - - \overbrace{\mathbf{\Omega} \cdot \mathbf{\nabla} \psi(\mathbf{r},\mathbf{\Omega},E)}^{\text{streaming term}} + \overbrace{\Sigma_t(\mathbf{r},E) \psi(\mathbf{r},\mathbf{\Omega},E)}^{\text{absorption term}} = \overbrace{Q(\mathbf{r}, \mathbf{\Omega},E)}^{\text{total neutron source term}} - -Fundamentally, MOC works by solving Equation :eq:`transport_simple` along a -single characteristic line, thus altering the full spatial and angular scope of -the transport equation into something that holds true only for a particular -linear path (or track) through the reactor. These tracks are linear for neutral -particles that are not subject to field effects. With our transport equation in -hand, we will now derive the solution along a track. To accomplish this, we -parameterize :math:`\mathbf{r}` with respect to some reference location -:math:`\mathbf{r}_0` such that :math:`\mathbf{r} = \mathbf{r}_0 + s\mathbf{\Omega}`. In this -manner, Equation :eq:`transport_simple` can be rewritten for a specific segment -length :math:`s` at a specific angle :math:`\mathbf{\Omega}` through a constant -cross section region of the reactor geometry as in Equation :eq:`char_long`. - -.. math:: - :label: char_long - - \mathbf{\Omega} \cdot \mathbf{\nabla} \psi(\mathbf{r}_0 + s\mathbf{\Omega},\mathbf{\Omega},E) + \Sigma_t(\mathbf{r}_0 + s\mathbf{\Omega},E) \psi(\mathbf{r}_0 + s\mathbf{\Omega},\mathbf{\Omega},E) = Q(\mathbf{r}_0 + s\mathbf{\Omega}, \mathbf{\Omega},E) - -As this equation holds along a one dimensional path, we can assume the -dependence of :math:`s` on :math:`\mathbf{r}_0` and :math:`\mathbf{\Omega}` such that -:math:`\mathbf{r}_0 + s\mathbf{\Omega}` simplifies to :math:`s`. When the differential -operator is also applied to the angular flux :math:`\psi`, we arrive at the -characteristic form of the Boltzmann Neutron Transport Equation given in -Equation :eq:`char`. - -.. math:: - :label: char - - \frac{d}{ds} \psi(s,\mathbf{\Omega},E) + \Sigma_t(s,E) \psi(s,\mathbf{\Omega},E) = Q(s, \mathbf{\Omega},E) - -An analytical solution to this characteristic equation can be achieved with the -use of an integrating factor: - -.. math:: - :label: int_factor - - e^{ \int_0^s ds' \Sigma_t (s', E)} - -to arrive at the final form of the characteristic equation shown in Equation -:eq:`full_char`. - -.. math:: - :label: full_char - - \psi(s,\mathbf{\Omega},E) = \psi(\mathbf{r}_0,\mathbf{\Omega},E) e^{-\int_0^s ds^\prime \Sigma_t(s^\prime,E)} + \int_0^s ds^{\prime\prime} Q(s^{\prime\prime},\mathbf{\Omega}, E) e^{-\int_{s^{\prime\prime}}^s ds^\prime \Sigma_t(s^\prime,E)} - -With this characteristic form of the transport equation, we now have an -analytical solution along a linear path through any constant cross section -region of a system. While the solution only holds along a linear track, no -discretizations have yet been made. - -Similar to many other solution approaches to the Boltzmann neutron transport -equation, the MOC approach also uses a "multigroup" approximation in order to -discretize the continuous energy spectrum of neutrons traveling through the -system into fixed set of energy groups :math:`G`, where each group :math:`g \in -G` has its own specific cross section parameters. This makes the difficult -non-linear continuous energy dependence much more manageable as group wise cross -section data can be precomputed and fed into a simulation as input data. The -computation of multigroup cross section data is not a trivial task and can -introduce errors in the simulation. However, this is an active field of research -common to all multigroup methods, and there are numerous generation methods -available that are capable of reducing the biases introduced by the multigroup -approximation. Commonly used methods include the subgroup self-shielding method -and use of fast (unconverged) Monte Carlo simulations to produce cross section -estimates. It is important to note that Monte Carlo methods are capable of -treating the energy variable of the neutron continuously, meaning that they do -not need to make this approximation and are therefore not subject to any -multigroup errors. - -Following the multigroup discretization, another assumption made is that a large -and complex problem can be broken up into small constant cross section regions, -and that these regions have group dependent, flat, isotropic sources (fission -and scattering), :math:`Q_g`. Anisotropic as well as higher order sources are -also possible with MOC-based methods. With these key assumptions, the multigroup -MOC form of the neutron transport equation can be written as in Equation -:eq:`moc_final`. - -.. math:: - :label: moc_final - - \psi_g(s, \mathbf{\Omega}) = \psi_g(\mathbf{r_0}, \mathbf{\Omega}) e^{-\int_0^s ds^\prime \Sigma_{t_g}(s^\prime)} + \int_0^s ds^{\prime\prime} Q_g(s^{\prime\prime},\mathbf{\Omega}) e^{-\int_{s^{\prime\prime}}^s ds^\prime \Sigma_{t_g}(s^\prime)} - -The CSG definition of the system is used to create spatially defined source -regions (each region being denoted as :math:`i`). These neutron source regions -are often approximated as being constant -(flat) in source intensity but can also be defined using a higher order source -(linear, quadratic, etc.) that allows for fewer source regions to be required to -achieve a specified solution fidelity. In OpenMC, the approximation of a -spatially constant isotropic fission and scattering source :math:`Q_{i,g}` in -cell :math:`i` leads -to simple exponential attenuation along an individual characteristic of length -:math:`s` given by Equation :eq:`fsr_attenuation`. - -.. math:: - :label: fsr_attenuation - - \psi_g(s) = \psi_g(0) e^{-\Sigma_{t,i,g} s} + \frac{Q_{i,g}}{\Sigma_{t,i,g}} \left( 1 - e^{-\Sigma_{t,i,g} s} \right) - -For convenience, we can also write this equation in terms of the incoming and -outgoing angular flux (:math:`\psi_g^{in}` and :math:`\psi_g^{out}`), and -consider a specific tracklength for a particular ray :math:`r` crossing cell -:math:`i` as :math:`\ell_r`, as in: - -.. math:: - :label: fsr_attenuation_in_out - - \psi_g^{out} = \psi_g^{in} e^{-\Sigma_{t,i,g} \ell_r} + \frac{Q_{i,g}}{\Sigma_{t,i,g}} \left( 1 - e^{-\Sigma_{t,i,g} \ell_r} \right) . - -We can then define the average angular flux of a single ray passing through the -cell as: - -.. math:: - :label: average - - \overline{\psi}_{r,i,g} = \frac{1}{\ell_r} \int_0^{\ell_r} \psi_{g}(s)ds . - -We can then substitute in Equation :eq:`fsr_attenuation` and solve, resulting -in: - -.. math:: - :label: average_solved - - \overline{\psi}_{r,i,g} = \frac{Q_{i,g}}{\Sigma_{t,i,g}} - \frac{\psi_{r,g}^{out} - \psi_{r,g}^{in}}{\ell_r \Sigma_{t,i,g}} . - -By rearranging Equation :eq:`fsr_attenuation_in_out`, we can then define -:math:`\Delta \psi_{r,g}` as the change in angular flux for ray :math:`r` -passing through region :math:`i` as: - -.. math:: - :label: delta_psi - - \Delta \psi_{r,g} = \psi_{r,g}^{in} - \psi_{r,g}^{out} = \left(\psi_{r,g}^{in} - \frac{Q_{i,g}}{\Sigma_{t,i,g}} \right) \left( 1 - e^{-\Sigma_{t,i,g} \ell_r} \right) . - -Equation :eq:`delta_psi` is a useful expression as it is easily computed with -the known inputs for a ray crossing through the region. - -By substituting :eq:`delta_psi` into :eq:`average_solved`, we can arrive at a -final expression for the average angular flux for a ray crossing a region as: - -.. math:: - :label: average_psi_final - - \overline{\psi}_{r,i,g} = \frac{Q_{i,g}}{\Sigma_{t,i,g}} + \frac{\Delta \psi_{r,g}}{\ell_r \Sigma_{t,i,g}}. - -~~~~~~~~~~~ -Random Rays -~~~~~~~~~~~ - -In the previous subsection, the governing characteristic equation along a 1D -line through the system was written, such that an analytical solution for the -ODE can be computed. If enough characteristic tracks (ODEs) are solved, then the -behavior of the governing PDE can be numerically approximated. In traditional -deterministic MOC, the selection of tracks is chosen deterministically, where -azimuthal and polar quadratures are defined along with even track spacing in -three dimensions. This is the point at which random ray diverges from -deterministic MOC numerically. In the random ray method, rays are randomly -sampled from a uniform distribution in space and angle and tracked along a -predefined distance through the geometry before terminating. **Importantly, -different rays are sampled each power iteration, leading to a fully stochastic -convergence process.** This results in a need to utilize both inactive and -active batches as in the Monte Carlo method. - -While Monte Carlo implicitly converges the scattering source fully within each -iteration, random ray (and MOC) solvers are not typically written to fully -converge the scattering source within a single iteration. Rather, both the -fission and scattering sources are updated each power iteration, thus requiring -enough outer iterations to reach a stationary distribution in both the fission -source and scattering source. So, even in a low dominance ratio problem like a -2D pincell, several hundred inactive batches may still be required with random -ray to allow the scattering source to fully develop, as neutrons undergoing -hundreds of scatters may constitute a non-trivial contribution to the fission -source. We note that use of a two-level second iteration scheme is sometimes -used by some MOC or random ray solvers so as to fully converge the scattering -source with many inner iterations before updating the fission source in the -outer iteration. It is typically more efficient to use the single level -iteration scheme, as there is little reason to spend so much work converging the -scattering source if the fission source is not yet converged. - -Overall, the difference in how random ray and Monte Carlo converge the -scattering source means that in practice, random ray typically requires more -inactive iterations than are required in Monte Carlo. While a Monte Carlo -simulation may need 100 inactive iterations to reach a stationary source -distribution for many problems, a random ray solve will likely require 1,000 -iterations or more. Source convergence metrics (e.g., Shannon entropy) are thus -recommended when performing random ray simulations to ascertain when the source -has fully developed. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Converting Angular Flux to Scalar Flux -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Thus far in our derivation, we have been able to write analytical equations that -solve for the change in angular flux of a ray crossing a flat source region -(Equation :eq:`delta_psi`) as well as the ray's average angular flux through -that region (Equation :eq:`average_psi_final`). To determine the source for the -next power iteration, we need to assemble our estimates of angular fluxes from -all the sampled rays into scalar fluxes within each FSR. - -We can define the scalar flux in region :math:`i` as: - -.. math:: - :label: integral - - \phi_i = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} . - -The integral in the numerator: - -.. math:: - :label: numerator - - \int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r} . - -is not known analytically, but with random ray, we are going the numerically -approximate it by discretizing over a finite number of tracks (with a finite -number of locations and angles) crossing the domain. We can then use the -characteristic method to determine the total angular flux along that line. - -Conceptually, this can be thought of as taking a volume-weighted sum of angular -fluxes for all :math:`N_i` rays that happen to pass through cell :math:`i` that -iteration. When written in discretized form (with the discretization happening -in terms of individual ray segments :math:`r` that pass through region -:math:`i`), we arrive at: - -.. math:: - :label: discretized - - \phi_{i,g} = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} = \overline{\overline{\psi}}_{i,g} \approx \frac{\sum\limits_{r=1}^{N_i} \ell_r w_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r w_r} . - -Here we introduce the term :math:`w_r`, which represents the "weight" of the ray -(its 2D area), such that the volume that a ray is responsible for can be -determined by multiplying its length :math:`\ell` by its weight :math:`w`. As -the scalar flux vector is a shape function only, we are actually free to -multiply all ray weights :math:`w` by any constant such that the overall shape -is still maintained, even if the magnitude of the shape function changes. Thus, -we can simply set :math:`w_r` to be unity for all rays, such that: - -.. math:: - :label: weights - - \text{Volume of cell } i = V_i \approx \sum\limits_{r=1}^{N_i} \ell_r w_r = \sum\limits_{r=1}^{N_i} \ell_r . - -We can then rewrite our discretized equation as: - -.. math:: - :label: discretized_2 - - \phi_{i,g} \approx \frac{\sum\limits_{r=1}^{N_i} \ell_r w_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r w_r} = \frac{\sum\limits_{r=1}^{N_i} \ell_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r} . - -Thus, the scalar flux can be inferred if we know the volume weighted sum of the -average angular fluxes that pass through the cell. Substituting -:eq:`average_psi_final` into :eq:`discretized_2`, we arrive at: - -.. math:: - :label: scalar_full - - \phi_{i,g} = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} = \overline{\overline{\psi}}_{i,g} = \frac{\sum\limits_{r=1}^{N_i} \ell_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r} = \frac{\sum\limits_{r=1}^{N_i} \ell_r \frac{Q_{i,g}}{\Sigma_{t,i,g}} + \frac{\Delta \psi_{r,g}}{\ell_r \Sigma_{t,i,g}}}{\sum\limits_{r=1}^{N_i} \ell_r}, - -which when partially simplified becomes: - -.. math:: - :label: scalar_four_vols - - \phi = \frac{Q_{i,g} \sum\limits_{r=1}^{N_i} \ell_r}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} + \frac{\sum\limits_{r=1}^{N_i} \ell_r \frac{\Delta \psi_i}{\ell_r}}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} . - -Note that there are now four (seemingly identical) volume terms in this equation. - -.. _methods_random_ray_vol: - -~~~~~~~~~~~~~~ -Volume Dilemma -~~~~~~~~~~~~~~ - -At first glance, Equation :eq:`scalar_four_vols` appears ripe for cancellation -of terms. Mathematically, such cancellation allows us to arrive at the following -"naive" estimator for the scalar flux: - -.. math:: - :label: phi_naive - - \phi_{i,g}^{naive} = \frac{Q_{i,g} }{\Sigma_{t,i,g}} + \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} . - -This derivation appears mathematically sound at first glance but unfortunately -raises a serious issue as discussed in more depth by `Tramm et al. -`_ and `Cosgrove and Tramm `_. Namely, the second -term: - -.. math:: - :label: ratio_estimator - - \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} - -features stochastic variables (the sums over random ray lengths and angular -fluxes) in both the numerator and denominator, making it a stochastic ratio -estimator, which is inherently biased. In practice, usage of the naive estimator -does result in a biased, but "consistent" estimator (i.e., it is biased, but -the bias tends towards zero as the sample size increases). Empirically, this -bias tends to effect eigenvalue calculations much more significantly than in -fixed source simulations. Experimentally, the right answer can be obtained with -this estimator, though for eigenvalue simulations a very fine ray density is -required to eliminate the bias. - -How might we solve the biased ratio estimator problem? While there is no obvious -way to alter the numerator term (which arises from the characteristic -integration approach itself), there is potentially more flexibility in how we -treat the stochastic term in the denominator, :math:`\sum\limits_{r=1}^{N_i} -\ell_r` . From Equation :eq:`weights` we know that this term can be directly -inferred from the volume of the problem, which does not actually change between -iterations. Thus, an alternative treatment for this "volume" term in the -denominator is to replace the actual stochastically sampled total track length -with the expected value of the total track length. For instance, if the true -volume of the FSR is known (as is the total volume of the full simulation domain -and the total tracklength used for integration that iteration), then we know the -true expected value of the tracklength in that FSR. That is, if a FSR accounts -for 2% of the overall volume of a simulation domain, then we know that the -expected value of tracklength in that FSR will be 2% of the total tracklength -for all rays that iteration. This is a key insight, as it allows us to the -replace the actual tracklength that was accumulated inside that FSR each -iteration with the expected value. - -If we know the analytical volumes, then those can be used to directly compute -the expected value of the tracklength in each cell, :math:`L_{avg}`. However, as -the analytical volumes are not typically known in OpenMC due to the usage of -user-defined constructive solid geometry, we need to source this quantity from -elsewhere. An obvious choice is to simply accumulate the total tracklength -through each FSR across all iterations (batches) and to use that sum to compute -the expected average length per iteration, as: - -.. math:: - :label: L_avg - - \sum\limits^{}_{i} \ell_i \approx L_{avg} = \frac{\sum\limits^{B}_{b}\sum\limits^{N_i}_{r=1} \ell_{b,r} }{B} - -where :math:`b` is a single batch in :math:`B` total batches simulated so far. - -In this manner, the expected value of the tracklength will become more refined -as iterations continue, until after many iterations the variance of the -denominator term becomes trivial compared to the numerator term, essentially -eliminating the presence of the stochastic ratio estimator. A "simulation -averaged" estimator is therefore: - -.. math:: - :label: phi_sim - - \phi_{i,g}^{simulation} = \frac{Q_{i,g} }{\Sigma_{t,i,g}} + \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}}{\Sigma_{t,i,g} L_{avg}} - -In practical terms, the "simulation averaged" estimator is virtually -indistinguishable numerically from use of the true analytical volume to estimate -this term. Note also that the term "simulation averaged" refers only to the -volume/length treatment, the scalar flux estimate itself is computed fully again -each iteration. - -There are some drawbacks to this method. Recall, this denominator volume term -originally stemmed from taking a volume weighted integral of the angular flux, -in which case the denominator served as a normalization term for the numerator -integral in Equation :eq:`integral`. Essentially, we have now used a different -term for the volume in the numerator as compared to the normalizing volume in -the denominator. The inevitable mismatch (due to noise) between these two -quantities results in a significant increase in variance, and can even result in -the generation of negative fluxes. Notably, the same problem occurs if using a -tracklength estimate based on the analytical volume, as again the numerator -integral and the normalizing denominator integral no longer match on a -per-iteration basis. - -In practice, the simulation averaged method does completely remove the bias seen -when using the naive estimator, though at the cost of a notable increase in -variance. Empirical testing reveals that on most eigenvalue problems, the -simulation averaged estimator does win out overall in numerical performance, as -a much coarser quadrature can be used resulting in faster runtimes overall. -Thus, OpenMC uses the simulation averaged estimator as default in its random ray -mode for eigenvalue solves. - -OpenMC also features a "hybrid" volume estimator that uses the naive estimator -for all regions containing an external (fixed) source term. For all other -source regions, the "simulation averaged" estimator is used. This typically achieves -a best of both worlds result, with the benefits of the low bias simulation averaged -estimator in most regions, while preventing instability and/or large biases in regions -with external source terms via use of the naive estimator. In general, it is -recommended to use the "hybrid" estimator, which is the default method used -in OpenMC. If instability is encountered despite high ray densities, then -the naive estimator may be preferable. - -A table that summarizes the pros and cons, as well as recommendations for -different use cases, is given in the :ref:`volume -estimators` section of the user guide. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -What Happens When a Source Region is Missed? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Given the stochastic nature of random ray, when low ray densities are used it is -common for small source regions to occasionally not be hit by any rays in a -particular power iteration :math:`n`. This naturally collapses the flux estimate -in that cell for the iteration from Equation :eq:`phi_naive` to: - -.. math:: - :label: phi_missed_one - - \phi_{i,g,n}^{missed} = \frac{Q_{i,g,n} }{\Sigma_{t,i,g}} - -as the streaming operator has gone to zero. While this is obviously innacurate -as it ignores transport, for most problems where the region is only occasionally -missed this estimator does not tend to introduce any significant bias. - -However, in cases where the total cross section in the region is very small -(e.g., a void-like material) and where a strong external fixed source has been -placed, then this treatment causes major issues. In this pathological case, the -lack of transport forces the entirety of the fixed source to effectively be -contained and collided within the cell, which for a low cross section region is -highly unphysical. The net effect is that a very high estimate of the flux -(often orders of magnitude higher than is expected) is generated that iteration, -which cannot be washed out even with hundreds or thousands of iterations. Thus, -huge biases are often seen in spatial tallies containing void-like regions with -external sources unless a high enough ray density is used such that all source -regions are always hit each iteration. This is particularly problematic as -external sources placed in void-like regions are very common in many types of -fixed source analysis. - -For regions where external sources are present, to eliminate this bias it is -therefore preferable to simply use the previous iteration's estimate of the flux -in that cell, as: - -.. math:: - :label: phi_missed_two - - \phi_{i,g,n}^{missed} = \phi_{i,g,n-1} . - -When linear sources are present, the flux moments from the previous iteration -are used in the same manner. While this introduces some small degree of -correlation to the simulation, for miss rates on the order of a few percent the -correlations are trivial and the bias is eliminated. Thus, in OpenMC the -previous iteration's scalar flux estimate is applied to cells that are missed -where there is an external source term present within the cell. - -~~~~~~~~~~~~~~~ -Power Iteration -~~~~~~~~~~~~~~~ - -Given a starting source term, we now have a way of computing an estimate of the -scalar flux in each cell by way of transporting rays randomly through the -domain, recording the change in angular flux for the rays into each cell as they -make their traversals, and summing these contributions up as in Equation -:eq:`phi_sim`. How then do we turn this into an iterative process such that we -improve the estimate of the source and scalar flux over many iterations, given -that our initial starting source will just be a guess? - -In an eigenvalue simulation, the source :math:`Q^{n}` for iteration :math:`n` -can be inferred from the scalar flux from the previous iteration :math:`n-1` as: - -.. math:: - :label: source_update - - Q^{n}(i, g) = \frac{\chi}{k^{n-1}_{eff}} \nu \Sigma_f(i, g) \phi^{n-1}(g) + \sum\limits^{G}_{g'} \Sigma_{s}(i,g,g') \phi^{n-1}(g') - -where :math:`Q^{n}(i, g)` is the total source (fission + scattering) in region -:math:`i` and energy group :math:`g`. Notably, the in-scattering source in group -:math:`g` must be computed by summing over the contributions from all groups -:math:`g' \in G`. - -The eigenvalue for iteration :math:`n` can be computed as: - -.. math:: - :label: eigenvalue_update - - k^{n}_{eff} = k^{n-1}_{eff} \frac{F^n}{F^{n-1}}, - -where the total spatial- and energy-integrated fission rate :math:`F^n` in -iteration :math:`n` can be computed as: - -.. math:: - :label: fission_source - - F^n = \sum\limits^{M}_{i} \left( V_i \sum\limits^{G}_{g} \nu \Sigma_f(i, g) \phi^{n}(g) \right) - -where :math:`M` is the total number of FSRs in the simulation. Similarly, the -total spatial- and energy-integrated fission rate :math:`F^{n-1}` in iteration -:math:`n-1` can be computed as: - -.. math:: - :label: fission_source_prev - - F^{n-1} = \sum\limits^{M}_{i} \left( V_i \sum\limits^{G}_{g} \nu \Sigma_f(i, g) \phi^{n-1}(g) \right) - -Notably, the volume term :math:`V_i` appears in the eigenvalue update equation. -The same logic applies to the treatment of this term as was discussed earlier. -In OpenMC, we use the "simulation averaged" volume (Equation :eq:`L_avg`) -derived from summing over all ray tracklength contributions to a FSR over all -iterations and dividing by the total integration tracklength to date. Thus, -Equation :eq:`fission_source` becomes: - -.. math:: - :label: fission_source_volumed - - F^n = \sum\limits^{M}_{i} \left( L_{avg} \sum\limits^{G}_{g} \nu \Sigma_f(i, g) \phi^{n}(g) \right) - -and a similar substitution can be made to update Equation -:eq:`fission_source_prev` . In OpenMC, the most up-to-date version of the volume -estimate is used, such that the total fission source from the previous iteration -(:math:`n-1`) is also recomputed each iteration. - -In a fixed source simulation, the fission source is replaced by a user specified -fixed source term :math:`Q_\text{fixed}(i,E)`, which is defined for each FSR and -energy group. This additional source term is applied at this stage for -generating the next iteration's source estimate as: - -.. math:: - :label: fixed_source_update - - Q^{n}(i, g) = Q_\text{fixed}(i,g) + \sum\limits^{G}_{g'} \Sigma_{s}(i,g,g') \phi^{n-1}(g') - -and no eigenvalue is computed. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Ray Starting Conditions and Inactive Length -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Another key area of divergence between deterministic MOC and random ray is the -starting conditions for rays. In deterministic MOC, the angular flux spectrum -for rays are stored at any reflective or periodic boundaries so as to provide a -starting condition for the next iteration. As there are many tracks, storage of -angular fluxes can become costly in terms of memory consumption unless there are -only vacuum boundaries present. - -In random ray, as the starting locations of rays are sampled anew each -iteration, the initial angular flux spectrum for the ray is unknown. While a -guess can be made by taking the isotropic source from the FSR the ray was -sampled in, direct usage of this quantity would result in significant bias and -error being imparted on the simulation. - -Thus, an `on-the-fly approximation method `_ was developed (known -as the "dead zone"), where the first several mean free paths of a ray are -considered to be "inactive" or "read only". In this sense, the angular flux is -solved for using the MOC equation, but the ray does not "tally" any scalar flux -back to the FSRs that it travels through. After several mean free paths have -been traversed, the ray's angular flux spectrum typically becomes dominated by -the accumulated source terms from the cells it has traveled through, while the -(incorrect) starting conditions have been attenuated away. In the animation in -the :ref:`introductory section on this page `, the -yellow portion of the ray lengths is the dead zone. As can be seen in this -animation, the tallied :math:`\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}` term -that is plotted is not affected by the ray when the ray is within its inactive -length. Only when the ray enters its active mode does the ray contribute to the -:math:`\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}` sum for the iteration. - -~~~~~~~~~~~~~~~~~~~~~ -Ray Ending Conditions -~~~~~~~~~~~~~~~~~~~~~ - -To ensure that a uniform density of rays is integrated in space and angle -throughout the simulation domain, after exiting the initial inactive "dead zone" -portion of the ray, the rays are run for a user-specified distance. Typically, a -choice of at least several times the length of the inactive "dead zone" is made -so as to amortize the cost of the dead zone. For example, if a dead zone of 30 -cm is selected, then an active length of 300 cm might be selected so that the -cost of the dead zone is at most 10% of the overall runtime. - --------------------- -Simplified Algorithm --------------------- - -A simplified set of functions that execute a single random ray power iteration -are given below. Not all global variables are defined in this illustrative -example, but the high level components of the algorithm are shown. A number of -significant simplifications are made for clarity---for example, no inactive -"dead zone" length is shown, geometry operations are abstracted, no parallelism -(or thread safety) is expressed, a naive exponential treatment is used, and rays -are not halted at their exact termination distances, among other subtleties. -Nonetheless, the below algorithms may be useful for gaining intuition on the -basic components of the random ray process. Rather than expressing the algorithm -in abstract pseudocode, C++ is used to make the control flow easier to -understand. - -The first block below shows the logic for a single power iteration (batch): - -.. code-block:: C++ - - double power_iteration(double k_eff) { - - // Update source term (scattering + fission) - update_neutron_source(k_eff); - - // Reset scalar fluxes to zero - fill(global::scalar_flux_new, 0.0f); - - // Transport sweep over all random rays for the iteration - for (int i = 0; i < nrays; i++) { - RandomRay ray; - initialize_ray(ray); - transport_single_ray(ray); - } - - // Normalize scalar flux and update volumes - normalize_scalar_flux_and_volumes(); - - // Add source to scalar flux, compute number of FSR hits - add_source_to_scalar_flux(); - - // Compute k-eff using updated scalar flux - k_eff = compute_k_eff(k_eff); - - // Set phi_old = phi_new - global::scalar_flux_old.swap(global::scalar_flux_new); - - return k_eff; - } - -The second function shows the logic for transporting a single ray within the -transport loop: - -.. code-block:: C++ - - void transport_single_ray(RandomRay& ray) { - - // Reset distance to zero - double distance = 0.0; - - // Continue transport of ray until active length is reached - while (distance < user_setting::active_length) { - // Ray trace to find distance to next surface (i.e., segment length) - double s = distance_to_nearest_boundary(ray); - - // Attenuate flux (and accumulate source/attenuate) on segment - attenuate_flux(ray, s); - - // Advance particle to next surface - ray.location = ray.location + s * ray.direction; - - // Move ray across the surface - cross_surface(ray); - - // Add segment length "s" to total distance traveled - distance += s; - } - } - -The final function below shows the logic for solving for the characteristic MOC -equation (and accumulating the scalar flux contribution of the ray into the -scalar flux value for the FSR). - -.. code-block:: C++ - - void attenuate_flux(RandomRay& ray, double s) { - - // Determine which flat source region (FSR) the ray is currently in - int fsr = get_fsr_id(ray.location); - - // Determine material type - int material = get_material_type(fsr); - - // MOC incoming flux attenuation + source contribution/attenuation equation - for (int e = 0; e < global::n_energy_groups; e++) { - float sigma_t = global::macro_xs[material].total; - float tau = sigma_t * s; - float delta_psi = (ray.angular_flux[e] - global::source[fsr][e] / sigma_t) * (1 - exp(-tau)); - ray.angular_flux_[e] -= delta_psi; - global::scalar_flux_new[fsr][e] += delta_psi; - } - - // Record total tracklength in this FSR (to compute volume) - global::volume[fsr] += s; - } - -.. _methods_random_tallies: - ------------------------- -How are Tallies Handled? ------------------------- - -Most tallies, filters, and scores that you would expect to work with a -multigroup solver like random ray should work. For example, you can define 3D -mesh tallies with energy filters and flux, fission, and nu-fission scores, etc. - -There are some restrictions though. For starters, it is assumed that all filter -mesh boundaries will conform to physical surface boundaries (or lattice -boundaries) in the simulation geometry. It is acceptable for multiple cells -(FSRs) to be contained within a filter mesh cell (e.g., pincell-level or -assembly-level tallies should work), but it is currently left as undefined -behavior if a single simulation cell is able to score to multiple filter mesh -cells. In the future, the capability to fully support mesh tallies may be added -to OpenMC, but for now this restriction needs to be respected. - -Flux tallies are handled slightly differently than in Monte Carlo. By default, -in MC, flux tallies are reported in units of tracklength (cm), so must be -manually normalized by volume by the user to produce an estimate of flux in -units of cm\ :sup:`-2`\. Alternatively, MC flux tallies can be normalized via a -separated volume calculation process as discussed in the :ref:`Volume -Calculation Section`. In random ray, as the volumes are -computed on-the-fly as part of the transport process, the flux tallies can -easily be reported either in units of flux (cm\ :sup:`-2`\) or tracklength (cm). -By default, the unnormalized flux values (units of cm) will be reported. If the -user wishes to received volume normalized flux tallies, then an option for this -is available, as described in the :ref:`User Guide`. - --------------- -Linear Sources --------------- - -Instead of making a flat source approximation, as in the previous section, a -Linear Source (LS) approximation can be used. Different LS approximations have -been developed; the OpenMC implementation follows the MOC LS scheme described by -`Ferrer `_. The LS source along a characteristic is given by: - -.. math:: - :label: linear_source - - Q_{i,g}(s) = \bar{Q}_{r,i,g} + \hat{Q}_{r,i,g}(s-\ell_{r}/2), - -where the source, :math:`Q_{i,g}(s)`, varies linearly along the track and -:math:`\bar{Q}_{r,i,g}` and :math:`\hat{Q}_{r,i,g}` are track specific source -terms to define shortly. Integrating the source, as done in Equation -:eq:`moc_final`, leads to - -.. math:: - :label: lsr_attenuation - - \psi^{out}_{r,g}=\psi^{in}_{r,g} + \left(\frac{\bar{Q}_{r, i, g}}{\Sigma_{\mathrm{t}, i, g}}-\psi^{in}_{r,g}\right) - F_{1}\left(\tau_{i,g}\right)+\frac{\hat{Q}_{r, i, g}^{g}}{2\left(\Sigma_{\mathrm{t}, i,g}\right)^{2}} F_{2}\left(\tau_{i,g}\right), - -where for simplicity the term :math:`\tau_{i,g}` and the expoentials :math:`F_1` -and :math:`F_2` are introduced, given by: - -.. math:: - :label: tau - - \tau_{i,g} = \Sigma_{\mathrm{t,i,g}} \ell_{r} - -.. math:: - :label: f1 - - F_1(\tau) = 1 - e^{-\tau}, - -and - -.. math:: - :label: f2 - - F_{2}\left(\tau\right) = 2\left[\tau-F_{1}\left(\tau\right)\right]-\tau F_{1}\left(\tau\right). - - -To solve for the track specific source terms in Equation :eq:`linear_source` we -first define a local reference frame. If we now refer to :math:`\mathbf{r}` as -the global coordinate and introduce the source region specific coordinate -:math:`\mathbf{u}` such that, - -.. math:: - :label: local_coord - - \mathbf{u}_{r} = \mathbf{r}-\mathbf{r}_{\mathrm{c}}, - -where :math:`\mathbf{r}_{\mathrm{c}}` is the centroid of the source region of -interest. In turn :math:`\mathbf{u}_{r,\mathrm{c}}` and :math:`\mathbf{u}_{r,0}` -are the local centroid and entry positions of a ray. The computation of the -local and global centroids are described further by `Gunow `_. - -Using the local position, the source in a source region is given by: - -.. math:: - :label: region_source - - \tilde{Q}(\boldsymbol{x}) ={Q}_{i,g}+ \boldsymbol{\vec{Q}}_{i,g} \cdot \mathbf{u}_{r}\;\mathrm{,} - -This definition allows us to solve for our characteric source terms resulting in: - -.. math:: - :label: source_term_1 - - \bar{Q}_{r, i, g} = Q_{i,g} + \left[\mathbf{u}_{r,\mathrm{c}} \cdot \boldsymbol{\vec{Q}}_{i,g}\right], - -.. math:: - :label: source_term_2 - - \hat{Q}_{r, i, g} = \left[\boldsymbol{\Omega} \cdot \boldsymbol{\vec{Q}}_{i,g}\right]\;\mathrm{,} - -:math:`\boldsymbol{\Omega}` being the direction vector of the ray. The next step -is to solve for the LS source vector :math:`\boldsymbol{\vec{Q}}_{i,g}`. A -relationship between the LS source vector and the source moments, -:math:`\boldsymbol{\vec{q}}_{i,g}` can be derived, as in `Ferrer -`_ and `Gunow `_: - -.. math:: - :label: m_equation - - \mathbf{M}_{i} \boldsymbol{\vec{Q}}_{i,g} = \boldsymbol{\vec{q}}_{i,g} \;\mathrm{.} - -The spatial moments matrix :math:`M_i` in region :math:`i` represents the -spatial distribution of the 3D object composing the `source region -`_. This matrix is independent of the material of the source -region, fluxes, and any transport effects -- it is a purely geometric quantity. -It is a symmetric :math:`3\times3` matrix. While :math:`M_i` is not known -apriori to the simulation, similar to the source region volume, it can be -computed "on-the-fly" as a byproduct of the random ray integration process. Each -time a ray randomly crosses the region within its active length, an estimate of -the spatial moments matrix can be computed by using the midpoint of the ray as -an estimate of the centroid, and the distance and direction of the ray can be -used to inform the other spatial moments within the matrix. As this information -is purely geometric, the stochastic estimate of the centroid and spatial moments -matrix can be accumulated and improved over the entire duration of the -simulation, converging towards their true quantities. - -With an estimate of the spatial moments matrix :math:`M_i` resulting from the -ray tracing process naturally, the LS source vector -:math:`\boldsymbol{\vec{Q}}_{i,g}` can be obtained via a linear solve of -:eq:`m_equation`, or by the direct inversion of :math:`M_i`. However, to -accomplish this, we must first know the source moments -:math:`\boldsymbol{\vec{q}}_{i,g}`. Fortunately, the source moments are also -defined by the definition of the source: - -.. math:: - :label: source_moments - - q_{v, i, g}= \frac{\chi_{i,g}}{k_{eff}} \sum_{g^{\prime}=1}^{G} \nu - \Sigma_{\mathrm{f},i, g^{\prime}} \hat{\phi}_{v, i, g^{\prime}} + \sum_{g^{\prime}=1}^{G} - \Sigma_{\mathrm{s}, i, g^{\prime}\rightarrow g} \hat{\phi}_{v, i, g^{\prime}}\quad \forall v \in(x, y, z)\;\mathrm{,} - -where :math:`v` indicates the direction vector component, and we have introduced -the scalar flux moments :math:`\hat{\phi}`. The scalar flux moments can be -solved for by taking the `integral definition `_ of a spatial -moment, allowing us to derive a "simulation averaged" estimator for the scalar -moment, as in Equation :eq:`phi_sim`, - -.. math:: - :label: scalar_moments_sim - - \hat{\phi}_{v,i,g}^{simulation} = \frac{\sum\limits_{r=1}^{N_i} - \ell_{r} \left[\Omega_{v} \hat{\psi}_{r,i,g} + u_{r,v,0} \bar{\psi}_{r,i,g}\right]} - {\Sigma_{t,i,g} \frac{\sum\limits^{B}_{b}\sum\limits^{N_i}_{r} \ell_{b,r} }{B}} - \quad \forall v \in(x, y, z)\;\mathrm{,} - - -where the average angular flux is given by Equation :eq:`average_psi_final`, and -the angular flux spatial moments :math:`\hat{\psi}_{r,i,g}` by: - -.. math:: - :label: angular_moments - - \hat{\psi}_{r, i, g} = \frac{\ell_{r}\psi^{in}_{r,g}}{2} + - \left(\frac{\bar{Q}_{r,i, g}}{\Sigma_{\mathrm{t}, i, g}}-\psi^{in}_{r,g}\right) - \frac{G_{1}\left(\tau_{i,g}\right)}{\Sigma_{\mathrm{t}, i, g}} + \frac{\ell_{r}\hat{Q}_{r,i,g}} - {2\left(\Sigma_{\mathrm{t}, i, g}\right)^{2}}G_{2}\left(\tau_{i,g}\right)\;\mathrm{.} - - -The new exponentials introduced, again for simplicity, are simply: - -.. math:: - :label: G1 - - G_{1}(\tau) = 1+\frac{\tau}{2}-\left(1+\frac{1}{\tau}\right) F_{1}(\tau), - -.. math:: - :label: G2 - - G_{2}(\tau) = \frac{2}{3} \tau-\left(1+\frac{2}{\tau}\right) G_{1}(\tau) - -The contents of this section, alongside the equations for the flat source and -scalar flux, Equations :eq:`source_update` and :eq:`phi_sim` respectively, -completes the set of equations for LS. - -.. _methods-shannon-entropy-random-ray: - ------------------------------ -Shannon Entropy in Random Ray ------------------------------ - -As :math:`k_{eff}` is updated at each generation, the fission source at each FSR -is used to compute the Shannon entropy. This follows the :ref:`same procedure -for computing Shannon entropy in continuous-energy or multigroup Monte Carlo -simulations `, except that fission sources at FSRs are -considered, rather than fission sites of user-defined regular meshes. Thus, the -volume-weighted fission rate is considered instead, and the fraction of fission -sources is adjusted such that: - -.. math:: - :label: fraction-source-random-ray - - S_i = \frac{\text{Fission source in FSR $i \times$ Volume of FSR - $i$}}{\text{Total fission source}} = \frac{Q_{i} V_{i}}{\sum_{i=1}^{i=N} - Q_{i} V_{i}} - -The Shannon entropy is then computed normally as - -.. math:: - :label: shannon-entropy-random-ray - - H = - \sum_{i=1}^N S_i \log_2 S_i - -where :math:`N` is the number of FSRs. FSRs with no fission source (or, -occassionally, negative fission source, :ref:`due to the volume estimator -problem `) are skipped to avoid taking an undefined -logarithm in :eq:`shannon-entropy-random-ray`. - -.. _usersguide_fixed_source_methods: - ------------- -Fixed Source ------------- - -The random ray solver in OpenMC can be used for both eigenvalue and fixed source -problems. There are a few key differences between fixed source transport with -random ray and Monte Carlo, however. - -- **Source definition:** In Monte Carlo, it is relatively easy to define various - source distributions, including point sources, surface sources, volume - sources, and even custom user sources -- all with varying angular and spatial - statistical distributions. In random ray, the natural way to include a fixed - source term is by adding a fixed (flat) contribution to specific flat source - regions. Thus, in the OpenMC implementation of random ray, particle sources - are restricted to being volumetric and isotropic, although different energy - spectrums are supported. Fixed sources can be applied to specific materials, - cells, or universes. Point sources are "smeared" to fill the volume of the - source region that contains the point source coordinate. - -- **Inactive batches:** In Monte Carlo, use of a fixed source implies that all - batches are active batches, as there is no longer a need to develop a fission - source distribution. However, in random ray mode, there is still a need to - develop the scattering source by way of inactive batches before beginning - active batches. - -.. _adjoint: - ------------------------- -Adjoint Flux Solver Mode ------------------------- - -The random ray solver in OpenMC can also be used to solve for the adjoint flux, -:math:`\psi^{\dagger}`. In combination with the regular (forward) flux solution, -the adjoint flux is useful for perturbation methods as well as for computing -weight windows for subsequent Monte Carlo simulations. The adjoint flux can be -thought of as the "backwards" flux, representing the flux where a particle is -born at an absoprtion point (and typical absorption energy), and then undergoes -transport with a transposed scattering matrix. That is, instead of sampling a -particle and seeing where it might go as in a standard forward solve, we will -sample an absorption location and see where the particle that was absorbed there -might have come from. Notably, for typical neutron absorption at low energy -levels, this means that adjoint flux particles are typically sampled at a low -energy and then upscatter (via a transposed scattering matrix) over their -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 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. - -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 ---------------------------- - -Compared to continuous energy Monte Carlo simulations, the known sources of bias -in random ray particle transport are: - - - **Multigroup Energy Discretization:** The multigroup treatment of flux and - cross sections incurs a significant bias, as a reaction rate (:math:`R_g = - V \phi_g \Sigma_g`) for an energy group :math:`g` can only be conserved - for a given choice of multigroup cross section :math:`\Sigma_g` if the - flux (:math:`\phi_g`) is known a priori. If the flux was already known, - then there would be no point to the simulation, resulting in a fundamental - need for approximating this quantity. There are numerous methods for - generating relatively accurate multigroup cross section libraries that can - each be applied to a narrow design area reliably, although there are - always limitations and/or complexities that arise with a multigroup energy - treatment. This is by far the most significant source of simulation bias - between Monte Carlo and random ray for most problems. While the other - areas typically have solutions that are highly effective at mitigating - bias, error stemming from multigroup energy discretization is much harder - to remedy. - - **Source Approximation:**. In OpenMC, a "flat" (0th order) source - approximation is often made, wherein the scattering and fission sources within a - cell are assumed to be spatially uniform. As the source in reality is a - continuous function, this leads to bias, although the bias can be reduced - to acceptable levels if the flat source regions are sufficiently small. - The bias can also be mitigated by assuming a higher-order source such as the - linear source approximation currently implemented into OpenMC. - In practical terms, this source of bias can become very large if cells are - large (with dimensions beyond that of a typical particle mean free path), - but the subdivision of cells can often reduce this bias to trivial levels. - - **Anisotropic Source Approximation:** In OpenMC, the source is not only - assumed to be flat but also isotropic, leading to bias. It is possible for - MOC (and likely random ray) to treat anisotropy explicitly, but this is - not currently supported in OpenMC. This source of bias is not significant - for some problems, but becomes more problematic for others. Even in the - absence of explicit treatment of anistropy, use of transport-corrected - multigroup cross sections can often mitigate this bias, particularly for - light water reactor simulation problems. - - **Angular Flux Initial Conditions:** Each time a ray is sampled, its - starting angular flux is unknown, so a guess must be made (typically the - source term for the cell it starts in). Usage of an adequate inactive ray - length (dead zone) mitigates this error. As the starting guess is - attenuated at a rate of :math:`\exp(-\Sigma_t \ell)`, this bias can driven - below machine precision in a low cost manner on many problems. - -.. _Tramm-2017a: https://doi.org/10.1016/j.jcp.2017.04.038 -.. _Tramm-2017b: https://doi.org/10.1016/j.anucene.2017.10.015 -.. _Tramm-2018: https://dspace.mit.edu/handle/1721.1/119038 -.. _Tramm-2020: https://doi.org/10.1051/EPJCONF/202124703021 -.. _Cosgrove-2023: https://doi.org/10.1080/00295639.2023.2270618 -.. _Ferrer-2016: https://doi.org/10.13182/NSE15-6 -.. _Gunow-2018: https://dspace.mit.edu/handle/1721.1/119030 - -.. only:: html - - .. rubric:: References - -.. [Askew-1972] Askew, “A Characteristics Formulation of the Neutron Transport - Equation in Complicated Geometries.” Technical Report AAEW-M 1108, UK Atomic - Energy Establishment (1972). diff --git a/docs/source/methods/tallies.rst b/docs/source/methods/tallies.rst index f2c22ab22..1aae47d6e 100644 --- a/docs/source/methods/tallies.rst +++ b/docs/source/methods/tallies.rst @@ -4,9 +4,9 @@ Tallies ======= -The methods discussed in this section are written specifically for continuous- -energy mode. However, they can also apply to the multi-group mode if the -particle's energy is instead interpreted as the particle's group. +Note that the methods discussed in this section are written specifically for +continuous-energy mode but equivalent apply to the multi-group mode if the +particle's energy is replaced with the particle's group ------------------ Filters and Scores @@ -179,12 +179,12 @@ n(\mathbf{r}, \mathbf{\hat{\Omega}}, E, t)` and :math:`d\ell = v \, dt` where Equation :eq:`track-length-integral` indicates that we can use the length of a particle's trajectory as an estimate for the flux, i.e. the track-length -estimator of the volume-integrated flux would be +estimator of the flux would be .. math:: :label: track-length-flux - V \phi = \frac{1}{W} \sum_{i \in T} w_i \ell_i + \phi = \frac{1}{W} \sum_{i \in T} w_i \ell_i where :math:`T` is the set of all the particle's trajectories within the desired volume and :math:`\ell_i` is the length of the :math:`i`-th trajectory. In the @@ -205,73 +205,7 @@ 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. ------------------------------------ -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 `_. - -.. _tallies_statistics: +.. TODO: Add description of surface current tallies ---------- Statistics @@ -334,14 +268,6 @@ normal, log-normal, Weibull, etc. The central limit theorem states that as Estimating Statistics of a Random Variable ------------------------------------------ -After running OpenMC, each tallied quantity has a reported mean and standard -deviation. The below sections explain how these quantities are computed. Note -that OpenMC uses **batch statistics**, meaning that each observation for a tally -random variable corresponds to the aggregation of tally contributions from -multiple source particles that are grouped together into a single batch. See -:ref:`usersguide_particles` for more information on how the number of source -particles and statistical batches are specified. - Mean ++++ @@ -451,130 +377,6 @@ of this is that the longer you run a simulation, the better you know your results. Therefore, by running a simulation long enough, it is possible to reduce the stochastic uncertainty to arbitrarily low levels. -Skewness -++++++++ - -The `skewness`_ of a population quantifies the asymmetry of the probability -distribution around its mean. Positive and negative skewness indicate a -longer/heavier right and left tail respectively. Let :math:`x_1,\ldots,x_n` be -the per-realization values for a bin, with sample mean :math:`\bar{x}` and -sample central moments: - -.. math:: - - m_k \;=\; \frac{1}{n}\sum_{i=1}^{n}\bigl(x_i-\bar{x}\bigr)^k. - -OpenMC reports the *adjusted Fisher-Pearson skewness* (defined for :math:`n \ge -3`), which is commonly used in many statistical packages: - -.. math:: - - G_1 \;=\; \frac{\sqrt{n \cdot (n-1)}}{\,n-2\,}\cdot\frac{m_3}{m_2^{3/2}}. - -where :math:`m_2` and :math:`m_3` correspond to the biased sample second and -third central moment respectively. - -Kurtosis -++++++++ - -The `kurtosis`_ of a population quantifies tail weight (also called tailedness) -of the probability distribution relative to a normal distribution. Positive -excess kurtosis indicates *heavier tails* whereas negative excess kurtosis -indicates *lighter tails*. Kurtosis is especially useful for identifying bins -where occasional extreme scores dominate uncertainty. OpenMC reports the -*adjusted excess kurtosis* (defined for :math:`n \ge 4`): - -.. math:: - - G_2 \;=\; \frac{(n-1)}{(n-2)(n-3)} - \left[(n+1)\,\frac{m_4}{m_2^{2}} \;-\; 3(n-1)\right]. - -where :math:`m_2` and :math:`m_4` correspond to the biased sample second and -fourth central moment respectively. For a perfectly normal distribution, the -excess kurtosis is :math:`0`. - -Variance of Variance -++++++++++++++++++++ - -The variance of the variance (also known as the coefficient of variation -squared) measures *stability of the sample variance* :math:`s^2` and, by -extension, the reliability of reported relative errors. High VOV means that -error bars themselves are noisy—often due to heavy tails, skewness, or too few -realizations. - -.. math:: - - VOV = \frac{s^2(s_{\bar{X}}^2)}{s_{\bar{X}}^4 } = \frac{m_4}{m_2^2} - \frac{1}{n} - -where :math:`s_{\bar{X}}^2` is the estimated variance of the mean and -:math:`s^2(s_{\bar{X}}^2)` is the estimated variance in :math:`s_{\bar{X}}^2`. -The MCNP manual suggests a hard threshold such that :math:`VOV < 0.1` to improve -the probability of forming a reliable confidence interval. However, OpenMC does -not enforce an universal cut-off because the suitability of any single threshold -depends strongly on problem specifics (estimator choice, variance-reduction -settings, tally binning, or even effective sample size). - - -Normality Tests (D'Agostino-Pearson) -++++++++++++++++++++++++++++++++++++ - -These normality test verify the hypothesis that fluctuations are *approximately -normal*, a working assumption behind many Monte Carlo diagnostics and -`confidence-interval heuristics`_. Tests are provided for: (i) skewness-only, -(ii) kurtosis-only, and (iii) the *omnibus* combination. OpenMC uses the -finite-sample-adjusted skewness :math:`G_1` and excess kurtosis :math:`G_2` -above to construct standardized normal scores :math:`Z_1` (from :math:`G_1`) and -:math:`Z_2` (from :math:`G_2`) via the D'Agostino-Pearson transformations. The -omnibus statistic is - -.. math:: - - K^2 \;=\; Z_1^{\,2} \;+\; Z_2^{\,2} - \;\sim\; \chi^2_{(2)} \quad \text{under } H_0:\ \text{normality}. - -OpenMC reports :math:`Z_1`, :math:`Z_2`, :math:`K^2`, and their p-values when -prerequisites are met (skewness for :math:`n\ge 3`, kurtosis and omnibus for -:math:`n\ge 4`). Given a user-chosen significance level :math:`\alpha` (default -is :math:`0.05`), reject :math:`H_0` if :math:`\text{p-value}<\alpha`; otherwise -fail to reject. OpenMC leaves the interpretation to the user, who should -consider VOV together with skewness, kurtosis, and normality tests results when -judging whether reported confidence intervals are credible for their application -[#norm-tests]_. - -.. [#norm-tests] - Higher-moments accumulation must be enabled with ``higher_moments = True`` - for running these diagnostics including the skewness, kurtosis, and normality - tests. - -Figure of Merit -+++++++++++++++ - -The figure of merit (FOM) is an indicator that accounts for both the statistical -uncertainty and the execution time and represents how much information is -obtained per unit time in the simulation. The FOM is defined as - -.. math:: - :label: figure_of_merit - - FOM = \frac{1}{r^2 t}, - -where :math:`t` is the total execution time and :math:`r` is the relative error -defined as - -.. math:: - :label: relative_error - - r = \frac{s_{\bar{X}}}{\bar{x}}. - -Based on this definition, one can see that a higher FOM is desirable. The FOM is -useful as a comparative tool. For example, if a variance reduction technique is -being applied to a simulation, the FOM with variance reduction can be compared -to the FOM without variance reduction to ascertain whether the reduction in -variance outweighs the potential increase in execution time (e.g., due to -particle splitting). It is important to note that MCNP reports the FOM using CPU -time (wall-clock time multiplied by the number of threads/cores), whereas OpenMC -reports the FOM using only the wall-clock time :math:`t`. - Confidence Intervals ++++++++++++++++++++ @@ -682,8 +484,6 @@ improve the estimate of the percentile. .. rubric:: References -.. _confidence-interval heuristics: https://doi.org/10.1080/00031305.1990.10475751 - .. _following approximation: https://doi.org/10.1080/03610918708812641 .. _Bessel's correction: https://en.wikipedia.org/wiki/Bessel's_correction @@ -704,10 +504,6 @@ improve the estimate of the percentile. .. _converges in distribution: https://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_distribution -.. _skewness: https://en.wikipedia.org/wiki/Skewness - -.. _kurtosis: https://en.wikipedia.org/wiki/Kurtosis - .. _confidence intervals: https://en.wikipedia.org/wiki/Confidence_interval .. _Student's t-distribution: https://en.wikipedia.org/wiki/Student%27s_t-distribution @@ -716,4 +512,4 @@ improve the estimate of the percentile. .. _unpublished rational approximation: https://stackedboxes.org/2017/05/01/acklams-normal-quantile-function/ -.. _MC21: https://www.osti.gov/servlets/purl/903083 +.. _MC21: http://www.osti.gov/bridge/servlets/purl/903083-HT5p1o/903083.pdf diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst deleted file mode 100644 index 7778e0714..000000000 --- a/docs/source/methods/variance_reduction.rst +++ /dev/null @@ -1,216 +0,0 @@ -.. _methods_variance_reduction: - -================== -Variance Reduction -================== - -.. _methods_variance_reduction_intro: - ------------- -Introduction ------------- - -Transport problems can sometimes involve a significant degree of attenuation -between the source and a detector (tally) region, which can result in a flux -differential of ten orders of magnitude (or more) throughout the simulation -domain. As Monte Carlo uncertainties tend to be inversely proportional to the -physical flux density, it can be extremely difficult to accurately resolve -tallies in locations that are optically far from the source. This issue is -particularly common in fixed source simulations, where some tally locations may -not experience a single scoring event, even after billions of analog histories. - -Variance reduction techniques aim to either flatten the global uncertainty -distribution, such that all regions of phase space have a fairly similar -uncertainty, or to reduce the uncertainty in specific locations (such as a -detector). There are three strategies available in OpenMC for variance -reduction: weight windows generated via the MAGIC method or the FW-CADIS method, -and source biasing. Both weight windowing strategies work by developing a mesh -that can be utilized by subsequent Monte Carlo solves to split particles heading -towards areas of lower flux densities while terminating particles in higher flux -regions. In contrast, source biasing modifies source site sampling behavior to -preferentially track particles more likely to reach phase space regions of -interest. - ------------- -MAGIC Method ------------- - -The Method of Automatic Generation of Importances by Calculation, or `MAGIC -method `_, is an iterative -technique that uses spatial flux information :math:`\phi(r)` obtained from a -normal Monte Carlo solve to produce weight windows :math:`w(r)` that can be -utilized by a subsequent iteration of Monte Carlo. While the first generation of -weight windows produced may only help to reduce variance slightly, use of these -weights to generate another set of weight windows results in a progressively -improving iterative scheme. - -Equation :eq:`magic` defines how the lower bound of weight windows -:math:`w_{\ell}(r)` are generated with MAGIC using forward flux information. -Here, we can see that the flux at location :math:`r` is normalized by the -maximum flux in any group at that location. We can also see that the weights are -divided by a factor of two, which accounts for the typical :math:`5\times` -factor separating the lower and upper weight window bounds in OpenMC. - -.. math:: - :label: magic - - w_{\ell}(r) = \frac{\phi(r)}{2\,\text{max}(\phi(r))} - -A major advantage of this technique is that it does not require any special -transport machinery; it simply uses multiple Monte Carlo simulations to -iteratively improve a set of weight windows (which are typically defined on a -mesh covering the simulation domain). The downside to this method is that as the -flux differential increases between areas near and far from the source, it -requires more outer Monte Carlo iterations, each of which can be expensive in -itself. Additionally, computation of weight windows based on regular (forward) -neutron flux tally information does not produce the most numerically effective -set of weight windows. Nonetheless, MAGIC remains a simple and effective -technique for generating weight windows. - --------- -FW-CADIS --------- - -As discussed in the previous section, computation of weight windows based on -regular (forward) neutron flux tally information does not produce the most -numerically efficient set of weight windows. It is highly preferable to generate -weight windows based on spatial adjoint flux :math:`\phi^{\dag}(r)` -information. The adjoint flux is essentially the "reverse" simulation problem, -where we sample a random point and assume this is where a particle was absorbed, -and then trace it backwards (upscattering in energy), until we sample the point -where it was born from. - -The Forward-Weighted Consistent Adjoint Driven Importance Sampling method, or -`FW-CADIS method `_, produces weight windows -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:: - :label: fw_cadis - - w_{\ell}(r) = \frac{1}{2\phi^{\dag}(r)} - -While the algorithm itself is quite simple, it requires estimates of the global -adjoint flux distribution, which is difficult to generate directly with Monte -Carlo transport. Thus, FW-CADIS typically uses an alternative solver (often -deterministic) that can be more readily adapted for generating adjoint flux -information, and which is often much cheaper than Monte Carlo given that a rough -solution is often sufficient for weight window generation. - -The FW-CADIS implementation in OpenMC utilizes its own internal random ray -multigroup transport solver to generate the adjoint source distribution. No -coupling to any external transport is solver is necessary. The random ray solver -operates on the same geometry as the Monte Carlo solver, so no redefinition of -the simulation geometry is required. More details on how the adjoint flux is -computed are given in the :ref:`adjoint methods section `. - -More information on the workflow is available in the :ref:`user guide -`, but generally production of weight windows with FW-CADIS -involves several stages (some of which are highly automated). These tasks -include generation of approximate multigroup cross section data for use by the -random ray solver, running of the random ray solver in normal (forward flux) -mode to generate a source for the adjoint solver, running of the random ray -solver in adjoint mode to generate adjoint flux tallies, and finally the -production of weight windows via the FW-CADIS method. As is discussed in the -user guide, most of these steps are automated together, making the additional -burden on the user fairly small. - -The major advantage of this technique is that it typically produces much more -numerically efficient weight windows as compared to those generated with MAGIC, -sometimes with an order-of-magnitude improvement in the figure of merit -(Equation :eq:`variance_fom`), which accounts for both the variance and the -execution time. Another major advantage is that the cost of the random ray -solver is typically negligible compared to the cost of the subsequent Monte -Carlo solve itself, making it a very cheap method to deploy. The downside to -this method is that it introduces a second transport method into the mix (random -ray), such that there are more free input parameters for the user to know about -and adjust, potentially making the method more complex to use. However, as many -of the parameters have natural choices, much of this parameterization can be -handled automatically behind the scenes without the need for the user to be -aware of this. - -.. math:: - :label: variance_fom - - \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`. 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: - --------------- -Source Biasing --------------- - -In contrast to the previous two methods that introduce population controls -during transport, source biasing modifies the sampling of the external source -distribution. The basic premise of the technique is that for each spatial, -angular, energy, or time distribution of a source, an additional distribution -can be specified provided that the two share a common support (set of points -where the distribution is nonzero). Samples are then drawn from this "bias" -distribution, which can be chosen to preferentially direct particles towards -phase space regions of interest. In order to avoid biasing the tally results, -however, a weight adjustment is applied to each sampled site as described below. - -Assume that the unbiased probability density function of a random variable -:math:`X:x \rightarrow \mathbb{R}` is given by :math:`f(x)`, but that using the -biased distribution :math:`g(x)` will result in a greater number of particle -trajectories reaching some phase space region of interest. Then a sample -:math:`x_0` may be drawn from :math:`g(x)` while maintaining a fair game, -provided that its weight is adjusted as: - -.. math:: - :label: source_bias - - w = w_0 \times \frac{f(x_0)}{g(x_0)} - -where :math:`w_0` is the weight of an unbiased sample from :math:`f(x)`, -typically unity. - -Returning now to Equation :eq:`source_bias`, the requirement for common support -becomes evident. If :math:`\mathrm{supp} (g)` fully contains but is not -identical to :math:`\mathrm{supp} (f)`, then some samples from :math:`g(x)` will -correspond to points where :math:`f(x) = 0`. Thus these source sites would be -assigned a starting weight of 0, meaning the particles would be killed -immediately upon transport, effectively wasting computation time. Conversely, if -:math:`\mathrm{supp} (g)` is fully contained by but not identical to -:math:`\mathrm{supp} (f)`, the contributions of some regions outside -:math:`\mathrm{supp} (g)` will not be counted towards the integral, potentially -biasing the tally. The weight assigned to such points would be undefined since -:math:`g(x) = \mathbf{0}` at these points. - -When an independent source is sampled in OpenMC, the particle's coordinate in -each variable of phase space :math:`(\mathbf{r},\mathbf{\Omega},E,t)` is -successively drawn from an independent probability distribution. Multiple -variables can be biased, in which case the resultant weight :math:`w` applied to -the particle is the product of the weights assigned from all sampled -distributions: space, angle, energy, and time, as shown in Equation -:eq:`tot_wgt`. - -.. math:: - :label: tot_wgt - - w = w_r \times w_{\Omega} \times w_E \times w_t - -Finally, source biasing and weight windows serve different purposes. Source -biasing changes how particles are born, allowing the initial source sites to be -sampled preferentially from important regions of phase space (space, angle, -energy, and time) with an accompanying weight adjustment. Weight windows, by -contrast, apply population control during transport (splitting and Russian -roulette) to help particles reach and contribute in important regions as they -move through the system. Because particle transport proceeds as usual after a -biased source is sampled, particle attenuation in optically thick regions -outside the source volume will not be affected by source biasing; in such -scenarios, transport biasing techniques such as weight windows are often more -effective. diff --git a/docs/source/publications.rst b/docs/source/publications.rst index a2d60d5af..88d0a97b9 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -138,8 +138,8 @@ Geometry and Visualization *Trans. Am. Nucl. Soc.*, **114**, 391-394 (2016). - Derek M. Lax, "`Memory efficient indexing algorithm for physical properties in - OpenMC `_," S. M. Thesis, - Massachusetts Institute of Technology (2015). + OpenMC `_," S. M. Thesis, Massachusetts + Institute of Technology (2015). - Derek Lax, William Boyd, Nicholas Horelik, Benoit Forget, and Kord Smith, "A memory efficient algorithm for classifying unique regions in constructive @@ -399,8 +399,7 @@ Doppler Broadening - Jonathan A. Walsh, Benoit Forget, Kord S. Smith, Brian C. Kiedrowski, and Forrest B. Brown, "`Direct, on-the-fly calculation of unresolved resonance region cross sections in Monte Carlo simulations - `_," *Proc. Joint Int. Conf. - M&C+SNA+MC*, + `_," *Proc. Joint Int. Conf. M&C+SNA+MC*, Nashville, Tennessee, Apr. 19--23 (2015). - Colin Josey, Benoit Forget, and Kord Smith, "`Windowed multipole sensitivity @@ -597,8 +596,7 @@ Depletion - Matthew S. Ellis, Colin Josey, Benoit Forget, and Kord Smith, "`Spatially Continuous Depletion Algorithm for Monte Carlo Simulations - `_," *Trans. Am. Nucl. Soc.*, - **115**, + `_," *Trans. Am. Nucl. Soc.*, **115**, 1221-1224 (2016). - Anas Gul, K. S. Chaudri, R. Khan, and M. Azeen, "`Development and verification diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index f06a1eba4..076b02722 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -21,14 +21,10 @@ Simulation Settings :nosignatures: :template: myclass.rst - openmc.SourceBase - openmc.IndependentSource - openmc.FileSource - openmc.CompiledSource - openmc.MeshSource - openmc.TokamakSource + openmc.Source openmc.SourceParticle openmc.VolumeCalculation + openmc.WeightWindows openmc.Settings .. autosummary:: @@ -36,8 +32,8 @@ Simulation Settings :nosignatures: :template: myfunction.rst - openmc.read_source_file openmc.write_source_file + openmc.wwinp_to_wws Material Specification ---------------------- @@ -47,6 +43,9 @@ Material Specification :nosignatures: :template: myclass.rst + openmc.Nuclide + openmc.Element + openmc.Macroscopic openmc.Material openmc.Materials @@ -88,7 +87,6 @@ Building geometry openmc.Intersection openmc.Union openmc.Complement - openmc.BoundingBox openmc.Cell openmc.Universe openmc.DAGMCUniverse @@ -120,22 +118,17 @@ Constructing Tallies openmc.Filter openmc.UniverseFilter openmc.MaterialFilter - openmc.MaterialFromFilter openmc.CellFilter openmc.CellFromFilter - openmc.CellBornFilter + openmc.CellbornFilter openmc.CellInstanceFilter openmc.CollisionFilter openmc.SurfaceFilter openmc.MeshFilter - openmc.MeshBornFilter - openmc.MeshMaterialFilter openmc.MeshSurfaceFilter openmc.EnergyFilter openmc.EnergyoutFilter - openmc.ParticleProductionFilter openmc.MuFilter - openmc.MuSurfaceFilter openmc.PolarFilter openmc.AzimuthalFilter openmc.DistribcellFilter @@ -145,31 +138,18 @@ Constructing Tallies openmc.SpatialLegendreFilter openmc.SphericalHarmonicsFilter openmc.TimeFilter - openmc.WeightFilter openmc.ZernikeFilter openmc.ZernikeRadialFilter - openmc.ParentNuclideFilter openmc.ParticleFilter - openmc.ReactionFilter - openmc.MeshMaterialVolumes - openmc.Trigger - openmc.TallyDerivative - openmc.Tally - openmc.Tallies - -Meshes ------- - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myclassinherit.rst - openmc.RegularMesh openmc.RectilinearMesh openmc.CylindricalMesh openmc.SphericalMesh openmc.UnstructuredMesh + openmc.Trigger + openmc.TallyDerivative + openmc.Tally + openmc.Tallies Geometry Plotting ----------------- @@ -179,10 +159,7 @@ Geometry Plotting :nosignatures: :template: myclass.rst - openmc.SlicePlot - openmc.VoxelPlot - openmc.WireframeRayTracePlot - openmc.SolidRayTracePlot + openmc.Plot openmc.Plots Running OpenMC @@ -208,23 +185,12 @@ Post-processing :template: myclass.rst openmc.Particle - openmc.ParticleList openmc.ParticleTrack openmc.StatePoint openmc.Summary openmc.Track openmc.Tracks -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - openmc.read_collision_track_file - openmc.read_collision_track_hdf5 - openmc.read_collision_track_mcpl - openmc.voxel_to_vtk - The following classes and functions are used for functional expansion reconstruction. .. autosummary:: @@ -256,27 +222,6 @@ Various classes may be created when performing tally slicing and/or arithmetic: openmc.arithmetic.AggregateNuclide openmc.arithmetic.AggregateFilter -Variance Reduction ------------------- - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myclass - - openmc.WeightWindows - openmc.WeightWindowsList - openmc.WeightWindowGenerator - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - openmc.hdf5_to_wws - openmc.wwinp_to_wws - - Coarse Mesh Finite Difference Acceleration ------------------------------------------ diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index dab45481d..882e3c71b 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -13,39 +13,26 @@ Functions :template: myfunction.rst calculate_volumes - current_batch export_properties - export_weight_windows finalize find_cell find_material - dagmc_universe_cell_ids - global_bounding_box - global_tallies hard_reset - id_map import_properties - import_weight_windows init - is_statepoint_batch iter_batches keff load_nuclide - master next_batch num_realizations plot_geometry - property_map reset - reset_timers run run_in_memory - run_random_ray sample_external_source - simulation_finalize simulation_init + simulation_finalize source_bank - statepoint_load statepoint_write Classes @@ -56,98 +43,12 @@ Classes :nosignatures: :template: myclass.rst - AzimuthalFilter Cell - CellFilter - CellInstanceFilter - CellbornFilter - CellfromFilter - CollisionFilter - CylindricalMesh - DelayedGroupFilter - DistribcellFilter EnergyFilter - EnergyFunctionFilter - EnergyoutFilter - Filter - LegendreFilter - Material MaterialFilter - MaterialFromFilter - Mesh + Material MeshFilter - MeshBornFilter MeshSurfaceFilter - MuFilter Nuclide - ParentNuclideFilter - ParticleFilter - ParticleProductionFilter - PolarFilter - ReactionFilter - RectilinearMesh RegularMesh - SpatialLegendreFilter - SphericalHarmonicsFilter - SphericalMesh - SolidRayTracePlot - SurfaceFilter Tally - TemporarySession - UniverseFilter - UnstructuredMesh - WeightFilter - WeightWindows - ZernikeFilter - ZernikeRadialFilter - -Data ----- - -.. data:: cells - - Mapping of cell ID to :class:`openmc.lib.Cell` instances. - - :type: dict - -.. data:: filters - - Mapping of filter ID to :class:`openmc.lib.Filter` instances. - - :type: dict - -.. data:: materials - - Mapping of material ID to :class:`openmc.lib.Material` instances. - - :type: dict - -.. data:: meshes - - Mapping of mesh ID to :class:`openmc.lib.Mesh` instances. - - :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. - - :type: dict - -.. data:: tallies - - Mapping of tally ID to :class:`openmc.lib.Tally` instances. - - :type: dict - -.. data:: weight_windows - - Mapping of weight window ID to :class:`openmc.lib.WeightWindows` instances. - - :type: dict diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 9d47430f7..c7c65e14a 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -63,16 +63,12 @@ Core Functions atomic_weight combine_distributions decay_constant - decay_energy - decay_photon_energy dose_coefficients - gnds_name + gnd_name half_life isotopes kalbach_slope linearize - mass_attenuation_coefficient - mass_energy_absorption_coefficient thin water_density zam diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index 25fcd898f..dd679a40a 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -26,7 +26,7 @@ provided to obtain reaction rates from cross-section data. Several classes are provided that implement different time-integration algorithms for depletion calculations, which are described in detail in Colin Josey's thesis, `Development and analysis of high order neutron transport-depletion coupling -algorithms `_. +algorithms `_. .. autosummary:: :toctree: generated @@ -54,19 +54,9 @@ provides the following transport operator classes: IndependentOperator The :class:`CoupledOperator` and :class:`IndependentOperator` classes must also -have some knowledge of how nuclides transmute and decay. This is handled by the +have some knowledge of how nuclides transmute and decay. This is handled by the :class:`Chain` class. -The :class:`IndependentOperator` class requires a set of fluxes and microscopic -cross sections. The following function can be used to generate this information: - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - get_microxs_and_flux - Minimal Example --------------- @@ -78,18 +68,20 @@ A minimal example for performing depletion would be: >>> import openmc.deplete >>> geometry = openmc.Geometry.from_xml() >>> settings = openmc.Settings.from_xml() - >>> model = openmc.Model(geometry, settings) + >>> model = openmc.model.Model(geometry, settings) # Representation of a depletion chain >>> chain_file = "chain_casl.xml" - >>> operator = openmc.deplete.CoupledOperator(model, chain_file) + >>> operator = openmc.deplete.CoupledOperator( + ... model, chain_file) # Set up 5 time steps of one day each >>> dt = [24 * 60 * 60] * 5 >>> power = 1e6 # constant power of 1 MW # Deplete using mid-point predictor-corrector - >>> cecm = openmc.deplete.CECMIntegrator(operator, dt, power) + >>> cecm = openmc.deplete.CECMIntegrator( + ... operator, dt, power) >>> cecm.integrate() Internal Classes and Functions @@ -203,25 +195,14 @@ total system energy. helpers.FissionYieldCutoffHelper helpers.FluxCollapseHelper -The :class:`openmc.deplete.IndependentOperator` uses inner classes subclassed +The :class:`openmc.deplete.IndependentOperator` uses inner classes subclassed from those listed above to perform similar calculations. -The following classes are used to define external source rates or transfer rates -to model continuous removal or feed of nuclides during depletion. - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myclass.rst - - transfer_rates.ExternalSourceRates - transfer_rates.TransferRates - Intermediate Classes -------------------- Specific implementations of abstract base classes may utilize some of -the same methods and data structures. These methods and data are stored +the same methods and data structures. These methods and data are stored in intermediate classes. Methods common to tally-based implementation of :class:`FissionYieldHelper` @@ -286,25 +267,3 @@ the following abstract base classes: abc.Integrator abc.SIIntegrator abc.DepSystemSolver - -R2S Automation --------------- - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myclass.rst - - R2SManager - -D1S Functions -------------- - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - d1s.prepare_tallies - d1s.time_correction_factors - d1s.apply_time_correction diff --git a/docs/source/pythonapi/mgxs.rst b/docs/source/pythonapi/mgxs.rst index 4141aa0a0..392914b36 100644 --- a/docs/source/pythonapi/mgxs.rst +++ b/docs/source/pythonapi/mgxs.rst @@ -11,16 +11,6 @@ Module Variables .. autodata:: openmc.mgxs.GROUP_STRUCTURES :annotation: -Functions -+++++++++ - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - openmc.mgxs.convert_flux_groups - Classes +++++++ diff --git a/docs/source/pythonapi/model.rst b/docs/source/pythonapi/model.rst index 3034826bd..5dd3d3293 100644 --- a/docs/source/pythonapi/model.rst +++ b/docs/source/pythonapi/model.rst @@ -11,6 +11,9 @@ Convenience Functions :template: myfunction.rst openmc.model.borated_water + openmc.model.cylinder_from_points + openmc.model.hexagonal_prism + openmc.model.rectangular_prism openmc.model.subdivide openmc.model.pin @@ -22,17 +25,10 @@ Composite Surfaces :nosignatures: :template: myclass.rst - openmc.model.ConicalFrustum - openmc.model.CruciformPrism openmc.model.CylinderSector - openmc.model.HexagonalPrism openmc.model.IsogonalOctagon - openmc.model.OrthogonalBox - openmc.model.Polygon openmc.model.RectangularParallelepiped - openmc.model.RectangularPrism openmc.model.RightCircularCylinder - openmc.model.Vessel openmc.model.XConeOneSided openmc.model.YConeOneSided openmc.model.ZConeOneSided diff --git a/docs/source/pythonapi/stats.rst b/docs/source/pythonapi/stats.rst index 2f2e2835a..b4f115854 100644 --- a/docs/source/pythonapi/stats.rst +++ b/docs/source/pythonapi/stats.rst @@ -22,16 +22,7 @@ Univariate Probability Distributions openmc.stats.Legendre openmc.stats.Mixture openmc.stats.Normal - openmc.stats.DecaySpectrum - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - openmc.stats.delta_function - openmc.stats.fusion_neutron_spectrum - openmc.stats.muir + openmc.stats.Muir Angular Distributions --------------------- @@ -60,8 +51,6 @@ Spatial Distributions openmc.stats.SphericalIndependent openmc.stats.Box openmc.stats.Point - openmc.stats.MeshSpatial - openmc.stats.PointCloud .. autosummary:: :toctree: generated @@ -69,4 +58,3 @@ Spatial Distributions :template: myfunction.rst openmc.stats.spherical_uniform - openmc.stats.cylindrical_uniform diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 6cb774b5b..480db5be6 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -8,42 +8,56 @@ This quick install guide outlines the basic steps needed to install OpenMC on your computer. For more detailed instructions on configuring and installing OpenMC, see :ref:`usersguide_install` in the User's Manual. ----------------------------------- -Installing on Linux/Mac with Conda ----------------------------------- +-------------------------------------------------- +Installing on Linux/Mac with Mamba and conda-forge +-------------------------------------------------- -`Conda `_ is an open source package management +`Conda `_ is an open source package management system and environments management system for installing multiple versions of software packages and their dependencies and switching easily between them. -OpenMC can be installed in a `conda` environment. First, `conda` should be -`installed `_ -with either Anaconda Distribution or Miniconda. Once you have `conda` installed -on your system, OpenMC can be installed via the `conda-forge` channel. +`Mamba `_ is a cross-platform package +manager and is compatible with `conda` packages. +OpenMC can be installed in a `conda` environment with `mamba`. +First, `conda` should be installed with one of the following installers: +`Miniconda `_, +`Anaconda `_, or `Miniforge `_. +Once you have `conda` installed on your system, OpenMC can be installed via the +`conda-forge` channel with `mamba`. First, add the `conda-forge` channel with: .. code-block:: sh conda config --add channels conda-forge - conda config --set channel_priority strict -Then create and activate a new conda enviroment called `openmc-env` (or whatever -you wish) with OpenMC installed. +Then create and activate a new conda enviroment called `openmc-env` in +which to install OpenMC. .. code-block:: sh - conda create --name openmc-env openmc + conda create -n openmc-env conda activate openmc-env -If you are installing on macOS with an Apple silicon ARM-based processor, you -will also need to specify the `--platform` option: +Then install `mamba`, which will be used to install OpenMC. .. code-block:: sh - conda create --name openmc-env --platform osx-64 openmc + conda install mamba -You are now in a conda environment called `openmc-env` that has OpenMC -installed. +To list the versions of OpenMC that are available on the `conda-forge` channel, +in your terminal window or an Anaconda Prompt run: + +.. code-block:: sh + + mamba search openmc + +OpenMC can then be installed with: + +.. code-block:: sh + + mamba install openmc + +You are now in a conda environment called `openmc-env` that has OpenMC installed. ------------------------------------------- Installing on Linux/Mac/Windows with Docker @@ -93,53 +107,31 @@ 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 -------------------------------- -Manually Installing from Source -------------------------------- +-------------------------------- +Installing from Source on Ubuntu +-------------------------------- -Obtaining prerequisites on Ubuntu ---------------------------------- - -When building OpenMC from source, all :ref:`prerequisites ` can -be installed using the package manager: +To build OpenMC from source, several :ref:`prerequisites ` are +needed. If you are using Ubuntu or higher, all prerequisites can be installed +directly from the package manager: .. code-block:: sh sudo apt install g++ cmake libhdf5-dev libpng-dev -After the packages have been installed, follow the instructions to build from -source below. +After the packages have been installed, follow the instructions below for +building and installing OpenMC from source. -Obtaining prerequisites on macOS --------------------------------- - -For an OpenMC build with multithreading enabled, a package manager like -`Homebrew `_ should first be installed. Then, the following -packages should be installed, for example in Homebrew via: - -.. code-block:: sh - - 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 -by OpenMC. To ensure CMake picks up the correct compiler, make sure that either -the :envvar:`CXX` environment variable is set to the brew-installed ``clang++`` -or that the directory containing it is on your :envvar:`PATH` environment -variable. Common locations for the brew-installed compiler are -``/opt/homebrew/opt/llvm/bin`` and ``/usr/local/opt/llvm/bin``. - -After the packages have been installed, follow the instructions to build from -source below. - -Building Source on Linux or macOS ---------------------------------- +------------------------------------------- +Installing from Source on Linux or Mac OS X +------------------------------------------- All OpenMC source code is hosted on `GitHub `_. If you have `git -`_, a modern C++ compiler, `CMake `_, -and `HDF5 `_ installed, you can -download and install OpenMC by entering the following commands in a terminal: +`_, the `gcc `_ compiler suite, +`CMake `_, and `HDF5 +`_ installed, you can download and +install OpenMC be entering the following commands in a terminal: .. code-block:: sh @@ -159,14 +151,14 @@ should specify an installation directory where you have write access, e.g. cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. The :mod:`openmc` Python package must be installed separately. The easiest way -to install it is using `pip `_. -From the root directory of the OpenMC repository, run: +to install it is using `pip `_, which is +included by default in Python 3.4+. From the root directory of the OpenMC +distribution/repository, run: .. code-block:: sh - python -m pip install . + pip install . -By default, OpenMC will be built with multithreading support. To build -distributed-memory parallel versions of OpenMC using MPI or to configure other -options, directions can be found in the :ref:`detailed installation instructions +If you want to build a parallel version of OpenMC (using OpenMP or MPI), +directions can be found in the :ref:`detailed installation instructions `. diff --git a/docs/source/releasenotes/0.13.2.rst b/docs/source/releasenotes/0.13.2.rst deleted file mode 100644 index b0c9b0691..000000000 --- a/docs/source/releasenotes/0.13.2.rst +++ /dev/null @@ -1,99 +0,0 @@ -==================== -What's New in 0.13.2 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This release of OpenMC includes several bug fixes, performance improvements for -complex geometries and depletion simulations, and other general enhancements. -Notably, a capability has been added to compute the photon spectra from decay of -unstable nuclides. Alongside that, a new :data:`openmc.config` configuration -variable has been introduced that allows easier configuration of data sources. -Additionally, users can now perform cell or material rejection when sampling -external source distributions. - ------------------------------------- -Compatibility Notes and Deprecations ------------------------------------- - -- If you are building against libMesh for unstructured mesh tally support, - version 1.6 or higher is now required. -- The ``openmc.stats.Muir`` class has been replaced by a - :func:`openmc.stats.muir` function that returns an instance of - :class:`openmc.stats.Normal`. - ------------- -New Features ------------- - -- The :meth:`openmc.Material.get_nuclide_atom_densities` method now takes an - optional ``nuclide`` argument. -- Functions/methods in the :mod:`openmc.deplete` module now accept times in - Julian years (``'a'``). -- The :meth:`openmc.Universe.plot` method now allows a pre-existing axes object - to be passed in. -- Performance optimization for geometries with many complex regions. -- Performance optimization for depletion by avoiding deepcopies and caching - reaction rates. -- The :class:`openmc.RegularMesh` class now has a - :meth:`~openmc.RegularMesh.from_domain` classmethod. -- The :class:`openmc.CylindricalMesh` class now has a - :meth:`~openmc.CylindricalMesh.from_domain` classmethod. -- Improved method to condense diffusion coefficients from the :mod:`openmc.mgxs` - module. -- A new :data:`openmc.config` configuration variable has been introduced that - allows data sources to be specified at runtime or via environment variables. -- The :class:`openmc.EnergyFunctionFilter` class now supports multiple - interpolation schemes, not just linear-linear interpolation. -- The :class:`openmc.DAGMCUniverse` class now has ``material_names``, - ``n_cells``, and ``n_surfaces`` attributes. -- A new :func:`openmc.data.decay_photon_energy` function has been added that - returns the energy spectrum of photons emitted from the decay of an unstable - nuclide. -- The :class:`openmc.Material` class also has a new - :attr:`~openmc.Material.decay_photon_energy` attribute that gives the decay - photon energy spectrum from the material based on its constituent nuclides. -- The :class:`openmc.deplete.StepResult` now has a - :meth:`~openmc.deplete.StepResult.get_material` method. -- The :class:`openmc.Source` class now takes a ``domains`` argument that - specifies a list of cells, materials, or universes that is used to reject - source sites (i.e., if the sampled sites are not within the specified domain, - they are rejected). - ---------- -Bug Fixes ---------- - -- `Delay call to Tally::set_strides `_ -- `Fix reading reference direction from XML for angular distributions `_ -- `Fix erroneous behavior in Material.add_components `_ -- `Fix reading thermal elastic data from ACE `_ -- `Fix reading source file with time attribute `_ -- `Fix conversion of multiple thermal scattering data files from ACE `_ -- `Fix reading values from wwinp file `_ -- `Handle possibility of .ppm file in Universe.plot `_ -- `Update volume calc types to mitigate overflow issues `_ - ------------- -Contributors ------------- - -- `Lewis Gross `_ -- `Andrew Johnson `_ -- `Miriam Kreher `_ -- `James Logan `_ -- `Jose Ignacio Marquez Damien `_ -- `Josh May `_ -- `Patrick Myers `_ -- `Adam Nelson `_ -- `April Novak `_ -- `Ethan Peterson `_ -- `Gavin Ridley `_ -- `Paul Romano `_ -- `Patrick Shriwise `_ -- `Jonathan Shimwell `_ -- `Olek Yardas `_ diff --git a/docs/source/releasenotes/0.13.3.rst b/docs/source/releasenotes/0.13.3.rst deleted file mode 100644 index c2debbcb3..000000000 --- a/docs/source/releasenotes/0.13.3.rst +++ /dev/null @@ -1,134 +0,0 @@ -==================== -What's New in 0.13.3 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This release of OpenMC includes many bug fixes, performance improvements, and -several notable new features. Some of the highlights include support for MCPL -source files, NCrystal thermal scattering materials, and a new -:class:`openmc.stats.MeshSpatial` class that allows a source distribution to be -specified over a mesh. Additionally, OpenMC now allows you to export your model -as a single XML file rather than separate XML files for geometry, materials, -settings, and tallies. - ------------------------------------- -Compatibility Notes and Deprecations ------------------------------------- - -- Atomic mass data used in :func:`openmc.data.atomic_mass` has been updated to - AME 2020, which results in slightly different masses. - ------------- -New Features ------------- - -- Support was added for `MCPL `_ files to be - used as external sources. Additionally, source points and surfaces sources can - be written as MCPL files instead of HDF5 files. (`#2116 - `_) -- Support was added for `NCrystal `_ - thermal scattering materials. (`#2222 - `_) -- The :class:`~openmc.CylindricalMesh` and :class:`~openmc.SphericalMesh` - classes now have an ``origin`` attribute that changes the center of the mesh. - (`#2256 `_) -- A new :class:`openmc.model.Polygon` class allows defining generalized 2D - polygons. (`#2266 `_) -- A new :func:`openmc.data.decay_energy` function and - :meth:`openmc.Material.get_decay_heat` method enable determination of decay - heat from a single nuclide or material. (`#2287 - `_) -- Full models can now be written as a single XML file rather than separate - geometry, materials, settings, and tallies XML files. (`#2291 - `_) -- Discrete distributions are now sampled using alias sampling, which is O(1) in - time. (`#2329 `_) -- The new :class:`openmc.stats.MeshSpatial` allows a spatial source distribution - to be specified with source strengths for each mesh element. (`#2334 - `_) -- The new :meth:`openmc.Geometry.get_surfaces_by_name` method returns a list of - matching surfaces in a geometry. (`#2347 - `_) -- A new :attr:`openmc.Settings.create_delayed_neutrons` attribute controls - whether delayed neutrons are created during a simulation. (`#2348 - `_) -- The :meth:`openmc.deplete.Results.export_to_materials` method now takes a - ``path`` argument. (`#2364 `_) -- A new :meth:`openmc.EnergyFilter.get_tabular` method allows one to create a - tabular distribution based on tally results using an energy filter. (`#2371 - `_) -- Several methods in the :class:`openmc.Material` class that require a volume to - be set (e.g., :meth:`~openmc.Material.get_mass`) now accept a ``volume`` - argument. (`#2412 `_) - ---------- -Bug Fixes ---------- - -- Fix for finding redundant surfaces (`#2263 `_) -- Adds tolerance for temperatures slightly out of bounds (`#2265 `_) -- Fix getter/setter for weight window bounds (`#2275 `_) -- Make sure Chain.reduce preserves decay source (`#2283 `_) -- Fix array shape for weight window bounds (`#2284 `_) -- Fix for non-zero CDF start points in TSL data (`#2290 `_) -- Fix a case where inelastic scattering yield is zero (`#2295 `_) -- Prevent Compton profile out-of-bounds memory access (`#2297 `_) -- Produce light particles from decay (`#2301 `_) -- Fix zero runtime attributes in depletion statepoints (`#2302 `_) -- Fix bug in openmc.Universe.get_nuclide_densities (`#2310 `_) -- Only show print output from depletion on rank 0 (`#2311 `_) -- Fix photon transport with no atomic relaxation data (`#2312 `_) -- Fix for precedence in region expressions (`#2318 `_) -- Allow source particles with energy below cutoff (`#2319 `_) -- Fix IncidentNeutron.from_njoy for high temperatures (`#2320 `_) -- Add capability to unset cell temperatures (`#2323 `_) -- Fix in plot_xs when S(a,b) tables are present (`#2335 `_) -- Various fixes for tally triggers (`#2344 `_) -- Raise error when mesh is flat (`#2363 `_) -- Don't call normalize inside Tabular.mean (`#2375 `_) -- Avoid out-of-bounds access in inelastic scatter sampling (`#2378 `_) -- Use correct direction for anisotropic fission (`#2381 `_) -- Fix several thermal scattering nuclide assignments (`#2382 `_) -- Fix _materials_by_id attribute in Model (`#2385 `_) -- Updates to batch checks for simulation restarts (`#2390 `_) -- write_data_to_vtk volume normalization correction (`#2397 `_) -- Enable generation of JEFF 3.3 depletion chain (`#2410 `_) -- Fix spherical to Cartesian coordinate conversion (`#2417 `_) -- Handle zero photon cross sections in IncidentPhoton.from_ace (`#2433 `_) -- Fix hybrid depletion when nuclides are not present (`#2436 `_) -- Fix bug in cylindrical and spherical meshes (`#2439 `_) -- Improvements to mesh radial boundary coincidence (`#2443 `_) - ------------- -Contributors ------------- - -- `Hunter Belanger `_ -- `Rémi Delaporte-Mathurin `_ -- `Christopher Fichtlscherer `_ -- `Valerio Giusti `_ -- `Chris Keckler `_ -- `Kalin Kiesling `_ -- `Thomas Kittelmann `_ -- `Erik Knudsen `_ -- `Colin Larmier `_ -- `Amanda Lund `_ -- `Jose Ignacio Marquez Damien `_ -- `Josh May `_ -- `Patrick Myers `_ -- `Baptiste Mouginot `_ -- `April Novak `_ -- `Matthew Nyberg `_ -- `Ethan Peterson `_ -- `Gavin Ridley `_ -- `Paul Romano `_ -- `Patrick Shriwise `_ -- `Jonathan Shimwell `_ -- `Paul Wilson `_ -- `Olek Yardas `_ -- `Jiankai Yu `_ diff --git a/docs/source/releasenotes/0.14.0.rst b/docs/source/releasenotes/0.14.0.rst deleted file mode 100644 index f82aa3085..000000000 --- a/docs/source/releasenotes/0.14.0.rst +++ /dev/null @@ -1,284 +0,0 @@ -==================== -What's New in 0.14.0 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This release of OpenMC includes many bug fixes, performance improvements, and -several notable new features. Some of the highlights include projection plots, -pulse height tallies for photons, weight window generation, and an ability to -specify continuous removal or feed of nuclides/elements during depletion. -Additionally, one of the longstanding annoyances of depletion calculations, -namely the need to include initial "dilute" nuclides, has been eliminated. There -are also a wide array of general improvements in the Python API. - ------------------------------------- -Compatibility Notes and Deprecations ------------------------------------- - -- The :class:`openmc.deplete.MicroXS` has been completely redesigned and - improved. See further comments below under "New Features". (`#2572 - `_, `#2579 - `_, `#2595 - `_, `#2700 - `_) -- The ``rectangular_prism`` function has been replaced by the - :class:`openmc.model.RectangularPrism` class and the ``hexagonal_prism`` - function has been replaced by the :class:`openmc.model.HexagonalPrism` class. - Note that whereas the ``rectangular_prism`` and ``hexagonal_prism`` functions - returned a region representing the interior of the prism, the new - :class:`~openmc.model.RectangularPrism` and - :class:`~openmc.model.HexagonalPrism` classes return composite surfaces, so - you need to use the unary ``-`` or ``+`` operators to obtain a region that can - be assigned to a cell. (`#2739 - `_) -- The ``Source`` class has been refactored and split up into three separate - classes: :class:`~openmc.IndependentSource`, :class:`~openmc.FileSource`, and - :class:`~openmc.CompiledSource`. (`#2524 - `_) -- The ``vertices`` and ``centroids`` attributes on mesh classes now always - return Cartesian coordinates and the shape of the returned arrays has changed - to allow `ijk` indexing using a tuple (i.e., `xyz = vertices[i, j, k]`). - (`#2711 `_) -- The :attr:`openmc.Material.decay_photon_energy` attribute has been replaced by - the :meth:`openmc.Material.get_decay_photon_energy` method. (`#2715 - `_) - ------------- -New Features ------------- - -- A new :class:`openmc.WireframeRayTracePlot` class enables the generation of orthographic or - perspective projection plots. (`#1926 - `_) -- The :class:`openmc.model.RightCircularCylinder` class now supports optional - filleted edges. (`#2309 `_) -- Continuous removal or feed of nuclides/elements between materials can now be - modeled during depletion via the - :meth:`openmc.deplete.abc.Integrator.add_transfer_rate` method. (`#2358 - `_, `#2564 - `_, `#2626 - `_) -- The MAGIC method for global weight window generation has been implemented as - part of the C++ API. (`#2359 - `_) -- A new capability for pulse height tallies (currently limited to photons) has - been added and can be used via the "pulse-height" tally score. (`#2452 - `_) -- A :class:`openmc.model.CruciformPrism` class has been added that provides a - generalized cruciform prism composite surface. (`#2457 - `_) -- Type hints have been added in various places throughout the Python API. - (`#2462 `_, `#2467 - `_, `#2468 - `_, `#2470 - `_, `#2471 - `_, `#2601 - `_) -- Voxel plots can now be generated through the :meth:`openmc.Plot.to_vtk` - method. (`#2464 `_) -- The :class:`openmc.mgxs.EnergyGroups` class now allows you to alternatively - pass a string of the group structure name (e.g., "CCFE-709") instead of the - energy group boundaries. (`#2466 - `_) -- Several enhancements have been made to the :meth:`openmc.Universe.plot` method - (addition of axis labels with units, ability to show legend and/or outlines, automatic - determination of origin/width, ability to pass total number of pixels). - (`#2472 `_, `#2482 - `_, `#2483 - `_, `#2492 - `_, `#2513 - `_, `#2575 - `_) -- Functionality in the Python dealing with bounding boxes now relies on a new - :class:`openmc.BoundingBox` class. (`#2475 - `_) -- Users now have more flexibility in specifying nuclides and reactions in the - :func:`openmc.plot_xs` function. (`#2478 - `_) -- The import time of the :mod:`openmc` Python module has been improved by - deferring the import of matplotlib. (`#2488 - `_) -- Mesh clases in the Python API now support a ``bounding_box`` property. (`#2507 - `_, `#2620 - `_, `#2621 - `_) -- The ``Source`` class has been refactored and split up into three separate - classes: :class:`~openmc.IndependentSource`, :class:`~openmc.FileSource`, and - :class:`~openmc.CompiledSource`. (`#2524 - `_) -- Support was added for curvilinear elements when exporting cylindrical and - spherical meshes to VTK. (`#2533 - `_) -- The :class:`openmc.Tally` class now has a - :attr:`~openmc.Tally.multiply_density` attribute that indicates whether - reaction rate tallies should include the number density of the nuclide of - interest. (`#2539 `_) -- The :func:`~openmc.wwinp_to_wws` function now supports ``wwinp`` files with - cylindrical or spherical meshes. (`#2556 - `_) -- Depletion no longer relies on adding initial "dilute" nuclides to each - depletable material in order to compute reaction rates. (`#2559 - `_, `#2568 - `_) -- The :class:`openmc.deplete.Results` class now has - :meth:`~openmc.deplete.Results.get_mass` (`#2565 - `_), - :meth:`~openmc.deplete.Results.get_activity` (`#2617 - `_), and - :meth:`~openmc.deplete.Results.get_decay_heat` (`#2625 - `_) methods. -- The :meth:`openmc.deplete.StepResult.save` method now supports a ``path`` - argument. (`#2567 `_) -- The :class:`openmc.deplete.MicroXS` has been completely redesigned and - improved. First, it no longer relies on the :mod:`openmc.mgxs` module, no - longer subclasses :class:`pandas.DataFrame`, and doesn't require adding - initial "dilute" nuclides into material compositions. It now enables users to - specify an energy group structure to collect multigroup cross sections, - specify nuclides/reactions, and works with mesh domains in addition to the - existing domains. A new :func:`openmc.deplete.get_microxs_and_flux` function - was added that improves the workflow for calculating microscopic cross - sections along with fluxes. Altogether, these changes make it straightforward - to switch between coupled and independent operators for depletion/activation - calculations. (`#2572 `_, - `#2579 `_, `#2595 - `_, `#2700 - `_) -- The :class:`openmc.Geometry` class now has ``merge_surfaces`` and - ``surface_precision`` arguments. (`#2602 - `_) -- Several predefined energy group structures have been added ("MPACT-51", - "MPACT-60", "MPACT-69", "SCALE-252"). (`#2614 - `_) -- When running a depletion calculation, you are now allowed to include nuclides - in the initial material compositions that do not have neutron cross sections - (decay-only nuclides). (`#2616 - `_) -- The :class:`~openmc.CylindricalMesh` and :class:`~openmc.SphericalMesh` - classes can now be fully formed using the constructor. (`#2619 - `_) -- A time cutoff can now be specified in the :attr:`openmc.Settings.cutoff` - attribute. (`#2631 `_) -- The :meth:`openmc.Material.add_element` method now supports a - ``cross_sections`` argument that allows a cross section data source to be - specified. (`#2633 `_) -- The :class:`~openmc.Cell` class now has a :meth:`~openmc.Cell.plot` method. - (`#2648 `_) -- The :class:`~openmc.Geometry` class now has a :meth:`~openmc.Geometry.plot` - method. (`#2661 `_) -- When weight window checks are performed can now be explicitly specified with - the :attr:`openmc.Settings.weight_window_checkpoints` attribute. (`#2670 - `_) -- The :class:`~openmc.Settings` class now has a - :attr:`~openmc.Settings.max_write_lost_particles` attribute that can limit the - number of lost particle files written. (`#2688 - `_) -- The :class:`~openmc.deplete.CoupledOperator` class now has a - ``diff_volume_method`` argument that specifies how the volume of new materials - should be determined. (`#2691 - `_) -- The :meth:`openmc.DAGMCUniverse.bounding_region` method now has a - ``padding_distance`` argument. (`#2701 - `_) -- A new :meth:`openmc.Material.get_decay_photon_energy` method replaces the - :attr:`decay_photon_energy` attribute and includes an ability to eliminate - low-importance points. This is facilitated by a new - :meth:`openmc.stats.Discrete.clip` method. (`#2715 - `_) -- The :meth:`openmc.model.Model.differentiate_depletable_mats` method allows - depletable materials to be differentiated independent of the depletion - calculation itself. (`#2718 - `_) -- Albedos can now be specified on surface boundary conditions. (`#2724 - `_) - ---------- -Bug Fixes ---------- - -- Enable use of NCrystal materials in plot_xs (`#2435 `_) -- Avoid segfault from extern "C" std::string (`#2455 `_) -- Fix several issues with the Model class (`#2465 `_) -- Provide alternative batch estimation message (`#2479 `_) -- Correct index check for remove_tally (`#2494 `_) -- Support for NCrystal material in from_xml_element (`#2496 `_) -- Fix compilation with gcc 5 (`#2498 `_) -- Fixed in the Tally::add_filter method (`#2501 `_) -- Fix meaning of "masking" for plots (`#2510 `_) -- Fix description of statepoint.batches in Settings class (`#2514 `_) -- Reorder list initialization of Plot constructor (`#2519 `_) -- Added mkdir to cwd argument in Model.run (`#2523 `_) -- Fix export of spherical coordinates in SphericalMesh (`#2538 `_) -- Add virtual destructor on PlottableInterface (`#2541 `_) -- Ensure parent directory is created during depletion (`#2543 `_) -- Fix potential out-of-bounds access in TimeFilter (`#2532 `_) -- Remove use of sscanf for reading surface coefficients (`#2574 `_) -- Fix torus intersection bug (`#2589 `_) -- Multigroup per-thread cache fixes (`#2591 `_) -- Bank surface source particles in all active cycles (`#2592 `_) -- Fix for muir standard deviation (`#2598 `_) -- Check for zero fission cross section (`#2600 `_) -- XML read fixes in Plot classes (`#2623 `_) -- Added infinity check in VolumeCalculation (`#2634 `_) -- Fix sampling issue in Mixture distributions (`#2658 `_) -- Prevent segfault in distance to boundary calculation (`#2659 `_) -- Several CylindricalMesh fixes (`#2676 - `_, `#2680 - `_, `#2684 - `_, `#2710 - `_) -- Add type checks on Intersection, Union, Complement (`#2685 `_) -- Fixed typo in CF4Integrator docstring (`#2704 `_) -- Ensure property setters are used in CylindricalMesh and SphericalMesh (`#2709 `_) -- Fix sample_external_source bug (`#2713 `_) -- Fix localization issue affecting openmc-plotter (`#2723 `_) -- Correct openmc.lib wrapper for evaluate_legendre (`#2729 `_) -- Bug fix in Region.from_expression during tokenization (`#2733 `_) -- Fix bug in temperature interpolation (`#2734 `_) -- Check for invalid domain IDs in volume calculations (`#2742 `_) -- Skip boundary condition check for volume calculations (`#2743 `_) -- Fix loop over coordinates for source domain rejection (`#2751 `_) - ------------- -Contributors ------------- - -- `April Novak `_ -- `Baptiste Mouginot `_ -- `Ben Collins `_ -- `Chritopher Billingham `_ -- `Christopher Fichtlscherer `_ -- `Christina Cai `_ -- `Lorenzo Chierici `_ -- `Huw Rhys Jones `_ -- `Emilio Castro `_ -- `Erik Knudsen `_ -- `Ethan Peterson `_ -- `Egor Afanasenko `_ -- `Paul Wilson `_ -- `Gavin Ridley `_ -- `Hunter Belanger `_ -- `Jack Fletcher `_ -- `John Vincent Cauilan `_ -- `Josh May `_ -- `John Tramm `_ -- `Kevin McLaughlin `_ -- `Yue Jin `_ -- `Lewis Gross `_ -- `Luke Labrie-Cleary `_ -- `Patrick Myers `_ -- `Nicola Rizzi `_ -- `Yuvraj Jain `_ -- `Paul Romano `_ -- `Patrick Shriwise `_ -- `Rosie Barker `_ -- `Jonathan Shimwell `_ -- `John Tchakerian `_ -- `Travis Labossiere-Hickman `_ -- `Xinyan Wang `_ -- `Olek Yardas `_ -- `Zoe Prieto `_ diff --git a/docs/source/releasenotes/0.15.0.rst b/docs/source/releasenotes/0.15.0.rst deleted file mode 100644 index 069bfd783..000000000 --- a/docs/source/releasenotes/0.15.0.rst +++ /dev/null @@ -1,262 +0,0 @@ -==================== -What's New in 0.15.0 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This release of OpenMC includes many bug fixes, performance improvements, and -several notable new features. The major highlight of this release is the -introduction of a new transport solver based on the random ray method, which is -fully described in the :ref:`user's guide `. Other notable additions -include a mesh-based source class (:class:`openmc.MeshSource`), a generalization -of source domain rejection through the notion of "constraints", and new methods -on mesh-based classes for computing material volume fractions and homogenized -materials. - ------------------------------------- -Compatibility Notes and Deprecations ------------------------------------- - -Previously, specifying domain rejection for a source was only possible on the -:class:`~openmc.IndependentSoure` class and worked by specifying a `domains` -argument. This capability has been generalized to all source classes and -expanded as well; specifying a domain to reject on should now be done with the -`constraints` argument as follows:: - - source = openmc.IndependentSource(..., constraints={'domains': [cell]}) - -The `domains` argument is deprecated and will be removed in a future version of -OpenMC. Similarly, the ``only_fissionable`` argument to -:class:`openmc.stats.Box` has been replaced by a `'fissionable'` constraint. -That is, instead of specifying:: - - space = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) - source = openmc.IndependentSource(space=space) - -You should now provide the constraint as:: - - space = openmc.stats.Box(lower_left, upper_right) - source = openmc.IndependentSource(space=space, constraints={'fissionable': True}) - -The :attr:`openmc.Settings.max_splits` attribute was renamed to -``max_history_splits`` and its default value has been changed to 1e7 (`#2954 -`_). - ------------- -New Features ------------- - -- When running OpenMC in volume calculation mode, only atomic weight ratio data - is loaded from data files which reduces initialization time. (`#2741 - `_) -- Introduced a ``GeometryState`` class in C++ to better separate particle and - geometry data. (`#2744 `_)) -- A new :class:`openmc.MaterialFromFilter` class allows filtering tallies by - which material a particle came from. (`#2750 - `_) -- Implemented a :meth:`openmc.deplete.MicroXS.from_multigroup_flux` method that - generates microscopic cross sections for depletion from a predetermined - multigroup flux. (`#2755 `_) -- A new :class:`openmc.MeshSource` class enables the specification of a source - distribution over a mesh, where each mesh element has a different - energy/angle/time distribution. (`#2759 - `_) -- Improve performance of depletion solver by utilizing CSR sparse matrix - representation. (`#2764 `_, - `#2771 `_) -- Added a :meth:`openmc.CylindricalMesh.get_indices_at_coords` method that - provides the mesh element index corresponding to a given point in space. - (`#2782 `_) -- Added a `path` argument to the :meth:`openmc.deplete.Integrator.integrate` - method. (`#2784 `_) -- Added a :meth:`openmc.Geometry.get_all_nuclides` method. (`#2796 - `_) -- A new capability to compute material volume fractions over mesh elements was - added in the :meth:`openmc.lib.Mesh.material_volumes` method. (`#2802 - `_) -- A new transport solver was added based on the `random ray - `_ method. (`#2823 - `_, `#2988 - `_) -- Added a :attr:`openmc.lib.Material.depletable` attribute. (`#2843 - `_) -- Added a :meth:`openmc.lib.Mesh.get_plot_bins` method and corresponding - ``openmc_mesh_get_plot_bins`` C API function that can be utilized to generate - mesh tally visualizations in the plotter application. (`#2854 - `_) -- Introduced a :func:`openmc.read_source_file` function that enables reading a - source file from the Python API. (`#2858 - `_) -- Added a ``bounding_box`` property on the :class:`openmc.RectilinearMesh` and - :class:`openmc.UnstructuredMesh` classes. (`#2861 - `_) -- Added a ``openmc_mesh_get_volumes`` C API function. (`#2869 - `_) -- The :attr:`openmc.Settings.surf_source_write` dictionary now accepts `cell`, - `cellfrom`, or `cellto` keys that limit surface source sites to those entering - or leaving specific cells. (`#2888 - `_) -- Added a :meth:`openmc.Region.plot` method that allows regions to be plotted - directly. (`#2895 `_) -- Implemented "contains" operator for the :class:`openmc.BoundingBox` class. - (`#2906 `_) -- Generalized source rejection via a new ``constraints`` argument to all source - classes. (`#2916 `_) -- Added a new :class:`openmc.MeshBornFilter` class that filters tally events - based on which mesh element a particle was born in. (`#2925 - `_) -- The :class:`openmc.Trigger` class now has a ``ignore_zeros`` argument that - results in any bins with zero score to be ignored when checking the trigger. - (`#2928 `_) -- Introduced a :attr:`openmc.Settings.max_events` attribute that controls the - maximum number of events a particle can undergo. (`#2945 - `_) -- Added support for :class:`openmc.UnstructuredMesh` in the - :class:`openmc.MeshSource` class. (`#2949 - `_) -- Added a :meth:`openmc.MeshBase.get_homogenized_materials` method that computes - homogenized materials over mesh elements. (`#2971 - `_) -- Add an ``options`` argument to :class:`openmc.UnstructuredMesh` that allows - configuring underlying data structures in MOAB. (`#2976 - `_) -- Type hints were added to several classes in the :mod:`openmc.deplete` module. - (`#2866 `_) - ---------- -Bug Fixes ---------- - -- Fix unit conversion in openmc.deplete.Results.get_mass (`#2761 `_) -- Fix Lagrangian interpolation (`#2775 `_) -- Depletion restart with MPI (`#2778 `_) -- Modify depletion transfer rates test to be more robust (`#2779 `_) -- Call simulation_finalize if needed when finalizing OpenMC (`#2790 `_) -- F90_NONE Removal (MGMC tallying optimization) (`#2785 `_) -- Correctly apply volumes to materials when using DAGMC geometries (`#2787 `_) -- Add inline to openmc::interpolate (`#2789 `_) -- Use huge_tree=True in lxml parsing (`#2791 `_) -- OpenMPMutex "Copying" (`#2794 `_) -- Do not link against several transitive dependencies of HDF5 (`#2797 `_) -- Added check to length of input arguments for IndependantOperator (`#2799 `_) -- Pytest Update Documentation (`#2801 `_) -- Move 'import lxml' to third-party block of imports (`#2803 `_) -- Fix creation of meshes when from loading settings from XML (`#2805 `_) -- Avoid high memory use when writing unstructured mesh VTK files (`#2806 `_) -- Consolidating thread information into the openmp interface header (`#2809 `_) -- Prevent underflow in calculation of speed (`#2811 `_) -- Provide error message if a cell path can't be determined (`#2812 `_) -- Fix distribcell labels for lattices used as fill in multiple cells (`#2813 `_) -- Make creation of spatial trees based on usage for unstructured mesh. (`#2815 `_) -- Ensure particle direction is normalized for plotting / volume calculations (`#2816 `_) -- Added missing meshes to documentation (`#2820 `_) -- Reset timers at correct place in deplete (`#2821 `_) -- Fix config change not propagating through to decay energies (`#2825 `_) -- Ensure that implicit complement cells appear last in DAGMC universes (`#2838 `_) -- Export model.tallies to XML in CoupledOperator (`#2840 `_) -- Fix locating h5m files references in DAGMC universes (`#2842 `_) -- Prepare for NumPy 2.0 (`#2845 `_) -- Added missing functions and classes to openmc.lib docs (`#2847 `_) -- Fix compilation on CentOS 7 (missing link to libdl) (`#2849 `_) -- Adding resulting nuclide to cross section plot legend (`#2851 `_) -- Updating file extension for Excel files when exporting MGXS data (`#2852 `_) -- Removed error raising when calling warn (`#2853 `_) -- Setting ``surf_source_`` attribute for DAGMC surfaces. (`#2857 `_) -- Changing y axis label for heating plots (`#2859 `_) -- Removed unused step_index arg from restart (`#2867 `_) -- Fix issue with Cell::get_contained_cells() utility function (`#2873 `_) -- Adding energy axis units to plot xs (`#2876 `_) -- Set OpenMCOperator materials when diff_burnable_mats = True (`#2877 `_) -- Fix expansion filter merging (`#2882 `_) -- Added checks that tolerance value is between 0 and 1 (`#2884 `_) -- Statepoint file loading refactor and CAPI function (`#2886 `_) -- Added check for length of value passed into EnergyFilter (`#2887 `_) -- Ensure that Model.run() works when specifying a custom XML path (`#2889 `_) -- Updating docker file base to bookworm (`#2890 `_) -- Clarifying documentation for cones (`#2892 `_) -- Abort on cmake config if openmp requested but not found (`#2893 `_) -- Tiny updates from experience building on Mac (`#2894 `_) -- Added damage-energy as optional reaction for micro (`#2903 `_) -- docs: add missing max_splits in settings specification (`#2910 `_) -- Changed CI to use latest actions to get away from the Node 16 deprecation. (`#2912 `_) -- Mkdir to always allow parents and exist ok (`#2914 `_) -- Fixed small sphinx typo (`#2915 `_) -- Hexagonal lattice iterators (`#2921 `_) -- Fix Chain.form_matrix to work with scipy 1.12 (`#2922 `_) -- Allow get_microxs_and_flux to use OPENMC_CHAIN_FILE environment variable (`#2934 `_) -- Polygon fix to better handle colinear points (`#2935 `_) -- Fix CMFD to work with scipy 1.13 (`#2936 `_) -- Print warning if no natural isotopes when using add_element (`#2938 `_) -- Update xtl and xtensor submodules (`#2941 `_) -- Ensure two surfaces with different boundary type are not considered redundant (`#2942 `_) -- Updated package versions in Dockerfile (`#2946 `_) -- Add MPI calls to DAGMC external test (`#2948 `_) -- Eliminate deprecation warnings from scipy and pandas (`#2951 `_) -- Update math function unit test with catch2 (`#2955 `_) -- Support track file writing for particle restart runs. (`#2957 `_) -- Make UWUW optional (`#2965 `_) -- Allow pure decay IndependentOperator (`#2966 `_) -- Added fix to cfloat_endf for length 11 endf floats (`#2967 `_) -- Moved apt get to optional CI parts (`#2970 `_) -- Update bounding_box docstrings (`#2972 `_) -- Added extra error checking on spherical mesh creation (`#2973 `_) -- Update CODEOWNERS file (`#2974 `_) -- Added error checking on cylindrical mesh (`#2977 `_) -- Correction for histogram interpolation of Tabular distributions (`#2981 `_) -- Enforce lower_left in lattice geometry (`#2982 `_) -- Update random_dist.h comment to be less specific (`#2991 `_) -- Apply memoization in get_all_universes (`#2995 `_) -- Make sure skewed dataset is cast to bool properly (`#3001 `_) -- Hexagonal lattice roundtrip (`#3003 `_) -- Fix CylinderSector and IsogonalOctagon translations (`#3018 `_) -- Sets used instead of lists when membership testing (`#3021 `_) -- Fixing plot xs for when plotting element string reaction (`#3029 `_) -- Fix shannon entropy broken link (`#3034 `_) -- Only add png or h5 extension if not present in plots.py (`#3036 `_) -- Fix non-existent path causing segmentation fault when saving plot (`#3038 `_) -- Resolve warnings related to numpy 2.0 (`#3044 `_) -- Update IsogonalOctagon to use xz basis (`#3045 `_) -- Determine whether nuclides are fissionable in volume calc mode (`#3047 `_) -- Avoiding more numpy 2.0 deprecation warnings (`#3049 `_) -- Set DAGMC cell instances on surface crossing (`#3052 `_) - ------------- -Contributors ------------- - -- `Aidan Crilly `_ -- `April Novak `_ -- `Davide Mancusi `_ -- `Baptiste Mouginot `_ -- `Chris Wagner `_ -- `Lorenzo Chierici `_ -- `Catherine Yu `_ -- `Erik Knudsen `_ -- `Ethan Peterson `_ -- `Gavin Ridley `_ -- `hsameer481 `_ -- `Hunter Belanger `_ -- `Isaac Meyer `_ -- `Jin Whan Bae `_ -- `Joffrey Dorville `_ -- `John Tramm `_ -- `Yue Jin `_ -- `Sigfrid Stjärnholm `_ -- `Kimberly Meagher `_ -- `lhchg `_ -- `Luke Labrie-Cleary `_ -- `Micah Gale `_ -- `Nicholas Linden `_ -- `pitkajuh `_ -- `Rosie Barker `_ -- `Paul Romano `_ -- `Patrick Shriwise `_ -- `Jonathan Shimwell `_ -- `Travis Labossiere-Hickman `_ -- `Vanessa Lulla `_ -- `Olek Yardas `_ -- `Perry Young `_ diff --git a/docs/source/releasenotes/0.15.1.rst b/docs/source/releasenotes/0.15.1.rst deleted file mode 100644 index d879b50ed..000000000 --- a/docs/source/releasenotes/0.15.1.rst +++ /dev/null @@ -1,224 +0,0 @@ -==================== -What's New in 0.15.1 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This release of OpenMC includes many bug fixes, performance improvements, and -several notable new features. The random ray solver continues to receive many -updates and improvements, which are listed below in more detail. A new -:class:`~openmc.SolidRayTracePlot` class has been added that enables attractive -3D visualization using Phong shading. Several composite surfaces have been -introduced (which help to further expand the capabilities of the -`openmc_mcnp_adapter `_). -The :meth:`openmc.Mesh.material_volumes` method has been completely -reimplemented with a new approach based on ray tracing that greatly improves -performance and can be executed in parallel. Tally results can be automatically -applied to input :class:`~openmc.Tally` objects with :meth:`openmc.Model.run`, -bypassing boilerplate code for collecting tally results from statepoint files. -Finally, a new :mod:`openmc.deplete.d1s` submodule has been added that enables -Direct 1-Step (D1S) calculations of shutdown dose rate for fusion applications. - ------------------------------------- -Compatibility Notes and Deprecations ------------------------------------- - -The ``openmc.ProjectionPlot`` class has been renamed to -:class:`openmc.WireframeRayTracePlot` to be in better alignment with the newly -introduced :class:`openmc.SolidRayTracePlot` class. - -NCrystal has been moved from a build-time dependency to a runtime dependency, -which means there is no longer a ``OPENMC_USE_NCRYSTAL`` CMake option. Instead, -OpenMC will look for an installed version of NCrystal using the -``ncrystal-config`` command. - ------------- -New Features ------------- - -- Numerous improvements have been made in the random ray solver: - - Calculation of Shannon entropy now works with random ray (`#3030 `_) - - Support for linear sources (`#3072 `_) - - Ability to slove for adjoint flux (`#3191 `_) - - Support randomized Quasi-Monte Carlo sampling (`#3268 `_) - - FW-CADIS weight window generation (`#3273 `_) - - Source region mesh subdivision(`#3333 `_) -- Several new composite surfaces have been added: - - :class:`openmc.model.OrthogonalBox` (`#3118 `_) - - :class:`openmc.model.ConicalFrustum` (`#3151 `_) - - :class:`openmc.model.Vessel` (`#3168 `_) -- The :meth:`openmc.Model.plot` method now supports plotting source sites - (`#2863 `_) -- The :func:`openmc.stats.delta_function` convenience function can be used for - specifying distributions with a single point (`#3090 - `_) -- Added a :meth:`openmc,Material.get_element_atom_densities` method (`#3103 - `_) -- Several third-party dependencies have been removed: - - Cython (`#3111 `_) - - gsl-lite (`#3225 `_) -- Added a new :class:`openmc.MuSurfaceFilter` class that filters tally events by - the cosine of angle of a surface crossing (`#2768 - `_) -- Introduced a :class:`openmc.ParticleList` class for manipulating a list of - source particles (`#3148 `_) -- Support dose coefficients from ICRP 74 in - :func:`openmc.data.dose_coefficients` (`#3020 - `_) -- Introduced a new :attr:`openmc.Settings.uniform_source_sampling` option - (`#3195 `_) -- Ability to differentiate materials in DAGMC universes (`#3056 - `_) -- Added methods to automatically apply results to existing Tally objects. - (`#2671 `_) -- Implemented a new :class:`openmc.SolidRayTracePlot` class that can produce a - 3D visualization based on Phong shading (`#2655 - `_) -- The :meth:`openmc.UnstructuredMesh.write_data_to_vtk` method now supports - writing a VTU file (`#3290 `_) -- Composite surfaces now have a - :attr:`~openmc.CompositeSurface.component_surfaces` attribute that provides - the underlying primitive surfaces (`#3167 - `_) -- A new :mod:`openmc.deplete.d1s` submodule has been added that enables Direct - 1-Step (D1S) calculations of shutdown dose rate for fusion applications - (`#3235 `_) - ---------------------------- -Bug Fixes and Small Changes ---------------------------- - -- run microxs with mpi (`#3028 `_) -- Rely on std::filesystem for file_utils (`#3042 `_) -- Random Ray Normalization Improvements (`#3051 `_) -- Alternative Random Ray Volume Estimators (`#3060 `_) -- Random Ray Testing Simplification (`#3061 `_) -- Fix hyperlinks in `random_ray.rst` (`#3064 `_) -- Add missing show_overlaps option to plots.xml input file documentation (`#3068 `_) -- Remove use of pkg_resources package (`#3069 `_) -- Add option for survival biasing source normalization (`#3070 `_) -- Enforce sequence type when setting ``Setting.track`` (`#3071 `_) -- Moving most of setup.py to pyproject.toml (`#3074 `_) -- Enforce non-negative percents for ``material.add_nuclide`` to prevent unintended ao/wo flipping (`#3075 `_) -- Include batch statistics discussion in methodology introduction (`#3076 `_) -- Add -DCMAKE_BUILD_TYPE=Release flag for MOAB in Dockerfile (`#3077 `_) -- Adjust decay data reader to better handle non-normalized branching ratios (`#3080 `_) -- Correct openmc.Geometry initializer to accept iterables of ``openmc.Cell`` (`#3081 `_) -- Replace all deprecated Python typing imports and syntax with updated forms (`#3085 `_) -- Fix ParticleFilter to work with set inputs (`#3092 `_) -- packages used for testing moved to tests section of pyprojects.toml (`#3094 `_) -- removed unused which function in CI scripts (`#3095 `_) -- Improve description of probabilities for ``openmc.stats.Tabular`` class (`#3099 `_) -- Ensure RegularMesh repr shows value for width of the mesh (`#3100 `_) -- Replacing endf c functions with package (`#3101 `_) -- Fix random ray solver to correctly simulate fixed source problems with fissionable materials (`#3106 `_) -- Improve error for nuclide temperature not found (`#3110 `_) -- Added error if cross sections path is a folder (`#3115 `_) -- Implement bounding_box operation for meshes (`#3119 `_) -- allowing varible offsets for ``polygon.offset`` (`#3120 `_) -- Write surface source files per batch (`#3124 `_) -- Mat ids reset (`#3125 `_) -- Tweaking title of feature issue template (`#3127 `_) -- Fix a typo in feature request template (`#3128 `_) -- Update quickinstall instructions for macOS (`#3130 `_) -- adapt the openmc-update-inputs script for surfaces (`#3131 `_) -- Theory documentation on PCG random number generator (`#3134 `_) -- Adding tmate action to CI for debugging (`#3138 `_) -- Add Versioning Support from `version.txt` (`#3140 `_) -- Correct failure due to progress bar values (`#3143 `_) -- Avoid writing subnormal nuclide densities to XML (`#3144 `_) -- Immediately resolve complement operators for regions (`#3145 `_) -- Improve Detection of libMesh Installation via `LIBMESH_ROOT` and CMake's PkgConfig (`#3149 `_) -- Fix for UWUW Macro Conflict (`#3150 `_) -- Consistency in treatment of paths for files specified within the Model class (`#3153 `_) -- Improve clipping of Mixture distributions (`#3154 `_) -- Fix check for trigger score name (`#3155 `_) -- Prepare point query data structures on meshes when applying Weight Windows (`#3157 `_) -- Add PointCloud spatial distribution (`#3161 `_) -- Update fmt submodule to version 11.0.2 (`#3162 `_) -- Move to support python 3.13 (`#3165 `_) -- avoid zero division if source rate of previous result is zero (`#3169 `_) -- Fix path handling for thermal ACE generation (`#3171 `_) -- Update `fmt` Formatters for Compatibility with Versions below 11 (`#3172 `_) -- added subfolders to txt search command in pyproject (`#3174 `_) -- added list to doc string arg for plot_xs (`#3178 `_) -- enable polymorphism for mix_materials (`#3180 `_) -- Fix plot_xs type hint (`#3184 `_) -- Enable adaptive mesh support on libMesh tallies (`#3185 `_) -- Reset values of lattice offset tables when allocated (`#3188 `_) -- Update surface_composite.py (`#3189 `_) -- add export_model_xml arguments to ``Model.plot_geometry`` and ``Model.calculate_volumes`` (`#3190 `_) -- Fixes in MicroXS.from_multigroup_flux (`#3192 `_) -- Fix documentation typo in ``boundary_type`` (`#3196 `_) -- Fix docstring for ``Model.plot`` (`#3198 `_) -- Apply weight windows at collisions in multigroup transport mode. (`#3199 `_) -- External sources alias sampler (`#3201 `_) -- Add test for flux bias with weight windows in multigroup mode (`#3202 `_) -- Fix bin index to DoF ID mapping bug in adaptive libMesh meshes (`#3206 `_) -- Ensure ``libMesh::ReplicatedMesh`` is used for LibMesh tallies (`#3208 `_) -- Set Model attributes only if needed (`#3209 `_) -- adding unstrucutred mesh file suffix to docstring (`#3211 `_) -- Write and read mesh name attribute (`#3221 `_) -- Adjust for secondary particle energy directly in heating scores (`#3227 `_) -- Correct normalization of thermal elastic in non standard ENDF-6 files (`#3234 `_) -- Adding '#define _USE_MATH_DEFINES' to make M_PI declared in Intel and MSVC compilers (`#3238 `_) -- updated link to log mapping technique (`#3241 `_) -- Fix for erroneously non-zero tally results of photon threshold reactions (`#3242 `_) -- Fix type comparison (`#3244 `_) -- Enable the LegendreFilter filter to be used in photon tallies for orders greater than P0. (`#3245 `_) -- Enable UWUW library when building with DAGMC in CI (`#3246 `_) -- Remove top-level import of ``openmc.lib`` (`#3250 `_) -- updated docker file to latest DAGMC (`#3251 `_) -- Write mesh type as a dataset always (`#3253 `_) -- Update to a consistent definition of the r2 parameter for cones (`#3254 `_) -- Add Patrick Shriwise to technical committee (`#3255 `_) -- Change `Zernike` documentation in polynomial.py (`#3258 `_) -- Bug fix for Polygon 'yz' basis (`#3259 `_) -- Add constant for invalid surface tokens. (`#3260 `_) -- Update plots.py for PathLike to string handling error (`#3261 `_) -- Fix bug in WeightWindowGenerator for empty energy bounds (`#3263 `_) -- Update recognized thermal scattering materials for ENDF/B-VIII.1 (`#3267 `_) -- simplify mechanism to detect if geometry entity is DAG (`#3269 `_) -- Fix bug in ``Surface.normalize`` (`#3270 `_) -- Tweak To Sphinx Install Documentation (`#3271 `_) -- add continue feature for depletion (`#3272 `_) -- Updates for building with NCrystal support (and fix CI) (`#3274 `_) -- Added missing documentation (`#3275 `_) -- fix the bug in function differentiate_mats() (`#3277 `_) -- Fix the bug in the ``Material.from_xml_element`` function (`#3278 `_) -- Doc typo fix for rand ray mgxs (`#3280 `_) -- Consolidate plotting capabilities in Model.plot (`#3282 `_) -- adding non elastic MT number (`#3285 `_) -- Fix ``Tabular.from_xml_element`` for histogram case (`#3287 `_) -- Random Ray Source Region Refactor (`#3288 `_) -- added terminal output showing compile options selected (`#3291 `_) -- Random ray consistency changes (`#3298 `_) -- Random Ray Explicit Void Treatment (`#3299 `_) -- removed old command line scripts (`#3300 `_) -- Avoid end of life ubuntu 20.04 in ReadTheDocs runner (`#3301 `_) -- Avoid error in CI from newlines in commit message (`#3302 `_) -- Handle reflex angles in CylinderSector (`#3303 `_) -- Relax requirement on polar/azimuthal axis for wwinp conversion (`#3307 `_) -- Add nuclides_to_ignore argument on Model export methods (`#3309 `_) -- Enable overlap plotting from Python API (`#3310 `_) -- Fix access order issues after applying tally results from `Model.run` (`#3313 `_) -- Random Ray Void Accuracy Fix (`#3316 `_) -- Fixes for problems encountered with version determination (`#3320 `_) -- Clarify effect of CMAKE_BUILD_TYPE in docs (`#3321 `_) -- Random Ray Linear Source Stability Improvement (`#3322 `_) -- Mark a canonical URL for docs (`#3324 `_) -- Random Ray Adjoint Source Logic Improvement (`#3325 `_) -- Reflect multigroup MicroXS in IndependentOperator docstrings (`#3327 `_) -- NCrystal becomes runtime rather than buildtime dependency (`#3328 `_) -- Adding per kg as unit option on material functions (`#3329 `_) -- Fix reading of horizontal field of view for ray-traced plots (`#3330 `_) -- Manually fix broken links (`#3331 `_) -- Update pugixml to v1.15 (`#3332 `_) -- Determine nuclides correctly for DAGMC models in d1s.get_radionuclides (`#3335 `_) -- openmc.Material.mix_materials() allows for keyword arguments (`#3336 `_) -- Fix bug in ``Mesh::material_volumes`` for void materials (`#3337 `_) -- added stable and unstable nuclides to the Chain object (`#3338 `_) diff --git a/docs/source/releasenotes/0.15.2.rst b/docs/source/releasenotes/0.15.2.rst deleted file mode 100644 index e72df37d3..000000000 --- a/docs/source/releasenotes/0.15.2.rst +++ /dev/null @@ -1,20 +0,0 @@ -==================== -What's New in 0.15.2 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This is a hotfix release to fix an MPI-related bug that was inadvertently -introduced in the prior release. - ---------------------------- -Bug Fixes and Small Changes ---------------------------- - -- Remove errant ``openmc.Settings.random_ray`` check and removed of not useful warning in MG mode (`#3344 `_) -- Throw an error if a spherical harmonics order larger than 10 is provided. (`#3354 `_) -- Correcting the size of the displacement list in the SourceSite MPI interface object (`#3356 `_) diff --git a/docs/source/releasenotes/0.15.3.rst b/docs/source/releasenotes/0.15.3.rst deleted file mode 100644 index c50958104..000000000 --- a/docs/source/releasenotes/0.15.3.rst +++ /dev/null @@ -1,226 +0,0 @@ -==================== -What's New in 0.15.3 -==================== - -.. currentmodule:: openmc - -------- -Summary -------- - -This release of OpenMC includes many bug fixes, performance improvements, and -several notable new features. The major highlights of this release include a new -:class:`~openmc.deplete.R2SManager` class that automates the workflow for -rigorous 2-step (R2S) shutdown dose rate calculations, the ability to collect -higher moments for tally results that can be used to test normality, a new -uncertainty-aware criticality search method, a new collision tracking feature -that enables detailed tracking of particle interactions, support for distributed -cell densities, and several new tally filters. The random ray solver also -continues to receive significant updates, including automatic setup -capabilities, improved geometry handling, and better weight window support. -Depletion capabilities have been expanded with thermochemical redox control, -external transfer rates, and improved performance. - ------------------------------------- -Compatibility Notes and Deprecations ------------------------------------- - -MCPL has been changed from a build-time dependency to a runtime optional -dependency, which means OpenMC will attempt to load the MCPL library at -runtime when needed rather than requiring it at build time. - -The ``openmc.mgxs.Library.add_to_tallies_file`` method has been renamed to -:meth:`openmc.mgxs.Library.add_to_tallies`. - ------------- -New Features ------------- - -- A new collision tracking feature enables detailed tracking of particle - interactions (`#3417 `_) -- Added :meth:`~openmc.model.Model.keff_search` method for automated criticality - searches (`#3569 `_) -- Introduced automated workflow for mesh- or cell-based R2S calculations - (`#3508 `_) -- Ability to source electron/positrons directly for charged particle - simulations (`#3404 `_) -- Multi-group capability for kinetics parameter calculations with Iterated - Fission Probability (`#3425 - `_) -- Introduced a new :class:`openmc.MeshMaterialFilter` class (`#3406 - `_) -- Added support for distributed cell densities (`#3546 - `_) -- Implemented a :class:`openmc.WeightWindowsList` class that enables export to - HDF5 (`#3456 `_) -- Added :meth:`openmc.Material.mean_free_path` method (`#3469 - `_) -- Introduced :func:`openmc.lib.TemporarySession` context manager (`#3475 - `_) -- Added material depletion function for tracking individual material depletion - (`#3420 `_) -- Added methods on :class:`~openmc.Material` class for waste disposal rating / - classification (`#3366 `_, - `#3376 `_) -- Support for thermochemical redox control transfer rates in depletion - (`#2783 `_) -- Support for external transfer rates source term in depletion (`#3088 - `_) -- Added combing capability for fission site sampling and delayed neutron - emission time (`#2992 `_) -- Ability to specify reference direction for azimuthal angle in - :class:`~openmc.stats.PolarAzimuthal` distribution (`#3582 - `_) -- Allow spatial constraints on element sources within - :class:`~openmc.MeshSource` (`#3431 - `_) -- Added VTK HDF (.vtkhdf) format support for writing VTK data (`#3252 - `_) -- Implemented filter weight capability (`#3345 - `_) -- Optionally collect higher moments for tallies (`#3363 - `_) -- Several random ray solver enhancements: - - - Random Ray AutoMagic Setup for automatic configuration (`#3351 `_) - - Point source locator for random ray mode (`#3360 `_) - - Support for DAGMC geometries (`#3374 `_) - - Optimized mapping of source regions to tallies (`#3465 `_) - - Base source region refactor (`#3576 `_) - ---------------------------- -Bug Fixes and Small Changes ---------------------------- - -- Add two MPI barriers in R2S workflow (`#3646 `_) -- Fix a few warnings, rename add_to_tallies_file (`#3639 `_) -- Fix typo in DAGMC lost particle test (`#3634 `_) -- Avoid multiprocessing Pool when running depletion tests with MPI (`#3633 `_) -- Support MPI parallelism in R2SManager (`#3632 `_) -- Update documentation for particle tracks (`#3627 `_) -- Adding variance of variance and normality tests for tally statistics (`#3454 `_) -- Avoid divide-by-zero in ``from_multigroup_flux`` when flux is zero (`#3624 `_) -- Write particle states as separate lines in track VTK files (`#3628 `_) -- Reset DAGMC history when reviving from source (`#3601 `_) -- Add energy group structure: SCALE-999 (`#3564 `_) -- Fix bug in normalization of tally results with no_reduce (`#3619 `_) -- Enable nuclide filters with get_decay_photon_energy (`#3614 `_) -- Update ``check_type`` calls to accept both ``str`` and ``os.PathLike`` objects (`#3618 `_) -- Speed up ``apply_time_correction`` by reducing file I/O and deepcopies (`#3617 `_) -- FW-CADIS Disregard Max Realizations Setting (`#3616 `_) -- Random Ray Geometry Debug Mode Fix (`#3615 `_) -- Don't write reaction rates in depletion results by default (`#3609 `_) -- Allow Path objects in MGXSLibrary.export_to_hdf5 (`#3608 `_) -- Clip mixture distributions based on mean times integral (`#3603 `_) -- Allow V0 in atomic_mass function (for ENDF/B-VII.0 data) (`#3607 `_) -- Re-run flaky tests when needed (`#3604 `_) -- Ability to load mesh objects from weight_windows.h5 file (`#3598 `_) -- Switch to using coveralls github action for reporting (`#3594 `_) -- Add user setting for free gas threshold (`#3593 `_) -- Speed up time correction factors (`#3592 `_) -- Fix caching issue when using NCrystal materials (`#3538 `_) -- Fix random ray source region mesh export when using model.export_to_xml() (`#3579 `_) -- Ensure weight_windows_file information is read from XML (`#3587 `_) -- Add missing documentation on in depletion chain file format (`#3590 `_) -- Adding tally filter type option to statepoint get_tally (`#3584 `_) -- Optional separation of mesh-material-volume calc from get_homogenized_materials (`#3581 `_) -- Fix IFP implementation (`#3580 `_) -- Remove several TODOs related to C++17 support (`#3574 `_) -- Fix performance regression in libMesh unstructured mesh tallies (`#3577 `_) -- Update find_package calls in OpenMCConfig.cmake (`#3572 `_) -- Ensure ``n_dimension_`` attribute is set for unstructured meshes (`#3575 `_) -- Allow newer Sphinx version and fix docbuild warnings (`#3571 `_) -- Fixed a bug when combining TimeFilter, MeshFilter, and tracklength estimator (`#3525 `_) -- PowerLaw raises an error if sampling interval contains negative values (`#3542 `_) -- depletion: fix performance of chain matrix construction (`#3567 `_) -- Do not apply boundary conditions when initialized in volume calculation mode (`#3562 `_) -- Bump up tolerance for flaky activation test (`#3560 `_) -- Fixed a bug in plotting cross sections with S(a,b) data (`#3558 `_) -- Change test order to run unit tests first (`#3533 `_) -- adding ecco 33 (`#3556 `_) -- Refactor endf_data to be a fixture (`#3539 `_) -- Revert "fix broken CI" (`#3554 `_) -- fix broken CI (`#3551 `_) -- Leverage particle.move_distance in event advance (`#3544 `_) -- fix tests that accidentaly got broken (`#3543 `_) -- not printing nuclides with 0 percent to terminal (option 2 ) (`#3448 `_) -- Fix a bug in time cutoff behavior (`#3526 `_) -- Avoid duplicate materials written to XML (`#3536 `_) -- Use cached property for openmc.data.Decay.sources (`#3535 `_) -- more helpful error message for dose_coefficients (`#3534 `_) -- Adding 616 group structure (`#3531 `_) -- Remove unused special accessors for tallies (`#3527 `_) -- Consistent XML parsing using functions from _xml module (`#3517 `_) -- Add stat:sum field to MCPL files for proper weight normalization (`#3522 `_) -- Remove reorder_attributes from openmc._xml (`#3519 `_) -- fixed a bug in MeshMaterialFilter.from_volumes (`#3520 `_) -- Fixed a bug in distribcell offsets logic (`#3424 `_) -- Add test for FW-CADIS based WW generation on a DAGMC model (`#3504 `_) -- Fix for Weight Window Scaling Bug (`#3511 `_) -- Fix: ``materials``, ``plots``, and ``tallies`` cannot be passed as lists (`#3513 `_) -- Allow already-initialized openmc.lib in TemporarySession (`#3505 `_) -- Update DAGMC and libMesh precompiler definitions (`#3510 `_) -- Avoid adding ParentNuclideFilter twice when calling prepare_tallies (`#3506 `_) -- Enabling MCPL source files to be read when using surf_source_read (`#3472 `_) -- Boundary info accessors (`#3496 `_) -- automatically finding appropriate dimension when making regular mesh from domain (`#3468 `_) -- Add accessor methods for LocalCoord (`#3494 `_) -- Make MCPL a Runtime Optional Dependency (`#3429 `_) -- Use auto-chunking for StepResult HDF5 writing (`#3498 `_) -- Provide a way to get ID maps from plot parameters on the Model class (`#3481 `_) -- Update OSX install instructions to point to x64 platform (`#3501 `_) -- Update conda install instructions for macOS Apple silicon (`#3488 `_) -- Only show warning if in restart mode (`#3478 `_) -- Add flag to CMakeLists to use submodules instead of searching (`#3480 `_) -- Added citation metadata file (`#3409 `_) -- fix zam parsing (`#3484 `_) -- Support flux collapse method in ``get_microxs_and_flux`` (`#3466 `_) -- Stabilize Adjoint Source (`#3476 `_) -- Refactor and Harden Configuration Management (`#3461 `_) -- Updated Docs to Not Give Specific Python Version Requirement (`#3473 `_) -- Parallelization of Weight Window Update (`#3467 `_) -- Limit Random Ray Weight Window Generation to Final Batch (`#3464 `_) -- Fix Dockerfile DAGMC build (`#3463 `_) -- Fix Weight Window Infinite Loop Bug (`#3457 `_) -- Weight Window Birth Scaling (`#3459 `_) -- Adding checks to geometry.plot to avoid material name overlaps (`#3458 `_) -- Fixing crash when calling Geometry.plot when DAGMCUniverse in geometry (`#3455 `_) -- fixing expansion of elemental Ta bug (`#3443 `_) -- Prevent Adjoint Sources from Trending towards Infinity (`#3449 `_) -- adding plot function to DAGMCUnvierse (`#3451 `_) -- Allow specifying number of equiprobable angles for thermal scattering data generation (`#3346 `_) -- Change Dockerfile from debian:bookworm-slim to ubuntu:24.04 (`#3442 `_) -- Fix Resetting of Auto IDs When Generating MGXS (`#3437 `_) -- Allowing chain_file to be chain object to save reloading time (`#3436 `_) -- update units for flux (`#3441 `_) -- Fix raytrace infinite loop (`#3423 `_) -- Apply Max Number of Events Check to Random Rays (`#3438 `_) -- Add user setting for source rejection fraction (`#3433 `_) -- Adding fix and tests for spherical mesh as spatial distribution (`#3428 `_) -- Random Ray Missed Cell Policy Change for Adjoint Mode (`#3434 `_) -- Random Ray External Source Plotting Fix (`#3430 `_) -- Avoid negative heating values during pair production and bremsstrahlung (`#3426 `_) -- Fix no serialization of periodic_surface_id bug (`#3421 `_) -- Update _get_start_data to always grab the beginning of timestep time (`#3414 `_) -- Fixed a bug in charged particle energy deposition (`#3416 `_) -- Fix bug where the same mesh is written multiple times to settings.xml (`#3418 `_) -- small typo - spelling of Debian (`#3411 `_) -- added test for dagmc geometry plot (`#3375 `_) -- Random Ray Misc Memory Error Fixes (`#3405 `_) -- added type hints to model file (`#3399 `_) -- Apply resolve paths to path values in ``config`` (`#3400 `_) -- Fixing an incorrect computation of CDF of bremsstrahlung photons (`#3396 `_) -- Fix weight modification for uniform source sampling (`#3395 `_) -- Updates to VTK data checks (`#3371 `_) -- Map Compton subshell data to atomic relaxation data (`#3392 `_) -- Skip atomic relaxation if binding energy is larger than photon energy (`#3391 `_) -- Fix extremely large yields from Bremsstrahlung (`#3386 `_) -- corrected tally name in D1S example (`#3383 `_) -- Install MCPL using same build type as OpenMC in CI (`#3388 `_) -- using reduce chain level to remove need for reduce chain (`#3377 `_) -- Fix negative distances from bins_crossed for CylindricalMesh (`#3370 `_) -- Add check for equal value bins in an EnergyFilter (`#3372 `_) -- Fix for Issue Loading MGXS Data Files with LLVM 20 or Newer (`#3368 `_) -- Report plot ID instead of index for unsupported plot types in random ray mode (`#3361 `_) -- Handle Missing Tags in Versioning by Setting Default to 0 (`#3359 `_) -- added kg units to doc string in results class (`#3358 `_) diff --git a/docs/source/releasenotes/index.rst b/docs/source/releasenotes/index.rst index 1292599ba..34ddb285a 100644 --- a/docs/source/releasenotes/index.rst +++ b/docs/source/releasenotes/index.rst @@ -7,13 +7,6 @@ Release Notes .. toctree:: :maxdepth: 1 - 0.15.3 - 0.15.2 - 0.15.1 - 0.15.0 - 0.14.0 - 0.13.3 - 0.13.2 0.13.1 0.13.0 0.12.2 diff --git a/docs/source/usersguide/basics.rst b/docs/source/usersguide/basics.rst index c0bc2f976..250255f45 100644 --- a/docs/source/usersguide/basics.rst +++ b/docs/source/usersguide/basics.rst @@ -53,7 +53,7 @@ eXtensible Markup Language (XML) Unlike many other Monte Carlo codes which use an arbitrary-format ASCII file with "cards" to specify a particular geometry, materials, and associated run settings, the input files for OpenMC are structured in a set of `XML -`_ files. XML, which stands for eXtensible Markup +`_ files. XML, which stands for eXtensible Markup Language, is a simple format that allows data to be exchanged efficiently between different programs and interfaces. @@ -75,7 +75,10 @@ person. The nested tags *firstname*, *lastname*, *age*, and *occupation* indicate characteristics about the person being described. In much the same way, OpenMC input uses XML tags to describe the geometry, the -materials, and settings for a Monte Carlo simulation. +materials, and settings for a Monte Carlo simulation. Note that because the XML +files have a well-defined structure, they can be validated using the +:ref:`scripts_validate` script or using :ref:`Emacs nXML mode +`. Creating Input Files -------------------- @@ -83,12 +86,12 @@ Creating Input Files .. currentmodule:: openmc The most rudimentary option for creating input files is to simply write them -from scratch using the :ref:`XML format specifications `. -This approach will feel familiar to users of other Monte Carlo codes such as -MCNP and Serpent, with the added bonus that the XML formats feel much more -"readable". However, it is strongly recommended to generate input files using -OpenMC's :ref:`Python API `, which is introduced in the following -section. +from scratch using the :ref:`XML format specifications +`. This approach will feel familiar to users of other +Monte Carlo codes such as MCNP and Serpent, with the added bonus that the XML +formats feel much more "readable". Alternatively, input files can be generated +using OpenMC's :ref:`Python API `, which is introduced in the +following section. ---------- Python API @@ -178,3 +181,14 @@ energy electronvolt eV time second s ======= ============ ====== +------------------------------------ +ERSN-OpenMC Graphical User Interface +------------------------------------ + +A third-party Java-based user-friendly graphical user interface for creating XML +input files called ERSN-OpenMC_ is developed and maintained by members of the +Radiation and Nuclear Systems Group at the Faculty of Sciences Tetouan, Morocco. +The GUI also allows one to automatically download prerequisites for installing and +running OpenMC. + +.. _ERSN-OpenMC: https://github.com/EL-Bakkali-Jaafar/ERSN-OpenMC diff --git a/docs/source/usersguide/beginners.rst b/docs/source/usersguide/beginners.rst index 6876a3324..eef927b84 100644 --- a/docs/source/usersguide/beginners.rst +++ b/docs/source/usersguide/beginners.rst @@ -109,8 +109,8 @@ familiar with. Whether you plan on working in Linux, macOS, or Windows, you should be comfortable working in a command line environment. There are many resources online for learning command line environments. If you are using Linux or Mac OS X (also Unix-derived), `this tutorial -`_ will help you get acquainted -with commonly-used commands. +`_ will help you get acquainted with +commonly-used commands. To reap the full benefits of OpenMC, you should also have basic proficiency in the use of `Python `_, as OpenMC includes a rich Python @@ -127,8 +127,8 @@ are hosted at `GitHub`_. In order to receive updates to the code directly, submit `bug reports`_, and perform other development tasks, you may want to sign up for a free account on GitHub. Once you have an account, you can follow `these instructions -`_ -on how to set up your computer for using GitHub. +`_ on +how to set up your computer for using GitHub. If you are new to nuclear engineering, you may want to review the NRC's `Reactor Concepts Manual`_. This manual describes the basics of nuclear power for @@ -149,9 +149,9 @@ and `Volume II`_. You may also find it helpful to review the following terms: .. _neutron transport: https://en.wikipedia.org/wiki/Neutron_transport .. _discretization: https://en.wikipedia.org/wiki/Discretization .. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry -.. _git: https://git-scm.com/ +.. _git: http://git-scm.com/ .. _git tutorials: https://git-scm.com/doc -.. _Reactor Concepts Manual: https://www.tayloredge.com/periodic/trivia/ReactorConcepts.pdf +.. _Reactor Concepts Manual: http://www.tayloredge.com/periodic/trivia/ReactorConcepts.pdf .. _Volume I: https://www.standards.doe.gov/standards-documents/1000/1019-bhdbk-1993-v1 .. _Volume II: https://www.standards.doe.gov/standards-documents/1000/1019-bhdbk-1993-v2 .. _OpenMC source code: https://github.com/openmc-dev/openmc diff --git a/docs/source/usersguide/data.rst b/docs/source/usersguide/cross_sections.rst similarity index 61% rename from docs/source/usersguide/data.rst rename to docs/source/usersguide/cross_sections.rst index 8b2938556..0cbb581bd 100644 --- a/docs/source/usersguide/data.rst +++ b/docs/source/usersguide/cross_sections.rst @@ -1,76 +1,57 @@ -.. _usersguide_data: +.. _usersguide_cross_sections: -================== -Data Configuration -================== +=========================== +Cross Section Configuration +=========================== -OpenMC relies on a variety of physical data in order to carry out transport -simulations, depletion simulations, and other common tasks. As a user, you are -responsible for specifying one or more of the following: +In order to run a simulation with OpenMC, you will need cross section data for +each nuclide or material in your problem. OpenMC can be run in continuous-energy +or multi-group mode. -- **Cross sections (XML)** -- A :ref:`cross sections XML ` - file (commonly named ``cross_sections.xml``) contains a listing of other data - files, in particular neutron cross sections, photon cross sections, and - windowed multipole data. Each of those files, in turn, uses a `HDF5 - `_ format (see - :ref:`io_nuclear_data`). In order to run transport simulations with - continuous-energy cross sections, you need to specify this file. +In continuous-energy mode, OpenMC uses a native `HDF5 +`_ format (see :ref:`io_nuclear_data`) to +store all nuclear data. Pregenerated HDF5 libraries can be found at +https://openmc.org; unless you have specific data needs, it is highly +recommended to use one of the pregenerated libraries. Alternatively, if you have +ACE format data that was produced with NJOY_, such as that distributed with +MCNP_ or Serpent_, it can be converted to the HDF5 format using the :ref:`using +the Python API `. Several sources provide openly available +ACE data including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the +`LANL Nuclear Data Team `_. In addition to +tabulated cross sections in the HDF5 files, OpenMC relies on :ref:`windowed +multipole ` data to perform on-the-fly Doppler broadening. -- **Depletion chain (XML)** -- A :ref:`depletion chain XML ` - file contains decay data, fission product yields, and information on what - neutron reactions can result in transmutation. This file is needed for - depletion/activation calculations as well as some basic functions in the - :mod:`openmc.data` module. - -- **Multigroup cross sections (HDF5)** -- OpenMC can also perform transport - simulations using multigroup data. In this case, multigroup cross sections are - stored in a single :ref:`HDF5 file `. Thus, in order to run a - multigroup transport simulation, this file needs to be specified. - -Each of the above files can specified in several ways. In the Python API, a -:ref:`runtime configuration variable ` -:data:`openmc.config` can be used to specify any of the above and is initialized -using a set of environment variables. Data configuration paths set in -:data:`openmc.config` will be expanded to absolute paths. - -.. _usersguide_data_runtime: +In multi-group mode, OpenMC utilizes an HDF5-based library format which can be +used to describe nuclide- or material-specific quantities. --------------------- -Runtime Configuration +Environment Variables --------------------- -Data sources for OpenMC can be specified at runtime in Python using the -:data:`openmc.config` variable. This variable acts like a dictionary and stores -key-values pairs, where the values are file paths (strings or path-like objects) -and the key can be one of the following: +When :ref:`scripts_openmc` is run, it will look for several environment +variables that indicate where cross sections can be found. While the location of +cross sections can also be indicated through the +:attr:`openmc.Materials.cross_sections` attribute (or in the :ref:`materials.xml +` file), if you always use the same set of cross section data, it +is often easier to just set an environment variable that will be picked up by +default every time OpenMC is run. The following environment variables are used: -``"cross_sections"`` - Indicates the path to the :ref:`cross sections XML ` file - that lists HDF5 format neutron cross sections, photon cross sections, and - windowed multipole data. At startup, this is initialized with the value of the - :envvar:`OPENMC_CROSS_SECTIONS` environment variable. Note that the - :attr:`openmc.Materials.cross_sections` attribute will override this, if - specified. +:envvar:`OPENMC_CROSS_SECTIONS` + Indicates the path to the :ref:`cross_sections.xml ` + summary file that is used to locate HDF5 format cross section libraries if the + user has not specified :attr:`openmc.Materials.cross_sections` (equivalently, + the :ref:`cross_sections` in :ref:`materials.xml `). -``"chain_file"`` - Indicates the path to the :ref:`depletion chain XML ` file - that contains decay data, fission product yields, and what neutron reactions - may result in transmutation of a target nuclide. At startup, this is - initialized with the value of the :envvar:`OPENMC_CHAIN_FILE` environment - variable. - -``"mg_cross_sections"`` +:envvar:`OPENMC_MG_CROSS_SECTIONS` Indicates the path to an :ref:`HDF5 file ` that contains - multigroup cross sections. At startup, this is initialized with the value of - the :envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable. Note that the - :attr:`openmc.Materials.cross_sections` attribute will override this if - specified. + multi-group cross sections if the user has not specified + :attr:`openmc.Materials.cross_sections` (equivalently, the + :ref:`cross_sections` in :ref:`materials.xml `). -If you want to persistently set the environment variables used to initialized -the configuration, export them from your shell profile (``.profile`` or -``.bashrc`` in bash_). +To set these environment variables persistently, export them from your shell +profile (``.profile`` or ``.bashrc`` in bash_). -.. _bash: https://www.linuxfromscratch.org/blfs/view/6.3/postlfs/profile.html +.. _bash: http://www.linuxfromscratch.org/blfs/view/6.3/postlfs/profile.html -------------------------------- Continuous-Energy Cross Sections @@ -80,13 +61,12 @@ Using Pregenerated Libraries ---------------------------- Various evaluated nuclear data libraries have been processed into the HDF5 -format required by OpenMC and can be found at https://openmc.org. Unless you -have specific data needs, it is highly recommended to use one of the -pregenerated libraries. You can find both libraries generated by the OpenMC -development team as well as libraries based on ACE files distributed elsewhere. -To use these libraries, download the archive file, unpack it, and then specify -the path of the ``cross_sections.xml`` file contained in the unpacked directory -as described in :ref:`usersguide_data_runtime`. +format required by OpenMC and can be found at https://openmc.org. You +can find both libraries generated by the OpenMC development team as well as +libraries based on ACE files distributed elsewhere. To use these libraries, +download the archive file, unpack it, and then set your +:envvar:`OPENMC_CROSS_SECTIONS` environment variable to the absolute path of +the ``cross_sections.xml`` file contained in the unpacked directory. .. _create_xs_library: @@ -95,12 +75,6 @@ Manually Creating a Library from ACE files .. currentmodule:: openmc.data -If you have ACE format data that was produced with NJOY_, such as that -distributed with MCNP_ or Serpent_, it can be converted to the HDF5 format using -the using the Python API. Several sources provide openly available ACE data -including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the `LANL -Nuclear Data Team `_. - The :mod:`openmc.data` module in the Python API enables users to directly convert ACE data to OpenMC's HDF5 format and create a corresponding :ref:`cross_sections.xml ` file. For those who prefer to use @@ -250,19 +224,6 @@ relaxation sublibrary files are required: Once the HDF5 files have been generated, a library can be created using the :class:`DataLibrary` class as described in :ref:`create_xs_library`. ------------ -Chain Files ------------ - -Pregenerated depletion chain XML files can be found at https://openmc.org. -Additionally, depletion chains can be generated using the -:class:`openmc.deplete.Chain` class. In particular, the -:meth:`~openmc.deplete.Chain.from_endf` method allows a chain to be generated -starting from a set of ENDF incident neutron, decay, and fission product yield -sublibrary files. Once you've downloaded or generated a depletion chain XML -file, make sure to specify its path as described in -:ref:`usersguide_data_runtime`. - ----------------------- Windowed Multipole Data ----------------------- @@ -280,27 +241,27 @@ The `official ENDF/B-VII.1 HDF5 library multipole library, so if you are using this library, the windowed multipole data will already be available to you. -.. _create_mgxs: +-------------------------- +Multi-Group Cross Sections +-------------------------- -------------------------- -Multigroup Cross Sections -------------------------- - -Multigroup cross section libraries are generally tailored to the specific +Multi-group cross section libraries are generally tailored to the specific calculation to be performed. Therefore, at this point in time, OpenMC is not -distributed with any pre-existing multigroup cross section libraries. However, -if a multigroup library file is downloaded or generated, the path to the file -needs to be specified as described in :ref:`usersguide_data_runtime`. For an -example of how to create a multigroup library, see this `MG mode notebook -`_. +distributed with any pre-existing multi-group cross section libraries. +However, if obtained or generated their own library, the user +should set the :envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable +to the absolute path of the file library expected to used most frequently. -.. _NJOY: https://www.njoy21.io/ +For an example of how to create a multi-group library, see the `example notebook +<../examples/mg-mode-part-i.ipynb>`__. + +.. _NJOY: http://www.njoy21.io/ .. _NNDC: https://www.nndc.bnl.gov/endf .. _MCNP: https://mcnp.lanl.gov -.. _Serpent: https://serpent.vtt.fi +.. _Serpent: http://montecarlo.vtt.fi .. _ENDF/B: https://www.nndc.bnl.gov/endf-b7.1/acefiles.html .. _JEFF: https://www.oecd-nea.org/dbdata/jeff/jeff33/ -.. _TENDL: https://tendl.web.psi.ch/tendl_2023/tendl2023.html +.. _TENDL: https://tendl.web.psi.ch/tendl_2017/tendl2017.html .. _Seltzer and Berger: https://doi.org/10.1016/0092-640X(86)90014-8 .. _NIST ESTAR database: https://physics.nist.gov/PhysRefData/Star/Text/ESTAR.html .. _Biggs et al.: https://doi.org/10.1016/0092-640X(75)90030-3 diff --git a/docs/source/usersguide/decay_sources.rst b/docs/source/usersguide/decay_sources.rst deleted file mode 100644 index 19f1e5d5f..000000000 --- a/docs/source/usersguide/decay_sources.rst +++ /dev/null @@ -1,272 +0,0 @@ -.. usersguide_decay_sources: - -============= -Decay Sources -============= - -Through the :ref:`depletion ` capabilities in OpenMC, it -is possible to simulate radiation emitted from the decay of activated materials. -For fusion energy systems, this is commonly done using either the `rigorous -2-step `_ (R2S) method or the -`direct 1-step `_ (D1S) method. -In the R2S method, a neutron transport calculation is used to determine the -neutron flux and reaction rates over a cell- or mesh-based spatial -discretization of the model. Then, the neutron flux in each discrete region is -used to predict the activated material composition using a depletion solver. -Finally, a photon transport calculation with a source based on the activity and -energy spectrum of the activated materials is used to determine a desired -physical response (e.g., a dose rate) at one or more locations of interest. -OpenMC includes automation for both the R2S and D1S methods as described in the -following sections. - -Rigorous 2-Step (R2S) Calculations -================================== - -OpenMC includes an :class:`openmc.deplete.R2SManager` class that fully automates -cell- and mesh-based R2S calculations. Before we describe this class, it is -useful to understand the basic mechanics of how an R2S calculation works. -Generally, it involves the following steps: - -1. The :meth:`openmc.deplete.get_microxs_and_flux` function is called to run a - neutron transport calculation that determines fluxes and microscopic cross - sections in each activation region. -2. The :class:`openmc.deplete.IndependentOperator` and - :class:`openmc.deplete.PredictorIntegrator` classes are used to carry out a - depletion (activation) calculation in order to determine predicted material - compositions based on a set of timesteps and source rates. -3. The activated material composition is determined using the - :class:`openmc.deplete.Results` class. Indexing an instance of this class - with the timestep index returns a :class:`~openmc.deplete.StepResult` object, - which itself has a :meth:`~openmc.deplete.StepResult.get_material` method - returning an activated material. -4. The :meth:`openmc.Material.get_decay_photon_energy` method is used to obtain - the energy spectrum of the decay photon source. The integral of the spectrum - also indicates the intensity of the source in units of [Bq]. -5. A new photon source is defined using one of OpenMC's source classes with the - energy distribution set equal to the object returned by the - :meth:`openmc.Material.get_decay_photon_energy` method. The source is then - assigned to a photon :class:`~openmc.Model`. -6. A photon transport calculation is run with ``model.run()``. - -Altogether, the workflow looks as follows:: - - # Run neutron transport calculation - fluxes, micros = openmc.deplete.get_microxs_and_flux(model, domains) - - # Run activation calculation - op = openmc.deplete.IndependentOperator(mats, fluxes, micros) - timesteps = ... - source_rates = ... - integrator = openmc.deplete.Integrator(op, timesteps, source_rates) - integrator.integrate() - - # Get decay photon source at last timestep - results = openmc.deplete.Results("depletion_results.h5") - step = results[-1] - activated_mat = step.get_material('1') - photon_energy = activated_mat.get_decay_photon_energy() - photon_source = openmc.IndependentSource( - space=..., - energy=photon_energy, - particle='photon', - strength=photon_energy.integral() - ) - - # Run photon transport calculation - model.settings.source = photon_source - model.run() - -Note that by default, the :meth:`~openmc.Material.get_decay_photon_energy` -method will eliminate spectral lines with very low intensity, but this behavior -can be configured with the ``clip_tolerance`` argument. - -Cell-based R2S --------------- - -In practice, users do not need to manually go through each of the steps in an R2S -calculation described above. The :class:`~openmc.deplete.R2SManager` fully -automates the execution of neutron transport, depletion, decay source -generation, and photon transport. For a cell-based R2S calculation, once you -have a :class:`~openmc.Model` that has been defined, simply create an instance -of :class:`~openmc.deplete.R2SManager` by passing the model and a list of cells -to activate:: - - r2s = openmc.deplete.R2SManager(model, [cell1, cell2, cell3]) - -Note that the ``volume`` attribute must be set for any cell that is to be -activated. The :class:`~openmc.deplete.R2SManager` class allows you to -optionally specify a separate photon model; if not given as an argument, it will -create a shallow copy of the original neutron model (available as the -``neutron_model`` attribute) and store it in the ``photon_model`` attribute. We -can use this to define tallies specific to the photon model:: - - dose_tally = openmc.Tally() - ... - r2s.photon_model.tallies = [dose_tally] - -Next, define the timesteps and source rates for the activation calculation:: - - timesteps = [(3.0, 'd'), (5.0, 'h')] - source_rates = [1e12, 0.0] - -In this case, the model is irradiated for 3 days with a source rate of -:math:`10^{12}` neutron/sec and then the source is turned off and the activated -materials are allowed to decay for 5 hours. These parameters should be passed to -the :meth:`~openmc.deplete.R2SManager.run` method to execute the full R2S -calculation. Before we can do that though, for a cell-based calculation, the one -other piece of information that is needed is bounding boxes of the activated -cells:: - - bounding_boxes = { - cell1.id: cell1.bounding_box, - cell2.id: cell2.bounding_box, - cell3.id: cell3.bounding_box - } - -Note that calling the ``bounding_box`` attribute may not work for all -constructive solid geometry regions (for example, a cell that uses a -non-axis-aligned plane). In these cases, the bounding box will need to be -specified manually. Once you have a set of bounding boxes, the R2S calculation -can be run:: - - r2s.run(timesteps, source_rates, bounding_boxes=bounding_boxes) - -If not specified otherwise, a photon transport calculation is run at each time -in the depletion schedule for which a decay photon source exists. Times without -a decay photon source, such as the initial state of a model containing only -stable nuclides, are omitted. To specify particular times at which photon -transport calculations should be run, pass the ``photon_time_indices`` argument. -For example, if we wanted to run a photon transport calculation only on the last -time (after the 5 hour decay), we would run:: - - r2s.run(timesteps, source_rates, bounding_boxes=bounding_boxes, - photon_time_indices=[2]) - -To attribute photon tally results to their parent radionuclides, set -``by_parent_nuclide=True``. This automatically adds a -:class:`openmc.ParentNuclideFilter` to every photon tally that does not already -have one. The filter bins are the union of radionuclides contributing to the -prepared decay photon sources. The resulting bins can be used directly when -inspecting the tally results:: - - r2s.run(timesteps, source_rates, bounding_boxes=bounding_boxes, - photon_time_indices=[2], by_parent_nuclide=True) - - photon_tally = r2s.results['photon_tallies'][2][0] - tally_by_parent = photon_tally.get_pandas_dataframe() - -After an R2S calculation has been run, the :class:`~openmc.deplete.R2SManager` -instance will have a ``results`` dictionary that allows you to directly access -results from each of the steps. It will also write out all the output files into -a directory that is named "r2s_/". The ``output_dir`` argument to the -:meth:`~openmc.deplete.R2SManager.run` method enables you to override the -default output directory name if desired. - -The :meth:`~openmc.deplete.R2SManager.run` method actually runs four -lower-level methods under the hood:: - - r2s.step1_neutron_transport(...) - r2s.step2_activation(...) - r2s.step3_photon_source(...) - r2s.step4_photon_transport(...) - -For users looking for more control over the calculation, these lower-level -methods can be used in lieu of the :meth:`openmc.deplete.R2SManager.run` method. - -Mesh-based R2S --------------- - -Executing a mesh-based R2S calculation looks nearly identical to the cell-based -R2S workflow described above. The only difference is that instead of passing a -list of cells to the ``domains`` argument of -:class:`~openmc.deplete.R2SManager`, you need to define a mesh object and pass -that instead. This might look like the following:: - - # Define a regular Cartesian mesh - mesh = openmc.RegularMesh() - mesh.lower_left = (-50., -50., 0.) - mesh.upper_right = (50., 50., 75.) - mesh.dimension = (10, 10, 5) - - r2s = openmc.deplete.R2SManager(model, mesh) - -Executing the R2S calculation is then performed by adding photon tallies and -calling the :meth:`~openmc.deplete.R2SManager.run` method with the appropriate -timesteps and source rates. Note that in this case we do not need to define cell -volumes or bounding boxes as is required for a cell-based R2S calculation. -Instead, during the neutron transport step, OpenMC will run a raytracing -calculation to determine material volume fractions within each mesh element -using the :meth:`openmc.MeshBase.material_volumes` method. Arguments to this -method can be customized via the ``mat_vol_kwargs`` argument to the -:meth:`~openmc.deplete.R2SManager.run` method. Most often, this would involve -customizing the number of rays traced to obtain better estimates of volumes. As -an example, if we wanted to run the raytracing calculation with 10 million rays, -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 -================================ - -OpenMC also includes built-in capability for performing shutdown dose rate -calculations using the `direct 1-step -`_ (D1S) method. In this method, -a single coupled neutron--photon transport calculation is used where the prompt -photon production is replaced with photons produced from the decay of -radionuclides in an activated material. To obtain properly scaled results, it is -also necessary to apply time correction factors. A normal neutron transport -calculation can be extended to a D1S calculation with a few helper functions. -First, import the ``d1s`` submodule, which is part of :mod:`openmc.deplete`:: - - from openmc.deplete import d1s - -First, you need to instruct OpenMC to use decay photon data instead of prompt -photon data. This is done with an attribute on the :class:`~openmc.Settings` -class:: - - model = openmc.Model() - ... - model.settings.use_decay_photons = True - -To prepare any tallies for use of the D1S method, you should call the -:func:`~openmc.deplete.d1s.prepare_tallies` function, which adds a -:class:`openmc.ParentNuclideFilter` (used later for assigning time correction -factors) to any applicable tally and returns a list of possible radionuclides -based on the :ref:`chain file `. Once the tallies are prepared, -the model can be simulated:: - - output_path = model.run() - -Finally, the time correction factors need to be computed and applied to the -relevant tallies. This can be done with the aid of the -:func:`~openmc.deplete.d1s.time_correction_factors` and -:func:`~openmc.deplete.d1s.apply_time_correction` functions:: - - # Compute time correction factors based on irradiation schedule - factors = d1s.time_correction_factors(nuclides, timesteps, source_rates) - - # Get tally from statepoint - with openmc.StatePoint(output_path) as sp: - dose_tally = sp.get_tally(name='dose tally') - - # Apply time correction factors - tally = d1s.apply_time_correction(dose_tally, factors, time_index) diff --git a/docs/source/usersguide/depletion.rst b/docs/source/usersguide/depletion.rst index 9a22adf01..be9406182 100644 --- a/docs/source/usersguide/depletion.rst +++ b/docs/source/usersguide/depletion.rst @@ -197,54 +197,39 @@ across all material instances. Transport-independent depletion =============================== -This category of operator uses multigroup microscopic cross sections along with -multigroup flux spectra to obtain transmutation reaction rates. The cross -sections are pre-calculated, so there is no need for direct coupling between a -transport-independent operator and a transport solver. The :mod:`openmc.deplete` -module offers a single transport-independent operator, -:class:`~openmc.deplete.IndependentOperator`, and only one operator is needed -since, in theory, any transport code could calculate the multigroup microscopic -cross sections. The :class:`~openmc.deplete.IndependentOperator` class has two -constructors. The default constructor requires a :class:`openmc.Materials` -instance, a list of multigroup flux arrays, and a list of -:class:`~openmc.deplete.MicroXS` instances containing multigroup microscopic -cross sections in units of barns. This might look like the following:: +.. warning:: - materials = openmc.Materials([m1, m2, m3]) + This feature is still under heavy development and has yet to be rigorously + verified. API changes and feature additions are possible and likely in + the near future. + +This category of operator uses pre-calculated one-group microscopic cross +sections to obtain transmutation reaction rates. OpenMC provides the +:class:`~openmc.deplete.IndependentOperator` for this method of calculation. +While the one-group microscopic cross sections can be calculated using a +transport solver, :class:`~openmc.deplete.IndependentOperator` is not directly +coupled to any transport solver. The +:class:`~openmc.deplete.IndependentOperator` class requires a +:class:`openmc.Materials` object, a :class:`~openmc.deplete.MicroXS` object, +and a path to a depletion chain file:: + + # load in the microscopic cross sections + materials = openmc.Materials() ... - # Assign fluxes (generated from any code) - flux_m1 = numpy.array([...]) - flux_m2 = numpy.array([...]) - flux_m3 = numpy.array([...]) - fluxes = [flux_m1, flux_m2, flux_m3] - - # Assign microscopic cross sections - micro_m1 = openmc.deplete.MicroXS.from_csv('xs_m1.csv') - micro_m2 = openmc.deplete.MicroXS.from_csv('xs_m2.csv') - micro_m3 = openmc.deplete.MicroXS.from_csv('xs_m3.csv') - micros = [micro_m1, micro_m2, micro_m3] - - # Create operator - op = openmc.deplete.IndependentOperator(materials, fluxes, micros) - -For more details on the :class:`~openmc.deplete.MicroXS` class, including how to -use OpenMC's transport solver to generate microscopic cross sections and fluxes -for use with :class:`~openmc.deplete.IndependentOperator`, see :ref:`micros`. + micro_xs = openmc.deplete.MicroXS.from_csv(micro_xs_path) + op = openmc.deplete.IndependentOperator(materials, micro_xs, chain_file) .. note:: - The same statements from :ref:`coupled-depletion` about which materials are - depleted and the requirement for depletable materials to have a specified - volume also apply here. + The same statements from :ref:`coupled-depletion` about which + materials are depleted and the requirement for depletable materials to have + a specified volume also apply here. An alternate constructor, :meth:`~openmc.deplete.IndependentOperator.from_nuclides`, accepts a volume and dictionary of nuclide concentrations in place of the :class:`openmc.Materials` -instance. Note that while the normal constructor allows multiple materials to be -depleted with a single operator, the -:meth:`~openmc.deplete.IndependentOperator.from_nuclides` classmethod only works -for a single material:: +object:: nuclides = {'U234': 8.92e18, 'U235': 9.98e20, @@ -255,7 +240,6 @@ for a single material:: volume = 0.5 op = openmc.deplete.IndependentOperator.from_nuclides(volume, nuclides, - flux, micro_xs, chain_file, nuc_units='atom/cm3') @@ -265,21 +249,33 @@ transport-depletion calculation and follow the same steps from there. .. note:: - Ideally, multigroup cross section data should be available for every reaction - in the depletion chain. If cross section data is not present for a nuclide in - the depletion chain with at least one reaction, that reaction will not be + Ideally, one-group cross section data should be available for every + reaction in the depletion chain. If a nuclide that has a reaction + associated with it in the depletion chain is present in the `nuclides` + parameter but not the cross section data, that reaction will not be simulated. -.. _micros: +Generating Microscopic Cross Sections +------------------------------------- -Loading and Generating Microscopic Cross Sections -------------------------------------------------- +Users can generate the one-group microscopic cross sections needed by +:class:`~openmc.deplete.IndependentOperator` using the +:class:`~openmc.deplete.MicroXS` class:: -As mentioned above, any transport code could be used to calculate multigroup -microscopic cross sections and fluxes. The :mod:`openmc.deplete` module provides -the :class:`~openmc.deplete.MicroXS` class, which can either be instantiated -from pre-calculated cross sections in a ``.csv`` file or from data arrays -directly:: + import openmc + + model = openmc.Model.from_xml() + + micro_xs = openmc.deplete.MicroXS.from_model(model, + model.materials[0], + chain_file) + +The :meth:`~openmc.deplete.MicroXS.from_model()` method will produce a +:class:`~openmc.deplete.MicroXS` object with microscopic cross section data in +units of barns, which is what :class:`~openmc.deplete.IndependentOperator` +expects the units to be. The :class:`~openmc.deplete.MicroXS` class also +includes functions to read in cross section data directly from a ``.csv`` file +or from data arrays:: micro_xs = MicroXS.from_csv(micro_xs_path) @@ -288,32 +284,16 @@ directly:: data = np.array([[0.1, 0.2], [0.3, 0.4], [0.01, 0.5]]) - micro_xs = MicroXS(data, nuclides, reactions) + micro_xs = MicroXS.from_array(nuclides, reactions, data) .. important:: - The cross section values are assumed to be in units of barns. Make sure your - cross sections are in the correct units before passing to a + Both :meth:`~openmc.deplete.MicroXS.from_csv()` and + :meth:`~openmc.deplete.MicroXS.from_array()` assume the cross section values + provided are in barns by defualt, but have no way of verifying this. Make + sure your cross sections are in the correct units before passing to a :class:`~openmc.deplete.IndependentOperator` object. -Additionally, a convenience function, -:func:`~openmc.deplete.get_microxs_and_flux`, can provide the needed fluxes and -cross sections using OpenMC's transport solver:: - - model = openmc.Model() - ... - - fluxes, micros = openmc.deplete.get_microxs_and_flux(model, materials) - -If you are running :func:`~openmc.deplete.get_microxs_and_flux` on a cluster -where temporary files are created on a local filesystem that is not shared -across nodes, you'll need to set an environment variable pointing to a local -directoy so that each MPI process knows where to store output files used to -calculate the microscopic cross sections. In order of priority, they are -:envvar:`TMPDIR`. :envvar:`TEMP`, and :envvar:`TMP`. Users interested in further -details can read the documentation for the `tempfile -`_ module. - Caveats ------- @@ -332,32 +312,25 @@ normalizing reaction rates: 1. ``source-rate`` normalization, which assumes the ``source_rate`` provided by the time integrator is a flux, and obtains the reaction rates by multiplying - the cross sections by the ``source-rate``. + the cross-sections by the ``source-rate``. 2. ``fission-q`` normalization, which uses the ``power`` or ``power_density`` - provided by the time integrator to obtain normalized reaction rates by - computing a normalization factor as the ratio of the user-specified power to - the "observed" power based on fission reaction rates. The equation for the - normalization factor is + provided by the time integrator to obtain reaction rates by computing a value + for the flux based on this power. The general equation for the flux is .. math:: - :label: fission-q - f = \frac{P}{\sum\limits_m \sum\limits_i \left(Q_i N_{i,m} \sum\limits_g - \sigma^f_{i,g,m} \phi_{g,m} \right)} + \phi = \frac{P}{\sum\limits_i (Q_i \sigma^f_i N_i)} where :math:`P` is the power, :math:`Q_i` is the fission Q value for nuclide - :math:`i`, :math:`\sigma_{i,g,m}^f` is the microscopic fission cross section - for nuclide :math:`i` in energy group :math:`g` for material :math:`m`, - :math:`\phi_{g,m}` is the neutron flux in group :math:`g` for material - :math:`m`, and :math:`N_{i,m}` is the number of atoms of nuclide :math:`i` - for material :math:`m`. Reaction rates are then multiplied by :math:`f` so - that the total fission power matches :math:`P`. This equation makes the same - assumptions and issues as discussed in :ref:`energy-deposition`. - Unfortunately, the proposed solution in that section does not apply here - since we are decoupled from transport code. However, there is a method to - converge to a more accurate value for flux by using substeps during time - integration. `This paper `_ - provides a good discussion of this method. + :math:`i`, :math:`\sigma_i^f` is the microscopic fission cross section for + nuclide :math:`i`, and :math:`N_i` is the number of atoms of nuclide + :math:`i`. This equation makes the same assumptions and issues as discussed + in :ref:`energy-deposition`. Unfortunately, the proposed solution in that + section does not apply here since we are decoupled from transport code. + However, there is a method to converge to a more accurate value for flux by + using substeps during time integration. `This paper + `_ provides a good discussion + of this method. .. warning:: @@ -368,123 +341,19 @@ normalizing reaction rates: Multiple Materials ~~~~~~~~~~~~~~~~~~ -A transport-independent depletion simulation using ``source-rate`` normalization -will calculate reaction rates for each material independently. This can be -useful for running many different cases of a particular scenario. A -transport-independent depletion simulation using ``fission-q`` normalization -will sum the fission energy values across all materials into :math:`Q_i` in -Equation :math:numref:`fission-q`, and Equation :math:numref:`fission-q` -provides the normalization factor applied to reaction rates in each material. -This can be useful for running a scenario with multiple depletable materials -that are part of the same reactor. This behavior may change in the future. +Running a depletion simulation with multiple materials using the +``source-rate`` normalization method treats each material as completely +separate with respect to reaction rates. This can be useful for running many +different cases of a particular scenario. However, running a depletion +simulation with multiple materials using the ``fission-q`` normalization method +treats each material as part of the same "reactor" due to how ``fission-q`` +normalization accumulates energy values from each material to a single value. +This behavior may change in the future. Time integration ~~~~~~~~~~~~~~~~ -The values of the microscopic cross sections passed to -:class:`openmc.deplete.IndependentOperator` are fixed for the entire depletion -simulation. This implicit assumption may produce inaccurate results for certain -scenarios. - -Transfer Rates -============== - -Transfer rates define removal or feed of nuclides to or from one or more -depletable materials. This can be useful to model continuous fuel reprocessing, -online fission products separation, etc. - -Transfer rates are defined by calling the -:meth:`~openmc.deplete.abc.Integrator.add_transfer_rate()` method directly from -one of the Integrator classes:: - - ... - integrator = openmc.deplete.PredictorIntegrator(op, time_steps, power) - integrator.add_transfer_rate(...) - -Defining transfer rates ------------------------ - -The :meth:`~openmc.deplete.abc.Integrator.add_transfer_rate()` method requires a -:class:`~openmc.Material` instance (alternatively, a material id or -the name) as the depletable material from which nuclides are processed, -a list of elements that share the same transfer rate, and a transfer rate itself. - -.. caution:: - - Make sure you set the transfer rate value with the right sign. - A positive transfer rate assumes removal, while a negative one assumes feed. - -The ``transfer_rate_units`` argument specifies the units for the transfer rate. -The default is `1/s`, but '1/min', '1/h', '1/d' and '1/a' are also valid -options. - -For example, to define continuous removal of xenon from one material with a -removal rate value of 0.1 s\ :sup:`-1` (or a cycle time of 10 s), you'd use:: - - mat1 = openmc.Material(material_id=1, name='fuel') - - ... - - integrator = openmc.deplete.PredictorIntegrator(op, time_steps, power) - # by openmc.Material object - integrator.add_transfer_rate(mat1, ['Xe'], 0.1) - # or by material id - integrator.add_transfer_rate(1, ['Xe'], 0.1) - # or by material name - integrator.add_transfer_rate('fuel', ['Xe'], 0.1) - -Note that in this case the xenon isotopes that are removed will not be tracked. - -Defining a destination material -------------------------------- - -To transfer elements from one depletable material to another, the -``destination_material`` parameter needs to be passed to the -:meth:`~openmc.deplete.abc.Integrator.add_transfer_rate()` method. For example, -to transfer xenon from one material to another, you'd use:: - - ... - mat2 = openmc.Material(name='storage') - - ... - - integrator.add_transfer_rate(mat1, ['Xe'], 0.1, destination_material=mat2) - -Comparing to Other Codes -======================== - -Comparing depletion results from OpenMC with those from another code, such as -MCNP or Serpent, requires more than constructing equivalent transport models. -At each depletion step, differences in the transport solution, nuclear data, -reaction rate normalization, and numerical integration can all affect the -result. Small differences can also accumulate over successive depletion steps. - -For a meaningful comparison, align as many of the following inputs and methods -as possible: - -- Geometry and material definitions and associated physical properties such as - temperature -- Neutron cross section library (e.g., ENDF/B-VIII.0) -- Treatment of thermal scattering and unresolved resonance probability tables -- Neutron reactions accounted for in the depletion chain -- Decay data in the depletion chain -- Isomeric branching ratios for reactions in the depletion chain -- Fission product yields in the depletion chain -- Fission product yield interpolation method - (``CoupledOperator(fission_yield_mode=...)``) -- Reaction rate normalization, including fission Q values - (``CoupledOperator(fission_q=...)``) -- Depletion integration method (``PredictorIntegrator``, ``CECMIntegrator``, - etc.) and time-step sizes - -When comparing to codes that use ACE format cross sections, it is recommended to -directly convert the ACE files to HDF5 format using functionality from the -:mod:`openmc.data` module (see :ref:`create_xs_library`). Some of the -LANL-distributed ACE libraries used with MCNP have also been converted to HDF5 -format and are available for download at https://openmc.org/data. - -Even after these choices have been aligned, exact agreement should not be -expected. Codes may use different approximations or numerical methods that -cannot be configured identically. When investigating a discrepancy, first -compare transport results and one-group reaction rates at the initial time, then -compare changes over subsequent timesteps. +The one-group microscopic cross sections passed to +:class:`openmc.deplete.IndependentOperator` are fixed values for the entire +depletion simulation. This implicit assumption may produce inaccurate results +for certain scenarios. diff --git a/docs/source/usersguide/geometry.rst b/docs/source/usersguide/geometry.rst index 8f83b9b08..2382609a4 100644 --- a/docs/source/usersguide/geometry.rst +++ b/docs/source/usersguide/geometry.rst @@ -147,13 +147,12 @@ For many regions, a bounding-box can be determined automatically:: While a bounding box can be determined for regions involving half-spaces of spheres, cylinders, and axis-aligned planes, it generally cannot be determined if the region involves cones, non-axis-aligned planes, or other exotic -second-order surfaces. For example, the :class:`openmc.model.HexagonalPrism` -class returns a hexagonal prism surface; because it utilizes a -:class:`openmc.Plane`, trying to get the bounding box of its interior won't -work:: +second-order surfaces. For example, the :func:`openmc.model.hexagonal_prism` +function returns the interior region of a hexagonal prism; because it is bounded +by a :class:`openmc.Plane`, trying to get its bounding box won't work:: - >>> hex = openmc.model.HexagonalPrism() - >>> (-hex).bounding_box + >>> hex = openmc.model.hexagonal_prism() + >>> hex.bounding_box (array([-0.8660254, -inf, -inf]), array([ 0.8660254, inf, inf])) @@ -173,19 +172,13 @@ surface. To specify a vacuum boundary condition, simply change the outer_surface = openmc.Sphere(r=100.0) outer_surface.boundary_type = 'vacuum' -Reflective, periodic, and white boundary conditions can be set with the -strings 'reflective', 'periodic', and 'white' respectively. -Vacuum, reflective and white boundary conditions can be applied to any -type of surface. The 'white' boundary condition supports diffuse particle -reflection in contrast to specular reflection provided by the 'reflective' -boundary condition. - -Periodic boundary conditions can be applied to pairs of planar surfaces. -If there are only two periodic surfaces they will be matched automatically. - - -Otherwise it is necessary to specify pairs explicitly using the -:attr:`Surface.periodic_surface` attribute as in the following example:: +Reflective and periodic boundary conditions can be set with the strings +'reflective' and 'periodic'. Vacuum and reflective boundary conditions can be +applied to any type of surface. Periodic boundary conditions can be applied to +pairs of planar surfaces. If there are only two periodic surfaces they will be +matched automatically. Otherwise it is necessary to specify pairs explicitly +using the :attr:`Surface.periodic_surface` attribute as in the following +example:: p1 = openmc.Plane(a=0.3, b=5.0, d=1.0, boundary_type='periodic') p2 = openmc.Plane(a=0.3, b=5.0, d=-1.0, boundary_type='periodic') @@ -194,7 +187,7 @@ Otherwise it is necessary to specify pairs explicitly using the Both rotational and translational periodic boundary conditions are specified in the same fashion. If both planes have the same normal vector, a translational periodicity is assumed; rotational periodicity is assumed otherwise. Currently, -rotations must be about the :math:`x`-, :math:`y`-, or :math:`z`-axis. +only rotations about the :math:`z`-axis are supported. For a rotational periodic BC, the normal vectors of each surface must point inwards---towards the valid geometry. For example, a :class:`XPlane` and @@ -203,20 +196,6 @@ lies in the first quadrant of the Cartesian grid. If the geometry instead lies in the fourth quadrant, the :class:`YPlane` must be replaced by a :class:`Plane` with the normal vector pointing in the :math:`-y` direction. -Additionally, 'reflective', 'periodic', and 'white' boundary conditions have -an albedo parameter that can be used to modify the importance of particles -that encounter the boundary. The albedo value specifies the ratio between -the particle's importance after interaction with the boundary to its initial -importance. The following example creates a reflective planar surface which -reduces the reflected particles' importance by 33.3%:: - - x1 = openmc.XPlane(1.0, boundary_type='reflective', albedo=0.667) - - # This is equivalent - x1 = openmc.XPlane(1.0) - x1.boundary_type = 'reflective' - x1.albedo = 0.667 - .. _usersguide_cells: ----- @@ -248,28 +227,6 @@ 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` or :ref:`lattice -`. 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: --------- @@ -437,11 +394,11 @@ to help figure out how to place universes:: Note that by default, hexagonal lattices are positioned such that each lattice -element has two faces that are perpendicular to the :math:`y` axis. As one -example, to create a three-ring lattice centered at the origin with a pitch of -10 cm where all the lattice elements centered along the :math:`y` axis are -filled with universe ``u`` and the remainder are filled with universe ``q``, the -following code would work:: +element has two faces that are parallel to the :math:`y` axis. As one example, +to create a three-ring lattice centered at the origin with a pitch of 10 cm +where all the lattice elements centered along the :math:`y` axis are filled with +universe ``u`` and the remainder are filled with universe ``q``, the following +code would work:: hexlat = openmc.HexLattice() hexlat.center = (0, 0) @@ -453,7 +410,7 @@ following code would work:: hexlat.universes = [outer_ring, middle_ring, inner_ring] If you need to create a hexagonal boundary (composed of six planar surfaces) for -a hexagonal lattice, :class:`openmc.model.HexagonalPrism` can be used. +a hexagonal lattice, :func:`openmc.model.hexagonal_prism` can be used. .. _usersguide_geom_export: @@ -498,7 +455,7 @@ applied as universes in the OpenMC geometry file. A geometry represented entirely by a DAGMC geometry will contain only the DAGMC universe. Using a :class:`openmc.DAGMCUniverse` looks like the following:: - dag_univ = openmc.DAGMCUniverse('dagmc.h5m') + dag_univ = openmc.DAGMCUniverse(filename='dagmc.h5m') geometry = openmc.Geometry(dag_univ) geometry.export_to_xml() @@ -519,22 +476,13 @@ It is important in these cases to understand the DAGMC model's position with respect to the CSG geometry. DAGMC geometries can be plotted with OpenMC to verify that the model matches one's expectations. -By default, when you specify a .h5m file for a :class:`~openmc.DAGMCUniverse` -instance, it will store the absolute path to the .h5m file. If you prefer to -store the relative path, you can set the ``'resolve_paths'`` configuration -variable:: - - openmc.config['resolve_paths'] = False - dag_univ = openmc.DAGMCUniverse('dagmc.h5m') - -.. note:: - DAGMC geometries used in OpenMC are currently required to be clean, - meaning that all surfaces have been `imprinted and merged - `_ successfully - and that the model is `watertight - `_. - Future implementations of DAGMC geometry will support small volume overlaps and - un-merged surfaces. +**Note:** DAGMC geometries used in OpenMC are currently required to be clean, +meaning that all surfaces have been `imprinted and merged +`_ successfully +and that the model is `watertight +`_. +Future implementations of DAGMC geometry will support small volume overlaps and +un-merged surfaces. Cell, Surface, and Material IDs ------------------------------- @@ -554,89 +502,6 @@ UWUW and OpenMC material ID space will cause an error. To automatically resolve these ID overlaps, ``auto_ids`` can be set to ``True`` to append the UWUW material IDs to the OpenMC material ID space. - -Material overrides and differentiation --------------------------------------- - -Programmatic access to DAGMC cell information for material overrides -and differentiation requires synchronization of the DAGMC universe -representation across Python and C-API:: - - model.init_lib() - model.sync_dagmc_universes() - model.finalize_lib() - -Upon completion of these steps, the :attr:`DAGMCUniverse.cells` attribute will -be populated with :class:`DAGMCCell` proxy objects that represent the cells -defined in the DAGMC model. The :class:`DAGMCCell` objects will have -:class:`openmc.Material`'s' applied according to the assignments upon -initialization of the model. These materials can be replaced in the same manner -as :class:`openmc.Cell` objects to override material assignments in the DAGMC -model. - -Depletion with DAGMC geometry -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The synchronization of :class:`openmc.DAGMCUniverse`'s is important for -depletion calculations using DAGMC geometry when materials need to be -differentiated to perform material burnup independently in each DAGMC cell. See -:meth:`openmc.model.Model.differentiate_mats`. - -Material overrides -~~~~~~~~~~~~~~~~~~ - -OpenMC supports overriding material assignments defined inside a DAGMC HDF5 -model so that CAD-assigned materials can be replaced by :class:`openmc.Material` -objects. This is useful when the CAD geometry provides the shape but OpenMC -materials (specific nuclide content, densities, or depletion behavior) are -required. - - -Replacing materials by name -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If a DAGMC file includes material name tags, you can replace all cells that -reference a particular name with an :class:`openmc.Material` using -:meth:`~openmc.DAGMCUniverse.replace_material_assignment`:: - - import openmc - - dag_univ = openmc.DAGMCUniverse('dagmc.h5m') - - fuel = openmc.Material(name='fuel') - fuel.add_nuclide('U235', 0.05) - fuel.add_nuclide('U238', 0.95) - fuel.set_density('g/cm3', 10.5) - - dag_univ.replace_material_assignment('Fuel', fuel) - -This lets you keep CAD geometry while adopting OpenMC material definitions. - -Per-cell material overrides -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To assign overrides without initializing :class:`openmc.Model`, the -:meth:`openmc.DAGMCUniverse.add_material_override` method can be used to assign -materials to particular DAGMC cells. The method accepts either an integer cell -ID:: - - dag_univ = openmc.DAGMCUniverse('dagmc.h5m') - - enriched = openmc.Material(name='fuel_enriched') - enriched.add_nuclide('U235', 0.10) - enriched.add_nuclide('U238', 0.90) - enriched.set_density('g/cm3', 10.5) - - dag_univ.add_material_override(1, enriched) - -In the case that the :class:`openmc.DAGMCUniverse` has already been synchronized, -a :class:`openmc.DAGMCCell` object can also be provide to assign the material. - -Overrides are written to the `` element of the -:ref:` ` XML element so the C++ core can apply -them on initialization. - - .. _Direct Accelerated Geometry Monte Carlo: https://svalinn.github.io/DAGMC/ .. _University of Wisconsin Unified Workflow: https://svalinn.github.io/DAGMC/usersguide/uw2.html diff --git a/docs/source/usersguide/index.rst b/docs/source/usersguide/index.rst index 5f8e0197e..fab353c77 100644 --- a/docs/source/usersguide/index.rst +++ b/docs/source/usersguide/index.rst @@ -13,7 +13,7 @@ essential aspects of using OpenMC to perform simulations. beginners install - data + cross_sections basics materials geometry @@ -21,12 +21,8 @@ essential aspects of using OpenMC to perform simulations. tallies plots depletion - decay_sources - kinetics scripts processing parallel volume - variance_reduction - random_ray troubleshoot diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 2a0d301d4..3d48828fb 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -8,42 +8,56 @@ Installation and Configuration .. _install_conda: ----------------------------------- -Installing on Linux/Mac with Conda ----------------------------------- +-------------------------------------------------- +Installing on Linux/Mac with Mamba and conda-forge +-------------------------------------------------- -`Conda`_ is an open source package management -system and environments management system for installing multiple versions of +`Conda `_ is an open source package management +systems and environments management system for installing multiple versions of software packages and their dependencies and switching easily between them. -OpenMC can be installed in a `conda` environment. First, `conda` should be -`installed `_ -with either Anaconda Distribution or Miniconda. Once you have `conda` installed -on your system, OpenMC can be installed via the `conda-forge` channel. +`Mamba `_ is a cross-platform package +manager and is compatible with `conda` packages. +OpenMC can be installed in a `conda` environment with `mamba`. +First, `conda` should be installed with one of the following installers: +`Miniconda `_, +`Anaconda `_, or `Miniforge `_. +Once you have `conda` installed on your system, OpenMC can be installed via the +`conda-forge` channel with `mamba`. First, add the `conda-forge` channel with: .. code-block:: sh conda config --add channels conda-forge - conda config --set channel_priority strict -Then create and activate a new conda enviroment called `openmc-env` (or whatever -you wish) with OpenMC installed. +Then create and activate a new conda enviroment called `openmc-env` in +which to install OpenMC. .. code-block:: sh - conda create --name openmc-env openmc + conda create -n openmc-env conda activate openmc-env -If you are installing on macOS with an Apple silicon ARM-based processor, you -will also need to specify the `--platform` option: +Then install `mamba`, which will be used to install OpenMC. .. code-block:: sh - conda create --name openmc-env --platform osx-64 openmc + conda install mamba -You are now in a conda environment called `openmc-env` that has OpenMC -installed. +To list the versions of OpenMC that are available on the `conda-forge` channel, +in your terminal window or an Anaconda Prompt run: + +.. code-block:: sh + + mamba search openmc + +OpenMC can then be installed with: + +.. code-block:: sh + + mamba install openmc + +You are now in a conda environment called `openmc-env` that has OpenMC installed. ------------------------------------------- Installing on Linux/Mac/Windows with Docker @@ -91,9 +105,9 @@ other information use: .. note:: - It should be noted that by default OpenMC is built with - `-DCMAKE_BUILD_TYPE=RelwithDebInfo`. In addition, MPI is OFF while OpenMP is - ON. + It should be noted that by default OpenMC builds with ``-O2 -g`` flags which + are equivalent to a CMake build type of `RelwithDebInfo`. In addition, MPI + is OFF while OpenMP is ON. It is recommended to install OpenMC with the Python API. Information about this Spack recipe can be found with the following command: @@ -119,18 +133,17 @@ following command: configured defaults unless otherwise specfied in the specification on the command line. In the above example, assuming the default options weren't changed in Spack's package configuration, py-openmc will link against a - non-MPI non-release build of openmc. Even if a release build of openmc was - built separately, it will rebuild openmc with the default build type. Thus, - if you are trying to link against dependencies that were configured - different than defaults, ``^openmc[variants]`` will have to be present in - the command. + non-optimized non-MPI openmc. Even if an optimized openmc was built + separately, it will rebuild openmc with optimization OFF. Thus, if you are + trying to link against dependencies that were configured different than + defaults, ``^openmc[variants]`` will have to be present in the command. -For a release build of OpenMC with MPI support on (provided by OpenMPI), the -following command can be used: +For a more performant build of OpenMC with optimization turned ON and MPI +provided by OpenMPI, the following command can be used: .. code-block:: sh - spack install py-openmc +mpi ^openmpi ^openmc build_type=Release + spack install py-openmc+mpi ^openmc+optimize ^openmpi .. note:: @@ -150,7 +163,7 @@ This can be observed using Spack's ``spec`` tool: .. code-block:: - spack spec py-openmc +mpi ^openmc build_type=Release + spack spec py-openmc+mpi ^openmc+optimize Once installed, environment/lmod modules can be generated or Spack's ``load`` feature can be used to access the installed packages. @@ -158,75 +171,6 @@ 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) `_. 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 `_ 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: @@ -297,7 +241,7 @@ Prerequisites OpenMC's built-in plotting capabilities use the libpng library to produce compressed PNG files. In the absence of this library, OpenMC will fallback to writing PPM files, which are uncompressed and only supported by select - image viewers. libpng can be installed on Debian derivates with:: + image viewers. libpng can be installed on Ddebian derivates with:: sudo apt install libpng-dev @@ -327,26 +271,6 @@ Prerequisites cmake -DOPENMC_USE_DAGMC=on -DCMAKE_PREFIX_PATH=/path/to/dagmc/installation .. - * MCPL_ library for reading and writing .mcpl files - - 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). - 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 `_ - for instructions on how to accomplish this. - - * NCrystal_ library for defining materials with enhanced thermal neutron transport - - OpenMC supports the creation of materials from NCrystal, which replaces - the scattering kernel treatment of ACE files with a modular, on-the-fly - approach. OpenMC does not need any particular build option to use this, - but NCrystal must be installed on the system. Refer to `NCrystal - documentation - `_ for how this is - achieved. - * libMesh_ mesh library framework for numerical simulations of partial differential equations This optional dependency enables support for unstructured mesh tally @@ -354,7 +278,7 @@ Prerequisites be used, but the implementation is currently restricted to collision estimators. In addition to turning this option on, the path to the libMesh installation should be specified as part of the ``CMAKE_PREFIX_PATH`` - variable:: + variable.:: cmake -DOPENMC_USE_LIBMESH=on -DOPENMC_USE_MPI=on -DCMAKE_PREFIX_PATH=/path/to/libmesh/installation .. @@ -370,8 +294,6 @@ Prerequisites .. _MOAB: https://bitbucket.org/fathomteam/moab .. _libMesh: https://libmesh.github.io/ .. _libpng: http://www.libpng.org/pub/png/libpng.html -.. _MCPL: https://github.com/mctools/mcpl -.. _NCrystal: https://github.com/mctools/ncrystal Obtaining the Source -------------------- @@ -426,10 +348,6 @@ CMakeLists.txt Options The following options are available in the CMakeLists.txt file: -OPENMC_ENABLE_COVERAGE - Compile and link code instrumented for coverage analysis. This is typically - used in conjunction with gcov_. (Default: off) - OPENMC_ENABLE_PROFILE Enables profiling using the GNU profiler, gprof. (Default: off) @@ -447,29 +365,13 @@ OPENMC_USE_DAGMC OPENMC_USE_LIBMESH Enables the use of unstructured mesh tallies with libMesh_. (Default: off) +OPENMC_ENABLE_COVERAGE + Compile and link code instrumented for coverage analysis. This is typically + used in conjunction with gcov_. (Default: off) + OPENMC_USE_MPI - Turns on compiling with MPI (Default: off). For further information on MPI - options, please see the `FindMPI.cmake documentation - `_. - -.. _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 - modules. + Turns on compiling with MPI (default: off). For further information on MPI options, + please see the `FindMPI.cmake documentation `_. To set any of these options (e.g., turning on profiling), the following form should be used: @@ -489,19 +391,13 @@ OpenMC can be configured for debug, release, or release with debug info by setti the `CMAKE_BUILD_TYPE` option. Debug - Enable debug compiler flags with no optimization. On most platforms/compilers, - this is equivalent to `-O0 -g`. + Enable debug compiler flags with no optimization `-O0 -g`. Release - Disable debug and enable optimization. On most platforms/compilers, this is - equivalent to `-O3 -DNDEBUG`. + Disable debug and enable optimization `-O3 -DNDEBUG`. RelWithDebInfo - (Default if no type is specified.) Enable optimization and debug. On most - platforms/compilers, this is equivalent to `-O2 -g`. When - :ref:`OPENMC_ENABLE_STRICT_FP ` is enabled, OpenMC removes the - ``-DNDEBUG`` flag that CMake normally adds for this build type, so that - C/C++ assertions remain active. + (Default if no type is specified.) Enable optimization and debug `-O2 -g`. Example of configuring for Debug mode: @@ -533,11 +429,11 @@ can typically be set for a single command, i.e. .. _compile_linux: -Compiling on Linux and macOS ----------------------------- +Compiling on Linux and Mac OS X +------------------------------- -To compile OpenMC on Linux or macOS, run the following commands from within the -root directory of the source code: +To compile OpenMC on Linux or Max OS X, run the following commands from within +the root directory of the source code: .. code-block:: sh @@ -557,13 +453,13 @@ OpenMC locally by specifying an install prefix when running cmake: The ``CMAKE_INSTALL_PREFIX`` variable can be changed to any path for which you have write-access. -Compiling on Windows --------------------- +Compiling on Windows 10 +----------------------- -Recent versions of Windows include a subsystem for Linux that allows one to run -Bash within Ubuntu running in Windows. First, follow the installation guide -`here `_ to get Bash on -Ubuntu on Windows set up. Once you are within bash, obtain the necessary +Recent versions of Windows 10 include a subsystem for Linux that allows one to +run Bash within Ubuntu running in Windows. First, follow the installation guide +`here `_ to get Bash +on Ubuntu on Windows setup. Once you are within bash, obtain the necessary :ref:`prerequisites ` via ``apt``. Finally, follow the :ref:`instructions for compiling on linux `. @@ -591,12 +487,18 @@ distribution/repository, run: .. code-block:: sh - python -m pip install . + pip install . pip will first check that all :ref:`required third-party packages ` have been installed, and if they are not present, they will be installed by downloading the appropriate packages from the Python -Package Index (`PyPI `_). +Package Index (`PyPI `_). However, do note that since pip +runs the ``setup.py`` script which requires NumPy, you will have to first +install NumPy: + +.. code-block:: sh + + pip install numpy Installing in "Development" Mode -------------------------------- @@ -609,13 +511,10 @@ to install the Python package in :ref:`"editable" mode `. Prerequisites ------------- -In addition to Python itself, the OpenMC Python API relies on a number of -third-party packages. All prerequisites can be installed using Conda_ -(recommended), pip_, or through the package manager in most Linux distributions. -The current required Python version and up-to-date list of package dependencies -can be found in the `pyproject.toml `_ -file in the root directory of the OpenMC repository. An overview of these -dependencies is provided below. +The Python API works with Python 3.6+. In addition to Python itself, the API +relies on a number of third-party packages. All prerequisites can be installed +using Conda_ (recommended), pip_, or through the package manager in most Linux +distributions. .. admonition:: Required :class: error @@ -633,7 +532,7 @@ dependencies is provided below. notebook `_. - `h5py `_ + `h5py `_ h5py provides Python bindings to the HDF5 library. Since OpenMC outputs various HDF5 files, h5py is needed to provide access to data within these files from Python. @@ -646,7 +545,8 @@ dependencies is provided below. Uncertainties are used for decay data in the :mod:`openmc.data` module. `lxml `_ - lxml is used for various parts of the Python API. + lxml is used for the :ref:`scripts_validate` script and various other + parts of the Python API. .. admonition:: Optional :class: note @@ -656,6 +556,10 @@ dependencies is provided below. parallel runs. This package is needed if you plan on running depletion simulations in parallel using MPI. + `Cython `_ + Cython is used for resonance reconstruction for ENDF data converted to + :class:`openmc.data.IncidentNeutron`. + `vtk `_ The Python VTK bindings are needed to convert voxel and track files to VTK format. @@ -676,16 +580,41 @@ for OpenMC. Thus, the install process would proceed as follows: make install cd .. - MPICC= python -m pip install mpi4py - HDF5_DIR= python -m pip install --no-binary=h5py h5py + MPICC= pip install mpi4py + HDF5_DIR= pip install --no-binary=h5py h5py If you are using parallel HDF5, you'll also need to make sure the right MPI wrapper is used when installing h5py: .. code-block:: sh - CC= HDF5_MPI=ON HDF5_DIR= python -m pip install --no-binary=h5py h5py + CC= HDF5_MPI=ON HDF5_DIR= pip install --no-binary=h5py h5py -.. _Mamba: https://mamba.readthedocs.io/en/latest/ +.. _usersguide_nxml: + +----------------------------------------------------- +Configuring Input Validation with GNU Emacs nXML mode +----------------------------------------------------- + +The `GNU Emacs`_ text editor has a built-in mode that extends functionality for +editing XML files. One of the features in nXML mode is the ability to perform +real-time `validation`_ of XML files against a `RELAX NG`_ schema. The OpenMC +source contains RELAX NG schemas for each type of user input file. In order for +nXML mode to know about these schemas, you need to tell emacs where to find a +"locating files" description. Adding the following lines to your ``~/.emacs`` +file will enable real-time validation of XML input files: + +.. code-block:: common-lisp + + (require 'rng-loc) + (add-to-list 'rng-schema-locating-files "~/openmc/schemas.xml") + +Make sure to replace the last string on the second line with the path to the +schemas.xml file in your own OpenMC source directory. + +.. _GNU Emacs: http://www.gnu.org/software/emacs/ +.. _validation: https://en.wikipedia.org/wiki/XML_validation +.. _RELAX NG: https://relaxng.org/ +.. _ctest: https://cmake.org/cmake/help/latest/manual/ctest.1.html .. _Conda: https://conda.io/en/latest/ .. _pip: https://pip.pypa.io/en/stable/ diff --git a/docs/source/usersguide/kinetics.rst b/docs/source/usersguide/kinetics.rst deleted file mode 100644 index 9024ff822..000000000 --- a/docs/source/usersguide/kinetics.rst +++ /dev/null @@ -1,133 +0,0 @@ -.. _kinetics: - -=================== -Kinetics parameters -=================== - -OpenMC has the capability to estimate the following adjoint-weighted effective -generation time :math:`\Lambda_{\text{eff}}` and the effective delayed neutron -fraction :math:`\beta_{\text{eff}}`. These parameters are calculated using the -iterated fission probability (IFP) method [Hurwitz_1964]_ based on a similar -approach as in `Serpent 2 `_. The -implementation in OpenMC is limited to eigenvalue calculations and is described -in more details in [Dorville_2025]_. - ----------------------------------- -Iterated Fission Probability (IFP) ----------------------------------- - -With IFP, additional information needs to be recorded during the simulation -compared to a typical eigenvalue calculation. OpenMC stores an additional -set of values (neutron lifetime or delayed neutron group number for -:math:`\Lambda_{\text{eff}}` or :math:`\beta_{\text{eff}}`, respectively) -for every fission neutron simulated. Each set of values corresponds to -the values that are associated to the :math:`N_{\text{gen}}` direct ancestors -of any given fission neutron. - -:math:`N_{\text{gen}}` is referred to as the number of generations in the -IFP method and corresponds to the number of generations between the birth of -a fission neutron and the time its score is added to the IFP tally. By default, -OpenMC considers 10 generations but this value can be modified by the user via -the ``ifp_n_generation`` settings in the Python API:: - - settings.ifp_n_generation = 5 - -``ifp_n_generation`` should be greater than 0, but should also be lower than -or equal to the number of inactive batches declared for the calculation. -The respect of these constraints is verified by OpenMC before any calculation. - -OpenMC will automatically detect the type of data that needs to be stored based -on the tally scores selected by the user. This guarantees that only information -of interest are stored during a simulation and avoids using extra memory when -only one parameter is needed. The following table shows the tally scores that -are needed to compute kinetics parameters in OpenMC: - -.. table:: **OpenMC tally scores needed to calculate adjoint-weighted kinetics parameters** - :align: center - - =============================== ============================ ========================== ======== - OpenMC tally score \\ Parameter :math:`\Lambda_{\text{eff}}` :math:`\beta_{\text{eff}}` Both - =============================== ============================ ========================== ======== - ``ifp-time-numerator`` X X - ``ifp-beta-numerator`` X X - ``ifp-denominator`` X X X - =============================== ============================ ========================== ======== - -| - -.. note:: Because the memory footprint of additional data is generally non-negligible - with IFP, it is recommended to choose the value for ``ifp_n_generation`` carefully. - For example, using one generation for both kinetics parameters corresponds to store - one additional integer (for the delayed neutron group number used with - :math:`\beta_{\text{eff}}`) and one floating point value (for the neutron lifetime - used with :math:`\Lambda_{\text{eff}}`) for every fission neutron simulated once the - asymptotic regime is reached. - ------------------------------ -Obtaining kinetics parameters ------------------------------ - -The ``Model`` class can be used to automatically generate all IFP tallies using -the Python API with :attr:`openmc.Settings.ifp_n_generation` greater than 0 and -the :meth:`openmc.Model.add_ifp_kinetics_tallies` method:: - - model = openmc.Model(geometry, settings=settings) - model.add_kinetics_parameters_tallies(num_groups=6) # Add 6 precursor groups - -Alternatively, each of the tallies can be manually defined using group-wise or -total :math:`\beta_{\text{eff}}` specified by providing a 6-group -:class:`openmc.DelayedGroupFilter`:: - - beta_tally = openmc.Tally(name="group-beta-score") - beta_tally.scores = ["ifp-beta-numerator"] - - # Add DelayedGroupFilter to enable group-wise tallies - beta_tally.filters = [openmc.DelayedGroupFilter(list(range(1, 7)))] - -Here is an example showing how to declare the three available IFP scores in a -single tally:: - - tally = openmc.Tally(name="ifp-scores") - tally.scores = [ - "ifp-time-numerator", - "ifp-beta-numerator", - "ifp-denominator" - ] - -The effective generation time :math:`\Lambda_{\text{eff}}` is calculated -by dividing the result of the ``ifp-time-numerator`` score by the one obtained -for ``ifp-denominator`` and by the :math:`k_{\text{eff}}` of the simulation: - -.. math:: - :label: lambda_eff - - \Lambda_{\text{eff}} = \frac{S_{\text{ifp-time-numerator}}}{S_{\text{ifp-denominator}} \times k_{\text{eff}}} - -The effective delayed neutron fraction :math:`\beta_{\text{eff}}` is calculated -by dividing the result of the ``ifp-beta-numerator`` score by the one obtained -for ``ifp-denominator``: - -.. math:: - :label: beta_eff - - \beta_{\text{eff}} = \frac{S_{\text{ifp-beta-numerator}}}{S_{\text{ifp-denominator}}} - -The kinetics parameters can be retrieved directly from a statepoint file using -the :meth:`openmc.StatePoint.ifp_results` method:: - - with openmc.StatePoint(output_path) as sp: - generation_time, beta_eff = sp.get_kinetics_parameters() - -.. only:: html - - .. rubric:: References - -.. [Hurwitz_1964] H. Hurwitz Jr., "Naval Reactors Physics Handbook", volume 1, p. 864. - Radkowsky, A. (Ed.), Naval Reactors, Division of Reactor Development, U.S. - Atomic Energy Commission (1964). - -.. [Dorville_2025] J. Dorville, L. Labrie-Cleary, and P. K. Romano, "Implementation - of the Iterated Fission Probability Method in OpenMC to Compute Adjoint-Weighted - Kinetics Parameters", International Conference on Mathematics and Computational - Methods Applied to Nuclear Science and Engineering (M&C 2025), Denver, April 27-30, - 2025. diff --git a/docs/source/usersguide/materials.rst b/docs/source/usersguide/materials.rst index 83af55805..8b43f1a2a 100644 --- a/docs/source/usersguide/materials.rst +++ b/docs/source/usersguide/materials.rst @@ -101,42 +101,6 @@ you would need to add hydrogen and oxygen to a material and then assign the .. _usersguide_naming: -------------------------- -Adding NCrystal materials -------------------------- - -Additional support for thermal scattering can be added by using NCrystal_. The -:meth:`Material.from_ncrystal` class method generates a :class:`openmc.Material` -object from an `NCrystal configuration string -`_. -Temperature, material composition, and density are passed from the configuration -string and the `NCMAT file -`_ that define the -material, e.g.:: - - mat = openmc.Material.from_ncrystal('Al_sg225.ncmat;temp=300K') - -defines a material containing polycrystalline alumnium, - -:: - - mat = openmc.Material.from_ncrystal("""Ge_sg227.ncmat;dcutoff=0.5;mos=40arcsec; - dir1=@crys_hkl:5,1,1@lab:0,0,1; - dir2=@crys_hkl:0,-1,1@lab:0,1,0""") - -defines an oriented germanium single crystal with 40 arcsec mosaicity. - -NCrystal only handles low energy neutron interactions. Other interactions are -provided by standard ACE files. NCrystal_ comes with a `predefined library -`_ but more materials can -be added by creating NCMAT files or on-the-fly in the configuration string. - -.. warning:: Currently, NCrystal_ materials cannot be modified after they are created. - Density, temperature and composition should be defined in the - configuration string or the NCMAT file. - -.. _NCrystal: https://github.com/mctools/ncrystal - ------------------ Naming Conventions ------------------ @@ -258,4 +222,3 @@ been generated, you can tell OpenMC to use this file either by setting materials.cross_sections = '/path/to/cross_sections.xml' .. _MCNP: https://mcnp.lanl.gov/ - diff --git a/docs/source/usersguide/parallel.rst b/docs/source/usersguide/parallel.rst index ecbdd20b6..be4189604 100644 --- a/docs/source/usersguide/parallel.rst +++ b/docs/source/usersguide/parallel.rst @@ -101,5 +101,5 @@ performance on a machine when running in parallel: settings = openmc.Settings() settings.output = {'tallies': False} -.. _Haswell-EP: https://www.anandtech.com/show/8423/intel-xeon-e5-version-3-up-to-18-haswell-ep-cores-/4 -.. _bound: https://github.com/pmodels/mpich/blob/main/doc/wiki/how_to/Using_the_Hydra_Process_Manager.md#process-core-binding +.. _Haswell-EP: http://www.anandtech.com/show/8423/intel-xeon-e5-version-3-up-to-18-haswell-ep-cores-/4 +.. _bound: https://wiki.mpich.org/mpich/index.php/Using_the_Hydra_Process_Manager#Process-core_Binding diff --git a/docs/source/usersguide/plots.rst b/docs/source/usersguide/plots.rst index b5c29a3e8..d57917a3d 100644 --- a/docs/source/usersguide/plots.rst +++ b/docs/source/usersguide/plots.rst @@ -6,14 +6,13 @@ Geometry Visualization .. currentmodule:: openmc -OpenMC is capable of producing two-dimensional slice plots of a geometry, -three-dimensional voxel plots, and three-dimensional raytrace plots using the -geometry plotting :ref:`run mode `. The geometry plotting -mode relies on the presence of a :ref:`plots.xml ` file that indicates -what plots should be created. To create this file, one needs to create one or -more instances of the various plot classes described below, add them to a -:class:`openmc.Plots` collection, and then use the :class:`Plots.export_to_xml` -method to write the ``plots.xml`` file. +OpenMC is capable of producing two-dimensional slice plots of a geometry as well +as three-dimensional voxel plots using the geometry plotting :ref:`run mode +`. The geometry plotting mode relies on the presence of a +:ref:`plots.xml ` file that indicates what plots should be created. To +create this file, one needs to create one or more :class:`openmc.Plot` +instances, add them to a :class:`openmc.Plots` collection, and then use the +:class:`Plots.export_to_xml` method to write the ``plots.xml`` file. ----------- Slice Plots @@ -22,14 +21,15 @@ Slice Plots .. image:: ../_images/atr.png :width: 300px -The :class:`openmc.SlicePlot` class indicates that a 2D slice plot should be -made. You can specify the origin of the plot (:attr:`SlicePlot.origin`), the -width of the plot in each direction (:attr:`SlicePlot.width`), the number of -pixels to use in each direction (:attr:`SlicePlot.pixels`), and the basis -directions for the plot. For example, to create a :math:`x` - :math:`z` plot -centered at (5.0, 2.0, 3.0) with a width of (50., 50.) and 400x400 pixels:: +By default, when an instance of :class:`openmc.Plot` is created, it indicates +that a 2D slice plot should be made. You can specify the origin of the plot +(:attr:`Plot.origin`), the width of the plot in each direction +(:attr:`Plot.width`), the number of pixels to use in each direction +(:attr:`Plot.pixels`), and the basis directions for the plot. For example, to +create a :math:`x` - :math:`z` plot centered at (5.0, 2.0, 3.0) with a width of +(50., 50.) and 400x400 pixels:: - plot = openmc.SlicePlot() + plot = openmc.Plot() plot.basis = 'xz' plot.origin = (5.0, 2.0, 3.0) plot.width = (50., 50.) @@ -47,7 +47,7 @@ that location. By default, a unique color will be assigned to each cell in the geometry. If you want your plot to be colored by material instead, change the -:attr:`SlicePlot.color_by` attribute:: +:attr:`Plot.color_by` attribute:: plot.color_by = 'material' @@ -68,8 +68,8 @@ particular cells/materials should be given colors of your choosing:: Note that colors can be given as RGB tuples or by a string indicating a valid `SVG color `_. -When you're done creating your :class:`openmc.SlicePlot` instances, you need to -then assign them to a :class:`openmc.Plots` collection and export it to XML:: +When you're done creating your :class:`openmc.Plot` instances, you need to then +assign them to a :class:`openmc.Plots` collection and export it to XML:: plots = openmc.Plots([plot1, plot2, plot3]) plots.export_to_xml() @@ -97,11 +97,13 @@ Voxel Plots .. image:: ../_images/3dba.png :width: 200px -The :class:`openmc.VoxelPlot` class enables the generation of a 3D voxel plot -instead of a 2D slice plot. In this case, the :attr:`VoxelPlot.width` and -:attr:`VoxelPlot.pixels` attributes should be three items long, e.g.:: +The :class:`openmc.Plot` class can also be told to generate a 3D voxel plot +instead of a 2D slice plot. Simply change the :attr:`Plot.type` attribute to +'voxel'. In this case, the :attr:`Plot.width` and :attr:`Plot.pixels` attributes +should be three items long, e.g.:: - vox_plot = openmc.VoxelPlot() + vox_plot = openmc.Plot() + vox_plot.type = 'voxel' vox_plot.width = (100., 100., 50.) vox_plot.pixels = (400, 400, 200) @@ -109,159 +111,13 @@ The voxel plot data is written to an :ref:`HDF5 file `. The voxel file can subsequently be converted into a standard mesh format that can be viewed in `ParaView `_, `VisIt `_, etc. This typically -will compress the size of the file significantly. The -:func:`openmc.voxel_to_vtk` function can convert the HDF5 voxel file to VTK -formats. Once processed into a standard 3D file format, colors and masks can be -defined using the stored ID numbers to better explore the geometry. The process -for doing this will depend on the 3D viewer, but should be straightforward. +will compress the size of the file significantly. The provided +:ref:`scripts_voxel` script can convert the HDF5 voxel file to VTK formats. Once +processed into a standard 3D file format, colors and masks can be defined using +the stored ID numbers to better explore the geometry. The process for doing this +will depend on the 3D viewer, but should be straightforward. .. note:: 3D voxel plotting can be very computer intensive for the viewing program (Visit, ParaView, etc.) if the number of voxels is large (>10 million or so). Thus if you want an accurate picture that renders smoothly, consider using only one voxel in a certain direction. - ----------------------- -Solid Ray-traced Plots ----------------------- - -.. image:: ../_images/phong_triso.png - :width: 300px - -The :class:`openmc.SolidRayTracePlot` class allows three dimensional -visualization of detailed geometric features without voxelization. The plot -above visualizes a geometry created by :class:`openmc.TRISO`, with the materials -in the fuel kernel distinguished by color. It was enclosed in a bounding box -such that some kernels are cut off, revealing the inner structure of the kernel. - -The `Phong reflection model -`_ approximates how light -reflects off of a surface. On a diffusely light-scattering material, the Phong -model prescribes the amount of light reflected from a surface as proportional to -the dot product between the normal vector of the surface and the vector between -that point on the surface and the light. With this assumption, visually -appealing plots of simulation geometries can be created. - -Solid ray-traced plots use the same ray tracing functions that neutrons and -photons do in OpenMC, so any input that does not leak particles can be -visualized in 3D using a solid ray-traced plot. That being said, these plots are -not useful for detecting overlap or undefined regions, so it is recommended to -use the slice plot approach for geometry debugging. - -Only a few inputs are required for a solid ray-traced plot. The camera location, -where the camera is looking, and a set of opaque material or cell IDs are -required. The colors of materials or cells are prescribed in the same way as -slice plots. The set of IDs that are opaque in the plot must correspond to -materials if coloring by material, or cells if coloring by cell. - -A minimal solid ray-traced plot input could be:: - - plot = openmc.SolidRayTracePlot() - plot.pixels = (600, 600) - plot.camera_position = (10.0, 20.0, -30.0) - plot.look_at = (4.0, 5.0, 1.0) - plot.color_by = 'cell' - - # optional. defaults to camera_position - plot.light_position = (10, 20, 30) - - # controls ambient lighting. Defaults to 10% - plot.diffuse_fraction = 0.1 - plot.opaque_domains = [cell2, cell3] - -These plots are then stored into a :class:`openmc.Plots` instance, just like the -slice plots. - ---------------- -Wireframe Plots ---------------- - -.. only:: html - - .. image:: ../_images/hexlat_anim.gif - :width: 200px - -The :class:`openmc.WireframeRayTracePlot` class also produces 3D visualizations -of OpenMC geometries without voxelization but is intended to show the inside of -a model using wireframing of cell or material boundaries in addition to cell -coloring based on the path length of camera rays through the model. The coloring -in these plots is a bit like turning the model into partially transparent -colored glass that can be seen through, without any refractive effects. This is -called volume rendering. The colors are specified in exactly the same interface -employed by slice plots. - -Similar to solid ray-traced plots, these use the native ray tracing capabilities -within OpenMC, so any geometry in which particles successfully run without -overlaps or leaks will work with wireframe plots. - -One drawback of wireframe plots is that particle tracks cannot be overlaid on -them at present. Moreover, checking for overlap regions is not currently -possible with wireframe plots. The image heading this section can be created by -adding the following code to the hexagonal lattice example packaged with OpenMC, -before exporting to plots.xml. - -:: - - r = 5 - import numpy as np - for i in range(100): - phi = 2 * np.pi * i/100 - thisp = openmc.WireframeRayTracePlot(plot_id = 4 + i) - thisp.filename = 'frame%s'%(str(i).zfill(3)) - thisp.look_at = [0, 0, 0] - thisp.camera_position = [r * np.cos(phi), r * np.sin(phi), 6 * np.sin(phi)] - thisp.pixels = [200, 200] - thisp.color_by = 'material' - thisp.colorize(geometry) - thisp.set_transparent(geometry) - thisp.xs[fuel] = 1.0 - thisp.xs[iron] = 1.0 - thisp.wireframe_domains = [fuel] - thisp.wireframe_thickness = 2 - - plot_file.append(thisp) - -This generates a sequence of png files that can be joined to form a gif. Each -image specifies a different camera position using some simple periodic functions -to create a perfectly looped gif. :attr:`~WireframeRayTracePlot.look_at` defines -where the camera's centerline should point at. -:attr:`~WireframeRayTracePlot.camera_position` similarly defines where the -camera is situated in the universe level we seek to plot. The other settings -resemble those employed by :class:`openmc.Plot`, with the exception of the -:meth:`~WireframeRayTracePlot.set_transparent` method and -:attr:`~WireframeRayTracePlot.xs` dictionary. These are used to control volume -rendering of material volumes. "xs" here stands for cross section, and it -defines material opacities in units of inverse centimeters. Setting this value -to a large number would make a material or cell opaque, and setting it to zero -makes a material transparent. Thus, the -:meth:`~WireframeRayTracePlot.set_transparent` method can be used to make all -materials in the geometry transparent. From there, individual material or cell -opacities can be tuned to produce the desired result. - -Two camera projections are available when using these plots, perspective and -orthographic. The default, perspective projection, is a cone of rays passing -through each pixel which radiate from the camera position and span the field of -view in the x and y positions. The horizontal field of view can be set with the -:attr:`~WireframeRayTracePlot.horizontal_field_of_view` attribute, which is to -be specified in units of degrees. The field of view only influences behavior in -perspective projection mode. - -In the orthographic projection, rays follow the same angle but originate from -different points. The horizontal width of this plane of ray starting points may -be set with the :attr:`~WireframeRayTracePlot.orthographic_width` attribute. If -this element is nonzero, the orthographic projection is employed. Left to its -default value of zero, the perspective projection is employed. - -Most importantly, wireframe plots come packaged with wireframe generation that -can target either all surface/cell/material boundaries in the geometry, or only -wireframing around specific regions. In the above example, we have set only the -fuel region from the hexagonal lattice example to have a wireframe drawn around -it. This is accomplished by setting the -:attr:`~WireframeRayTracePlot.wireframe_domains` attribute, which may be set to -either material IDs or cell IDs. The -:attr:`~WireframeRayTracePlot.wireframe_thickness` attribute sets the wireframe -thickness in units of pixels. - -.. note:: When setting specific material or cell regions to have wireframes - drawn around them, the plot must be colored by materials if wireframing - around specific materials and similarly colored by cell instance if - wireframing around specific cells. diff --git a/docs/source/usersguide/processing.rst b/docs/source/usersguide/processing.rst index ed3e8564a..3103b7b7c 100644 --- a/docs/source/usersguide/processing.rst +++ b/docs/source/usersguide/processing.rst @@ -41,9 +41,12 @@ Plotting in 2D -------------- The `example notebook`_ also demonstrates how to plot a structured mesh tally in -two dimensions using the Python API. One can also use the `openmc-plotter -`_ application that provides an -interactive GUI to explore and plot a much wider variety of tallies. +two dimensions using the Python API. One can also use the :ref:`scripts_plot` +script which provides an interactive GUI to explore and plot structured mesh +tallies for any scores and filter bins. + +.. image:: ../_images/plotmeshtally.png + :width: 400px .. _usersguide_track: @@ -68,17 +71,17 @@ generation, and particle number of the desired particle. For example, to create a track file for particle 4 of batch 1 and generation 2:: settings = openmc.Settings() - settings.track = [(1, 2, 4)] + settings.track = (1, 2, 4) -To specify multiple particles, specify a list of tuples, e.g., if we wanted -particles 3 and 4 from batch 1 and generation 2:: +To specify multiple particles, the length of the iterable should be a multiple +of three, e.g., if we wanted particles 3 and 4 from batch 1 and generation 2:: - settings.track = [(1, 2, 3), (1, 2, 4)] + settings.track = (1, 2, 3, 1, 2, 4) -After running OpenMC (now, without the ``-t`` argument), the working directory -will contain a file named `tracks.h5`, which contains a collection of particle -tracks. These track files can be converted into VTK poly data files or -matplotlib plots with the :class:`openmc.Tracks` class. +After running OpenMC, the working directory will contain a file of the form +"track_(batch #)_(generation #)_(particle #).h5" for each particle tracked. +These track files can be converted into VTK poly data files with the +:ref:`scripts_track` script. ---------------------- Source Site Processing @@ -91,90 +94,3 @@ from a statepoint file, the ``openmc.statepoint`` module can be used. An `example notebook`_ demontrates how to analyze and plot source information. .. _example notebook: https://nbviewer.jupyter.org/github/openmc-dev/openmc-notebooks/blob/main/post-processing.ipynb - ------------------------- -VTK Mesh File Generation ------------------------- - -VTK files of OpenMC meshes can be created using 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`, -:class:`~openmc.CylindricalMesh`, or :class:`SphericalMesh`), the data can be -shaped with dimensions that match the dimensions of the mesh itself. - - -.. image:: ../_images/sphere-mesh-vtk.png - :width: 400px - :align: center - :alt: OpenMC spherical mesh exported to VTK - - -For all mesh types, if a flat data array is provided to the mesh, it is expected -that the data is ordered in the same ordering as the :attr:`openmc.Mesh.indices` -for that mesh object. When providing data directly from a tally, as shown below, -a flat array for a given dataset can be passed directly to this method. - -:: - - # create model above - - # create a mesh tally - mesh = openmc.RegularMesh() - mesh.dimension = [10, 20, 30] - mesh.lower_left = [-5, -10, -15] - mesh.upper_right = [5, 10, 15] - mesh_filter = openmc.MeshFilter(mesh) - tally = openmc.Tally() - tally.filters = [mesh_filter] - tally.scores = ['flux'] - - model.tallies = [tally] - model.run(apply_tally_results=True) - - # provide the data as-is to the method - mesh.write_data_to_vtk('flux.vtk', {'flux-mean': tally.mean}) - -The :class:`~openmc.Tally` object also provides a way to expand the dimensions -of the mesh filter into a meaningful form where indexing the mesh filter -dimensions results in intuitive slicing of structured meshes by setting -``expand_dims=True`` when using :meth:`openmc.Tally.get_reshaped_data`. This -reshaping does cause flat indexing of the data to change, however. As noted -above, provided datasets are allowed to be shaped so long as such datasets have -shapes that match the mesh dimensions. The ability to pass datasets in this way -is useful when additional filters are applied to a tally. The example below -demonstrates such a case for tally with both a :class:`~openmc.MeshFilter` and -:class:`~openmc.EnergyFilter` applied. - -:: - - # create model above - - # create a mesh tally with energy filter - mesh = openmc.RegularMesh() - mesh.dimension = [10, 20, 30] - mesh.lower_left = [-5, -10, -15] - mesh.upper_right = [5, 10, 15] - mesh_filter = openmc.MeshFilter(mesh) - energy_filter = openmc.EnergyFilter([0.0, 1.0, 20.0e6]) - tally = openmc.Tally() - tally.filters = [mesh_filter, energy_filter] - tally.scores = ['flux'] - - model.tallies = [tally] - model.run(apply_tally_results=True) - - # get the data with mesh dimensions expanded, squeeze out length-one dimensions (nuclides, scores) - flux = tally.get_reshaped_data(expand_dims=True).squeeze() # shape: (10, 20, 30, 2) - - # write the lowest energy group to a VTK file - mesh.write_data_to_vtk('flux-group1.vtk', datasets={'flux-mean': flux[..., 0]}) diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst deleted file mode 100644 index 06d4e50ed..000000000 --- a/docs/source/usersguide/random_ray.rst +++ /dev/null @@ -1,1277 +0,0 @@ -.. _random_ray: - -================= -Random Ray Solver -================= - -In general, the random ray solver mode uses most of the same settings and -:ref:`run strategies ` as the standard Monte Carlo solver -mode. For instance, random ray solves are also split up into :ref:`inactive and -active batches `. However, there are a couple of settings -that are unique to the random ray solver and a few areas that the random ray -run strategy differs, both of which will be described in this section. - -.. _quick_start: - ------------ -Quick Start ------------ - -While this page contains a comprehensive guide to the random ray solver and -its various parameters, the process of converting an existing continuous energy -Monte Carlo model to a random ray model can be largely automated via convenience -functions in OpenMC's Python interface:: - - # Define continuous energy model as normal - model = openmc.Model() - ... - - # Convert model to multigroup (will auto-generate MGXS library if needed) - model.convert_to_multigroup() - - # Convert model to random ray and initialize random ray parameters - # to reasonable defaults based on the specifics of the geometry - model.convert_to_random_ray() - - # (Optional) Overlay source region decomposition mesh to improve fidelity of the - # random ray solver. Adjust 'n' for fidelity vs runtime. - n = 100 - mesh = openmc.RegularMesh() - mesh.dimension = (n, n, n) - mesh.lower_left = model.geometry.bounding_box.lower_left - mesh.upper_right = model.geometry.bounding_box.upper_right - model.settings.random_ray['source_region_meshes'] = [(mesh, [model.geometry.root_universe])] - - # (Optional) Improve fidelity of the random ray solver by enabling linear sources - model.settings.random_ray['source_shape'] = 'linear' - - # (Optional) Increase the number of rays/batch, to reduce uncertainty - model.settings.particles = 500 - -The above strategy first converts the continuous energy model to a multigroup -one using the :meth:`openmc.Model.convert_to_multigroup` method. By default, -this will internally run a coarsely converged continuous energy Monte Carlo -simulation to produce an estimated multigroup macroscopic cross section set for -each material specified in the model, and store this data into a multigroup -cross section library file (``mgxs.h5``) that can be used by the random ray -solver. - -The :meth:`openmc.Model.convert_to_random_ray` method enables random ray mode -and performs an analysis of the model geometry to determine reasonable values -for all required parameters. If default behavior is not satisfactory, the user -can manually adjust the settings in the :attr:`~openmc.Settings.random_ray` -dictionary in the :class:`openmc.Settings` as described in the sections below. - -Finally a few optional steps are shown. The first (recommended) step overlays a -mesh over the geometry to create smaller source regions so that source -resolution improves and the random ray solver becomes more accurate. Varying the -mesh resolution can be used to trade off between accuracy and runtime. -High-fidelity fission reactor simulation may require source region sizes below 1 -cm, while larger fixed source problems with some tolerance for error may be able -to use source regions of 10 or 100 cm. - -We also enable linear sources, which can improve the accuracy of the random ray -solver and/or allow for a much coarser mesh resolution to be overlaid. Finally, -the number of rays per batch is adjusted. The goal here is to ensure that the -source region miss rate is below 1%, which is reported by OpenMC at the end of -the simulation (or before via a warning if it is very high). - -.. warning:: - If using a mesh filter for tallying or weight window generation, ensure that - the same mesh is used for source region decomposition via - ``model.settings.random_ray['source_region_meshes']``. - ------------------------- -Enabling Random Ray Mode ------------------------- - -To utilize the random ray solver, the :attr:`~openmc.Settings.random_ray` -dictionary must be present in the :class:`openmc.Settings` Python class. There -are a number of additional settings that must be specified within this -dictionary that will be discussed below. Additionally, the "multi-group" energy -mode must be specified. - -------- -Batches -------- - -In Monte Carlo simulations, inactive batches are used to let the fission source -develop into a stationary distribution before active batches are performed that -actually accumulate statistics. While this is true of random ray as well, in the -random ray mode the inactive batches are also used to let the scattering source -develop. Monte Carlo fully represents the scattering source within each -iteration (by its nature of fully simulating particles from birth to death -through any number of physical scattering events), whereas the scattering source -in random ray can only represent as many scattering events as batches have been -completed. For example, by iteration 10 in random ray, the scattering source -only captures the behavior of neutrons through their 10th scattering event. -Thus, while inactive batches are only required in an eigenvalue solve in Monte -Carlo, **inactive batches are required for both eigenvalue and fixed source -solves in random ray mode** due to this additional need to converge the -scattering source. - -.. warning:: - Unlike Monte Carlo, the random ray solver still requires usage of inactive - batches when in fixed source mode so as to develop the scattering source. - -The additional burden of converging the scattering source generally results in a -higher requirement for the number of inactive batches---often by an order of -magnitude or more. For instance, it may be reasonable to only use 50 inactive -batches for a light water reactor simulation with Monte Carlo, but random ray -might require 500 or more inactive batches. - -Similar to Monte Carlo, active batches are used in the random ray solver mode to -accumulate and converge statistics on unknown quantities (i.e., the random ray -sources, scalar fluxes, as well as any user-specified tallies). - -The batch parameters are set in the same manner as with the regular Monte Carlo -solver:: - - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.batches = 1200 - settings.inactive = 600 - ---------------- -Shannon Entropy ---------------- - -Similar to Monte Carlo, :ref:`Shannon entropy -` can be used to gauge whether the fission -source has fully developed. The Shannon entropy is calculated automatically -after each batch and is printed to the statepoint file. Unlike Monte Carlo, an -entropy mesh does not need to be defined, as the Shannon entropy is calculated -over FSRs using a volume-weighted approach. - -------------------------------- -Inactive Ray Length (Dead Zone) -------------------------------- - -A major issue with random ray is that the starting angular flux distribution for -each sampled ray is unknown. Thus, an on-the-fly method is used to build a high -quality approximation of the angular flux of the ray each iteration. This is -accomplished by running the ray through an inactive length (also known as a dead -zone length), where the ray is moved through the geometry and its angular flux -is solved for via the normal :ref:`MOC ` equation, but -no information is written back to the system. Thus, the ray is run in a "read -only" mode for the set inactive length. This parameter can be adjusted, in units -of cm, as:: - - settings.random_ray['distance_inactive'] = 40.0 - -After several mean free paths are traversed, the angular flux spectrum of the -ray becomes dominated by the in-scattering and fission source components that it -picked up when travelling through the geometry, while its original (incorrect) -starting angular flux is attenuated toward zero. Thus, longer selections of -inactive ray length will asymptotically approach the true angular flux. - -In practice, 10 mean free paths are sufficient (with light water reactors often -requiring only about 10--50 cm of inactive ray length for the error to become -undetectable). However, we caution that certain models with large quantities of -void regions (even if just limited to a few streaming channels) may require -significantly longer inactive ray lengths to ensure that the angular flux is -accurate before the conclusion of the inactive ray length. Additionally, -problems where a sensitive estimate of the uncollided flux is required (e.g., -the detector response to fast neutrons is required, and the detected is located -far away from the source in a moderator region) may require the user to specify -an inactive length that is derived from the pyhsical geometry of the simulation -problem rather than its material properties. For instance, consider a detector -placed 30 cm outside of a reactor core, with a moderator region separating the -detector from the core. In this case, rays sampled in the moderator region and -heading toward the detector will begin life with a highly scattered thermal -spectrum and will have an inaccurate fast spectrum. If the dead zone length is -only 20 cm, we might imagine such rays writing to the detector tally within -their active lengths, despite their inaccurate estimate of the uncollided fast -angular flux. Thus, an inactive length of 100--200 cm would ensure that any such -rays would still be within their inactive regions, and only rays that have -actually traversed through the core (and thus have an accurate representation of -the core's emitted fast flux) will score to the detector region while in their -active phase. - - ------------------------------------- -Active Ray Length and Number of Rays ------------------------------------- - -Once the inactive length of the ray has completed, the active region of the ray -begins. The ray is now run in regular mode, where changes in angular flux as it -traverses through each flat source region are written back to the system, so as -to contribute to the estimate for the iteration scalar flux (which is used to -compute the source for the next iteration). The active ray length can be -adjusted, in units of [cm], as:: - - settings.random_ray['distance_active'] = 400.0 - -Assuming that a sufficient inactive ray length is used so that the starting -angular flux is highly accurate, any selection of active length greater than -zero is theoretically acceptable. However, in order to adequately sample the -full integration domain, a selection of a very short track length would require -a very high number of rays to be selected. Due to the static costs per ray of -computing the starting angular flux in the dead zone, typically very short ray -lengths are undesireable. Thus, to amortize the per-ray cost of the inactive -region of the ray, it is desirable to select a very long inactive ray length. -For example, if the inactive length is set to 20 cm, a 200 cm active ray length -ensures that only about 10% of the overall simulation runtime is spent in the -inactive ray phase integration, making the dead zone a relatively inexpensive -way of estimating the angular flux. - -Thus, to fully amortize the cost of the dead zone integration, one might ask why -not simply run a single ray per iteration with an extremely long active length? -While this is also theoretically possible, this results in two issues. The first -problem is that each ray only represents a single angular sample. As we want to -sample the angular phase space of the simulation with similar fidelity to the -spatial phase space, we naturally want a lot of angles. This means in practice, -we want to balance the need to amortize the cost of the inactive region of the -ray with the need to sample lots of angles. The second problem is that -parallelism in OpenMC is expressed in terms of rays, with each being processed -by an independent MPI rank and/or OpenMP thread, thus we want to ensure each -thread has many rays to process. - -In practical terms, the best strategy is typically to set an active ray length -that is about 10 times that of the inactive ray length. This is often the right -balance between ensuring not too much time is spent in the dead zone, while -still adequately sampling the angular phase space. However, as discussed in the -previous section, some types of simulation may demand that additional thought be -applied to this parameter. For instance, in the same example where we have a -detector region far outside a reactor core, we want to make sure that there is -enough active ray length that rays exiting the core can reach the detector -region. For example, if the detector were to be 30 cm outside of the core, then -we would need to ensure that at least a few hundred cm of active length were -used so as to ensure even rays with indirect angles will be able to reach the -target region. - -The number of rays each iteration can be set by reusing the normal Monte Carlo -particle count selection parameter, as:: - - settings.particles = 2000 - ------------ -Ray Density ------------ - -In the preceding sections, it was argued that for most use cases, the inactive -length for a ray can be determined by taking a multiple of the mean free path -for the limiting energy group. The active ray length could then be set by taking -a multiple of the inactive length. With these parameters set, how many rays per -iteration should be run? - -There are three basic settings that control the density of the stochastic -quadrature being used to integrate the domain each iteration. These three -variables are: - -- The number of rays (in OpenMC settings parlance, "particles") -- The inactive distance per ray -- The active distance per ray - -While the inactive and active ray lengths can usually be chosen by simply -examining the geometry, tallies, and cross section data, one has much more -flexibility in the choice of the number of rays to run. Consider a few -scenarios: - -- If a choice of zero rays is made, then no information is gained by the system - after each batch. -- If a choice of rays close to zero is made, then some information is gained - after each batch, but many source regions may not have been visited that - iteration, which is not ideal numerically and can result in instability. - Empirically, we have found that the simulation can remain stable and produce - accurate results even when on average 20% or more of the cells have zero rays - passing through them each iteration. However, besides the cost of transporting - rays, a new neutron source must be computed based on the scalar flux at each - iteration. This cost is dictated only by the number of source regions and - energy groups---it is independent of the number of rays. Thus, in practical - terms, if too few rays are run, then the simulation runtime becomes dominated - by the fixed cost of source updates, making it inefficient overall given that - a huge number of active batches will likely be required to converge statistics - to acceptable levels. Additionally, if many cells are missed each iteration, - then the fission and scattering sources may not develop very quickly, - resulting in a need for far more inactive batches than might otherwise be - required. -- If a choice of running a very large number of rays is made such that you - guarantee that all cells are hit each iteration, this avoids any issues with - numerical instability. As even more rays are run, this reduces the number of - active batches that must be used to converge statistics and therefore - minimizes the fixed per-iteration source update costs. While this seems - advantageous, it has the same practical downside as with Monte Carlo---namely, - that the inactive batches tend to be overly well integrated, resulting in a - lot of wasted time. This issue is actually much more serious than in Monte - Carlo (where typically only tens of inactive batches are needed), as random - ray often requires hundreds or even thousands of inactive batches. Thus, - minimizing the cost of the source updates in the active phase needs to be - balanced against the increased cost of the inactive phase of the simulation. -- If a choice of rays is made such that relatively few (e.g., around 0.1%) of - cells are missed each iteration, the cost of the inactive batches of the - simulation is minimized. In this "goldilocks" regime, there is very little - chance of numerical instability, and enough information is gained by each cell - to progress the fission and scattering sources forward at their maximum rate. - However, the inactive batches can proceed with minimal cost. While this will - result in the active phase of the simulation requiring more batches (and - correspondingly higher source update costs), the added cost is typically far - less than the savings by making the inactive phase much cheaper. - -To help you set this parameter, OpenMC will report the average flat source -region miss rate at the end of the simulation. Additionally, OpenMC will alert -you if very high miss rates are detected, indicating that more rays and/or a -longer active ray length might improve numerical performance. Thus, a "guess and -check" approach to this parameter is recommended, where a very low guess is -made, a few iterations are performed, and then the simulation is restarted with -a larger value until the "low ray density" messages go away. - -.. note:: - In summary, the user should select an inactive length corresponding to many - times the mean free path of a particle, generally O(10--100) cm, to ensure accuracy of - the starting angular flux. The active length should be 10× the inactive - length to amortize its cost. The number of rays should be enough so that - nearly all :ref:`FSRs ` are hit at least once each power iteration (the hit fraction - is reported by OpenMC for empirical user adjustment). - -.. warning:: - For simulations where long range uncollided flux estimates need to be - accurately resolved (e.g., shielding, detector response, and problems with - significant void areas), make sure that selections for inactive and active - ray lengths are sufficiently long to allow for transport to occur between - source and target regions of interest. - -.. _usersguide_ray_source: - ----------- -Ray Source ----------- - -Random ray requires that the ray source be uniform in space and isotropic in -angle. To facilitate sampling, the user must specify a single random ray source -for sampling rays in both eigenvalue and fixed source solver modes. The random -ray integration source should be of type :class:`openmc.IndependentSource`, and -is specified as part of the :attr:`openmc.Settings.random_ray` dictionary. Note -that the source must not be limited to only fissionable regions. Additionally, -the source box must cover the entire simulation domain. In the case of a -simulation domain that is not box shaped, a box source should still be used to -bound the domain but with the source limited to rejection sampling the actual -simulation universe (which can be specified via the ``domains`` constraint of the -:class:`openmc.IndependentSource` Python class). Similar to Monte Carlo sources, -for two-dimensional problems (e.g., a 2D pincell) it is desirable to make the -source bounded near the origin of the infinite dimension. An example of an -acceptable ray source for a two-dimensional 2x2 lattice would look like: - -:: - - pitch = 1.26 - lower_left = (-pitch, -pitch, -pitch) - upper_right = ( pitch, pitch, pitch) - uniform_dist = openmc.stats.Box(lower_left, upper_right) - settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) - -.. note:: - The random ray source is not related to the underlying particle flux or - source distribution of the simulation problem. It is akin to the selection - of an integration quadrature. Thus, in fixed source mode, the ray source - still needs to be provided and still needs to be uniform in space and angle - throughout the simulation domain. In fixed source mode, the user will - provide physical particle fixed sources in addition to the random ray - source. - --------------------------- -Quasi-Monte Carlo Sampling --------------------------- - -By default OpenMC will use a pseudorandom number generator (PRNG) to sample ray -starting locations from a uniform distribution in space and angle. -Alternatively, a randomized Halton sequence may be sampled from, which is a form -of Randomized Qusi-Monte Carlo (RQMC) sampling. RQMC sampling with random ray -has been shown to offer reduced variance as compared to regular PRNG sampling, -as the Halton sequence offers a more uniform distribution of sampled points. -Randomized Halton sampling can be enabled as:: - - settings.random_ray['sample_method'] = 'halton' - -Default behavior using OpenMC's native PRNG can be manually specified as:: - - settings.random_ray['sample_method'] = 'prng' - -.. _subdivision_fsr: - ------------------------------ -Subdivision of Source Regions ------------------------------ - -While the scattering and fission sources in Monte Carlo are treated -continuously, they are assumed to have a shape (flat or linear) within a MOC or -random ray source region (SR). This introduces bias into the simulation that can -be remedied by reducing the physical size of the SR to be smaller than the -typical mean free paths of particles. While use of linear sources in OpenMC -greatly reduces the error stemming from this approximation, subdivision is still -typically required. - -In OpenMC, this subdivision can be done either manually by the user (by defining -additional surfaces and cells in the geometry) or automatically by assigning a -mesh to one or more cells, universes, or material types. The level of -subdivision needed will be dependent on the fidelity the user requires. For -typical light water reactor analysis, consider the following example of manual -subdivision of a two-dimensional 2x2 reflective pincell lattice: - -.. figure:: ../_images/2x2_materials.jpeg - :class: with-border - :width: 400 - - Material definition for an asymmetrical 2x2 lattice (1.26 cm pitch) - -.. figure:: ../_images/2x2_fsrs.jpeg - :class: with-border - :width: 400 - - Manual decomposition for an asymmetrical 2x2 lattice (1.26 cm pitch) - -Geometry cells can also be subdivided into small source regions by assigning a -mesh to a list of domains, with each domain being of type -:class:`openmc.Material`, :class:`openmc.Cell`, or :class:`openmc.Universe`. The -idea of defining a source region as a combination of a base geometry cell and a -mesh element is known as "cell-under-voxel" style geometry, although in OpenMC -the mesh can be any kind and is not restricted to 3D regular voxels. An example -of overlaying a simple 2D mesh over a geometry is given as:: - - sr_mesh = openmc.RegularMesh() - sr_mesh.dimension = (n, n) - sr_mesh.lower_left = (0.0, 0.0) - sr_mesh.upper_right = (x, y) - domain = geometry.root_universe - settings.random_ray['source_region_meshes'] = [(sr_mesh, [domain])] - -In the above example, we apply a single :math:`n \times n` uniform mesh over the -entire domain by assigning it to the root universe of the geometry. -Alternatively, we might want to apply a finer or coarser mesh to different -regions of a 3D problem, for instance, as:: - - fuel = openmc.Material(name='UO2 fuel') - ... - water = openmc.Material(name='hot borated water') - ... - clad = openmc.Material(name='Zr cladding') - ... - - coarse_mesh = openmc.RegularMesh() - coarse_mesh.dimension = (n, n, n) - coarse_mesh.lower_left = (0.0, 0.0, 0.0) - coarse_mesh.upper_right = (x, y, z) - - fine_mesh = openmc.RegularMesh() - fine_mesh.dimension = (2*n, 2*n, 2*n) - fine_mesh.lower_left = (0.0, 0.0, 0.0) - fine_mesh.upper_right = (x, y, z) - - settings.random_ray['source_region_meshes'] = [(fine_mesh, [fuel, clad]), (coarse_mesh, [water])] - -Note that we don't need to adjust the outer bounds of the mesh to tightly wrap -the domain we assign the mesh to. Rather, OpenMC will dynamically generate -source regions based on the mesh bins rays actually visit, such that no -additional memory is wasted even if a domain only intersects a few mesh bins. -Going back to our 2x2 lattice example, if using a mesh-based subdivision, this -might look as below: - -.. figure:: ../_images/2x2_sr_mesh.png - :class: with-border - :width: 400 - - 20x20 overlaid "cell-under-voxel" mesh decomposition for an asymmetrical 2x2 lattice (1.26 cm pitch) - -Note that mesh-bashed subdivision is much easier for a user to implement but -does have a few downsides compared to manual subdivision. Manual subdivision can -be done with the specifics of the geometry in mind. As in the pincell example, -it is more efficient to subdivide the fuel region into azimuthal sectors and -radial rings as opposed to a Cartesian mesh. This is more efficient because the -regions are a more uniform size and follow the material boundaries closer, -resulting in the need for fewer source regions. Fewer source regions tends to -equate to a faster computational speed and/or the need for fewer rays per batch -to achieve good statistics. Additionally, applying a mesh often tends to create -a few very small source regions, as shown in the above picture where corners of -the mesh happen to intersect close to the actual fuel-moderator interface. These -small regions are rarely visited by rays, which can result in inaccurate -estimates of the source within those small regions and, thereby, numerical -instability. However, OpenMC utilizes several techniques to detect these small -source regions and mitigate instabilities that are associated with them. In -conclusion, mesh overlay is a great way to subdivide any geometry into smaller -source regions. It can be used while retaining stability, though typically at -the cost of generating more source regions relative to an optimal manual -subdivision. - -.. _usersguide_flux_norm: - -------- -Tallies -------- - -Most tallies, filters, and scores that you would expect to work with a -multigroup solver like random ray are supported. For example, you can define 3D -mesh tallies with energy filters and flux, fission, and nu-fission scores, etc. -There are some restrictions though. For starters, it is assumed that all filter -mesh boundaries will conform to physical surface boundaries (or lattice -boundaries) in the simulation geometry. It is acceptable for multiple cells -(FSRs) to be contained within a mesh element (e.g., pincell-level or -assembly-level tallies should work), but it is currently left as undefined -behavior if a single simulation cell is contained in multiple mesh elements. - -Supported scores: - - flux - - total - - fission - - nu-fission - - kappa-fission - - events - -Supported Estimators: - - tracklength - -Supported Filters: - - cell - - cell instance - - distribcell - - energy - - material - - mesh - - universe - -Note that there is no difference between the analog, tracklength, and collision -estimators in random ray mode as individual particles are not being simulated. -Tracklength-style tally estimation is inherent to the random ray method. - -As discussed in the random ray theory section on :ref:`Random Ray -Tallies`, by default flux tallies in the random ray mode -are not normalized by the spatial tally volumes such that flux tallies are in -units of cm. While the volume information is readily available as a byproduct of -random ray integration, the flux value is reported in unnormalized units of cm -so that the user will be able to compare "apples to apples" with the default -flux tallies from the Monte Carlo solver (also reported by default in units of -cm). If volume normalized flux tallies (in units of cm\ :sup:`-2`) are desired, -then the user can set the ``volume_normalized_flux_tallies`` field in the -:attr:`openmc.Settings.random_ray` dictionary to ``True``. An example is given -below: - -:: - - settings.random_ray['volume_normalized_flux_tallies'] = True - -Note that MC mode flux tallies can also be normalized by volume, as discussed in -the :ref:`Volume Calculation Section` of the user guide. - --------- -Plotting --------- - -Visualization of geometry is handled in the same way as normal with OpenMC (see -:ref:`plotting guide ` for more details). That is, ``openmc ---plot`` is handled without any modifications, as the random ray solver uses the -same geometry definition as in Monte Carlo. - -In addition to OpenMC's standard geometry plotting mode, the random ray solver -also features an additional method of data visualization. If a ``plots.xml`` -file is present, any voxel plots that are defined will be output at the end of a -random ray simulation. Rather than being stored in HDF5 file format, the random -ray plotting will generate ``.vtk`` files that can be directly read and plotted -with `Paraview `_. - -In fixed source Monte Carlo (MC) simulations, by default the only thing global -tally provided is the leakage fraction. In a k-eigenvalue MC simulation, by -default global tallies are collected for the eigenvalue and leakage fraction. -Spatial flux information must be manually requested, and often fine-grained -spatial meshes are considered costly/unnecessary, so it is impractical in MC -mode to plot spatial flux or power info by default. Conversely, in random ray, -the solver functions by estimating the multigroup source and flux spectrums in -every fine-grained FSR each iteration. Thus, for random ray, in both fixed -source and eigenvalue simulations, the simulation always finishes with a well -converged flux estimate for all areas. As such, it is much more common in random -ray, MOC, and other deterministic codes to provide spatial flux information by -default. In the future, all FSR data will be made available in the statepoint -file, which facilitates plotting and manipulation through the Python API; at -present, statepoint support is not available. - -Only voxel plots will be used to generate output; other plot types present in -the ``plots.xml`` file will be ignored. The following fields will be written to -the VTK structured grid file: - - - material - - FSR index - - flux spectrum (for each energy group) - - total fission source (integrated across all energy groups) - ------------------------------------------- -Inputting Multigroup Cross Sections (MGXS) ------------------------------------------- - -Multigroup cross sections for use with OpenMC's random ray solver are input the -same way as with OpenMC's traditional multigroup Monte Carlo mode. There is more -information on generating multigroup cross sections via OpenMC in the -:ref:`multigroup materials ` user guide. You may also wish to use -an existing ``mgxs.h5`` MGXS library file, or define your own given a known set -of cross section data values (e.g., as taken from a benchmark specification). An -example of using OpenMC's Python interface to generate a correctly formatted -``mgxs.h5`` input file is given in the `OpenMC Jupyter notebook collection -`_. - -.. note:: - Currently only isotropic and isothermal multigroup cross sections are - supported in random ray mode. To represent multiple material temperatures, - separate materials can be defined each with a separate multigroup dataset - corresponding to a given temperature. - -.. _mgxs_gen: - -------------------------------------------- -Generating Multigroup Cross Sections (MGXS) -------------------------------------------- - -OpenMC is capable of generating multigroup cross sections by way of flux -collapsing data based on flux solutions obtained from a continuous energy Monte -Carlo solve. While it is a circular excercise in some respects to use continuous -energy Monte Carlo to generate cross sections to be used by a reduced-fidelity -multigroup transport solver, there are many use cases where this is nonetheless -highly desirable. For instance, generation of a multigroup library may enable -the same set of approximate multigroup cross section data to be used across a -variety of problem types (or through a multidimensional parameter sweep of -design variables) with only modest errors and at greatly reduced cost as -compared to using only continuous energy Monte Carlo. - -~~~~~~~~~~~~ -The Easy Way -~~~~~~~~~~~~ - -The easiest way to generate a multigroup cross section library is to use the -:meth:`openmc.Model.convert_to_multigroup` method. This method will -automatically output a multigroup cross section library file (``mgxs.h5``) from -a continuous energy Monte Carlo model and alter the material definitions in the -model to use these multigroup cross sections. An example is given below:: - - # Assume we already have a working continuous energy model - model.convert_to_multigroup( - method="material_wise", - groups="CASMO-2", - nparticles=2000, - overwrite_mgxs_library=False, - mgxs_path="mgxs.h5", - correction=None, - source_energy=None, - temperatures=None, - temperature_settings=None - ) - -The most important parameter to set is the ``method`` parameter, which can be -either "stochastic_slab", "material_wise", or "infinite_medium". An overview -of these methods is given below: - -.. list-table:: Comparison of Automatic MGXS Generation Methods - :header-rows: 1 - :widths: 10 30 30 30 - - * - Method - - Description - - Pros - - Cons - * - ``material_wise`` (default) - - * Higher Fidelity - * Runs a CE simulation with the original geometry and source, tallying - cross sections with a material filter. - - * Typically the most accurate of the three methods - * Accurately captures (averaged over the full problem domain) - both spatial and resonance self shielding effects - - * Potentially slower as the full geometry must be run - * If a material is only present far from the source and doesn't get tallied - to in the CE simulation, the MGXS will be zero for that material. - * - ``stochastic_slab`` - - * Medium Fidelity - * Runs a CE simulation with a greatly simplified geometry, where materials - are randomly assigned to layers in a 1D "stochastic slab sandwich" geometry - - * Still captures resonant self shielding and resonance effects between materials - * Fast due to the simplified geometry - * Able to produce cross section data for all materials, regardless of how - far they are from the source in the original geometry - - * Does not capture most spatial self shielding effects, e.g., no lattice physics. - * - ``infinite_medium`` - - * Lower Fidelity - * Runs one CE simulation per material independently. Each simulation is just - an infinite medium slowing down problem, with an assumed external source term. - - * Simple - - * Poor accuracy (no spatial information, no lattice physics, no resonance effects - between materials) - * May hang if a material has a k-infinity greater than 1.0 - -When selecting a non-default energy group structure, you can manually define -group boundaries or specify the name of a known group structure (a list of which -can be found at :data:`openmc.mgxs.GROUP_STRUCTURES`). The ``nparticles`` -parameter can be adjusted upward to improve the fidelity of the generated cross -section library. The ``correction`` parameter can be set to ``"P0"`` to enable -P0 transport correction. The ``overwrite_mgxs_library`` parameter can be set to -``True`` to overwrite an existing MGXS library file, or ``False`` to skip -generation and use an existing library file. - -.. note:: - MGXS transport correction (via setting the ``correction`` parameter in the - :meth:`openmc.Model.convert_to_multigroup` method to ``"P0"``) may - result in negative in-group scattering cross sections, which can cause - numerical instability. To mitigate this, during a random ray solve OpenMC - will automatically apply - `diagonal stabilization `_ - with a :math:`\rho` default value of 1.0, which can be adjusted with the - ``settings.random_ray['diagonal_stabilization_rho']`` parameter. - -When generating MGXS data with either the ``stochastic_slab`` or -``infinite_medium`` methods, by default the simulation will use a uniform source -distribution spread evenly over all energy groups. This ensures that all energy -groups receive tallies and therefore produce non-zero total multigroup cross -sections. Additionally, the function will convert any sources in the model into -simplified spatial sources that retain the original energy distributions. If -sources are present, they will be used 99% of the time to sample source energies -during MGXS generation. The other 1% of the time, energies will be sampled -uniformly over all energy groups to ensure that all groups receive some tallies. -However, the user may wish to specify a different source energy spectrum (for -instance, if they are using a FileSource, such that the energy distribution -cannot be extracted from the python source object). This can be done by -providing a :class:`openmc.stats.Univariate` distribution as the -``source_energy`` parameter of the :meth:`openmc.Model.convert_to_multigroup` -method. If provided, it will override any sources present in the model and will -be used 99% of the time to sample source energies during MGXS generation. The -other 1% of the time, energies will be sampled uniformly over all energy groups -to ensure that all groups receive some tallies. - -For instance, a D-D fusion simulation may involve a complex file source. In this -case, the user may wish to provide a discrete 2.45 MeV energy source -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 -useful in that they can provide a good starting point for a random ray -simulation, and if more fidelity is needed the user may wish to follow the -instructions below or experiment with transport correction techniques to improve -the fidelity of the generated MGXS data. - -~~~~~~~~~~~~ -The Hard Way -~~~~~~~~~~~~ - -We give here a quick summary of how to produce a multigroup cross section data -file (``mgxs.h5``) from a starting point of a typical continuous energy Monte -Carlo model. Notably, continuous energy models define materials as a mixture of -nuclides with different densities, whereas multigroup materials are simply -defined by which name they correspond to in a ``mgxs.h5`` library file. - -To generate the cross section data, we begin with a continuous energy Monte -Carlo model and add in the tallies that are needed to generate our library. In -this example, we will specify material-wise cross sections and a two-group -energy decomposition:: - - # Define geometry - ... - geometry = openmc.Geometry() - ... - - # Initialize MGXS library with a finished OpenMC geometry object - mgxs_lib = openmc.mgxs.Library(geometry) - - # Pick energy group structure - groups = openmc.mgxs.EnergyGroups('CASMO-2') - mgxs_lib.energy_groups = groups - - # Disable transport correction - mgxs_lib.correction = None - - # Specify needed cross sections for random ray - mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', - 'nu-scatter matrix', 'multiplicity matrix', 'chi'] - - # Specify a "cell" domain type for the cross section tally filters - mgxs_lib.domain_type = "material" - - # Specify the cell domains over which to compute multi-group cross sections - mgxs_lib.domains = geometry.get_all_materials().values() - - # Do not compute cross sections on a nuclide-by-nuclide basis - mgxs_lib.by_nuclide = False - - # Check the library - if no errors are raised, then the library is satisfactory. - mgxs_lib.check_library_for_openmc_mgxs() - - # Construct all tallies needed for the multi-group cross section library - mgxs_lib.build_library() - - # Create a "tallies.xml" file for the MGXS Library - tallies = openmc.Tallies() - mgxs_lib.add_to_tallies(tallies, merge=True) - - # Export - tallies.export_to_xml() - - ... - -When selecting an energy decomposition, you can manually define group boundaries -or specify the name of known group structure (a list of which can be found at -:data:`openmc.mgxs.GROUP_STRUCTURES`). Once the above model has been run, the -resulting statepoint file will contain the needed flux and reaction rate tally -data so that a MGXS library file can be generated. Below is the postprocessing -script needed to generate the ``mgxs.h5`` library file given a statepoint file -(e.g., ``statepoint.100.h5``) file and summary file (e.g., ``summary.h5``) that -resulted from running our previous example:: - - import openmc - - summary = openmc.Summary('summary.h5') - geom = summary.geometry - mats = summary.materials - - groups = openmc.mgxs.EnergyGroups('CASMO-2') - mgxs_lib = openmc.mgxs.Library(geom) - mgxs_lib.energy_groups = groups - mgxs_lib.correction = None - mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', - 'nu-scatter matrix', 'multiplicity matrix', 'chi'] - - # Specify a "cell" domain type for the cross section tally filters - mgxs_lib.domain_type = "material" - - # Specify the cell domains over which to compute multi-group cross sections - mgxs_lib.domains = geom.get_all_materials().values() - - # Do not compute cross sections on a nuclide-by-nuclide basis - mgxs_lib.by_nuclide = False - - # Check the library - if no errors are raised, then the library is satisfactory. - mgxs_lib.check_library_for_openmc_mgxs() - - # Construct all tallies needed for the multi-group cross section library - mgxs_lib.build_library() - - with openmc.StatePoint('statepoint.100.h5') as sp: - mgxs_lib.load_from_statepoint(sp) - - names = [mat.name for mat in mgxs_lib.domains] - - # Create a MGXS File which can then be written to disk - mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names) - - # Write the file to disk using the default filename of "mgxs.h5" - mgxs_file.export_to_hdf5("mgxs.h5") - -Notably, the postprocessing script needs to match the same -:class:`openmc.mgxs.Library` settings that were used to generate the tallies but -is otherwise able to discern the rest of the simulation details from the -statepoint and summary files. Once the postprocessing script is successfully -run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC. - -If you want to convert continuous energy material objects in an OpenMC input -deck to multigroup ones from a ``mgxs.h5`` library, you can follow the below -example. Here we begin with the original continuous energy materials we used to -generate our MGXS library:: - - fuel = openmc.Material(name='UO2 (2.4%)') - fuel.set_density('g/cm3', 10.29769) - fuel.add_nuclide('U234', 4.4843e-6) - fuel.add_nuclide('U235', 5.5815e-4) - fuel.add_nuclide('U238', 2.2408e-2) - fuel.add_nuclide('O16', 4.5829e-2) - - water = openmc.Material(name='Hot borated water') - water.set_density('g/cm3', 0.740582) - water.add_nuclide('H1', 4.9457e-2) - water.add_nuclide('O16', 2.4672e-2) - water.add_nuclide('B10', 8.0042e-6) - water.add_nuclide('B11', 3.2218e-5) - water.add_s_alpha_beta('c_H_in_H2O') - - materials = openmc.Materials([fuel, water]) - -Once the ``mgxs.h5`` library file has been generated, we can then manually make -the necessary edits to the material definitions so that they load from the -multigroup library instead of defining their isotopic contents, as:: - - # Instantiate some Macroscopic Data - fuel_data = openmc.Macroscopic('UO2 (2.4%)') - water_data = openmc.Macroscopic('Hot borated water') - - # Instantiate some Materials and register the appropriate Macroscopic objects - fuel = openmc.Material(name='UO2 (2.4%)') - fuel.set_density('macro', 1.0) - fuel.add_macroscopic(fuel_data) - - water = openmc.Material(name='Hot borated water') - water.set_density('macro', 1.0) - water.add_macroscopic(water_data) - - # Instantiate a Materials collection and export to XML - materials = openmc.Materials([fuel, water]) - materials.cross_sections = "mgxs.h5" - -In the above example, our ``fuel`` and ``water`` materials will now load MGXS -data from the ``mgxs.h5`` file instead of loading continuous energy isotopic -cross section data. - --------------- -Linear Sources --------------- - -Linear Sources (LS), are supported with the eigenvalue and fixed source random -ray solvers. General 3D LS can be toggled by setting the ``source_shape`` field -in the :attr:`openmc.Settings.random_ray` dictionary to ``'linear'`` as:: - - settings.random_ray['source_shape'] = 'linear' - -LS enables the use of coarser mesh discretizations and lower ray populations, -offsetting the increased computation per ray. - -While OpenMC has no specific mode for 2D simulations, such simulations can be -performed implicitly by leaving one of the dimensions of the geometry unbounded -or by imposing reflective boundary conditions with no variation in between them -in that dimension. When 3D linear sources are used in a 2D random ray -simulation, the extremely long (or potentially infinite) spatial dimension along -one of the axes can cause the linear source to become noisy, leading to -potentially large increases in variance. To mitigate this, the user can force -the z-terms of the linear source to zero by setting the ``source_shape`` field -as:: - - settings.random_ray['source_shape'] = 'linear_xy' - -which will greatly improve the quality of the linear source term in 2D -simulations. - -.. _usersguide_random_ray_run_modes: - ---------------------------------- -Fixed Source and Eigenvalue Modes ---------------------------------- - -Both fixed source and eigenvalue modes are supported with the random ray solver -in OpenMC. Modes can be selected as described in the :ref:`run modes section -`. In both modes, a ray source must be provided to let -OpenMC know where to sample ray starting locations from, as discussed in the -:ref:`ray source section `. In fixed source mode, at -least one regular source must be provided as well that represents the physical -particle fixed source. As discussed in the :ref:`fixed source methodology -section `, the types of fixed sources supported -in the random ray solver mode are limited compared to what is possible with the -Monte Carlo solver. - -Currently, all of the following conditions must be met for the particle source -to be valid in random ray mode: - -- Either a point source must be used, or a domain constraint must be specified - that indicates which cells, universes, or materials the source applies to. In - either case, this implicitly limits the source type to being volumetric, as - even in the point source case the source will be "smeared" throughout the - source region that contains the point source coordinate. A source domain is - specified via the ``domains`` constraint placed on the - :class:`openmc.IndependentSource` Python class. -- The source must be isotropic (default for a source) -- The source must use a discrete (i.e., multigroup) energy distribution. The - discrete energy distribution is input by defining a - :class:`openmc.stats.Discrete` Python class, and passed as the ``energy`` - field of the :class:`openmc.IndependentSource` Python class. - -Any other spatial distribution information contained in a particle source will -be ignored. Only the specified cell, material, or universe domains will be used -to define the spatial location of the source, as the source will be applied -during a pre-processing stage of OpenMC to all source regions that are contained -within the specified domains for the source. - -When defining a :class:`openmc.stats.Discrete` object, note that the ``x`` field -will correspond to the discrete energy points, and the ``p`` field will -correspond to the discrete probabilities. It is recommended to select energy -points that fall within energy groups rather than on boundaries between the -groups. That is, if the problem contains two energy groups (with bin edges of -1.0e-5, 1.0e-1, 1.0e7), then a good selection for the ``x`` field might be -points of 1.0e-2 and 1.0e1. - -:: - - # Define geometry, etc. - ... - source_cell = openmc.Cell(fill=source_mat, name='cell where fixed source will be') - ... - # Define physical neutron fixed source - energy_points = [1.0e-2, 1.0e1] - strengths = [0.25, 0.75] - energy_distribution = openmc.stats.Discrete(x=energy_points, p=strengths) - neutron_source = openmc.IndependentSource( - energy=energy_distribution, - constraints={'domains': [source_cell]} - ) - - # Add fixed source and ray sampling source to settings file - settings.source = [neutron_source] - -.. _usersguide_vol_estimators: - ------------------------------ -Alternative Volume Estimators ------------------------------ - -As discussed in the random ray theory section on :ref:`volume estimators -`, there are several possible derivations for the scalar -flux estimate. These options deal with different ways of treating the -accumulation over ray lengths crossing each FSR (a quantity directly -proportional to volume), which can be computed using several methods. The -following methods are currently available in OpenMC: - -.. list-table:: Comparison of Estimators - :header-rows: 1 - :widths: 10 30 30 30 - - * - Estimator - - Description - - Pros - - Cons - * - ``simulation_averaged`` - - Accumulates total active ray lengths in each FSR over all iterations, - improving the estimate of the volume in each cell each iteration. - - * Virtually unbiased after several iterations - * Asymptotically approaches the true analytical volume - * Typically most efficient in terms of speed vs. accuracy - - * Higher variance - * Can lead to negative fluxes and numerical instability in pathological - cases - * - ``naive`` - - Treats the volume as composed only of the active ray length through each - FSR per iteration, being a biased but numerically consistent ratio - estimator. - - * Low variance - * Unlikely to result in negative fluxes - * Recommended in cases where the simulation averaged estimator is - unstable - - * Biased estimator - * Requires more rays or longer active ray length to mitigate bias - * - ``hybrid`` (default) - - Applies the naive estimator to all cells that contain an external (fixed) - source contribution. Applies the simulation averaged estimator to all - other cells. - - * High accuracy/low bias of the simulation averaged estimator in most - cells - * Stability of the naive estimator in cells with fixed sources - - * Can lead to slightly negative fluxes in cells where the simulation - averaged estimator is used - -These estimators can be selected by setting the ``volume_estimator`` field in the -:attr:`openmc.Settings.random_ray` dictionary. For example, to use the naive -estimator, the following code would be used: - -:: - - settings.random_ray['volume_estimator'] = 'naive' - ------------------ -Adjoint Flux Mode ------------------ - -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 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 -`. 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. When an initial forward solve is performed (i.e., when no -user-specified adjoint source is present), its output files are also written to -disk with a ``forward`` infix, so they are not overwritten by the subsequent -adjoint solve. This applies to the statepoint, ``tallies.out``, and any voxel -plots, e.g., ``statepoint.forward.N.h5`` and ``tallies.forward.out``; the -adjoint solve keeps the usual file names. This allows analyses requiring both -the forward and adjoint solutions to be performed from a single run. When -generating FW-CADIS weight windows, no weight window file is written for the -forward solve, as only the final adjoint-derived weight windows are meaningful. - -.. note:: - Use of the automated - :ref:`FW-CADIS weight window generator` 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 ---------------------------------------- - -~~~~~~~~~~~~~~~~~~ -Eigenvalue Example -~~~~~~~~~~~~~~~~~~ - -An example of a settings definition for an eigenvalue random ray simulation is -given below: - -:: - - # Geometry and MGXS material definition of 2x2 lattice (not shown) - pitch = 1.26 - group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] - ... - - # Instantiate a settings object for a random ray solve - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.batches = 1200 - settings.inactive = 600 - settings.particles = 2000 - - settings.random_ray['distance_inactive'] = 40.0 - settings.random_ray['distance_active'] = 400.0 - - # Create an initial uniform spatial source distribution for sampling rays - lower_left = (-pitch, -pitch, -pitch) - upper_right = ( pitch, pitch, pitch) - uniform_dist = openmc.stats.Box(lower_left, upper_right) - settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) - - settings.export_to_xml() - - # Define tallies - - # Create a mesh filter - mesh = openmc.RegularMesh() - mesh.dimension = (2, 2) - mesh.lower_left = (-pitch/2, -pitch/2) - mesh.upper_right = (pitch/2, pitch/2) - mesh_filter = openmc.MeshFilter(mesh) - - # Create a multigroup energy filter - energy_filter = openmc.EnergyFilter(group_edges) - - # Create tally using our two filters and add scores - tally = openmc.Tally() - tally.filters = [mesh_filter, energy_filter] - tally.scores = ['flux', 'fission', 'nu-fission'] - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([tally]) - tallies.export_to_xml() - - # Create voxel plot - plot = openmc.VoxelPlot() - plot.origin = [0, 0, 0] - plot.width = [2*pitch, 2*pitch, 1] - plot.pixels = [1000, 1000, 1] - - # Instantiate a Plots collection and export to XML - plots = openmc.Plots([plot]) - plots.export_to_xml() - -All other inputs (e.g., geometry, materials) will be unchanged from a typical -Monte Carlo run (see the :ref:`geometry ` and -:ref:`multigroup materials ` user guides for more information). - -There is also a complete example of a pincell available in the -``openmc/examples/pincell_random_ray`` folder. - -~~~~~~~~~~~~~~~~~~~~ -Fixed Source Example -~~~~~~~~~~~~~~~~~~~~ - -An example of a settings definition for a fixed source random ray simulation is -given below: - -:: - - # Geometry and MGXS material definition of 2x2 lattice (not shown) - pitch = 1.26 - source_cell = openmc.Cell(fill=source_mat, name='cell where fixed source will be') - ebins = [1e-5, 1e-1, 20.0e6] - ... - - # Instantiate a settings object for a random ray solve - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.batches = 1200 - settings.inactive = 600 - settings.particles = 2000 - settings.run_mode = 'fixed source' - settings.random_ray['distance_inactive'] = 40.0 - settings.random_ray['distance_active'] = 400.0 - - # Create an initial uniform spatial source distribution for sampling rays - lower_left = (-pitch, -pitch, -pitch) - upper_right = ( pitch, pitch, pitch) - uniform_dist = openmc.stats.Box(lower_left, upper_right) - settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) - - # Define physical neutron fixed source - energy_points = [1.0e-2, 1.0e1] - strengths = [0.25, 0.75] - energy_distribution = openmc.stats.Discrete(x=energy_points, p=strengths) - neutron_source = openmc.IndependentSource( - energy=energy_distribution, - constraints={'domains': [source_cell]} - ) - - # Add fixed source and ray sampling source to settings file - settings.source = [neutron_source] - - settings.export_to_xml() - - # Define tallies - - # Create a mesh filter - mesh = openmc.RegularMesh() - mesh.dimension = (2, 2) - mesh.lower_left = (-pitch/2, -pitch/2) - mesh.upper_right = (pitch/2, pitch/2) - mesh_filter = openmc.MeshFilter(mesh) - - # Create a multigroup energy filter - energy_filter = openmc.EnergyFilter(ebins) - - # Create tally using our two filters and add scores - tally = openmc.Tally() - tally.filters = [mesh_filter, energy_filter] - tally.scores = ['flux'] - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([tally]) - tallies.export_to_xml() - - # Create voxel plot - plot = openmc.VoxelPlot() - plot.origin = [0, 0, 0] - plot.width = [2*pitch, 2*pitch, 1] - plot.pixels = [1000, 1000, 1] - - # Instantiate a Plots collection and export to XML - plots = openmc.Plots([plot]) - plots.export_to_xml() - -All other inputs (e.g., geometry, material) will be unchanged from a typical -Monte Carlo run (see the :ref:`geometry ` and -:ref:`multigroup materials ` user guides for more information). diff --git a/docs/source/usersguide/scripts.rst b/docs/source/usersguide/scripts.rst index eb0abeb0d..f2ba81605 100644 --- a/docs/source/usersguide/scripts.rst +++ b/docs/source/usersguide/scripts.rst @@ -48,9 +48,175 @@ flags: restart file -s, --threads N Run with *N* OpenMP threads -t, --track Write tracks for all particles (up to max_tracks) --q, --verbosity V Set the output verbosity to *V* -v, --version Show version information -h, --help Show help message .. note:: If you're using the Python API, :func:`openmc.run` is equivalent to running ``openmc`` from the command line. + +.. _scripts_ace: + +---------------------- +``openmc-ace-to-hdf5`` +---------------------- + +This script can be used to create HDF5 nuclear data libraries used by OpenMC if +you have existing ACE files. There are four different ways you can specify ACE +libraries that are to be converted: + +1. List each ACE library as a positional argument. This is very useful in + conjunction with the usual shell utilities (``ls``, ``find``, etc.). +2. Use the ``--xml`` option to specify a pre-v0.9 cross_sections.xml file. +3. Use the ``--xsdir`` option to specify a MCNP xsdir file. +4. Use the ``--xsdata`` option to specify a Serpent xsdata file. + +The script does not use any extra information from cross_sections.xml/ xsdir/ +xsdata files to determine whether the nuclide is metastable. Instead, the +``--metastable`` argument can be used to specify whether the ZAID naming convention +follows the NNDC data convention (1000*Z + A + 300 + 100*m), or the MCNP data +convention (essentially the same as NNDC, except that the first metastable state +of Am242 is 95242 and the ground state is 95642). + +The optional ``--fission_energy_release`` argument will accept an HDF5 file +containing a library of fission energy release (ENDF MF=1 MT=458) data. A +library built from ENDF/B-VII.1 data is released with OpenMC and can be found at +openmc/data/fission_Q_data_endb71.h5. This data is necessary for +'fission-q-prompt' and 'fission-q-recoverable' tallies, but is not needed +otherwise. + +-h, --help show help message and exit + +-d DESTINATION, --destination DESTINATION + Directory to create new library in + +-m META, --metastable META + How to interpret ZAIDs for metastable nuclides. META + can be either 'nndc' or 'mcnp'. (default: nndc) + +--xml XML Old-style cross_sections.xml that lists ACE libraries + +--xsdir XSDIR MCNP xsdir file that lists ACE libraries + +--xsdata XSDATA Serpent xsdata file that lists ACE libraries + +--fission_energy_release FISSION_ENERGY_RELEASE + HDF5 file containing fission energy release data + +.. _scripts_plot: + +-------------------------- +``openmc-plot-mesh-tally`` +-------------------------- + +``openmc-plot-mesh-tally`` provides a graphical user interface for plotting mesh +tallies. The path to the statepoint file can be provided as an optional arugment +(if omitted, a file dialog will be presented). + +.. _scripts_track_combine: + +------------------------ +``openmc-track-combine`` +------------------------ + +This script combines multiple HDF5 :ref:`particle track files +` into a single HDF5 particle track file. The filenames of the +particle track files should be given as posititional arguments. The output +filename can also be changed with the ``-o`` flag: + +-o OUT, --out OUT Output HDF5 particle track file + +.. _scripts_track: + +----------------------- +``openmc-track-to-vtk`` +----------------------- + +This script converts HDF5 :ref:`particle track files ` to VTK +poly data that can be viewed with ParaView or VisIt. The filenames of the +particle track files should be given as posititional arguments. The output +filename can also be changed with the ``-o`` flag: + +-o OUT, --out OUT Output VTK poly filename + +------------------------ +``openmc-update-inputs`` +------------------------ + +If you have existing XML files that worked in a previous version of OpenMC that +no longer work with the current version, you can try to update these files using +``openmc-update-inputs``. If any of the given files do not match the most +up-to-date formatting, then they will be automatically rewritten. The old +out-of-date files will not be deleted; they will be moved to a new file with +'.original' appended to their name. + +Formatting changes that will be made: + +geometry.xml + Lattices containing 'outside' attributes/tags will be replaced with lattices + containing 'outer' attributes, and the appropriate cells/universes will be + added. Any 'surfaces' attributes/elements on a cell will be renamed 'region'. + +materials.xml + Nuclide names will be changed from ACE aliases (e.g., Am-242m) to HDF5/GND + names (e.g., Am242_m1). Thermal scattering table names will be changed from + ACE aliases (e.g., HH2O) to HDF5/GND names (e.g., c_H_in_H2O). + +---------------------- +``openmc-update-mgxs`` +---------------------- + +This script updates OpenMC's deprecated multi-group cross section XML files to +the latest HDF5-based format. + +-i IN, --input IN Input XML file +-o OUT, --output OUT Output file in HDF5 format + +.. _scripts_validate: + +----------------------- +``openmc-validate-xml`` +----------------------- + +Input files can be checked before executing OpenMC using the +``openmc-validate-xml`` script which is installed alongside the Python API. Two +command line arguments can be set when running ``openmc-validate-xml``: + +-i, --input-path Location of OpenMC input files. +-r, --relaxng-path Location of OpenMC RelaxNG files + +If the RelaxNG path is not set, the script will search for these files because +it expects that the user is either running the script located in the install +directory ``bin`` folder or in ``src/utils``. Once executed, it will match +OpenMC XML files with their RelaxNG schema and check if they are valid. Below +is a table of the messages that will be printed after each file is checked. + +======================== =================================== +Message Description +======================== =================================== +[XML ERROR] Cannot parse XML file. +[NO RELAXNG FOUND] No RelaxNG file found for XML file. +[NOT VALID] XML file does not match RelaxNG. +[VALID] XML file matches RelaxNG. +======================== =================================== + +.. _scripts_voxel: + +--------------------------- +``openmc-voxel-to-vtk`` +--------------------------- + +When OpenMC generates :ref:`voxel plots `, they are in an +:ref:`HDF5 format ` that is not terribly useful by itself. The +``openmc-voxel-to-vtk`` script converts a voxel HDF5 file to a `VTK +`_ file. To run this script, you will need to have the VTK +Python bindings installed. To convert a voxel file, simply provide the path to +the file: + +.. code-block:: sh + + openmc-voxel-to-vtk voxel_1.h5 + +The ``openmc-voxel-to-vtk`` script also takes the following optional +command-line arguments: + +-o, --output Path to output VTK file diff --git a/docs/source/usersguide/settings.rst b/docs/source/usersguide/settings.rst index 6faeb59e1..336982ac6 100644 --- a/docs/source/usersguide/settings.rst +++ b/docs/source/usersguide/settings.rst @@ -169,20 +169,16 @@ External Source Distributions External source distributions can be specified through the :attr:`Settings.source` attribute. If you have a single external source, you can -create an instance of any of the subclasses of :class:`openmc.SourceBase` -(:class:`openmc.IndependentSource`, :class:`openmc.FileSource`, -:class:`openmc.CompiledSource`) and use it to set the :attr:`Settings.source` -attribute. If you have multiple external sources with varying source strengths, -:attr:`Settings.source` should be set to a list of :class:`openmc.SourceBase` -objects. - -The :class:`openmc.IndependentSource` class is the primary class for defining -source distributions and has four main attributes that one can set: -:attr:`IndependentSource.space`, which defines the spatial distribution, -:attr:`IndependentSource.angle`, which defines the angular distribution, -:attr:`IndependentSource.energy`, which defines the energy distribution, and -:attr:`IndependentSource.time`, which defines the time distribution. +create an instance of :class:`openmc.Source` and use it to set the +:attr:`Settings.source` attribute. If you have multiple external sources with +varying source strengths, :attr:`Settings.source` should be set to a list of +:class:`openmc.Source` objects. +The :class:`openmc.Source` class has four main attributes that one can set: +:attr:`Source.space`, which defines the spatial distribution, +:attr:`Source.angle`, which defines the angular distribution, +:attr:`Source.energy`, which defines the energy distribution, and +:attr:`Source.time`, which defines the time distribution. The spatial distribution can be set equal to a sub-class of :class:`openmc.stats.Spatial`; common choices are :class:`openmc.stats.Point` or @@ -191,11 +187,7 @@ The spatial distribution can be set equal to a sub-class of :class:`openmc.stats.CartesianIndependent`. To independently specify distributions using spherical or cylindrical coordinates, you can use :class:`openmc.stats.SphericalIndependent` or -:class:`openmc.stats.CylindricalIndependent`, respectively. Meshes can also be -used to represent spatial distributions with :class:`openmc.stats.MeshSpatial` -by specifying a mesh and source strengths for each mesh element. It is also -possible to define a "cloud" of source points, each with a different relative -probability, using :class:`openmc.stats.PointCloud`. +:class:`openmc.stats.CylindricalIndependent`, respectively. The angular distribution can be set equal to a sub-class of :class:`openmc.stats.UnitSphere` such as :class:`openmc.stats.Isotropic`, @@ -226,63 +218,38 @@ distribution. This could be a probability mass function (:class:`openmc.stats.Tabular`). By default, if no time distribution is specified, particles are started at :math:`t=0`. - As an example, to create an isotropic, 10 MeV monoenergetic source uniformly distributed over a cube centered at the origin with an edge length of 10 cm, and emitting a pulse of particles from 0 to 10 µs, one would run:: - source = openmc.IndependentSource() + source = openmc.Source() source.space = openmc.stats.Box((-5, -5, -5), (5, 5, 5)) source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([10.0e6], [1.0]) source.time = openmc.stats.Uniform(0, 1e-6) settings.source = source -All subclasses of :class:`openmc.SourceBase` have a :attr:`SourceBase.strength` -attribute that indicates the relative strength of a source distribution if -multiple are used. For example, to create two sources, one that should be -sampled 70% of the time and another that should be sampled 30% of the time:: +The :class:`openmc.Source` class also has a :attr:`Source.strength` attribute +that indicates the relative strength of a source distribution if multiple are +used. For example, to create two sources, one that should be sampled 70% of the +time and another that should be sampled 30% of the time:: - src1 = openmc.IndependentSource() + src1 = openmc.Source() src1.strength = 0.7 ... - src2 = openmc.IndependentSource() + src2 = openmc.Source() src2.strength = 0.3 ... settings.source = [src1, src2] -When the relative strengths are several orders of magnitude different, it may -happen that not enough statistics are obtained from the lower strength source. -This can be improved by sampling among the sources with equal probability, -applying the source strength as a weight on the sampled source particles. The -:attr:`Settings.uniform_source_sampling` attribute can be used to enable this -option:: +Finally, the :attr:`Source.particle` attribute can be used to indicate the +source should be composed of particles other than neutrons. For example, the +following would generate a photon source:: - src1 = openmc.IndependentSource() - src1.strength = 100.0 - ... - - src2 = openmc.IndependentSource() - src2.strength = 1.0 - ... - - settings.source = [src1, src2] - settings.uniform_source_sampling = True - -Additionally, sampling from an :class:`openmc.IndependentSource` may be biased -for local or global variance reduction by modifying the -:attr:`~openmc.IndependentSource.bias` attribute of each of its four main -distributions. Further discussion of source biasing can be found in -:ref:`source_biasing`. - -Finally, the :attr:`IndependentSource.particle` attribute can be used to -indicate the source should be composed of particles other than neutrons. For -example, the following would generate a photon source:: - - source = openmc.IndependentSource() + source = openmc.Source() source.particle = 'photon' ... @@ -291,60 +258,13 @@ example, the following would generate a photon source:: For a full list of all classes related to statistical distributions, see :ref:`pythonapi_stats`. -Tokamak Plasma Sources ----------------------- - -For fusion applications, the :class:`openmc.TokamakSource` class provides a -native parametric neutron source for tokamak plasmas. Rather than specifying -spatial, angular, and energy distributions separately, the source is defined by -the plasma geometry (using a `Miller-style flux-surface parameterization -`_) and a radial emission profile. Source -sites are sampled directly from the plasma volume without rejection. - -The plasma shape is described by the major radius :math:`R_0`, minor radius -:math:`a`, elongation :math:`\kappa`, triangularity :math:`\delta`, and -Shafranov shift :math:`\Delta`. The neutron birth profile is given as an -emission density :math:`S(r/a)` tabulated on a normalized minor-radius grid that -runs from 0 (magnetic axis) to 1 (last closed flux surface); only the shape of -the profile matters, since it is normalized internally. The emission density is -linearly interpolated between the supplied points and refined internally for -radial sampling. For example:: - - import numpy as np - - r_over_a = np.linspace(0.0, 1.0, 50) - emission = (1.0 - r_over_a**2)**2 # peaked on-axis profile - - source = openmc.TokamakSource( - major_radius=620.0, # cm - minor_radius=200.0, # cm - elongation=1.8, - triangularity=0.45, - shafranov_shift=10.0, # cm - r_over_a=r_over_a, - emission_density=emission, - energy=openmc.stats.muir(e0=14.08e6, m_rat=5.0, kt=20000.0), - ) - - settings.source = source - -The ``energy`` argument accepts either a single -:class:`~openmc.stats.Univariate` distribution applied at all radii, or a -sequence with one distribution per ``r_over_a`` grid point to model a -radially-varying neutron spectrum (energies are then sampled by stochastic -interpolation between the two distributions bracketing the sampled radius). A -time distribution can be given with the ``time`` argument; by default, particles -are born at :math:`t=0`. The toroidal extent can be restricted with -``phi_start`` and ``phi_extent`` to model a sector of the plasma, and -``vertical_shift`` translates the plasma center along the z-axis. - File-based Sources ------------------ -OpenMC can use a pregenerated HDF5 source file through the -:class:`openmc.FileSource` class:: +OpenMC can use a pregenerated HDF5 source file by specifying the ``filename`` +argument to :class:`openmc.Source`:: - settings.source = openmc.FileSource('source.h5') + settings.source = openmc.Source(filename='source.h5') Statepoint and source files are generated automatically when a simulation is run and can be used as the starting source in a new simulation. Alternatively, a @@ -352,9 +272,6 @@ source file can be manually generated with the :func:`openmc.write_source_file` function. This is particularly useful for coupling OpenMC with another program that generates a source to be used in OpenMC. -Surface Sources -+++++++++++++++ - A source file based on particles that cross one or more surfaces can be generated during a simulation using the :attr:`Settings.surf_source_write` attribute:: @@ -365,67 +282,12 @@ attribute:: } In this example, at most 10,000 source particles are stored when particles cross -surfaces with IDs of 1, 2, or 3. If no surface IDs are declared, particles -crossing any surface of the model will be banked:: +surfaces with IDs of 1, 2, or 3. - settings.surf_source_write = {'max_particles': 10000} +.. _custom_source: -A cell ID can also be used to bank particles that are crossing any surface of -a cell that particles are either coming from or going to:: - - settings.surf_source_write = {'cell': 1, 'max_particles': 10000} - -In this example, particles that are crossing any surface that bounds cell 1 will -be banked excluding any surface that does not use a 'transmission' or 'vacuum' -boundary condition. - -.. note:: Surfaces with boundary conditions that are not "transmission" or "vacuum" - are not eligible to store any particles when using ``cell``, ``cellfrom`` - or ``cellto`` attributes. It is recommended to use surface IDs instead. - -Surface IDs can be used in combination with a cell ID:: - - settings.surf_source_write = { - 'cell': 1, - 'surfaces_ids': [1, 2, 3], - 'max_particles': 10000 - } - -In that case, only particles that are crossing the declared surfaces coming from -cell 1 or going to cell 1 will be banked. To account specifically for particles -leaving or entering a given cell, ``cellfrom`` and ``cellto`` are also available -to respectively account for particles coming from a cell:: - - settings.surf_source_write = { - 'cellfrom': 1, - 'max_particles': 10000 - } - -or particles going to a cell:: - - settings.surf_source_write = { - 'cellto': 1, - 'max_particles': 10000 - } - -.. note:: The ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be - used simultaneously. - -To generate more than one surface source files when the maximum number of stored -particles is reached, ``max_source_files`` is available. The surface source bank -will be cleared in simulation memory each time a surface source file is written. -As an example, to write a maximum of three surface source files::: - - settings.surf_source_write = { - 'surfaces_ids': [1, 2, 3], - 'max_particles': 10000, - 'max_source_files': 3 - } - -.. _compiled_source: - -Compiled Sources ----------------- +Custom Sources +-------------- It is often the case that one may wish to simulate a complex source distribution that is not possible to represent with the classes described above. For these @@ -441,13 +303,13 @@ below. #include "openmc/source.h" #include "openmc/particle.h" - class CompiledSource : public openmc::Source + class CustomSource : public openmc::Source { openmc::SourceSite sample(uint64_t* seed) const { 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); @@ -463,9 +325,9 @@ below. } }; - extern "C" std::unique_ptr openmc_create_source(std::string parameters) + extern "C" std::unique_ptr openmc_create_source(std::string parameters) { - return std::make_unique(); + return std::make_unique(); } The above source creates monodirectional 14.08 MeV neutrons that are distributed @@ -492,21 +354,19 @@ OpenMC shared library. This can be done by writing a CMakeLists.txt file: target_link_libraries(source OpenMC::libopenmc) After running ``cmake`` and ``make``, you will have a libsource.so (or .dylib) -file in your build directory. You can then use this as an external source during -an OpenMC run by passing the path of the shared library to the -:class:`openmc.CompiledSource` class, which is then set as the -:attr:`Settings.source` attribute:: +file in your build directory. Setting the :attr:`openmc.Source.library` +attribute to the path of this shared library will indicate that it should be +used for sampling source particles at runtime. - settings.source = openmc.CompiledSource('libsource.so') +.. _parameterized_custom_source: -.. _parameterized_compiled_source: +Custom Parameterized Sources +---------------------------- -Parameterized Compiled Sources ------------------------------- - -Some compiled sources may have values (parameters) that can be changed between -runs. This is supported by using the ``openmc_create_source()`` function to pass -parameters to the source class when it is created: +Some custom sources may have values (parameters) that can be changed between +runs. This is supported by using the ``openmc_create_source()`` function to +pass parameters defined in the :attr:`openmc.Source.parameters` attribute to +the source class when it is created: .. code-block:: c++ @@ -515,16 +375,16 @@ parameters to the source class when it is created: #include "openmc/source.h" #include "openmc/particle.h" - class CompiledSource : public openmc::Source { + class CustomSource : public openmc::Source { public: - CompiledSource(double energy) : energy_{energy} { } + CustomSource(double energy) : energy_{energy} { } // Samples from an instance of this class. openmc::SourceSite sample(uint64_t* seed) const { openmc::SourceSite particle; // weight - particle.particle = openmc::ParticleType::neutron(); + particle.particle = openmc::ParticleType::neutron; particle.wgt = 1.0; // position particle.r.x = 0.0; @@ -542,64 +402,13 @@ parameters to the source class when it is created: double energy_; }; - extern "C" std::unique_ptr openmc_create_source(std::string parameter) { + extern "C" std::unique_ptr openmc_create_source(std::string parameter) { double energy = std::stod(parameter); - return std::make_unique(energy); + return std::make_unique(energy); } -When creating an instance of the :class:`openmc.CompiledSource` class, you will -need to pass both the path of the shared library as well as the parameters as a -string, which gets passed down to the ``openmc_create_source()`` function:: - - settings.source = openmc.CompiledSource('libsource.so', '3.5e6') - -.. _usersguide_source_constraints: - -Source Constraints ------------------- - -All source classes in OpenMC have the ability to apply a set of "constraints" -that limit which sampled source sites are actually used for transport. The most -common use case is to sample source sites over some simple spatial distribution -(e.g., uniform over a box) and then only accept those that appear in a given -cell or material. This can be done with a domain constraint, which can be -specified as follows:: - - source_cell = openmc.Cell(...) - ... - - spatial_dist = openmc.stats.Box((-10., -10., -10.), (10., 10., 10.)) - source = openmc.IndependentSource( - space=spatial_dist, - constraints={'domains': [source_cell]} - ) - -For k-eigenvalue problems, a convenient constraint is available that limits -source sites to those sampled in a fissionable material:: - - source = openmc.IndependentSource( - space=spatial_dist, constraints={'fissionable': True} - ) - -Constraints can also be placed on a range of energies or times:: - - # Only use source sites between 500 keV and 1 MeV and with times under 1 sec - source = openmc.FileSource( - 'source.h5', - constraints={'energy_bounds': [500.0e3, 1.0e6], 'time_bounds': [0.0, 1.0]} - ) - -Normally, when a source site is rejected, a new one will be resampled until one -is found that meets the constraints. However, the rejection strategy can be -changed so that a rejected site will just not be simulated by specifying:: - - source = openmc.IndependentSource( - space=spatial_dist, - constraints={'domains': [cell], 'rejection_strategy': 'kill'} - ) - -In this case, the actual number of particles simulated may be less than what you -specified in :attr:`Settings.particles`. +As with the basic custom source functionality, the custom source library +location must be provided in the :attr:`openmc.Source.library` attribute. .. _usersguide_entropy: @@ -651,13 +460,6 @@ 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) approximation is used to generate @@ -672,6 +474,7 @@ selected:: Some features related to photon transport are not currently implemented, including: + * Tallying photon energy deposition. * Generating a photon source from a neutron calculation that can be used for a later fixed source photon calculation. * Photoneutron reactions. @@ -811,102 +614,8 @@ instance, whereas the :meth:`openmc.Track.filter` method returns a new with more than one process, a separate track file will be written for each MPI process with the filename ``tracks_p#.h5`` where # is the rank of the corresponding process. Multiple track files can be - combined with the :meth:`openmc.Tracks.combine` method:: + combined with the :ref:`scripts_track_combine` script: - track_files = [f"tracks_p{rank}.h5" for rank in range(32)] - openmc.Tracks.combine(track_files, "tracks.h5") + .. code-block:: sh -Collision Track File ---------------------- - -OpenMC can generate a collision track file that contains detailed collision -information (position, direction, energy, deposited energy, time, weight, cell -ID, material ID, universe ID, nuclide ZAID, particle type, particle delayed -group and particle ID) for each particle collision depending on user-defined -parameters. To invoke this feature, set the -:attr:`~openmc.Settings.collision_track` attribute as shown in this example:: - - settings.collision_track = { - "max_collisions": 300, - "reactions": ["(n,fission)", "(n,2n)"], - "material_ids": [1,2], - "nuclides": ["U238", "O16"], - "cell_ids": [5, 12] - } - -In this example, collision track information is written to the -collision_track.h5 file at the end of the simulation. The file contains -300 recorded collisions that occurred in materials with IDs 1 or 2, involving -fission or (n,2n) reactions on the nuclides U-238 or O-16, within cells -with IDs 5 and 12. - -.. note:: - Electron and positron collision-track events are not associated with a - specific nuclide. If a ``nuclides`` entry is specified, these events are omitted. - -The file can be read using :func:`openmc.read_collision_track_file`. -The example below shows how to extract the data from the collision_track -feature and displays the fields stored in the file: - ->>> data = openmc.read_collision_track_file('collision_track.h5') ->>> data.dtype - dtype([('r', [('x', '`) is satisfied. Note that if the number of batches in the -statepoint file is the same as that specified in the settings object (i.e., if -the inputs were not modified before the restart run), no particles will be -transported and OpenMC will exit immediately. - -.. note:: A statepoint file must match the input model to be successfully used in a restart simulation. + openmc-track-combine tracks_p*.h5 --out tracks.h5 diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 20a89cea7..da2c5f26d 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -105,124 +105,109 @@ 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,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. | - +------------------------+-------------------------------------------------+ + +----------------------+---------------------------------------------------+ + |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. | + +----------------------+---------------------------------------------------+ .. table:: **Particle production scores: units are particles produced per source particles.** @@ -261,21 +246,18 @@ The following tables show all valid scores: +----------------------+---------------------------------------------------+ |Score | Description | +======================+===================================================+ - |current |It may not be used in conjunction with any other | - | |score except flux. | - | | | - | |When used in combination with a meshsurface filter:| + |current |Used in combination with a meshsurface filter: | | |Partial currents on the boundaries of each cell in | - | |a mesh. | - | | | - | |When used in combination with a surface filter: | + | |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: | | |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 | @@ -287,8 +269,9 @@ The following tables show all valid scores: |heating |Total nuclear heating in units of eV per source | | |particle. For neutrons, this corresponds to MT=301 | | |produced by NJOY's HEATR module while for photons, | - | |this is tallied from direct photon energy | - | |deposition. See :ref:`methods_heating`. | + | |this is tallied from either direct photon energy | + | |deposition (analog estimator) or pre-generated | + | |photon heating number. See :ref:`methods_heating` | +----------------------+---------------------------------------------------+ |heating-local |Total nuclear heating in units of eV per source | | |particle assuming energy from secondary photons is | @@ -335,29 +318,6 @@ The following tables show all valid scores: | |particle. This corresponds to MT=444 produced by | | |NJOY's HEATR module. | +----------------------+---------------------------------------------------+ - |pulse-height |The energy deposited by an entire photon's history | - | |(including its progeny). Units are eV per source | - | |particle. Note that this score can only be combined| - | |with a cell filter and an energy filter. | - +----------------------+---------------------------------------------------+ - |ifp-time-numerator |Adjoint-weighted lifetime of neutron produced by | - | |fission in units of seconds per source particle. | - | |This score is used to compute kinetics parameters | - | |using the iterated fission probability (IFP) | - | |method. | - +----------------------+---------------------------------------------------+ - |ifp-beta-numerator |Adjoint-weighted number of delayed fission events | - | |in units of number of delayed fission event per | - | |source particle. This score is used to compute | - | |kinetics parameters using the iterated fission | - | |probability (IFP) method. | - +----------------------+---------------------------------------------------+ - |ifp-denominator |Weights corresponding to the number of fission | - | |events in units of number of fission event per | - | |source particle. This score is used to compute | - | |kinetics parameters using the iterated fission | - | |probability (IFP) method. | - +----------------------+---------------------------------------------------+ .. _usersguide_tally_normalization: @@ -373,7 +333,7 @@ it is usually straightforward to convert units if the source rate is known. For example, if the system being modeled includes a source that is emitting 10\ :sup:`4` neutrons per second, the tally results just need to be multipled by 10\ :sup:`4`. This can either be done manually or using the -:attr:`openmc.SourceBase.strength` attribute. +:attr:`openmc.Source.strength` attribute. For a :math:`k`\ -eigenvalue calculation, normalizing tally results is not as simple because the source rate is not actually known. Instead, we typically know diff --git a/docs/source/usersguide/troubleshoot.rst b/docs/source/usersguide/troubleshoot.rst index f86ed7274..b1cd80f3e 100644 --- a/docs/source/usersguide/troubleshoot.rst +++ b/docs/source/usersguide/troubleshoot.rst @@ -28,7 +28,7 @@ commands: .. code-block:: sh mkdir build-debug && cd build-debug - cmake -DCMAKE_BUILD_TYPE=Debug /path/to/openmc + cmake -Ddebug=on /path/to/openmc make Now when you re-run your problem, it should report exactly where the program diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst deleted file mode 100644 index d551195f5..000000000 --- a/docs/source/usersguide/variance_reduction.rst +++ /dev/null @@ -1,373 +0,0 @@ -.. _variance_reduction: - -================== -Variance Reduction -================== - -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 Global Weight Windows with MAGIC -------------------------------------------- - -As discussed in the :ref:`methods section `, MAGIC -is an iterative method that uses flux tally information from a Monte Carlo -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` -instance, as follows:: - - # Define weight window spatial mesh - ww_mesh = openmc.RegularMesh() - ww_mesh.dimension = (10, 10, 10) - ww_mesh.lower_left = (0.0, 0.0, 0.0) - ww_mesh.upper_right = (100.0, 100.0, 100.0) - - # Create weight window object and adjust parameters - wwg = openmc.WeightWindowGenerator( - method='magic', - mesh=ww_mesh, - max_realizations=settings.batches - ) - - # Add generator to Settings instance - settings.weight_window_generators = wwg - -Notably, the :attr:`max_realizations` attribute is adjusted to the number of -batches, such that all iterations are used to refine the weight window -parameters. - -With the :class:`~openmc.WeightWindowGenerator` instance added to the -:attr:`~openmc.Settings`, the rest of the problem can be defined as normal. When -running, note that the second iteration and beyond may be several orders of -magnitude slower than the first. As the weight windows are applied in each -iteration, particles may be aggressively split, resulting in a large number of -secondary (split) particles being generated per initial source particle. This is -not necessarily a bad thing, as the split particles are much more efficient at -exploring low flux regions of phase space as compared to initial particles. -Thus, even though the reported "particles/second" metric of OpenMC may be much -lower when generating (or just applying) weight windows as compared to analog -MC, it typically leads to an overall improvement in the figure of merit -accounting for the reduction in the variance. - -.. warning:: - The number of particles per batch may need to be adjusted downward - significantly to result in reasonable runtimes when weight windows are being - generated or used. - -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. - -.. _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. 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 `. - -.. note:: - It is a long term goal for OpenMC to be able to generate FW-CADIS weight - windows with only a few tweaks to an existing continuous energy Monte Carlo - input deck. However, at the present time, the workflow requires several - steps to generate multigroup cross section data and to configure the random - 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 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 `, summarized below:: - - # Define continuous energy model - ce_model = openmc.pwr_pin_cell() # example, replace with your model - - # Make a copy to convert to multigroup and random ray - model = copy.deepcopy(ce_model) - - # Convert model to multigroup (will auto-generate MGXS library if needed) - model.convert_to_multigroup() - - # Convert model to random ray and initialize random ray parameters - # to reasonable defaults based on the specifics of the geometry - model.convert_to_random_ray() - - # (Optional) Overlay source region decomposition mesh to improve fidelity of the - # random ray solver. Adjust 'n' for fidelity vs runtime. - n = 10 - mesh = openmc.RegularMesh() - mesh.dimension = (n, n, n) - mesh.lower_left = model.geometry.bounding_box.lower_left - mesh.upper_right = model.geometry.bounding_box.upper_right - model.settings.random_ray['source_region_meshes'] = [(mesh, [model.geometry.root_universe])] - - # (Optional) Improve fidelity of the random ray solver by enabling linear sources - model.settings.random_ray['source_shape'] = 'linear' - - # (Optional) Increase the number of rays/batch, to reduce uncertainty - model.settings.particles = 500 - - If you need to improve the fidelity of the MGXS library, there is more - information on generating multigroup cross sections via OpenMC in the - :ref:`random ray MGXS guide `. - -2. Add in a :class:`~openmc.WeightWindowGenerator` in a similar manner as for - MAGIC generation with Monte Carlo and set the :attr:`method` attribute set to - ``"fw_cadis"``:: - - # Create weight window object and adjust parameters, using the same mesh - # we used for source region decomposition - wwg = openmc.WeightWindowGenerator( - method='fw_cadis', - mesh=mesh - ) - - # Add generator to openmc.settings object - settings.weight_window_generators = wwg - -.. warning:: - If using FW-CADIS weight window generation, ensure that the selected weight - window mesh does not subdivide any source regions in the problem. This can - be ensured by using the same mesh for both source region subdivision (i.e., - assigning to ``model.settings.random_ray['source_region_meshes']``) and for - weight window generation. - -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 - identical manner as one generated with MAGIC, as described below. - --------------------- -Using Weight Windows --------------------- - -To use a ``weight_windows.h5`` weight window file with OpenMC's Monte Carlo -solver, the Python input just needs to load the h5 file:: - - settings.weight_window_checkpoints = {'collision': True, 'surface': True} - settings.survival_biasing = False - settings.weight_windows_file = "weight_windows.h5" - settings.weight_windows_on = True - -The :class:`~openmc.WeightWindowGenerator` instance is not needed to load an -existing ``weight_windows.h5`` file. Inclusion of a -:class:`~openmc.WeightWindowGenerator` instance will cause OpenMC to generate -*new* weight windows and thus overwrite the existing ``weight_windows.h5`` file. -Weight window mesh information is embedded into the weight window file, so the -mesh does not need to be redefined. Monte Carlo solves that load a weight window -file as above will utilize weight windows to reduce the variance of the -simulation. - -.. _source_biasing: - --------------- -Source Biasing --------------- - -In fixed source problems, source biasing provides a means to reduce the variance -on global or localized responses, depending on the biasing scheme. In either -case, the premise of the method is to sample source sites from a biased -distribution that directs a larger fraction of the simulated histories towards -phase space regions of interest than would be found there under analog sampling. -In order to preserve an unbiased estimate of the tally mean, the weight of these -with analog sampling, divided by the probability assigned by the biased -distribution. While the assignment of statistical weights is outlined in the -:ref:`methods section `, this section demonstrates the -implementation of source biasing to problems in OpenMC. - -Source biasing in OpenMC is accomplished by applying a distribution to the -:attr:`bias` attribute of one or more of the univariate or independent -multivariate distributions which make up an :class:`~openmc.IndependentSource` -instance as follows:: - - # First create the biased distribution - biased_dist = openmc.stats.PowerLaw(a=0, b=3, n=3) - - # Construct a new distribution with the bias applied - dist = openmc.stats.PowerLaw(a=0, b=3, n=2, bias=biased_dist) - - # The bias attribute can also be set on an existing "analog" distribution: - sphere_dist = openmc.stats.spherical_uniform(r_outer=3) - sphere_dist.r.bias = biased_dist - -Univariate distributions may be sampled via the Python API, returning the -sample(s) along with the associated weight(s):: - - sample_vec, wgt_vec = dist.sample(n_samples=100) - -Here, if the distribution is unbiased, the weight of each sample will be unity. -Finally, :class:`~openmc.IndependentSource` instances can be constructed with -biased distributions:: - - # Create a source with a biased spatial distribution - source = openmc.IndependentSource(space=sphere_dist) - -During the simulation, source sites are then sampled using the biased -distributions where available and given starting statistical weights -corresponding to the cumulative product of the weights assigned by each -distribution in the source object. Hence multiple source variables (e.g., -direction and energy) may be biased and the resulting source sites will have -their weights adjusted accordingly. - -.. note:: - Combining source biasing with weight windows can be a powerful variance - reduction technique if each is constructed appropriately for the response - of interest. For example, if a source biasing scheme is devised for - variance reduction of a specific localized response, the user may be able - to specify their own weight window structure that results in more efficient - transport than if weight windows were generated by either of OpenMC's - automatic weight window generators, which are intended for global variance - reduction. - -Biased distributions that could result in degenerate weight mappings are not -recommended; this is most commonly seen when biasing the :math:`\phi`-coordinate -of spherical or cylindrical independent multivariate distributions. In such -cases degenerate behavior will be observed at the pole about which :math:`\phi` -is measured, with all values of :math:`\phi` (hence many possible statistical -weights) mapping to the same point for :math:`r=0` or :math:`\mu=0`, and large -weight gradients in the vicinity. In most cases requiring a spherical -independent source, it would be preferable to reorient the reference vector of -the distribution such that biasing could be applied to the -:math:`\mu`-coordinate instead. - -When biasing a distribution, care should also be taken to ensure that both the -unbiased and biased distribution share a common support---that is, every region -of phase space mapped to a nonzero probability density by the unbiased -distribution should likewise map to nonzero probability under the biased -distribution, and vice versa. In OpenMC, this places restrictions on the set of -compatible distributions that may be used to bias sampling of each distribution -type. The following table summarizes the method for each distribution in OpenMC -that permits biased sampling. - -.. list-table:: **Distributions that support biased sampling** - :header-rows: 1 - :widths: 35 65 - - * - Discrete Univariate PDFs - - Biasing Method - * - :class:`openmc.stats.Discrete` - - Apply a vector of alternative probabilities to the :attr:`bias` - attribute - -.. list-table:: - :header-rows: 1 - :widths: 35 65 - - * - Continuous Univariate PDFs - - Biasing Method - * - :class:`openmc.stats.Uniform`, - :class:`openmc.stats.PowerLaw`, - :class:`openmc.stats.Maxwell`, - :class:`openmc.stats.Watt`, - :class:`openmc.stats.Normal`, - :class:`openmc.stats.Tabular` - - Apply a second, unbiased continous univariate PDF to the :attr:`bias` - attribute, ensuring that the :attr:`support` attribute of each - distribution is the same - -.. list-table:: - :header-rows: 1 - :widths: 35 65 - - * - Mixed Univariate PDFs - - Biasing Method - * - :class:`openmc.stats.Mixture` - - May be constructed from multiple biased univariate distributions, or a - second, unbiased continous univariate PDF may be applied to the - :attr:`bias` attribute - -.. list-table:: - :header-rows: 1 - :widths: 35 65 - - * - Discrete Multivariate PDFs - - Biasing Method - * - :class:`openmc.stats.PointCloud`, - :class:`openmc.stats.MeshSpatial` - - Apply a vector of the new relative probabilities of each point or mesh - element under biased sampling to the :attr:`bias` attribute - -.. list-table:: - :header-rows: 1 - :widths: 35 65 - - * - Continuous Multivariate PDFs - - Biasing Method - * - :class:`openmc.stats.CartesianIndependent`, - :class:`openmc.stats.CylindricalIndependent`, - :class:`openmc.stats.SphericalIndependent`, - :class:`openmc.stats.PolarAzimuthal` - - Construct from biased univariate distributions for :attr:`x`, :attr:`y`, - :attr:`z`, etc. - * - :class:`openmc.stats.Isotropic` - - Apply an unbiased :class:`openmc.stats.PolarAzimuthal` to the - :attr:`bias` attribute diff --git a/examples/assembly/assembly.py b/examples/assembly/assembly.py index d94cb69bf..ec1bb7e9f 100644 --- a/examples/assembly/assembly.py +++ b/examples/assembly/assembly.py @@ -99,11 +99,11 @@ def assembly_model(): assembly.universes[gt_pos[:, 0], gt_pos[:, 1]] = guide_tube_pin() # Create outer boundary of the geometry to surround the lattice - outer_boundary = openmc.model.RectangularPrism( + outer_boundary = openmc.model.rectangular_prism( pitch, pitch, boundary_type='reflective') # Create a cell filled with the lattice - main_cell = openmc.Cell(fill=assembly, region=-outer_boundary) + main_cell = openmc.Cell(fill=assembly, region=outer_boundary) # Finally, create geometry by providing a list of cells that fill the root # universe @@ -112,10 +112,11 @@ def assembly_model(): model.settings.batches = 150 model.settings.inactive = 50 model.settings.particles = 1000 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box((-pitch/2, -pitch/2, -1), (pitch/2, pitch/2, 1)), - constraints={'fissionable': True} - ) + model.settings.source = openmc.Source(space=openmc.stats.Box( + (-pitch/2, -pitch/2, -1), + (pitch/2, pitch/2, 1), + only_fissionable=True + )) # NOTE: We never actually created a Materials object. When you export/run # using the Model object, if no materials were assigned it will look through diff --git a/examples/custom_source/CMakeLists.txt b/examples/custom_source/CMakeLists.txt index ba5ae94ad..949817694 100644 --- a/examples/custom_source/CMakeLists.txt +++ b/examples/custom_source/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16 FATAL_ERROR) +cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_sources CXX) add_library(source SHARED source_ring.cpp) find_package(OpenMC REQUIRED) diff --git a/examples/custom_source/build_xml.py b/examples/custom_source/build_xml.py index ff6dae2bb..a0817d422 100644 --- a/examples/custom_source/build_xml.py +++ b/examples/custom_source/build_xml.py @@ -8,8 +8,8 @@ mats = openmc.Materials([iron]) mats.export_to_xml() # Create a 5 cm x 5 cm box filled with iron -box = openmc.model.RectangularPrism(10.0, 10.0, boundary_type='vacuum') -cell = openmc.Cell(fill=iron, region=-box) +box = openmc.model.rectangular_prism(10.0, 10.0, boundary_type='vacuum') +cell = openmc.Cell(fill=iron, region=box) geometry = openmc.Geometry([cell]) geometry.export_to_xml() @@ -18,7 +18,7 @@ settings = openmc.Settings() settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.CompiledSource() +source = openmc.Source() source.library = 'build/libsource.so' settings.source = source settings.export_to_xml() diff --git a/examples/custom_source/source_ring.cpp b/examples/custom_source/source_ring.cpp index bce6c27eb..b87afbd17 100644 --- a/examples/custom_source/source_ring.cpp +++ b/examples/custom_source/source_ring.cpp @@ -1,17 +1,17 @@ -#define _USE_MATH_DEFINES -#include // for M_PI +#include // for M_PI #include // 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,11 +25,10 @@ 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 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 openmc_create_source(std::string parameters) { return std::make_unique(); } diff --git a/examples/lattice/hexagonal/build_xml.py b/examples/lattice/hexagonal/build_xml.py index 2624e52b4..c0aa815b4 100644 --- a/examples/lattice/hexagonal/build_xml.py +++ b/examples/lattice/hexagonal/build_xml.py @@ -114,9 +114,8 @@ settings_file.particles = particles # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) -settings_file.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) +settings_file.source = openmc.source.Source(space=uniform_dist) settings_file.keff_trigger = {'type' : 'std_dev', 'threshold' : 5E-4} settings_file.trigger_active = True @@ -128,14 +127,14 @@ settings_file.export_to_xml() # Exporting to OpenMC plots.xml file ############################################################################### -plot_xy = openmc.SlicePlot(plot_id=1) +plot_xy = openmc.Plot(plot_id=1) plot_xy.filename = 'plot_xy' plot_xy.origin = [0, 0, 0] plot_xy.width = [6, 6] plot_xy.pixels = [400, 400] plot_xy.color_by = 'material' -plot_yz = openmc.SlicePlot(plot_id=2) +plot_yz = openmc.Plot(plot_id=2) plot_yz.filename = 'plot_yz' plot_yz.basis = 'yz' plot_yz.origin = [0, 0, 0] diff --git a/examples/lattice/nested/build_xml.py b/examples/lattice/nested/build_xml.py index a1d9c092d..06641f5ac 100644 --- a/examples/lattice/nested/build_xml.py +++ b/examples/lattice/nested/build_xml.py @@ -124,9 +124,8 @@ settings_file.particles = particles # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) -settings_file.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) +settings_file.source = openmc.source.Source(space=uniform_dist) settings_file.export_to_xml() @@ -135,7 +134,7 @@ settings_file.export_to_xml() # Exporting to OpenMC plots.xml file ############################################################################### -plot = openmc.SlicePlot(plot_id=1) +plot = openmc.Plot(plot_id=1) plot.origin = [0, 0, 0] plot.width = [4, 4] plot.pixels = [400, 400] diff --git a/examples/lattice/simple/build_xml.py b/examples/lattice/simple/build_xml.py index 44531edd8..17544b87f 100644 --- a/examples/lattice/simple/build_xml.py +++ b/examples/lattice/simple/build_xml.py @@ -115,9 +115,8 @@ settings_file.particles = particles # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) -settings_file.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) +settings_file.source = openmc.source.Source(space=uniform_dist) settings_file.trigger_active = True settings_file.trigger_max_batches = 100 @@ -128,7 +127,7 @@ settings_file.export_to_xml() # Exporting to OpenMC plots.xml file ############################################################################### -plot = openmc.SlicePlot(plot_id=1) +plot = openmc.Plot(plot_id=1) plot.origin = [0, 0, 0] plot.width = [4, 4] plot.pixels = [400, 400] diff --git a/examples/parameterized_custom_source/CMakeLists.txt b/examples/parameterized_custom_source/CMakeLists.txt index 20dac4d8f..3024e90cf 100644 --- a/examples/parameterized_custom_source/CMakeLists.txt +++ b/examples/parameterized_custom_source/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16 FATAL_ERROR) +cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_sources CXX) add_library(parameterized_source SHARED parameterized_source_ring.cpp) find_package(OpenMC REQUIRED) diff --git a/examples/parameterized_custom_source/build_xml.py b/examples/parameterized_custom_source/build_xml.py index 5ac6bf928..5edb204df 100644 --- a/examples/parameterized_custom_source/build_xml.py +++ b/examples/parameterized_custom_source/build_xml.py @@ -8,8 +8,8 @@ mats = openmc.Materials([iron]) mats.export_to_xml() # Create a 5 cm x 5 cm box filled with iron -box = openmc.model.RectangularPrism(10.0, 10.0, boundary_type='vacuum') -cell = openmc.Cell(fill=iron, region=-box) +box = openmc.model.rectangular_prism(10.0, 10.0, boundary_type='vacuum') +cell = openmc.Cell(fill=iron, region=box) geometry = openmc.Geometry([cell]) geometry.export_to_xml() @@ -18,7 +18,7 @@ settings = openmc.Settings() settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.CompiledSource() +source = openmc.Source() source.library = 'build/libparameterized_source.so' source.parameters = 'radius=3.0, energy=14.08e6' settings.source = source diff --git a/examples/parameterized_custom_source/parameterized_source_ring.cpp b/examples/parameterized_custom_source/parameterized_source_ring.cpp index 3aabf3581..e70dc8bb1 100644 --- a/examples/parameterized_custom_source/parameterized_source_ring.cpp +++ b/examples/parameterized_custom_source/parameterized_source_ring.cpp @@ -1,66 +1,63 @@ -#define _USE_MATH_DEFINES -#include -#include +#include // for M_PI +#include // for unique_ptr #include -#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 from_string(std::string parameters) - { - std::unordered_map 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 from_string(std::string parameters) + { + std::unordered_map 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; + 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(radius, energy); } - double radius = std::stod(parameter_mapping["radius"]); - double energy = std::stod(parameter_mapping["energy"]); - return std::make_unique(radius, energy); - } + // 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_; - // 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_; + return particle; + } - return particle; - } - -private: - double radius_; - double energy_; + 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 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 openmc_create_source(std::string parameters) { return RingSource::from_string(parameters); } diff --git a/examples/pincell/build_xml.py b/examples/pincell/build_xml.py index aed0c790f..c5d614ea9 100644 --- a/examples/pincell/build_xml.py +++ b/examples/pincell/build_xml.py @@ -43,13 +43,13 @@ clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR') # Create a region represented as the inside of a rectangular prism pitch = 1.25984 -box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') +box = openmc.rectangular_prism(pitch, pitch, boundary_type='reflective') # Create cells, mapping materials to regions fuel = openmc.Cell(fill=uo2, region=-fuel_or) gap = openmc.Cell(fill=helium, region=+fuel_or & -clad_ir) clad = openmc.Cell(fill=zircaloy, region=+clad_ir & -clad_or) -water = openmc.Cell(fill=borated_water, region=+clad_or & -box) +water = openmc.Cell(fill=borated_water, region=+clad_or & box) # Create a geometry and export to XML geometry = openmc.Geometry([fuel, gap, clad, water]) @@ -67,9 +67,8 @@ settings.particles = 1000 # Create an initial uniform spatial source distribution over fissionable zones lower_left = (-pitch/2, -pitch/2, -1) upper_right = (pitch/2, pitch/2, 1) -uniform_dist = openmc.stats.Box(lower_left, upper_right) -settings.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) +settings.source = openmc.source.Source(space=uniform_dist) # For source convergence checks, add a mesh that can be used to calculate the # Shannon entropy diff --git a/examples/pincell_depletion/restart_depletion.py b/examples/pincell_depletion/restart_depletion.py index de9fc16cb..6bb715f3b 100644 --- a/examples/pincell_depletion/restart_depletion.py +++ b/examples/pincell_depletion/restart_depletion.py @@ -26,9 +26,8 @@ settings.particles = 10000 # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) -settings.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) +settings.source = openmc.source.Source(space=uniform_dist) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] diff --git a/examples/pincell_depletion/run_depletion.py b/examples/pincell_depletion/run_depletion.py index 013c83c86..6a6c25f59 100644 --- a/examples/pincell_depletion/run_depletion.py +++ b/examples/pincell_depletion/run_depletion.py @@ -41,13 +41,13 @@ pitch = 1.25984 fuel_or = openmc.ZCylinder(r=0.39218, name='Fuel OR') clad_ir = openmc.ZCylinder(r=0.40005, name='Clad IR') clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR') -box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') +box = openmc.model.rectangular_prism(pitch, pitch, boundary_type='reflective') # Define cells fuel = openmc.Cell(fill=uo2, region=-fuel_or) gap = openmc.Cell(fill=helium, region=+fuel_or & -clad_ir) clad = openmc.Cell(fill=zircaloy, region=+clad_ir & -clad_or) -water = openmc.Cell(fill=borated_water, region=+clad_or & -box) +water = openmc.Cell(fill=borated_water, region=+clad_or & box) # Define overall geometry geometry = openmc.Geometry([fuel, gap, clad, water]) @@ -71,9 +71,8 @@ settings.particles = 1000 # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) -settings.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) +settings.source = openmc.source.Source(space=uniform_dist) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] diff --git a/examples/pincell_multigroup/build_xml.py b/examples/pincell_multigroup/build_xml.py index 0971e5de6..1f3468391 100644 --- a/examples/pincell_multigroup/build_xml.py +++ b/examples/pincell_multigroup/build_xml.py @@ -90,11 +90,11 @@ fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') # Create a region represented as the inside of a rectangular prism pitch = 1.26 -box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') +box = openmc.rectangular_prism(pitch, pitch, boundary_type='reflective') # Instantiate Cells fuel = openmc.Cell(fill=uo2, region=-fuel_or, name='fuel') -moderator = openmc.Cell(fill=water, region=+fuel_or & -box, name='moderator') +moderator = openmc.Cell(fill=water, region=+fuel_or & box, name='moderator') # Create a geometry with the two cells and export to XML geometry = openmc.Geometry([fuel, moderator]) @@ -113,9 +113,8 @@ settings.particles = 1000 # Create an initial uniform spatial source distribution over fissionable zones lower_left = (-pitch/2, -pitch/2, -1) upper_right = (pitch/2, pitch/2, 1) -uniform_dist = openmc.stats.Box(lower_left, upper_right) -settings.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) +uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) +settings.source = openmc.source.Source(space=uniform_dist) settings.export_to_xml() ############################################################################### diff --git a/examples/pincell_pulsed/run_pulse.py b/examples/pincell_pulsed/run_pulse.py deleted file mode 100644 index b6a61ad3d..000000000 --- a/examples/pincell_pulsed/run_pulse.py +++ /dev/null @@ -1,101 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -import openmc - -############################################################################### -# Create materials for the problem - -uo2 = openmc.Material(name="UO2 fuel at 2.4% wt enrichment") -uo2.set_density("g/cm3", 10.29769) -uo2.add_element("U", 1.0, enrichment=2.4) -uo2.add_element("O", 2.0) - -helium = openmc.Material(name="Helium for gap") -helium.set_density("g/cm3", 0.001598) -helium.add_element("He", 2.4044e-4) - -zircaloy = openmc.Material(name="Zircaloy 4") -zircaloy.set_density("g/cm3", 6.55) -zircaloy.add_element("Sn", 0.014, "wo") -zircaloy.add_element("Fe", 0.00165, "wo") -zircaloy.add_element("Cr", 0.001, "wo") -zircaloy.add_element("Zr", 0.98335, "wo") - -borated_water = openmc.Material(name="Borated water") -borated_water.set_density("g/cm3", 0.740582) -borated_water.add_element("B", 2.0e-4) # 3x the original pincell -borated_water.add_element("H", 5.0e-2) -borated_water.add_element("O", 2.4e-2) -borated_water.add_s_alpha_beta("c_H_in_H2O") - -############################################################################### -# Define problem geometry - -# Create cylindrical surfaces -fuel_or = openmc.ZCylinder(r=0.39218, name="Fuel OR") -clad_ir = openmc.ZCylinder(r=0.40005, name="Clad IR") -clad_or = openmc.ZCylinder(r=0.45720, name="Clad OR") - -# Create a region represented as the inside of a rectangular prism -pitch = 1.25984 -box = openmc.model.RectangularPrism(pitch, pitch, boundary_type="reflective") - -# Create cells, mapping materials to regions -fuel = openmc.Cell(fill=uo2, region=-fuel_or) -gap = openmc.Cell(fill=helium, region=+fuel_or & -clad_ir) -clad = openmc.Cell(fill=zircaloy, region=+clad_ir & -clad_or) -water = openmc.Cell(fill=borated_water, region=+clad_or & -box) - -# Create a model and assign geometry -model = openmc.Model() -model.geometry = openmc.Geometry([fuel, gap, clad, water]) - -############################################################################### -# Define problem settings - -# Set the mode -model.settings.run_mode = "fixed source" - -# Indicate how many batches and particles to run -model.settings.batches = 10 -model.settings.particles = 10000 - -# Set time cutoff (we only care about t < 100 seconds, see tally below) -model.settings.cutoff = {"time_neutron": 100} - -# Create the neutron pulse source (by default, isotropic direction, t=0) -space = openmc.stats.Point() # At the origin (0, 0, 0) -energy = openmc.stats.delta_function(14.1e6) # At 14.1 MeV -model.settings.source = openmc.IndependentSource(space=space, energy=energy) - -############################################################################### -# Define tallies - -# Create time filter -t_grid = np.insert(np.logspace(-6, 2, 100), 0, 0.0) -time_filter = openmc.TimeFilter(t_grid) - -# Tally for total neutron density in time -density_tally = openmc.Tally(name="Density") -density_tally.filters = [time_filter] -density_tally.scores = ["inverse-velocity"] - -# Add tallies to model -model.tallies = openmc.Tallies([density_tally]) - - -# Run the model -model.run(apply_tally_results=True) - -# Bin-averaged result -density_mean = density_tally.mean.ravel() / np.diff(t_grid) - -# Plot particle density versus time -fig, ax = plt.subplots() -ax.stairs(density_mean, t_grid) -ax.set_xscale("log") -ax.set_yscale("log") -ax.set_xlabel("Time [s]") -ax.set_ylabel("Total density") -ax.grid() -plt.show() diff --git a/examples/pincell_random_ray/build_xml.py b/examples/pincell_random_ray/build_xml.py deleted file mode 100644 index 5ff4c0082..000000000 --- a/examples/pincell_random_ray/build_xml.py +++ /dev/null @@ -1,202 +0,0 @@ -import numpy as np -import openmc -import openmc.mgxs - -############################################################################### -# Create multigroup data - -# Instantiate the energy group data -group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] -groups = openmc.mgxs.EnergyGroups(group_edges) - -# Instantiate the 7-group (C5G7) cross section data -uo2_xsdata = openmc.XSdata('UO2', groups) -uo2_xsdata.order = 0 -uo2_xsdata.set_total( - [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, - 0.5644058]) -uo2_xsdata.set_absorption([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02, - 3.0020e-02, 1.1126e-01, 2.8278e-01]) -scatter_matrix = np.array( - [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) -scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) -uo2_xsdata.set_scatter_matrix(scatter_matrix) -uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03, - 1.85648e-02, 1.78084e-02, 8.30348e-02, - 2.16004e-01]) -uo2_xsdata.set_nu_fission([2.005998e-02, 2.027303e-03, 1.570599e-02, - 4.518301e-02, 4.334208e-02, 2.020901e-01, - 5.257105e-01]) -uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, - 0.0000e+00, 0.0000e+00]) - -h2o_xsdata = openmc.XSdata('LWTR', groups) -h2o_xsdata.order = 0 -h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, - 0.718, 1.2544497, 2.650379]) -h2o_xsdata.set_absorption([6.0105e-04, 1.5793e-05, 3.3716e-04, - 1.9406e-03, 5.7416e-03, 1.5001e-02, - 3.7239e-02]) -scatter_matrix = np.array( - [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], - [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], - [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], - [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], - [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]) -scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) -h2o_xsdata.set_scatter_matrix(scatter_matrix) - -mg_cross_sections_file = openmc.MGXSLibrary(groups) -mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata]) -mg_cross_sections_file.export_to_hdf5() - -############################################################################### -# Create materials for the problem - -# Instantiate some Materials and register the appropriate macroscopic data -uo2 = openmc.Material(name='UO2 fuel') -uo2.set_density('macro', 1.0) -uo2.add_macroscopic('UO2') - -water = openmc.Material(name='Water') -water.set_density('macro', 1.0) -water.add_macroscopic('LWTR') - -# Instantiate a Materials collection and export to XML -materials_file = openmc.Materials([uo2, water]) -materials_file.cross_sections = "mgxs.h5" -materials_file.export_to_xml() - -############################################################################### -# Define problem geometry - -# The geometry we will define a simplified pincell with fuel radius 0.54 cm -# surrounded by moderator (same as in the multigroup example). -# In random ray, we typically want several radial regions and azimuthal -# sectors in both the fuel and moderator areas of the pincell. This is -# due to the flat source approximation requiring that source regions are -# small compared to the typical mean free path of a neutron. Below we -# sudivide the basic pincell into 8 aziumthal sectors (pizza slices) and -# 5 concentric rings in both the fuel and moderator. - -# TODO: When available in OpenMC, use cylindrical lattice instead to -# simplify definition and improve runtime performance. - -pincell_base = openmc.Universe() - -# These are the subdivided radii (creating 5 concentric regions in the -# fuel and moderator) -ring_radii = [0.241, 0.341, 0.418, 0.482, 0.54, 0.572, 0.612, 0.694, 0.786] -fills = [uo2, uo2, uo2, uo2, uo2, water, water, water, water, water] - -# We then create cells representing the bounded rings, with special -# treatment for both the innermost and outermost cells -cells = [] -for r in range(10): - cell = [] - if r == 0: - outer_bound = openmc.ZCylinder(r=ring_radii[r]) - cell = openmc.Cell(fill=fills[r], region=-outer_bound) - elif r == 9: - inner_bound = openmc.ZCylinder(r=ring_radii[r-1]) - cell = openmc.Cell(fill=fills[r], region=+inner_bound) - else: - inner_bound = openmc.ZCylinder(r=ring_radii[r-1]) - outer_bound = openmc.ZCylinder(r=ring_radii[r]) - cell = openmc.Cell(fill=fills[r], region=+inner_bound & -outer_bound) - pincell_base.add_cell(cell) - -# We then generate 8 planes to bound 8 azimuthal sectors -azimuthal_planes = [] -for i in range(8): - angle = 2 * i * openmc.pi / 8 - normal_vector = (-openmc.sin(angle), openmc.cos(angle), 0) - azimuthal_planes.append(openmc.Plane(a=normal_vector[0], b=normal_vector[1], c=normal_vector[2], d=0)) - -# Create a cell for each azimuthal sector using the pincell base class -azimuthal_cells = [] -for i in range(8): - azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}') - azimuthal_cell.fill = pincell_base - azimuthal_cell.region = +azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] - azimuthal_cells.append(azimuthal_cell) - -# Create the (subdivided) geometry with the azimuthal universes -pincell = openmc.Universe(cells=azimuthal_cells) - -# Create a region represented as the inside of a rectangular prism -pitch = 1.26 -box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') -pincell_bounded = openmc.Cell(fill=pincell, region=-box, name='pincell') - -# Create a geometry (specifying merge surfaces option to remove -# all the redundant cylinder/plane surfaces) and export to XML -geometry = openmc.Geometry([pincell_bounded], merge_surfaces=True) -geometry.export_to_xml() - -############################################################################### -# Define problem settings - -# Instantiate a Settings object, set all runtime parameters, and export to XML -settings = openmc.Settings() -settings.energy_mode = "multi-group" -settings.batches = 600 -settings.inactive = 300 -settings.particles = 50 - -# Create an initial uniform spatial source distribution for sampling rays. -# Note that this must be uniform in space and angle. -lower_left = (-pitch/2, -pitch/2, -1) -upper_right = (pitch/2, pitch/2, 1) -uniform_dist = openmc.stats.Box(lower_left, upper_right) -settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) -settings.random_ray['distance_inactive'] = 40.0 -settings.random_ray['distance_active'] = 400.0 - -settings.export_to_xml() - -############################################################################### -# Define tallies - -# Create a mesh that will be used for tallying -mesh = openmc.RegularMesh() -mesh.dimension = (2, 2) -mesh.lower_left = (-pitch/2, -pitch/2) -mesh.upper_right = (pitch/2, pitch/2) - -# Create a mesh filter that can be used in a tally -mesh_filter = openmc.MeshFilter(mesh) - -# Let's also create a filter to measure each group -# indepdendently -energy_filter = openmc.EnergyFilter(group_edges) - -# Now use the mesh filter in a tally and indicate what scores are desired -tally = openmc.Tally(name="Mesh and Energy tally") -tally.filters = [mesh_filter, energy_filter] -tally.scores = ['flux', 'fission', 'nu-fission'] - -# Instantiate a Tallies collection and export to XML -tallies = openmc.Tallies([tally]) -tallies.export_to_xml() - -############################################################################### -# Exporting to OpenMC plots.xml file -############################################################################### - -plot = openmc.VoxelPlot() -plot.origin = [0, 0, 0] -plot.width = [pitch, pitch, pitch] -plot.pixels = [1000, 1000, 1] - -# Instantiate a Plots collection and export to XML -plots = openmc.Plots([plot]) -plots.export_to_xml() diff --git a/include/openmc/angle_energy.h b/include/openmc/angle_energy.h index 55deb5d41..ac931b1b5 100644 --- a/include/openmc/angle_energy.h +++ b/include/openmc/angle_energy.h @@ -14,22 +14,8 @@ 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; }; diff --git a/include/openmc/atomic_mass.h b/include/openmc/atomic_mass.h deleted file mode 100644 index b4d515d2e..000000000 --- a/include/openmc/atomic_mass.h +++ /dev/null @@ -1,28 +0,0 @@ -//============================================================================== -// atomic masses definitions -//============================================================================== - -#ifndef OPENMC_ATOMIC_MASS_H -#define OPENMC_ATOMIC_MASS_H - -#include -#include - -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 ATOMIC_MASS; - -} // namespace openmc - -#endif // OPENMC_ATOMIC_MASS_H diff --git a/include/openmc/bank.h b/include/openmc/bank.h index 6abcdd7f1..95386514d 100644 --- a/include/openmc/bank.h +++ b/include/openmc/bank.h @@ -20,38 +20,22 @@ extern vector source_bank; extern SharedArray surf_source_bank; -extern SharedArray collision_track_bank; - extern SharedArray fission_bank; -extern vector> ifp_source_delayed_group_bank; - -extern vector> ifp_source_lifetime_bank; - -extern vector> ifp_fission_delayed_group_bank; - -extern vector> ifp_fission_lifetime_bank; - extern vector progeny_per_particle; -extern SharedArray shared_secondary_bank_read; -extern SharedArray shared_secondary_bank_write; - } // namespace simulation //============================================================================== // Non-member functions //============================================================================== -void sort_bank(SharedArray& bank, bool is_fission_bank); +void sort_fission_bank(); void free_memory_bank(); void init_fission_bank(int64_t max); -int64_t synchronize_global_secondary_bank( - SharedArray& shared_secondary_bank); - } // namespace openmc #endif // OPENMC_BANK_H diff --git a/include/openmc/bank_io.h b/include/openmc/bank_io.h deleted file mode 100644 index 418ec111f..000000000 --- a/include/openmc/bank_io.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef OPENMC_BANK_IO_H -#define OPENMC_BANK_IO_H - -#include "hdf5.h" - -#include "openmc/message_passing.h" -#include "openmc/span.h" -#include "openmc/vector.h" - -#include - -#ifdef OPENMC_MPI -#include -#endif - -namespace openmc { - -template -void write_bank_dataset( - const char* dataset_name, hid_t group_id, span bank, - const vector& bank_index, hid_t membanktype, hid_t filebanktype -#ifdef OPENMC_MPI - , - MPI_Datatype mpi_dtype -#endif -) -{ - int64_t dims_size = bank_index.back(); - int64_t count_size = bank_index[mpi::rank + 1] - bank_index[mpi::rank]; - -#ifdef PHDF5 - hsize_t dims[] {static_cast(dims_size)}; - hid_t dspace = H5Screate_simple(1, dims, nullptr); - hid_t dset = H5Dcreate(group_id, dataset_name, filebanktype, dspace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - - hsize_t count[] {static_cast(count_size)}; - hid_t memspace = H5Screate_simple(1, count, nullptr); - - hsize_t start[] {static_cast(bank_index[mpi::rank])}; - H5Sselect_hyperslab(dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); - - hid_t plist = H5Pcreate(H5P_DATASET_XFER); - H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); - - H5Dwrite(dset, membanktype, memspace, dspace, plist, bank.data()); - - H5Sclose(dspace); - H5Sclose(memspace); - H5Dclose(dset); - H5Pclose(plist); -#else - if (mpi::master) { - hsize_t dims[] {static_cast(dims_size)}; - hid_t dspace = H5Screate_simple(1, dims, nullptr); - hid_t dset = H5Dcreate(group_id, dataset_name, filebanktype, dspace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - -#ifdef OPENMC_MPI - vector temp_bank {bank.begin(), bank.end()}; -#endif - - for (int i = 0; i < mpi::n_procs; ++i) { - hsize_t count[] {static_cast(bank_index[i + 1] - bank_index[i])}; - hid_t memspace = H5Screate_simple(1, count, nullptr); - -#ifdef OPENMC_MPI - if (i > 0) { - MPI_Recv(bank.data(), count[0], mpi_dtype, i, i, mpi::intracomm, - MPI_STATUS_IGNORE); - } -#endif - - hid_t dspace_rank = H5Dget_space(dset); - hsize_t start[] {static_cast(bank_index[i])}; - H5Sselect_hyperslab( - dspace_rank, H5S_SELECT_SET, start, nullptr, count, nullptr); - - H5Dwrite( - dset, membanktype, memspace, dspace_rank, H5P_DEFAULT, bank.data()); - - H5Sclose(memspace); - H5Sclose(dspace_rank); - } - - H5Dclose(dset); - -#ifdef OPENMC_MPI - std::copy(temp_bank.begin(), temp_bank.end(), bank.begin()); -#endif - } -#ifdef OPENMC_MPI - else { - if (!bank.empty()) { - MPI_Send( - bank.data(), bank.size(), mpi_dtype, 0, mpi::rank, mpi::intracomm); - } - } -#endif -#endif -} - -} // namespace openmc - -#endif // OPENMC_BANK_IO_H diff --git a/include/openmc/boundary_condition.h b/include/openmc/boundary_condition.h index 89bf7ca8b..0f16fa3b3 100644 --- a/include/openmc/boundary_condition.h +++ b/include/openmc/boundary_condition.h @@ -1,16 +1,12 @@ #ifndef OPENMC_BOUNDARY_CONDITION_H #define OPENMC_BOUNDARY_CONDITION_H -#include "openmc/hdf5_interface.h" -#include "openmc/particle.h" #include "openmc/position.h" -#include namespace openmc { // Forward declare some types used in function arguments. class Particle; -class RandomRay; class Surface; //============================================================================== @@ -19,8 +15,6 @@ class Surface; class BoundaryCondition { public: - virtual ~BoundaryCondition() = default; - //! Perform tracking operations for a particle that strikes the boundary. //! \param p The particle that struck the boundary. This class is not meant //! to directly modify anything about the particle, but it will do so @@ -28,44 +22,8 @@ public: //! \param surf The specific surface on the boundary the particle struck. virtual void handle_particle(Particle& p, const Surface& surf) const = 0; - //! Modify the incident particle's weight according to the boundary's albedo. - //! \param p The particle that struck the boundary. This function calculates - //! the reduction in the incident particle's weight as it interacts - //! with a boundary. The lost weight is tallied before the remaining weight - //! is reassigned to the incident particle. Implementations of the - //! handle_particle function typically call this method in its body. - //! \param surf The specific surface on the boundary the particle struck. - void handle_albedo(Particle& p, const Surface& surf) const - { - if (!has_albedo()) - return; - double initial_wgt = p.wgt(); - // Treat the lost weight fraction as leakage, similar to VacuumBC. - // This ensures the lost weight is tallied properly. - p.wgt() *= (1.0 - albedo_); - p.cross_vacuum_bc(surf); - p.wgt() = initial_wgt * albedo_; - }; - //! Return a string classification of this BC. virtual std::string type() const = 0; - - //! Write albedo data of this BC to hdf5. - void to_hdf5(hid_t surf_group) const - { - if (has_albedo()) { - write_string(surf_group, "albedo", fmt::format("{}", albedo_), false); - } - }; - - //! Set albedo of this BC. - void set_albedo(double albedo) { albedo_ = albedo; } - - //! Return if this BC has an albedo. - bool has_albedo() const { return (albedo_ > 0.0); } - -private: - double albedo_ = -1.0; }; //============================================================================== @@ -111,10 +69,6 @@ public: std::string type() const override { return "periodic"; } - int i_surf() const { return i_surf_; } - - int j_surf() const { return j_surf_; } - protected: int i_surf_; int j_surf_; @@ -138,28 +92,18 @@ protected: //============================================================================== //! A BC that rotates particles about a global axis. // -//! Only rotations about the x, y, and z axes are supported. +//! Currently only rotations about the z-axis are supported. //============================================================================== class RotationalPeriodicBC : public PeriodicBC { public: - enum PeriodicAxis { x, y, z }; - RotationalPeriodicBC(int i_surf, int j_surf, PeriodicAxis axis); - double compute_periodic_rotation( - double rise_1, double run_1, double rise_2, double run_2) const; + RotationalPeriodicBC(int i_surf, int j_surf); + void handle_particle(Particle& p, const Surface& surf) const override; protected: //! Angle about the axis by which particle coordinates will be rotated double angle_; - //! Do we need to flip surfaces senses when applying the transformation? - bool flip_sense_; - //! Ensure that choice of axes is right handed. axis_1_idx_ corresponds to the - //! independent axis and axis_2_idx_ corresponds to the dependent axis in the - //! 2D plane perpendicular to the planes' axis of rotation - int zero_axis_idx_; - int axis_1_idx_; - int axis_2_idx_; }; } // namespace openmc diff --git a/include/openmc/bounding_box.h b/include/openmc/bounding_box.h deleted file mode 100644 index 4fabe1b70..000000000 --- a/include/openmc/bounding_box.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef OPENMC_BOUNDING_BOX_H -#define OPENMC_BOUNDING_BOX_H - -#include // for min, max - -#include "openmc/constants.h" -#include "openmc/position.h" - -namespace openmc { - -//============================================================================== -//! Coordinates for an axis-aligned cuboid that bounds a geometric object. -//============================================================================== - -struct BoundingBox { - Position min = {-INFTY, -INFTY, -INFTY}; - Position max = {INFTY, INFTY, INFTY}; - - // Constructors - BoundingBox() = default; - BoundingBox(Position min_, Position max_) : min {min_}, max {max_} {} - - // Static factory methods - static BoundingBox infinite() { return {}; } - static BoundingBox inverted() - { - return {{INFTY, INFTY, INFTY}, {-INFTY, -INFTY, -INFTY}}; - } - - inline BoundingBox operator&(const BoundingBox& other) - { - BoundingBox result = *this; - return result &= other; - } - - inline BoundingBox operator|(const BoundingBox& other) - { - BoundingBox result = *this; - return result |= other; - } - - // intersect operator - inline BoundingBox& operator&=(const BoundingBox& other) - { - min.x = std::max(min.x, other.min.x); - min.y = std::max(min.y, other.min.y); - min.z = std::max(min.z, other.min.z); - max.x = std::min(max.x, other.max.x); - max.y = std::min(max.y, other.max.y); - max.z = std::min(max.z, other.max.z); - return *this; - } - - // union operator - inline BoundingBox& operator|=(const BoundingBox& other) - { - min.x = std::min(min.x, other.min.x); - min.y = std::min(min.y, other.min.y); - min.z = std::min(min.z, other.min.z); - max.x = std::max(max.x, other.max.x); - max.y = std::max(max.y, other.max.y); - max.z = std::max(max.z, other.max.z); - return *this; - } -}; - -} // namespace openmc - -#endif diff --git a/include/openmc/bremsstrahlung.h b/include/openmc/bremsstrahlung.h index d3b586831..2f7e41bf0 100644 --- a/include/openmc/bremsstrahlung.h +++ b/include/openmc/bremsstrahlung.h @@ -3,7 +3,7 @@ #include "openmc/particle.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" namespace openmc { @@ -14,9 +14,9 @@ namespace openmc { class BremsstrahlungData { public: // Data - tensor::Tensor pdf; //!< Bremsstrahlung energy PDF - tensor::Tensor cdf; //!< Bremsstrahlung energy CDF - tensor::Tensor yield; //!< Photon yield + xt::xtensor pdf; //!< Bremsstrahlung energy PDF + xt::xtensor cdf; //!< Bremsstrahlung energy CDF + xt::xtensor yield; //!< Photon yield }; class Bremsstrahlung { @@ -32,9 +32,9 @@ public: namespace data { -extern tensor::Tensor +extern xt::xtensor ttb_e_grid; //! energy T of incident electron in [eV] -extern tensor::Tensor +extern xt::xtensor ttb_k_grid; //! reduced energy W/T of emitted photon } // namespace data diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 9f6987d74..29e900965 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -9,43 +9,14 @@ extern "C" { #endif -//! Run a stochastic volume calculation -// -//! \return Status (negative if an error occurred) int openmc_calculate_volumes(); - int openmc_cell_filter_get_bins( int32_t index, const int32_t** cells, int32_t* n); - -//! Get the fill for a cell -// -//! \param index Index in the cells array -//! \param type Type of the fill -//! \param indices Array of material indices for cell -//! \param n Length of indices array -//! \return Status (negative if an error occurred) int openmc_cell_get_fill( int32_t index, int* type, int32_t** indices, int32_t* n); - -//! Get the ID of a cell -// -//! \param index Index in the cells array -//! \param id ID of the cell -//! \return Status (negative if an error occurred) int openmc_cell_get_id(int32_t index, int32_t* id); - -//! Get the temperature of a cell -// -//! \param index Index in the cells array -//! \param instance Which instance of the cell. If a null pointer is -//! passed, the temperature of the first instance is returned. -//! \param T temperature of the cell -//!\return Status (negative if an error occurred) int openmc_cell_get_temperature( int32_t index, const int32_t* instance, double* T); - -int openmc_cell_get_density( - int32_t index, const int32_t* instance, double* rho); int openmc_cell_get_translation(int32_t index, double xyz[]); int openmc_cell_get_rotation(int32_t index, double rot[], size_t* n); int openmc_cell_get_name(int32_t index, const char** name); @@ -56,13 +27,8 @@ int openmc_cell_set_fill( int openmc_cell_set_id(int32_t index, int32_t id); int openmc_cell_set_temperature( int32_t index, double T, const int32_t* instance, bool set_contained = false); -int openmc_cell_set_density(int32_t index, double rho, const int32_t* instance, - bool set_contained = false); int openmc_cell_set_translation(int32_t index, const double xyz[]); int openmc_cell_set_rotation(int32_t index, const double rot[], size_t rot_len); -int openmc_dagmc_universe_get_cell_ids( - int32_t univ_id, int32_t* ids, size_t* n); -int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n); int openmc_energy_filter_get_bins( int32_t index, const double** energies, size_t* n); int openmc_energy_filter_set_bins( @@ -72,9 +38,6 @@ int openmc_energyfunc_filter_get_energy( int openmc_energyfunc_filter_get_y(int32_t index, size_t* n, const double** y); int openmc_energyfunc_filter_set_data( int32_t index, size_t n, const double* energies, const double* y); -int openmc_energyfunc_filter_set_interpolation( - int32_t index, const char* interp); -int openmc_energyfunc_filter_get_interpolation(int32_t index, int* interp); int openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_extend_filters(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_extend_materials( @@ -84,7 +47,6 @@ int openmc_extend_meshes( int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_filter_get_id(int32_t index, int32_t* id); int openmc_filter_get_type(int32_t index, char* type); -int openmc_filter_get_num_bins(int32_t index, int* n_bins); int openmc_filter_set_id(int32_t index, int32_t id); int openmc_finalize(); int openmc_find_cell(const double* xyz, int32_t* index, int32_t* instance); @@ -102,7 +64,6 @@ int openmc_get_nuclide_index(const char name[], int* index); int openmc_add_unstructured_mesh( const char filename[], const char library[], int* id); int64_t openmc_get_seed(); -uint64_t openmc_get_stride(); int openmc_get_tally_index(int32_t id, int32_t* index); void openmc_get_tally_next_id(int32_t* id); int openmc_global_tallies(double** ptr); @@ -128,8 +89,6 @@ int openmc_material_set_id(int32_t index, int32_t id); int openmc_material_get_name(int32_t index, const char** name); int openmc_material_set_name(int32_t index, const char* name); int openmc_material_set_volume(int32_t index, double volume); -int openmc_material_get_depletable(int32_t index, bool* depletable); -int openmc_material_set_depletable(int32_t index, bool depletable); int openmc_material_filter_get_bins( int32_t index, const int32_t** bins, size_t* n); int openmc_material_filter_set_bins( @@ -140,66 +99,14 @@ int openmc_mesh_filter_get_translation(int32_t index, double translation[3]); int openmc_mesh_filter_set_translation(int32_t index, double translation[3]); int openmc_mesh_get_id(int32_t index, int32_t* id); int openmc_mesh_set_id(int32_t index, int32_t id); -int openmc_mesh_get_n_elements(int32_t index, size_t* n); -int openmc_mesh_get_volumes(int32_t index, double* volumes); -int openmc_mesh_material_volumes(int32_t index, int nx, int ny, int nz, - int max_mats, int32_t* materials, double* volumes, double* bboxes); int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh); int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh); int openmc_new_filter(const char* type, int32_t* index); int openmc_next_batch(int* status); int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); -// Deprecated; use openmc_slice_data. int openmc_id_map(const void* slice, int32_t* data_out); -// Deprecated; use openmc_slice_data. int openmc_property_map(const void* slice, double* data_out); -int openmc_slice_data(const double origin[3], const double u_span[3], - const double v_span[3], const size_t pixels[2], bool show_overlaps, int level, - int32_t filter_index, int32_t* geom_data, double* property_data); -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, @@ -215,10 +122,8 @@ 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); int openmc_set_n_batches( int32_t n_batches, bool set_max_batches, bool add_statepoint_batch); int openmc_simulation_finalize(); @@ -235,7 +140,6 @@ int openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]); int openmc_sphharm_filter_set_order(int32_t index, int order); int openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]); int openmc_statepoint_write(const char* filename, bool* write_source); -int openmc_statepoint_load(const char* filename); int openmc_tally_allocate(int32_t index, const char* type); int openmc_tally_get_active(int32_t index, bool* active); int openmc_tally_get_estimator(int32_t index, int* estimator); @@ -256,47 +160,6 @@ int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); int openmc_tally_set_scores(int32_t index, int n, const char** scores); int openmc_tally_set_type(int32_t index, const char* type); int openmc_tally_set_writable(int32_t index, bool writable); -int openmc_get_weight_windows_index(int32_t id, int32_t* idx); -int openmc_weight_windows_get_id(int32_t index, int32_t* id); -int openmc_weight_windows_set_id(int32_t index, int32_t id); - -//! Updates weight window values using the specified tally -//! \param[in] ww_idx Index of the weight window object -//! \param[in] tally_idx Index of the tally to use for the update -//! \param[in] value Tally value to use for the update (one of 'mean', -//! 'rel_err') \param[in] threshold Relative error threshold for applied results -//! \param[in] ratio Upper to lower weight window bound ratio -int openmc_weight_windows_update_magic(int32_t ww_idx, int32_t tally_idx, - const char* value, double threshold, double ratio); - -int openmc_extend_weight_windows( - int32_t n, int32_t* index_start, int32_t* index_end); -int openmc_weight_windows_get_mesh(int32_t index, int32_t* mesh_idx); -int openmc_weight_windows_set_mesh(int32_t index, int32_t mesh_idx); -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, 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, - const double* upper_bounds, size_t size); -int openmc_weight_windows_get_survival_ratio(int32_t index, double* ratio); -int openmc_weight_windows_set_survival_ratio(int32_t index, double ratio); -int openmc_weight_windows_get_max_lower_bound_ratio( - int32_t index, double* lb_ratio); -int openmc_weight_windows_set_max_lower_bound_ratio( - int32_t index, double lb_ratio); -int openmc_weight_windows_get_weight_cutoff(int32_t index, double* cutoff); -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); int openmc_zernike_filter_get_params( int32_t index, double* x, double* y, double* r); @@ -304,10 +167,8 @@ 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, int32_t bins[]); - //! Sets the mesh and energy grid for CMFD reweight -//! \param[in] meshtally_id id of CMFD Mesh Tally +//! \param[in] meshtyally_id id of CMFD Mesh Tally //! \param[in] cmfd_indices indices storing spatial and energy dimensions of //! CMFD problem \param[in] norm CMFD normalization factor void openmc_initialize_mesh_egrid( diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 1a27ad516..01f037586 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -10,8 +10,8 @@ #include "hdf5.h" #include "pugixml.hpp" +#include -#include "openmc/bounding_box.h" #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr #include "openmc/neighbor_list.h" @@ -28,6 +28,7 @@ namespace openmc { enum class Fill { MATERIAL, UNIVERSE, LATTICE }; +// TODO: Convert to enum constexpr int32_t OP_LEFT_PAREN {std::numeric_limits::max()}; constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits::max() - 1}; constexpr int32_t OP_COMPLEMENT {std::numeric_limits::max() - 2}; @@ -39,7 +40,6 @@ constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; //============================================================================== class Cell; -class GeometryState; class ParentCell; class CellInstance; class Universe; @@ -52,123 +52,6 @@ extern vector> cells; } // namespace model //============================================================================== - -class Region { -public: - //---------------------------------------------------------------------------- - // Constructors - Region() {} - explicit Region(std::string region_spec, int32_t cell_id); - - //---------------------------------------------------------------------------- - // Methods - - //! \brief Determine if a cell contains the particle at a given location. - //! - //! The bounds of the cell are determined by a logical expression involving - //! surface half-spaces. The expression used is given in infix notation - //! - //! The function is split into two cases, one for simple cells (those - //! involving only the intersection of half-spaces) and one for complex cells. - //! Both cases use short circuiting; however, in the case fo complex cells, - //! the complexity increases with the binary operators involved. - //! \param r The 3D Cartesian coordinate to check. - //! \param u A direction used to "break ties" the coordinates are very - //! close to a surface. - //! \param on_surface The signed index of a surface that the coordinate is - //! known to be on. This index takes precedence over surface sense - //! calculations. - bool contains(Position r, Direction u, int32_t on_surface) const; - - //! Find the oncoming boundary of this cell. - std::pair distance( - Position r, Direction u, int32_t on_surface) const; - - //! Get the BoundingBox for this cell. - BoundingBox bounding_box(int32_t cell_id) const; - - //! Get the CSG expression as a string - std::string str() const; - - //! Get a vector containing all the surfaces in the region expression - vector surfaces() const; - - //---------------------------------------------------------------------------- - // Accessors - - //! Get Boolean of if the cell is simple or not - bool is_simple() const { return simple_; } - -private: - //---------------------------------------------------------------------------- - // Private Methods - - //! Get a vector of the region expression in postfix notation - vector generate_postfix(int32_t cell_id) const; - - //! Determine if a particle is inside the cell for a simple cell (only - //! intersection operators) - bool contains_simple(Position r, Direction u, int32_t on_surface) const; - - //! Determine if a particle is inside the cell for a complex cell. - //! - //! Uses the comobination of half-spaces and binary operators to determine - //! if short circuiting can be used. Short cicuiting uses the relative and - //! absolute depth of parentheses in the expression. - bool contains_complex(Position r, Direction u, int32_t on_surface) const; - - //! BoundingBox if the paritcle is in a simple cell. - BoundingBox bounding_box_simple() const; - - //! BoundingBox if the particle is in a complex cell. - BoundingBox bounding_box_complex(vector postfix) const; - - //! Enforce precedence between intersections and unions - void enforce_precedence(); - - //! Add parenthesis to enforce precedence - void add_parentheses(int64_t start); - - //! Remove complement operators from the expression - void remove_complement_ops(); - - //! Remove complement operators by using DeMorgan's laws - void apply_demorgan( - vector::iterator start, vector::iterator stop); - - //---------------------------------------------------------------------------- - // Private Data - - //! Definition of spatial region as Boolean expression of half-spaces - // TODO: Should this be a vector of some other type - vector expression_; - bool simple_; //!< Does the region contain only intersections? -}; - -//============================================================================== -// XML parsing helpers for nodes -//============================================================================== - -//! Parse material IDs from a 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 parse_cell_material_xml(pugi::xml_node node, int32_t cell_id); - -//! Parse temperatures in [K] from a 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 parse_cell_temperature_xml(pugi::xml_node node, int32_t cell_id); - -//! Parse densities in [g/cm³] from a 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 parse_cell_density_xml(pugi::xml_node node, int32_t cell_id); - //============================================================================== class Cell { @@ -206,7 +89,7 @@ public: //! Find the oncoming boundary of this cell. virtual std::pair distance( - Position r, Direction u, int32_t on_surface, GeometryState* p) const = 0; + Position r, Direction u, int32_t on_surface, Particle* p) const = 0; //! Write all information needed to reconstruct the cell to an HDF5 group. //! \param group_id An HDF5 group id. @@ -225,12 +108,6 @@ public: //! Get the BoundingBox for this cell. virtual BoundingBox bounding_box() const = 0; - //! Get a vector of surfaces in the cell - virtual vector surfaces() const { return vector(); } - - //! Check if the cell region expression is simple - virtual bool is_simple() const { return true; } - //---------------------------------------------------------------------------- // Accessors @@ -240,18 +117,6 @@ public: //! \return Temperature in [K] double temperature(int32_t instance = -1) const; - //! Get the density multiplier of a cell instance - //! \param[in] instance Instance index. If -1 is given, the density multiplier - //! for the first instance is returned. - //! \return Density multiplier - double density_mult(int32_t instance = -1) const; - - //! Get the density of a cell instance in g/cm3 - //! \param[in] instance Instance index. If -1 is given, the density - //! for the first instance is returned. - //! \return Density in [g/cm3] - double density(int32_t instance = -1) const; - //! Set the temperature of a cell instance //! \param[in] T Temperature in [K] //! \param[in] instance Instance index. If -1 is given, the temperature for @@ -262,18 +127,6 @@ public: void set_temperature( double T, int32_t instance = -1, bool set_contained = false); - //! Set the density of a cell instance - //! \param[in] density Density [g/cm3] - //! \param[in] instance Instance index. If -1 is given, the density - //! for all instances is set. - //! \param[in] set_contained If this cell is not filled with a material, - //! collect all contained cells with material fills and set their - //! densities. - void set_density( - double density, int32_t instance = -1, bool set_contained = false); - - int32_t n_instances() const; - //! Set the rotation matrix of a cell instance //! \param[in] rot The rotation matrix of length 3 or 9 void set_rotation(const vector& rot); @@ -295,42 +148,6 @@ public: std::unordered_map> get_contained_cells( int32_t instance = 0, Position* hint = nullptr) const; - //! Determine the material index corresponding to a specific cell instance, - //! taking into account presence of distribcell material - //! \param[in] instance of the cell - //! \return material index - int32_t material(int32_t instance) const - { - // If distributed materials are used, then each instance has its own - // material definition. If distributed materials are not used, then - // all instances used the same material stored at material_[0]. The - // presence of distributed materials is inferred from the size of - // the material_ vector being greater than one. - if (material_.size() > 1) { - return material_[instance]; - } else { - return material_[0]; - } - } - - //! Determine the temperature index corresponding to a specific cell instance, - //! taking into account presence of distribcell temperature - //! \param[in] instance of the cell - //! \return temperature index - double sqrtkT(int32_t instance) const - { - // If distributed materials are used, then each instance has its own - // temperature definition. If distributed materials are not used, then - // all instances used the same temperature stored at sqrtkT_[0]. The - // presence of distributed materials is inferred from the size of - // the sqrtkT_ vector being greater than one. - if (sqrtkT_.size() > 1) { - return sqrtkT_[instance]; - } else { - return sqrtkT_[0]; - } - } - protected: //! Determine the path to this cell instance in the geometry hierarchy //! \param[in] instance of the cell to find parent cells for @@ -344,12 +161,13 @@ protected: //! \param[in] p particle used to do a fast search for parent cells //! \return parent cells vector find_parent_cells( - int32_t instance, GeometryState& p) const; + int32_t instance, Particle& p) const; //! Determine the path to this cell instance in the geometry hierarchy //! \param[in] instance of the cell to find parent cells for //! \return parent cells - vector exhaustive_find_parent_cells(int32_t instance) const; + vector exhaustive_find_parent_cells( + int32_t instance) const; //! Inner function for retrieving contained cells void get_contained_cells_inner( @@ -360,11 +178,13 @@ public: //---------------------------------------------------------------------------- // Data members - int32_t id_; //!< Unique ID - std::string name_; //!< User-defined name - Fill type_; //!< Material, universe, or lattice - int32_t universe_; //!< Universe # this cell is in - int32_t fill_; //!< Universe # filling this cell + int32_t id_; //!< Unique ID + std::string name_; //!< User-defined name + Fill type_; //!< Material, universe, or lattice + int32_t universe_; //!< Universe # this cell is in + int32_t fill_; //!< Universe # filling this cell + int32_t n_instances_ {0}; //!< Number of instances of this cell + GeometryType geom_type_; //!< Geometric representation type (CSG, DAGMC) //! \brief Index corresponding to this cell in distribcell arrays int distribcell_index_ {C_NONE}; @@ -380,8 +200,11 @@ public: //! T. The units are sqrt(eV). vector sqrtkT_; - //! \brief Unitless density multiplier(s) within this cell. - vector density_mult_; + //! Definition of spatial region as Boolean expression of half-spaces + vector region_; + //! Reverse Polish notation for region expression + vector rpn_; + bool simple_; //!< Does the region contain only intersections? //! \brief Neighboring cells in the same universe. NeighborList neighbors_; @@ -397,9 +220,6 @@ public: vector rotation_; vector offset_; //!< Distribcell offset table - - // Right now, either CSG or DAGMC cells are used. - virtual GeometryType geom_type() const = 0; }; struct CellInstanceItem { @@ -411,38 +231,35 @@ struct CellInstanceItem { class CSGCell : public Cell { public: - //---------------------------------------------------------------------------- - // Constructors - CSGCell() = default; + CSGCell(); + explicit CSGCell(pugi::xml_node cell_node); - //---------------------------------------------------------------------------- - // Methods - vector surfaces() const override { return region_.surfaces(); } + bool contains(Position r, Direction u, int32_t on_surface) const override; - std::pair distance(Position r, Direction u, - int32_t on_surface, GeometryState* p) const override - { - return region_.distance(r, u, on_surface); - } - - bool contains(Position r, Direction u, int32_t on_surface) const override - { - return region_.contains(r, u, on_surface); - } - - BoundingBox bounding_box() const override - { - return region_.bounding_box(id_); - } + std::pair distance( + Position r, Direction u, int32_t on_surface, Particle* p) const override; void to_hdf5_inner(hid_t group_id) const override; - bool is_simple() const override { return region_.is_simple(); } - - virtual GeometryType geom_type() const override { return GeometryType::CSG; } + BoundingBox bounding_box() const override; protected: + bool contains_simple(Position r, Direction u, int32_t on_surface) const; + bool contains_complex(Position r, Direction u, int32_t on_surface) const; + BoundingBox bounding_box_simple() const; + static BoundingBox bounding_box_complex(vector rpn); + + //! Applies DeMorgan's laws to a section of the RPN + //! \param start Starting point for token modification + //! \param stop Stopping point for token modification + static void apply_demorgan( + vector::iterator start, vector::iterator stop); + + //! Removes complement operators from the RPN + //! \param rpn The rpn to remove complement operators from. + static void remove_complement_ops(vector& rpn); + //! Returns the beginning position of a parenthesis block (immediately before //! two surface tokens) in the RPN given a starting position at the end of //! that block (immediately after two surface tokens) @@ -450,9 +267,6 @@ protected: //! \param rpn The rpn being searched static vector::iterator find_left_parenthesis( vector::iterator start, const vector& rpn); - -private: - Region region_; }; //============================================================================== @@ -467,8 +281,8 @@ struct CellInstance { return index_cell == other.index_cell && instance == other.instance; } - int64_t index_cell; - int64_t instance; + gsl::index index_cell; + gsl::index instance; }; //! Structure necessary for inserting CellInstance into hashed STL data diff --git a/include/openmc/chain.h b/include/openmc/chain.h deleted file mode 100644 index e01f2a01c..000000000 --- a/include/openmc/chain.h +++ /dev/null @@ -1,108 +0,0 @@ -//! \file chain.h -//! \brief Depletion chain and associated information - -#ifndef OPENMC_CHAIN_H -#define OPENMC_CHAIN_H - -#include -#include -#include - -#include "pugixml.hpp" - -#include "openmc/angle_energy.h" // for AngleEnergy -#include "openmc/distribution.h" // for UPtrDist -#include "openmc/memory.h" // for unique_ptr -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -// Data for a nuclide in the depletion chain -//============================================================================== - -class ChainNuclide { -public: - // Types - struct Product { - std::string name; //!< Reaction product name - double branching_ratio; //!< Branching ratio - }; - - // Constructors, destructors - ChainNuclide(pugi::xml_node node); - ~ChainNuclide(); - - //! Compute the decay constant for the nuclide - //! \return Decay constant in [1/s] - double decay_constant() const { return std::log(2.0) / half_life_; } - - const Distribution* photon_energy() const { return photon_energy_.get(); } - const std::unordered_map>& reaction_products() const - { - return reaction_products_; - } - -private: - // Data members - std::string name_; //!< Name of nuclide - double half_life_ {0.0}; //!< Half-life in [s] - double decay_energy_ {0.0}; //!< Decay energy in [eV] - std::unordered_map> - reaction_products_; //!< Map of MT to reaction products - UPtrDist photon_energy_; //!< Decay photon energy distribution -}; - -//============================================================================== -// Angle-energy distribution for decay photon -//============================================================================== - -class DecayPhotonAngleEnergy : public AngleEnergy { -public: - explicit DecayPhotonAngleEnergy(const Distribution* dist) - : photon_energy_(dist) - {} - - //! Sample distribution for an angle and energy - //! \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 - 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_; -}; - -//============================================================================== -// Global variables -//============================================================================== - -namespace data { - -extern std::unordered_map chain_nuclide_map; -extern vector> chain_nuclides; - -} // namespace data - -//============================================================================== -// Non-member functions -//============================================================================== - -void read_chain_file_xml(); - -void free_memory_chain(); - -} // namespace openmc - -#endif // OPENMC_CHAIN_H diff --git a/include/openmc/collision_track.h b/include/openmc/collision_track.h deleted file mode 100644 index 208b8f6e1..000000000 --- a/include/openmc/collision_track.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef OPENMC_COLLISION_TRACK_H -#define OPENMC_COLLISION_TRACK_H - -#include - -namespace openmc { - -class Particle; - -//! Reserve space in the collision track bank according to user settings. -void collision_track_reserve_bank(); - -//! Write collision track data to disk when the bank is full or the batch ends. -void collision_track_flush_bank(); - -//! Record the current particle as a collision-track entry when applicable. -//! -//! \param particle Particle whose collision should be recorded if eligible -void collision_track_record(Particle& particle); - -} // namespace openmc - -#endif // OPENMC_COLLISION_TRACK_H diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 26b4a224c..a7362ea9e 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -5,11 +5,9 @@ #define OPENMC_CONSTANTS_H #include -#include #include #include "openmc/array.h" -#include "openmc/atomic_mass.h" #include "openmc/vector.h" #include "openmc/version.h" @@ -26,16 +24,14 @@ using double_4dvec = vector>>>; constexpr int HDF5_VERSION[] {3, 0}; // Version numbers for binary files -constexpr array VERSION_STATEPOINT {18, 2}; -constexpr array VERSION_PARTICLE_RESTART {2, 1}; -constexpr array VERSION_TRACK {3, 1}; -constexpr array VERSION_SUMMARY {6, 1}; +constexpr array VERSION_STATEPOINT {18, 0}; +constexpr array VERSION_PARTICLE_RESTART {2, 0}; +constexpr array VERSION_TRACK {3, 0}; +constexpr array VERSION_SUMMARY {6, 0}; constexpr array VERSION_VOLUME {1, 0}; constexpr array VERSION_VOXEL {2, 0}; constexpr array VERSION_MGXS_LIBRARY {1, 0}; -constexpr array VERSION_PROPERTIES {1, 1}; -constexpr array VERSION_WEIGHT_WINDOWS {1, 0}; -constexpr array VERSION_COLLISION_TRACK {1, 2}; +constexpr array VERSION_PROPERTIES {1, 0}; // ============================================================================ // ADJUSTABLE PARAMETERS @@ -54,27 +50,9 @@ constexpr double FP_PRECISION {1e-14}; constexpr double FP_REL_PRECISION {1e-5}; constexpr double FP_COINCIDENT {1e-12}; -// Coincidence tolerances -constexpr double TORUS_TOL {1e-10}; -constexpr double RADIAL_MESH_TOL {1e-10}; - // Maximum number of random samples per history constexpr int MAX_SAMPLE {100000}; -// Avg. number of hits per batch to be defined as a "small" -// source region in the random ray solver -constexpr double MIN_HITS_PER_BATCH {1.5}; - -// The minimum flux value to be considered non-zero when computing adjoint -// sources. Positive values below this cutoff will be treated as zero, so as to -// prevent extremely large adjoint source terms from being generated. -constexpr double ZERO_FLUX_CUTOFF {1e-22}; - -// The minimum macroscopic cross section value considered non-void for the -// random ray solver. Materials with any group with a cross section below this -// value will be converted to pure void. -constexpr double MINIMUM_MACRO_XS {1e-6}; - // ============================================================================ // MATH AND PHYSICAL CONSTANTS @@ -87,10 +65,10 @@ constexpr double INFTY {std::numeric_limits::max()}; // (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/). // Physical constants -constexpr double AMU_EV { - 9.3149410242e8}; // atomic mass unit energy equivalent in eV/c^2 +constexpr double MASS_NEUTRON {1.00866491595}; // mass of a neutron in amu constexpr double MASS_NEUTRON_EV { - 939.56542052e6}; // neutron mass energy equivalent in eV/c^2 + 939.56542052e6}; // mass of a neutron in eV/c^2 +constexpr double MASS_PROTON {1.007276466621}; // mass of a proton in amu constexpr double MASS_ELECTRON_EV { 0.51099895000e6}; // electron mass energy equivalent in eV/c^2 constexpr double FINE_STRUCTURE { @@ -227,7 +205,6 @@ enum ReactionType { N_XA = 207, HEATING = 301, DAMAGE_ENERGY = 444, - PHOTON_TOTAL = 501, COHERENT = 502, INCOHERENT = 504, PAIR_PROD_ELEC = 515, @@ -294,16 +271,16 @@ enum class MgxsType { // ============================================================================ // TALLY-RELATED CONSTANTS -enum class TallyResult { VALUE, SUM, SUM_SQ, SUM_THIRD, SUM_FOURTH }; +enum class TallyResult { VALUE, SUM, SUM_SQ }; -enum class TallyType { VOLUME, MESH_SURFACE, SURFACE, PULSE_HEIGHT }; +enum class TallyType { VOLUME, MESH_SURFACE, SURFACE }; 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/lib/tally.py +// _SCORES dictionary in openmc/capi/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 @@ -324,11 +301,7 @@ enum TallyScore { SCORE_INVERSE_VELOCITY = -13, // flux-weighted inverse velocity SCORE_FISS_Q_PROMPT = -14, // prompt fission Q-value SCORE_FISS_Q_RECOV = -15, // recoverable fission Q-value - SCORE_DECAY_RATE = -16, // delayed neutron precursor decay rate - SCORE_PULSE_HEIGHT = -17, // pulse-height - SCORE_IFP_TIME_NUM = -18, // IFP lifetime numerator - SCORE_IFP_BETA_NUM = -19, // IFP delayed fraction numerator - SCORE_IFP_DENOM = -20 // IFP common denominator + SCORE_DECAY_RATE = -16 // delayed neutron precursor decay rate }; // Global tally parameters @@ -337,9 +310,7 @@ enum class GlobalTally { K_COLLISION, K_ABSORPTION, K_TRACKLENGTH, LEAKAGE }; // Miscellaneous constexpr int C_NONE {-1}; - -// Default value of generation for IFP -constexpr int DEFAULT_IFP_N_GENERATION {10}; +constexpr int F90_NONE {0}; // TODO: replace usage of this with C_NONE // Interpolation rules enum class Interpolation { @@ -347,11 +318,7 @@ enum class Interpolation { lin_lin = 2, lin_log = 3, log_lin = 4, - log_log = 5, - // skip 6 b/c ENDF-6 reserves this value for - // "special one-dimensional interpolation law" - quadratic = 7, - cubic = 8 + log_log = 5 }; enum class RunMode { @@ -363,22 +330,11 @@ enum class RunMode { VOLUME }; -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, S2 }; -enum class RandomRaySolve { FORWARD, FORWARD_FOR_ADJOINT, ADJOINT }; - //============================================================================== // Geometry Constants enum class GeometryType { CSG, DAG }; -// a surface token cannot be zero due to the unsigned nature of zero for integer -// representations. This value represents no surface. -constexpr int32_t SURFACE_NONE {0}; - } // namespace openmc #endif // OPENMC_CONSTANTS_H diff --git a/include/openmc/cross_sections.h b/include/openmc/cross_sections.h index 06140a6a8..2b0473bec 100644 --- a/include/openmc/cross_sections.h +++ b/include/openmc/cross_sections.h @@ -62,11 +62,6 @@ extern vector libraries; //! libraries void read_cross_sections_xml(); -//! Read cross sections file (either XML or multigroup H5) and populate data -//! libraries -//! \param[in] root node of the cross_sections.xml -void read_cross_sections_xml(pugi::xml_node root); - //! Load nuclide and thermal scattering data from HDF5 files // //! \param[in] nuc_temps Temperatures for each nuclide in [K] diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 858636c0b..993076347 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -3,8 +3,7 @@ namespace openmc { extern "C" const bool DAGMC_ENABLED; -extern "C" const bool UWUW_ENABLED; -} // namespace openmc +} // always include the XML interface header #include "openmc/xml_interface.h" @@ -20,7 +19,7 @@ void check_dagmc_root_univ(); } // namespace openmc -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC #include "DagMC.hpp" #include "dagmcmetadata.hpp" @@ -29,12 +28,6 @@ void check_dagmc_root_univ(); #include "openmc/particle.h" #include "openmc/position.h" #include "openmc/surface.h" -#include "openmc/vector.h" - -#include // for shared_ptr, unique_ptr -#include -#include -#include // for pair class UWUW; @@ -44,20 +37,15 @@ class DAGSurface : public Surface { public: DAGSurface(std::shared_ptr dag_ptr, int32_t dag_idx); - moab::EntityHandle mesh_handle() const; - double evaluate(Position r) const override; double distance(Position r, Direction u, bool coincident) const override; Direction normal(Position r) const override; - Direction reflect( - Position r, Direction u, GeometryState* p = nullptr) const override; + Direction reflect(Position r, Direction u, Particle* p) const override; inline void to_hdf5_inner(hid_t group_id) const override {}; - virtual GeometryType geom_type() const override { return GeometryType::DAG; } - // Accessor methods - moab::DagMC* dagmc_ptr() const { return dagmc_ptr_.get(); } + const std::shared_ptr& dagmc_ptr() const { return dagmc_ptr_; } int32_t dag_index() const { return dag_index_; } private: @@ -69,21 +57,17 @@ class DAGCell : public Cell { public: DAGCell(std::shared_ptr dag_ptr, int32_t dag_idx); - moab::EntityHandle mesh_handle() const; - bool contains(Position r, Direction u, int32_t on_surface) const override; - std::pair distance(Position r, Direction u, - int32_t on_surface, GeometryState* p) const override; + std::pair distance( + Position r, Direction u, int32_t on_surface, Particle* p) const override; BoundingBox bounding_box() const override; void to_hdf5_inner(hid_t group_id) const override; - virtual GeometryType geom_type() const override { return GeometryType::DAG; } - // Accessor methods - moab::DagMC* dagmc_ptr() const { return dagmc_ptr_.get(); } + const std::shared_ptr& dagmc_ptr() const { return dagmc_ptr_; } int32_t dag_index() const { return dag_index_; } private: @@ -94,10 +78,6 @@ private: class DAGUniverse : public Universe { public: - using MaterialOverrides = std::unordered_map>; - using TemperatureOverrides = std::unordered_map>; - using DensityOverrides = std::unordered_map>; - explicit DAGUniverse(pugi::xml_node node); //! Create a new DAGMC universe @@ -116,9 +96,6 @@ 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(); @@ -139,33 +116,12 @@ public: void write_uwuw_materials_xml( const std::string& outfile = "uwuw_materials.xml") const; - //! Assign a material to a cell from uwuw material library - //! \param[in] vol_handle The DAGMC material assignment string - //! \param[in] c The OpenMC cell to which the material is assigned - void uwuw_assign_material( - moab::EntityHandle vol_handle, std::unique_ptr& c) const; - //! Assign a material to a cell based //! \param[in] mat_string The DAGMC material assignment string //! \param[in] c The OpenMC cell to which the material is assigned void legacy_assign_material( std::string mat_string, std::unique_ptr& c) const; - //! 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& c, - const MaterialOverrides& material_overrides) const; - - //! Return the index into the model cells vector for a given DAGMC volume - //! handle in the universe - //! \param[in] vol MOAB handle to the DAGMC volume set - int32_t cell_index(moab::EntityHandle vol) const; - - //! Return the index into the model surfaces vector for a given DAGMC surface - //! handle in the universe - //! \param[in] surf MOAB handle to the DAGMC surface set - int32_t surface_index(moab::EntityHandle surf) const; - //! Generate a string representing the ranges of IDs present in the DAGMC //! model. Contiguous chunks of IDs are represented as a range (i.e. 1-10). If //! there is a single ID a chunk, it will be represented as a single number @@ -173,12 +129,10 @@ public: //! string of the ID ranges for entities of dimension \p dim std::string dagmc_ids_for_dim(int dim) const; - bool find_cell(GeometryState& p) const override; + bool find_cell(Particle& p) const override; void to_hdf5(hid_t universes_group) const override; - virtual GeometryType geom_type() const override { return GeometryType::DAG; } - // Data Members std::shared_ptr dagmc_instance_; //!< DAGMC Instance for this universe @@ -188,16 +142,13 @@ public: //!< universe in OpenMC's surface vector // Accessors - moab::DagMC* dagmc_ptr() const { return dagmc_instance_.get(); } bool has_graveyard() const { return has_graveyard_; } 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(const MaterialOverrides& material_overrides, - const TemperatureOverrides& temperature_overrides, - const DensityOverrides& density_overrides); + void init_geometry(); //!< Create cells and surfaces from DAGMC entities std::string filename_; //!< Name of the DAGMC file used to create this universe @@ -217,10 +168,11 @@ private: // Non-member functions //============================================================================== -int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ); +int32_t next_cell( + DAGUniverse* dag_univ, DAGCell* cur_cell, DAGSurface* surf_xed); } // namespace openmc -#endif // OPENMC_DAGMC_ENABLED +#endif // DAGMC #endif // OPENMC_DAGMC_H diff --git a/include/openmc/distribution.h b/include/openmc/distribution.h index f319dd19d..8403f2c67 100644 --- a/include/openmc/distribution.h +++ b/include/openmc/distribution.h @@ -10,22 +10,10 @@ #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr -#include "openmc/span.h" #include "openmc/vector.h" // for vector namespace openmc { -//============================================================================== -// Helper function for computing importance weights from biased sampling -//============================================================================== - -//! Compute importance weights for biased sampling -//! \param p Unnormalized original probability vector -//! \param b Unnormalized bias probability vector -//! \return Vector of importance weights (p_norm[i] / b_norm[i]) -vector compute_importance_weights( - const vector& p, const vector& b); - //============================================================================== //! Abstract class representing a univariate probability distribution //============================================================================== @@ -33,41 +21,7 @@ vector compute_importance_weights( class Distribution { public: virtual ~Distribution() = default; - - //! Sample a value from the distribution, handling biasing automatically - //! \param seed Pseudorandom number seed pointer - //! \return (sampled value, importance weight) - virtual std::pair sample(uint64_t* seed) const; - - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - virtual double evaluate(double x) const; - - //! Return integral of distribution - //! \return Integral of distribution - virtual double integral() const { return 1.0; }; - - //! Set bias distribution - virtual void set_bias(std::unique_ptr bias) - { - bias_ = std::move(bias); - } - - const Distribution* bias() const { return bias_.get(); } - -protected: - //! Sample a value (unbiased) from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return Sampled value - virtual double sample_unbiased(uint64_t* seed) const = 0; - - //! Read bias distribution from XML - //! \param node XML node that may contain a bias child element - void read_bias_from_xml(pugi::xml_node node); - - // Biasing distribution - unique_ptr bias_; + virtual double sample(uint64_t* seed) const = 0; }; using UPtrDist = unique_ptr; @@ -77,40 +31,6 @@ using UPtrDist = unique_ptr; //! \return Unique pointer to distribution UPtrDist distribution_from_xml(pugi::xml_node node); -//============================================================================== -//! A discrete distribution index (probability mass function) -//============================================================================== - -class DiscreteIndex { -public: - DiscreteIndex() {}; - DiscreteIndex(pugi::xml_node node); - DiscreteIndex(span p); - - void assign(span p); - - //! Sample a value from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return Sampled index - size_t sample(uint64_t* seed) const; - - // Properties - const vector& prob() const { return prob_; } - const vector& alias() const { return alias_; } - double integral() const { return integral_; } - -private: - vector prob_; //!< Probability of accepting the uniformly sampled bin, - //!< mapped to alias method table - vector alias_; //!< Alias table - double integral_; //!< Integral of distribution - - //! Normalize distribution so that probabilities sum to unity - void normalize(); - - //! Initialize alias table for sampling - void init_alias(); -}; //============================================================================== //! A discrete distribution (probability mass function) @@ -119,34 +39,23 @@ private: class Discrete : public Distribution { public: explicit Discrete(pugi::xml_node node); - Discrete(const double* x, const double* p, size_t n); + Discrete(const double* x, const double* p, int n); //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer - //! \return (sampled value, sample weight) - std::pair sample(uint64_t* seed) const override; - - double integral() const override { return di_.integral(); }; - - //! Override set_bias as no-op (bias handled in constructor) - void set_bias(std::unique_ptr bias) override {} + //! \return Sampled value + double sample(uint64_t* seed) const; // Properties const vector& x() const { return x_; } - const vector& prob() const { return di_.prob(); } - const vector& alias() const { return di_.alias(); } - const vector& weight() const { return weight_; } - -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; + const vector& p() const { return p_; } private: - vector x_; //!< Possible outcomes - vector weight_; //!< Importance weights (empty if unbiased) - DiscreteIndex di_; //!< Discrete probability distribution of outcome indices + vector x_; //!< Possible outcomes + vector p_; //!< Probability of each outcome + + //! Normalize distribution so that probabilities sum to unity + void normalize(); }; //============================================================================== @@ -158,20 +67,14 @@ public: explicit Uniform(pugi::xml_node node); Uniform(double a, double b) : a_ {a}, b_ {b} {}; - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - double evaluate(double x) const override; + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const; double a() const { return a_; } double b() const { return b_; } -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: double a_; //!< Lower bound of distribution double b_; //!< Upper bound of distribution @@ -188,26 +91,19 @@ public: : offset_ {std::pow(a, n + 1)}, span_ {std::pow(b, n + 1) - offset_}, ninv_ {1 / (n + 1)} {}; - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - double evaluate(double x) const override; + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const; double a() const { return std::pow(offset_, ninv_); } double b() const { return std::pow(offset_ + span_, ninv_); } double n() const { return 1 / ninv_ - 1; } - -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: //! Store processed values in object to allow for faster sampling double offset_; //!< a^(n+1) - double span_; //!< b^(n+1) - a^(n+1) - double ninv_; //!< 1/(n+1) + double span_; //!< b^(n+1) - a^(n+1) + double ninv_; //!< 1/(n+1) }; //============================================================================== @@ -219,18 +115,12 @@ public: explicit Maxwell(pugi::xml_node node); Maxwell(double theta) : theta_ {theta} {}; - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - double evaluate(double x) const override; - - double theta() const { return theta_; } - -protected: - //! Sample a value (unbiased) from the distribution + //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample_unbiased(uint64_t* seed) const override; + double sample(uint64_t* seed) const; + + double theta() const { return theta_; } private: double theta_; //!< Factor in exponential [eV] @@ -245,66 +135,70 @@ public: explicit Watt(pugi::xml_node node); Watt(double a, double b) : a_ {a}, b_ {b} {}; - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - double evaluate(double x) const override; + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const; double a() const { return a_; } double b() const { return b_; } -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: double a_; //!< Factor in exponential [eV] double b_; //!< Factor in square root [1/eV] }; //============================================================================== -//! 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. +//! Normal distributions with form 1/2*std_dev*sqrt(pi) exp +//! (-(e-E0)/2*std_dev)^2 //============================================================================== class Normal : public Distribution { public: explicit Normal(pugi::xml_node node); - Normal(double mean_value, double std_dev, double lower = -INFTY, - double upper = INFTY); + Normal(double mean_value, double std_dev) + : mean_value_ {mean_value}, std_dev_ {std_dev} {}; - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x), accounting for truncation normalization - double evaluate(double x) const override; + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const; 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 - //! \param seed Pseudorandom number seed pointer - //! \return Sampled value - double sample_unbiased(uint64_t* seed) const override; private: - 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 + double mean_value_; //!< middle of distribution [eV] + double std_dev_; //!< standard deviation [eV] +}; - //! Compute normalization factor for truncated distribution - void compute_normalization(); +//============================================================================== +//! Muir (fusion) spectrum derived from Normal with extra params e0 is mean +//! std dev is sqrt(4*e0*kt/m) +//============================================================================== + +class Muir : public Distribution { +public: + explicit Muir(pugi::xml_node node); + Muir(double e0, double m_rat, double kt) + : e0_ {e0}, m_rat_ {m_rat}, kt_ {kt} {}; + + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const; + + double e0() const { return e0_; } + double m_rat() const { return m_rat_; } + double kt() const { return kt_; } + +private: + // example DT fusion m_rat = 5 (D = 2 + T = 3) + // ion temp = 20000 eV + // mean neutron energy 14.08e6 eV + double e0_; //!< mean neutron energy [eV] + double m_rat_; //!< ratio of reactant masses relative to atomic mass unit + double kt_; //!< ion temperature [eV] }; //============================================================================== @@ -317,30 +211,22 @@ public: Tabular(const double* x, const double* p, int n, Interpolation interp, const double* c = nullptr); - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - double evaluate(double x) const override; + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const; - // properties + // x property vector& x() { return x_; } const vector& x() const { return x_; } const vector& p() const { return p_; } Interpolation interp() const { return interp_; } - double integral() const override { return integral_; }; - -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: vector x_; //!< tabulated independent variable vector p_; //!< tabulated probability density vector c_; //!< cumulative distribution at tabulated values Interpolation interp_; //!< interpolation rule - double integral_; //!< Integral of distribution //! Initialize tabulated probability density function //! \param x Array of values for independent variable @@ -359,18 +245,12 @@ public: explicit Equiprobable(pugi::xml_node node); Equiprobable(const double* x, int n) : x_ {x, x + n} {}; - //! Evaluate probability density, f(x), at a point - //! \param x Point to evaluate f(x) - //! \return f(x) - double evaluate(double x) const override; - - const vector& x() const { return x_; } - -protected: - //! Sample a value (unbiased) from the distribution + //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample_unbiased(uint64_t* seed) const override; + double sample(uint64_t* seed) const; + + const vector& x() const { return x_; } private: vector x_; //! Possible outcomes @@ -386,91 +266,17 @@ public: //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer - //! \return (sampled value, sample weight) - std::pair sample(uint64_t* seed) const override; - - double integral() const override { return integral_; } - - //! Override set_bias as no-op (bias handled in constructor) - void set_bias(std::unique_ptr bias) 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; + double sample(uint64_t* seed) const; private: - vector distribution_; //!< Sub-distributions - vector weight_; //!< Importance weights for component selection - DiscreteIndex di_; //!< Discrete probability distribution of indices - double integral_; //!< Integral of distribution + // Storrage for probability + distribution + using DistPair = std::pair; + + vector + distribution_; //!< sub-distributions + cummulative probabilities }; -//============================================================================== -// 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 ```` 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 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 nuclide_indices, const vector& atoms); - - vector nuclide_indices_; //!< Indices of emitting nuclides in the chain - DiscreteIndex di_; //!< Discrete index for component selection - double integral_; //!< Total photon emission rate -}; } // namespace openmc diff --git a/include/openmc/distribution_angle.h b/include/openmc/distribution_angle.h index 78de70c42..efd4e5842 100644 --- a/include/openmc/distribution_angle.h +++ b/include/openmc/distribution_angle.h @@ -26,12 +26,6 @@ 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(); } diff --git a/include/openmc/distribution_energy.h b/include/openmc/distribution_energy.h index efacb9131..d8512aa45 100644 --- a/include/openmc/distribution_energy.h +++ b/include/openmc/distribution_energy.h @@ -5,7 +5,7 @@ #define OPENMC_DISTRIBUTION_ENERGY_H #include "hdf5.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/constants.h" #include "openmc/endf.h" @@ -37,7 +37,7 @@ public: //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const override; + double sample(double E, uint64_t* seed) const; private: int primary_flag_; //!< Indicator of whether the photon is a primary or @@ -58,7 +58,7 @@ public: //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const override; + double sample(double E, uint64_t* seed) const; private: double threshold_; //!< Energy threshold in lab, (A + 1)/A * |Q| @@ -79,16 +79,16 @@ public: //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const override; + double sample(double E, uint64_t* seed) const; private: //! Outgoing energy for a single incoming energy struct CTTable { Interpolation interpolation; //!< Interpolation law int n_discrete; //!< Number of of discrete energies - tensor::Tensor e_out; //!< Outgoing energies in [eV] - tensor::Tensor p; //!< Probability density - tensor::Tensor c; //!< Cumulative distribution + xt::xtensor e_out; //!< Outgoing energies in [eV] + xt::xtensor p; //!< Probability density + xt::xtensor c; //!< Cumulative distribution }; int n_region_; //!< Number of inteprolation regions @@ -110,7 +110,7 @@ public: //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const override; + double sample(double E, uint64_t* seed) const; private: Tabulated1D theta_; //!< Incoming energy dependent parameter @@ -130,7 +130,7 @@ public: //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const override; + double sample(double E, uint64_t* seed) const; private: Tabulated1D theta_; //!< Incoming energy dependent parameter @@ -150,7 +150,7 @@ public: //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const override; + double sample(double E, uint64_t* seed) const; private: Tabulated1D a_; //!< Energy-dependent 'a' parameter diff --git a/include/openmc/distribution_multi.h b/include/openmc/distribution_multi.h index a72780737..991294f79 100644 --- a/include/openmc/distribution_multi.h +++ b/include/openmc/distribution_multi.h @@ -6,7 +6,6 @@ #include "pugixml.hpp" #include "openmc/distribution.h" -#include "openmc/error.h" #include "openmc/position.h" namespace openmc { @@ -23,20 +22,10 @@ public: explicit UnitSphereDistribution(pugi::xml_node node); virtual ~UnitSphereDistribution() = default; - static unique_ptr create(pugi::xml_node node); - //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer - //! \return (sampled Direction, sample weight) - virtual std::pair 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"); - } + //! \return Direction sampled + virtual Direction sample(uint64_t* seed) const = 0; Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction }; @@ -52,35 +41,14 @@ public: //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer - //! \return (sampled Direction, sample weight) - std::pair sample(uint64_t* seed) const override; - - //! Sample a direction and return evaluation of the PDF for biased sampling. - //! Note that bias distributions are intended to return unit-weight samples. - //! \param seed Pseudorandom number seed points - //! \return (sampled Direction, value of the PDF at this Direction) - std::pair 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; + //! \return Direction sampled + Direction sample(uint64_t* seed) const; // Observing pointers Distribution* mu() const { return mu_.get(); } Distribution* phi() const { return phi_.get(); } private: - //! Common sampling implementation - //! \param seed Pseudorandom number seed pointer - //! \param return_pdf If true, return PDF evaluation; if false, return - //! importance weight - //! \return (sampled Direction, weight or PDF value) - std::pair sample_impl( - uint64_t* seed, bool return_pdf) const; - - Direction v_ref_ {1.0, 0.0, 0.0}; //!< reference direction - Direction w_ref_; UPtrDist mu_; //!< Distribution of polar angle UPtrDist phi_; //!< Distribution of azimuthal angle }; @@ -94,29 +62,11 @@ Direction isotropic_direction(uint64_t* seed); class Isotropic : public UnitSphereDistribution { public: Isotropic() {}; - explicit Isotropic(pugi::xml_node node); //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer - //! \return (sampled direction, sample weight) - std::pair 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 bias) - { - bias_ = std::move(bias); - } - - const PolarAzimuthal* bias() const { return bias_.get(); } - -protected: - // Biasing distribution - unique_ptr bias_; + //! \return Sampled direction + Direction sample(uint64_t* seed) const; }; //============================================================================== @@ -131,8 +81,8 @@ public: //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer - //! \return (sampled direction, sample weight) - std::pair sample(uint64_t* seed) const override; + //! \return Sampled direction + Direction sample(uint64_t* seed) const; }; using UPtrAngle = unique_ptr; diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index 663cf5568..5e426b878 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -4,9 +4,7 @@ #include "pugixml.hpp" #include "openmc/distribution.h" -#include "openmc/mesh.h" #include "openmc/position.h" -#include "openmc/span.h" namespace openmc { @@ -19,11 +17,7 @@ public: virtual ~SpatialDistribution() = default; //! Sample a position from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - virtual std::pair sample(uint64_t* seed) const = 0; - - static unique_ptr create(pugi::xml_node node); + virtual Position sample(uint64_t* seed) const = 0; }; //============================================================================== @@ -36,8 +30,8 @@ public: //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; + //! \return Sampled position + Position sample(uint64_t* seed) const; // Observer pointers Distribution* x() const { return x_.get(); } @@ -60,25 +54,19 @@ public: //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; + //! \return Sampled position + Position sample(uint64_t* seed) const; Distribution* r() const { return r_.get(); } 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 - 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 + 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 }; //============================================================================== @@ -91,8 +79,8 @@ public: //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; + //! \return Sampled position + Position sample(uint64_t* seed) const; Distribution* r() const { return r_.get(); } Distribution* cos_theta() const { return cos_theta_.get(); } @@ -106,66 +94,6 @@ private: Position origin_; //!< Cartesian coordinates of the sphere center }; -//============================================================================== -//! Distribution of points within a mesh -//============================================================================== - -class MeshSpatial : public SpatialDistribution { -public: - explicit MeshSpatial(pugi::xml_node node); - explicit MeshSpatial(int32_t mesh_id, span strengths); - - //! Sample a position from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; - - //! Sample the mesh for an element and position within that element - //! \param seed Pseudorandom number seed pointer - //! \return Sampled element index and position within that element - std::pair sample_mesh(uint64_t* seed) const; - - //! Sample a mesh element - //! \param seed Pseudorandom number seed pointer - //! \return Sampled element index - int32_t sample_element_index(uint64_t* seed) const; - - //! For unstructured meshes, ensure that elements are all linear tetrahedra - void check_element_types() const; - - // Accessors - const Mesh* mesh() const { return model::meshes.at(mesh_idx_).get(); } - int32_t n_sources() const { return this->mesh()->n_bins(); } - - double total_strength() { return this->elem_idx_dist_.integral(); } - -private: - int32_t mesh_idx_ {C_NONE}; - DiscreteIndex elem_idx_dist_; //!< Distribution of mesh element indices - vector weight_; //!< Importance weights (empty if unbiased) -}; - -//============================================================================== -//! Distribution of points -//============================================================================== - -class PointCloud : public SpatialDistribution { -public: - explicit PointCloud(pugi::xml_node node); - explicit PointCloud( - std::vector point_cloud, span strengths); - - //! Sample a position from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; - -private: - std::vector point_cloud_; - DiscreteIndex point_idx_dist_; //!< Distribution of Position indices - vector weight_; //!< Importance weights (empty if unbiased) -}; - //============================================================================== //! Uniform distribution of points over a box //============================================================================== @@ -173,12 +101,11 @@ private: class SpatialBox : public SpatialDistribution { public: explicit SpatialBox(pugi::xml_node node, bool fission = false); - SpatialBox(Position lower_left, Position upper_right, bool fission = false); //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; + //! \return Sampled position + Position sample(uint64_t* seed) const; // Properties bool only_fissionable() const { return only_fissionable_; } @@ -203,8 +130,8 @@ public: //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer - //! \return Sampled (position, importance weight) - std::pair sample(uint64_t* seed) const override; + //! \return Sampled position + Position sample(uint64_t* seed) const; Position r() const { return r_; } diff --git a/include/openmc/eigenvalue.h b/include/openmc/eigenvalue.h index 438747676..b456fee21 100644 --- a/include/openmc/eigenvalue.h +++ b/include/openmc/eigenvalue.h @@ -6,7 +6,7 @@ #include // for int64_t -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include #include "openmc/array.h" @@ -24,7 +24,7 @@ namespace simulation { extern double keff_generation; //!< Single-generation k on each processor extern array k_sum; //!< Used to reduce sum and sum_sq extern vector entropy; //!< Shannon entropy at each generation -extern tensor::Tensor source_frac; //!< Source fraction for UFS +extern xt::xtensor source_frac; //!< Source fraction for UFS } // namespace simulation diff --git a/include/openmc/endf.h b/include/openmc/endf.h index 34fee9758..e580874b4 100644 --- a/include/openmc/endf.h +++ b/include/openmc/endf.h @@ -33,13 +33,6 @@ 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 //============================================================================== @@ -60,10 +53,6 @@ public: //! \param[in] dset Dataset containing coefficients explicit Polynomial(hid_t dset); - //! Construct polynomial from coefficients - //! \param[in] coef Polynomial coefficients - explicit Polynomial(vector coef) : coef_(coef) {} - //! Evaluate the polynomials //! \param[in] x independent variable //! \return Polynomial evaluated at x diff --git a/include/openmc/error.h b/include/openmc/error.h index 1f6e15f49..d73795aee 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -64,14 +64,14 @@ void write_message( int level, const std::string& message, const Params&... fmt_args) { if (settings::verbosity >= level) { - write_message(fmt::format(fmt::runtime(message), fmt_args...)); + write_message(fmt::format(message, fmt_args...)); } } template void write_message(const std::string& message, const Params&... fmt_args) { - write_message(fmt::format(fmt::runtime(message), fmt_args...)); + write_message(fmt::format(message, fmt_args...)); } #ifdef OPENMC_MPI diff --git a/include/openmc/event.h b/include/openmc/event.h index 48a009f2b..2d215a10e 100644 --- a/include/openmc/event.h +++ b/include/openmc/event.h @@ -112,19 +112,6 @@ 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& shared_secondary_bank); - } // namespace openmc #endif // OPENMC_EVENT_H diff --git a/include/openmc/file_utils.h b/include/openmc/file_utils.h index db6564034..f9c23468d 100644 --- a/include/openmc/file_utils.h +++ b/include/openmc/file_utils.h @@ -1,35 +1,19 @@ #ifndef OPENMC_FILE_UTILS_H #define OPENMC_FILE_UTILS_H +#include // for ifstream #include namespace openmc { -// NOTE: This is a thin wrapper over std::filesystem because we -// pass strings around a lot. Objects like settings::path_input -// are extern std::string to play with other libraries and languages - -//! Determine if a path is a directory -//! \param[in] path Path to check -//! \return Whether the path is a directory -bool dir_exists(const std::string& path); - //! Determine if a file exists //! \param[in] filename Path to file //! \return Whether file exists -bool file_exists(const std::string& filename); - -//! Determine directory containing given file -//! \param[in] filename Path to file -//! \return Name of directory containing file excluding the final directory -//! separator -std::string dir_name(const std::string& filename); - -// Gets the file extension of whatever string is passed in. This is defined as -// a sequence of strictly alphanumeric characters which follow the last period, -// i.e. at least one alphabet character is present, and zero or more numbers. -// If such a sequence of characters is not found, an empty string is returned. -std::string get_file_extension(const std::string& filename); +inline bool file_exists(const std::string& filename) +{ + std::ifstream s {filename}; + return s.good(); +} } // namespace openmc diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 43cf9bb58..001e58c4c 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -3,46 +3,15 @@ #include #include -#include -#include #include "openmc/array.h" #include "openmc/constants.h" -#include "openmc/random_ray/source_region.h" // For hash_combine #include "openmc/vector.h" namespace openmc { class BoundaryInfo; -class GeometryState; - -//============================================================================== -//! OverlapKey to store cell and universe data of a single overlap, along with -//! a functor for hashing an OverlapKey into an unordered_map. -//============================================================================== - -struct OverlapKey { - int universe_id; - int cell1_id; - int cell2_id; - - bool operator==(const OverlapKey& other) const - { - return universe_id == other.universe_id && cell1_id == other.cell1_id && - cell2_id == other.cell2_id; - } -}; - -struct OverlapKeyHash { - std::size_t operator()(const OverlapKey& k) const - { - size_t seed = 0; - hash_combine(seed, k.universe_id); - hash_combine(seed, k.cell1_id); - hash_combine(seed, k.cell2_id); - return seed; - } -}; +class Particle; //============================================================================== // Global variables @@ -55,10 +24,6 @@ extern "C" int n_coord_levels; //!< Number of CSG coordinate levels extern vector overlap_check_count; -// Overlap data structures get cleared every slice_data run -extern vector overlap_keys; -extern std::unordered_map overlap_key_index; - } // namespace model //============================================================================== @@ -73,7 +38,8 @@ inline bool coincident(double d1, double d2) //============================================================================== //! Check for overlapping cells at a particle's position. //============================================================================== -int check_cell_overlap(GeometryState& p, bool error = true); + +bool check_cell_overlap(Particle& p, bool error = true); //============================================================================== //! Get the cell instance for a particle at the specified universe level @@ -84,7 +50,7 @@ int check_cell_overlap(GeometryState& p, bool error = true); //! should be computed. \return The instance of the cell at the specified level. //============================================================================== -int cell_instance_at_level(const GeometryState& p, int level); +int cell_instance_at_level(const Particle& p, int level); //============================================================================== //! Locate a particle in the geometry tree and set its geometry data fields. @@ -94,22 +60,20 @@ int cell_instance_at_level(const GeometryState& p, int level); //! \return True if the particle's location could be found and ascribed to a //! valid geometry coordinate stack. //============================================================================== -bool exhaustive_find_cell(GeometryState& p, bool verbose = false); -bool neighbor_list_find_cell( - GeometryState& p, bool verbose = false); // Only usable on surface crossings +bool exhaustive_find_cell(Particle& p); +bool neighbor_list_find_cell(Particle& p); // Only usable on surface crossings //============================================================================== //! Move a particle into a new lattice tile. //============================================================================== -void cross_lattice( - GeometryState& p, const BoundaryInfo& boundary, bool verbose = false); +void cross_lattice(Particle& p, const BoundaryInfo& boundary); //============================================================================== //! Find the next boundary a particle will intersect. //============================================================================== -BoundaryInfo distance_to_boundary(GeometryState& p); +BoundaryInfo distance_to_boundary(Particle& p); } // namespace openmc diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 4dafdea5c..b248d491a 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -10,21 +10,17 @@ #include #include "openmc/vector.h" -#include "openmc/xml_interface.h" namespace openmc { namespace model { +extern std::unordered_map> + universe_cell_counts; extern std::unordered_map universe_level_counts; } // namespace model -//! Read geometry from XML file void read_geometry_xml(); -//! Read geometry from XML node -//! \param[in] root node of geometry XML element -void read_geometry_xml(pugi::xml_node root); - //============================================================================== //! Replace Universe, Lattice, and Material IDs with indices. //============================================================================== @@ -37,12 +33,6 @@ void adjust_indices(); void assign_temperatures(); -//============================================================================== -//! Finalize densities (compute density multipliers). -//============================================================================== - -void finalize_cell_densities(); - //============================================================================== //! \brief Obtain a list of temperatures that each nuclide/thermal scattering //! table appears at in the model. Later, this list is used to determine the @@ -84,13 +74,15 @@ void prepare_distribcell( const std::vector* user_distribcells = nullptr); //============================================================================== -//! Recursively search through the geometry and count universe instances. +//! Recursively search through the geometry and count cell instances. //! -//! This function will update Universe.n_instances_ for each -//! universe in the geometry. +//! This function will update the Cell::n_instances value for each cell in the +//! geometry. +//! \param univ_indx The index of the universe to begin searching from (probably +//! the root universe). //============================================================================== -void count_universe_instances(); +void count_cell_instances(int32_t univ_indx); //============================================================================== //! Recursively search through universes and count universe instances. @@ -128,14 +120,6 @@ std::string distribcell_path( int maximum_levels(int32_t univ); -//============================================================================== -//! Check whether or not a universe is the root universe using its ID. -//! \param univ_id The ID of the universe to check. -//! \return Whether or not it is the root universe. -//============================================================================== - -bool is_root_universe(int32_t univ_id); - //============================================================================== //! Deallocates global vectors and maps for cells, universes, and lattices. //============================================================================== diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 93e4bfc82..0092c08f8 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -11,7 +11,8 @@ #include "hdf5.h" #include "hdf5_hl.h" -#include "openmc/tensor.h" +#include "xtensor/xadapt.hpp" +#include "xtensor/xarray.hpp" #include "openmc/array.h" #include "openmc/error.h" @@ -99,8 +100,8 @@ void read_llong(hid_t obj_id, const char* name, long long* buffer, bool indep); void read_string( hid_t obj_id, const char* name, size_t slen, char* buffer, bool indep); -void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - hsize_t n_results, double* results); +void read_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results); void write_attr_double(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, const double* buffer); void write_attr_int(hid_t obj_id, int ndim, const hsize_t* dims, @@ -113,9 +114,9 @@ void write_int(hid_t group_id, int ndim, const hsize_t* dims, const char* name, void write_llong(hid_t group_id, int ndim, const hsize_t* dims, const char* name, const long long* buffer, bool indep); void write_string(hid_t group_id, int ndim, const hsize_t* dims, size_t slen, - const char* name, const char* buffer, bool indep); -void write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - hsize_t n_results, const double* results); + const char* name, char const* buffer, bool indep); +void write_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, const double* results); } // extern "C" //============================================================================== @@ -165,19 +166,24 @@ void read_attribute(hid_t obj_id, const char* name, vector& vec) read_attr(obj_id, name, H5TypeMap::type_id, vec.data()); } -// Tensor version +// Generic array version template -void read_attribute(hid_t obj_id, const char* name, tensor::Tensor& tensor) +void read_attribute(hid_t obj_id, const char* name, xt::xarray& arr) { - // Get shape of attribute + // Get shape of attribute array auto shape = attribute_shape(obj_id, name); - // Resize tensor and read data directly - vector tshape(shape.begin(), shape.end()); - tensor.resize(tshape); + // Allocate new array to read data into + std::size_t size = 1; + for (const auto x : shape) + size *= x; + vector buffer(size); // Read data from attribute - read_attr(obj_id, name, H5TypeMap::type_id, tensor.data()); + read_attr(obj_id, name, H5TypeMap::type_id, buffer.data()); + + // Adapt array into xarray + arr = xt::adapt(buffer, shape); } // overload for std::string @@ -284,34 +290,63 @@ void read_dataset( } template -void read_dataset(hid_t dset, tensor::Tensor& tensor, bool indep = false) +void read_dataset(hid_t dset, xt::xarray& arr, bool indep = false) { // Get shape of dataset vector shape = object_shape(dset); - // Resize tensor and read data directly - vector tshape(shape.begin(), shape.end()); - tensor.resize(tshape); + // Allocate space in the array to read data into + std::size_t size = 1; + for (const auto x : shape) + size *= x; + arr.resize(shape); - // Read data from dataset + // Read data from attribute read_dataset_lowlevel( - dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, tensor.data()); + dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, arr.data()); } template<> void read_dataset( - hid_t dset, tensor::Tensor>& tensor, bool indep); + hid_t dset, xt::xarray>& arr, bool indep); template void read_dataset( - hid_t obj_id, const char* name, tensor::Tensor& tensor, bool indep = false) + hid_t obj_id, const char* name, xt::xarray& arr, bool indep = false) { - // Open dataset and read tensor + // Open dataset and read array hid_t dset = open_dataset(obj_id, name); - read_dataset(dset, tensor, indep); + read_dataset(dset, arr, indep); close_dataset(dset); } +template +void read_dataset( + hid_t obj_id, const char* name, xt::xtensor& arr, bool indep = false) +{ + // Open dataset and read array + hid_t dset = open_dataset(obj_id, name); + + // Get shape of dataset + vector hsize_t_shape = object_shape(dset); + close_dataset(dset); + + // cast from hsize_t to size_t + vector shape(hsize_t_shape.size()); + for (int i = 0; i < shape.size(); i++) { + shape[i] = static_cast(hsize_t_shape[i]); + } + + // Allocate new xarray to read data into + xt::xarray 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) @@ -323,22 +358,31 @@ inline void read_dataset( r.z = x[2]; } -template +template inline void read_dataset_as_shape( - hid_t obj_id, const char* name, tensor::Tensor& tensor, bool indep = false) + hid_t obj_id, const char* name, xt::xtensor& arr, bool indep = false) { hid_t dset = open_dataset(obj_id, name); - // Read data directly into pre-shaped tensor + // Allocate new array to read data into + std::size_t size = 1; + for (const auto x : arr.shape()) + size *= x; + vector buffer(size); + + // Read data from attribute read_dataset_lowlevel( - dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, tensor.data()); + dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, buffer.data()); + + // Adapt into xarray + arr = xt::adapt(buffer, arr.shape()); close_dataset(dset); } -template -inline void read_nd_tensor(hid_t obj_id, const char* name, - tensor::Tensor& result, bool must_have = false) +template +inline void read_nd_vector(hid_t obj_id, const char* name, + xt::xtensor& result, bool must_have = false) { if (object_exists(obj_id, name)) { read_dataset_as_shape(obj_id, name, result, true); @@ -452,16 +496,12 @@ inline void write_dataset( false, buffer.data()); } -// 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 and StaticTensor2D. -template>::value>> -inline void write_dataset(hid_t obj_id, const char* name, const Container& arr) +// Template for xarray, xtensor, etc. +template +inline void write_dataset( + hid_t obj_id, const char* name, const xt::xcontainer& arr) { - using T = typename std::decay_t::value_type; + using T = typename D::value_type; auto s = arr.shape(); vector dims {s.cbegin(), s.cend()}; write_dataset_lowlevel(obj_id, dims.size(), dims.data(), name, diff --git a/include/openmc/ifp.h b/include/openmc/ifp.h deleted file mode 100644 index 2b751d66f..000000000 --- a/include/openmc/ifp.h +++ /dev/null @@ -1,222 +0,0 @@ -#ifndef OPENMC_IFP_H -#define OPENMC_IFP_H - -#include "openmc/message_passing.h" -#include "openmc/particle.h" -#include "openmc/particle_data.h" -#include "openmc/settings.h" - -#include // for copy - -namespace openmc { - -//! Check the value of the IFP parameter for beta effective or both. -//! -//! \return true if "BetaEffective" or "Both", false otherwise. -bool is_beta_effective_or_both(); - -//! Check the value of the IFP parameter for generation time or both. -//! -//! \return true if "GenerationTime" or "Both", false otherwise. -bool is_generation_time_or_both(); - -//! Resize IFP vectors -//! -//! \param[in,out] delayed_groups List of delayed group numbers -//! \param[in,out] lifetimes List of lifetimes -//! \param[in] n Dimension to resize vectors -template -void resize_ifp_data(vector& delayed_groups, vector& lifetimes, int64_t n) -{ - if (is_beta_effective_or_both()) { - delayed_groups.resize(n); - } - if (is_generation_time_or_both()) { - lifetimes.resize(n); - } -} - -//! Update a list of values by adding a new value if the size -//! of the list can accomodate the new value or by shifting all -//! values to the left (removing the first value of the list -//! and adding the new value at the end of the list). -//! -//! \param[in] value Value to add to the list -//! \param[in] data Initial version of the list -//! \return Updated list -template -vector _ifp(const T& value, const vector& data) -{ - vector updated; - size_t source_idx = data.size(); - - if (source_idx < settings::ifp_n_generation) { - updated.resize(source_idx + 1); - for (size_t i = 0; i < source_idx; i++) { - updated[i] = data[i]; - } - updated[source_idx] = value; - } else if (source_idx == settings::ifp_n_generation) { - updated.resize(source_idx); - for (size_t i = 0; i < source_idx - 1; i++) { - updated[i] = data[i + 1]; - } - updated[source_idx - 1] = value; - } - return updated; -} - -//! \brief Iterated Fission Probability (IFP) method. -//! -//! Add the IFP information in the IFP banks using the same index -//! as the one used to append the fission site to the fission bank. -//! The information stored are the delayed group number and lifetime -//! of the neutron that created the fission event. -//! Multithreading protection is guaranteed by the index returned by the -//! thread_safe_append call in physics.cpp. -//! -//! \param[in] p Particle -//! \param[in] idx Bank index from the thread_safe_append call in physics.cpp -void ifp(const Particle& p, int64_t idx); - -//! Resize the IFP banks used in the simulation -void resize_simulation_ifp_banks(); - -//! Retrieve IFP data from the IFP fission banks. -//! -//! \param[in] i_bank Index in the fission banks -//! \param[in,out] delayed_groups Delayed group numbers -//! \param[in,out] lifetimes Lifetimes lists -void copy_ifp_data_from_fission_banks( - int i_bank, vector& delayed_groups, vector& lifetimes); - -#ifdef OPENMC_MPI - -//! Deserialization information for transfer of IFP data using MPI -struct DeserializationInfo { - int64_t index_local; //!< local index - int64_t n; //!< number of sites sent -}; - -//! Broadcast the number of generation determined by the size of the first -//! element on the first processor. -//! -//! \param[in] n_generation Number of generations -//! \param[in] delayed_groups List of delayed group numbers lists -//! \param[in] lifetimes List of lifetimes lists -void broadcast_ifp_n_generation(int& n_generation, - const vector>& delayed_groups, - const vector>& lifetimes); - -//! Send IFP data using MPI. -//! -//! \param[in] idx Index of the first site -//! \param[in] n Number of sites to send -//! \param[in] n_generation Number of generations -//! \param[in] neighbor Index of the neighboring processor -//! \param[in] requests MPI requests -//! \param[in] data List of data lists -//! \param[out] send_data data buffer -template -void send_ifp_info(int64_t idx, int64_t n, int n_generation, int neighbor, - vector& requests, const vector>& data, - vector& send_data) -{ - // Copy data in buffer - for (int i = idx; i < idx + n; i++) { - std::copy( - data[i].begin(), data[i].end(), send_data.begin() + i * n_generation); - } - - // Send data - requests.emplace_back(); - MPI_Datatype datatype = mpi::MPITypeMap::mpi_type; - MPI_Isend(&send_data[n_generation * idx], n_generation * static_cast(n), - datatype, neighbor, mpi::rank, mpi::intracomm, &requests.back()); -} - -//! Receive IFP data using MPI. -//! -//! \param[in] idx Index of the first site -//! \param[in] n Number of sites to receive -//! \param[in] n_generation Number of generations -//! \param[in] neighbor Index of the neighboring processor -//! \param[in] requests MPI requests -//! \param[in] data data buffer -//! \param[out] deserialization Information to deserialize the received data -template -void receive_ifp_data(int64_t idx, int64_t n, int n_generation, int neighbor, - vector& requests, vector& data, - vector& deserialization) -{ - requests.emplace_back(); - MPI_Datatype datatype = mpi::MPITypeMap::mpi_type; - MPI_Irecv(&data[n_generation * idx], n_generation * static_cast(n), - datatype, neighbor, neighbor, mpi::intracomm, &requests.back()); - - // Deserialization info to reconstruct data later - DeserializationInfo info = {idx, n}; - deserialization.push_back(info); -} - -//! Copy partial IFP data from local lists to source banks. -//! -//! \param[in] idx Index of the first site -//! \param[in] n Number of sites to copy -//! \param[in] i_bank Index in the IFP source banks -//! \param[in] delayed_groups List of delayed group numbers lists -//! \param[in] lifetimes List of lifetimes lists -void copy_partial_ifp_data_to_source_banks(int64_t idx, int n, int64_t i_bank, - const vector>& delayed_groups, - const vector>& lifetimes); - -//! Deserialize IFP information received using MPI and store it in -//! the IFP source banks. -//! -//! \param[in] n_generation Number of generations -//! \param[in] data data to deserialize -//! \param[in] bank bank to store data -//! \param[out] deserialization Information to deserialize the received data -template -void deserialize_ifp_info(int n_generation, const vector& data, - vector>& bank, const vector& deserialization) -{ - for (auto info : deserialization) { - int64_t index_local = info.index_local; - int64_t n = info.n; - - for (int i = index_local; i < index_local + n; i++) { - vector data_received( - data.begin() + n_generation * i, data.begin() + n_generation * (i + 1)); - bank[i] = data_received; - } - } -} - -#endif - -//! Copy IFP temporary vectors to source banks. -//! -//! \param[in] delayed_groups List of delayed group numbers lists -//! \param[in] lifetimes List of lifetimes lists -void copy_complete_ifp_data_to_source_banks( - const vector>& delayed_groups, - const vector>& lifetimes); - -//! Allocate temporary vectors for IFP data. -//! -//! \param[in,out] delayed_groups List of delayed group numbers lists -//! \param[in,out] lifetimes List of delayed group numbers lists -void allocate_temporary_vector_ifp( - vector>& delayed_groups, vector>& lifetimes); - -//! Copy local IFP data to IFP fission banks. -//! -//! \param[in] delayed_groups_ptr Pointer to delayed group numbers -//! \param[in] lifetimes_ptr Pointer to lifetimes -void copy_ifp_data_to_fission_banks( - const vector* delayed_groups_ptr, const vector* lifetimes_ptr); - -} // namespace openmc - -#endif // OPENMC_IFP_H diff --git a/include/openmc/initialize.h b/include/openmc/initialize.h index a9b8b336f..869be4441 100644 --- a/include/openmc/initialize.h +++ b/include/openmc/initialize.h @@ -1,8 +1,6 @@ #ifndef OPENMC_INITIALIZE_H #define OPENMC_INITIALIZE_H -#include - #ifdef OPENMC_MPI #include "mpi.h" #endif @@ -13,13 +11,7 @@ int parse_command_line(int argc, char* argv[]); #ifdef OPENMC_MPI void initialize_mpi(MPI_Comm intracomm); #endif - -//! Read material, geometry, settings, and tallies from a single XML file -bool read_model_xml(); -//! Read inputs from separate XML files -void read_separate_xml_files(); -//! Write some output that occurs right after initialization -void initial_output(); +void read_input_xml(); } // namespace openmc diff --git a/include/openmc/interpolate.h b/include/openmc/interpolate.h deleted file mode 100644 index 31ae8b0e3..000000000 --- a/include/openmc/interpolate.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef OPENMC_INTERPOLATE_H -#define OPENMC_INTERPOLATE_H - -#include -#include - -#include "openmc/error.h" -#include "openmc/search.h" -#include "openmc/span.h" - -namespace openmc { - -inline double interpolate_lin_lin( - double x0, double x1, double y0, double y1, double x) -{ - return y0 + (x - x0) / (x1 - x0) * (y1 - y0); -} - -inline double interpolate_lin_log( - double x0, double x1, double y0, double y1, double x) -{ - return y0 + std::log(x / x0) / std::log(x1 / x0) * (y1 - y0); -} - -inline double interpolate_log_lin( - double x0, double x1, double y0, double y1, double x) -{ - return y0 * std::exp((x - x0) / (x1 - x0) * std::log(y1 / y0)); -} - -inline double interpolate_log_log( - double x0, double x1, double y0, double y1, double x) -{ - double f = std::log(x / x0) / std::log(x1 / x0); - return y0 * std::exp(f * std::log(y1 / y0)); -} - -inline double interpolate_lagrangian( - span xs, span ys, int idx, double x, int order) -{ - double output {0.0}; - - for (int i = 0; i < order + 1; i++) { - double numerator {1.0}; - double denominator {1.0}; - for (int j = 0; j < order + 1; j++) { - if (i == j) - continue; - numerator *= (x - xs[idx + j]); - denominator *= (xs[idx + i] - xs[idx + j]); - } - output += (numerator / denominator) * ys[idx + i]; - } - - return output; -} - -inline double interpolate(span xs, span ys, - double x, Interpolation i = Interpolation::lin_lin) -{ - int idx = lower_bound_index(xs.begin(), xs.end(), x); - - if (idx == xs.size()) - idx--; - - switch (i) { - case Interpolation::histogram: - return ys[idx]; - case Interpolation::lin_lin: - return interpolate_lin_lin(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); - case Interpolation::log_log: - return interpolate_log_log(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); - case Interpolation::lin_log: - return interpolate_lin_log(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); - case Interpolation::log_lin: - return interpolate_log_lin(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); - case Interpolation::quadratic: - // move back one point if x is in the last interval of the x-grid - if (idx == xs.size() - 2 && idx > 0) - idx--; - return interpolate_lagrangian(xs, ys, idx, x, 2); - case Interpolation::cubic: - // if x is not in the first interval of the x-grid, move back one - if (idx > 0) - idx--; - // if the index was the last interval of the x-grid, move it back one more - if (idx == xs.size() - 3) - idx--; - return interpolate_lagrangian(xs, ys, idx, x, 3); - default: - fatal_error("Unsupported interpolation"); - } -} - -} // namespace openmc - -#endif diff --git a/include/openmc/lattice.h b/include/openmc/lattice.h index ca40bbc2a..a2411467d 100644 --- a/include/openmc/lattice.h +++ b/include/openmc/lattice.h @@ -56,14 +56,13 @@ public: virtual ~Lattice() {} - virtual const int32_t& operator[](const array& i_xyz) = 0; + virtual int32_t const& operator[](array const& i_xyz) = 0; virtual LatticeIter begin(); - virtual LatticeIter end(); - virtual int32_t& back(); + LatticeIter end(); virtual ReverseLatticeIter rbegin(); - virtual ReverseLatticeIter rend(); + ReverseLatticeIter rend(); //! Convert internal universe values from IDs to indices using universe_map. void adjust_indices(); @@ -71,19 +70,18 @@ public: //! Allocate offset table for distribcell. void allocate_offset_table(int n_maps) { - offsets_.resize(n_maps * universes_.size()); - std::fill(offsets_.begin(), offsets_.end(), C_NONE); + offsets_.resize(n_maps * universes_.size(), C_NONE); } //! Populate the distribcell offset tables. - int32_t fill_offset_table(int32_t target_univ_id, int map, + int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map, std::unordered_map& univ_count_memo); //! \brief Check lattice indices. //! \param i_xyz[3] The indices for a lattice tile. //! \return true if the given indices fit within the lattice bounds. False //! otherwise. - virtual bool are_valid_indices(const array& i_xyz) const = 0; + virtual bool are_valid_indices(array const& i_xyz) const = 0; //! \brief Find the next lattice surface crossing //! \param r A 3D Cartesian coordinate. @@ -113,14 +111,6 @@ public: virtual Position get_local_position( Position r, const array& 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& 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 @@ -135,7 +125,7 @@ public: //! \param i_xyz[3] The indices for a lattice tile. //! \return Distribcell offset i.e. the largest instance number for the target //! cell found in the geometry tree under this lattice tile. - virtual int32_t& offset(int map, const array& i_xyz) = 0; + virtual int32_t& offset(int map, array const& i_xyz) = 0; //! \brief Get the distribcell offset for a lattice tile. //! \param The map index for the target cell. @@ -177,12 +167,12 @@ public: LatticeIter& operator++() { - while (indx_ < lat_.end().indx_) { + while (indx_ < lat_.universes_.size()) { ++indx_; if (lat_.is_valid_index(indx_)) return *this; } - indx_ = lat_.end().indx_; + indx_ = lat_.universes_.size(); return *this; } @@ -200,7 +190,7 @@ public: ReverseLatticeIter& operator++() { - while (indx_ > lat_.begin().indx_ - 1) { + while (indx_ > -1) { --indx_; if (lat_.is_valid_index(indx_)) return *this; @@ -216,31 +206,26 @@ class RectLattice : public Lattice { public: explicit RectLattice(pugi::xml_node lat_node); - const int32_t& operator[](const array& i_xyz) override; + int32_t const& operator[](array const& i_xyz); - bool are_valid_indices(const array& i_xyz) const override; + bool are_valid_indices(array const& i_xyz) const; std::pair> distance( - Position r, Direction u, const array& i_xyz) const override; + Position r, Direction u, const array& i_xyz) const; - void get_indices( - Position r, Direction u, array& result) const override; + void get_indices(Position r, Direction u, array& result) const; - int get_flat_index(const array& i_xyz) const override; + int get_flat_index(const array& i_xyz) const; - Position get_local_position( - Position r, const array& i_xyz) const override; + Position get_local_position(Position r, const array& i_xyz) const; - Direction get_normal( - const array& i_xyz, bool& is_valid) const override; + int32_t& offset(int map, array const& i_xyz); - int32_t& offset(int map, const array& i_xyz) override; + int32_t offset(int map, int indx) const; - int32_t offset(int map, int indx) const override; + std::string index_to_string(int indx) const; - std::string index_to_string(int indx) const override; - - void to_hdf5_inner(hid_t group_id) const override; + void to_hdf5_inner(hid_t group_id) const; private: array n_cells_; //!< Number of cells along each axis @@ -254,43 +239,32 @@ class HexLattice : public Lattice { public: explicit HexLattice(pugi::xml_node lat_node); - const int32_t& operator[](const array& i_xyz) override; + int32_t const& operator[](array const& i_xyz); - LatticeIter begin() override; + LatticeIter begin(); - ReverseLatticeIter rbegin() override; + ReverseLatticeIter rbegin(); - LatticeIter end() override; - - int32_t& back() override; - - ReverseLatticeIter rend() override; - - bool are_valid_indices(const array& i_xyz) const override; + bool are_valid_indices(array const& i_xyz) const; std::pair> distance( - Position r, Direction u, const array& i_xyz) const override; + Position r, Direction u, const array& i_xyz) const; - void get_indices( - Position r, Direction u, array& result) const override; + void get_indices(Position r, Direction u, array& result) const; - int get_flat_index(const array& i_xyz) const override; + int get_flat_index(const array& i_xyz) const; - Position get_local_position( - Position r, const array& i_xyz) const override; + Position get_local_position(Position r, const array& i_xyz) const; - Direction get_normal( - const array& i_xyz, bool& is_valid) const override; + bool is_valid_index(int indx) const; - bool is_valid_index(int indx) const override; + int32_t& offset(int map, array const& i_xyz); - int32_t& offset(int map, const array& i_xyz) override; + int32_t offset(int map, int indx) const; - int32_t offset(int map, int indx) const override; + std::string index_to_string(int indx) const; - std::string index_to_string(int indx) const override; - - void to_hdf5_inner(hid_t group_id) const override; + void to_hdf5_inner(hid_t group_id) const; private: enum class Orientation { diff --git a/include/openmc/material.h b/include/openmc/material.h index 3967c3687..b251a3ca8 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -4,17 +4,15 @@ #include #include -#include "openmc/span.h" -#include "openmc/tensor.h" #include "pugixml.hpp" +#include "xtensor/xtensor.hpp" +#include #include #include "openmc/bremsstrahlung.h" #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr -#include "openmc/ncrystal_interface.h" #include "openmc/particle.h" -#include "openmc/settings.h" #include "openmc/vector.h" namespace openmc { @@ -91,36 +89,16 @@ public: void set_densities( const vector& name, const vector& density); - //! Clone the material by deep-copying all members, except for the ID, - // which will get auto-assigned to the next available ID. After creating - // the new material, it is added to openmc::model::materials. - //! \return reference to the cloned material - Material& clone(); - //---------------------------------------------------------------------------- // Accessors - //! Get the atom density in [atom/b-cm] - //! \return Density in [atom/b-cm] - double atom_density(int32_t i, double rho_multiplier = 1.0) const - { - return atom_density_(i) * rho_multiplier; - } - //! Get density in [atom/b-cm] //! \return Density in [atom/b-cm] double density() const { return density_; } - //! Get density in [g/cm^3]. + //! Get density in [g/cm^3] //! \return Density in [g/cm^3] - double density_gpcc() const - { - return settings::run_CE ? density_gpcc_ : density(); - } - - //! Get charge density in [e/b-cm] - //! \return Charge density in [e/b-cm] - double charge_density() const { return charge_density_; }; + double density_gpcc() const { return density_gpcc_; } //! Get name //! \return Material name @@ -133,21 +111,21 @@ public: // //! \param[in] density Density value //! \param[in] units Units of density - void set_density(double density, const std::string& units); + void set_density(double density, gsl::cstring_span units); //! Set temperature of the material void set_temperature(double temperature) { temperature_ = temperature; }; //! Get nuclides in material //! \return Indices into the global nuclides vector - span nuclides() const + gsl::span nuclides() const { return {nuclide_.data(), nuclide_.size()}; } //! Get densities of each nuclide in material //! \return Densities in [atom/b-cm] - span densities() const + gsl::span densities() const { return {atom_density_.data(), atom_density_.size()}; } @@ -164,7 +142,6 @@ public: //! Get whether material is fissionable //! \return Whether material is fissionable bool fissionable() const { return fissionable_; } - bool& fissionable() { return fissionable_; } //! Get volume of material //! \return Volume in [cm^3] @@ -174,28 +151,21 @@ public: //! \return Temperature in [K] double temperature() const; - //! Whether or not the material is depletable - bool depletable() const { return depletable_; } - bool& depletable() { return depletable_; } - - //! Get pointer to NCrystal material object - //! \return Pointer to NCrystal material object - const NCrystalMat& ncrystal_mat() const { return ncrystal_mat_; }; - //---------------------------------------------------------------------------- // Data int32_t id_ {C_NONE}; //!< Unique ID std::string name_; //!< Name of material vector nuclide_; //!< Indices in nuclides vector vector element_; //!< Indices in elements vector - NCrystalMat ncrystal_mat_; //!< NCrystal material object - tensor::Tensor atom_density_; //!< Nuclide atom density in [atom/b-cm] + xt::xtensor 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] double volume_ {-1.0}; //!< Volume in [cm^3] - vector p0_; //!< Indicate which nuclides are to be treated with - //!< iso-in-lab scattering + bool fissionable_ { + false}; //!< Does this material contain fissionable nuclides + bool depletable_ {false}; //!< Is the material depletable? + vector p0_; //!< Indicate which nuclides are to be treated with + //!< iso-in-lab scattering // To improve performance of tallying, we store an array (direct address // table) that indicates for each nuclide in data::nuclides the index of the @@ -226,11 +196,8 @@ private: //---------------------------------------------------------------------------- // Private data members - int64_t index_; + gsl::index index_; - bool depletable_ {false}; //!< Is the material depletable? - bool fissionable_ { - false}; //!< Does this material contain fissionable nuclides //! \brief Default temperature for cells containing this material. //! //! A negative value indicates no default temperature was specified. @@ -254,10 +221,6 @@ double density_effect(const vector& f, const vector& e_b_sq, //! Read material data from materials.xml void read_materials_xml(); -//! Read material data XML node -//! \param[in] root node of materials XML element -void read_materials_xml(pugi::xml_node root); - void free_memory_material(); } // namespace openmc diff --git a/include/openmc/math_functions.h b/include/openmc/math_functions.h index d3bccca7b..c30ef7558 100644 --- a/include/openmc/math_functions.h +++ b/include/openmc/math_functions.h @@ -9,7 +9,6 @@ #include #include "openmc/position.h" -#include "openmc/search.h" namespace openmc { @@ -201,63 +200,5 @@ std::complex faddeeva(std::complex z); //! \return Derivative of Faddeeva function evaluated at z std::complex w_derivative(std::complex 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); - -//! Evaluate the cylindrical Bessel function of the first kind J_n(x) -//! -//! Uses std::cyl_bessel_j where available (e.g., libstdc++). On standard -//! library implementations lacking the C++17 special math functions (e.g., -//! libc++ on Apple Clang/LLVM), falls back to the ascending power series, -//! which converges to machine precision for the small arguments (|x| <= 2) -//! used in OpenMC. Unlike std::cyl_bessel_j, negative arguments are handled -//! via the parity relation J_n(-x) = (-1)^n J_n(x). -//! -//! \param n Non-negative integer order of the Bessel function -//! \param x Real argument -//! \return J_n(x) -double cyl_bessel_j(int n, double x); - -//! Helper function to get index and interpolation function on an incident -//! energy grid -//! -//! \param energies energy grid -//! \param E incident energy -//! \param i grid index -//! \param f interpolation factor -void get_energy_index( - const vector& 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); - -//============================================================================== -//! Return true if two floating-point values are approximately equal within a -//! combined relative and absolute tolerance. -//! -//! \param a first floating point value -//! \param b second floating point value -//! \param rel_tol relative tolerance -//! \param abs_tol absolute tolerance -//! \return true if a and b are approximately equal, false otherwise -//============================================================================== -bool isclose(double a, double b, double rel_tol, double abs_tol); - } // namespace openmc #endif // OPENMC_MATH_FUNCTIONS_H diff --git a/include/openmc/mcpl_interface.h b/include/openmc/mcpl_interface.h deleted file mode 100644 index a9cce3e69..000000000 --- a/include/openmc/mcpl_interface.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef OPENMC_MCPL_INTERFACE_H -#define OPENMC_MCPL_INTERFACE_H - -#include "openmc/particle_data.h" -#include "openmc/span.h" -#include "openmc/vector.h" - -#include - -namespace openmc { - -//============================================================================== -// Functions -//============================================================================== - -//! Get a vector of source sites from an MCPL file -// -//! \param[in] path Path to MCPL file -//! \return Vector of source sites -vector mcpl_source_sites(std::string path); - -//! Write an MCPL source file with stat:sum metadata -//! -//! This function writes particle data to an MCPL file. For MCPL >= 2.1.0, -//! it includes a stat:sum field (key: "openmc_np1") containing the total -//! number of source particles, which is essential for proper file merging -//! and weight normalization when using MCPL files with McStas/McXtrace. -//! -//! The stat:sum field follows the crash-safety pattern: -//! - Initially set to -1 when opening (indicates incomplete file) -//! - Updated with actual particle count before closing -//! -//! \param[in] filename Path to MCPL file -//! \param[in] source_bank Vector of SourceSites to write to file for this -//! MPI rank. -//! \param[in] bank_index Pointer to vector of site index ranges over all -//! MPI ranks. -void write_mcpl_source_point(const char* filename, span source_bank, - const vector& bank_index); - -//! Write an MCPL collision track file -//! -//! This function writes collision track data to an MCPL file. Additional -//! collision-specific metadata (such as energy deposition, material info, etc.) -//! is stored in the file header as blob data. -//! -//! \param[in] filename Path to MCPL file -//! \param[in] collision_track_bank Vector of CollisionTrackSites to write to -//! file for this MPI rank. -//! \param[in] bank_index Pointer to vector of site index ranges over all -//! MPI ranks. -void write_mcpl_collision_track(const char* filename, - span collision_track_bank, - const vector& bank_index); - -//! Check if MCPL functionality is available -bool is_mcpl_interface_available(); - -//! Initialize the MCPL interface -void initialize_mcpl_interface_if_needed(); - -} // namespace openmc - -#endif // OPENMC_MCPL_INTERFACE_H diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 0d8189caa..eece0f1ff 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -4,30 +4,26 @@ #ifndef OPENMC_MESH_H #define OPENMC_MESH_H -#include #include #include "hdf5.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "pugixml.hpp" -#include "openmc/bounding_box.h" -#include "openmc/error.h" #include "openmc/memory.h" // for unique_ptr #include "openmc/particle.h" #include "openmc/position.h" -#include "openmc/span.h" #include "openmc/vector.h" #include "openmc/xml_interface.h" -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC #include "moab/AdaptiveKDTree.hpp" #include "moab/Core.hpp" #include "moab/GeomUtil.hpp" #include "moab/Matrix3.hpp" #endif -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH #include "libmesh/bounding_box.h" #include "libmesh/dof_map.h" #include "libmesh/elem.h" @@ -45,7 +41,7 @@ namespace openmc { // Constants //============================================================================== -enum class ElementType { UNSUPPORTED = -1, LINEAR_TET, LINEAR_HEX }; +enum class ElementType { UNSUPPORTED=-1, LINEAR_TET, LINEAR_HEX }; //============================================================================== // Global variables @@ -62,7 +58,7 @@ extern vector> meshes; } // namespace model -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH namespace settings { // used when creating new libMesh::MeshBase instances extern unique_ptr libmesh_init; @@ -70,109 +66,14 @@ extern const libMesh::Parallel::Communicator* libmesh_comm; } // namespace settings #endif -//============================================================================== -//! Helper class for keeping track of volume for each material in a mesh element -// -//! This class is used in Mesh::material_volumes to manage for each mesh element -//! a list of (material, volume) pairs. The openmc.lib.Mesh class allocates two -//! 2D arrays, one for materials and one for volumes. Because we don't know a -//! priori how many materials there are in each element but at the same time we -//! can't dynamically size an array at runtime for performance reasons, we -//! assume a maximum number of materials per element. For each element, the set -//! of material indices are stored in a hash table with twice as many slots as -//! the assumed maximum number of materials per element. Collision resolution is -//! handled by open addressing with linear probing. -//============================================================================== - -namespace detail { - -class MaterialVolumes { -public: - MaterialVolumes(int32_t* mats, double* vols, double* bboxes, int table_size) - : materials_(mats), volumes_(vols), bboxes_(bboxes), table_size_(table_size) - {} - - MaterialVolumes(int32_t* mats, double* vols, int table_size) - : MaterialVolumes(mats, vols, nullptr, table_size) - {} - - //! Add volume for a given material in a mesh element - // - //! \param[in] index_elem Index of the mesh element - //! \param[in] index_material Index of the material within the model - //! \param[in] volume Volume to add - //! \param[in] bbox Bounding box to union into the result (optional) - void add_volume(int index_elem, int index_material, double volume, - const BoundingBox* bbox = nullptr); - void add_volume_unsafe(int index_elem, int index_material, double volume, - const BoundingBox* bbox = nullptr); - - // Accessors - int32_t& materials(int i, int j) { return materials_[i * table_size_ + j]; } - const int32_t& materials(int i, int j) const - { - return materials_[i * table_size_ + j]; - } - - double& volumes(int i, int j) { return volumes_[i * table_size_ + j]; } - const double& volumes(int i, int j) const - { - return volumes_[i * table_size_ + j]; - } - - double& bboxes(int i, int j, int k) - { - return bboxes_[(i * table_size_ + j) * 6 + k]; - } - const double& bboxes(int i, int j, int k) const - { - return bboxes_[(i * table_size_ + j) * 6 + k]; - } - - bool has_bboxes() const { return bboxes_ != nullptr; } - - bool table_full() const { return table_full_; } - -private: - int32_t* materials_; //!< material index (bins, table_size) - double* volumes_; //!< volume in [cm^3] (bins, table_size) - double* bboxes_; //!< bounding boxes (bins, table_size, 6) - int table_size_; //!< Size of hash table for each mesh element - bool table_full_ {false}; //!< Whether the hash table is full -}; - -} // namespace detail - -//============================================================================== -//! Base mesh class -//============================================================================== - class Mesh { public: // Constructors and destructor Mesh() = default; Mesh(pugi::xml_node node); - Mesh(hid_t group); virtual ~Mesh() = default; - // Factory method for creating meshes from either an XML node or HDF5 group - template - static const std::unique_ptr& create( - T dataset, const std::string& mesh_type, const std::string& mesh_library); - // Methods - //! Perform any preparation needed to support point location within the mesh - virtual void prepare_for_point_location() {}; - - //! Return a position in the local coordinates of the mesh - virtual Position local_coords(const Position& r) const { return r; }; - - //! Sample a position within a mesh element - // - //! \param[in] bin Bin value of the mesh element sampled - //! \param[inout] seed Seed to use for random sampling - //! \return sampled position within mesh element - virtual Position sample_element(int32_t bin, uint64_t* seed) const = 0; //! Determine which bins were crossed by a particle // @@ -205,20 +106,13 @@ public: //! Get the number of mesh cell surfaces. virtual int n_surface_bins() const = 0; - int32_t id() const { return id_; } - - const std::string& name() const { return name_; } - //! Set the mesh ID void set_id(int32_t id = -1); - //! Write the mesh data to an HDF5 group - void to_hdf5(hid_t group) const; - //! Write mesh data to an HDF5 group // //! \param[in] group HDF5 group - virtual void to_hdf5_inner(hid_t group) const = 0; + virtual void to_hdf5(hid_t group) const = 0; //! Find the mesh lines that intersect an axis-aligned slice plot // @@ -236,66 +130,18 @@ public: //! \param[in] bin Mesh bin to generate a label for virtual std::string bin_label(int bin) const = 0; - //! Get the volume of a mesh bin - // - //! \param[in] bin Bin to return the volume for - //! \return Volume of the bin - virtual double volume(int bin) const = 0; - - //! Volumes of all elements in the mesh in bin ordering - vector volumes() const; - + //! Return the mesh type virtual std::string get_mesh_type() const = 0; - //! Determine volume of materials within each mesh element - // - //! \param[in] nx Number of samples in x direction - //! \param[in] ny Number of samples in y direction - //! \param[in] nz Number of samples in z direction - //! \param[in] max_materials Maximum number of materials in a single mesh - //! element - //! \param[inout] materials Array storing material indices - //! \param[inout] volumes Array storing volumes - void material_volumes(int nx, int ny, int nz, int max_materials, - int32_t* materials, double* volumes) const; - - //! Determine volume and bounding boxes of materials within each mesh element - // - //! \param[in] nx Number of samples in x direction - //! \param[in] ny Number of samples in y direction - //! \param[in] nz Number of samples in z direction - //! \param[in] max_materials Maximum number of materials in a single mesh - //! element - //! \param[inout] materials Array storing material indices - //! \param[inout] volumes Array storing volumes - //! \param[inout] bboxes Array storing bounding boxes (n_elems, table_size, 6) - void material_volumes(int nx, int ny, int nz, int max_materials, - int32_t* materials, double* volumes, double* bboxes) const; - - //! Determine bounding box of mesh - // - //! \return Bounding box of mesh - BoundingBox bounding_box() const - { - return {this->lower_left(), this->upper_right()}; - } - - virtual Position lower_left() const = 0; - virtual Position upper_right() const = 0; - // Data members - tensor::Tensor lower_left_; //!< Lower-left coordinates of mesh - tensor::Tensor 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 + int id_ {-1}; //!< User-specified ID + int n_dimension_; //!< Number of dimensions }; class StructuredMesh : public Mesh { public: StructuredMesh() = default; StructuredMesh(pugi::xml_node node) : Mesh {node} {}; - StructuredMesh(hid_t group) : Mesh {group} {}; virtual ~StructuredMesh() = default; using MeshIndex = std::array; @@ -314,13 +160,6 @@ public: } }; - Position sample_element(int32_t bin, uint64_t* seed) const override - { - return sample_element(get_indices_from_bin(bin), seed); - }; - - virtual Position sample_element(const MeshIndex& ijk, uint64_t* seed) const; - int get_bin(Position r) const override; int n_bins() const override; @@ -348,7 +187,7 @@ public: //! \param[in] Pointer to bank sites //! \param[in] Number of bank sites //! \param[out] Whether any bank sites are outside the mesh - tensor::Tensor count_sites( + xt::xtensor count_sites( const SourceSite* bank, int64_t length, bool* outside) const; //! Get bin given mesh indices @@ -376,30 +215,6 @@ public: //! \param[in] i Direction index virtual int get_index_in_direction(double r, int i) const = 0; - //! Get the coordinate for the mesh grid boundary in the positive direction - //! - //! \param[in] ijk Array of mesh indices - //! \param[in] i Direction index - virtual double positive_grid_boundary(const MeshIndex& ijk, int i) const - { - auto msg = - fmt::format("Attempting to call positive_grid_boundary on a {} mesh.", - get_mesh_type()); - fatal_error(msg); - }; - - //! Get the coordinate for the mesh grid boundary in the negative direction - //! - //! \param[in] ijk Array of mesh indices - //! \param[in] i Direction index - virtual double negative_grid_boundary(const MeshIndex& ijk, int i) const - { - auto msg = - fmt::format("Attempting to call negative_grid_boundary on a {} mesh.", - get_mesh_type()); - fatal_error(msg); - }; - //! Get the closest distance from the coordinate r to the grid surface //! in i direction that bounds mesh cell ijk and that is larger than l //! The coordinate r does not have to be inside the mesh cell ijk. In @@ -419,59 +234,17 @@ public: //! Get a label for the mesh bin std::string bin_label(int bin) const override; - //! Get mesh dimensions as a tensor - tensor::Tensor get_shape_tensor() const; - - double volume(int bin) const override - { - return this->volume(get_indices_from_bin(bin)); - } - - Position lower_left() const override - { - int n = lower_left_.size(); - Position ll {lower_left_[0], 0.0, 0.0}; - ll.y = (n >= 2) ? lower_left_[1] : -INFTY; - ll.z = (n == 3) ? lower_left_[2] : -INFTY; - return ll; - }; - - Position upper_right() const override - { - int n = upper_right_.size(); - Position ur {upper_right_[0], 0.0, 0.0}; - ur.y = (n >= 2) ? upper_right_[1] : INFTY; - ur.z = (n == 3) ? upper_right_[2] : INFTY; - return ur; - }; - - //! Get the volume of a specified element - //! \param[in] ijk Mesh index to return the volume for - //! \return Volume of the bin - virtual double volume(const MeshIndex& ijk) const = 0; + //! Get shape as xt::xtensor + xt::xtensor get_x_shape() const; // Data members + xt::xtensor lower_left_; //!< Lower-left coordinates of mesh + xt::xtensor upper_right_; //!< Upper-right coordinates of mesh std::array shape_; //!< Number of mesh elements in each dimension protected: }; -class PeriodicStructuredMesh : public StructuredMesh { - -public: - PeriodicStructuredMesh() = default; - PeriodicStructuredMesh(pugi::xml_node node) : StructuredMesh {node} {}; - PeriodicStructuredMesh(hid_t group) : StructuredMesh {group} {}; - - Position local_coords(const Position& r) const override - { - return r - origin_; - }; - - // Data members - Position origin_ {0.0, 0.0, 0.0}; //!< Origin of the mesh -}; - //============================================================================== //! Tessellation of n-dimensional Euclidean space by congruent squares or cubes //============================================================================== @@ -481,7 +254,6 @@ public: // Constructors RegularMesh() = default; RegularMesh(pugi::xml_node node); - RegularMesh(hid_t group); // Overridden methods int get_index_in_direction(double r, int i) const override; @@ -496,37 +268,32 @@ public: std::pair, vector> plot( Position plot_ll, Position plot_ur) const override; - void to_hdf5_inner(hid_t group) const override; + void to_hdf5(hid_t group) const override; + // New methods //! Get the coordinate for the mesh grid boundary in the positive direction //! //! \param[in] ijk Array of mesh indices //! \param[in] i Direction index - double positive_grid_boundary(const MeshIndex& ijk, int i) const override; + double positive_grid_boundary(const MeshIndex& ijk, int i) const; //! Get the coordinate for the mesh grid boundary in the negative direction //! //! \param[in] ijk Array of mesh indices //! \param[in] i Direction index - double negative_grid_boundary(const MeshIndex& ijk, int i) const override; + double negative_grid_boundary(const MeshIndex& ijk, int i) const; //! Count number of bank sites in each mesh bin / energy bin // //! \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 - tensor::Tensor count_sites( + xt::xtensor count_sites( const SourceSite* bank, int64_t length, bool* outside) const; - //! Return the volume for a given mesh index - double volume(const MeshIndex& ijk) const override; - - int set_grid(); - // Data members double volume_frac_; //!< Volume fraction of each mesh element - double element_volume_; //!< Volume of each mesh element - tensor::Tensor width_; //!< Width of each mesh element + xt::xtensor width_; //!< Width of each mesh element }; class RectilinearMesh : public StructuredMesh { @@ -534,7 +301,6 @@ public: // Constructors RectilinearMesh() = default; RectilinearMesh(pugi::xml_node node); - RectilinearMesh(hid_t group); // Overridden methods int get_index_in_direction(double r, int i) const override; @@ -549,35 +315,31 @@ public: std::pair, vector> plot( Position plot_ll, Position plot_ur) const override; - void to_hdf5_inner(hid_t group) const override; + void to_hdf5(hid_t group) const override; + // New methods //! Get the coordinate for the mesh grid boundary in the positive direction //! //! \param[in] ijk Array of mesh indices //! \param[in] i Direction index - double positive_grid_boundary(const MeshIndex& ijk, int i) const override; + double positive_grid_boundary(const MeshIndex& ijk, int i) const; //! Get the coordinate for the mesh grid boundary in the negative direction //! //! \param[in] ijk Array of mesh indices //! \param[in] i Direction index - double negative_grid_boundary(const MeshIndex& ijk, int i) const override; + double negative_grid_boundary(const MeshIndex& ijk, int i) const; - //! Return the volume for a given mesh index - double volume(const MeshIndex& ijk) const override; + array, 3> grid_; int set_grid(); - - // Data members - array, 3> grid_; }; -class CylindricalMesh : public PeriodicStructuredMesh { +class CylindricalMesh : public StructuredMesh { public: // Constructors CylindricalMesh() = default; CylindricalMesh(pugi::xml_node node); - CylindricalMesh(hid_t group); // Overridden methods virtual MeshIndex get_indices(Position r, bool& in_mesh) const override; @@ -588,28 +350,18 @@ public: static const std::string mesh_type; - Position sample_element(const MeshIndex& ijk, uint64_t* seed) const override; - MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, const Position& r0, const Direction& u, double l) const override; std::pair, vector> plot( Position plot_ll, Position plot_ur) const override; - void to_hdf5_inner(hid_t group) const override; + void to_hdf5(hid_t group) const override; - double volume(const MeshIndex& ijk) const override; - - // grid accessors - double r(int i) const { return grid_[0][i]; } - double phi(int i) const { return grid_[1][i]; } - double z(int i) const { return grid_[2][i]; } + array, 3> grid_; int set_grid(); - // Data members - array, 3> grid_; - private: double find_r_crossing( const Position& r, const Direction& u, double l, int shell) const; @@ -620,7 +372,7 @@ private: bool full_phi_ {false}; - inline int sanitize_angular_index(int idx, bool full, int N) const + constexpr inline int sanitize_angular_index(int idx, bool full, int N) const { if ((idx > 0) and (idx <= N)) { return idx; @@ -637,12 +389,11 @@ private: } }; -class SphericalMesh : public PeriodicStructuredMesh { +class SphericalMesh : public StructuredMesh { public: // Constructors SphericalMesh() = default; SphericalMesh(pugi::xml_node node); - SphericalMesh(hid_t group); // Overridden methods virtual MeshIndex get_indices(Position r, bool& in_mesh) const override; @@ -653,25 +404,18 @@ public: static const std::string mesh_type; - Position sample_element(const MeshIndex& ijk, uint64_t* seed) const override; - MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, const Position& r0, const Direction& u, double l) const override; std::pair, vector> plot( Position plot_ll, Position plot_ur) const override; - void to_hdf5_inner(hid_t group) const override; + void to_hdf5(hid_t group) const override; - double r(int i) const { return grid_[0][i]; } - double theta(int i) const { return grid_[1][i]; } - double phi(int i) const { return grid_[2][i]; } + array, 3> grid_; int set_grid(); - // Data members - array, 3> grid_; - private: double find_r_crossing( const Position& r, const Direction& u, double l, int shell) const; @@ -683,7 +427,7 @@ private: bool full_theta_ {false}; bool full_phi_ {false}; - inline int sanitize_angular_index(int idx, bool full, int N) const + constexpr inline int sanitize_angular_index(int idx, bool full, int N) const { if ((idx > 0) and (idx <= N)) { return idx; @@ -694,8 +438,6 @@ private: } } - double volume(const MeshIndex& ijk) const override; - inline int sanitize_theta(int idx) const { return sanitize_angular_index(idx, full_theta_, shape_[1]); @@ -711,19 +453,18 @@ class UnstructuredMesh : public Mesh { public: // Constructors - UnstructuredMesh() { n_dimension_ = 3; }; + UnstructuredMesh() {}; UnstructuredMesh(pugi::xml_node node); - UnstructuredMesh(hid_t group); + UnstructuredMesh(const std::string& filename); static const std::string mesh_type; virtual std::string get_mesh_type() const override; // Overridden Methods - void surface_bins_crossed(Position r0, Position r1, const Direction& u, vector& bins) const override; - void to_hdf5_inner(hid_t group) const override; + void to_hdf5(hid_t group) const override; std::string bin_label(int bin) const override; @@ -768,6 +509,12 @@ public: //! \return element connectivity as IDs of the vertices virtual std::vector connectivity(int id) const = 0; + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin + virtual double volume(int bin) const = 0; + //! Get the library used for this unstructured mesh virtual std::string library() const = 0; @@ -776,36 +523,14 @@ public: true}; //!< Write tallies onto the unstructured mesh at the end of a run std::string filename_; //!< Path to unstructured mesh file - ElementType element_type(int bin) const; - - Position lower_left() const override - { - return {lower_left_[0], lower_left_[1], lower_left_[2]}; - } - Position upper_right() const override - { - return {upper_right_[0], upper_right_[1], upper_right_[2]}; - } - protected: //! Set the length multiplier to apply to each point in the mesh void set_length_multiplier(const double length_multiplier); - //! Sample barycentric coordinates given a seed and the vertex positions and - //! return the sampled position - // - //! \param[in] coords Coordinates of the tetrahedron - //! \param[in] seed Random number generation seed - //! \return Sampled position within the tetrahedron - Position sample_tet(std::array coords, uint64_t* seed) const; - // Data members double length_multiplier_ { - -1.0}; //!< Multiplicative factor applied to mesh coordinates - std::string options_; //!< Options for search data structures - - //! Determine lower-left and upper-right bounds of mesh - void determine_bounds(); + 1.0}; //!< Constant multiplication factor to apply to mesh coordinates + bool specified_length_multiplier_ {false}; private: //! Setup method for the mesh. Builds data structures, @@ -813,14 +538,13 @@ private: virtual void initialize() = 0; }; -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC class MOABMesh : public UnstructuredMesh { public: // Constructors MOABMesh() = default; MOABMesh(pugi::xml_node); - MOABMesh(hid_t group); MOABMesh(const std::string& filename, double length_multiplier = 1.0); MOABMesh(std::shared_ptr external_mbi); @@ -828,11 +552,6 @@ public: // Overridden Methods - //! Perform any preparation needed to support use in mesh filters - void prepare_for_point_location() override; - - Position sample_element(int32_t bin, uint64_t* seed) const override; - void bins_crossed(Position r0, Position r1, const Direction& u, vector& bins, vector& lengths) const override; @@ -868,10 +587,6 @@ public: std::vector connectivity(int id) const override; - //! Get the volume of a mesh bin - // - //! \param[in] bin Bin to return the volume for - //! \return Volume of the bin double volume(int bin) const override; private: @@ -972,7 +687,7 @@ private: std::pair get_score_tags(std::string score) const; // Data members - moab::Range ehs_; //!< Range of tetrahedra EntityHandle's in the mesh + moab::Range ehs_; //!< Range of tetrahedra EntityHandle's in the mesh moab::Range verts_; //!< Range of vertex EntityHandle's in the mesh moab::EntityHandle tetset_; //!< EntitySet containing all tetrahedra moab::EntityHandle kdtree_root_; //!< Root of the MOAB KDTree @@ -984,15 +699,14 @@ private: #endif -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH class LibMesh : public UnstructuredMesh { public: // Constructors LibMesh(pugi::xml_node node); - LibMesh(hid_t group); - LibMesh(const std::string& filename, double length_multiplier = 1.0); - LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier = 1.0); + LibMesh(const std::string & filename, double length_multiplier = 1.0); + LibMesh(libMesh::MeshBase & input_mesh, double length_multiplier = 1.0); static const std::string mesh_lib_type; @@ -1000,9 +714,7 @@ public: void bins_crossed(Position r0, Position r1, const Direction& u, vector& bins, vector& lengths) const override; - Position sample_element(int32_t bin, uint64_t* seed) const override; - - virtual int get_bin(Position r) const override; + int get_bin(Position r) const override; int n_bins() const override; @@ -1030,90 +742,39 @@ public: std::vector connectivity(int id) const override; - //! Get the volume of a mesh bin - // - //! \param[in] bin Bin to return the volume for - //! \return Volume of the bin double volume(int bin) const override; libMesh::MeshBase* mesh_ptr() const { return m_; }; -protected: - // Methods - //! Translate a bin value to an element reference - virtual const libMesh::Elem& get_element_from_bin(int bin) const; - - //! Translate an element pointer to a bin index - virtual int get_bin_from_element(const libMesh::Elem* elem) const; - - // Data members - libMesh::MeshBase* m_; //!< pointer to libMesh MeshBase instance, always set - //!< during intialization - vector> - pl_; //!< per-thread point locators - libMesh::BoundingBox bbox_; //!< bounding box of the mesh - private: - // Methods void initialize() override; void set_mesh_pointer_from_filename(const std::string& filename); - void build_eqn_sys(); + + // Methods + + //! Translate a bin value to an element reference + const libMesh::Elem& get_element_from_bin(int bin) const; + + //! Translate an element pointer to a bin index + int get_bin_from_element(const libMesh::Elem* elem) const; // Data members - unique_ptr unique_m_ = - nullptr; //!< pointer to the libMesh MeshBase instance, only used if mesh is - //!< created inside OpenMC + unique_ptr unique_m_ = nullptr; //!< pointer to the libMesh MeshBase instance, only used if mesh is created inside OpenMC + libMesh::MeshBase* m_; //!< pointer to libMesh MeshBase instance, always set during intialization + vector> + pl_; //!< per-thread point locators unique_ptr - equation_systems_; //!< pointer to the libMesh EquationSystems - //!< instance + equation_systems_; //!< pointer to the equation systems of the mesh std::string eq_system_name_; //!< name of the equation system holding OpenMC results std::unordered_map variable_map_; //!< mapping of variable names (tally scores) to libMesh //!< variable numbers + libMesh::BoundingBox bbox_; //!< bounding box of the mesh libMesh::dof_id_type first_element_id_; //!< id of the first element in the mesh }; -class AdaptiveLibMesh : public LibMesh { -public: - // Constructor - AdaptiveLibMesh(libMesh::MeshBase& input_mesh, double length_multiplier = 1.0, - const std::set& block_ids = - std::set()); - - // Overridden methods - int n_bins() const override; - - void add_score(const std::string& var_name) override; - - void set_score_data(const std::string& var_name, const vector& values, - const vector& std_dev) override; - - void write(const std::string& filename) const override; - - int get_bin(Position r) const override; - -protected: - // Overridden methods - int get_bin_from_element(const libMesh::Elem* elem) const override; - - const libMesh::Elem& get_element_from_bin(int bin) const override; - -private: - // Data members - const std::set - block_ids_; //!< subdomains of the mesh to tally on - const bool block_restrict_; //!< whether a subset of the mesh is being used - const libMesh::dof_id_type num_active_; //!< cached number of active elements - - std::vector - bin_to_elem_map_; //!< mapping bin indices to dof indices for active - //!< elements - std::vector elem_to_bin_map_; //!< mapping dof indices to bin indices for - //!< active elements -}; - #endif //============================================================================== @@ -1125,11 +786,6 @@ private: //! \param[in] root XML node void read_meshes(pugi::xml_node root); -//! Read meshes from an HDF5 file -// -//! \param[in] group HDF5 group ("meshes" group) -void read_meshes(hid_t group); - //! Write mesh data to an HDF5 group // //! \param[in] group HDF5 group diff --git a/include/openmc/message_passing.h b/include/openmc/message_passing.h index 03e236338..b02d2938f 100644 --- a/include/openmc/message_passing.h +++ b/include/openmc/message_passing.h @@ -1,14 +1,10 @@ #ifndef OPENMC_MESSAGE_PASSING_H #define OPENMC_MESSAGE_PASSING_H -#include - #ifdef OPENMC_MPI #include #endif -#include "openmc/vector.h" - namespace openmc { namespace mpi { @@ -18,35 +14,9 @@ extern bool master; #ifdef OPENMC_MPI extern MPI_Datatype source_site; -extern MPI_Datatype collision_track_site; extern MPI_Comm intracomm; #endif -//============================================================================== -// Template struct used to map types to MPI datatypes -// By having a single static data member, the template can -// be specialized for each type we know of. The specializations appear in the -// .cpp file since they are definitions. -//============================================================================== -#ifdef OPENMC_MPI -template -struct MPITypeMap { - static const MPI_Datatype mpi_type; -}; -#endif - -// Calculates global indices of the bank particles -// across all ranks using a parallel scan. This is used to write -// the surface source file in parallel runs. It will probably -// be used in the future for other types of bank like particles -// in flight used to kick off transient simulations. -// -// More abstractly, this just takes a number from each MPI rank, -// and returns a vector which is the exclusive parallel scan across -// all of those numbers, having a length of the number of MPI ranks -// plus one. -vector calculate_parallel_index_vector(int64_t size); - } // namespace mpi } // namespace openmc diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 5d8ff58c2..2da3c8363 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -6,7 +6,7 @@ #include -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/constants.h" #include "openmc/hdf5_interface.h" @@ -16,19 +16,34 @@ namespace openmc { +//============================================================================== +// Cache contains the cached data for an MGXS object +//============================================================================== + +struct CacheData { + double sqrtkT; // last temperature corresponding to t + int t; // temperature index + int a; // angle index + // last angle that corresponds to a + double u; + double v; + double w; +}; + //============================================================================== // MGXS contains the mgxs data for a nuclide/material //============================================================================== class Mgxs { private: - tensor::Tensor kTs; // temperature in eV (k * T) + xt::xtensor 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 int num_delayed_groups; // number of delayed neutron groups vector xs; // Cross section data // MGXS Incoming Flux Angular grid information + bool is_isotropic; // used to skip search for angle indices if isotropic int n_pol; int n_azi; vector polar; @@ -81,15 +96,12 @@ private: bool equiv(const Mgxs& that); public: - std::string name; // name of dataset, e.g., UO2 - double awr; // atomic weight ratio - bool fissionable; // Is this fissionable - bool is_isotropic { - true}; // used to skip search for angle indices if isotropic - bool exists_in_model {true}; // Is this present in model + std::string name; // name of dataset, e.g., UO2 + double awr; // atomic weight ratio + bool fissionable; // Is this fissionable + vector cache; // index and data cache Mgxs() = default; - Mgxs(bool exists) : exists_in_model(exists) {} //! \brief Constructor that loads the Mgxs object from the HDF5 file //! @@ -113,11 +125,6 @@ public: const vector& micros, const vector& 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 @@ -128,15 +135,13 @@ public: //! @param mu Cosine of the change-in-angle, for scattering quantities; //! use nullptr if irrelevant. //! @param dg delayed group index; use nullptr if irrelevant. - //! @param t Temperature index. - //! @param a Angle index. //! @return Requested cross section value. - double get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, - const int* dg, int t, int a); + double get_xs( + MgxsType xstype, int gin, const int* gout, const double* mu, const int* dg); - inline double get_xs(MgxsType xstype, int gin, int t, int a) + inline double get_xs(MgxsType xstype, int gin) { - return get_xs(xstype, gin, nullptr, nullptr, nullptr, t, a); + return get_xs(xstype, gin, nullptr, nullptr, nullptr); } //! \brief Samples the fission neutron energy and if prompt or delayed. @@ -145,10 +150,7 @@ public: //! @param dg Sampled delayed group index. //! @param gout Sampled outgoing energy group. //! @param seed Pseudorandom seed pointer - //! @param t Temperature index. - //! @param a Angle index. - void sample_fission_energy( - int gin, int& dg, int& gout, uint64_t* seed, int t, int a); + void sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed); //! \brief Samples the outgoing energy and angle from a scatter event. //! @@ -157,37 +159,23 @@ public: //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. //! @param seed Pseudorandom seed pointer. - //! @param t Temperature index. - //! @param a Angle index. void sample_scatter( - int gin, int& gout, double& mu, double& wgt, uint64_t* seed, int t, int a); + int gin, int& gout, double& mu, double& wgt, uint64_t* seed); //! \brief Calculates cross section quantities needed for tracking. //! //! @param p The particle whose attributes set which MGXS to get. void calculate_xs(Particle& p); - //! \brief Sets the temperature index in the particle's cache. - //! - //! @param p Particle. - void set_temperature_index(Particle& p); - - //! \brief Gets the temperature index given a temperature. + //! \brief Sets the temperature index in cache given a temperature //! //! @param sqrtkT Temperature of the material. - //! @return The temperature index corresponding to sqrtkT. - int get_temperature_index(double sqrtkT) const; + void set_temperature_index(double sqrtkT); - //! \brief Sets the angle index in the particle's cache. - //! - //! @param p Particle. - void set_angle_index(Particle& p); - - //! \brief Gets the angle index given a direction. + //! \brief Sets the angle index in cache given a direction //! //! @param u Incoming particle direction. - //! @return The angle index corresponding to u. - int get_angle_index(const Direction& u) const; + void set_angle_index(Direction u); //! \brief Provide const access to list of XsData held by this const vector& get_xsdata() const { return xs; } diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 117ac503d..8bcdf6dc6 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -46,9 +46,6 @@ public: // Get the kT values which are used in the OpenMC model vector> get_mat_kTs(); - // Get the group index corresponding to a continuous energy - int get_group_index(double E); - int num_energy_groups_; int num_delayed_groups_; vector xs_names_; // available names in HDF5 file @@ -61,8 +58,6 @@ public: vector energy_bin_avg_; vector rev_energy_bins_; vector> nuc_temps_; // all available temperatures - vector - default_inverse_velocity_; // approximate default inverse-velocity data }; namespace data { diff --git a/include/openmc/ncrystal_interface.h b/include/openmc/ncrystal_interface.h deleted file mode 100644 index e9bd8ae79..000000000 --- a/include/openmc/ncrystal_interface.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef OPENMC_NCRYSTAL_INTERFACE_H -#define OPENMC_NCRYSTAL_INTERFACE_H - -#include "openmc/ncrystal_load.h" -#include "openmc/particle.h" - -#include // for uint64_t -#include // for numeric_limits -#include - -namespace openmc { - -//============================================================================== -// Constants -//============================================================================== - -//! Energy in [eV] to switch between NCrystal and ENDF -constexpr double NCRYSTAL_MAX_ENERGY {5.0}; - -//============================================================================== -// Wrapper class for an NCrystal material -//============================================================================== - -class NCrystalMat { -public: - //---------------------------------------------------------------------------- - // Constructors - NCrystalMat() = default; // empty object - explicit NCrystalMat(const std::string& cfg); - - //---------------------------------------------------------------------------- - // Methods - - //! Return configuration string: - const std::string& cfg() const { return cfg_; } - - //! Get cross section from NCrystal material - // - //! \param[in] p Particle object - //! \return Cross section in [b] - double xs(const Particle& p) const; - - // Process scattering event - // - //! \param[in] p Particle object - void scatter(Particle& p) const; - - //! Whether the object holds a valid NCrystal material - operator bool() const { return !cfg_.empty(); } - - NCrystalMat clone() const - { - NCrystalMat c; - c.cfg_ = cfg_; - c.proc_ = proc_.clone(); - return c; - } - -private: - //---------------------------------------------------------------------------- - // Data members (only present when compiling with NCrystal support) - std::string cfg_; //!< NCrystal configuration string - NCrystalScatProc proc_; //!< NCrystal scatter process -}; - -//============================================================================== -// Functions -//============================================================================== - -void ncrystal_update_micro(double xs, NuclideMicroXS& micro); - -} // namespace openmc - -#endif // OPENMC_NCRYSTAL_INTERFACE_H diff --git a/include/openmc/ncrystal_load.h b/include/openmc/ncrystal_load.h deleted file mode 100644 index d85f24090..000000000 --- a/include/openmc/ncrystal_load.h +++ /dev/null @@ -1,127 +0,0 @@ -//! \file ncrystal_load.h -//! \brief Helper class taking care of loading NCrystal at runtime. - -#ifndef OPENMC_NCRYSTAL_LOAD_H -#define OPENMC_NCRYSTAL_LOAD_H - -#include // for swap -#include // for function -#include // for shared_ptr -#include // for move - -namespace NCrystalVirtualAPI { - -// NOTICE: Do NOT make ANY changes in the NCrystalVirtualAPI::VirtAPI_Type1_v1 -// class, it is required to stay exactly constant over time and compatible with -// the same definition used to compile the NCrystal library! But changes to -// white space, comments, and formatting is of course allowed. This API was -// introduced in NCrystal 4.1.0. - -//! Abstract base class for NCrystal interface which must be declared exactly as -// it is in NCrystal itself. - -class VirtAPI_Type1_v1 { -public: - // Note: neutron must be an array of length 4 with values {ekin,ux,uy,uz} - class ScatterProcess; - virtual const ScatterProcess* createScatter(const char* cfgstr) const = 0; - virtual const ScatterProcess* cloneScatter(const ScatterProcess*) const = 0; - virtual void deallocateScatter(const ScatterProcess*) const = 0; - virtual double crossSectionUncached( - const ScatterProcess&, const double* neutron) const = 0; - virtual void sampleScatterUncached(const ScatterProcess&, - std::function& rng, double* neutron) const = 0; - // Plumbing: - static constexpr unsigned interface_id = 1001; - virtual ~VirtAPI_Type1_v1() = default; - VirtAPI_Type1_v1() = default; - VirtAPI_Type1_v1(const VirtAPI_Type1_v1&) = delete; - VirtAPI_Type1_v1& operator=(const VirtAPI_Type1_v1&) = delete; - VirtAPI_Type1_v1(VirtAPI_Type1_v1&&) = delete; - VirtAPI_Type1_v1& operator=(VirtAPI_Type1_v1&&) = delete; -}; - -} // namespace NCrystalVirtualAPI - -namespace openmc { - -using NCrystalAPI = NCrystalVirtualAPI::VirtAPI_Type1_v1; - -//! Function which locates and loads NCrystal at runtime using the virtual API -std::shared_ptr load_ncrystal_api(); - -//! Class encapsulating exactly the parts of NCrystal needed by OpenMC - -class NCrystalScatProc final { -public: - //! Empty constructor which does not load NCrystal - NCrystalScatProc() {} - - //! Load NCrystal and instantiate a scattering process - //! \param cfgstr NCrystal cfg-string defining the material. - NCrystalScatProc(const char* cfgstr) - : api_(load_ncrystal_api()), p_(api_->createScatter(cfgstr)) - {} - - // Note: Neutron state array is {ekin,ux,uy,uz} - - //! Returns total scattering cross section in units of barns per atom. - //! \param neutron_state array {ekin,ux,uy,uz} with ekin (eV) and direction. - double cross_section(const double* neutron_state) const - { - return api_->crossSectionUncached(*p_, neutron_state); - } - - //! Returns total scattering cross section in units of barns per atom. - //! \param rng function returning random numbers in the unit interval - //! \param neutron_state array {ekin,ux,uy,uz} with ekin (eV) and direction. - void scatter(std::function& rng, double* neutron_state) const - { - api_->sampleScatterUncached(*p_, rng, neutron_state); - } - - //! Clones the object which is otherwise move-only - NCrystalScatProc clone() const - { - NCrystalScatProc c; - if (p_) { - c.api_ = api_; - c.p_ = api_->cloneScatter(p_); - } - return c; - } - - // Plumbing (move-only semantics, but supports explicit clone): - NCrystalScatProc(const NCrystalScatProc&) = delete; - NCrystalScatProc& operator=(const NCrystalScatProc&) = delete; - - NCrystalScatProc(NCrystalScatProc&& o) : api_(std::move(o.api_)), p_(nullptr) - { - std::swap(p_, o.p_); - } - - NCrystalScatProc& operator=(NCrystalScatProc&& o) - { - if (p_) { - api_->deallocateScatter(p_); - p_ = nullptr; - } - std::swap(api_, o.api_); - std::swap(p_, o.p_); - return *this; - } - - ~NCrystalScatProc() - { - if (p_) - api_->deallocateScatter(p_); - } - -private: - std::shared_ptr api_; - const NCrystalAPI::ScatterProcess* p_ = nullptr; -}; - -} // namespace openmc - -#endif diff --git a/include/openmc/nuclide.h b/include/openmc/nuclide.h index ae39a53dd..b05c76bbb 100644 --- a/include/openmc/nuclide.h +++ b/include/openmc/nuclide.h @@ -7,6 +7,7 @@ #include #include // for pair +#include #include #include "openmc/array.h" @@ -16,7 +17,6 @@ #include "openmc/particle.h" #include "openmc/reaction.h" #include "openmc/reaction_product.h" -#include "openmc/span.h" #include "openmc/urr.h" #include "openmc/vector.h" #include "openmc/wmp.h" @@ -29,7 +29,6 @@ namespace openmc { class Nuclide { public: - //============================================================================ // Types, aliases using EmissionMode = ReactionProduct::EmissionMode; struct EnergyGrid { @@ -37,32 +36,18 @@ public: vector energy; }; - //============================================================================ // Constructors/destructors Nuclide(hid_t group, const vector& temperature); ~Nuclide(); - //============================================================================ - // Methods - //! Initialize logarithmic grid for energy searches void init_grid(); - //! Calculate microscopic cross sections - // - //! \param[in] i_sab Index in data::thermal_scatt - //! \param[in] i_log_union Log-grid search index - //! \param[in] sab_frac S(a,b) table fraction - //! \param[in,out] p Particle object void calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p); - //! Calculate thermal scattering cross section - // - //! \param[in] i_sab Index in data::thermal_scatt - //! \param[in] sab_frac S(a,b) table fraction - //! \param[in,out] p Particle object void calculate_sab_xs(int i_sab, double sab_frac, Particle& p); + // Methods double nu(double E, EmissionMode mode, int group = 0) const; void calculate_elastic_xs(Particle& p) const; @@ -81,25 +66,21 @@ public: //! \param[in] energy Energy group boundaries in [eV] //! \param[in] flux Flux in each energy group (not normalized per eV) //! \return Reaction rate - double collapse_rate(int MT, double temperature, span energy, - span flux) const; + double collapse_rate(int MT, double temperature, + gsl::span energy, gsl::span flux) const; - //! Return a ParticleType object representing this nuclide - ParticleType particle_type() const { return {Z_, A_, metastable_}; } - - //============================================================================ // Data members std::string name_; //!< Name of nuclide, e.g. "U235" int Z_; //!< Atomic number int A_; //!< Mass number int metastable_; //!< Metastable state double awr_; //!< Atomic weight ratio - int64_t index_; //!< Index in the nuclides array + gsl::index index_; //!< Index in the nuclides array // Temperature dependent cross section data vector kTs_; //!< temperatures in eV (k*T) vector grid_; //!< Energy grid at each temperature - vector> xs_; //!< Cross sections at each temperature + vector> xs_; //!< Cross sections at each temperature // Multipole data unique_ptr multipole_; @@ -141,7 +122,7 @@ private: // //! \param[in] T Temperature in [K] //! \return Temperature index and interpolation factor - std::pair find_temperature(double T) const; + std::pair find_temperature(double T) const; static int XS_TOTAL; static int XS_ABSORPTION; @@ -166,9 +147,9 @@ bool multipole_in_range(const Nuclide& nuc, double E); namespace data { // Minimum/maximum transport energy for each particle type. Order corresponds to -// transport_index() for supported transport particles. -extern array energy_min; -extern array energy_max; +// that of the ParticleType enum +extern array energy_min; +extern array energy_max; //! Minimum temperature in [K] that nuclide data is available at extern double temperature_min; diff --git a/include/openmc/openmp_interface.h b/include/openmc/openmp_interface.h index 30bd6f008..dac03ac59 100644 --- a/include/openmc/openmp_interface.h +++ b/include/openmc/openmp_interface.h @@ -7,27 +7,6 @@ namespace openmc { -//============================================================================== -//! Accessor functions related to number of threads and thread number -//============================================================================== -inline int num_threads() -{ -#ifdef _OPENMP - return omp_get_max_threads(); -#else - return 1; -#endif -} - -inline int thread_num() -{ -#ifdef _OPENMP - return omp_get_thread_num(); -#else - return 0; -#endif -} - //============================================================================== //! An object used to prevent concurrent access to a piece of data. // @@ -36,15 +15,13 @@ inline int thread_num() class OpenMPMutex { public: - void init() + OpenMPMutex() { #ifdef _OPENMP omp_init_lock(&mutex_); #endif } - OpenMPMutex() { init(); } - ~OpenMPMutex() { #ifdef _OPENMP @@ -52,22 +29,11 @@ public: #endif } - // omp_lock_t objects cannot be deep copied, they can only be shallow - // copied. Thus, while shallow copying of an omp_lock_t object is - // completely valid (provided no race conditions exist), true copying - // of an OpenMPMutex object is not valid due to the action of the - // destructor. However, since locks are fungible, we can simply replace - // copying operations with default construction. This allows storage of - // OpenMPMutex objects within containers that may need to move/copy them - // (e.g., std::vector). It is left to the caller to understand that - // copying of OpenMPMutex does not produce two handles to the same mutex, - // rather, it produces two different mutexes. - - // Copy constructor - OpenMPMutex(const OpenMPMutex& other) { init(); } - - // Copy assignment operator - OpenMPMutex& operator=(const OpenMPMutex& other) { return *this; } + // Mutexes cannot be copied. We need to explicitly delete the copy + // constructor and copy assignment operator to ensure the compiler doesn't + // "help" us by implicitly trying to copy the underlying mutexes. + OpenMPMutex(const OpenMPMutex&) = delete; + OpenMPMutex& operator=(const OpenMPMutex&) = delete; //! Lock the mutex. // diff --git a/include/openmc/output.h b/include/openmc/output.h index 0ad8b2fe5..2ebe2711f 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -10,8 +10,6 @@ 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(); @@ -42,9 +40,6 @@ void print_usage(); //! Display current version and copright/license information void print_version(); -//! Display compile flags employed, etc -void print_build_info(); - //! Display header listing what physical values will displayed void print_columns(); @@ -59,34 +54,5 @@ void print_results(); void write_tallies(); -void show_time(const char* label, double secs, int indent_level = 0); - } // namespace openmc - -////////////////////////////////////// -// Custom formatters -////////////////////////////////////// -namespace fmt { - -template -struct formatter> { - template - constexpr auto parse(ParseContext& ctx) - { - return ctx.begin(); - } - - template -#if FMT_VERSION >= 110000 // Version 11.0.0 and above - auto format(const std::array& arr, FormatContext& ctx) const { -#else // For versions below 11.0.0 - auto format(const std::array& arr, FormatContext& ctx) - { -#endif - return format_to(ctx.out(), "({}, {})", arr[0], arr[1]); -} -}; // namespace fmt - -} // namespace fmt - #endif // OPENMC_OUTPUT_H diff --git a/include/openmc/particle.h b/include/openmc/particle.h index 8db9721ba..da2f6a61f 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -5,6 +5,7 @@ //! \brief Particle type #include +#include #include #include "openmc/constants.h" @@ -34,13 +35,8 @@ public: Particle() = default; - //========================================================================== - // Methods - double speed() const; - double mass() const; - //! create a secondary particle // //! stores the current phase space attributes of the particle in the @@ -49,14 +45,7 @@ public: //! \param u Direction of the secondary particle //! \param E Energy of the secondary particle in [eV] //! \param type Particle type - //! \return Whether a secondary particle was created - bool create_secondary(double wgt, Direction u, double E, ParticleType type); - - //! split a particle - // - //! creates a new particle with weight wgt - //! \param wgt Weight of the new particle - void split(double wgt); + void create_secondary(double wgt, Direction u, double E, ParticleType type); //! initialize from a source site // @@ -71,16 +60,11 @@ public: void event_advance(); void event_cross_surface(); void event_collide(); - void event_revive_from_secondary(const SourceSite& site); - void event_check_limit_and_revive(); + void event_revive_from_secondary(); void event_death(); - //! pulse-height recording - void pht_collision_energy(); - void pht_secondary_particles(); - //! Cross a surface and handle boundary conditions - void cross_surface(const Surface& surf); + void cross_surface(); //! Cross a vacuum boundary condition. // @@ -108,28 +92,29 @@ public: //! mark a particle as lost and create a particle restart file //! \param message A warning message to display - virtual void mark_as_lost(const char* message) override; - using GeometryState::mark_as_lost; + void mark_as_lost(const char* message); + + void mark_as_lost(const std::string& message) + { + mark_as_lost(message.c_str()); + } + + void mark_as_lost(const std::stringstream& message) + { + mark_as_lost(message.str()); + } //! create a particle restart HDF5 file void write_restart() const; - - //! Update microscopic cross section cache - // - //! \param[in] i_nuclide Index in data::nuclides - //! \param[in] i_grid Index on log union grid - //! \param[in] i_sab Index in data::thermal_scatt - //! \param[in] sab_frac S(a,b) table fraction - //! \param[in] ncrystal_xs Thermal scattering xs from NCrystal - void update_neutron_xs(int i_nuclide, int i_grid = C_NONE, int i_sab = C_NONE, - double sab_frac = 0.0, double ncrystal_xs = -1.0); }; //============================================================================ //! Functions //============================================================================ -void add_surf_source_to_bank(Particle& p, const Surface& surf); +std::string particle_type_to_str(ParticleType type); + +ParticleType str_to_particle_type(std::string str); } // namespace openmc diff --git a/include/openmc/particle_data.h b/include/openmc/particle_data.h index 44e82fd23..d3d00571a 100644 --- a/include/openmc/particle_data.h +++ b/include/openmc/particle_data.h @@ -3,13 +3,12 @@ #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" #include "openmc/vector.h" -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC #include "DagMC.hpp" #endif @@ -28,9 +27,15 @@ constexpr int MAX_DELAYED_GROUPS {8}; constexpr double CACHE_INVALID {-1.0}; +// Maximum number of collisions/crossings +constexpr int MAX_EVENTS {1000000}; + //========================================================================== // 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 @@ -45,32 +50,7 @@ struct SourceSite { double time {0.0}; double wgt {1.0}; int delayed_group {0}; - int surf_id {SURFACE_NONE}; - ParticleType particle; - - // Extra attributes that don't show up in source written to file - int parent_nuclide {-1}; - 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 { - Position r; - Direction u; - double E; - double dE; - double time {0.0}; - double wgt {1.0}; - int event_mt {0}; - int delayed_group {0}; - int cell_id {0}; - int nuclide_id; - int material_id {0}; - int universe_id {0}; - int n_collision {0}; + int surf_id {0}; ParticleType particle; int64_t parent_id; int64_t progeny_id; @@ -108,37 +88,13 @@ public: //! clear data from a single coordinate level void reset(); - // accessors - Position& r() { return r_; } - const Position& r() const { return r_; } - - Direction& u() { return u_; } - const Direction& u() const { return u_; } - - int& cell() { return cell_; } - const int& cell() const { return cell_; } - - int& universe() { return universe_; } - const int& universe() const { return universe_; } - - int& lattice() { return lattice_; } - int lattice() const { return lattice_; } - - array& lattice_index() { return lattice_index_; } - const array& lattice_index() const { return lattice_index_; } - - bool& rotated() { return rotated_; } - const bool& rotated() const { return rotated_; } - -private: - // Data members - Position r_; //!< particle position - Direction u_; //!< particle direction - int cell_ {-1}; - int universe_ {-1}; - int lattice_ {-1}; - array lattice_index_ {{-1, -1, -1}}; - bool rotated_ {false}; //!< Is the level rotated? + Position r; //!< particle position + Direction u; //!< particle direction + int cell {-1}; + int universe {-1}; + int lattice {-1}; + array lattice_i {{-1, -1, -1}}; + bool rotated {false}; //!< Is the level rotated? }; //============================================================================== @@ -174,10 +130,9 @@ struct NuclideMicroXS { // Energy and temperature last used to evaluate these cross sections. If // these values have changed, then the cross sections must be re-evaluated. - double last_E {0.0}; //!< Last evaluated energy - double last_sqrtkT {0.0}; //!< Last temperature in sqrt(Boltzmann constant - //!< * temperature (eV)) - double ncrystal_xs {-1.0}; //!< NCrystal cross section + double last_E {0.0}; //!< Last evaluated energy + double last_sqrtkT {0.0}; //!< Last temperature in sqrt(Boltzmann constant + //!< * temperature (eV)) }; //============================================================================== @@ -215,241 +170,16 @@ struct MacroXS { double pair_production; //!< macroscopic pair production xs }; -//============================================================================== -// Cache contains the cached data for an MGXS object -//============================================================================== - -struct CacheDataMG { - int material {-1}; //!< material index - double sqrtkT; //!< last temperature corresponding to t - int t {0}; //!< temperature index - int a {0}; //!< angle index - Direction u; //!< angle that corresponds to a -}; - //============================================================================== // Information about nearest boundary crossing //============================================================================== -class BoundaryInfo { -public: - void reset() - { - distance_ = INFINITY; - surface_ = SURFACE_NONE; - coord_level_ = 0; - lattice_translation_ = {0, 0, 0}; - } - double& distance() { return distance_; } - const double& distance() const { return distance_; } - - int& surface() { return surface_; } - const int& surface() const { return surface_; } - - int coord_level() const { return coord_level_; } - int& coord_level() { return coord_level_; } - - array& lattice_translation() { return lattice_translation_; } - const array& lattice_translation() const - { - return lattice_translation_; - } - - // TODO: off-by-one - int surface_index() const { return std::abs(surface()) - 1; } - -private: - // Data members - double distance_ {INFINITY}; //!< distance to nearest boundary - int surface_ { - SURFACE_NONE}; //!< surface token, non-zero if boundary is surface - int coord_level_ {0}; //!< coordinate level after crossing boundary - array lattice_translation_ { - 0, 0, 0}; //!< which way lattice indices will change -}; - -/* - * Contains all geometry state information for a particle. - */ -class GeometryState { -public: - GeometryState(); - - /* - * GeometryState does not store any ID info, so give some reasonable behavior - * here. The Particle class redefines this. This is only here for the error - * reporting behavior that occurs in geometry.cpp. The explanation for - * mark_as_lost is the same. - */ - virtual void mark_as_lost(const char* message); - void mark_as_lost(const std::string& message); - void mark_as_lost(const std::stringstream& message); - - // resets all coordinate levels for the particle - void clear() - { - for (auto& level : coord_) { - level.reset(); - } - n_coord_ = 1; - - for (auto& cell : cell_last_) { - cell = C_NONE; - } - n_coord_last_ = 1; - } - - //! moves the particle by the specified distance to its next location - //! \param distance the distance the particle is moved - void move_distance(double distance); - - void advance_to_boundary_from_void(); - - // Initialize all internal state from position and direction - void init_from_r_u(Position r_a, Direction u_a) - { - clear(); - surface() = SURFACE_NONE; - material() = C_NONE; - r() = r_a; - u() = u_a; - r_last_current() = r_a; - r_last() = r_a; - u_last() = u_a; - } - - // Unique ID. This is not geometric info, but the - // error reporting in geometry.cpp requires this. - // We could save this to implement it in Particle, - // but that would require virtuals. - int64_t& id() { return id_; } - const int64_t& id() const { return id_; } - - // Number of current coordinate levels - int& n_coord() { return n_coord_; } - const int& n_coord() const { return n_coord_; } - - // Offset for distributed properties - int& cell_instance() { return cell_instance_; } - const int& cell_instance() const { return cell_instance_; } - - // Coordinates for all nesting levels - LocalCoord& coord(int i) { return coord_[i]; } - const LocalCoord& coord(int i) const { return coord_[i]; } - const vector& coord() const { return coord_; } - - // Innermost universe nesting coordinates - LocalCoord& lowest_coord() { return coord_[n_coord_ - 1]; } - const LocalCoord& lowest_coord() const { return coord_[n_coord_ - 1]; } - - // Last coordinates on all nesting levels, before crossing a surface - int& n_coord_last() { return n_coord_last_; } - const int& n_coord_last() const { return n_coord_last_; } - int& cell_last(int i) { return cell_last_[i]; } - const int& cell_last(int i) const { return cell_last_[i]; } - - // Coordinates at birth - Position& r_born() { return r_born_; } - const Position& r_born() const { return r_born_; } - - // Coordinates of last collision or reflective/periodic surface - // crossing for current tallies - Position& r_last_current() { return r_last_current_; } - const Position& r_last_current() const { return r_last_current_; } - - // Previous direction and spatial coordinates before a collision - Position& r_last() { return r_last_; } - const Position& r_last() const { return r_last_; } - Position& u_last() { return u_last_; } - const Position& u_last() const { return u_last_; } - - // Accessors for position in global coordinates - Position& r() { return coord_[0].r(); } - const Position& r() const { return coord_[0].r(); } - - // Accessors for position in local coordinates - Position& r_local() { return coord_[n_coord_ - 1].r(); } - const Position& r_local() const { return coord_[n_coord_ - 1].r(); } - - // Accessors for direction in global coordinates - Direction& u() { return coord_[0].u(); } - const Direction& u() const { return coord_[0].u(); } - - // Accessors for direction in local coordinates - Direction& u_local() { return coord_[n_coord_ - 1].u(); } - const Direction& u_local() const { return coord_[n_coord_ - 1].u(); } - - // Surface token for the surface that the particle is currently on - int& surface() { return surface_; } - const int& surface() const { return surface_; } - - // Surface index based on the current value of the surface_ attribute - int surface_index() const - { - // TODO: off-by-one - return std::abs(surface_) - 1; - } - - // Boundary information - BoundaryInfo& boundary() { return boundary_; } - -#ifdef OPENMC_DAGMC_ENABLED - // DagMC state variables - moab::DagMC::RayHistory& history() { return history_; } - Direction& last_dir() { return last_dir_; } -#endif - - // material of current and last cell - int& material() { return material_; } - const int& material() const { return material_; } - int& material_last() { return material_last_; } - const int& material_last() const { return material_last_; } - - // temperature of current and last cell - double& sqrtkT() { return sqrtkT_; } - const double& sqrtkT() const { return sqrtkT_; } - double& sqrtkT_last() { return sqrtkT_last_; } - - // density multiplier of the current and last cell - double& density_mult() { return density_mult_; } - const double& density_mult() const { return density_mult_; } - double& density_mult_last() { return density_mult_last_; } - -private: - int64_t id_ {-1}; //!< Unique ID - - int n_coord_ {1}; //!< number of current coordinate levels - int cell_instance_; //!< offset for distributed properties - vector coord_; //!< coordinates for all levels - - int n_coord_last_ {1}; //!< number of current coordinates - vector cell_last_; //!< coordinates for all levels - - Position r_born_; //!< coordinates at birth - Position r_last_current_; //!< coordinates of the last collision or - //!< reflective/periodic surface crossing for - //!< current tallies - Position r_last_; //!< previous coordinates - Direction u_last_; //!< previous direction coordinates - - int surface_ { - SURFACE_NONE}; //!< surface token for surface the particle is currently on - - BoundaryInfo boundary_; //!< Info about the next intersection - - int material_ {-1}; //!< index for current material - int material_last_ {-1}; //!< index for last material - - double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV - double sqrtkT_last_ {0.0}; //!< last temperature - - double density_mult_ {1.0}; //!< density multiplier - double density_mult_last_ {1.0}; //!< last density multiplier - -#ifdef OPENMC_DAGMC_ENABLED - moab::DagMC::RayHistory history_; - Direction last_dir_; -#endif +struct BoundaryInfo { + double distance {INFINITY}; //!< distance to nearest boundary + int surface_index {0}; //!< if boundary is surface, index in surfaces vector + int coord_level; //!< coordinate level after crossing boundary + array + lattice_translation {}; //!< which way lattice indices will change }; //============================================================================ @@ -487,123 +217,157 @@ private: * Algorithms.” Annals of Nuclear Energy 113 (March 2018): 506–18. * https://doi.org/10.1016/j.anucene.2017.11.032. */ -class ParticleData : public GeometryState { +class ParticleData { + +public: + ParticleData(); + private: //========================================================================== - // Data members -- see public: below for descriptions + // Data members (accessor methods are below) - vector neutron_xs_; - vector photon_xs_; - MacroXS macro_xs_; - CacheDataMG mg_xs_cache_; + // Cross section caches + vector neutron_xs_; //!< Microscopic neutron cross sections + vector photon_xs_; //!< Microscopic photon cross sections + MacroXS macro_xs_; //!< Macroscopic cross sections - ParticleType type_; + int64_t id_; //!< Unique ID + ParticleType type_ {ParticleType::neutron}; //!< Particle type (n, p, e, etc.) - double E_; - double E_last_; - int g_ {0}; - int g_last_; + int n_coord_ {1}; //!< number of current coordinate levels + int cell_instance_; //!< offset for distributed properties + vector coord_; //!< coordinates for all levels - double wgt_ {1.0}; - double wgt_born_ {1.0}; - double wgt_ww_born_ {-1.0}; - double mu_; - double time_ {0.0}; - double time_last_ {0.0}; - double wgt_last_ {1.0}; + // Particle coordinates before crossing a surface + int n_coord_last_ {1}; //!< number of current coordinates + vector cell_last_; //!< coordinates for all levels - bool fission_ {false}; - TallyEvent event_; - int event_nuclide_; - int event_mt_; - int delayed_group_ {0}; - int parent_nuclide_ {-1}; + // Energy data + double E_; //!< post-collision energy in eV + double E_last_; //!< pre-collision energy in eV + int g_ {0}; //!< post-collision energy group (MG only) + int g_last_; //!< pre-collision energy group (MG only) - int n_bank_ {0}; - double bank_second_E_ {0.0}; - double wgt_bank_ {0.0}; - int n_delayed_bank_[MAX_DELAYED_GROUPS]; + // Other physical data + double wgt_ {1.0}; //!< particle weight + double mu_; //!< angle of scatter + double time_ {0.0}; //!< time in [s] + double time_last_ {0.0}; //!< previous time in [s] - int cell_born_ {-1}; + // Other physical data + Position r_last_current_; //!< coordinates of the last collision or + //!< reflective/periodic surface crossing for + //!< current tallies + Position r_last_; //!< previous coordinates + Direction u_last_; //!< previous direction coordinates + double wgt_last_ {1.0}; //!< pre-collision particle weight - // Iterated Fission Probability - double lifetime_ {0.0}; //!< neutron lifetime [s] + // What event took place + bool fission_ {false}; //!< did particle cause implicit fission + TallyEvent event_; //!< scatter, absorption + int event_nuclide_; //!< index in nuclides array + int event_mt_; //!< reaction MT + int delayed_group_ {0}; //!< delayed group - int n_collision_ {0}; + // Post-collision physical data + int n_bank_ {0}; //!< number of fission sites banked + int n_bank_second_ {0}; //!< number of secondary particles banked + double wgt_bank_ {0.0}; //!< weight of fission sites banked + int n_delayed_bank_[MAX_DELAYED_GROUPS]; //!< number of delayed fission + //!< sites banked + // Indices for various arrays + int surface_ {0}; //!< index for surface particle is on + int cell_born_ {-1}; //!< index for cell particle was born in + int material_ {-1}; //!< index for current material + int material_last_ {-1}; //!< index for last material + + // Boundary information + BoundaryInfo boundary_; + + // Temperature of current cell + double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV + double sqrtkT_last_ {0.0}; //!< last temperature + + // Statistical data + int n_collision_ {0}; //!< number of collisions + + // Track output bool write_track_ {false}; - uint64_t seeds_[N_STREAMS]; - int stream_; + // Current PRNG state + uint64_t seeds_[N_STREAMS]; // current seeds + int stream_; // current RNG stream - vector local_secondary_bank_; + // Secondary particle bank + vector secondary_bank_; - // 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_; // current work index - int64_t current_work_ {0}; + vector flux_derivs_; // for derivatives for this particle - vector flux_derivs_; + vector filter_matches_; // tally filter matches - vector filter_matches_; + vector tracks_; // tracks for outputting to file - vector tracks_; - - vector nu_bank_; - - vector pht_storage_; + vector nu_bank_; // bank of most recently fissioned particles + // Global tally accumulators double keff_tally_absorption_ {0.0}; double keff_tally_collision_ {0.0}; double keff_tally_tracklength_ {0.0}; double keff_tally_leakage_ {0.0}; - bool trace_ {false}; + bool trace_ {false}; //!< flag to show debug information - double collision_distance_; + double collision_distance_; // distance to particle's next closest collision - int n_event_ {0}; + int n_event_ {0}; // number of events executed in this particle's history - int64_t n_tracks_ {0}; //!< number of tracks in this particle history + // Weight window information + int n_split_ {0}; // Number of times this particle has been split + double ww_factor_ { + 0.0}; // Particle-specific factor for on-the-fly weight window adjustment - int64_t n_split_ {0}; - double ww_factor_ {0.0}; +// DagMC state variables +#ifdef DAGMC + moab::DagMC::RayHistory history_; + Direction last_dir_; +#endif - int64_t n_progeny_ {0}; + int64_t n_progeny_ {0}; // Number of progeny produced by this particle public: - //---------------------------------------------------------------------------- - // Constructors - ParticleData(); - //========================================================================== // Methods and accessors - // Cross section caches - // Microscopic neutron cross sections NuclideMicroXS& neutron_xs(int i) { return neutron_xs_[i]; } const NuclideMicroXS& neutron_xs(int i) const { return neutron_xs_[i]; } - - // Microscopic photon cross sections ElementMicroXS& photon_xs(int i) { return photon_xs_[i]; } - - // Macroscopic cross sections MacroXS& macro_xs() { return macro_xs_; } const MacroXS& macro_xs() const { return macro_xs_; } - // Multigroup macroscopic cross sections - CacheDataMG& mg_xs_cache() { return mg_xs_cache_; } - const CacheDataMG& mg_xs_cache() const { return mg_xs_cache_; } - - // Particle type (n, p, e, gamma, etc) + int64_t& id() { return id_; } + const int64_t& id() const { return id_; } ParticleType& type() { return type_; } const ParticleType& type() const { return type_; } - // Current particle energy, energy before collision, - // and corresponding multigroup group indices. Energy - // units are eV. + int& n_coord() { return n_coord_; } + const int& n_coord() const { return n_coord_; } + int& cell_instance() { return cell_instance_; } + const int& cell_instance() const { return cell_instance_; } + LocalCoord& coord(int i) { return coord_[i]; } + const LocalCoord& coord(int i) const { return coord_[i]; } + const vector& coord() const { return coord_; } + + LocalCoord& lowest_coord() { return coord_[n_coord_ - 1]; } + const LocalCoord& lowest_coord() const { return coord_[n_coord_ - 1]; } + + int& n_coord_last() { return n_coord_last_; } + const int& n_coord_last() const { return n_coord_last_; } + int& cell_last(int i) { return cell_last_[i]; } + const int& cell_last(int i) const { return cell_last_[i]; } + double& E() { return E_; } const double& E() const { return E_; } double& E_last() { return E_last_; } @@ -613,158 +377,111 @@ public: int& g_last() { return g_last_; } const int& g_last() const { return g_last_; } - // Statistic weight of particle. Setting to zero indicates that the particle - // is dead. double& wgt() { return wgt_; } double wgt() const { return wgt_; } - - // Statistic weight of particle at birth - double& wgt_born() { return wgt_born_; } - double wgt_born() const { return wgt_born_; } - - // Weight window value at birth - double& wgt_ww_born() { return wgt_ww_born_; } - const double& wgt_ww_born() const { return wgt_ww_born_; } - - // Statistic weight of particle at last collision - double& wgt_last() { return wgt_last_; } - const double& wgt_last() const { return wgt_last_; } - - // Whether particle is alive - bool alive() const { return wgt_ != 0.0; } - - // Polar scattering angle after a collision double& mu() { return mu_; } const double& mu() const { return mu_; } - - // Tracks the time of a particle as it traverses the problem. - // Units are seconds. double& time() { return time_; } const double& time() const { return time_; } double& time_last() { return time_last_; } const double& time_last() const { return time_last_; } + bool alive() const { return wgt_ != 0.0; } - // Particle lifetime - double& lifetime() { return lifetime_; } - const double& lifetime() const { return lifetime_; } + Position& r_last_current() { return r_last_current_; } + const Position& r_last_current() const { return r_last_current_; } + Position& r_last() { return r_last_; } + const Position& r_last() const { return r_last_; } + Position& u_last() { return u_last_; } + const Position& u_last() const { return u_last_; } + double& wgt_last() { return wgt_last_; } + const double& wgt_last() const { return wgt_last_; } - // What event took place, described in greater detail below + bool& fission() { return fission_; } TallyEvent& event() { return event_; } const TallyEvent& event() const { return event_; } - bool& fission() { return fission_; } // true if implicit fission - int& event_nuclide() { return event_nuclide_; } // index of collision nuclide + int& event_nuclide() { return event_nuclide_; } const int& event_nuclide() const { return event_nuclide_; } - int& event_mt() { return event_mt_; } // MT number of collision - const int& event_mt() const { return event_mt_; } - int& delayed_group() { return delayed_group_; } // delayed group - const int& delayed_group() const { return delayed_group_; } - const int& parent_nuclide() const { return parent_nuclide_; } - int& parent_nuclide() { return parent_nuclide_; } // Parent nuclide + int& event_mt() { return event_mt_; } + int& delayed_group() { return delayed_group_; } - // Post-collision data - double& bank_second_E() - { - return bank_second_E_; - } // energy of last reaction secondaries - const double& bank_second_E() const { return bank_second_E_; } + int& n_bank() { return n_bank_; } + int& n_bank_second() { return n_bank_second_; } + double& wgt_bank() { return wgt_bank_; } + int* n_delayed_bank() { return n_delayed_bank_; } + int& n_delayed_bank(int i) { return n_delayed_bank_[i]; } - int& n_bank() { return n_bank_; } // number of banked fission sites - double& wgt_bank() { return wgt_bank_; } // weight of banked fission sites - int* n_delayed_bank() - { - return n_delayed_bank_; - } // number of delayed fission sites - int& n_delayed_bank(int i) - { - return n_delayed_bank_[i]; - } // number of delayed fission sites - - // Index of cell particle is born in + int& surface() { return surface_; } + const int& surface() const { return surface_; } int& cell_born() { return cell_born_; } const int& cell_born() const { return cell_born_; } + int& material() { return material_; } + const int& material() const { return material_; } + int& material_last() { return material_last_; } + + BoundaryInfo& boundary() { return boundary_; } + + double& sqrtkT() { return sqrtkT_; } + const double& sqrtkT() const { return sqrtkT_; } + double& sqrtkT_last() { return sqrtkT_last_; } - // Total number of collisions suffered by particle int& n_collision() { return n_collision_; } const int& n_collision() const { return n_collision_; } - // whether this track is to be written bool& write_track() { return write_track_; } - - // RNG state uint64_t& seeds(int i) { return seeds_[i]; } uint64_t* seeds() { return seeds_; } int& stream() { return stream_; } - // secondary particle 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 + SourceSite& secondary_bank(int i) { return secondary_bank_[i]; } + decltype(secondary_bank_)& secondary_bank() { return secondary_bank_; } int64_t& current_work() { return current_work_; } const int64_t& current_work() const { return current_work_; } - - // Used in tally derivatives double& flux_derivs(int i) { return flux_derivs_[i]; } const double& flux_derivs(int i) const { return flux_derivs_[i]; } - - // Matches of tallies decltype(filter_matches_)& filter_matches() { return filter_matches_; } FilterMatch& filter_matches(int i) { return filter_matches_[i]; } - - // Tracks to output to file decltype(tracks_)& tracks() { return tracks_; } - - // Bank of recently fissioned particles decltype(nu_bank_)& nu_bank() { return nu_bank_; } NuBank& nu_bank(int i) { return nu_bank_[i]; } - // Interim pulse height tally storage - vector& pht_storage() { return pht_storage_; } - - // Global tally accumulators double& keff_tally_absorption() { return keff_tally_absorption_; } double& keff_tally_collision() { return keff_tally_collision_; } double& keff_tally_tracklength() { return keff_tally_tracklength_; } double& keff_tally_leakage() { return keff_tally_leakage_; } - // Shows debug info bool& trace() { return trace_; } - - // Distance to the next collision double& collision_distance() { return collision_distance_; } - - // Number of events particle has undergone int& n_event() { return n_event_; } - // Number of times variance reduction has caused a particle split - int64_t n_split() const { return n_split_; } - int64_t& n_split() { return n_split_; } + int n_split() const { return n_split_; } + int& 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_; } +#ifdef DAGMC + moab::DagMC::RayHistory& history() { return history_; } + Direction& last_dir() { return last_dir_; } +#endif - // Number of progeny produced by this particle int64_t& n_progeny() { return n_progeny_; } + // Accessors for position in global coordinates + Position& r() { return coord_[0].r; } + const Position& r() const { return coord_[0].r; } + + // Accessors for position in local coordinates + Position& r_local() { return coord_[n_coord_ - 1].r; } + const Position& r_local() const { return coord_[n_coord_ - 1].r; } + + // Accessors for direction in global coordinates + Direction& u() { return coord_[0].u; } + const Direction& u() const { return coord_[0].u; } + + // Accessors for direction in local coordinates + Direction& u_local() { return coord_[n_coord_ - 1].u; } + const Direction& u_local() const { return coord_[n_coord_ - 1].u; } + //! Gets the pointer to the particle's current PRN seed uint64_t* current_seed() { return seeds_ + stream_; } const uint64_t* current_seed() const { return seeds_ + stream_; } @@ -776,6 +493,14 @@ public: micro.last_E = 0.0; } + //! resets all coordinate levels for the particle + void clear() + { + for (auto& level : coord_) + level.reset(); + n_coord_ = 1; + } + //! Get track information based on particle's current state TrackState get_track_state() const; diff --git a/include/openmc/particle_type.h b/include/openmc/particle_type.h deleted file mode 100644 index 0fd896c57..000000000 --- a/include/openmc/particle_type.h +++ /dev/null @@ -1,184 +0,0 @@ -//============================================================================== -// ParticleType class definition -//============================================================================== - -#ifndef OPENMC_PARTICLE_TYPE_H -#define OPENMC_PARTICLE_TYPE_H - -#include -#include -#include -#include -#include - -#include "openmc/constants.h" -#include "openmc/error.h" - -namespace openmc { - -//------------------------------------------------------------------------------ -// PDG constants (canonical particle identity as simple integers) -//------------------------------------------------------------------------------ - -inline constexpr int32_t PDG_NEUTRON = 2112; -inline constexpr int32_t PDG_PHOTON = 22; -inline constexpr int32_t PDG_ELECTRON = 11; -inline constexpr int32_t PDG_POSITRON = -11; -inline constexpr int32_t PDG_PROTON = 2212; -inline constexpr int32_t PDG_DEUTERON = 1000010020; -inline constexpr int32_t PDG_TRITON = 1000010030; -inline constexpr int32_t PDG_ALPHA = 1000020040; - -//------------------------------------------------------------------------------ -// ParticleType class (standard-layout, trivially copyable) -//------------------------------------------------------------------------------ - -class ParticleType { -public: - //---------------------------------------------------------------------------- - // Constructors - - // Default constructor: defaults to neutron - constexpr ParticleType() : pdg_number_(PDG_NEUTRON) {} - - // Constructor from PDG number - constexpr explicit ParticleType(int32_t pdg_number) : pdg_number_(pdg_number) - {} - - // Constructor from particle name string (e.g., "neutron", "photon", "Fe56") - explicit ParticleType(std::string_view str); - - // Constructor from Z, A, and metastable state for nuclear particles - constexpr ParticleType(int Z, int A, int m = 0) - : pdg_number_(1000000000 + Z * 10000 + A * 10 + m) - {} - - //---------------------------------------------------------------------------- - // Accessors - - // Accessor for the underlying PDG number - constexpr int32_t pdg_number() const { return pdg_number_; } - - //---------------------------------------------------------------------------- - // Methods - - // Get particle mass in [u] - double mass() const - { - int32_t p = std::abs(pdg_number_); - if (ATOMIC_MASS.count(p)) { - return ATOMIC_MASS[p]; - } else { - fatal_error("Unknown mass for particle " + str()); - } - } - - // Convert to string representation - std::string str() const; - - // Check if this represents a nucleus (vs elementary particle) - constexpr bool is_nucleus() const - { - // PDG nuclear codes are >= 1000000000 (100ZZZAAAI format) - return pdg_number_ >= 1000000000; - } - - // Get transport index (0-3 for transportable particles, C_NONE otherwise) - constexpr int transport_index() const; - - // Check if this is a neutron - constexpr bool is_neutron() const { return pdg_number_ == PDG_NEUTRON; } - - // Check if this is a photon - constexpr bool is_photon() const { return pdg_number_ == PDG_PHOTON; } - - constexpr bool is_transportable() const - { - return this->transport_index() != C_NONE; - } - - //---------------------------------------------------------------------------- - // Static factory methods - - static constexpr ParticleType neutron() { return ParticleType {PDG_NEUTRON}; } - static constexpr ParticleType photon() { return ParticleType {PDG_PHOTON}; } - static constexpr ParticleType electron() - { - return ParticleType {PDG_ELECTRON}; - } - static constexpr ParticleType positron() - { - return ParticleType {PDG_POSITRON}; - } - static constexpr ParticleType proton() { return ParticleType {PDG_PROTON}; } - static constexpr ParticleType deuteron() - { - return ParticleType {PDG_DEUTERON}; - } - static constexpr ParticleType triton() { return ParticleType {PDG_TRITON}; } - static constexpr ParticleType alpha() { return ParticleType {PDG_ALPHA}; } - -private: - int32_t pdg_number_; -}; - -//------------------------------------------------------------------------------ -// Static assertions to ensure standard-layout and trivially copyable -//------------------------------------------------------------------------------ - -static_assert(std::is_standard_layout_v, - "ParticleType must be standard-layout"); -static_assert(std::is_trivially_copyable_v, - "ParticleType must be trivially copyable"); -static_assert(sizeof(ParticleType) == sizeof(int32_t), - "ParticleType must be same size as int32_t"); - -//------------------------------------------------------------------------------ -// Comparison operators (free functions for symmetry) -//------------------------------------------------------------------------------ - -constexpr bool operator==(ParticleType lhs, ParticleType rhs) -{ - return lhs.pdg_number() == rhs.pdg_number(); -} - -constexpr bool operator!=(ParticleType lhs, ParticleType rhs) -{ - return lhs.pdg_number() != rhs.pdg_number(); -} - -constexpr bool operator<(ParticleType lhs, ParticleType rhs) -{ - return lhs.pdg_number() < rhs.pdg_number(); -} - -//------------------------------------------------------------------------------ -// ParticleType member function implementations (inline) -//------------------------------------------------------------------------------ - -constexpr int ParticleType::transport_index() const -{ - switch (pdg_number_) { - case PDG_NEUTRON: - return 0; - case PDG_PHOTON: - return 1; - case PDG_ELECTRON: - return 2; - case PDG_POSITRON: - return 3; - default: - return C_NONE; - } -} - -//------------------------------------------------------------------------------ -// Legacy conversion helpers -//------------------------------------------------------------------------------ - -// Legacy enum code (0..3) to ParticleType conversion -ParticleType legacy_particle_index_to_type(int code); - -} // namespace openmc - -#endif // OPENMC_PARTICLE_TYPE_H diff --git a/include/openmc/photon.h b/include/openmc/photon.h index 93c6dba53..09fb3ba01 100644 --- a/include/openmc/photon.h +++ b/include/openmc/photon.h @@ -6,7 +6,8 @@ #include "openmc/particle.h" #include "openmc/vector.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" +#include #include #include @@ -33,6 +34,7 @@ public: int index_subshell; //!< index in SUBSHELLS int threshold; + double n_electrons; double binding_energy; vector transitions; }; @@ -59,17 +61,17 @@ public: // Data members std::string name_; //!< Name of element, e.g. "Zr" int Z_; //!< Atomic number - int64_t index_; //!< Index in global elements vector + gsl::index index_; //!< Index in global elements vector // Microscopic cross sections - tensor::Tensor energy_; - tensor::Tensor coherent_; - tensor::Tensor incoherent_; - tensor::Tensor photoelectric_total_; - tensor::Tensor pair_production_total_; - tensor::Tensor pair_production_electron_; - tensor::Tensor pair_production_nuclear_; - tensor::Tensor heating_; + xt::xtensor energy_; + xt::xtensor coherent_; + xt::xtensor incoherent_; + xt::xtensor photoelectric_total_; + xt::xtensor pair_production_total_; + xt::xtensor pair_production_electron_; + xt::xtensor pair_production_nuclear_; + xt::xtensor heating_; // Form factors Tabulated1D incoherent_form_factor_; @@ -81,30 +83,22 @@ public: // stored separately to improve memory access pattern when calculating the // total cross section vector shells_; - tensor::Tensor cross_sections_; + xt::xtensor cross_sections_; // Compton profile data - tensor::Tensor profile_pdf_; - tensor::Tensor profile_cdf_; - tensor::Tensor binding_energy_; - tensor::Tensor electron_pdf_; - - // Map subshells from Compton profile data obtained from Biggs et al, - // "Hartree-Fock Compton profiles for the elements" to ENDF/B atomic - // relaxation data - tensor::Tensor subshell_map_; + xt::xtensor profile_pdf_; + xt::xtensor profile_cdf_; + xt::xtensor binding_energy_; + xt::xtensor electron_pdf_; // Stopping power data double I_; // mean excitation energy - tensor::Tensor n_electrons_; - tensor::Tensor ionization_energy_; - tensor::Tensor stopping_power_radiative_; + xt::xtensor n_electrons_; + xt::xtensor ionization_energy_; + xt::xtensor stopping_power_radiative_; // Bremsstrahlung scaled DCS - tensor::Tensor dcs_; - - // Whether atomic relaxation data is present - bool has_atomic_relaxation_ {false}; + xt::xtensor dcs_; // Constant data static constexpr int MAX_STACK_SIZE = @@ -137,7 +131,7 @@ void free_memory_photon(); namespace data { -extern tensor::Tensor +extern xt::xtensor compton_profile_pz; //! Compton profile momentum grid //! Photon interaction data for each element diff --git a/include/openmc/physics.h b/include/openmc/physics.h index 2472d9799..262b3a884 100644 --- a/include/openmc/physics.h +++ b/include/openmc/physics.h @@ -10,6 +10,13 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +// Monoatomic ideal-gas scattering treatment threshold +constexpr double FREE_GAS_THRESHOLD {400.0}; + //============================================================================== // Non-member functions //============================================================================== @@ -80,8 +87,8 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, Direction sample_cxs_target_velocity( double awr, double E, Direction u, double kT, uint64_t* seed); -void sample_fission_neutron( - int i_nuclide, const Reaction& rx, SourceSite* site, Particle& p); +void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, + SourceSite* site, uint64_t* seed); //! handles all reactions with a single secondary neutron (other than fission), //! i.e. level scattering, (n,np), (n,na), etc. @@ -89,9 +96,8 @@ void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p); void sample_secondary_photons(Particle& p, int i_nuclide); -//! Split or Roulette particles based their weight and the lower weight window -//! bound. -// +//!Split or Roulette particles based their weight and the lower weight window +// bound. //! \param[in] p, particle to be split or rouletted with the weight window. void split_particle(Particle& p); diff --git a/include/openmc/physics_common.h b/include/openmc/physics_common.h index b0e395c1e..e38a3c7f8 100644 --- a/include/openmc/physics_common.h +++ b/include/openmc/physics_common.h @@ -13,9 +13,5 @@ namespace openmc { //! \param[in] weight_survive Weight assigned to particles that survive void russian_roulette(Particle& p, double weight_survive); -//! \brief Performs the global russian roulette operation on a particle -//! \param[in,out] p Particle object -void apply_russian_roulette(Particle& p); - } // namespace openmc #endif // OPENMC_PHYSICS_COMMON_H diff --git a/include/openmc/plot.h b/include/openmc/plot.h index ba8ac84a1..650b7e16a 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -1,14 +1,11 @@ #ifndef OPENMC_PLOT_H #define OPENMC_PLOT_H -#include #include #include -#include -#include -#include "openmc/tensor.h" #include "pugixml.hpp" +#include "xtensor/xarray.hpp" #include "hdf5.h" #include "openmc/cell.h" @@ -18,9 +15,6 @@ #include "openmc/particle.h" #include "openmc/position.h" #include "openmc/random_lcg.h" -#include "openmc/ray.h" -#include "openmc/tallies/filter.h" -#include "openmc/tallies/filter_match.h" #include "openmc/xml_interface.h" namespace openmc { @@ -29,13 +23,12 @@ namespace openmc { // Global variables //=============================================================================== -class PlottableInterface; +class Plot; namespace model { extern std::unordered_map plot_map; //!< map of plot ids to index -extern vector> - plots; //!< Plot instance container +extern vector plots; //!< Plot instance container extern uint64_t plotter_seed; // Stream index used by the plotter @@ -66,14 +59,6 @@ struct RGBColor { return red == other.red && green == other.green && blue == other.blue; } - RGBColor& operator*=(const double x) - { - red *= x; - green *= x; - blue *= x; - return *this; - } - // Members uint8_t red, green, blue; }; @@ -81,194 +66,112 @@ struct RGBColor { // some default colors const RGBColor WHITE {255, 255, 255}; const RGBColor RED {255, 0, 0}; -const RGBColor BLACK {0, 0, 0}; -/** - * \class PlottableInterface - * \brief Interface for plottable objects. - * - * PlottableInterface classes must have unique IDs. If no ID (or -1) is - * provided, the next available ID is assigned automatically. They guarantee - * the ability to create output in some form. This interface is designed to be - * implemented by classes that produce plot-relevant data which can be - * visualized. - */ - -typedef tensor::Tensor ImageData; -class PlottableInterface { -public: - PlottableInterface() = default; - - void set_default_colors(); - -private: - void set_id(pugi::xml_node plot_node); - int id_ {C_NONE}; // unique plot ID - - void set_bg_color(pugi::xml_node plot_node); - void set_universe(pugi::xml_node plot_node); - void set_color_by(pugi::xml_node plot_node); - void set_user_colors(pugi::xml_node plot_node); - void set_overlap_color(pugi::xml_node plot_node); - void set_mask(pugi::xml_node plot_node); - -protected: - // Plot output filename, derived classes have logic to set it - std::string path_plot_; - -public: - enum class PlotColorBy { cells = 0, mats = 1 }; - - // Generates image data based on plot parameters and returns it - virtual ImageData create_image() const = 0; - - // Creates the output image named path_plot_ - virtual void create_output() const = 0; - - // Write populated image data to file - void write_image(const ImageData& data) const; - - // Print useful info to the terminal - virtual void print_info() const = 0; - - const std::string& path_plot() const { return path_plot_; } - std::string& path_plot() { return path_plot_; } - int id() const { return id_; } - void set_id(int id = C_NONE); - int level() const { return level_; } - PlotColorBy color_by() const { return color_by_; } - - // Public color-related data - PlottableInterface(pugi::xml_node plot_node); - virtual ~PlottableInterface() = default; - int level_ {-1}; // Universe level to plot - bool color_overlaps_ {false}; // Show overlapping cells? - PlotColorBy color_by_ {PlotColorBy::mats}; // Plot coloring (cell/material) - RGBColor not_found_ {WHITE}; // Plot background color - RGBColor overlap_color_ {RED}; // Plot overlap color - vector colors_; // Plot colors -}; +typedef xt::xtensor ImageData; struct IdData { // Constructor - IdData(size_t h_res, size_t v_res, bool include_filter = false); + IdData(size_t h_res, size_t v_res); // Methods - void set_value(size_t y, size_t x, const Particle& p, int level, - Filter* filter = nullptr, FilterMatch* match = nullptr); - void set_overlap(size_t y, size_t x, int overlap_idx); + void set_value(size_t y, size_t x, const Particle& p, int level); + void set_overlap(size_t y, size_t x); // Members - tensor::Tensor data_; //!< 2D array of cell & material ids + xt::xtensor data_; //!< 2D array of cell & material ids }; struct PropertyData { // Constructor - PropertyData(size_t h_res, size_t v_res, bool include_filter = false); + PropertyData(size_t h_res, size_t v_res); // Methods - void set_value(size_t y, size_t x, const Particle& p, int level, - Filter* filter = nullptr, FilterMatch* match = nullptr); - void set_overlap(size_t y, size_t x, int overlap_idx); + void set_value(size_t y, size_t x, const Particle& p, int level); + void set_overlap(size_t y, size_t x); // Members - tensor::Tensor data_; //!< 2D array of temperature & density data + xt::xtensor data_; //!< 2D array of temperature & density data }; -struct RasterData { - // Constructor - RasterData(size_t h_res, size_t v_res, bool include_filter = false); +enum class PlotType { slice = 1, voxel = 2 }; - // Methods - void set_value(size_t y, size_t x, const Particle& p, int level, - Filter* filter = nullptr, FilterMatch* match = nullptr); - void set_overlap(size_t y, size_t x, int overlap_idx); +enum class PlotBasis { xy = 1, xz = 2, yz = 3 }; - // Members - tensor::Tensor - id_data_; //!< [v_res, h_res, 3 or 4]: cell, instance, mat, [filter_bin] - tensor::Tensor - property_data_; //!< [v_res, h_res, 2]: temperature, density - bool include_filter_; //!< Whether filter bin index is included -}; +enum class PlotColorBy { cells = 0, mats = 1 }; //=============================================================================== // Plot class //=============================================================================== - -class SlicePlotBase { +class PlotBase { public: template - T get_map(int32_t filter_index = -1) const; - - enum class PlotBasis { xy = 1, xz = 2, yz = 3 }; - - // Accessors - - const std::array& pixels() const { return pixels_; } - std::array& pixels() { return pixels_; } + T get_map() const; // Members public: Position origin_; //!< Plot origin in geometry - Direction u_span_; //!< Full-width span vector in geometry - Direction v_span_; //!< Full-height span vector in geometry + Position width_; //!< Plot width in geometry + PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) array pixels_; //!< Plot size in pixels - bool show_overlaps_; //!< Show overlapping cells? - int slice_level_ {-1}; //!< Plot universe level -private: + bool color_overlaps_; //!< Show overlapping cells? + int level_; //!< Plot universe level }; template -T SlicePlotBase::get_map(int32_t filter_index) const +T PlotBase::get_map() const { size_t width = pixels_[0]; size_t height = pixels_[1]; - // Determine if filter is being used - bool include_filter = (filter_index >= 0); - Filter* filter = nullptr; - if (include_filter) { - filter = model::tally_filters[filter_index].get(); - } + // get pixel size + double in_pixel = (width_[0]) / static_cast(width); + double out_pixel = (width_[1]) / static_cast(height); // size data array - T data(width, height, include_filter); + T data(width, height); - // compute pixel steps and top-left pixel center - Direction u_step = u_span_ / static_cast(width); - Direction v_step = v_span_ / static_cast(height); - - Position start = - origin_ - 0.5 * u_span_ + 0.5 * v_span_ + 0.5 * u_step - 0.5 * v_step; - - // Validate that span vectors define a valid plane - Position cross = u_span_.cross(v_span_); - if (cross.norm() == 0.0) { - fatal_error("Slice span vectors are invalid (zero area)."); + // setup basis indices and initial position centered on pixel + int in_i, out_i; + Position xyz = origin_; + switch (basis_) { + case PlotBasis::xy: + in_i = 0; + out_i = 1; + break; + case PlotBasis::xz: + in_i = 0; + out_i = 2; + break; + case PlotBasis::yz: + in_i = 1; + out_i = 2; + break; + default: + UNREACHABLE(); } - // Use an arbitrary direction that is not aligned with any coordinate axis. - // The direction has no physical meaning for plotting but is used by - // Surface::sense() to break ties when a pixel is coincident with a surface. - Direction dir = {1.0 / std::sqrt(2.0), 1.0 / std::sqrt(2.0), 0.0}; + // set initial position + xyz[in_i] = origin_[in_i] - width_[0] / 2. + in_pixel / 2.; + xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.; + + // arbitrary direction + Direction dir = {0.7071, 0.7071, 0.0}; #pragma omp parallel { Particle p; - p.r() = start; + p.r() = xyz; p.u() = dir; - p.coord(0).universe() = model::root_universe; - int level = slice_level_; + p.coord(0).universe = model::root_universe; + int level = level_; int j {}; - FilterMatch match; #pragma omp for for (int y = 0; y < height; y++) { - Position row = start - v_step * static_cast(y); + p.r()[out_i] = xyz[out_i] - out_pixel * y; for (int x = 0; x < width; x++) { - p.r() = row + u_step * static_cast(x); + p.r()[in_i] = xyz[in_i] + in_pixel * x; p.n_coord() = 1; // local variables bool found_cell = exhaustive_find_cell(p); @@ -277,316 +180,73 @@ T SlicePlotBase::get_map(int32_t filter_index) const j = level; } if (found_cell) { - data.set_value(y, x, p, j, filter, &match); + data.set_value(y, x, p, j); } - if (show_overlaps_) { - int overlap_idx = check_cell_overlap(p, false); - if (overlap_idx >= 0) { - data.set_overlap(y, x, overlap_idx); - } + if (color_overlaps_ && check_cell_overlap(p, false)) { + data.set_overlap(y, x); } } // inner for - } - } + } // outer for + } // omp parallel return data; } -// Represents either a voxel or pixel plot -class Plot : public PlottableInterface, public SlicePlotBase { +class Plot : public PlotBase { public: - enum class PlotType { slice = 1, voxel = 2 }; - - Plot(pugi::xml_node plot, PlotType type); + // Constructor + Plot(pugi::xml_node plot); + // Methods private: + void set_id(pugi::xml_node plot_node); + void set_type(pugi::xml_node plot_node); void set_output_path(pugi::xml_node plot_node); + void set_bg_color(pugi::xml_node plot_node); void set_basis(pugi::xml_node plot_node); void set_origin(pugi::xml_node plot_node); void set_width(pugi::xml_node plot_node); + void set_universe(pugi::xml_node plot_node); + void set_default_colors(pugi::xml_node plot_node); + void set_user_colors(pugi::xml_node plot_node); void set_meshlines(pugi::xml_node plot_node); + void set_mask(pugi::xml_node plot_node); + void set_overlap_color(pugi::xml_node plot_node); + // Members public: - // Add mesh lines to ImageData - void draw_mesh_lines(ImageData& data) const; - ImageData create_image() const override; - void create_voxel() const; - - void create_output() const override; - void print_info() const override; - + int id_; //!< Plot ID PlotType type_; //!< Plot type (Slice/Voxel) - Position width_; //!< Axis-aligned width from plot.xml - PlotBasis basis_; //!< Basis from plot.xml for slice plots + PlotColorBy color_by_; //!< Plot coloring (cell/material) int meshlines_width_; //!< Width of lines added to the plot int index_meshlines_mesh_ {-1}; //!< Index of the mesh to draw on the plot RGBColor meshlines_color_; //!< Color of meshlines on the plot -}; - -/** - * \class RaytracePlot - * \brief Base class for plots that generate images through ray tracing. - * - * This class serves as a base for plots that create their visuals by tracing - * rays from a camera through the problem geometry. It inherits from - * PlottableInterface, ensuring that it provides an implementation for - * generating output specific to ray-traced visualization. WireframeRayTracePlot - * and SolidRayTracePlot provide concrete implementations of this class. - */ -class RayTracePlot : public PlottableInterface { -public: - RayTracePlot() = default; - RayTracePlot(pugi::xml_node plot); - - // Standard getters. No setting since it's done from XML. - const Position& camera_position() const { return camera_position_; } - Position& camera_position() { return camera_position_; } - const Position& look_at() const { return look_at_; } - Position& look_at() { return look_at_; } - - const double& horizontal_field_of_view() const - { - return horizontal_field_of_view_; - } - double& horizontal_field_of_view() { return horizontal_field_of_view_; } - - void print_info() const override; - - const std::array& pixels() const { return pixels_; } - std::array& pixels() { return pixels_; } - - const Direction& up() const { return up_; } - Direction& up() { return up_; } - - //! brief Updates the cached camera-to-model matrix after changes to - //! camera parameters. - void update_view(); - -protected: - Direction camera_x_axis() const - { - return {camera_to_model_[0], camera_to_model_[3], camera_to_model_[6]}; - } - - Direction camera_y_axis() const - { - return {camera_to_model_[1], camera_to_model_[4], camera_to_model_[7]}; - } - - Direction camera_z_axis() const - { - return {camera_to_model_[2], camera_to_model_[5], camera_to_model_[8]}; - } - - void set_output_path(pugi::xml_node plot_node); - - /* - * Gets the starting position and direction for the pixel corresponding - * to this horizontal and vertical position. - */ - std::pair get_pixel_ray(int horiz, int vert) const; - -private: - void set_look_at(pugi::xml_node node); - void set_camera_position(pugi::xml_node node); - void set_field_of_view(pugi::xml_node node); - void set_pixels(pugi::xml_node node); - void set_orthographic_width(pugi::xml_node node); - - double horizontal_field_of_view_ {70.0}; // horiz. f.o.v. in degrees - Position camera_position_; // where camera is - Position look_at_; // point camera is centered looking at - std::array pixels_ {100, 100}; // pixel dimension of resulting image - Direction up_ {0.0, 0.0, 1.0}; // which way is up - - /* The horizontal thickness, if using an orthographic projection. - * If set to zero, we assume using a perspective projection. - */ - double orthographic_width_ {C_NONE}; - - /* - * Cached camera-to-model matrix with column vectors of axes. The x-axis is - * the vector between the camera_position_ and look_at_; the y-axis is the - * cross product of the x-axis with the up_ vector, and the z-axis is the - * cross product of the x and y axes. - */ - std::array camera_to_model_; -}; - -class ProjectionRay; - -/** - * \class WireframeRayTracePlot - * \brief Creates plots that are like colorful x-ray imaging - * - * WireframeRayTracePlot is a specialized form of RayTracePlot designed for - * creating projection plots. This involves tracing rays from a camera through - * the problem geometry and rendering the results based on depth of penetration - * through materials or cells and their colors. - */ -class WireframeRayTracePlot : public RayTracePlot { - - friend class ProjectionRay; - -public: - WireframeRayTracePlot(pugi::xml_node plot); - - ImageData create_image() const override; - void create_output() const override; - void print_info() const override; - -private: - void set_opacities(pugi::xml_node node); - void set_wireframe_thickness(pugi::xml_node node); - void set_wireframe_ids(pugi::xml_node node); - void set_wireframe_color(pugi::xml_node node); - - /* Checks if a vector of two TrackSegments is equivalent. We define this - * to mean not having matching intersection lengths, but rather having - * a matching sequence of surface/cell/material intersections. - */ - struct TrackSegment; - bool trackstack_equivalent(const vector& track1, - const vector& track2) const; - - /* Used for drawing wireframe and colors. We record the list of - * surface/cell/material intersections and the corresponding lengths as a ray - * traverses the geometry, then color by iterating in reverse. - */ - struct TrackSegment { - int id; // material or cell ID (which is being colored) - double length; // length of this track intersection - - /* Recording this allows us to draw edges on the wireframe. For instance - * if two surfaces bound a single cell, it allows drawing that sharp edge - * where the surfaces intersect. - */ - int surface_index {-1}; // last surface index intersected in this segment - TrackSegment(int id_a, double length_a, int surface_a) - : id(id_a), length(length_a), surface_index(surface_a) - {} - }; - - // which color IDs should be wireframed. If empty, all cells are wireframed. - vector wireframe_ids_; - - // Thickness of the wireframe lines. Can set to zero for no wireframe. - int wireframe_thickness_ {1}; - - RGBColor wireframe_color_ {BLACK}; // wireframe color - vector xs_; // macro cross section values for cell volume rendering -}; - -/** - * \class SolidRayTracePlot - * \brief Plots 3D objects as the eye might see them. - * - * Plots a geometry with single-scattered Phong lighting plus a diffuse lighting - * contribution. The result is a physically reasonable, aesthetic 3D view of a - * geometry. - */ -class SolidRayTracePlot : public RayTracePlot { - friend class PhongRay; - -public: - SolidRayTracePlot() = default; - - SolidRayTracePlot(pugi::xml_node plot); - - ImageData create_image() const override; - void create_output() const override; - void print_info() const override; - - const std::unordered_set& opaque_ids() const { return opaque_ids_; } - std::unordered_set& opaque_ids() { return opaque_ids_; } - - const Position& light_location() const { return light_location_; } - Position& light_location() { return light_location_; } - - const double& diffuse_fraction() const { return diffuse_fraction_; } - double& diffuse_fraction() { return diffuse_fraction_; } - -private: - void set_opaque_ids(pugi::xml_node node); - void set_light_position(pugi::xml_node node); - void set_diffuse_fraction(pugi::xml_node node); - - std::unordered_set opaque_ids_; - - double diffuse_fraction_ {0.1}; - - // By default, the light is at the camera unless otherwise specified. - Position light_location_; -}; - -class ProjectionRay : public Ray { -public: - ProjectionRay(Position r, Direction u, const WireframeRayTracePlot& plot, - vector& line_segments) - : Ray(r, u), plot_(plot), line_segments_(line_segments) - {} - - void on_intersection() override; - -private: - /* Store a reference to the plot object which is running this ray, in order - * to access some of the plot settings which influence the behavior where - * intersections are. - */ - const WireframeRayTracePlot& plot_; - - /* The ray runs through the geometry, and records the lengths of ray segments - * and cells they lie in along the way. - */ - vector& line_segments_; -}; - -class PhongRay : public Ray { -public: - PhongRay(Position r, Direction u, const SolidRayTracePlot& plot) - : Ray(r, u), plot_(plot) - { - result_color_ = plot_.not_found_; - } - - void on_intersection() override; - - const RGBColor& result_color() { return result_color_; } - -private: - const SolidRayTracePlot& plot_; - - /* After the ray is reflected, it is moving towards the - * camera. It does that in order to see if the exposed surface - * is shadowed by something else. - */ - bool reflected_ {false}; - - // Have to record the first hit ID, so that if the region - // does get shadowed, we recall what its color should be - // when tracing from the surface to the light. - int orig_hit_id_ {-1}; - - RGBColor result_color_; + RGBColor not_found_ {WHITE}; //!< Plot background color + RGBColor overlap_color_ {RED}; //!< Plot overlap color + vector colors_; //!< Plot colors + std::string path_plot_; //!< Plot output filename }; //=============================================================================== // Non-member functions //=============================================================================== -/* Write a PPM image - * filename - name of output file - * data - image data to write - */ -void output_ppm(const std::string& filename, const ImageData& data); +//! Add mesh lines to image data of a plot object +//! \param[in] plot object +//! \param[out] image data associated with the plot object +void draw_mesh_lines(Plot const& pl, ImageData& data); + +//! Write a PPM image using a plot object's image data +//! \param[in] plot object +//! \param[out] image data associated with the plot object +void output_ppm(Plot const& pl, const ImageData& data); #ifdef USE_LIBPNG -/* Write a PNG image - * filename - name of output file - * data - image data to write - */ -void output_png(const std::string& filename, const ImageData& data); +//! Write a PNG image using a plot object's image data +//! \param[in] plot object +//! \param[out] image data associated with the plot object +void output_png(Plot const& pl, const ImageData& data); #endif //! Initialize a voxel file @@ -619,13 +279,17 @@ void voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace); //! Read plot specifications from a plots.xml file void read_plots_xml(); -//! Read plot specifications from an XML Node -//! \param[in] XML node containing plot info -void read_plots_xml(pugi::xml_node root); - //! Clear memory void free_memory_plot(); +//! Create an image for a plot object +//! \param[in] plot object +void create_image(Plot const& pl); + +//! Create an hdf5 voxel file for a plot object +//! \param[in] plot object +void create_voxel(Plot const& pl); + //! Create a randomly generated RGB color //! \return RGBColor with random value RGBColor random_color(); diff --git a/include/openmc/position.h b/include/openmc/position.h index 5d291d26b..4fde420cc 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -83,35 +83,14 @@ struct Position { return x * other.x + y * other.y + z * other.z; } inline double norm() const { return std::sqrt(x * x + y * y + z * z); } - inline Position cross(Position other) const - { - return {y * other.z - z * other.y, z * other.x - x * other.z, - x * other.y - y * other.x}; - } //! Reflect a direction across a normal vector //! \param[in] other Vector to reflect across //! \result Reflected vector Position reflect(Position n) const; - //! Rotate the position by applying a rotation matrix - template - Position rotate(const T& rotation) const - { - return {x * rotation[0] + y * rotation[1] + z * rotation[2], - x * rotation[3] + y * rotation[4] + z * rotation[5], - x * rotation[6] + y * rotation[7] + z * rotation[8]}; - } - - //! Rotate the position by applying the inverse of a rotation matrix - //! using the fact that rotation matrices are orthonormal. - template - Position inverse_rotate(const T& rotation) const - { - return {x * rotation[0] + y * rotation[3] + z * rotation[6], - x * rotation[1] + y * rotation[4] + z * rotation[7], - x * rotation[2] + y * rotation[5] + z * rotation[8]}; - } + //! Rotate the position based on a rotation matrix + Position rotate(const vector& rotation) const; // Data members double x = 0.; @@ -232,22 +211,14 @@ using Direction = Position; } // namespace openmc -namespace fmt { - template<> -struct formatter : formatter { +struct fmt::formatter : formatter { template -#if FMT_VERSION >= 110000 // Version 11.0.0 and above - auto format(const openmc::Position& pos, FormatContext& ctx) const { -#else // For versions below 11.0.0 auto format(const openmc::Position& pos, FormatContext& ctx) { -#endif - return formatter::format( + return fmt::formatter::format( fmt::format("({}, {}, {})", pos.x, pos.y, pos.z), ctx); -} -}; // namespace fmt - -} // namespace fmt + } +}; #endif // OPENMC_POSITION_H diff --git a/include/openmc/random_dist.h b/include/openmc/random_dist.h index 32f055b53..9bf55aa93 100644 --- a/include/openmc/random_dist.h +++ b/include/openmc/random_dist.h @@ -16,17 +16,6 @@ namespace openmc { double uniform_distribution(double a, double b, uint64_t* seed); -//============================================================================== -//! Sample an integer from uniform distribution [a, b] -// -//! \param a Lower bound of uniform distribution -//! \param b Upper bound of uniform distribtion -//! \param seed A pointer to the pseudorandom seed -//! \return Sampled variate -//============================================================================== - -int64_t uniform_int_distribution(int64_t a, int64_t b, uint64_t* seed); - //============================================================================== //! Samples an energy from the Maxwell fission distribution based on a direct //! sampling scheme. @@ -59,13 +48,13 @@ extern "C" double maxwell_spectrum(double T, uint64_t* seed); extern "C" double watt_spectrum(double a, double b, uint64_t* seed); //============================================================================== -//! Samples an energy from the Gaussian distribution. +//! Samples an energy from the Gaussian energy-dependent fission distribution. //! -//! Samples from a normal distribution with a given mean and standard deviation +//! Samples from a Normal distribution with a given mean and standard deviation //! The PDF is defined as s(x) = (1/2*sigma*sqrt(2) * e-((mu-x)/2*sigma)^2 //! Its sampled according to -//! https://pdg.lbl.gov/2023/reviews/rpp2023-rev-monte-carlo-techniques.pdf -//! section 42.4.4 +//! http://www-pdg.lbl.gov/2009/reviews/rpp2009-rev-monte-carlo-techniques.pdf +//! section 33.4.4 //! //! \param mean mean of the Gaussian distribution //! \param std_dev standard deviation of the Gaussian distribution @@ -75,6 +64,23 @@ extern "C" double watt_spectrum(double a, double b, uint64_t* seed); extern "C" double normal_variate(double mean, double std_dev, uint64_t* seed); +//============================================================================== +//! Samples an energy from the Muir (Gaussian) energy-dependent distribution. +//! +//! This is another form of the Gaussian distribution but with more easily +//! modifiable parameters +//! https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-05411-MS +//! +//! \param e0 peak neutron energy [eV] +//! \param m_rat ratio of the fusion reactants to AMU +//! \param kt the ion temperature of the reactants [eV] +//! \param seed A pointer to the pseudorandom seed +//! \result The sampled outgoing energy +//============================================================================== + +extern "C" double muir_spectrum( + double e0, double m_rat, double kt, uint64_t* seed); + } // namespace openmc #endif // OPENMC_RANDOM_DIST_H diff --git a/include/openmc/random_lcg.h b/include/openmc/random_lcg.h index 5aecafed3..4157b7cfe 100644 --- a/include/openmc/random_lcg.h +++ b/include/openmc/random_lcg.h @@ -15,7 +15,6 @@ constexpr int STREAM_SOURCE {1}; constexpr int STREAM_URR_PTABLE {2}; constexpr int STREAM_VOLUME {3}; constexpr int64_t DEFAULT_SEED {1}; -constexpr uint64_t DEFAULT_STRIDE {152917ULL}; //============================================================================== //! Generate a pseudo-random number using a linear congruential generator. @@ -99,18 +98,5 @@ extern "C" int64_t openmc_get_seed(); extern "C" void openmc_set_seed(int64_t new_seed); -//============================================================================== -//! Get OpenMC's stride. -//============================================================================== - -extern "C" uint64_t openmc_get_stride(); - -//============================================================================== -//! Set OpenMC's stride. -//! @param new_stride Stride. -//============================================================================== - -extern "C" void openmc_set_stride(uint64_t new_stride); - } // namespace openmc #endif // OPENMC_RANDOM_LCG_H diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h deleted file mode 100644 index 09414fd44..000000000 --- a/include/openmc/random_ray/flat_source_domain.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H -#define OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H - -#include "openmc/constants.h" -#include "openmc/openmp_interface.h" -#include "openmc/position.h" -#include "openmc/random_ray/parallel_map.h" -#include "openmc/random_ray/source_region.h" -#include "openmc/source.h" -#include -#include - -namespace openmc { - -/* - * The FlatSourceDomain class encompasses data and methods for storing - * scalar flux and source region for all flat source regions in a - * random ray simulation domain. - */ - -class FlatSourceDomain { -public: - //---------------------------------------------------------------------------- - // Constructors and Destructors - FlatSourceDomain(); - virtual ~FlatSourceDomain() = default; - - //---------------------------------------------------------------------------- - // Methods - virtual void update_single_neutron_source(SourceRegionHandle& srh); - virtual void update_all_neutron_sources(); - void compute_k_eff(); - virtual void normalize_scalar_flux_and_volumes( - double total_active_distance_per_iteration); - - int64_t add_source_to_scalar_flux(); - virtual void batch_reset(); - void convert_source_regions_to_tallies(int64_t start_sr_id); - void reset_tally_volumes(); - void random_ray_tally(); - virtual void accumulate_iteration_flux(); - void output_to_vtk() const; - void convert_external_sources(bool use_adjoint_sources); - void count_external_source_regions(); - void set_fw_adjoint_sources(); - void set_local_adjoint_sources(); - void flux_swap(); - virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const; - double compute_fixed_source_normalization_factor() const; - void flatten_xs(); - void transpose_scattering_matrix(); - void serialize_final_fluxes(vector& flux); - void apply_meshes(); - void apply_mesh_to_cell_instances(int32_t i_cell, int32_t mesh_idx, - int target_material_id, const vector& instances, - bool is_target_void); - void apply_mesh_to_cell_and_children(int32_t i_cell, int32_t mesh_idx, - int32_t target_material_id, bool is_target_void); - SourceRegionHandle get_subdivided_source_region_handle( - SourceRegionKey sr_key, Position r, Direction u); - void finalize_discovered_source_regions(); - void apply_transport_stabilization(); - int64_t n_source_regions() const - { - return source_regions_.n_source_regions(); - } - int64_t n_source_elements() const - { - return source_regions_.n_source_regions() * negroups_; - } - int64_t lookup_base_source_region_idx(const GeometryState& p) const; - SourceRegionKey lookup_source_region_key(const GeometryState& p) const; - int64_t lookup_mesh_bin(int64_t sr, Position r) const; - int lookup_mesh_idx(int64_t sr) const; - - //---------------------------------------------------------------------------- - // Static Data members - static bool volume_normalized_flux_tallies_; - // If the user wants outputs based on the adjoint flux - static bool adjoint_requested_; - // The solve currently being executed - static RandomRaySolve solve_; - static bool fw_cadis_local_; - static double - diagonal_stabilization_rho_; // Adjusts strength of diagonal stabilization - // for transport corrected MGXS data - - // Static variables to store source region meshes and domains - static std::unordered_map>> - mesh_domain_map_; - - static std::vector fw_cadis_local_targets_; - - //---------------------------------------------------------------------------- - // Static data members - static RandomRayVolumeEstimator volume_estimator_; - - //---------------------------------------------------------------------------- - // Public Data members - double k_eff_ {1.0}; // Eigenvalue - bool mapped_all_tallies_ {false}; // If all source regions have been visited - - int64_t n_external_source_regions_ {0}; // Total number of source regions with - // non-zero external source terms - - // 1D array representing source region starting offset for each OpenMC Cell - // in model::cells - vector source_region_offsets_; - - // 3D arrays stored in 1D representing values for all materials x temperature - // points x energy groups - int n_materials_; - int ntemperature_; - vector sigma_t_; - vector nu_sigma_f_; - vector sigma_f_; - vector chi_; - vector kappa_fission_; - - // 4D arrays stored in 1D representing values for all materials x temperature - // points x energy groups x energy groups - vector sigma_s_; - - // The abstract container holding all source region-specific data - SourceRegionContainer source_regions_; - - // Parallel hash map holding all source regions discovered during - // a single iteration. This is a threadsafe data structure that is cleaned - // out after each iteration and stored in the "source_regions_" container. - // It is keyed with a SourceRegionKey, which combines the base source - // region index and the mesh bin. - ParallelMap - discovered_source_regions_; - - // Map that relates a SourceRegionKey to the index at which the source - // region can be found in the "source_regions_" container. - std::unordered_map - source_region_map_; - - // Map that relates a SourceRegionKey to the external source index. This map - // is used to check if there are any point sources within a subdivided source - // region at the time it is discovered. - std::unordered_map, SourceRegionKey::HashFunctor> - external_point_source_map_; - - // Map that relates a base source region index to the external source index. - // This map is used to check if there are any volumetric sources within a - // subdivided source region at the time it is discovered. - std::unordered_map> external_volumetric_source_map_; - - // Map that relates a base source region index to a mesh index. This map - // is used to check which subdivision mesh is present in a source region. - std::unordered_map mesh_map_; - - // If transport corrected MGXS data is being used, there may be negative - // in-group scattering cross sections that can result in instability in MOC - // and random ray if used naively. This flag enables a stabilization - // technique. - bool is_transport_stabilization_needed_ {false}; - -protected: - //---------------------------------------------------------------------------- - // Methods - void apply_external_source_to_source_region( - int src_idx, SourceRegionHandle& srh); - void apply_external_source_to_cell_instances(int32_t i_cell, int src_idx, - int target_material_id, const vector& instances); - void apply_external_source_to_cell_and_children( - int32_t i_cell, int src_idx, int32_t target_material_id); - virtual void set_flux_to_flux_plus_source(int64_t sr, double volume, int g); - void set_flux_to_source(int64_t sr, int g); - virtual void set_flux_to_old_flux(int64_t sr, int g); - - //---------------------------------------------------------------------------- - // Private data members - int negroups_; // Number of energy groups in simulation - - double - simulation_volume_; // Total physical volume of the simulation domain, as - // defined by the 3D box of the random ray source - - double - fission_rate_; // The system's fission rate (per cm^3), in eigenvalue mode - - // Volumes for each tally and bin/score combination. This intermediate data - // structure is used when tallying quantities that must be normalized by - // volume (i.e., flux). The vector is index by tally index, while the inner 2D - // tensor is indexed by bin index and score index in a similar manner to the - // results tensor in the Tally class, though without the third dimension, as - // SUM and SUM_SQ do not need to be tracked. - vector> tally_volumes_; - -}; // class FlatSourceDomain - -//============================================================================ -//! Non-member functions -//============================================================================ - -// Returns the inputted value in big endian byte ordering. If the system is -// little endian, the byte ordering is flipped. If the system is big endian, -// the inputted value is returned as is. This function is necessary as -// .vtk binary files use big endian byte ordering. -template -T convert_to_big_endian(T in) -{ - // 4 byte integer - uint32_t test = 1; - - // 1 byte pointer to first byte of test integer - uint8_t* ptr = reinterpret_cast(&test); - - // If the first byte of test is 0, then the system is big endian. In this - // case, we don't have to do anything as .vtk files are big endian - if (*ptr == 0) - return in; - - // Otherwise, the system is in little endian, so we need to flip the - // endianness - uint8_t* orig = reinterpret_cast(&in); - uint8_t swapper[sizeof(T)]; - for (int i = 0; i < sizeof(T); i++) { - swapper[i] = orig[sizeof(T) - i - 1]; - } - T out = *reinterpret_cast(&swapper); - return out; -} - -} // namespace openmc - -#endif // OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h deleted file mode 100644 index 0098c7820..000000000 --- a/include/openmc/random_ray/linear_source_domain.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef OPENMC_RANDOM_RAY_LINEAR_SOURCE_DOMAIN_H -#define OPENMC_RANDOM_RAY_LINEAR_SOURCE_DOMAIN_H - -#include "openmc/random_ray/flat_source_domain.h" -#include "openmc/random_ray/moment_matrix.h" - -#include "openmc/openmp_interface.h" -#include "openmc/position.h" -#include "openmc/source.h" - -namespace openmc { - -/* - * The LinearSourceDomain class encompasses data and methods for storing - * scalar flux and source region for all linear source regions in a - * random ray simulation domain. - */ - -class LinearSourceDomain : public FlatSourceDomain { -public: - //---------------------------------------------------------------------------- - // Methods - void update_single_neutron_source(SourceRegionHandle& srh) override; - void normalize_scalar_flux_and_volumes( - double total_active_distance_per_iteration) override; - - void batch_reset() override; - void accumulate_iteration_flux() override; - void output_to_vtk() const; - double evaluate_flux_at_point(Position r, int64_t sr, int g) const override; - -protected: - //---------------------------------------------------------------------------- - // Methods - void set_flux_to_flux_plus_source(int64_t sr, double volume, int g) override; - void set_flux_to_old_flux(int64_t sr, int g) override; - -}; // class LinearSourceDomain - -} // namespace openmc - -#endif // OPENMC_RANDOM_RAY_LINEAR_SOURCE_DOMAIN_H diff --git a/include/openmc/random_ray/moment_matrix.h b/include/openmc/random_ray/moment_matrix.h deleted file mode 100644 index c95bb2c12..000000000 --- a/include/openmc/random_ray/moment_matrix.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef OPENMC_MOMENT_MATRIX_H -#define OPENMC_MOMENT_MATRIX_H - -#include - -#include "openmc/position.h" - -namespace openmc { - -// The MomentArray class is a 3-element array representing the x, y, and z -// moments. It is defined as an alias for the Position class to allow for -// dot products and other operations with Position objects. -// TODO: This class could in theory have 32-bit instead of 64-bit FP values. -using MomentArray = Position; - -// The MomentMatrix class is a sparse representation a 3x3 symmetric -// matrix, with elements labeled as follows: -// -// | a b c | -// | b d e | -// | c e f | -// -// This class uses FP64 values as objects that are accumulated to over many -// iterations. -class MomentMatrix { -public: - //---------------------------------------------------------------------------- - // Public data members - double a; - double b; - double c; - double d; - double e; - double f; - - //---------------------------------------------------------------------------- - // Constructors - MomentMatrix() = default; - MomentMatrix(double a, double b, double c, double d, double e, double f) - : a {a}, b {b}, c {c}, d {d}, e {e}, f {f} - {} - - //---------------------------------------------------------------------------- - // Methods - MomentMatrix inverse() const; - double determinant() const; - void compute_spatial_moments_matrix( - const Position& r, const Direction& u, const double& distance); - - inline void set_to_zero() { a = b = c = d = e = f = 0; } - - inline MomentMatrix& operator*=(double x) - { - a *= x; - b *= x; - c *= x; - d *= x; - e *= x; - f *= x; - return *this; - } - - inline MomentMatrix operator*(double x) const - { - MomentMatrix m_copy = *this; - m_copy *= x; - return m_copy; - } - - inline MomentMatrix& operator+=(const MomentMatrix& rhs) - { - a += rhs.a; - b += rhs.b; - c += rhs.c; - d += rhs.d; - e += rhs.e; - f += rhs.f; - return *this; - } - - MomentArray operator*(const MomentArray& rhs) const - { - return {a * rhs.x + b * rhs.y + c * rhs.z, - b * rhs.x + d * rhs.y + e * rhs.z, c * rhs.x + e * rhs.y + f * rhs.z}; - } -}; - -} // namespace openmc - -#endif // OPENMC_MOMENT_MATRIX_H diff --git a/include/openmc/random_ray/parallel_map.h b/include/openmc/random_ray/parallel_map.h deleted file mode 100644 index 7f4f06d99..000000000 --- a/include/openmc/random_ray/parallel_map.h +++ /dev/null @@ -1,193 +0,0 @@ -#ifndef OPENMC_RANDOM_RAY_PARALLEL_HASH_MAP_H -#define OPENMC_RANDOM_RAY_PARALLEL_HASH_MAP_H - -#include "openmc/openmp_interface.h" - -#include -#include - -namespace openmc { - -/* - * The ParallelMap class allows for threadsafe access to a map-like data - * structure. It is implemented as a hash table with a fixed number of buckets, - * each of which contains a mutex lock and an unordered_map. The class provides - * a subset of the functionality of std::unordered_map. Users must first lock - * the object (using the key) before accessing or modifying the map. The object - * is locked by bucket, allowing for multiple threads to manipulate different - * keys simultaneously, though sometimes threads will need to wait if keys - * happen to be in the same bucket. The ParallelMap will generate pointers to - * hold values, rather than direct storage of values, so as to allow for - * pointers to values to remain valid even after the lock has been released - * (though locking of those values is then left to the user). Iterators to the - * class are provided but are not threadsafe, and are meant to be used only in a - * serial context (e.g., to dump the contents of the map to another data - * structure). - */ - -template -class ParallelMap { - - //---------------------------------------------------------------------------- - // Helper structs and classes - - struct Bucket { - OpenMPMutex lock_; - std::unordered_map, HashFunctor> map_; - }; - - // The iterator yields a pair: (const KeyType&, ValueType&) - class iterator { - public: - using iterator_category = std::forward_iterator_tag; - using value_type = std::pair; - using difference_type = std::ptrdiff_t; - using pointer = void; // Not providing pointer semantics. - using reference = value_type; - - iterator(std::vector* buckets, std::size_t bucket_index, - typename std::unordered_map, - HashFunctor>::iterator inner_it) - : buckets_(buckets), bucket_index_(bucket_index), inner_it_(inner_it) - { - // Advance to the first valid element if necessary. - advance_to_valid(); - } - - // Dereference returns a pair of (key, value). - reference operator*() const - { - return {inner_it_->first, *inner_it_->second}; - } - - iterator& operator++() - { - ++inner_it_; - advance_to_valid(); - return *this; - } - - iterator operator++(int) - { - iterator tmp = *this; - ++(*this); - return tmp; - } - - bool operator==(const iterator& other) const - { - // Two iterators are equal if they refer to the same bucket vector and are - // both at end, or if they have the same bucket index and inner iterator. - return buckets_ == other.buckets_ && - bucket_index_ == other.bucket_index_ && - (bucket_index_ == buckets_->size() || - inner_it_ == other.inner_it_); - } - - bool operator!=(const iterator& other) const { return !(*this == other); } - - private: - // Helper function: if we are at the end of the current bucket, advance to - // the next non-empty bucket. - void advance_to_valid() - { - while (bucket_index_ < buckets_->size() && - inner_it_ == (*buckets_)[bucket_index_].map_.end()) { - ++bucket_index_; - if (bucket_index_ < buckets_->size()) - inner_it_ = (*buckets_)[bucket_index_].map_.begin(); - } - } - - std::vector* buckets_; - std::size_t bucket_index_; - typename std::unordered_map, - HashFunctor>::iterator inner_it_; - }; - -public: - //---------------------------------------------------------------------------- - // Constructor - ParallelMap(int n_buckets = 1000) : buckets_(n_buckets) {} - - //---------------------------------------------------------------------------- - // Public Methods - void lock(const KeyType& key) - { - Bucket& bucket = get_bucket(key); - bucket.lock_.lock(); - } - - void unlock(const KeyType& key) - { - Bucket& bucket = get_bucket(key); - bucket.lock_.unlock(); - } - - void clear() - { - for (auto& bucket : buckets_) { - bucket.map_.clear(); - } - } - - bool contains(const KeyType& key) - { - Bucket& bucket = get_bucket(key); - // C++20 - // return bucket.map_.contains(key); - return bucket.map_.find(key) != bucket.map_.end(); - } - - ValueType& operator[](const KeyType& key) - { - Bucket& bucket = get_bucket(key); - return *bucket.map_[key].get(); - } - - ValueType* emplace(KeyType key, const ValueType& value) - { - Bucket& bucket = get_bucket(key); - // Attempt to emplace the new element into the unordered_map within the - auto result = bucket.map_.emplace(key, std::make_unique(value)); - auto it = result.first; - return it->second.get(); - } - - // Return iterator to first element. - iterator begin() - { - std::size_t bucket_index = 0; - auto inner_it = buckets_.empty() - ? typename std::unordered_map, HashFunctor>::iterator() - : buckets_[0].map_.begin(); - return iterator(&buckets_, bucket_index, inner_it); - } - - // Return iterator to one-past-last element. - iterator end() - { - // End is signaled by bucket_index_ equal to buckets_.size() - return iterator(&buckets_, buckets_.size(), - typename std::unordered_map, - HashFunctor>::iterator()); - } - -private: - //---------------------------------------------------------------------------- - // Private Methods - Bucket& get_bucket(const KeyType& key) - { - return buckets_[hash(key) % buckets_.size()]; - } - - //---------------------------------------------------------------------------- - // Private Data Fields - HashFunctor hash; - vector buckets_; -}; - -} // namespace openmc - -#endif // OPENMC_RANDOM_RAY_PARALLEL_HASH_MAP_H diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h deleted file mode 100644 index b61d2d67a..000000000 --- a/include/openmc/random_ray/random_ray.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef OPENMC_RANDOM_RAY_H -#define OPENMC_RANDOM_RAY_H - -#include "openmc/memory.h" -#include "openmc/particle.h" -#include "openmc/random_ray/flat_source_domain.h" -#include "openmc/random_ray/moment_matrix.h" -#include "openmc/source.h" - -namespace openmc { - -/* - * The RandomRay class encompasses data and methods for transporting random rays - * through the model. It is a small extension of the Particle class. - */ - -// TODO: Inherit from GeometryState instead of Particle -class RandomRay : public Particle { -public: - //---------------------------------------------------------------------------- - // Constructors - RandomRay(); - RandomRay(uint64_t ray_id, FlatSourceDomain* domain); - - //---------------------------------------------------------------------------- - // Methods - void event_advance_ray(); - void attenuate_flux(double distance, bool is_active, double offset = 0.0); - void attenuate_flux_inner( - double distance, bool is_active, int64_t sr, int mesh_bin, Position r); - void attenuate_flux_flat_source( - SourceRegionHandle& srh, double distance, bool is_active, Position r); - void attenuate_flux_flat_source_void( - SourceRegionHandle& srh, double distance, bool is_active, Position r); - void attenuate_flux_linear_source( - SourceRegionHandle& srh, double distance, bool is_active, Position r); - void attenuate_flux_linear_source_void( - SourceRegionHandle& srh, double distance, bool is_active, Position r); - - void initialize_ray(uint64_t ray_id, FlatSourceDomain* domain); - uint64_t transport_history_based_single_ray(); - SourceSite sample_prng(); - SourceSite sample_halton(); - SourceSite sample_s2(); - - //---------------------------------------------------------------------------- - // Static data members - static double distance_inactive_; // Inactive (dead zone) ray length - static double distance_active_; // Active ray length - static unique_ptr ray_source_; // Starting source for ray sampling - static RandomRaySourceShape source_shape_; // Flag for linear source - static RandomRaySampleMethod sample_method_; // Flag for sampling method - - //---------------------------------------------------------------------------- - // Public data members - vector angular_flux_; - - bool ray_trace_only_ {false}; // If true, only perform geometry operations - -private: - //---------------------------------------------------------------------------- - // Private data members - vector delta_psi_; - vector delta_moments_; - vector mesh_bins_; - vector mesh_fractional_lengths_; - - int negroups_; - int ntemperature_; - FlatSourceDomain* domain_ {nullptr}; // pointer to domain that has flat source - // data needed for ray transport - double distance_travelled_ {0}; - bool is_active_ {false}; - bool is_alive_ {true}; -}; // class RandomRay - -} // namespace openmc - -#endif // OPENMC_RANDOM_RAY_H diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h deleted file mode 100644 index e186c549f..000000000 --- a/include/openmc/random_ray/random_ray_simulation.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef OPENMC_RANDOM_RAY_SIMULATION_H -#define OPENMC_RANDOM_RAY_SIMULATION_H - -#include "openmc/random_ray/flat_source_domain.h" -#include "openmc/random_ray/linear_source_domain.h" - -namespace openmc { - -/* - * The RandomRaySimulation class encompasses data and methods for running a - * random ray simulation. - */ - -class RandomRaySimulation { -public: - //---------------------------------------------------------------------------- - // Constructors - RandomRaySimulation(); - - //---------------------------------------------------------------------------- - // Methods - void apply_fixed_sources_and_mesh_domains(); - void prepare_fw_fixed_sources_adjoint(); - void prepare_local_fixed_sources_adjoint(); - void prepare_adjoint_simulation(bool from_forward); - void simulate(); - void output_simulation_results() const; - void instability_check( - int64_t n_hits, double k_eff, double& avg_miss_rate) const; - void print_results_random_ray(uint64_t total_geometric_intersections, - double avg_miss_rate, int negroups, int64_t n_source_regions, - int64_t n_external_source_regions) const; - - //---------------------------------------------------------------------------- - // Accessors - FlatSourceDomain* domain() const { return domain_.get(); } - -private: - //---------------------------------------------------------------------------- - // Data members - - // Contains all flat source region data - unique_ptr domain_; - - // Tracks the average FSR miss rate for analysis and reporting - double avg_miss_rate_ {0.0}; - - // Tracks the total number of geometric intersections by all rays for - // reporting - uint64_t total_geometric_intersections_ {0}; - - // Number of energy groups - int negroups_; - -}; // class RandomRaySimulation - -//============================================================================ -//! Non-member functions -//============================================================================ - -void validate_random_ray_inputs(); -void openmc_finalize_random_ray(); - -} // namespace openmc - -#endif // OPENMC_RANDOM_RAY_SIMULATION_H diff --git a/include/openmc/random_ray/source_region.h b/include/openmc/random_ray/source_region.h deleted file mode 100644 index 1d2bbe1e8..000000000 --- a/include/openmc/random_ray/source_region.h +++ /dev/null @@ -1,698 +0,0 @@ -#ifndef OPENMC_RANDOM_RAY_SOURCE_REGION_H -#define OPENMC_RANDOM_RAY_SOURCE_REGION_H - -#include "openmc/openmp_interface.h" -#include "openmc/position.h" -#include "openmc/random_ray/moment_matrix.h" -#include "openmc/settings.h" - -namespace openmc { - -//---------------------------------------------------------------------------- -// Helper Functions - -// The hash_combine function is the standard hash combine function from boost -// that is typically used for combining multiple hash values into a single hash -// as is needed for larger objects being stored in a hash map. The function is -// taken from: -// https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine -// which carries the following license: -// -// Boost Software License - Version 1.0 - August 17th, 2003 -// Permission is hereby granted, free of charge, to any person or organization -// obtaining a copy of the software and accompanying documentation covered by -// this license (the "Software") to use, reproduce, display, distribute, -// execute, and transmit the Software, and to prepare derivative works of the -// Software, and to permit third-parties to whom the Software is furnished to -// do so, all subject to the following: -// The copyright notices in the Software and this entire statement, including -// the above license grant, this restriction and the following disclaimer, -// must be included in all copies of the Software, in whole or in part, and -// all derivative works of the Software, unless such copies or derivative -// works are solely in the form of machine-executable object code generated by -// a source language processor. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -inline void hash_combine(size_t& seed, const size_t v) -{ - seed ^= (v + 0x9e3779b9 + (seed << 6) + (seed >> 2)); -} - -//---------------------------------------------------------------------------- -// Helper Structs and Classes - -// A mapping object that is used to map between a specific random ray -// source region and an OpenMC native tally bin that it should score to -// every iteration. -struct TallyTask { - int tally_idx; - int64_t filter_idx; - int score_idx; - int score_type; - TallyTask(int tally_idx, int64_t filter_idx, int score_idx, int score_type) - : tally_idx(tally_idx), filter_idx(filter_idx), score_idx(score_idx), - score_type(score_type) - {} - TallyTask() = default; - - // Comparison and Hash operators are defined to allow usage of the - // TallyTask struct as a key in an unordered_set - bool operator==(const TallyTask& other) const - { - return tally_idx == other.tally_idx && filter_idx == other.filter_idx && - score_idx == other.score_idx && score_type == other.score_type; - } - - struct HashFunctor { - size_t operator()(const TallyTask& task) const - { - size_t seed = 0; - hash_combine(seed, task.tally_idx); - hash_combine(seed, task.filter_idx); - hash_combine(seed, task.score_idx); - hash_combine(seed, task.score_type); - return seed; - } - }; -}; - -// The SourceRegionKey combines a base source region (i.e., a material -// filled cell instance) with a mesh bin. This key is used as a handle -// for dynamically discovered source regions when subdividing source -// regions with meshes. -class SourceRegionKey { -public: - int64_t base_source_region_id; - int64_t mesh_bin; - SourceRegionKey() = default; - SourceRegionKey(int64_t source_region, int64_t bin) - : base_source_region_id(source_region), mesh_bin(bin) - {} - - // Equality operator required by the unordered_map - bool operator==(const SourceRegionKey& other) const - { - return base_source_region_id == other.base_source_region_id && - mesh_bin == other.mesh_bin; - } - - // Less than operator required by std::sort - bool operator<(const SourceRegionKey& other) const - { - if (base_source_region_id < other.base_source_region_id) { - return true; - } else if (base_source_region_id > other.base_source_region_id) { - return false; - } else { - return mesh_bin < other.mesh_bin; - } - } - - // Hashing functor required by the unordered_map - struct HashFunctor { - size_t operator()(const SourceRegionKey& key) const - { - size_t seed = 0; - hash_combine(seed, key.base_source_region_id); - hash_combine(seed, key.mesh_bin); - return seed; - } - }; -}; - -// Forward declaration of SourceRegion -class SourceRegion; - -class SourceRegionHandle { -public: - //---------------------------------------------------------------------------- - // Constructors - SourceRegionHandle(SourceRegion& sr); - SourceRegionHandle() = default; - - // All fields are commented/described in the SourceRegion class definition - // below - - //---------------------------------------------------------------------------- - // Public Data members - int negroups_; - bool is_numerical_fp_artifact_ {false}; - bool is_linear_ {false}; - - // Scalar fields - int* material_; - int* temperature_idx_; - double* density_mult_; - int* is_small_; - int* n_hits_; - int* birthday_; - OpenMPMutex* lock_; - double* volume_; - double* volume_t_; - double* volume_sq_; - double* volume_sq_t_; - double* volume_naive_; - int* position_recorded_; - int* external_source_present_; - Position* position_; - Position* centroid_; - Position* centroid_iteration_; - Position* centroid_t_; - MomentMatrix* mom_matrix_; - MomentMatrix* mom_matrix_t_; - // A set of volume tally tasks. This more complicated data structure is - // convenient for ensuring that volumes are only tallied once per source - // region, regardless of how many energy groups are used for tallying. - std::unordered_set* volume_task_; - - // Mesh that subdivides this source region - int* mesh_; - int64_t* parent_sr_; - - // Energy group-wise 1D arrays - double* scalar_flux_old_; - double* scalar_flux_new_; - float* source_; - float* external_source_; - double* scalar_flux_final_; - - MomentArray* source_gradients_; - MomentArray* flux_moments_old_; - MomentArray* flux_moments_new_; - MomentArray* flux_moments_t_; - - // 2D array representing values for all energy groups x tally - // tasks. Each group may have a different number of tally tasks - // associated with it, necessitating the use of a jagged array. - vector* tally_task_; - - //---------------------------------------------------------------------------- - // Public Accessors - - int& material() { return *material_; } - const int material() const { return *material_; } - - double& density_mult() { return *density_mult_; } - const double density_mult() const { return *density_mult_; } - - int& temperature_idx() { return *temperature_idx_; } - const int temperature_idx() const { return *temperature_idx_; } - - int& is_small() { return *is_small_; } - const int is_small() const { return *is_small_; } - - int& n_hits() { return *n_hits_; } - const int n_hits() const { return *n_hits_; } - - void lock() { lock_->lock(); } - void unlock() { lock_->unlock(); } - - double& volume() { return *volume_; } - const double volume() const { return *volume_; } - - double& volume_t() { return *volume_t_; } - const double volume_t() const { return *volume_t_; } - - double& volume_sq() { return *volume_sq_; } - const double volume_sq() const { return *volume_sq_; } - - double& volume_sq_t() { return *volume_sq_t_; } - const double volume_sq_t() const { return *volume_sq_t_; } - - double& volume_naive() { return *volume_naive_; } - const double volume_naive() const { return *volume_naive_; } - - int& position_recorded() { return *position_recorded_; } - const int position_recorded() const { return *position_recorded_; } - - int& external_source_present() { return *external_source_present_; } - const int external_source_present() const - { - return *external_source_present_; - } - - Position& position() { return *position_; } - const Position position() const { return *position_; } - - Position& centroid() { return *centroid_; } - const Position centroid() const { return *centroid_; } - - Position& centroid_iteration() { return *centroid_iteration_; } - const Position centroid_iteration() const { return *centroid_iteration_; } - - Position& centroid_t() { return *centroid_t_; } - const Position centroid_t() const { return *centroid_t_; } - - MomentMatrix& mom_matrix() { return *mom_matrix_; } - const MomentMatrix mom_matrix() const { return *mom_matrix_; } - - MomentMatrix& mom_matrix_t() { return *mom_matrix_t_; } - const MomentMatrix mom_matrix_t() const { return *mom_matrix_t_; } - - std::unordered_set& volume_task() - { - return *volume_task_; - } - const std::unordered_set& volume_task() - const - { - return *volume_task_; - } - - int& mesh() { return *mesh_; } - const int mesh() const { return *mesh_; } - - int64_t& parent_sr() { return *parent_sr_; } - const int64_t parent_sr() const { return *parent_sr_; } - - double& scalar_flux_old(int g) { return scalar_flux_old_[g]; } - const double scalar_flux_old(int g) const { return scalar_flux_old_[g]; } - - double& scalar_flux_new(int g) { return scalar_flux_new_[g]; } - const double scalar_flux_new(int g) const { return scalar_flux_new_[g]; } - - double& scalar_flux_final(int g) { return scalar_flux_final_[g]; } - const double scalar_flux_final(int g) const { return scalar_flux_final_[g]; } - - float& source(int g) { return source_[g]; } - const float source(int g) const { return source_[g]; } - - float& external_source(int g) { return external_source_[g]; } - const float external_source(int g) const { return external_source_[g]; } - - MomentArray& source_gradients(int g) { return source_gradients_[g]; } - const MomentArray source_gradients(int g) const - { - return source_gradients_[g]; - } - - MomentArray& flux_moments_old(int g) { return flux_moments_old_[g]; } - const MomentArray flux_moments_old(int g) const - { - return flux_moments_old_[g]; - } - - MomentArray& flux_moments_new(int g) { return flux_moments_new_[g]; } - const MomentArray flux_moments_new(int g) const - { - return flux_moments_new_[g]; - } - - MomentArray& flux_moments_t(int g) { return flux_moments_t_[g]; } - const MomentArray flux_moments_t(int g) const { return flux_moments_t_[g]; } - - vector& tally_task(int g) { return tally_task_[g]; } - const vector& tally_task(int g) const { return tally_task_[g]; } - -}; // class SourceRegionHandle - -class SourceRegion { -public: - //---------------------------------------------------------------------------- - // Constructors - SourceRegion(int negroups, bool is_linear); - SourceRegion() = default; - - //---------------------------------------------------------------------------- - // Public Data members - - //--------------------------------------- - // Scalar fields - int material_ {0}; //!< Index in openmc::model::materials array - int temperature_idx_ { - 0}; //!< Index into the MGXS array representing temperature - double density_mult_ {1.0}; //!< A density multiplier queried from the cell - //!< corresponding to the source region. - OpenMPMutex lock_; - double volume_ { - 0.0}; //!< Volume (computed from the sum of ray crossing lengths) - double volume_t_ {0.0}; //!< Volume totaled over all iterations - double volume_sq_ {0.0}; //!< Volume squared - double volume_sq_t_ {0.0}; //!< Volume squared totaled over all iterations - double volume_naive_ {0.0}; //!< Volume as integrated from this iteration only - int position_recorded_ {0}; //!< Has the position been recorded yet? - int external_source_present_ { - 0}; //!< Is an external source present in this region? - int is_small_ {0}; //!< Is it "small", receiving < 1.5 hits per iteration? - int n_hits_ {0}; //!< Number of total hits (ray crossings) - // Mesh that subdivides this source region - int mesh_ {C_NONE}; //!< Index in openmc::model::meshes array that subdivides - //!< this source region - int64_t parent_sr_ {C_NONE}; //!< Index of a parent source region - Position position_ { - 0.0, 0.0, 0.0}; //!< A position somewhere inside the region - Position centroid_ {0.0, 0.0, 0.0}; //!< The centroid - Position centroid_iteration_ { - 0.0, 0.0, 0.0}; //!< The centroid integrated from this iteration only - Position centroid_t_ { - 0.0, 0.0, 0.0}; //!< The centroid accumulated over all iterations - MomentMatrix mom_matrix_ { - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< The spatial moment matrix - MomentMatrix mom_matrix_t_ {0.0, 0.0, 0.0, 0.0, 0.0, - 0.0}; //!< The spatial moment matrix accumulated over all iterations - - // A set of volume tally tasks. This more complicated data structure is - // convenient for ensuring that volumes are only tallied once per source - // region, regardless of how many energy groups are used for tallying. - std::unordered_set volume_task_; - - //--------------------------------------- - // Energy group-wise 1D arrays - - vector - scalar_flux_old_; //!< The scalar flux from the previous iteration - vector - scalar_flux_new_; //!< The scalar flux from the current iteration - vector - source_; //!< The total source term (fission + scattering + external) - vector external_source_; //!< The external source term - vector scalar_flux_final_; //!< The scalar flux accumulated over all - //!< active iterations (used for plotting, - //!< or computing adjoint sources) - - vector source_gradients_; //!< The linear source gradients - vector - flux_moments_old_; //!< The linear flux moments from the previous iteration - vector - flux_moments_new_; //!< The linear flux moments from the current iteration - vector - flux_moments_t_; //!< The linear flux moments accumulated over all active - //!< iterations (used for plotting) - - //--------------------------------------- - // 2D array representing values for all energy groups x tally - // tasks. Each group may have a different number of tally tasks - // associated with it, necessitating the use of a jagged array. - vector> tally_task_; -}; // class SourceRegion - -class SourceRegionContainer { -public: - //---------------------------------------------------------------------------- - // Constructors - SourceRegionContainer(int negroups, bool is_linear) - : negroups_(negroups), is_linear_(is_linear) - {} - SourceRegionContainer() = default; - - //---------------------------------------------------------------------------- - // Public Accessors - int& material(int64_t sr) { return material_[sr]; } - const int material(int64_t sr) const { return material_[sr]; } - - int& temperature_idx(int64_t sr) { return temperature_idx_[sr]; } - const int temperature_idx(int64_t sr) const { return temperature_idx_[sr]; } - - double& density_mult(int64_t sr) { return density_mult_[sr]; } - const double density_mult(int64_t sr) const { return density_mult_[sr]; } - - int& is_small(int64_t sr) { return is_small_[sr]; } - const int is_small(int64_t sr) const { return is_small_[sr]; } - - int& n_hits(int64_t sr) { return n_hits_[sr]; } - const int n_hits(int64_t sr) const { return n_hits_[sr]; } - - OpenMPMutex& lock(int64_t sr) { return lock_[sr]; } - const OpenMPMutex& lock(int64_t sr) const { return lock_[sr]; } - - double& volume(int64_t sr) { return volume_[sr]; } - const double volume(int64_t sr) const { return volume_[sr]; } - - double& volume_t(int64_t sr) { return volume_t_[sr]; } - const double volume_t(int64_t sr) const { return volume_t_[sr]; } - - double& volume_sq(int64_t sr) { return volume_sq_[sr]; } - const double volume_sq(int64_t sr) const { return volume_sq_[sr]; } - - double& volume_sq_t(int64_t sr) { return volume_sq_t_[sr]; } - const double volume_sq_t(int64_t sr) const { return volume_sq_t_[sr]; } - - double& volume_naive(int64_t sr) { return volume_naive_[sr]; } - const double volume_naive(int64_t sr) const { return volume_naive_[sr]; } - - int& position_recorded(int64_t sr) { return position_recorded_[sr]; } - const int position_recorded(int64_t sr) const - { - return position_recorded_[sr]; - } - - int& external_source_present(int64_t sr) - { - return external_source_present_[sr]; - } - const int external_source_present(int64_t sr) const - { - return external_source_present_[sr]; - } - - Position& position(int64_t sr) { return position_[sr]; } - const Position position(int64_t sr) const { return position_[sr]; } - - Position& centroid(int64_t sr) { return centroid_[sr]; } - const Position centroid(int64_t sr) const { return centroid_[sr]; } - - Position& centroid_iteration(int64_t sr) { return centroid_iteration_[sr]; } - const Position centroid_iteration(int64_t sr) const - { - return centroid_iteration_[sr]; - } - - Position& centroid_t(int64_t sr) { return centroid_t_[sr]; } - const Position centroid_t(int64_t sr) const { return centroid_t_[sr]; } - - MomentMatrix& mom_matrix(int64_t sr) { return mom_matrix_[sr]; } - const MomentMatrix mom_matrix(int64_t sr) const { return mom_matrix_[sr]; } - - MomentMatrix& mom_matrix_t(int64_t sr) { return mom_matrix_t_[sr]; } - const MomentMatrix mom_matrix_t(int64_t sr) const - { - return mom_matrix_t_[sr]; - } - - MomentArray& source_gradients(int64_t sr, int g) - { - return source_gradients_[index(sr, g)]; - } - const MomentArray source_gradients(int64_t sr, int g) const - { - return source_gradients_[index(sr, g)]; - } - MomentArray& source_gradients(int64_t se) { return source_gradients_[se]; } - const MomentArray source_gradients(int64_t se) const - { - return source_gradients_[se]; - } - - MomentArray& flux_moments_old(int64_t sr, int g) - { - return flux_moments_old_[index(sr, g)]; - } - const MomentArray flux_moments_old(int64_t sr, int g) const - { - return flux_moments_old_[index(sr, g)]; - } - MomentArray& flux_moments_old(int64_t se) { return flux_moments_old_[se]; } - const MomentArray flux_moments_old(int64_t se) const - { - return flux_moments_old_[se]; - } - - MomentArray& flux_moments_new(int64_t sr, int g) - { - return flux_moments_new_[index(sr, g)]; - } - const MomentArray flux_moments_new(int64_t sr, int g) const - { - return flux_moments_new_[index(sr, g)]; - } - MomentArray& flux_moments_new(int64_t se) { return flux_moments_new_[se]; } - const MomentArray flux_moments_new(int64_t se) const - { - return flux_moments_new_[se]; - } - - MomentArray& flux_moments_t(int64_t sr, int g) - { - return flux_moments_t_[index(sr, g)]; - } - const MomentArray flux_moments_t(int64_t sr, int g) const - { - return flux_moments_t_[index(sr, g)]; - } - MomentArray& flux_moments_t(int64_t se) { return flux_moments_t_[se]; } - const MomentArray flux_moments_t(int64_t se) const - { - return flux_moments_t_[se]; - } - - double& scalar_flux_old(int64_t sr, int g) - { - return scalar_flux_old_[index(sr, g)]; - } - const double scalar_flux_old(int64_t sr, int g) const - { - return scalar_flux_old_[index(sr, g)]; - } - double& scalar_flux_old(int64_t se) { return scalar_flux_old_[se]; } - const double scalar_flux_old(int64_t se) const - { - return scalar_flux_old_[se]; - } - - double& scalar_flux_new(int64_t sr, int g) - { - return scalar_flux_new_[index(sr, g)]; - } - const double scalar_flux_new(int64_t sr, int g) const - { - return scalar_flux_new_[index(sr, g)]; - } - double& scalar_flux_new(int64_t se) { return scalar_flux_new_[se]; } - const double scalar_flux_new(int64_t se) const - { - return scalar_flux_new_[se]; - } - - double& scalar_flux_final(int64_t sr, int g) - { - return scalar_flux_final_[index(sr, g)]; - } - const double scalar_flux_final(int64_t sr, int g) const - { - return scalar_flux_final_[index(sr, g)]; - } - double& scalar_flux_final(int64_t se) { return scalar_flux_final_[se]; } - const double scalar_flux_final(int64_t se) const - { - return scalar_flux_final_[se]; - } - - float& source(int64_t sr, int g) { return source_[index(sr, g)]; } - const float source(int64_t sr, int g) const { return source_[index(sr, g)]; } - float& source(int64_t se) { return source_[se]; } - const float source(int64_t se) const { return source_[se]; } - - float& external_source(int64_t sr, int g) - { - return external_source_[index(sr, g)]; - } - const float external_source(int64_t sr, int g) const - { - return external_source_[index(sr, g)]; - } - float& external_source(int64_t se) { return external_source_[se]; } - const float external_source(int64_t se) const { return external_source_[se]; } - - vector& tally_task(int64_t sr, int g) - { - return tally_task_[index(sr, g)]; - } - const vector& tally_task(int64_t sr, int g) const - { - return tally_task_[index(sr, g)]; - } - vector& tally_task(int64_t se) { return tally_task_[se]; } - const vector& tally_task(int64_t se) const - { - return tally_task_[se]; - } - - std::unordered_set& volume_task(int64_t sr) - { - return volume_task_[sr]; - } - const std::unordered_set& volume_task( - int64_t sr) const - { - return volume_task_[sr]; - } - - int& mesh(int64_t sr) { return mesh_[sr]; } - const int mesh(int64_t sr) const { return mesh_[sr]; } - - int64_t& parent_sr(int64_t sr) { return parent_sr_[sr]; } - const int64_t parent_sr(int64_t sr) const { return parent_sr_[sr]; } - - //---------------------------------------------------------------------------- - // Public Methods - - void push_back(const SourceRegion& sr); - void assign(int n_source_regions, const SourceRegion& source_region); - void flux_swap(); - int64_t n_source_regions() const { return n_source_regions_; } - int64_t n_source_elements() const { return n_source_regions_ * negroups_; } - int& negroups() { return negroups_; } - const int negroups() const { return negroups_; } - bool& is_linear() { return is_linear_; } - const bool is_linear() const { return is_linear_; } - SourceRegionHandle get_source_region_handle(int64_t sr); - void adjoint_reset(); - -private: - //---------------------------------------------------------------------------- - // Private Data Members - int64_t n_source_regions_ {0}; - int negroups_ {0}; - bool is_linear_ {false}; - - // SoA storage for scalar fields (one item per source region) - vector material_; - vector temperature_idx_; - vector density_mult_; - vector is_small_; - vector n_hits_; - vector mesh_; - vector parent_sr_; - vector lock_; - vector volume_; - vector volume_t_; - vector volume_sq_; - vector volume_sq_t_; - vector volume_naive_; - vector position_recorded_; - vector external_source_present_; - vector position_; - vector centroid_; - vector centroid_iteration_; - vector centroid_t_; - vector mom_matrix_; - vector mom_matrix_t_; - // A set of volume tally tasks. This more complicated data structure is - // convenient for ensuring that volumes are only tallied once per source - // region, regardless of how many energy groups are used for tallying. - vector> volume_task_; - - // SoA energy group-wise 2D arrays flattened to 1D - vector scalar_flux_old_; - vector scalar_flux_new_; - vector scalar_flux_final_; - vector source_; - vector external_source_; - - vector source_gradients_; - vector flux_moments_old_; - vector flux_moments_new_; - vector flux_moments_t_; - - // SoA 3D array representing values for all source regions x energy groups x - // tally tasks. The outer two dimensions (source regions and energy groups) - // are flattened to 1D. Each group may have a different number of tally tasks - // associated with it, necessitating the use of a jagged array for the inner - // dimension. - vector> tally_task_; - - //---------------------------------------------------------------------------- - // Private Methods - - // Helper function for indexing - inline int64_t index(int64_t sr, int g) const { return sr * negroups_ + g; } -}; - -} // namespace openmc - -#endif // OPENMC_RANDOM_RAY_SOURCE_REGION_H diff --git a/include/openmc/ray.h b/include/openmc/ray.h deleted file mode 100644 index 62e86b0d9..000000000 --- a/include/openmc/ray.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef OPENMC_RAY_H -#define OPENMC_RAY_H - -#include "openmc/particle_data.h" -#include "openmc/position.h" - -namespace openmc { - -// Base class that implements ray tracing logic, not necessarily through -// defined regions of the geometry but also outside of it. -class Ray : public GeometryState { - -public: - // Initialize from location and direction - Ray(Position r, Direction u) { init_from_r_u(r, u); } - - // Initialize from known geometry state - Ray(const GeometryState& p) : GeometryState(p) {} - - // Called at every surface intersection within the model - virtual void on_intersection() = 0; - - /* - * Traces the ray through the geometry, calling on_intersection - * at every surface boundary. - */ - void trace(); - - // Stops the ray and exits tracing when called from on_intersection - void stop() { stop_ = true; } - - // Sets the dist_ variable - void compute_distance(); - -protected: - // Records how far the ray has traveled - double traversal_distance_ {0.0}; - -private: - // Max intersections before we assume ray tracing is caught in an infinite - // loop: - static const int MAX_INTERSECTIONS = 1000000; - - bool stop_ {false}; - - unsigned event_counter_ {0}; -}; - -} // namespace openmc -#endif // OPENMC_RAY_H diff --git a/include/openmc/reaction.h b/include/openmc/reaction.h index e95db1665..93987d9d7 100644 --- a/include/openmc/reaction.h +++ b/include/openmc/reaction.h @@ -7,10 +7,10 @@ #include #include "hdf5.h" +#include #include "openmc/particle_data.h" #include "openmc/reaction_product.h" -#include "openmc/span.h" #include "openmc/vector.h" namespace openmc { @@ -26,16 +26,14 @@ public: //! Construct reaction from HDF5 data //! \param[in] group HDF5 group containing reaction data //! \param[in] temperatures Desired temperatures for cross sections - //! \param[in] name Name of the nuclide - explicit Reaction( - hid_t group, const vector& temperatures, std::string name); + explicit Reaction(hid_t group, const vector& temperatures); //! Calculate cross section given temperautre/grid index, interpolation factor // //! \param[in] i_temp Temperature index //! \param[in] i_grid Energy grid index //! \param[in] interp_factor Interpolation factor between grid points - double xs(int64_t i_temp, int64_t i_grid, double interp_factor) const; + double xs(gsl::index i_temp, gsl::index i_grid, double interp_factor) const; //! Calculate cross section // @@ -49,8 +47,8 @@ public: //! \param[in] flux Flux in each energy group (not normalized per eV) //! \param[in] grid Nuclide energy grid //! \return Reaction rate - double collapse_rate(int64_t i_temp, span energy, - span flux, const vector& grid) const; + double collapse_rate(gsl::index i_temp, gsl::span energy, + gsl::span flux, const vector& grid) const; //! Cross section at a single temperature struct TemperatureXS { @@ -76,21 +74,11 @@ public: //! \return Name of the corresponding reaction std::string reaction_name(int mt); -//! Return MT value for given a reaction name (including special tally MT -//! values) +//! Return reaction type (MT value) given a reaction name // //! \param[in] name Reaction name -//! \return Corresponding MT number or special tally score -int reaction_tally_mt(std::string name); - -//! Return ENDF MT number given a reaction name -// -//! Unlike reaction_tally_mt(), this function always returns a positive ENDF MT -//! number and never a special negative tally score. -//! -//! \param[in] name Reaction name -//! \return Corresponding ENDF MT number -int reaction_mt(const std::string& name); +//! \return Corresponding reaction type (MT value) +int reaction_type(std::string name); } // namespace openmc diff --git a/include/openmc/reaction_product.h b/include/openmc/reaction_product.h index 79a6160e2..ce4fa8fc7 100644 --- a/include/openmc/reaction_product.h +++ b/include/openmc/reaction_product.h @@ -7,10 +7,9 @@ #include "hdf5.h" #include "openmc/angle_energy.h" -#include "openmc/chain.h" #include "openmc/endf.h" #include "openmc/memory.h" // for unique_ptr -#include "openmc/particle_type.h" +#include "openmc/particle.h" #include "openmc/vector.h" // for vector namespace openmc { @@ -38,10 +37,6 @@ public: //! \param[in] group HDF5 group containing data explicit ReactionProduct(hid_t group); - //! Construct reaction product for decay photon from chain nuclide product - //! \param[in] product Chain nuclide product - explicit ReactionProduct(const ChainNuclide::Product& product); - //! Sample an outgoing angle and energy //! \param[in] E_in Incoming energy in [eV] //! \param[out] E_out Outgoing energy in [eV] @@ -49,28 +44,12 @@ public: //! \param[inout] seed Pseudorandom seed pointer void sample(double E_in, double& E_out, double& mu, uint64_t* seed) const; - //! Select which angle-energy distribution to sample - //! \param[in] E_in Incoming energy in [eV] - //! \param[inout] seed Pseudorandom seed pointer - //! \return Reference to the selected angle-energy distribution - AngleEnergy& sample_dist(double E_in, uint64_t* seed) const; - - //! 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; - ParticleType particle_; //!< Particle type EmissionMode emission_mode_; //!< Emission mode double decay_rate_; //!< Decay rate (for delayed neutron precursors) in [1/s] unique_ptr yield_; //!< Yield as a function of energy vector applicability_; //!< Applicability of distribution vector distribution_; //!< Secondary angle-energy distribution - int parent_nuclide_ = -1; //!< Index of chain nuclide that is parent }; } // namespace openmc diff --git a/include/openmc/scattdata.h b/include/openmc/scattdata.h index bea881402..9f911d7db 100644 --- a/include/openmc/scattdata.h +++ b/include/openmc/scattdata.h @@ -4,7 +4,7 @@ #ifndef OPENMC_SCATTDATA_H #define OPENMC_SCATTDATA_H -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/constants.h" #include "openmc/vector.h" @@ -26,23 +26,23 @@ public: protected: //! \brief Initializes the attributes of the base class. - void base_init(int order, const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_energy, + void base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, const double_2dvec& in_mult); //! \brief Combines microscopic ScattDatas into a macroscopic one. void base_combine(size_t max_order, size_t order_dim, const vector& those_scatts, const vector& scalars, - tensor::Tensor& in_gmin, tensor::Tensor& in_gmax, + xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter); public: double_2dvec energy; // Normalized p0 matrix for sampling Eout double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) double_3dvec dist; // Angular distribution - tensor::Tensor gmin; // minimum outgoing group - tensor::Tensor gmax; // maximum outgoing group - tensor::Tensor scattxs; // Isotropic Sigma_{s,g_{in}} + xt::xtensor gmin; // minimum outgoing group + xt::xtensor gmax; // maximum outgoing group + xt::xtensor scattxs; // Isotropic Sigma_{s,g_{in}} //! \brief Calculates the value of normalized f(mu). //! @@ -72,8 +72,8 @@ public: //! @param in_gmax List of maximum outgoing groups for every incoming group //! @param in_mult Input sparse multiplicity matrix //! @param coeffs Input sparse scattering matrix - virtual void init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, + virtual void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) = 0; //! \brief Combines the microscopic data. @@ -96,7 +96,7 @@ public: //! @param max_order If Legendre this is the maximum value of "n" in "Pn" //! requested; ignored otherwise. //! @return The dense scattering matrix. - virtual tensor::Tensor get_matrix(size_t max_order) = 0; + virtual xt::xtensor get_matrix(size_t max_order) = 0; //! \brief Samples the outgoing energy from the ScattData info. //! @@ -135,25 +135,24 @@ protected: ScattDataLegendre& leg, ScattDataTabular& tab); public: - void init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, - const double_3dvec& coeffs) override; + void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs); - void combine(const vector& those_scatts, - const vector& scalars) override; + void combine( + const vector& those_scatts, const vector& scalars); //! \brief Find the maximal value of the angular distribution to use as a // bounding box with rejection sampling. void update_max_val(); - double calc_f(int gin, int gout, double mu) override; + double calc_f(int gin, int gout, double mu); - void sample( - int gin, int& gout, double& mu, double& wgt, uint64_t* seed) override; + void sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); - size_t get_order() override { return dist[0][0].size() - 1; }; + size_t get_order() { return dist[0][0].size() - 1; }; - tensor::Tensor get_matrix(size_t max_order) override; + xt::xtensor get_matrix(size_t max_order); }; //============================================================================== @@ -164,26 +163,25 @@ public: class ScattDataHistogram : public ScattData { protected: - tensor::Tensor mu; // Angle distribution mu bin boundaries + xt::xtensor mu; // Angle distribution mu bin boundaries double dmu; // Quick storage of the mu spacing double_3dvec fmu; // The angular distribution histogram public: - void init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, - const double_3dvec& coeffs) override; + void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs); - void combine(const vector& those_scatts, - const vector& scalars) override; + void combine( + const vector& those_scatts, const vector& scalars); - double calc_f(int gin, int gout, double mu) override; + double calc_f(int gin, int gout, double mu); - void sample( - int gin, int& gout, double& mu, double& wgt, uint64_t* seed) override; + void sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); - size_t get_order() override { return dist[0][0].size(); }; + size_t get_order() { return dist[0][0].size(); }; - tensor::Tensor get_matrix(size_t max_order) override; + xt::xtensor get_matrix(size_t max_order); }; //============================================================================== @@ -194,7 +192,7 @@ public: class ScattDataTabular : public ScattData { protected: - tensor::Tensor mu; // Angle distribution mu grid points + xt::xtensor mu; // Angle distribution mu grid points double dmu; // Quick storage of the mu spacing double_3dvec fmu; // The angular distribution function @@ -204,21 +202,20 @@ protected: ScattDataLegendre& leg, ScattDataTabular& tab); public: - void init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, - const double_3dvec& coeffs) override; + void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs); - void combine(const vector& those_scatts, - const vector& scalars) override; + void combine( + const vector& those_scatts, const vector& scalars); - double calc_f(int gin, int gout, double mu) override; + double calc_f(int gin, int gout, double mu); - void sample( - int gin, int& gout, double& mu, double& wgt, uint64_t* seed) override; + void sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); - size_t get_order() override { return dist[0][0].size(); }; + size_t get_order() { return dist[0][0].size(); }; - tensor::Tensor get_matrix(size_t max_order) override; + xt::xtensor get_matrix(size_t max_order); }; //============================================================================== diff --git a/include/openmc/secondary_correlated.h b/include/openmc/secondary_correlated.h index 69b22981a..6905c38e3 100644 --- a/include/openmc/secondary_correlated.h +++ b/include/openmc/secondary_correlated.h @@ -5,7 +5,7 @@ #define OPENMC_SECONDARY_CORRELATED_H #include "hdf5.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/angle_energy.h" #include "openmc/distribution.h" @@ -25,9 +25,9 @@ public: struct CorrTable { int n_discrete; //!< Number of discrete lines Interpolation interpolation; //!< Interpolation law - tensor::Tensor e_out; //!< Outgoing energies [eV] - tensor::Tensor p; //!< Probability density - tensor::Tensor c; //!< Cumulative distribution + xt::xtensor e_out; //!< Outgoing energies [eV] + xt::xtensor p; //!< Probability density + xt::xtensor c; //!< Cumulative distribution vector> angle; //!< Angle distribution }; @@ -41,22 +41,6 @@ public: void sample( double E_in, double& E_out, double& mu, uint64_t* seed) const override; - //! Sample the outgoing energy and return the angular distribution - //! \param[in] E_in Incoming energy in [eV] - //! \param[out] E_out Outgoing energy in [eV] - //! \param[inout] seed Pseudorandom seed pointer - //! \return Reference to the angular distribution at the sampled energy bin - Distribution& sample_dist(double E_in, double& E_out, uint64_t* seed) const; - - //! 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; - // energy property vector& energy() { return energy_; } const vector& energy() const { return energy_; } diff --git a/include/openmc/secondary_kalbach.h b/include/openmc/secondary_kalbach.h index b25352be9..83806d352 100644 --- a/include/openmc/secondary_kalbach.h +++ b/include/openmc/secondary_kalbach.h @@ -5,7 +5,7 @@ #define OPENMC_SECONDARY_KALBACH_H #include "hdf5.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/angle_energy.h" #include "openmc/constants.h" @@ -32,34 +32,16 @@ public: void sample( double E_in, double& E_out, double& mu, uint64_t* seed) const override; - //! Sample outgoing energy and Kalbach-Mann parameters - //! \param[in] E_in Incoming energy in [eV] - //! \param[out] E_out Outgoing energy in [eV] - //! \param[out] km_a Kalbach-Mann 'a' parameter - //! \param[out] km_r Kalbach-Mann pre-compound fraction 'r' - //! \param[inout] seed Pseudorandom seed pointer - void sample_params(double E_in, double& E_out, double& km_a, double& km_r, - uint64_t* seed) const; - - //! 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: //! Outgoing energy/angle at a single incoming energy struct KMTable { int n_discrete; //!< Number of discrete lines Interpolation interpolation; //!< Interpolation law - tensor::Tensor e_out; //!< Outgoing energies [eV] - tensor::Tensor p; //!< Probability density - tensor::Tensor c; //!< Cumulative distribution - tensor::Tensor r; //!< Pre-compound fraction - tensor::Tensor a; //!< Parameterized function + xt::xtensor e_out; //!< Outgoing energies [eV] + xt::xtensor p; //!< Probability density + xt::xtensor c; //!< Cumulative distribution + xt::xtensor r; //!< Pre-compound fraction + xt::xtensor a; //!< Parameterized function }; int n_region_; //!< Number of interpolation regions diff --git a/include/openmc/secondary_nbody.h b/include/openmc/secondary_nbody.h index 9d033a6b8..efb4fd75b 100644 --- a/include/openmc/secondary_nbody.h +++ b/include/openmc/secondary_nbody.h @@ -28,21 +28,6 @@ public: void sample( double E_in, double& E_out, double& mu, uint64_t* seed) const override; - //! Sample an outgoing energy from the N-body phase space distribution - //! \param[in] E_in Incoming energy in [eV] - //! \param[inout] seed Pseudorandom seed pointer - //! \return Sampled outgoing energy in [eV] - double sample_energy(double E_in, uint64_t* seed) const; - - //! 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: int n_bodies_; //!< Number of particles distributed double mass_ratio_; //!< Total mass of particles [neutron mass] diff --git a/include/openmc/secondary_thermal.h b/include/openmc/secondary_thermal.h index 45d2c5260..5b18902af 100644 --- a/include/openmc/secondary_thermal.h +++ b/include/openmc/secondary_thermal.h @@ -6,11 +6,10 @@ #include "openmc/angle_energy.h" #include "openmc/endf.h" -#include "openmc/search.h" #include "openmc/secondary_correlated.h" #include "openmc/vector.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include namespace openmc { @@ -34,20 +33,8 @@ 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 CoherentElasticXS& xs_; //!< Coherent elastic scattering cross section - tensor::Tensor bragg_edges_; //!< Copy of Bragg edges for slicing - tensor::Tensor - factors_diff_; //!< Differences over elastic scattering factors }; //============================================================================== @@ -69,15 +56,6 @@ 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: double debye_waller_; }; @@ -103,18 +81,9 @@ 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 vector& energy_; //!< Energies at which cosines are tabulated - tensor::Tensor mu_out_; //!< Cosines for each incident energy + xt::xtensor mu_out_; //!< Cosines for each incident energy }; //============================================================================== @@ -137,27 +106,12 @@ public: //! \param[inout] seed Pseudorandom number seed pointer void sample( double E_in, double& E_out, double& mu, uint64_t* seed) const override; - //! Sample outgoing energy bin parameters - //! \param[in] E_in Incoming energy in [eV] - //! \param[out] E_out Outgoing energy in [eV] - //! \param[out] j Sampled outgoing energy bin index - //! \param[inout] seed Pseudorandom seed pointer - void sample_params(double E_in, double& E_out, int& j, uint64_t* seed) const; - - //! 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 vector& energy_; //!< Incident energies - tensor::Tensor + xt::xtensor energy_out_; //!< Outgoing energies for each incident energy - tensor::Tensor + xt::xtensor mu_out_; //!< Outgoing cosines for each incident/outgoing energy bool skewed_; //!< Whether outgoing energy distribution is skewed }; @@ -181,33 +135,14 @@ public: void sample( double E_in, double& E_out, double& mu, uint64_t* seed) const override; - //! Sample outgoing energy bin parameters - //! \param[in] E_in Incoming energy in [eV] - //! \param[out] E_out Outgoing energy in [eV] - //! \param[out] f Interpolation factor within sampled energy bin - //! \param[out] l Index of the closer incident energy - //! \param[out] j Sampled outgoing energy bin index - //! \param[inout] seed Pseudorandom seed pointer - void sample_params(double E_in, double& E_out, double& f, int& l, int& j, - uint64_t* seed) const; - - //! 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: //! Secondary energy/angle distribution struct DistEnergySab { std::size_t n_e_out; //!< Number of outgoing energies - tensor::Tensor e_out; //!< Outgoing energies - tensor::Tensor e_out_pdf; //!< Probability density function - tensor::Tensor e_out_cdf; //!< Cumulative distribution function - tensor::Tensor mu; //!< Equiprobable angles at each outgoing energy + xt::xtensor e_out; //!< Outgoing energies + xt::xtensor e_out_pdf; //!< Probability density function + xt::xtensor e_out_cdf; //!< Cumulative distribution function + xt::xtensor mu; //!< Equiprobable angles at each outgoing energy }; vector energy_; //!< Incident energies @@ -235,21 +170,6 @@ public: void sample( double E_in, double& E_out, double& mu, uint64_t* seed) const override; - //! Select the coherent or incoherent elastic distribution to sample - //! \param[in] E_in Incoming energy in [eV] - //! \param[inout] seed Pseudorandom seed pointer - //! \return Reference to the selected angle-energy distribution - const AngleEnergy& sample_dist(double E_in, uint64_t* seed) const; - - //! 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: CoherentElasticAE coherent_dist_; //!< Coherent distribution unique_ptr incoherent_dist_; //!< Incoherent distribution @@ -258,133 +178,6 @@ private: const Function1D& incoherent_xs_; //!< Polymorphic ref. to incoherent XS }; -//! Internal helper for evaluating a piecewise-constant PDF on discrete points. -//! -//! The underlying discrete points are represented implicitly through a -//! monotonically increasing `center(i)` function and corresponding per-point -//! `weight(i)` values. Each point contributes a rectangular bin whose -//! half-width is half the distance to its nearest neighboring center. -//! -//! \tparam CenterFn Callable returning the location of the i-th discrete value -//! \tparam WeightFn Callable returning the weight of the i-th discrete value -//! \param[in] n Number of discrete values -//! \param[in] mu_0 Point at which to evaluate the PDF -//! \param[in] a Lower bound of the domain (default: -1) -//! \param[in] b Upper bound of the domain (default: 1) -//! \return Probability density at mu_0 -template -double get_pdf_discrete_impl(std::size_t n, double mu_0, double a, double b, - CenterFn center, WeightFn weight) -{ - if (n == 0 || mu_0 < a || mu_0 > b) - return 0.0; - - auto evaluate_bin = [&](std::size_t i) { - double x = center(i); - double left_span = (i == 0) ? 2.0 * (x - a) : x - center(i - 1); - double right_span = (i + 1 == n) ? 2.0 * (b - x) : center(i + 1) - x; - double delta = 0.5 * std::min(left_span, right_span); - if (delta <= 0.0) - return 0.0; - - double left = x - delta; - double right = x + delta; - bool in_bin = - (mu_0 >= left) && ((i + 1 == n) ? (mu_0 <= right) : (mu_0 < right)); - return in_bin ? weight(i) / (2.0 * delta) : 0.0; - }; - - // This is effectively a lower_bound over the sequence center(i), but the - // sequence is implicit rather than stored in a container, so the STL - // algorithms can not be used. - std::size_t low = 0; - std::size_t high = n; - while (low < high) { - std::size_t mid = low + (high - low) / 2; - if (center(mid) < mu_0) { - low = mid + 1; - } else { - high = mid; - } - } - - if (low < n) { - double pdf = evaluate_bin(low); - if (pdf > 0.0) - return pdf; - } - if (low > 0) - return evaluate_bin(low - 1); - return 0.0; -} - -//! Evaluate the PDF of a weighted discrete distribution at a given point. -//! -//! Given a set of discrete values mu[i] with weights w[i], this function -//! computes the probability density at mu_0 by treating each discrete value -//! as a rectangular bin. The bin half-width around each discrete value is -//! half the distance to its nearest neighbor. -//! -//! \tparam T1 Container type for discrete cosine values (must support -//! operator[], size()) -//! \tparam T2 Container type for weights (must support operator[]) -//! \param[in] mu Sorted array of discrete cosine values -//! \param[in] w Weights for each discrete value (need not be normalized) -//! \param[in] mu_0 Point at which to evaluate the PDF -//! \param[in] a Lower bound of the domain (default: -1) -//! \param[in] b Upper bound of the domain (default: 1) -//! \return Probability density at mu_0 -template -double get_pdf_discrete( - const T1 mu, const T2& w, double mu_0, double a = -1.0, double b = 1.0) -{ - // Returns the location of the discrete value for a given index - auto center = [&](std::size_t i) { return mu[i]; }; - auto weight = [&](std::size_t i) { return w[i]; }; - return get_pdf_discrete_impl(mu.size(), mu_0, a, b, center, weight); -} - -//! Evaluate the PDF of a discrete distribution with uniform weights -//! -//! \tparam T1 Container type for discrete cosine values -//! \param[in] mu Sorted array of discrete cosine values -//! \param[in] mu_0 Point at which to evaluate the PDF -//! \param[in] a Lower bound of the domain (default: -1) -//! \param[in] b Upper bound of the domain (default: 1) -//! \return Probability density at mu_0 -template -double get_pdf_discrete( - const T1 mu, double mu_0, double a = -1.0, double b = 1.0) -{ - auto center = [&](std::size_t i) { return mu[i]; }; - auto weight = [&](std::size_t i) { return 1.0 / mu.size(); }; - return get_pdf_discrete_impl(mu.size(), mu_0, a, b, center, weight); -} - -//! Evaluate the PDF of a uniformly weighted distribution on interpolated points -//! -//! \tparam T1 Container type for the lower tabulated cosine values -//! \tparam T2 Container type for the upper tabulated cosine values -//! \param[in] mu0 Sorted array of discrete cosine values at the lower grid -//! \param[in] mu1 Sorted array of discrete cosine values at the upper grid -//! \param[in] f Interpolation factor between mu0 and mu1 -//! \param[in] mu_0 Point at which to evaluate the PDF -//! \param[in] a Lower bound of the domain (default: -1) -//! \param[in] b Upper bound of the domain (default: 1) -//! \return Probability density at mu_0 -template -double get_pdf_discrete_interpolated(const T1 mu0, const T2 mu1, double f, - double mu_0, double a = -1.0, double b = 1.0) -{ - if (mu0.size() != mu1.size()) - return 0.0; - - // Returns interpolated discrete value for a given index - auto center = [&](std::size_t i) { return mu0[i] + f * (mu1[i] - mu0[i]); }; - auto weight = [&](std::size_t i) { return 1.0 / mu0.size(); }; - return get_pdf_discrete_impl(mu0.size(), mu_0, a, b, center, weight); -} - } // namespace openmc #endif // OPENMC_SECONDARY_THERMAL_H diff --git a/include/openmc/secondary_uncorrelated.h b/include/openmc/secondary_uncorrelated.h index f895ae77f..3afa3d9ce 100644 --- a/include/openmc/secondary_uncorrelated.h +++ b/include/openmc/secondary_uncorrelated.h @@ -32,15 +32,6 @@ 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; - // Accessors AngleDistribution& angle() { return angle_; } diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 3bba040f5..1e061b235 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -16,40 +16,6 @@ namespace openmc { -// Type of surface source write -enum class SSWCellType { - None, - Both, - From, - To, -}; - -// Type of IFP parameters -enum class IFPParameter { - None, - Both, - BetaEffective, - GenerationTime, -}; - -struct CollisionTrackConfig { - bool mcpl_write {false}; //!< Write collision tracks using MCPL? - std::unordered_set - cell_ids; //!< Cell ids where collisions will be written - std::unordered_set - mt_numbers; //!< MT Numbers where collisions will be written - std::unordered_set - universe_ids; //!< Universe IDs where collisions will be written - std::unordered_set - material_ids; //!< Material IDs where collisions will be written - std::unordered_set - nuclides; //!< Nuclides where collisions will be written - double deposited_energy_threshold {0.0}; //!< Minimum deposited energy [eV] - int64_t max_collisions { - 1000}; //!< Maximum events recorded per collision track file - int64_t max_files {1}; //!< Maximum number of collision track files -}; - //============================================================================== // Global variable declarations //============================================================================== @@ -59,53 +25,39 @@ namespace settings { // Boolean flags extern bool assume_separate; //!< assume tallies are spatially separate? extern bool check_overlaps; //!< check overlaps in geometry? -extern bool collision_track; //!< flag to use collision track feature? extern bool confidence_intervals; //!< use confidence intervals for results? extern bool create_fission_neutrons; //!< create fission neutrons (fixed source)? -extern bool create_delayed_neutrons; //!< create delayed fission neutrons? -extern "C" bool cmfd_run; //!< is a CMFD run? +extern "C" bool cmfd_run; //!< is a CMFD run? extern bool delayed_photon_scaling; //!< Scale fission photon yield to include delayed extern "C" bool entropy_on; //!< calculate Shannon entropy? extern "C" bool - event_based; //!< use event-based mode (instead of history-based) -extern bool ifp_on; //!< Use IFP for kinetics parameters? + event_based; //!< use event-based mode (instead of history-based) extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular? -extern bool material_cell_offsets; //!< create material cells offsets? -extern "C" bool output_summary; //!< write summary.h5? -extern bool output_tallies; //!< write tallies.out? -extern bool particle_restart_run; //!< particle restart run? -extern "C" bool photon_transport; //!< photon transport turned on? -extern bool atomic_relaxation; //!< atomic relaxation enabled? -extern "C" bool reduce_tallies; //!< reduce tallies at end of batch? -extern bool res_scat_on; //!< use resonance upscattering method? -extern "C" bool restart_run; //!< restart run? -extern "C" bool run_CE; //!< run with continuous-energy data? -extern bool source_latest; //!< write latest source at each batch? -extern bool source_separate; //!< write source to separate file? -extern bool source_write; //!< write source in HDF5 files? -extern bool source_mcpl_write; //!< write source in mcpl files? -extern bool surf_source_write; //!< write surface source file? -extern bool surf_mcpl_write; //!< write surface mcpl file? -extern bool surf_source_read; //!< read surface source file? -extern bool survival_biasing; //!< use survival biasing? -extern bool survival_normalization; //!< use survival normalization? -extern bool temperature_multipole; //!< use multipole data? -extern "C" bool trigger_on; //!< tally triggers enabled? -extern bool trigger_predict; //!< predict batches for triggers? -extern bool uniform_source_sampling; //!< sample sources uniformly? -extern bool ufs_on; //!< uniform fission site method on? -extern bool urr_ptables_on; //!< use unresolved resonance prob. tables? -extern bool use_decay_photons; //!< use decay photons for D1S -extern bool use_shared_secondary_bank; //!< Use shared bank for secondaries -extern "C" bool weight_windows_on; //!< are weight windows are enabled? -extern bool weight_window_checkpoint_surface; //!< enable weight window check - //!< upon surface crossing? -extern bool weight_window_checkpoint_collision; //!< enable weight window check - //!< upon collision? -extern bool write_all_tracks; //!< write track files for every particle? -extern bool write_initial_source; //!< write out initial source file? +extern bool material_cell_offsets; //!< create material cells offsets? +extern "C" bool output_summary; //!< write summary.h5? +extern bool output_tallies; //!< write tallies.out? +extern bool particle_restart_run; //!< particle restart run? +extern "C" bool photon_transport; //!< photon transport turned on? +extern "C" bool reduce_tallies; //!< reduce tallies at end of batch? +extern bool res_scat_on; //!< use resonance upscattering method? +extern "C" bool restart_run; //!< restart run? +extern "C" bool run_CE; //!< run with continuous-energy data? +extern bool source_latest; //!< write latest source at each batch? +extern bool source_separate; //!< write source to separate file? +extern bool source_write; //!< write source in HDF5 files? +extern bool surf_source_write; //!< write surface source file? +extern bool surf_source_read; //!< read surface source file? +extern bool survival_biasing; //!< use survival biasing? +extern bool temperature_multipole; //!< use multipole data? +extern "C" bool trigger_on; //!< tally triggers enabled? +extern bool trigger_predict; //!< predict batches for triggers? +extern bool ufs_on; //!< uniform fission site method on? +extern bool urr_ptables_on; //!< use unresolved resonance prob. tables? +extern bool weight_windows_on; //!< are weight windows are enabled? +extern bool write_all_tracks; //!< write track files for every particle? +extern bool write_initial_source; //!< write out initial source file? // Paths to various files extern std::string path_cross_sections; //!< path to cross_sections.xml @@ -113,41 +65,23 @@ extern std::string path_input; //!< directory where main .xml files resides extern std::string path_output; //!< directory where output files are written extern std::string path_particle_restart; //!< path to a particle restart file extern std::string path_sourcepoint; //!< path to a source file -extern std::string path_statepoint; //!< path to a statepoint file -extern std::string weight_windows_file; //!< Location of weight window file to - //!< load on simulation initialization -extern std::string properties_file; //!< Location of properties file to - //!< load on simulation initialization - -// This is required because the c_str() may not be the first thing in -// std::string. Sometimes it is, but it seems libc++ may not be like that -// on some computers, like the intel Mac. -extern "C" const char* path_statepoint_c; //!< C pointer to statepoint file name +extern "C" std::string path_statepoint; //!< path to a statepoint file extern "C" int32_t n_inactive; //!< number of inactive batches extern "C" int32_t max_lost_particles; //!< maximum number of lost particles extern double rel_max_lost_particles; //!< maximum number of lost particles, relative to the //!< total number of particles -extern "C" int32_t - max_write_lost_particles; //!< maximum number of lost particles - //!< to be written to files extern "C" int32_t gen_per_batch; //!< number of generations per batch extern "C" int64_t n_particles; //!< number of particles per generation extern int64_t - max_particles_in_flight; //!< Max num. event-based particles in flight -extern int max_particle_events; //!< Maximum number of particle events + max_particles_in_flight; //!< Max num. event-based particles in flight + extern ElectronTreatment electron_treatment; //!< how to treat secondary electrons extern array energy_cutoff; //!< Energy cutoff in [eV] for each particle type -extern array - time_cutoff; //!< Time cutoff in [s] for each particle type -extern int - ifp_n_generation; //!< Number of generation for Iterated Fission Probability -extern IFPParameter - ifp_parameter; //!< Parameter to calculate for Iterated Fission Probability extern int legendre_to_tabular_points; //!< number of points to convert Legendres extern int max_order; //!< Maximum Legendre order for multigroup data @@ -159,34 +93,17 @@ extern ResScatMethod res_scat_method; //!< resonance upscattering method extern double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering extern double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering extern vector - res_scat_nuclides; //!< Nuclides using res. upscattering treatment -extern RunMode run_mode; //!< Run mode (eigenvalue, fixed src, etc.) -extern SolverType solver_type; //!< Solver Type (Monte Carlo or Random Ray) + res_scat_nuclides; //!< Nuclides using res. upscattering treatment +extern RunMode run_mode; //!< Run mode (eigenvalue, fixed src, etc.) extern std::unordered_set sourcepoint_batch; //!< Batches when source should be written extern std::unordered_set statepoint_batch; //!< Batches when state should be written extern std::unordered_set source_write_surf_id; //!< Surface ids where sources will be written -extern CollisionTrackConfig collision_track_config; -extern double source_rejection_fraction; //!< Minimum fraction of source sites - //!< that must be accepted -extern double free_gas_threshold; //!< Threshold multiplier for free gas - //!< scattering treatment - -extern int - max_history_splits; //!< maximum number of particle splits for weight windows -extern int max_secondaries; //!< maximum number of secondaries in the bank -extern int64_t ssw_max_particles; //!< maximum number of particles to be - //!< banked on surfaces per process -extern int64_t ssw_max_files; //!< maximum number of surface source files - //!< to be created -extern int64_t ssw_cell_id; //!< Cell id for the surface source - //!< write setting -extern SSWCellType ssw_cell_type; //!< Type of option for the cell - //!< argument of surface source write -extern double surface_grazing_cutoff; //!< surface flux cosine cutoff -extern double surface_grazing_ratio; //!< surface flux substitution ratio +extern int max_splits; //!< maximum number of particle splits for weight windows +extern int64_t max_surface_particles; //!< maximum number of particles to be + //!< banked on surfaces per process extern TemperatureMethod temperature_method; //!< method for choosing temperatures extern double @@ -203,7 +120,6 @@ extern int trigger_batch_interval; //!< Batch interval for triggers extern "C" int verbosity; //!< How verbose to make output extern double weight_cutoff; //!< Weight cutoff for Russian roulette extern double weight_survive; //!< Survival weight after Russian roulette - } // namespace settings //============================================================================== @@ -211,11 +127,8 @@ extern double weight_survive; //!< Survival weight after Russian roulette //============================================================================== //! Read settings from XML file -void read_settings_xml(); - -//! Read settings from XML node //! \param[in] root XML node for -void read_settings_xml(pugi::xml_node root); +void read_settings_xml(); void free_memory_settings(); diff --git a/include/openmc/shared_array.h b/include/openmc/shared_array.h index 2829a2eb9..6fee29b82 100644 --- a/include/openmc/shared_array.h +++ b/include/openmc/shared_array.h @@ -4,8 +4,6 @@ //! \file shared_array.h //! \brief Shared array data structure -#include // for copy_n - #include "openmc/memory.h" namespace openmc { @@ -32,12 +30,14 @@ public: //! Default constructor. SharedArray() = default; - //! Construct a container with `size` elements and capacity equal to `size`. + //! Construct a zero size container with space to hold capacity number of + //! elements. // - //! \param size The number of elements to allocate and initialize - SharedArray(int64_t size) : size_(size), capacity_(size) + //! \param capacity The number of elements for the container to allocate + //! space for + SharedArray(int64_t capacity) : capacity_(capacity) { - data_ = make_unique(size); + data_ = make_unique(capacity); } //========================================================================== @@ -97,52 +97,8 @@ public: capacity_ = 0; } - //! Push back an element to the array, with capacity and reallocation behavior - //! as if this were a vector. This does not perform any thread safety checks. - //! If the size exceeds the capacity, then the capacity will double just as - //! with a vector. Data will be reallocated and moved to a new pointer and - //! copied in before the new item is appended. Old data will be freed. - void thread_unsafe_append(const T& value) - { - if (size_ == capacity_) { - int64_t new_capacity = capacity_ == 0 ? 8 : 2 * capacity_; - unique_ptr new_data = make_unique(new_capacity); - std::copy_n(data_.get(), size_, new_data.get()); - data_ = std::move(new_data); - capacity_ = new_capacity; - } - data_[size_++] = value; - } - - //! Increase the size of the container by count elements without assigning - //! values to the new elements. Existing elements are preserved if the - //! container needs to grow. This does not perform any thread safety checks. - // - //! \param count The number of elements to append - //! \return The starting index of the appended range - int64_t extend_uninitialized(int64_t count) - { - int64_t offset = size_; - int64_t new_size = size_ + count; - if (new_size > capacity_) { - int64_t new_capacity = capacity_ == 0 ? 8 : capacity_; - while (new_capacity < new_size) { - new_capacity *= 2; - } - unique_ptr new_data = make_unique(new_capacity); - if (size_ > 0) { - std::copy_n(data_.get(), size_, new_data.get()); - } - data_ = std::move(new_data); - capacity_ = new_capacity; - } - size_ = new_size; - return offset; - } - //! Return the number of elements in the container int64_t size() { return size_; } - int64_t size() const { return size_; } //! Resize the container to contain a specified number of elements. This is //! useful in cases where the container is written to in a non-thread safe @@ -151,9 +107,6 @@ public: //! \param size The new size of the container void resize(int64_t size) { size_ = size; } - //! Return whether the array is full - bool full() const { return size_ == capacity_; } - //! Return the number of elements that the container has currently allocated //! space for. int64_t capacity() { return capacity_; } @@ -162,12 +115,6 @@ public: T* data() { return data_.get(); } const T* data() const { return data_.get(); } - //! Classic iterators - T* begin() { return data_.get(); } - const T* cbegin() const { return data_.get(); } - T* end() { return data_.get() + size_; } - const T* cend() const { return data_.get() + size_; } - private: //========================================================================== // Data members diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 454752cd2..dd8bb7cdf 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -22,7 +22,6 @@ constexpr int STATUS_EXIT_ON_TRIGGER {2}; namespace simulation { -extern int ct_current_file; //!< current collision track file index extern "C" int current_batch; //!< current batch extern "C" int current_gen; //!< current fission generation extern "C" bool initialized; //!< has simulation been initialized? @@ -38,7 +37,6 @@ extern "C" int n_lost_particles; //!< cumulative number of lost particles extern "C" bool need_depletion_rx; //!< need to calculate depletion rx? extern "C" int restart_batch; //!< batch at which a restart job resumed extern "C" bool satisfy_triggers; //!< have tally triggers been satisfied? -extern int ssw_current_file; //!< current surface source file extern "C" int total_gen; //!< total number of generations simulated extern double total_weight; //!< Total source weight in a batch extern int64_t work_per_rank; //!< number of particles per MPI rank @@ -49,9 +47,6 @@ extern const RegularMesh* ufs_mesh; extern vector k_generation; extern vector work_index; -extern int64_t - simulation_tracks_completed; //!< Number of tracks completed on this rank - } // namespace simulation //============================================================================== @@ -62,7 +57,7 @@ extern int64_t void allocate_banks(); //! Determine number of particles to transport per process -void calculate_work(int64_t n_particles); +void calculate_work(); //! Initialize nuclear data before a simulation void initialize_data(); @@ -73,9 +68,8 @@ void initialize_batch(); //! Initialize a fission generation void initialize_generation(); -//! Full initialization of a particle track -void initialize_particle_track( - Particle& p, int64_t index_source, bool is_secondary); +//! Full initialization of a particle history +void initialize_history(Particle& p, int64_t index_source); //! Finalize a batch //! @@ -96,35 +90,16 @@ void broadcast_results(); void free_memory_simulation(); -//! Compute unique particle ID from a 1-based source index -//! \param index_source 1-based source index within this rank's work -//! \return globally unique particle ID -int64_t compute_particle_id(int64_t index_source); - -//! Compute the transport RNG seed from a particle ID -//! \param particle_id the particle's globally unique ID -//! \return seed value passed to init_particle_seeds() -int64_t compute_transport_seed(int64_t particle_id); - -//! Simulate a single particle history from birth to death, inclusive of any -//! secondary particles. In shared secondary mode, only a single track is -//! transported and secondaries are deposited into a shared bank instead. +//! Simulate a single particle history (and all generated secondary particles, +//! if enabled), from birth to death void transport_history_based_single_particle(Particle& p); //! Simulate all particle histories using history-based parallelism void transport_history_based(); -//! Simulate all particles using history-based parallelism, with a shared -//! secondary bank -void transport_history_based_shared_secondary(); - //! Simulate all particle histories using event-based parallelism void transport_event_based(); -//! Simulate all particles using event-based parallelism, with a shared -//! secondary bank -void transport_event_based_shared_secondary(); - } // namespace openmc #endif // OPENMC_SIMULATION_H diff --git a/include/openmc/source.h b/include/openmc/source.h index 51b54a1d1..18fddc689 100644 --- a/include/openmc/source.h +++ b/include/openmc/source.h @@ -4,19 +4,12 @@ #ifndef OPENMC_SOURCE_H #define OPENMC_SOURCE_H -#include -#include -#include -#include // for pair - #include "pugixml.hpp" -#include "openmc/array.h" -#include "openmc/distribution.h" #include "openmc/distribution_multi.h" #include "openmc/distribution_spatial.h" #include "openmc/memory.h" -#include "openmc/particle_type.h" +#include "openmc/particle.h" #include "openmc/vector.h" namespace openmc { @@ -25,113 +18,46 @@ namespace openmc { // Constants //============================================================================== -// Minimum number of external source sites rejected before checking againts the -// source_rejection_fraction +// Maximum number of external source spatial resamples to encounter before an +// error is thrown. constexpr int EXTSRC_REJECT_THRESHOLD {10000}; - -// Maximum number of source rejections allowed while sampling a single site -constexpr int64_t MAX_SOURCE_REJECTIONS_PER_SAMPLE {1'000'000}; +constexpr double EXTSRC_REJECT_FRACTION {0.05}; //============================================================================== // Global variables //============================================================================== -// Cumulative counters for source rejection diagnostics. These are atomic to -// allow thread-safe concurrent sampling of external sources. -extern std::atomic source_n_accept; -extern std::atomic source_n_reject; - class Source; namespace model { extern vector> external_sources; -extern vector> adjoint_sources; - -// Probability distribution for selecting external sources -extern DiscreteIndex external_sources_probability; } // namespace model //============================================================================== //! Abstract source interface -// -//! The Source class provides the interface that must be implemented by derived -//! classes, namely the sample() method that returns a sampled source site. From -//! this base class, source rejection is handled within the -//! sample_with_constraints() method. However, note that some classes directly -//! check for constraints for efficiency reasons (like IndependentSource), in -//! which case the constraints_applied() method indicates that constraints -//! should not be checked a second time from the base class. //============================================================================== class Source { public: - // Domain types - enum class DomainType { UNIVERSE, MATERIAL, CELL }; - // Constructors, destructors - Source() = default; - explicit Source(pugi::xml_node node); virtual ~Source() = default; - // Methods that can be overridden - virtual double strength() const { return strength_; } - - //! Sample a source site and apply constraints - // - //! \param[inout] seed Pseudorandom seed pointer - //! \return Sampled site - SourceSite sample_with_constraints(uint64_t* seed) const; - - //! Sample a source site (without applying constraints) - // - //! Sample from the external source distribution - //! \param[inout] seed Pseudorandom seed pointer - //! \return Sampled site + // Methods that must be implemented virtual SourceSite sample(uint64_t* seed) const = 0; - static unique_ptr create(pugi::xml_node node); - -protected: - // Strategy used for rejecting sites when constraints are applied. KILL means - // that sites are always accepted but if they don't satisfy constraints, they - // are given weight 0. RESAMPLE means that a new source site will be sampled - // until constraints are met. - enum class RejectionStrategy { KILL, RESAMPLE }; - - // Indicates whether derived class already handles constraints - virtual bool constraints_applied() const { return false; } - - // Methods for constraints - void read_constraints(pugi::xml_node node); - bool satisfies_spatial_constraints(Position r) const; - bool satisfies_energy_constraints(double E) const; - bool satisfies_time_constraints(double time) const; - - // Data members - double strength_ {1.0}; //!< Source strength - std::unordered_set domain_ids_; //!< Domains to reject from - DomainType domain_type_; //!< Domain type for rejection - std::pair time_bounds_ {-std::numeric_limits::max(), - std::numeric_limits::max()}; //!< time limits - std::pair energy_bounds_ { - 0, std::numeric_limits::max()}; //!< energy limits - bool only_fissionable_ { - false}; //!< Whether site must be in fissionable material - RejectionStrategy rejection_strategy_ { - RejectionStrategy::RESAMPLE}; //!< Procedure for rejecting + // Methods that can be overridden + virtual double strength() const { return 1.0; } }; //============================================================================== -//! Source composed of independent spatial, angle, energy, and time -//! distributions +//! Source composed of independent spatial, angle, energy, and time distributions //============================================================================== class IndependentSource : public Source { public: // Constructors - IndependentSource( - UPtrSpace space, UPtrAngle angle, UPtrDist energy, UPtrDist time); + IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy, UPtrDist time); explicit IndependentSource(pugi::xml_node node); //! Sample from the external source distribution @@ -141,6 +67,7 @@ public: // Properties ParticleType particle_type() const { return particle_; } + double strength() const override { return strength_; } // Make observing pointers available SpatialDistribution* space() const { return space_.get(); } @@ -148,24 +75,13 @@ public: Distribution* energy() const { return energy_.get(); } Distribution* time() const { return time_.get(); } - // Make domain type and ids available - DomainType domain_type() const { return domain_type_; } - const std::unordered_set& domain_ids() const { return domain_ids_; } - - // Setter for spatial distribution - void set_space(UPtrSpace space) { space_ = std::move(space); } - -protected: - // Indicates whether derived class already handles constraints - bool constraints_applied() const override { return true; } - private: - // Data members - ParticleType particle_; //!< Type of particle emitted - UPtrSpace space_; //!< Spatial distribution - UPtrAngle angle_; //!< Angular distribution - UPtrDist energy_; //!< Energy distribution - UPtrDist time_; //!< Time distribution + ParticleType particle_ {ParticleType::neutron}; //!< Type of particle emitted + double strength_ {1.0}; //!< Source strength + UPtrSpace space_; //!< Spatial distribution + UPtrAngle angle_; //!< Angular distribution + UPtrDist energy_; //!< Energy distribution + UPtrDist time_; //!< Time distribution }; //============================================================================== @@ -175,226 +91,39 @@ private: class FileSource : public Source { public: // Constructors - explicit FileSource(pugi::xml_node node); - explicit FileSource(const std::string& path); + explicit FileSource(std::string path); // Methods - void load_sites_from_file( - const std::string& path); //!< Load source sites from file - -protected: SourceSite sample(uint64_t* seed) const override; private: - vector sites_; //!< Source sites + vector sites_; //!< Source sites from a file }; //============================================================================== //! Wrapper for custom sources that manages opening/closing shared library //============================================================================== -class CompiledSourceWrapper : public Source { +class CustomSourceWrapper : public Source { public: // Constructors, destructors - CompiledSourceWrapper(pugi::xml_node node); - ~CompiledSourceWrapper(); + CustomSourceWrapper(std::string path, std::string parameters); + ~CustomSourceWrapper(); - double strength() const override { return compiled_source_->strength(); } - - void setup(const std::string& path, const std::string& parameters); - -protected: // Defer implementation to custom source library SourceSite sample(uint64_t* seed) const override { - return compiled_source_->sample(seed); + return custom_source_->sample(seed); } + double strength() const override { return custom_source_->strength(); } + private: void* shared_library_; //!< library from dlopen - unique_ptr compiled_source_; + unique_ptr custom_source_; }; -typedef unique_ptr create_compiled_source_t(std::string parameters); - -//============================================================================== -//! Mesh-based source with different distributions for each element -//============================================================================== - -// Helper class to sample spatial position on a single mesh element -class MeshElementSpatial : public SpatialDistribution { -public: - MeshElementSpatial(int32_t mesh_index, int elem_index) - : mesh_index_(mesh_index), elem_index_(elem_index) - {} - - //! Sample a position from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return (sampled position, importance weight) - std::pair sample(uint64_t* seed) const override; - -private: - int32_t mesh_index_ {C_NONE}; //!< Index in global meshes array - int elem_index_; //! Index of mesh element -}; - -class MeshSource : public Source { -public: - // Constructors - explicit MeshSource(pugi::xml_node node); - - //! Sample from the external source distribution - //! \param[inout] seed Pseudorandom seed pointer - //! \return Sampled site - SourceSite sample(uint64_t* seed) const override; - - // Properties - double strength() const override { return space_->total_strength(); } - - // Accessors - const unique_ptr& source(int32_t i) const - { - return sources_.size() == 1 ? sources_[0] : sources_[i]; - } - -private: - // Data members - unique_ptr space_; //!< Mesh spatial - vector> sources_; //!< Source distributions -}; - -//============================================================================== -//! Parametric tokamak plasma neutron source -//! -//! This source samples neutron positions from a tokamak plasma geometry using -//! Miller-style flux surface parameterization with user-specified emission -//! profiles and energy distributions. -//! -//! Flux surface parameterization: -//! R = R0 + r*cos(alpha + delta*sin(alpha)) + Delta*(1 - (r/a)^2) -//! Z = kappa * r * sin(alpha) -//! -//! The sampling algorithm: -//! 1. Sample minor radius r from precomputed CDF of S(r) * Jacobian -//! 2. Sample poloidal angle alpha from conditional P(alpha|r) using mixture -//! of precomputed CDFs weighted by functions of r -//! 3. Sample energy and time from user-provided distribution(s) -//! 4. Sample isotropic direction -//! 5. Sample toroidal angle phi uniformly in [phi_start, phi_start + -//! phi_extent] -//! 6. Transform (r, alpha, phi) to Cartesian (x, y, z), applying the optional -//! vertical shift of the plasma center -//! -//! The user provides the emission density S(r) directly (e.g., from transport -//! codes like TRANSP, ASTRA, etc.), allowing full flexibility in reaction -//! physics calculations. S(r) is a profile in arbitrary units sampled on the -//! r_over_a grid; only its shape matters, since it is normalized internally. -//! Energy distributions can be specified as either a single distribution for -//! all r, or one distribution per radial point. -//============================================================================== - -class TokamakSource : public Source { -public: - // Constructors - explicit TokamakSource(pugi::xml_node node); - - //! Sample from the tokamak source distribution - //! \param[inout] seed Pseudorandom seed pointer - //! \return Sampled site - SourceSite sample(uint64_t* seed) const override; - -private: - //========================================================================== - // Private methods - - //! Precompute data structures for efficient sampling - void precompute_sampling_distributions(); - - //! Sample minor radius from marginal CDF - //! \param seed Pseudorandom seed pointer - //! \return Sampled r/a value - double sample_r_over_a(uint64_t* seed) const; - - //! Sample poloidal angle given r using mixture of precomputed CDFs - //! \param r_norm Normalized minor radius r/a - //! \param seed Pseudorandom seed pointer - //! \return Sampled poloidal angle alpha [rad] - double sample_poloidal_angle(double r_norm, uint64_t* seed) const; - - //! Compute the k-th mixture weight w_k(r) * I_hat_k for poloidal sampling - //! \param k Basis function index (0-5) - //! \param r Normalized minor radius r/a - //! \return Mixture weight for component k - double mixture_weight(int k, double r) const; - - //! Sample energy from the distribution(s) - //! \param r_norm Normalized minor radius r/a (for distribution selection) - //! \param seed Pseudorandom seed pointer - //! \return (Sampled energy [eV], importance weight) - std::pair sample_energy(double r_norm, uint64_t* seed) const; - - //! Transform from flux coordinates (r, alpha, phi) to Cartesian (x, y, z) - //! \param r Minor radius [cm] - //! \param alpha Poloidal angle [rad] - //! \param phi Toroidal angle [rad] - //! \return Position in Cartesian coordinates [cm] - Position flux_to_cartesian(double r, double alpha, double phi) const; - - //========================================================================== - // Data members - - // Emission profile (input) - vector r_over_a_; //!< Normalized minor radius grid points - vector emission_density_; //!< Emission density S(r) at grid points - - // Energy distribution(s): either 1 for all r, or one per r point - vector> energy_dists_; - - // Time distribution (defaults to a delta distribution at t=0) - UPtrDist time_; - - // Angular distribution (isotropic) - UPtrAngle angle_; - - // Tokamak geometry parameters - double major_radius_; //!< Major radius R0 [cm] - double minor_radius_; //!< Minor radius a [cm] - double elongation_; //!< Elongation kappa - double triangularity_; //!< Triangularity delta - double shafranov_shift_; //!< Shafranov shift Delta [cm] - double vertical_shift_; //!< Vertical shift of plasma center [cm] - - // Normalized geometry parameters (precomputed for efficiency) - double epsilon_; //!< Inverse aspect ratio a/R0 - double delta_tilde_; //!< Normalized Shafranov shift Delta/a - - // Toroidal angle bounds - double phi_start_; //!< Starting toroidal angle [rad] - double phi_extent_; //!< Toroidal angle extent [rad] - - // Precomputed distribution for radial sampling - unique_ptr radial_dist_; - - // Coefficients of the radial geometric polynomial: A*r - B*r^2 - C*r^3 - // Also used as the analytical normalization for poloidal mixture weights - double radial_poly_a_; //!< 1 + ε·Δ̃ - double radial_poly_b_; //!< (3/8)·c₁·ε - double radial_poly_c_; //!< 2·ε·Δ̃ - - // Precomputed Bernstein basis functions for poloidal angle sampling. - // Using the factorization f(r_tilde, alpha) = R_tilde x J_tilde where: - // R_tilde = b0*(1-r)^2 + 2*b1*r*(1-r) + b2*r^2 (Bernstein quadratic) - // J_tilde = b3*(1-r) + b4*r (Bernstein linear) - // The product gives 6 non-negative basis functions g_k(alpha) with - // weights w_k(r_tilde) that are products of Bernstein polynomials. - // Distributions are tabulated on [0, pi] exploiting up-down symmetry. - static constexpr int N_POLOIDAL_BASIS = 6; //!< Number of basis functions - int n_alpha_; //!< Number of poloidal angle grid points - array, N_POLOIDAL_BASIS> - poloidal_dists_; //!< Distributions for each basis function g_k(alpha) - array - poloidal_integrals_; //!< Integrals of g_k(alpha) over [0, pi] -}; +typedef unique_ptr create_custom_source_t(std::string parameters); //============================================================================== // Functions @@ -411,9 +140,6 @@ SourceSite sample_external_source(uint64_t* seed); void free_memory_source(); -//! Reset cumulative source rejection counters -void reset_source_rejection_counters(); - } // namespace openmc #endif // OPENMC_SOURCE_H diff --git a/include/openmc/span.h b/include/openmc/span.h deleted file mode 100644 index 723bccd76..000000000 --- a/include/openmc/span.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef OPENMC_SPAN_H -#define OPENMC_SPAN_H -#include // for std::size_t, std::ptrdiff_t -#include // for std::begin, std::end -#include // for std::out_of_range -#include - -#include "openmc/vector.h" - -namespace openmc { - -template -class span { -public: - using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - using iterator = T*; - using const_iterator = const T*; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - /** - * @brief Default constructor for an empty span. - */ - span() noexcept : data_(nullptr), size_(0) {} - - /** - * @brief Constructs a span from a pointer and size. - * @param ptr Pointer to the first element. - * @param count Number of elements in the span. - */ - span(pointer ptr, size_type count) : data_(ptr), size_(count) {} - - /** - * @brief Constructs a span from two pointers marking the span range. - * @param first Pointer to the first element. - * @param last Pointer past the last element. - * @throws std::out_of_range if last < first. - */ - span(pointer first, pointer last) : data_(first), size_(last - first) - { - if (last < first) { - throw std::out_of_range("span: last pointer is before first pointer"); - } - } - - /** - * @brief Constructs a span from a non-const std::vector. - * @param vec Reference to the vector to create a span from. - */ - span(std::vector& vec) : data_(vec.data()), size_(vec.size()) {} - - /** - * @brief Constructs a span from a const std::vector. - * - * This is handling the semantics that a span is used - * for read-only access into a vector. - * @param vec Reference to the const vector to create a span from. - */ - template::value>> - span(const std::vector>& vec) - : data_(vec.data()), size_(vec.size()) - {} - - /** - * @brief Constructs a read-only span from a non-const span. - */ - template::value>> - span(const span>& other) noexcept - : data_(other.data()), size_(other.size()) - {} - - /** - * @brief Access an element without bounds checking. - * @param index Index of the element to access. - * @return Reference to the accessed element. - */ - reference operator[](size_type index) { return data_[index]; } - - /** - * @brief Access an element without bounds checking (const version). - * @param index Index of the element to access. - * @return Const reference to the accessed element. - */ - const_reference operator[](size_type index) const { return data_[index]; } - - /** - * @brief Access an element with bounds checking. - * @param index Index of the element to access. - * @return Reference to the accessed element. - * @throws std::out_of_range if index is out of range. - */ - reference at(size_type index) - { - if (index >= size_) { - throw std::out_of_range("span: index out of range"); - } - return data_[index]; - } - - /** - * @brief Access an element with bounds checking (const version). - * @param index Index of the element to access. - * @return Const reference to the accessed element. - * @throws std::out_of_range if index is out of range. - */ - const_reference at(size_type index) const - { - if (index >= size_) { - throw std::out_of_range("span: index out of range"); - } - return data_[index]; - } - - /** - * @brief Get a pointer to the underlying data. - * @return Pointer to the data, or nullptr if the span is empty. - */ - pointer data() noexcept { return data_; } - - /** - * @brief Get a const pointer to the underlying data. - * @return Const pointer to the data, or nullptr if the span is empty. - */ - const_pointer data() const noexcept { return data_; } - - /** - * @brief Get the number of elements in the span. - * @return The size of the span. - */ - size_type size() const noexcept { return size_; } - - /** - * @brief Check if the span is empty. - * @return True if the span is empty, false otherwise. - */ - bool empty() const noexcept { return size_ == 0; } - - /** - * @brief Get an iterator to the beginning of the span. - * @return Iterator pointing to the first element. - */ - iterator begin() noexcept { return data_; } - - /** - * @brief Get a const iterator to the beginning of the span. - * @return Const iterator pointing to the first element. - */ - const_iterator begin() const noexcept { return data_; } - - /** - * @brief Get a const iterator to the beginning of the span. - * @return Const iterator pointing to the first element. - */ - const_iterator cbegin() const noexcept { return data_; } - - /** - * @brief Get an iterator to the end of the span. - * @return Iterator pointing past the last element. - */ - iterator end() noexcept { return data_ + size_; } - - /** - * @brief Get a const iterator to the end of the span. - * @return Const iterator pointing past the last element. - */ - const_iterator end() const noexcept { return data_ + size_; } - - /** - * @brief Get a const iterator to the end of the span. - * @return Const iterator pointing past the last element. - */ - const_iterator cend() const noexcept { return data_ + size_; } - - /** - * @brief Access the first element. - * @return Reference to the first element. - * @throws std::out_of_range if the span is empty. - */ - reference front() - { - if (empty()) { - throw std::out_of_range("span::front(): span is empty"); - } - return data_[0]; - } - - /** - * @brief Access the first element (const version). - * @return Const reference to the first element. - * @throws std::out_of_range if the span is empty. - */ - const_reference front() const - { - if (empty()) { - throw std::out_of_range("span::front(): span is empty"); - } - return data_[0]; - } - - /** - * @brief Access the last element. - * @return Reference to the last element. - * @throws std::out_of_range if the span is empty. - */ - reference back() - { - if (empty()) { - throw std::out_of_range("span::back(): span is empty"); - } - return data_[size_ - 1]; - } - - /** - * @brief Access the last element (const version). - * @return Const reference to the last element. - * @throws std::out_of_range if the span is empty. - */ - const_reference back() const - { - if (empty()) { - throw std::out_of_range("span::back(): span is empty"); - } - return data_[size_ - 1]; - } - -private: - pointer data_; - size_type size_; -}; - -} // namespace openmc -#endif // OPENMC_SPAN_H diff --git a/include/openmc/state_point.h b/include/openmc/state_point.h index fb1aaf7b9..5ada2bf88 100644 --- a/include/openmc/state_point.h +++ b/include/openmc/state_point.h @@ -2,51 +2,19 @@ #define OPENMC_STATE_POINT_H #include -#include #include "hdf5.h" #include "openmc/capi.h" #include "openmc/particle.h" -#include "openmc/shared_array.h" -#include "openmc/span.h" #include "openmc/vector.h" namespace openmc { void load_state_point(); - -// By passing in a filename, source bank, and list of source indices -// on each MPI rank, this writes an HDF5 file which contains that -// information which can later be read in by read_source_bank -// (defined below). If you're writing code to write out a new kind -// of particle bank, this function is the one you want to use! -// -// For example, this is used to write both the surface source sites -// or fission source sites for eigenvalue continuation runs. -// -// This function ends up calling write_source_bank, and is responsible -// for opening the file to be written to and controlling whether the -// write is done in parallel (if compiled with parallel HDF5). -// -// bank_index is an exclusive parallel scan of the source_bank.size() -// values on each rank, used to create global indexing. This vector -// can be created by calling calculate_parallel_index_vector on -// source_bank.size() if such a vector is not already available. -// -// The source_bank variable is used as work space if MPI is used, -// so it cannot be given as a const span. -void write_h5_source_point(const char* filename, span source_bank, - const vector& bank_index); - -void write_source_point(std::string, span source_bank, - const vector& bank_index, bool use_mcpl); - -// This appends a source bank specification to an HDF5 file -// that's already open. It is used internally by write_source_point. -void write_source_bank(hid_t group_id, span source_bank, - const vector& bank_index); - +vector calculate_surf_source_size(); +void write_source_point(const char* filename, bool surf_source_bank = false); +void write_source_bank(hid_t group_id, bool surf_source_bank); void read_source_bank( hid_t group_id, vector& sites, bool distribute); void write_tally_results_nr(hid_t file_id); diff --git a/include/openmc/string_utils.h b/include/openmc/string_utils.h index 2e8b0d14f..6b4c69d48 100644 --- a/include/openmc/string_utils.h +++ b/include/openmc/string_utils.h @@ -1,7 +1,6 @@ #ifndef OPENMC_STRING_UTILS_H #define OPENMC_STRING_UTILS_H -#include #include #include "openmc/vector.h" @@ -16,7 +15,7 @@ std::string to_element(const std::string& name); void to_lower(std::string& str); -int word_count(const std::string& str); +int word_count(std::string const& str); vector split(const std::string& in); @@ -24,20 +23,5 @@ bool ends_with(const std::string& value, const std::string& ending); bool starts_with(const std::string& value, const std::string& beginning); -template -inline std::string concatenate(const T& values, const std::string& del = ", ") -{ - if (values.size() == 0) - return ""; - - std::stringstream oss; - auto it = values.begin(); - oss << *it++; - while (it != values.end()) { - oss << del << *it++; - } - return oss.str(); -} - } // namespace openmc #endif // OPENMC_STRING_UTILS_H diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 2d8580345..84a2ed113 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -2,7 +2,6 @@ #define OPENMC_SURFACE_H #include // For numeric_limits -#include #include #include @@ -10,7 +9,6 @@ #include "pugixml.hpp" #include "openmc/boundary_condition.h" -#include "openmc/bounding_box.h" #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr #include "openmc/particle.h" @@ -30,15 +28,65 @@ extern std::unordered_map surface_map; extern vector> surfaces; } // namespace model +//============================================================================== +//! Coordinates for an axis-aligned cuboid that bounds a geometric object. +//============================================================================== + +struct BoundingBox { + double xmin = -INFTY; + double xmax = INFTY; + double ymin = -INFTY; + double ymax = INFTY; + double zmin = -INFTY; + double zmax = INFTY; + + inline BoundingBox operator&(const BoundingBox& other) + { + BoundingBox result = *this; + return result &= other; + } + + inline BoundingBox operator|(const BoundingBox& other) + { + BoundingBox result = *this; + return result |= other; + } + + // intersect operator + inline BoundingBox& operator&=(const BoundingBox& other) + { + xmin = std::max(xmin, other.xmin); + xmax = std::min(xmax, other.xmax); + ymin = std::max(ymin, other.ymin); + ymax = std::min(ymax, other.ymax); + zmin = std::max(zmin, other.zmin); + zmax = std::min(zmax, other.zmax); + return *this; + } + + // union operator + inline BoundingBox& operator|=(const BoundingBox& other) + { + xmin = std::min(xmin, other.xmin); + xmax = std::max(xmax, other.xmax); + ymin = std::min(ymin, other.ymin); + ymax = std::max(ymax, other.ymax); + zmin = std::min(zmin, other.zmin); + zmax = std::max(zmax, other.zmax); + return *this; + } +}; + //============================================================================== //! A geometry primitive used to define regions of 3D space. //============================================================================== class Surface { public: - int id_; //!< Unique ID - std::string name_; //!< User-defined name - unique_ptr bc_; //!< Boundary condition + int id_; //!< Unique ID + std::string name_; //!< User-defined name + std::shared_ptr bc_ {nullptr}; //!< Boundary condition + GeometryType geom_type_; //!< Geometry type indicator (CSG or DAGMC) bool surf_source_ {false}; //!< Activate source banking for the surface? explicit Surface(pugi::xml_node surf_node); @@ -57,10 +105,9 @@ public: //! Determine the direction of a ray reflected from the surface. //! \param[in] r The point at which the ray is incident. //! \param[in] u Incident direction of the ray - //! \param[inout] p Pointer to the particle. Only DAGMC uses this. + //! \param[inout] p Pointer to the particle //! \return Outgoing direction of the ray - virtual Direction reflect( - Position r, Direction u, GeometryState* p = nullptr) const; + virtual Direction reflect(Position r, Direction u, Particle* p) const; virtual Direction diffuse_reflect( Position r, Direction u, uint64_t* seed) const; @@ -91,14 +138,14 @@ public: //! Get the BoundingBox for this surface. virtual BoundingBox bounding_box(bool /*pos_side*/) const { return {}; } - /* Must specify if this is a CSG or DAGMC-type surface. Only - * the DAGMC surface should return the DAG type geometry, so - * by default, this returns the CSG. The main difference is that - * if the geom_type is found to be DAG in the geometry handling code, - * some DAGMC-specific operations get carried out like resetting - * the particle's intersection history when necessary. - */ - virtual GeometryType geom_type() const { return GeometryType::CSG; } +protected: + virtual void to_hdf5_inner(hid_t group_id) const = 0; +}; + +class CSGSurface : public Surface { +public: + explicit CSGSurface(pugi::xml_node surf_node); + CSGSurface(); protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; @@ -110,14 +157,14 @@ protected: //! The plane is described by the equation \f$x - x_0 = 0\f$ //============================================================================== -class SurfaceXPlane : public Surface { +class SurfaceXPlane : public CSGSurface { public: explicit SurfaceXPlane(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double x0_; }; @@ -128,14 +175,14 @@ public: //! The plane is described by the equation \f$y - y_0 = 0\f$ //============================================================================== -class SurfaceYPlane : public Surface { +class SurfaceYPlane : public CSGSurface { public: explicit SurfaceYPlane(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double y0_; }; @@ -146,14 +193,14 @@ public: //! The plane is described by the equation \f$z - z_0 = 0\f$ //============================================================================== -class SurfaceZPlane : public Surface { +class SurfaceZPlane : public CSGSurface { public: explicit SurfaceZPlane(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double z0_; }; @@ -164,13 +211,13 @@ public: //! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ //============================================================================== -class SurfacePlane : public Surface { +class SurfacePlane : public CSGSurface { public: explicit SurfacePlane(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double A_, B_, C_, D_; }; @@ -182,14 +229,14 @@ public: //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceXCylinder : public Surface { +class SurfaceXCylinder : public CSGSurface { public: explicit SurfaceXCylinder(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double y0_, z0_, radius_; }; @@ -201,14 +248,14 @@ public: //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceYCylinder : public Surface { +class SurfaceYCylinder : public CSGSurface { public: explicit SurfaceYCylinder(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double x0_, z0_, radius_; }; @@ -220,14 +267,14 @@ public: //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceZCylinder : public Surface { +class SurfaceZCylinder : public CSGSurface { public: explicit SurfaceZCylinder(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double x0_, y0_, radius_; }; @@ -239,14 +286,14 @@ public: //! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceSphere : public Surface { +class SurfaceSphere : public CSGSurface { public: explicit SurfaceSphere(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; - BoundingBox bounding_box(bool pos_side) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; + BoundingBox bounding_box(bool pos_side) const; double x0_, y0_, z0_, radius_; }; @@ -258,13 +305,13 @@ public: //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ //============================================================================== -class SurfaceXCone : public Surface { +class SurfaceXCone : public CSGSurface { public: explicit SurfaceXCone(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double x0_, y0_, z0_, radius_sq_; }; @@ -276,13 +323,13 @@ public: //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ //============================================================================== -class SurfaceYCone : public Surface { +class SurfaceYCone : public CSGSurface { public: explicit SurfaceYCone(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double x0_, y0_, z0_, radius_sq_; }; @@ -294,13 +341,13 @@ public: //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ //============================================================================== -class SurfaceZCone : public Surface { +class SurfaceZCone : public CSGSurface { public: explicit SurfaceZCone(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double x0_, y0_, z0_, radius_sq_; }; @@ -312,13 +359,13 @@ public: //! 0\f$ //============================================================================== -class SurfaceQuadric : public Surface { +class SurfaceQuadric : public CSGSurface { public: explicit SurfaceQuadric(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_; @@ -330,13 +377,13 @@ public: //! \f$(x-x_0)^2/B^2 + (\sqrt{(y-y_0)^2 + (z-z_0)^2} - A)^2/C^2 -1 \f$ //============================================================================== -class SurfaceXTorus : public Surface { +class SurfaceXTorus : public CSGSurface { public: explicit SurfaceXTorus(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double x0_, y0_, z0_, A_, B_, C_; }; @@ -347,13 +394,13 @@ public: //! \f$(y-y_0)^2/B^2 + (\sqrt{(x-x_0)^2 + (z-z_0)^2} - A)^2/C^2 -1 \f$ //============================================================================== -class SurfaceYTorus : public Surface { +class SurfaceYTorus : public CSGSurface { public: explicit SurfaceYTorus(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double x0_, y0_, z0_, A_, B_, C_; }; @@ -364,13 +411,13 @@ public: //! \f$(z-z_0)^2/B^2 + (\sqrt{(x-x_0)^2 + (y-y_0)^2} - A)^2/C^2 -1 \f$ //============================================================================== -class SurfaceZTorus : public Surface { +class SurfaceZTorus : public CSGSurface { public: explicit SurfaceZTorus(pugi::xml_node surf_node); - double evaluate(Position r) const override; - double distance(Position r, Direction u, bool coincident) const override; - Direction normal(Position r) const override; - void to_hdf5_inner(hid_t group_id) const override; + double evaluate(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; + void to_hdf5_inner(hid_t group_id) const; double x0_, y0_, z0_, A_, B_, C_; }; @@ -379,39 +426,7 @@ public: // Non-member functions //============================================================================== -//! Read surface definitions from XML and populate the global surfaces vector. -//! -//! This function parses surface elements from the XML input, creates the -//! appropriate surface objects, and identifies periodic surfaces along with -//! their albedo values and sense information. -//! -//! \param node XML node containing surface definitions -//! \param[out] periodic_pairs Set of surface ID pairs representing periodic -//! boundary conditions -//! \param[out] albedo_map Map of surface IDs to albedo values for periodic -//! surfaces -//! \param[out] periodic_sense_map Map of surface IDs to their sense values -//! (used to determine orientation for periodic BCs) -void read_surfaces(pugi::xml_node node, - std::set>& periodic_pairs, - std::unordered_map& albedo_map, - std::unordered_map& periodic_sense_map); - -//! Resolve periodic surface pairs and assign boundary conditions. -//! -//! This function completes the setup of periodic boundary conditions by -//! resolving unpaired periodic surfaces, determining whether each pair -//! represents translational or rotational periodicity based on surface -//! normals, and assigning the appropriate boundary condition objects. -//! -//! \param[inout] periodic_pairs Set of surface ID pairs representing periodic -//! boundary conditions; unpaired entries are resolved -//! \param albedo_map Map of surface IDs to albedo values for periodic surfaces -//! \param periodic_sense_map Map of surface IDs to their sense values (used to -//! determine orientation for periodic BCs) -void prepare_boundary_conditions(std::set>& periodic_pairs, - std::unordered_map& albedo_map, - std::unordered_map& periodic_sense_map); +void read_surfaces(pugi::xml_node node); void free_memory_surfaces(); diff --git a/include/openmc/tallies/filter.h b/include/openmc/tallies/filter.h index 77b0d9f42..2eecfe0e4 100644 --- a/include/openmc/tallies/filter.h +++ b/include/openmc/tallies/filter.h @@ -6,6 +6,7 @@ #include #include "pugixml.hpp" +#include #include "openmc/constants.h" #include "openmc/hdf5_interface.h" @@ -16,42 +17,6 @@ namespace openmc { -enum class FilterType { - AZIMUTHAL, - CELLBORN, - CELLFROM, - CELL, - CELL_INSTANCE, - COLLISION, - DELAYED_GROUP, - DISTRIBCELL, - ENERGY_FUNCTION, - ENERGY, - ENERGY_OUT, - LEGENDRE, - MATERIAL, - MATERIALFROM, - MESH, - MESHBORN, - MESH_MATERIAL, - MESH_SURFACE, - MU, - MUSURFACE, - PARENT_NUCLIDE, - PARTICLE, - PARTICLE_PRODUCTION, - POLAR, - REACTION, - SPHERICAL_HARMONICS, - SPATIAL_LEGENDRE, - SURFACE, - TIME, - UNIVERSE, - WEIGHT, - ZERNIKE, - ZERNIKE_RADIAL -}; - //============================================================================== //! Modifies tally score events. //============================================================================== @@ -93,8 +58,7 @@ public: //---------------------------------------------------------------------------- // Methods - virtual std::string type_str() const = 0; - virtual FilterType type() const = 0; + virtual std::string type() const = 0; //! Matches a tally event to a set of filter bins and weights. //! @@ -108,7 +72,7 @@ public: //! Writes data describing this filter to an HDF5 statepoint group. virtual void to_statepoint(hid_t filter_group) const { - write_dataset(filter_group, "type", type_str()); + write_dataset(filter_group, "type", type()); write_dataset(filter_group, "n_bins", n_bins_); } @@ -134,7 +98,7 @@ public: //! \return Number of bins int n_bins() const { return n_bins_; } - int64_t index() const { return index_; } + gsl::index index() const { return index_; } //---------------------------------------------------------------------------- // Data members @@ -144,7 +108,7 @@ protected: private: int32_t id_ {C_NONE}; - int64_t index_; + gsl::index index_; }; //============================================================================== @@ -164,24 +128,5 @@ extern vector> tally_filters; //! Make sure index corresponds to a valid filter int verify_filter(int32_t index); -//============================================================================== -// Filter implementation -//============================================================================== - -template -T* Filter::create(int32_t id) -{ - static_assert(std::is_base_of::value, - "Type specified is not derived from openmc::Filter"); - // Create filter and add to filters vector - auto filter = make_unique(); - auto ptr_out = filter.get(); - model::tally_filters.emplace_back(std::move(filter)); - // Assign ID - model::tally_filters.back()->set_id(id); - - return ptr_out; -} - } // namespace openmc #endif // OPENMC_TALLIES_FILTER_H diff --git a/include/openmc/tallies/filter_azimuthal.h b/include/openmc/tallies/filter_azimuthal.h index 4853c5545..2272b500a 100644 --- a/include/openmc/tallies/filter_azimuthal.h +++ b/include/openmc/tallies/filter_azimuthal.h @@ -4,7 +4,8 @@ #include "openmc/vector.h" #include -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" namespace openmc { @@ -23,8 +24,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "azimuthal"; } - FilterType type() const override { return FilterType::AZIMUTHAL; } + std::string type() const override { return "azimuthal"; } void from_xml(pugi::xml_node node) override; @@ -38,7 +38,7 @@ public: //---------------------------------------------------------------------------- // Accessors - void set_bins(span bins); + void set_bins(gsl::span bins); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_cell.h b/include/openmc/tallies/filter_cell.h index ac6539466..46d89811d 100644 --- a/include/openmc/tallies/filter_cell.h +++ b/include/openmc/tallies/filter_cell.h @@ -4,7 +4,8 @@ #include #include -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -24,8 +25,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "cell"; } - FilterType type() const override { return FilterType::CELL; } + std::string type() const override { return "cell"; } void from_xml(pugi::xml_node node) override; @@ -41,7 +41,7 @@ public: const vector& cells() const { return cells_; } - void set_cells(span cells); + void set_cells(gsl::span cells); protected: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_cell_instance.h b/include/openmc/tallies/filter_cell_instance.h index 69499765b..4de3fcd29 100644 --- a/include/openmc/tallies/filter_cell_instance.h +++ b/include/openmc/tallies/filter_cell_instance.h @@ -4,8 +4,9 @@ #include #include +#include + #include "openmc/cell.h" -#include "openmc/span.h" #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -21,14 +22,13 @@ public: // Constructors, destructors CellInstanceFilter() = default; - CellInstanceFilter(span instances); + CellInstanceFilter(gsl::span instances); ~CellInstanceFilter() = default; //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "cellinstance"; } - FilterType type() const override { return FilterType::CELL_INSTANCE; } + std::string type() const override { return "cellinstance"; } void from_xml(pugi::xml_node node) override; @@ -46,7 +46,7 @@ public: const std::unordered_set& cells() const { return cells_; } - void set_cell_instances(span instances); + void set_cell_instances(gsl::span instances); private: //---------------------------------------------------------------------------- @@ -59,7 +59,7 @@ private: std::unordered_set cells_; //! A map from cell/instance indices to filter bin indices. - std::unordered_map map_; + std::unordered_map map_; //! Indicates if filter uses only material-filled cells bool material_cells_only_; diff --git a/include/openmc/tallies/filter_cellborn.h b/include/openmc/tallies/filter_cellborn.h index 417aedece..282854020 100644 --- a/include/openmc/tallies/filter_cellborn.h +++ b/include/openmc/tallies/filter_cellborn.h @@ -11,13 +11,12 @@ namespace openmc { //! Specifies which cell the particle was born in. //============================================================================== -class CellBornFilter : public CellFilter { +class CellbornFilter : public CellFilter { public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "cellborn"; } - FilterType type() const override { return FilterType::CELLBORN; } + std::string type() const override { return "cellborn"; } void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const override; diff --git a/include/openmc/tallies/filter_cellfrom.h b/include/openmc/tallies/filter_cellfrom.h index 61ff50b05..47abd0353 100644 --- a/include/openmc/tallies/filter_cellfrom.h +++ b/include/openmc/tallies/filter_cellfrom.h @@ -16,8 +16,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "cellfrom"; } - FilterType type() const override { return FilterType::CELLFROM; } + std::string type() const override { return "cellfrom"; } void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const override; diff --git a/include/openmc/tallies/filter_collision.h b/include/openmc/tallies/filter_collision.h index 7d42a5ddd..3724b06cf 100644 --- a/include/openmc/tallies/filter_collision.h +++ b/include/openmc/tallies/filter_collision.h @@ -1,9 +1,9 @@ #ifndef OPENMC_TALLIES_FILTER_COLLISIONS_H #define OPENMC_TALLIES_FILTER_COLLISIONS_H +#include #include -#include "openmc/span.h" #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -23,8 +23,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "collision"; } - FilterType type() const override { return FilterType::COLLISION; } + std::string type() const override { return "collision"; } void from_xml(pugi::xml_node node) override; @@ -39,7 +38,7 @@ public: // Accessors const vector& bins() const { return bins_; } - void set_bins(span bins); + void set_bins(gsl::span bins); protected: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_delayedgroup.h b/include/openmc/tallies/filter_delayedgroup.h index 7d11447ab..72ffa1db5 100644 --- a/include/openmc/tallies/filter_delayedgroup.h +++ b/include/openmc/tallies/filter_delayedgroup.h @@ -1,7 +1,8 @@ #ifndef OPENMC_TALLIES_FILTER_DELAYEDGROUP_H #define OPENMC_TALLIES_FILTER_DELAYEDGROUP_H -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -24,8 +25,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "delayedgroup"; } - FilterType type() const override { return FilterType::DELAYED_GROUP; } + std::string type() const override { return "delayedgroup"; } void from_xml(pugi::xml_node node) override; @@ -41,7 +41,7 @@ public: const vector& groups() const { return groups_; } - void set_groups(span groups); + void set_groups(gsl::span groups); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_distribcell.h b/include/openmc/tallies/filter_distribcell.h index b5cdcce84..d72ae022f 100644 --- a/include/openmc/tallies/filter_distribcell.h +++ b/include/openmc/tallies/filter_distribcell.h @@ -21,8 +21,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "distribcell"; } - FilterType type() const override { return FilterType::DISTRIBCELL; } + std::string type() const override { return "distribcell"; } void from_xml(pugi::xml_node node) override; diff --git a/include/openmc/tallies/filter_energy.h b/include/openmc/tallies/filter_energy.h index 3e410d9fd..000aaa28b 100644 --- a/include/openmc/tallies/filter_energy.h +++ b/include/openmc/tallies/filter_energy.h @@ -1,8 +1,8 @@ #ifndef OPENMC_TALLIES_FILTER_ENERGY_H #define OPENMC_TALLIES_FILTER_ENERGY_H -#include "openmc/particle.h" -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -22,8 +22,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "energy"; } - FilterType type() const override { return FilterType::ENERGY; } + std::string type() const override { return "energy"; } void from_xml(pugi::xml_node node) override; @@ -38,7 +37,7 @@ public: // Accessors const vector& bins() const { return bins_; } - void set_bins(span bins); + void set_bins(gsl::span bins); bool matches_transport_groups() const { return matches_transport_groups_; } @@ -64,8 +63,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "energyout"; } - FilterType type() const override { return FilterType::ENERGY_OUT; } + std::string type() const override { return "energyout"; } void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const override; diff --git a/include/openmc/tallies/filter_energyfunc.h b/include/openmc/tallies/filter_energyfunc.h index e03c23dda..c066dfa17 100644 --- a/include/openmc/tallies/filter_energyfunc.h +++ b/include/openmc/tallies/filter_energyfunc.h @@ -1,8 +1,6 @@ #ifndef OPENMC_TALLIES_FILTER_ENERGYFUNC_H #define OPENMC_TALLIES_FILTER_ENERGYFUNC_H -#include "openmc/constants.h" -#include "openmc/span.h" #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -25,8 +23,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "energyfunction"; } - FilterType type() const override { return FilterType::ENERGY_FUNCTION; } + std::string type() const override { return "energyfunction"; } void from_xml(pugi::xml_node node) override; @@ -42,9 +39,7 @@ public: const vector& energy() const { return energy_; } const vector& y() const { return y_; } - Interpolation interpolation() const { return interpolation_; } - void set_data(span energy, span y); - void set_interpolation(const std::string& interpolation); + void set_data(gsl::span energy, gsl::span y); private: //---------------------------------------------------------------------------- @@ -55,9 +50,6 @@ private: //! Interpolant values. vector y_; - - //! Interpolation scheme - Interpolation interpolation_ {Interpolation::lin_lin}; }; } // namespace openmc diff --git a/include/openmc/tallies/filter_legendre.h b/include/openmc/tallies/filter_legendre.h index 839fd77bf..b1fac37c8 100644 --- a/include/openmc/tallies/filter_legendre.h +++ b/include/openmc/tallies/filter_legendre.h @@ -21,8 +21,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "legendre"; } - FilterType type() const override { return FilterType::LEGENDRE; } + std::string type() const override { return "legendre"; } void from_xml(pugi::xml_node node) override; diff --git a/include/openmc/tallies/filter_material.h b/include/openmc/tallies/filter_material.h index ccfe5403d..f58fc9938 100644 --- a/include/openmc/tallies/filter_material.h +++ b/include/openmc/tallies/filter_material.h @@ -4,7 +4,8 @@ #include #include -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -24,8 +25,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "material"; } - FilterType type() const override { return FilterType::MATERIAL; } + std::string type() const override { return "material"; } void from_xml(pugi::xml_node node) override; @@ -43,9 +43,9 @@ public: const vector& materials() const { return materials_; } - void set_materials(span materials); + void set_materials(gsl::span materials); -protected: +private: //---------------------------------------------------------------------------- // Data members diff --git a/include/openmc/tallies/filter_materialfrom.h b/include/openmc/tallies/filter_materialfrom.h deleted file mode 100644 index 52039852a..000000000 --- a/include/openmc/tallies/filter_materialfrom.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_MATERIALFROM_H -#define OPENMC_TALLIES_FILTER_MATERIALFROM_H - -#include - -#include "openmc/tallies/filter_material.h" - -namespace openmc { - -//============================================================================== -//! Specifies which material particles exit when crossing a surface. -//============================================================================== - -class MaterialFromFilter : public MaterialFilter { -public: - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "materialfrom"; } - FilterType type() const override { return FilterType::MATERIALFROM; } - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - std::string text_label(int bin) const override; -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_MATERIALFROM_H diff --git a/include/openmc/tallies/filter_mesh.h b/include/openmc/tallies/filter_mesh.h index c35a477fe..ef055b1a2 100644 --- a/include/openmc/tallies/filter_mesh.h +++ b/include/openmc/tallies/filter_mesh.h @@ -9,9 +9,9 @@ namespace openmc { //============================================================================== -//! Indexes the location of particle events to a mesh. For tracklength tallies, -//! it will produce multiple valid bins and the bin weight will correspond to -//! the fraction of the track length that lies in that bin. +//! Indexes the location of particle events to a regular mesh. For tracklength +//! tallies, it will produce multiple valid bins and the bin weight will +//! correspond to the fraction of the track length that lies in that bin. //============================================================================== class MeshFilter : public Filter { @@ -24,8 +24,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "mesh"; } - FilterType type() const override { return FilterType::MESH; } + std::string type() const override { return "mesh"; } void from_xml(pugi::xml_node node) override; @@ -51,21 +50,13 @@ public: virtual bool translated() const { return translated_; } - virtual void set_rotation(const vector& rotation); - - virtual const vector& rotation() const { return rotation_; } - - virtual bool rotated() const { return rotated_; } - protected: //---------------------------------------------------------------------------- // Data members - int32_t mesh_; //!< Index of the mesh - bool translated_ {false}; //!< Whether or not the filter is translated - Position translation_ {0.0, 0.0, 0.0}; //!< Filter translation - bool rotated_ {false}; //!< Whether or not the filter is rotated - vector rotation_; //!< Filter rotation + int32_t mesh_; + bool translated_ {false}; + Position translation_ {0.0, 0.0, 0.0}; }; } // namespace openmc diff --git a/include/openmc/tallies/filter_meshborn.h b/include/openmc/tallies/filter_meshborn.h deleted file mode 100644 index 8ab7a8c76..000000000 --- a/include/openmc/tallies/filter_meshborn.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_MESHBORN_H -#define OPENMC_TALLIES_FILTER_MESHBORN_H - -#include - -#include "openmc/position.h" -#include "openmc/tallies/filter_mesh.h" - -namespace openmc { - -class MeshBornFilter : public MeshFilter { -public: - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "meshborn"; } - FilterType type() const override { return FilterType::MESHBORN; } - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - std::string text_label(int bin) const override; -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_MESHBORN_H diff --git a/include/openmc/tallies/filter_meshmaterial.h b/include/openmc/tallies/filter_meshmaterial.h deleted file mode 100644 index 42a4edcf0..000000000 --- a/include/openmc/tallies/filter_meshmaterial.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_MESHMATERIAL_H -#define OPENMC_TALLIES_FILTER_MESHMATERIAL_H - -#include -#include -#include -#include - -#include "openmc/position.h" -#include "openmc/random_ray/source_region.h" -#include "openmc/span.h" -#include "openmc/tallies/filter.h" -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -//! Helper structs that define a combination of a mesh element index and a -//! material index and a functor for hashing to place in an unordered_map -//============================================================================== - -struct ElementMat { - //! Check for equality - bool operator==(const ElementMat& other) const - { - return index_element == other.index_element && index_mat == other.index_mat; - } - - int32_t index_element; - int32_t index_mat; -}; - -struct ElementMatHash { - std::size_t operator()(const ElementMat& k) const - { - size_t seed = 0; - hash_combine(seed, k.index_element); - hash_combine(seed, k.index_mat); - return seed; - } -}; - -//============================================================================== -//! Indexes the location of particle events to combinations of mesh element -//! index and material. For tracklength tallies, it will produce multiple valid -//! bins and the bin weight will correspond to the fraction of the track length -//! that lies in that bin. -//============================================================================== - -class MeshMaterialFilter : public Filter { -public: - //---------------------------------------------------------------------------- - // Constructors, destructors - - ~MeshMaterialFilter() = default; - - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "meshmaterial"; } - FilterType type() const override { return FilterType::MESH_MATERIAL; } - - void from_xml(pugi::xml_node node) override; - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - void to_statepoint(hid_t filter_group) const override; - - std::string text_label(int bin) const override; - - //---------------------------------------------------------------------------- - // Accessors - - int32_t mesh() const { return mesh_; } - - void set_mesh(int32_t mesh); - - //! Set the bins based on a flat vector of alternating element index and - //! material IDs - void set_bins(span bins); - - //! Set the bins based on a vector of (element, material index) pairs - void set_bins(vector&& bins); - - virtual void set_translation(const Position& translation); - - virtual void set_translation(const double translation[3]); - - virtual const Position& translation() const { return translation_; } - - virtual bool translated() const { return translated_; } - -private: - //---------------------------------------------------------------------------- - // Data members - - int32_t mesh_; //!< Index of the mesh - bool translated_ {false}; //!< Whether or not the filter is translated - Position translation_ {0.0, 0.0, 0.0}; //!< Filter translation - - //! The indices of the mesh element-material combinations binned by this - //! filter. - vector bins_; - - //! The set of materials used in this filter - std::unordered_set materials_; - - //! A map from mesh element-material indices to filter bin indices. - std::unordered_map map_; -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_MESHMATERIAL_H diff --git a/include/openmc/tallies/filter_meshsurface.h b/include/openmc/tallies/filter_meshsurface.h index 195995c69..28f4e265f 100644 --- a/include/openmc/tallies/filter_meshsurface.h +++ b/include/openmc/tallies/filter_meshsurface.h @@ -10,8 +10,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "meshsurface"; } - FilterType type() const override { return FilterType::MESH_SURFACE; } + std::string type() const override { return "meshsurface"; } void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const override; diff --git a/include/openmc/tallies/filter_mu.h b/include/openmc/tallies/filter_mu.h index d6e7f1798..5299f6dd4 100644 --- a/include/openmc/tallies/filter_mu.h +++ b/include/openmc/tallies/filter_mu.h @@ -1,7 +1,8 @@ #ifndef OPENMC_TALLIES_FILTER_MU_H #define OPENMC_TALLIES_FILTER_MU_H -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -22,8 +23,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "mu"; } - FilterType type() const override { return FilterType::MU; } + std::string type() const override { return "mu"; } void from_xml(pugi::xml_node node) override; @@ -37,9 +37,9 @@ public: //---------------------------------------------------------------------------- // Accessors - void set_bins(span bins); + void set_bins(gsl::span bins); -protected: +private: //---------------------------------------------------------------------------- // Data members diff --git a/include/openmc/tallies/filter_musurface.h b/include/openmc/tallies/filter_musurface.h deleted file mode 100644 index fa6816836..000000000 --- a/include/openmc/tallies/filter_musurface.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_MU_SURFACE_H -#define OPENMC_TALLIES_FILTER_MU_SURFACE_H - -#include "openmc/tallies/filter_mu.h" -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -//! Bins the incoming-outgoing direction cosine. This is only used for surface -//! crossings. -//============================================================================== - -class MuSurfaceFilter : public MuFilter { -public: - //---------------------------------------------------------------------------- - // Constructors, destructors - - ~MuSurfaceFilter() = default; - - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "musurface"; } - FilterType type() const override { return FilterType::MUSURFACE; } - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_MU_SURFACE_H diff --git a/include/openmc/tallies/filter_parent_nuclide.h b/include/openmc/tallies/filter_parent_nuclide.h deleted file mode 100644 index 53f8a5fa4..000000000 --- a/include/openmc/tallies/filter_parent_nuclide.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_PARENT_NUCLIDE_H -#define OPENMC_TALLIES_FILTER_PARENT_NUCLIDE_H - -#include -#include - -#include "openmc/span.h" -#include "openmc/tallies/filter.h" -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -//! Bins events by parent nuclide (for decay photons) -//============================================================================== - -class ParentNuclideFilter : public Filter { -public: - //---------------------------------------------------------------------------- - // Constructors, destructors - - ~ParentNuclideFilter() = default; - - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "parentnuclide"; } - FilterType type() const override { return FilterType::PARENT_NUCLIDE; } - - void from_xml(pugi::xml_node node) override; - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - void to_statepoint(hid_t filter_group) const override; - - std::string text_label(int bin) const override; - - //---------------------------------------------------------------------------- - // Accessors - - const vector& bins() const { return bins_; } - void set_bins(span bins); - -protected: - //---------------------------------------------------------------------------- - // Data members - - vector bins_; - vector nuclides_; - - std::unordered_map map_; -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_PARENT_NUCLIDE_H diff --git a/include/openmc/tallies/filter_particle.h b/include/openmc/tallies/filter_particle.h index 9932a6037..cd4c5d413 100644 --- a/include/openmc/tallies/filter_particle.h +++ b/include/openmc/tallies/filter_particle.h @@ -1,8 +1,7 @@ #ifndef OPENMC_TALLIES_FILTER_PARTICLE_H #define OPENMC_TALLIES_FILTER_PARTICLE_H -#include "openmc/particle_type.h" -#include "openmc/span.h" +#include "openmc/particle.h" #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -22,8 +21,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "particle"; } - FilterType type() const override { return FilterType::PARTICLE; } + std::string type() const override { return "particle"; } void from_xml(pugi::xml_node node) override; @@ -39,7 +37,7 @@ public: const vector& particles() const { return particles_; } - void set_particles(span particles); + void set_particles(gsl::span particles); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_particle_production.h b/include/openmc/tallies/filter_particle_production.h deleted file mode 100644 index 00fac9f7c..000000000 --- a/include/openmc/tallies/filter_particle_production.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_PARTICLE_PRODUCTION_H -#define OPENMC_TALLIES_FILTER_PARTICLE_PRODUCTION_H - -#include - -#include "openmc/particle.h" -#include "openmc/tallies/filter.h" -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -//! Bins the outgoing energy of secondary particles -//! -//! This filter bins secondary particles by type and, optionally, by energy. It -//! can be used to get the photon production matrix for multigroup photon -//! transport, the energy distribution of secondary neutrons, etc. The weight -//! that is applied is equal to the weight of the secondary particle. Thus, to -//! get secondary production it should be used in conjunction with the "events" -//! score. -//============================================================================== - -class ParticleProductionFilter : public Filter { -public: - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "particleproduction"; } - FilterType type() const override { return FilterType::PARTICLE_PRODUCTION; } - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - std::string text_label(int bin) const override; - - void from_xml(pugi::xml_node node) override; - - void to_statepoint(hid_t filter_group) const override; - -private: - //---------------------------------------------------------------------------- - // Data members - - vector secondary_types_; //!< Types of secondary particles - - //! Map from PDG number to index in secondary_types_ for O(1) lookup - std::unordered_map type_to_index_; - - vector energy_bins_; //!< Energy bin boundaries (optional) -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_PARTICLE_PRODUCTION_H diff --git a/include/openmc/tallies/filter_polar.h b/include/openmc/tallies/filter_polar.h index c7c73c89f..e06aca1e0 100644 --- a/include/openmc/tallies/filter_polar.h +++ b/include/openmc/tallies/filter_polar.h @@ -3,7 +3,8 @@ #include -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -23,8 +24,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "polar"; } - FilterType type() const override { return FilterType::POLAR; } + std::string type() const override { return "polar"; } void from_xml(pugi::xml_node node) override; @@ -38,7 +38,7 @@ public: //---------------------------------------------------------------------------- // Accessors - void set_bins(span bins); + void set_bins(gsl::span bins); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_reaction.h b/include/openmc/tallies/filter_reaction.h deleted file mode 100644 index 015729eef..000000000 --- a/include/openmc/tallies/filter_reaction.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_REACTION_H -#define OPENMC_TALLIES_FILTER_REACTION_H - -#include "openmc/span.h" -#include "openmc/tallies/filter.h" -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -//! Bins tally events based on the reaction type (MT number). -//============================================================================== - -class ReactionFilter : public Filter { -public: - //---------------------------------------------------------------------------- - // Constructors, destructors - - ~ReactionFilter() = default; - - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "reaction"; } - FilterType type() const override { return FilterType::REACTION; } - - void from_xml(pugi::xml_node node) override; - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - void to_statepoint(hid_t filter_group) const override; - - std::string text_label(int bin) const override; - - //---------------------------------------------------------------------------- - // Accessors - - const vector& bins() const { return bins_; } - void set_bins(span bins); - -protected: - //---------------------------------------------------------------------------- - // Data members - - //! MT numbers to match - vector bins_; -}; - -} // namespace openmc - -#endif // OPENMC_TALLIES_FILTER_REACTION_H diff --git a/include/openmc/tallies/filter_sph_harm.h b/include/openmc/tallies/filter_sph_harm.h index a6904c301..5f5bf84f2 100644 --- a/include/openmc/tallies/filter_sph_harm.h +++ b/include/openmc/tallies/filter_sph_harm.h @@ -3,6 +3,8 @@ #include +#include + #include "openmc/tallies/filter.h" namespace openmc { @@ -23,8 +25,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "sphericalharmonics"; } - FilterType type() const override { return FilterType::SPHERICAL_HARMONICS; } + std::string type() const override { return "sphericalharmonics"; } void from_xml(pugi::xml_node node) override; @@ -44,7 +45,7 @@ public: SphericalHarmonicsCosine cosine() const { return cosine_; } - void set_cosine(const std::string& cosine); + void set_cosine(gsl::cstring_span cosine); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_sptl_legendre.h b/include/openmc/tallies/filter_sptl_legendre.h index b6c380e9b..d6ac24668 100644 --- a/include/openmc/tallies/filter_sptl_legendre.h +++ b/include/openmc/tallies/filter_sptl_legendre.h @@ -23,8 +23,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "spatiallegendre"; } - FilterType type() const override { return FilterType::SPATIAL_LEGENDRE; } + std::string type() const override { return "spatiallegendre"; } void from_xml(pugi::xml_node node) override; diff --git a/include/openmc/tallies/filter_surface.h b/include/openmc/tallies/filter_surface.h index e78243f5f..358963fde 100644 --- a/include/openmc/tallies/filter_surface.h +++ b/include/openmc/tallies/filter_surface.h @@ -4,7 +4,8 @@ #include #include -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -24,8 +25,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "surface"; } - FilterType type() const override { return FilterType::SURFACE; } + std::string type() const override { return "surface"; } void from_xml(pugi::xml_node node) override; @@ -39,7 +39,7 @@ public: //---------------------------------------------------------------------------- // Accessors - void set_surfaces(span surfaces); + void set_surfaces(gsl::span surfaces); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_time.h b/include/openmc/tallies/filter_time.h index 3ce557abd..c66481c57 100644 --- a/include/openmc/tallies/filter_time.h +++ b/include/openmc/tallies/filter_time.h @@ -1,7 +1,8 @@ #ifndef OPENMC_TALLIES_FILTER_TIME_H #define OPENMC_TALLIES_FILTER_TIME_H -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -21,8 +22,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "time"; } - FilterType type() const override { return FilterType::TIME; } + std::string type() const override { return "time"; } void from_xml(pugi::xml_node node) override; @@ -37,7 +37,7 @@ public: // Accessors const vector& bins() const { return bins_; } - void set_bins(span bins); + void set_bins(gsl::span bins); protected: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_universe.h b/include/openmc/tallies/filter_universe.h index 461434ec4..fde0b6397 100644 --- a/include/openmc/tallies/filter_universe.h +++ b/include/openmc/tallies/filter_universe.h @@ -4,7 +4,8 @@ #include #include -#include "openmc/span.h" +#include + #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -24,8 +25,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "universe"; } - FilterType type() const override { return FilterType::UNIVERSE; } + std::string type() const override { return "universe"; } void from_xml(pugi::xml_node node) override; @@ -39,7 +39,7 @@ public: //---------------------------------------------------------------------------- // Accessors - void set_universes(span universes); + void set_universes(gsl::span universes); private: //---------------------------------------------------------------------------- diff --git a/include/openmc/tallies/filter_weight.h b/include/openmc/tallies/filter_weight.h deleted file mode 100644 index 1fe9d75d3..000000000 --- a/include/openmc/tallies/filter_weight.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef OPENMC_TALLIES_FILTER_WEIGHT_H -#define OPENMC_TALLIES_FILTER_WEIGHT_H - -#include - -#include "openmc/span.h" -#include "openmc/tallies/filter.h" -#include "openmc/vector.h" - -namespace openmc { - -//============================================================================== -//! Bins the weights of the particles. -//============================================================================== - -class WeightFilter : public Filter { -public: - //---------------------------------------------------------------------------- - // Constructors, destructors - - ~WeightFilter() = default; - - //---------------------------------------------------------------------------- - // Methods - - std::string type_str() const override { return "weight"; } - FilterType type() const override { return FilterType::WEIGHT; } - - void from_xml(pugi::xml_node node) override; - - void get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const override; - - void to_statepoint(hid_t filter_group) const override; - - std::string text_label(int bin) const override; - - //---------------------------------------------------------------------------- - // Accessors - - const vector& bins() const { return bins_; } - void set_bins(span bins); - -protected: - //---------------------------------------------------------------------------- - // Data members - vector bins_; -}; - -} // namespace openmc -#endif // OPENMC_TALLIES_FILTER_WEIGHT_H diff --git a/include/openmc/tallies/filter_zernike.h b/include/openmc/tallies/filter_zernike.h index b6d9c91e6..72c47e654 100644 --- a/include/openmc/tallies/filter_zernike.h +++ b/include/openmc/tallies/filter_zernike.h @@ -21,8 +21,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "zernike"; } - FilterType type() const override { return FilterType::ZERNIKE; } + std::string type() const override { return "zernike"; } void from_xml(pugi::xml_node node) override; @@ -73,8 +72,7 @@ public: //---------------------------------------------------------------------------- // Methods - std::string type_str() const override { return "zernikeradial"; } - FilterType type() const override { return FilterType::ZERNIKE_RADIAL; } + std::string type() const override { return "zernikeradial"; } void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const override; diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index ae604b732..3cead91dc 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -3,13 +3,14 @@ #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr -#include "openmc/span.h" #include "openmc/tallies/filter.h" #include "openmc/tallies/trigger.h" #include "openmc/vector.h" -#include "openmc/tensor.h" #include "pugixml.hpp" +#include "xtensor/xfixed.hpp" +#include "xtensor/xtensor.hpp" +#include #include #include @@ -34,83 +35,39 @@ public: void set_id(int32_t id); - int id() const { return id_; } - void set_active(bool active) { active_ = active; } - void set_multiply_density(bool value) { multiply_density_ = value; } - void set_writable(bool writable) { writable_ = writable; } void set_scores(pugi::xml_node node); void set_scores(const vector& scores); - std::vector scores() const; - - int32_t n_scores() const { return scores_.size(); } - void set_nuclides(pugi::xml_node node); void set_nuclides(const vector& nuclides); - const tensor::Tensor& results() const { return results_; } - //! returns vector of indices corresponding to the tally this is called on - const vector& filters() const { return filters_; } - - //! returns a vector of filter types for the tally - std::vector filter_types() const; - - //! returns a mapping of filter types to index into the tally's filters - std::unordered_map filter_indices() const; + const vector& filters() const { return filters_; } //! \brief Returns the tally filter at index i - int32_t filters(int i) const { return filters_[i]; } + int32_t filters(int i) const { return filters_[i]; } - //! \brief Return a const pointer to a filter instance based on type. Always - //! returns the first matching filter type - template - const T* get_filter() const - { - const T* out; - for (auto filter_idx : filters_) { - if ((out = dynamic_cast(model::tally_filters[filter_idx].get()))) - return out; - } - return nullptr; - } - - template - const T* get_filter(int idx) const - { - if (const T* out = dynamic_cast(model::tally_filters[filters_.at(idx)])) - return out; - return nullptr; - } - - //! \brief Check if this tally has a specified type of filter - bool has_filter(FilterType filter_type) const; - - void set_filters(span filters); + void set_filters(gsl::span filters); //! Given already-set filters, set the stride lengths void set_strides(); - int64_t strides(int i) const { return strides_[i]; } + int32_t strides(int i) const { return strides_[i]; } - int64_t n_filter_bins() const { return n_filter_bins_; } - - bool multiply_density() const { return multiply_density_; } + int32_t n_filter_bins() const { return n_filter_bins_; } bool writable() const { return writable_; } - bool higher_moments() const { return higher_moments_; } - //---------------------------------------------------------------------------- // Other methods. - void add_filter(Filter* filter); + void add_filter(Filter* filter) { set_filters({&filter, 1}); } void init_triggers(pugi::xml_node node); @@ -120,12 +77,6 @@ public: void accumulate(); - //! return the index of a score specified by name - int score_index(const std::string& score) const; - - //! Tally results reshaped according to filter sizes - tensor::Tensor get_reshaped_data() const; - //! A string representing the i-th score on this tally std::string score_name(int score_idx) const; @@ -159,7 +110,7 @@ public: //! combination of filters (e.g. specific cell, specific energy group, etc.) //! and the second dimension of the array is for scores (e.g. flux, total //! reaction rate, fission reaction rate, etc.) - tensor::Tensor results_; + xt::xtensor results_; //! True if this tally should be written to statepoint files bool writable_ {true}; @@ -184,17 +135,11 @@ private: vector filters_; //!< Filter indices in global filters array //! Index strides assigned to each filter to support 1D indexing. - vector strides_; + vector strides_; - int64_t n_filter_bins_ {0}; + int32_t n_filter_bins_ {0}; - //! Whether to multiply by atom density for reaction rates - bool multiply_density_ {true}; - - //! Whether to accumulate higher moments (third and fourth) - bool higher_moments_ {false}; - - int64_t index_; + gsl::index index_; }; //============================================================================== @@ -207,19 +152,15 @@ extern vector> tallies; extern vector active_tallies; extern vector active_analog_tallies; extern vector active_tracklength_tallies; -extern vector active_timed_tracklength_tallies; extern vector active_collision_tallies; extern vector active_meshsurf_tallies; extern vector active_surface_tallies; -extern vector active_pulse_height_tallies; -extern vector pulse_height_cells; -extern vector time_grid; - } // namespace model namespace simulation { //! Global tallies (such as k-effective estimators) -extern tensor::StaticTensor2D global_tallies; +extern xt::xtensor_fixed> + global_tallies; //! Number of realizations for global tallies extern "C" int32_t n_realizations; @@ -237,24 +178,19 @@ extern double global_tally_leakage; //! Read tally specification from tallies.xml void read_tallies_xml(); -//! Read tally specification from an XML node -//! \param[in] root node of tallies XML element -void read_tallies_xml(pugi::xml_node root); - //! \brief Accumulate the sum of the contributions from each history within the //! batch to a new random variable void accumulate_tallies(); -//! Determine distance to next time boundary -// -//! \param time Current time of particle -//! \param speed Speed of particle -//! \return Distance to next time boundary (or INFTY if none) -double distance_to_time_boundary(double time, double speed); - //! Determine which tallies should be active void setup_active_tallies(); +// Alias for the type returned by xt::adapt(...). N is the dimension of the +// multidimensional array +template +using adaptor_type = + xt::xtensor_adaptor, N>; + #ifdef OPENMC_MPI //! Collect all tally results onto master process void reduce_tally_results(); diff --git a/include/openmc/tallies/tally_scoring.h b/include/openmc/tallies/tally_scoring.h index 4303ddb7a..85d0fc58f 100644 --- a/include/openmc/tallies/tally_scoring.h +++ b/include/openmc/tallies/tally_scoring.h @@ -41,7 +41,7 @@ public: FilterBinIter& operator++(); - int64_t index_ {1}; + int index_ {1}; double weight_ {1.}; vector& filter_matches_; @@ -91,36 +91,11 @@ void score_analog_tally_mg(Particle& p); //! \param distance The distance in [cm] traveled by the particle void score_tracklength_tally(Particle& p, double distance); -//! Score time filtered tallies using a tracklength estimate of the flux. -// -//! This is triggered at every event (surface crossing, lattice crossing, or -//! collision) and thus cannot be done for tallies that require post-collision -//! information. +//! Score surface or mesh-surface tallies for particle currents. // //! \param p The particle being tracked -//! \param total_distance The distance in [cm] traveled by the particle -void score_timed_tracklength_tally(Particle& p, double total_distance); - -//! Score mesh-surface tallies for particle currents. -// -//! \param p The particle being tracked -//! \param tallies A vector of the indices of the tallies to score to -void score_meshsurface_tally(Particle& p, const vector& tallies); - -//! Score surface tallies for particle currents. -// -//! \param p The particle being tracked -//! \param tallies A vector of the indices of the tallies to score to -//! \param normal The normal of the surface being crossed -void score_surface_tally( - Particle& p, const vector& tallies, const Direction& normal); - -//! Score the pulse-height tally -//! This is triggered at the end of every particle history -// -//! \param p The particle being tracked -//! \param tallies A vector of the indices of the tallies to score to -void score_pulse_height_tally(Particle& p, const vector& tallies); +//! \param tallies A vector of tallies to score to +void score_surface_tally(Particle& p, const vector& tallies); } // namespace openmc diff --git a/include/openmc/tallies/trigger.h b/include/openmc/tallies/trigger.h index 7feed5e8a..9fe159b9d 100644 --- a/include/openmc/tallies/trigger.h +++ b/include/openmc/tallies/trigger.h @@ -23,7 +23,6 @@ enum class TriggerMetric { struct Trigger { TriggerMetric metric; //!< The type of uncertainty (e.g. std dev) measured double threshold; //!< Uncertainty value below which trigger is satisfied - bool ignore_zeros; //!< Whether to allow zero tally bins to be ignored int score_index; //!< Index of the relevant score in the tally's arrays }; diff --git a/include/openmc/tensor.h b/include/openmc/tensor.h deleted file mode 100644 index 9e443e72f..000000000 --- a/include/openmc/tensor.h +++ /dev/null @@ -1,1210 +0,0 @@ -//! \file tensor.h -//! \brief Multi-dimensional tensor types for OpenMC. -//! -//! Tensor is the primary type: a dynamic-rank owning container that stores -//! elements contiguously in row-major order. View is a lightweight -//! non-owning reference into a Tensor's storage, returned by the slice() -//! method and flat(). StaticTensor2D is a small stack-allocated 2D -//! array used only for simulation::global_tallies. -//! -//! Slicing follows numpy conventions: each axis takes an index (rank-reducing), -//! All (keep entire axis), or Range (keep sub-range). For example, -//! arr.slice(0, all, range(2, 5)) is equivalent to numpy's arr[0, :, 2:5]. -//! -//! View is declared before Tensor because Tensor's methods return View objects. - -#ifndef OPENMC_TENSOR_H -#define OPENMC_TENSOR_H - -#include "openmc/vector.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openmc { -namespace tensor { - -//============================================================================== -// Forward declarations -//============================================================================== - -template -class Tensor; - -template -class StaticTensor2D; - -//============================================================================== -// Storage type mapping -// -// std::vector is a bit-packed specialization that returns proxy objects -// instead of real references, which breaks generic code. storage_type_map -// redirects bool to unsigned char so that Tensor stores one byte per -// element with normal reference semantics. -//============================================================================== - -template -struct storage_type_map { - using type = T; -}; -template<> -struct storage_type_map { - using type = unsigned char; -}; -template -using storage_type = typename storage_type_map::type; - -//============================================================================== -// Slice argument types -// -// Used with the variadic slice() method on Tensor, View, and StaticTensor2D. -// Each argument corresponds to one axis: a plain integer fixes that axis at -// a single index (rank-reducing), All keeps the entire axis, and Range keeps -// a sub-range. -//============================================================================== - -//! Keep an entire axis (equivalent to numpy's ':' or xtensor's xt::all()) -struct All {}; -constexpr All all {}; - -//! Sub-range along an axis [start, end) -struct Range { - size_t start; - size_t end; // SIZE_MAX means "to end of axis" -}; - -//! Create a Range [start, end) -inline Range range(size_t start, size_t end) -{ - return {start, end}; -} - -//! Create a Range [0, end) -inline Range range(size_t end) -{ - return {0, end}; -} - -namespace detail { - -//! Internal: normalized representation of a per-axis slice argument -struct SliceArg { - enum Kind { INDEX, ALL, RANGE } kind; - size_t start; - size_t end; -}; - -inline SliceArg to_slice_arg(All) -{ - return {SliceArg::ALL, 0, 0}; -} -inline SliceArg to_slice_arg(Range r) -{ - return {SliceArg::RANGE, r.start, r.end}; -} - -template -inline - typename std::enable_if::value || std::is_enum::value, - SliceArg>::type - to_slice_arg(I i) -{ - return {SliceArg::INDEX, static_cast(i), 0}; -} - -//! Result of a slice computation: pointer offset + new shape/strides -struct SliceResult { - size_t ptr_offset; - vector shape; - vector strides; -}; - -//! Compute the result of applying slice arguments to shape/strides -template -SliceResult compute_slice(const vector& shape, - const vector& strides, First first, Rest... rest) -{ - const size_t n = 1 + sizeof...(Rest); - SliceArg args[1 + sizeof...(Rest)] = { - to_slice_arg(first), to_slice_arg(rest)...}; - - size_t offset = 0; - vector new_shape; - vector new_strides; - - for (size_t a = 0; a < n; ++a) { - switch (args[a].kind) { - case SliceArg::INDEX: - offset += args[a].start * strides[a]; - break; - case SliceArg::ALL: - new_shape.push_back(shape[a]); - new_strides.push_back(strides[a]); - break; - case SliceArg::RANGE: { - offset += args[a].start * strides[a]; - size_t end = (args[a].end == SIZE_MAX) ? shape[a] : args[a].end; - new_shape.push_back(end - args[a].start); - new_strides.push_back(strides[a]); - break; - } - } - } - - // Trailing axes not covered by arguments are implicitly All. - // This matches numpy: a[i] on a 2D array returns a 1D row. - for (size_t a = n; a < shape.size(); ++a) { - new_shape.push_back(shape[a]); - new_strides.push_back(strides[a]); - } - - return {offset, std::move(new_shape), std::move(new_strides)}; -} - -} // namespace detail - -//============================================================================== -// View: a non-owning N-dimensional view into a tensor's storage. -// -// Holds a base pointer, shape, and strides (in elements). Supports arbitrary -// rank and multi-axis slicing via the variadic slice() method. -//============================================================================== - -template -class View { -public: - //-------------------------------------------------------------------------- - // Constructors - - View(T* data, vector shape, vector strides) - : data_(data), shape_(std::move(shape)), strides_(std::move(strides)) - {} - - // Explicitly default copy/move constructors (declaring copy assignment - // below would otherwise suppress the implicit move constructor). - View(const View&) = default; - View(View&&) = default; - - //-------------------------------------------------------------------------- - // Indexing - - //! Multi-index element access (1D, 2D, 3D, ...) - template - T& operator()(Indices... indices) - { - const size_t idx[] = {static_cast(indices)...}; - size_t off = 0; - for (size_t d = 0; d < sizeof...(Indices); ++d) - off += idx[d] * strides_[d]; - return data_[off]; - } - - template - const T& operator()(Indices... indices) const - { - const size_t idx[] = {static_cast(indices)...}; - size_t off = 0; - for (size_t d = 0; d < sizeof...(Indices); ++d) - off += idx[d] * strides_[d]; - return data_[off]; - } - - //! Flat logical index (row-major order) - T& operator[](size_t i) { return data_[flat_to_offset(i)]; } - const T& operator[](size_t i) const { return data_[flat_to_offset(i)]; } - - //-------------------------------------------------------------------------- - // Accessors - - size_t size() const - { - size_t s = 1; - for (auto d : shape_) - s *= d; - return s; - } - size_t ndim() const { return shape_.size(); } - size_t shape(size_t axis) const { return shape_[axis]; } - const vector& shape_vec() const { return shape_; } - T* data() { return data_; } - const T* data() const { return data_; } - - //-------------------------------------------------------------------------- - // View accessors - - //! Multi-axis slice. Each argument corresponds to one axis and is either: - //! - an integer (fixes that axis, rank-reducing) - //! - All (keeps entire axis) - //! - Range (keeps sub-range along that axis) - //! Example: v.slice(0, all, range(2, 5)) == numpy v[0, :, 2:5] - template - View slice(First first, Rest... rest) - { - auto r = detail::compute_slice(shape_, strides_, first, rest...); - return {data_ + r.ptr_offset, std::move(r.shape), std::move(r.strides)}; - } - - template - View slice(First first, Rest... rest) const - { - auto r = detail::compute_slice(shape_, strides_, first, rest...); - return {data_ + r.ptr_offset, std::move(r.shape), std::move(r.strides)}; - } - - //-------------------------------------------------------------------------- - // Assignment operators - - //! Copy assignment: element-wise deep copy (writes through data pointer). - //! Without this, the compiler's implicit copy assignment just copies the - //! View metadata (pointer, shape, strides) instead of the viewed data. - View& operator=(const View& other) - { - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] = other[i]; - return *this; - } - - //! Fill all elements with a scalar - View& operator=(T val) - { - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] = val; - return *this; - } - - //! Assignment from initializer_list (for 1D views) - View& operator=(std::initializer_list vals) - { - auto it = vals.begin(); - for (size_t i = 0; i < size() && it != vals.end(); ++i, ++it) - data_[flat_to_offset(i)] = *it; - return *this; - } - - //! Assignment from another View - template - View& operator=(const View& other) - { - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] = other[i]; - return *this; - } - - //! Assignment from Tensor (forward-declared, defined after Tensor) - template - View& operator=(const Tensor& other); - - //! Compound addition from Tensor (forward-declared, defined after Tensor) - template - View& operator+=(const Tensor& o); - - //! Compound multiply by scalar - View& operator*=(T val) - { - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] *= val; - return *this; - } - - //! Compound divide by scalar - View& operator/=(T val) - { - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] /= val; - return *this; - } - - //-------------------------------------------------------------------------- - // Reductions - - //! Sum of all elements - T sum() const - { - // remove_const needed so accumulator is mutable when T is const-qualified - std::remove_const_t s = 0; - size_t n = size(); - for (size_t i = 0; i < n; ++i) - s += data_[flat_to_offset(i)]; - return s; - } - - //-------------------------------------------------------------------------- - // Iterators - // - // Lightweight row-major iterator parameterized on pointer type (Ptr). - // Stores a flat logical position and converts to a physical offset on each - // dereference via divmod over shape/strides. For contiguous 1D views (the - // common case) the divmod chain reduces to a single multiply-by-1, which - // the compiler optimizes away. - // - // view_iterator = mutable iterator (from non-const View) - // view_iterator = read-only iterator (from const View) - - template - class view_iterator { - Ptr base_; - size_t count_; - const size_t* shape_; - const size_t* strides_; - size_t ndim_; - - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_const_t; - using difference_type = std::ptrdiff_t; - using pointer = Ptr; - using reference = decltype(*std::declval()); - - view_iterator(Ptr base, size_t count, const View* v) - : base_(base), count_(count), shape_(v->shape_.data()), - strides_(v->strides_.data()), ndim_(v->shape_.size()) - {} - - reference operator*() const { return base_[offset()]; } - reference operator[](difference_type n) const - { - return base_[offset_of(count_ + n)]; - } - view_iterator& operator++() - { - ++count_; - return *this; - } - view_iterator operator++(int) - { - auto tmp = *this; - ++count_; - return tmp; - } - view_iterator& operator--() - { - --count_; - return *this; - } - view_iterator operator+(difference_type n) const - { - auto tmp = *this; - tmp.count_ += n; - return tmp; - } - view_iterator operator-(difference_type n) const - { - auto tmp = *this; - tmp.count_ -= n; - return tmp; - } - difference_type operator-(const view_iterator& o) const - { - return static_cast(count_) - - static_cast(o.count_); - } - view_iterator& operator+=(difference_type n) - { - count_ += n; - return *this; - } - view_iterator& operator-=(difference_type n) - { - count_ -= n; - return *this; - } - bool operator==(const view_iterator& o) const { return count_ == o.count_; } - bool operator!=(const view_iterator& o) const { return count_ != o.count_; } - bool operator<(const view_iterator& o) const { return count_ < o.count_; } - bool operator>(const view_iterator& o) const { return count_ > o.count_; } - bool operator<=(const view_iterator& o) const { return count_ <= o.count_; } - bool operator>=(const view_iterator& o) const { return count_ >= o.count_; } - friend view_iterator operator+(difference_type n, const view_iterator& it) - { - return it + n; - } - - private: - size_t offset() const { return offset_of(count_); } - size_t offset_of(size_t flat) const - { - size_t off = 0; - for (int d = static_cast(ndim_) - 1; d >= 0; --d) { - off += (flat % shape_[d]) * strides_[d]; - flat /= shape_[d]; - } - return off; - } - }; - - using iterator = view_iterator; - using const_iterator = view_iterator; - - iterator begin() { return {data_, 0, this}; } - iterator end() { return {data_, size(), this}; } - const_iterator begin() const { return cbegin(); } - const_iterator end() const { return cend(); } - const_iterator cbegin() const { return {data_, 0, this}; } - const_iterator cend() const { return {data_, size(), this}; } - -private: - //! Convert a logical flat index (row-major) to a physical element offset - size_t flat_to_offset(size_t flat) const - { - size_t off = 0; - for (int d = static_cast(shape_.size()) - 1; d >= 0; --d) { - off += (flat % shape_[d]) * strides_[d]; - flat /= shape_[d]; - } - return off; - } - - T* data_; - vector shape_; - vector strides_; -}; - -//============================================================================== -// Tensor: dynamic-rank N-dimensional tensor. -// -// Stores elements in a contiguous row-major vector> -// with a dynamic shape. -//============================================================================== - -template -class Tensor { -public: - using value_type = T; - using stored_type = storage_type; - using iterator = typename vector::iterator; - using const_iterator = typename vector::const_iterator; - - //-------------------------------------------------------------------------- - // Constructors - - Tensor() = default; - - //! Construct with shape (uninitialized for arithmetic types via vector - //! resize) - explicit Tensor(vector shape) - : shape_(std::move(shape)), data_(compute_size()) - {} - - //! Construct with shape and fill value - Tensor(vector shape, T fill) - : shape_(std::move(shape)), data_(compute_size(), fill) - {} - - //! Construct from initializer_list shape - explicit Tensor(std::initializer_list shape) - : shape_(shape), data_(compute_size()) - {} - - //! Construct from initializer_list shape with fill - Tensor(std::initializer_list shape, T fill) - : shape_(shape), data_(compute_size(), fill) - {} - - //! 1D copy from raw pointer + count - Tensor(const T* ptr, size_t count) : shape_({count}), data_(ptr, ptr + count) - {} - - //! Copy from View (preserves view's shape) - template - explicit Tensor(const View& v) : shape_(v.shape_vec()) - { - size_t n = v.size(); - data_.resize(n); - for (size_t i = 0; i < n; ++i) - data_[i] = v[i]; - } - - //-------------------------------------------------------------------------- - // Assignment - - //! Assignment from View - template - Tensor& operator=(const View& v) - { - shape_ = v.shape_vec(); - size_t n = v.size(); - data_.resize(n); - for (size_t i = 0; i < n; ++i) - data_[i] = v[i]; - return *this; - } - - //! Assignment from initializer_list of values (1D) - Tensor& operator=(std::initializer_list vals) - { - shape_ = {vals.size()}; - data_.assign(vals.begin(), vals.end()); - return *this; - } - - //-------------------------------------------------------------------------- - // Accessors - - stored_type* data() { return data_.data(); } - const stored_type* data() const { return data_.data(); } - size_t size() const { return data_.size(); } - const vector& shape() const { return shape_; } - size_t shape(size_t dim) const - { - return dim < shape_.size() ? shape_[dim] : 0; - } - size_t ndim() const { return shape_.size(); } - bool empty() const { return data_.empty(); } - - //-------------------------------------------------------------------------- - // Indexing (row-major) - - template - stored_type& operator()(Indices... indices) - { - const size_t idx[] = {static_cast(indices)...}; - size_t off = 0; - for (size_t d = 0; d < sizeof...(Indices); ++d) - off = off * shape_[d] + idx[d]; - return data_[off]; - } - - template - const stored_type& operator()(Indices... indices) const - { - const size_t idx[] = {static_cast(indices)...}; - size_t off = 0; - for (size_t d = 0; d < sizeof...(Indices); ++d) - off = off * shape_[d] + idx[d]; - return data_[off]; - } - - stored_type& operator[](size_t i) { return data_[i]; } - const stored_type& operator[](size_t i) const { return data_[i]; } - - //! First and last element - stored_type& front() { return data_.front(); } - const stored_type& front() const { return data_.front(); } - stored_type& back() { return data_.back(); } - const stored_type& back() const { return data_.back(); } - - //-------------------------------------------------------------------------- - // Iterators - - iterator begin() { return data_.begin(); } - iterator end() { return data_.end(); } - const_iterator begin() const { return data_.begin(); } - const_iterator end() const { return data_.end(); } - const_iterator cbegin() const { return data_.cbegin(); } - const_iterator cend() const { return data_.cend(); } - - //-------------------------------------------------------------------------- - // Mutation - - void resize(const vector& shape) - { - shape_ = shape; - data_.resize(compute_size()); - } - - void resize(std::initializer_list shape) - { - shape_.assign(shape.begin(), shape.end()); - data_.resize(compute_size()); - } - - void reshape(const vector& new_shape) { shape_ = new_shape; } - - void fill(T val) { std::fill(data_.begin(), data_.end(), val); } - - //-------------------------------------------------------------------------- - // View accessors - - //! Fix one axis at a given index, returning an (N-1)-dimensional view - //! Multi-axis slice. Each argument corresponds to one axis and is either: - //! - an integer (fixes that axis, rank-reducing) - //! - All (keeps entire axis) - //! - Range (keeps sub-range along that axis) - //! Example: t.slice(0, all, range(2, 5)) == numpy t[0, :, 2:5] - template - View slice(First first, Rest... rest) - { - auto strides = compute_strides(); - auto r = detail::compute_slice(shape_, strides, first, rest...); - return { - data_.data() + r.ptr_offset, std::move(r.shape), std::move(r.strides)}; - } - - template - View slice(First first, Rest... rest) const - { - auto strides = compute_strides(); - auto r = detail::compute_slice(shape_, strides, first, rest...); - return { - data_.data() + r.ptr_offset, std::move(r.shape), std::move(r.strides)}; - } - - //! Flat 1D view of all elements - View flat() - { - return {data_.data(), {data_.size()}, {size_t(1)}}; - } - View flat() const - { - return {data_.data(), {data_.size()}, {size_t(1)}}; - } - - //-------------------------------------------------------------------------- - // Reductions and transforms - - //! Sum of all elements - T sum() const - { - T s = T(0); - for (size_t i = 0; i < data_.size(); ++i) - s += data_[i]; - return s; - } - - //! Sum along an axis, reducing rank by 1 (defined out-of-line below) - Tensor sum(size_t axis) const; - - //! Product of all elements - T prod() const - { - T p = T(1); - for (size_t i = 0; i < data_.size(); ++i) - p *= data_[i]; - return p; - } - - //! True if any element is nonzero - bool any() const - { - for (size_t i = 0; i < data_.size(); ++i) - if (data_[i]) - return true; - return false; - } - - //! True if all elements are nonzero - bool all() const - { - for (size_t i = 0; i < data_.size(); ++i) - if (!data_[i]) - return false; - return true; - } - - //! Flat index of the minimum element - size_t argmin() const - { - return static_cast(std::distance(data_.data(), - std::min_element(data_.data(), data_.data() + data_.size()))); - } - - //! Reverse element order along an axis (e.g. flip(0) reverses rows) - Tensor flip(size_t axis) const - { - size_t outer_size = 1; - for (size_t d = 0; d < axis; ++d) - outer_size *= shape_[d]; - size_t axis_size = shape_[axis]; - size_t inner_size = 1; - for (size_t d = axis + 1; d < shape_.size(); ++d) - inner_size *= shape_[d]; - - Tensor r(shape_); - for (size_t o = 0; o < outer_size; ++o) - for (size_t a = 0; a < axis_size; ++a) - for (size_t i = 0; i < inner_size; ++i) - r.data_[(o * axis_size + (axis_size - 1 - a)) * inner_size + i] = - data_[(o * axis_size + a) * inner_size + i]; - return r; - } - - //-------------------------------------------------------------------------- - // Operators - - Tensor& operator+=(T val) - { - for (auto& x : data_) - x += val; - return *this; - } - Tensor& operator-=(T val) - { - for (auto& x : data_) - x -= val; - return *this; - } - Tensor& operator*=(T val) - { - for (auto& x : data_) - x *= val; - return *this; - } - Tensor& operator/=(T val) - { - for (auto& x : data_) - x /= val; - return *this; - } - Tensor& operator+=(const Tensor& o) - { - for (size_t i = 0; i < data_.size(); ++i) - data_[i] += o.data_[i]; - return *this; - } - Tensor& operator-=(const Tensor& o) - { - for (size_t i = 0; i < data_.size(); ++i) - data_[i] -= o.data_[i]; - return *this; - } - Tensor& operator*=(const Tensor& o) - { - for (size_t i = 0; i < data_.size(); ++i) - data_[i] *= o.data_[i]; - return *this; - } - Tensor& operator/=(const Tensor& o) - { - for (size_t i = 0; i < data_.size(); ++i) - data_[i] /= o.data_[i]; - return *this; - } - - Tensor operator+(const Tensor& o) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] + o.data_[i]; - return r; - } - Tensor operator-(const Tensor& o) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] - o.data_[i]; - return r; - } - Tensor operator/(const Tensor& o) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] / o.data_[i]; - return r; - } - Tensor operator*(const Tensor& o) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] * o.data_[i]; - return r; - } - - Tensor operator+(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] + val; - return r; - } - Tensor operator-(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] - val; - return r; - } - Tensor operator*(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data_[i] = data_[i] * val; - return r; - } - - Tensor operator<=(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data()[i] = data_[i] <= val; - return r; - } - Tensor operator<(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data()[i] = data_[i] < val; - return r; - } - Tensor operator>=(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data()[i] = data_[i] >= val; - return r; - } - Tensor operator>(T val) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data()[i] = data_[i] > val; - return r; - } - Tensor operator<(const Tensor& o) const - { - Tensor r(shape_); - for (size_t i = 0; i < data_.size(); ++i) - r.data()[i] = data_[i] < o.data_[i]; - return r; - } - -private: - size_t compute_size() const - { - size_t s = 1; - for (auto d : shape_) - s *= d; - return s; - } - - //! Compute row-major strides from shape - vector compute_strides() const - { - vector strides(shape_.size()); - if (!shape_.empty()) { - strides.back() = 1; - for (int d = static_cast(shape_.size()) - 2; d >= 0; --d) - strides[d] = strides[d + 1] * shape_[d + 1]; - } - return strides; - } - - //-------------------------------------------------------------------------- - // Data members - - vector shape_; - vector> data_; -}; - -//============================================================================== -// Non-member operators (scalar op tensor) -//============================================================================== - -template -Tensor operator*(T val, const Tensor& arr) -{ - return arr * val; -} - -template -Tensor operator+(T val, const Tensor& arr) -{ - return arr + val; -} - -// Mixed-type arithmetic: Tensor op Tensor -> Tensor -// A SFINAE guard is used here, as without !is_same Tensor * Tensor -// would be ambiguous between the member operator* and this non-member function. -template::value>> -Tensor operator*(const Tensor& a, const Tensor& b) -{ - Tensor r(a.shape()); - for (size_t i = 0; i < a.size(); ++i) - r.data()[i] = - static_cast(a.data()[i]) * static_cast(b.data()[i]); - return r; -} - -// Same SFINAE guard as operator* above. -template::value>> -Tensor operator/(const Tensor& a, const Tensor& b) -{ - Tensor r(a.shape()); - for (size_t i = 0; i < a.size(); ++i) - r.data()[i] = - static_cast(a.data()[i]) / static_cast(b.data()[i]); - return r; -} - -//============================================================================== -// Out-of-line method definitions (require complete types) -//============================================================================== - -template -template -View& View::operator=(const Tensor& other) -{ - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] = static_cast(other.data()[i]); - return *this; -} - -template -template -View& View::operator+=(const Tensor& o) -{ - size_t n = size(); - for (size_t i = 0; i < n; ++i) - data_[flat_to_offset(i)] += o.data()[i]; - return *this; -} - -template -Tensor Tensor::sum(size_t axis) const -{ - // Build output shape (all dims except the summed axis) - vector out_shape; - for (size_t d = 0; d < shape_.size(); ++d) - if (d != axis) - out_shape.push_back(shape_[d]); - - // Split dimensions into three zones: outer | axis | inner - size_t outer_size = 1; - for (size_t d = 0; d < axis; ++d) - outer_size *= shape_[d]; - size_t axis_size = shape_[axis]; - size_t inner_size = 1; - for (size_t d = axis + 1; d < shape_.size(); ++d) - inner_size *= shape_[d]; - - Tensor result(out_shape, T(0)); - for (size_t o = 0; o < outer_size; ++o) - for (size_t a = 0; a < axis_size; ++a) - for (size_t i = 0; i < inner_size; ++i) - result.data()[o * inner_size + i] += - data_[(o * axis_size + a) * inner_size + i]; - - return result; -} - -//============================================================================== -// StaticTensor2D: compile-time fixed 2D tensor. -//============================================================================== - -template -class StaticTensor2D { -public: - using value_type = T; - - //-------------------------------------------------------------------------- - // Indexing - - //! Templated to accept enum class indices (e.g. GlobalTally, TallyResult) - //! which don't implicitly convert to integer types. - template - T& operator()(I0 i, I1 j) - { - return data_[static_cast(i) * C + static_cast(j)]; - } - template - const T& operator()(I0 i, I1 j) const - { - return data_[static_cast(i) * C + static_cast(j)]; - } - - //-------------------------------------------------------------------------- - // Accessors - - T* data() { return data_; } - const T* data() const { return data_; } - constexpr size_t size() const { return R * C; } - std::array shape() const { return {R, C}; } - - //-------------------------------------------------------------------------- - // Mutation - - void fill(T val) { std::fill(data_, data_ + R * C, val); } - - //-------------------------------------------------------------------------- - // Iterators - - T* begin() { return data_; } - T* end() { return data_ + R * C; } - const T* begin() const { return data_; } - const T* end() const { return data_ + R * C; } - - //-------------------------------------------------------------------------- - // View accessors - - //! Multi-axis slice (same interface as Tensor/View). - template - View slice(First first, Rest... rest) - { - vector sh = {R, C}; - vector st = {C, 1}; - auto r = detail::compute_slice(sh, st, first, rest...); - return {data_ + r.ptr_offset, std::move(r.shape), std::move(r.strides)}; - } - template - View slice(First first, Rest... rest) const - { - vector sh = {R, C}; - vector st = {C, 1}; - auto r = detail::compute_slice(sh, st, first, rest...); - return {data_ + r.ptr_offset, std::move(r.shape), std::move(r.strides)}; - } - - //! Flat view (1D, contiguous) - View flat() { return {data_, {R * C}, {size_t(1)}}; } - View flat() const { return {data_, {R * C}, {size_t(1)}}; } - -private: - //-------------------------------------------------------------------------- - // Data members - - T data_[R * C] = {}; -}; - -//============================================================================== -// Non-member functions -//============================================================================== - -template -Tensor zeros(std::initializer_list shape) -{ - vector s(shape); - return Tensor(std::move(s), T(0)); -} - -template -Tensor zeros(const vector& shape) -{ - return Tensor(shape, T(0)); -} - -template -Tensor ones(std::initializer_list shape) -{ - vector s(shape); - return Tensor(std::move(s), T(1)); -} - -template -Tensor ones(const vector& shape) -{ - return Tensor(shape, T(1)); -} - -template -Tensor zeros_like(const Tensor& o) -{ - return Tensor(o.shape(), T(0)); -} - -template -Tensor full_like(const Tensor& o, V val) -{ - return Tensor(o.shape(), static_cast(val)); -} - -//! Return a 1D tensor of n evenly spaced values from start to stop (inclusive) -template -Tensor linspace(T start, T stop, size_t n) -{ - Tensor result({n}); - if (n < 2) { - result[0] = start; - return result; - } - for (size_t i = 0; i < n; ++i) { - result[i] = - start + static_cast(i) * (stop - start) / static_cast(n - 1); - } - return result; -} - -//! Concatenate two 1D tensors end-to-end -template -Tensor concatenate(const Tensor& a, const Tensor& b) -{ - size_t total = a.size() + b.size(); - Tensor result({total}); - std::copy(a.data(), a.data() + a.size(), result.data()); - std::copy(b.data(), b.data() + b.size(), result.data() + a.size()); - return result; -} - -//! Element-wise natural logarithm -template -Tensor log(const Tensor& a) -{ - Tensor r(a.shape()); - for (size_t i = 0; i < a.size(); ++i) - r.data()[i] = std::log(a.data()[i]); - return r; -} - -//! Element-wise absolute value -template -Tensor abs(const Tensor& a) -{ - Tensor r(a.shape()); - for (size_t i = 0; i < a.size(); ++i) - r.data()[i] = std::abs(a.data()[i]); - return r; -} - -//! Element-wise conditional: select from true_val where cond is true, -//! otherwise use false_val -template -Tensor where( - const Tensor& cond, const Tensor& true_val, V false_val) -{ - Tensor r(cond.shape()); - for (size_t i = 0; i < cond.size(); ++i) - r.data()[i] = - cond.data()[i] ? true_val.data()[i] : static_cast(false_val); - return r; -} - -//! Replace NaN/Inf values with finite substitutes -template -Tensor nan_to_num(const Tensor& a, T nan_val = T(0), - T posinf_val = std::numeric_limits::max(), - T neginf_val = std::numeric_limits::lowest()) -{ - Tensor r(a.shape()); - for (size_t i = 0; i < a.size(); ++i) { - T val = a.data()[i]; - if (std::isnan(val)) - r.data()[i] = nan_val; - else if (std::isinf(val)) - r.data()[i] = val > 0 ? posinf_val : neginf_val; - else - r.data()[i] = val; - } - return r; -} - -//============================================================================== -// Type traits -//============================================================================== - -//! Type trait that is true for Tensor and StaticTensor2D. -//! Used by hdf5_interface.h to select the correct write_dataset overload. -template -struct is_tensor : std::false_type {}; - -template -struct is_tensor> : std::true_type {}; - -template -struct is_tensor> : std::true_type {}; - -} // namespace tensor -} // namespace openmc - -#endif // OPENMC_TENSOR_H diff --git a/include/openmc/thermal.h b/include/openmc/thermal.h index c06a2ee0d..de0767d0a 100644 --- a/include/openmc/thermal.h +++ b/include/openmc/thermal.h @@ -5,7 +5,7 @@ #include #include -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/angle_energy.h" #include "openmc/endf.h" @@ -51,25 +51,7 @@ public: //! \param[out] mu Outgoing scattering angle cosine //! \param[inout] seed Pseudorandom seed pointer void sample(const NuclideMicroXS& micro_xs, double E_in, double* E_out, - double* mu, uint64_t* seed) const; - - //! Select the elastic or inelastic distribution to sample - //! \param[in] micro_xs Microscopic cross sections - //! \param[in] E Incident neutron energy in [eV] - //! \param[inout] seed Pseudorandom seed pointer - //! \return Reference to the selected angle-energy distribution - AngleEnergy& sample_dist( - const NuclideMicroXS& micro_xs, double E, uint64_t* seed) const; - - //! Sample an outgoing energy and evaluate the angular PDF - //! \param[in] micro_xs Microscopic cross sections - //! \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(const NuclideMicroXS& micro_xs, double E_in, - double mu, double& E_out, uint64_t* seed) const; + double* mu, uint64_t* seed); private: struct Reaction { diff --git a/include/openmc/timer.h b/include/openmc/timer.h index d928aad45..62b97883f 100644 --- a/include/openmc/timer.h +++ b/include/openmc/timer.h @@ -31,7 +31,6 @@ extern Timer time_event_advance_particle; extern Timer time_event_surface_crossing; extern Timer time_event_collision; extern Timer time_event_death; -extern Timer time_update_src; } // namespace simulation diff --git a/include/openmc/universe.h b/include/openmc/universe.h index b7450224f..b98d2d57f 100644 --- a/include/openmc/universe.h +++ b/include/openmc/universe.h @@ -1,16 +1,14 @@ #ifndef OPENMC_UNIVERSE_H #define OPENMC_UNIVERSE_H -#include "openmc/bounding_box.h" #include "openmc/cell.h" namespace openmc { -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC class DAGUniverse; #endif -class GeometryState; class Universe; class UniversePartitioner; @@ -29,23 +27,22 @@ class Universe { public: int32_t id_; //!< Unique ID vector cells_; //!< Cells within this universe - int32_t n_instances_; //!< Number of instances of this universe //! \brief Write universe information to an HDF5 group. //! \param group_id An HDF5 group id. virtual void to_hdf5(hid_t group_id) const; - virtual bool find_cell(GeometryState& p) const; + virtual bool find_cell(Particle& p) const; BoundingBox bounding_box() const; - /* By default, universes are CSG universes. The DAGMC - * universe overrides standard behaviors, and in the future, - * other things might too. - */ - virtual GeometryType geom_type() const { return GeometryType::CSG; } + const GeometryType& geom_type() const { return geom_type_; } + GeometryType& geom_type() { return geom_type_; } unique_ptr partitioner_; + +private: + GeometryType geom_type_ = GeometryType::CSG; }; //============================================================================== diff --git a/include/openmc/urr.h b/include/openmc/urr.h index d40c2aff7..3978c7b86 100644 --- a/include/openmc/urr.h +++ b/include/openmc/urr.h @@ -3,7 +3,7 @@ #ifndef OPENMC_URR_H #define OPENMC_URR_H -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/constants.h" #include "openmc/hdf5_interface.h" @@ -27,10 +27,10 @@ public: double heating; }; - Interpolation interp_; //!< interpolation type - int inelastic_flag_; //!< inelastic competition flag - int absorption_flag_; //!< other absorption flag - bool multiply_smooth_; //!< multiply by smooth cross section? + Interpolation interp_; //!< interpolation type + int inelastic_flag_; //!< inelastic competition flag + int absorption_flag_; //!< other absorption flag + bool multiply_smooth_; //!< multiply by smooth cross section? vector energy_; //!< incident energies auto n_energy() const { return energy_.size(); } @@ -40,11 +40,11 @@ public: * below, obviously, values of the CDF are stored. For the xs_values * variable, the columns line up with the index of cdf_values. */ - tensor::Tensor cdf_values_; // Note: must be row major! - tensor::Tensor xs_values_; + xt::xtensor cdf_values_; // Note: must be row major! + xt::xtensor xs_values_; // Number of points in the CDF - auto n_cdf() const { return cdf_values_.shape(1); } + auto n_cdf() const { return cdf_values_.shape()[1]; } //! \brief Load the URR data from the provided HDF5 group explicit UrrData(hid_t group_id); diff --git a/include/openmc/version.h.in b/include/openmc/version.h.in index 6dfc7c7dd..a518e0d63 100644 --- a/include/openmc/version.h.in +++ b/include/openmc/version.h.in @@ -9,10 +9,8 @@ namespace openmc { // clang-format off constexpr int VERSION_MAJOR {@OPENMC_VERSION_MAJOR@}; constexpr int VERSION_MINOR {@OPENMC_VERSION_MINOR@}; -constexpr int VERSION_RELEASE {@OPENMC_VERSION_PATCH@}; -constexpr bool VERSION_DEV {@OPENMC_DEV_STATE@}; -constexpr const char* VERSION_COMMIT_COUNT = "@OPENMC_COMMIT_COUNT@"; -constexpr const char* VERSION_COMMIT_HASH = "@OPENMC_COMMIT_HASH@"; +constexpr int VERSION_RELEASE {@OPENMC_VERSION_RELEASE@}; +constexpr bool VERSION_DEV {false}; constexpr std::array VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE}; // clang-format on diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index ef75ec065..db96f250f 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -1,22 +1,16 @@ #ifndef OPENMC_VOLUME_CALC_H #define OPENMC_VOLUME_CALC_H -#include // for find -#include -#include -#include - #include "openmc/array.h" -#include "openmc/openmp_interface.h" #include "openmc/position.h" #include "openmc/tallies/trigger.h" #include "openmc/vector.h" -#include "openmc/tensor.h" #include "pugixml.hpp" -#ifdef _OPENMP -#include -#endif +#include "xtensor/xtensor.hpp" + +#include +#include namespace openmc { @@ -34,13 +28,11 @@ public: vector atoms; //!< Number of atoms for each nuclide vector uncertainty; //!< Uncertainty on number of atoms int iterations; //!< Number of iterations needed to obtain the results - }; // Results for a single domain + }; // Results for a single domain // Constructors VolumeCalculation(pugi::xml_node node); - VolumeCalculation() = default; - // Methods //! \brief Stochastically determine the volume of a set of domains along with @@ -77,8 +69,7 @@ private: //! \param[in] i_material Index in global materials vector //! \param[in,out] indices Vector of material indices //! \param[in,out] hits Number of hits corresponding to each material - void check_hit( - int i_material, vector& indices, vector& hits) const; + void check_hit(int i_material, vector& indices, vector& hits) const; }; //============================================================================== @@ -93,35 +84,6 @@ extern vector volume_calcs; // Non-member functions //============================================================================== -//! Reduce vector of indices and hits from each thread to a single copy -// -//! \param[in] local_indices Indices specific to each thread -//! \param[in] local_hits Hit count specific to each thread -//! \param[out] indices Reduced vector of indices -//! \param[out] hits Reduced vector of hits -template -void reduce_indices_hits(const vector& local_indices, - const vector& local_hits, vector& indices, vector& hits) -{ - const int n_threads = num_threads(); - -#pragma omp for ordered schedule(static, 1) - for (int i = 0; i < n_threads; ++i) { -#pragma omp ordered - for (int j = 0; j < local_indices.size(); ++j) { - // Check if this material has been added to the master list and if - // so, accumulate the number of hits - auto it = std::find(indices.begin(), indices.end(), local_indices[j]); - if (it == indices.end()) { - indices.push_back(local_indices[j]); - hits.push_back(local_hits[j]); - } else { - hits[it - indices.begin()] += local_hits[j]; - } - } - } -} - void free_memory_volume(); } // namespace openmc diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index d0b385d16..45c1de919 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -10,33 +10,38 @@ #include "openmc/constants.h" #include "openmc/memory.h" #include "openmc/mesh.h" -#include "openmc/particle_type.h" -#include "openmc/span.h" -#include "openmc/tallies/tally.h" +#include "openmc/particle.h" #include "openmc/vector.h" namespace openmc { -enum class WeightWindowUpdateMethod { MAGIC, FW_CADIS }; - //============================================================================== // Constants //============================================================================== constexpr double DEFAULT_WEIGHT_CUTOFF {1.0e-38}; // default low weight cutoff +//============================================================================== +// Non-member functions +//============================================================================== + +//! Apply weight windows to a particle +//! \param[in] p Particle to apply weight windows to +void apply_weight_windows(Particle& p); + +//! Free memory associated with weight windows +void free_memory_weight_windows(); + //============================================================================== // Global variables //============================================================================== class WeightWindows; -class WeightWindowsGenerator; namespace variance_reduction { extern std::unordered_map ww_map; extern vector> weight_windows; -extern vector> weight_windows_generators; } // namespace variance_reduction @@ -50,21 +55,16 @@ struct WeightWindow { double max_lb_ratio {1}; double survival_weight {0.5}; double weight_cutoff {DEFAULT_WEIGHT_CUTOFF}; - int max_split {10}; + int max_split {1}; - //! Whether the weight window is in a valid state. A non-positive lower - //! bound indicates that no weight window information exists at this - //! location (generators mark such cells with -1, and a lower bound of zero - //! conventionally turns the weight window game off in a cell, as in MCNP - //! wwinp files), in which case no weight window game is played. - bool is_valid() const { return lower_weight > 0.0; } + //! Whether the weight window is in a valid state + bool is_valid() const { return lower_weight >= 0.0; } //! Adjust the weight window by a constant factor void scale(double factor) { lower_weight *= factor; upper_weight *= factor; - survival_weight *= factor; } }; @@ -74,55 +74,15 @@ struct WeightWindow { class WeightWindows { public: - //---------------------------------------------------------------------------- // Constructors - WeightWindows(int32_t id = -1); + WeightWindows(); WeightWindows(pugi::xml_node node); - ~WeightWindows(); - static WeightWindows* create(int32_t id = -1); - static WeightWindows* from_hdf5( - hid_t wws_group, const std::string& group_name); - //---------------------------------------------------------------------------- // Methods -private: - template - void check_bounds(const T& lower, const T& upper) const; - template - void check_bounds(const T& lower) const; - - void check_tally_update_compatibility(const Tally* tally); - -public: //! Set the weight window ID void set_id(int32_t id = -1); - void set_energy_bounds(span bounds); - - void set_mesh(const std::unique_ptr& mesh); - - void set_mesh(const Mesh* mesh); - - void set_mesh(int32_t mesh_idx); - - //! Ready the weight window class for use - void set_defaults(); - - //! Ensure the weight window lower bounds are properly allocated - void allocate_ww_bounds(); - - //! Update weight window boundaries using tally results - //! \param[in] tally Pointer to the tally whose results will be used to - //! update weight windows \param[in] value String representing the type of - //! value to use for weight window generation (one of "mean" or "rel_err") - //! \param[in] threshold Relative error threshold. Results over this - //! threshold will be ignored \param[in] ratio Ratio of upper to lower - //! weight window bounds - void update_weights(const Tally* tally, const std::string& value = "mean", - double threshold = 1.0, double ratio = 5.0, - WeightWindowUpdateMethod method = WeightWindowUpdateMethod::MAGIC); - // NOTE: This is unused for now but may be used in the future //! Write weight window settings to an HDF5 file //! \param[in] group HDF5 group to write to @@ -130,130 +90,25 @@ public: //! Retrieve the weight window for a particle //! \param[in] p Particle to get weight window for - std::pair get_weight_window(const Particle& p) const; + WeightWindow get_weight_window(const Particle& p) const; - std::array bounds_size() const; - - const vector& energy_bounds() const { return energy_bounds_; } - - void set_bounds(const tensor::Tensor& lower_ww_bounds, - const tensor::Tensor& upper_bounds); - - void set_bounds(const tensor::Tensor& lower_bounds, double ratio); - - void set_bounds( - span lower_bounds, span upper_bounds); - - void set_bounds(span lower_bounds, double ratio); - - void set_particle_type(ParticleType p_type); - - double survival_ratio() const { return survival_ratio_; } - - double& survival_ratio() { return survival_ratio_; } - - double max_lower_bound_ratio() const { return max_lb_ratio_; } - - double& max_lower_bound_ratio() { return max_lb_ratio_; } - - int max_split() const { return max_split_; } - - int& max_split() { return max_split_; } - - double weight_cutoff() const { return weight_cutoff_; } - - double& weight_cutoff() { return weight_cutoff_; } - - //---------------------------------------------------------------------------- // Accessors int32_t id() const { return id_; } - int32_t& id() { return id_; } - - int32_t index() const { return index_; } - - vector& energy_bounds() { return energy_bounds_; } - - const std::unique_ptr& mesh() const { return model::meshes[mesh_idx_]; } - - const tensor::Tensor& lower_ww_bounds() const { return lower_ww_; } - tensor::Tensor& lower_ww_bounds() { return lower_ww_; } - - const tensor::Tensor& upper_ww_bounds() const { return upper_ww_; } - tensor::Tensor& upper_ww_bounds() { return upper_ww_; } - - ParticleType particle_type() const { return particle_type_; } + const Mesh& mesh() const { return *model::meshes[mesh_idx_]; } private: - //---------------------------------------------------------------------------- // Data members - int32_t id_; //!< Unique ID - int64_t index_; //!< Index into weight windows vector - ParticleType particle_type_; //!< Particle type to apply weight windows to - vector energy_bounds_; //!< Energy boundaries [eV] - tensor::Tensor lower_ww_; //!< Lower weight window bounds (shape: - //!< energy_bins, mesh_bins (k, j, i)) - tensor::Tensor - upper_ww_; //!< Upper weight window bounds (shape: energy_bins, mesh_bins) - double survival_ratio_ {3.0}; //!< Survival weight ratio + int32_t id_; //!< Unique ID + ParticleType particle_type_; //!< Particle type to apply weight windows to + vector energy_bounds_; //!< Energy boundaries [eV] + vector lower_ww_; //!< Lower weight window bounds + vector upper_ww_; //!< Upper weight window bounds + double survival_ratio_ {3.0}; //!< Survival weight ratio double max_lb_ratio_ {1.0}; //!< Maximum lower bound to particle weight ratio double weight_cutoff_ {DEFAULT_WEIGHT_CUTOFF}; //!< Weight cutoff - int max_split_ {10}; //!< Maximum value for particle splitting - int32_t mesh_idx_ {-1}; //!< Index in meshes vector + int max_split_ {10}; //!< Maximum value for particle splitting + int32_t mesh_idx_; //!< index in meshes vector }; -class WeightWindowsGenerator { -public: - // Constructors - WeightWindowsGenerator(pugi::xml_node node); - - // Methods - void update() const; - - //! Create the tally used for weight window generation - void create_tally(); - - // Data members - int32_t tally_idx_; //!< Index of the tally used to update the weight windows - int32_t ww_idx_; //!< Index of the weight windows object being generated - WeightWindowUpdateMethod method_; //!< Method used to update weight window. - int32_t max_realizations_; //!< Maximum number of tally realizations - int32_t update_interval_; //!< Determines how often updates occur - bool on_the_fly_; //!< Whether or not to keep tally results between batches or - //!< realizations - - // MAGIC update parameters - std::string tally_value_ { - "mean"}; // targets_; -}; - -//============================================================================== -// Non-member functions -//============================================================================== - -//! Apply weight windows to a particle -//! \param[in] p Particle to apply weight windows to -void apply_weight_windows(Particle& p); - -//! Apply weight window to a particle -//! \param[in] p Particle to apply weight window to -//! \param[in] weight_window WeightWindow to apply -void apply_weight_window(Particle& p, WeightWindow weight_window); - -//! Free memory associated with weight windows -void free_memory_weight_windows(); - -//! Search weight window that apply to a particle -//! \param[in] p Particle to search weight window for -std::pair search_weight_window(const Particle& p); - -//! Finalize variance reduction objects after all inputs have been read -void finalize_variance_reduction(); - } // namespace openmc #endif // OPENMC_WEIGHT_WINDOWS_H diff --git a/include/openmc/wmp.h b/include/openmc/wmp.h index 5cc04e595..6a4abd867 100644 --- a/include/openmc/wmp.h +++ b/include/openmc/wmp.h @@ -2,7 +2,7 @@ #define OPENMC_WMP_H #include "hdf5.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include #include @@ -78,9 +78,9 @@ public: int fit_order_; //!< Order of the fit bool fissionable_; //!< Is the nuclide fissionable? vector window_info_; // Information about a window - tensor::Tensor + xt::xtensor curvefit_; // Curve fit coefficients (window, poly order, reaction) - tensor::Tensor> data_; //!< Poles and residues + xt::xtensor, 2> data_; //!< Poles and residues // Constant data static constexpr int MAX_POLY_COEFFICIENTS = diff --git a/include/openmc/xml_interface.h b/include/openmc/xml_interface.h index 17a34e5c7..d96bb6cc2 100644 --- a/include/openmc/xml_interface.h +++ b/include/openmc/xml_interface.h @@ -5,10 +5,10 @@ #include // for stringstream #include -#include "openmc/tensor.h" #include "pugixml.hpp" +#include "xtensor/xadapt.hpp" +#include "xtensor/xarray.hpp" -#include "openmc/position.h" #include "openmc/vector.h" namespace openmc { @@ -41,18 +41,13 @@ vector get_node_array( } template -tensor::Tensor get_node_tensor( +xt::xarray get_node_xarray( pugi::xml_node node, const char* name, bool lowercase = false) { vector v = get_node_array(node, name, lowercase); - return tensor::Tensor(v.data(), v.size()); + vector shape = {v.size()}; + return xt::adapt(v, shape); } -std::vector get_node_position_array( - pugi::xml_node node, const char* name, bool lowercase = false); - -Position get_node_position( - pugi::xml_node node, const char* name, bool lowercase = false); - } // namespace openmc #endif // OPENMC_XML_INTERFACE_H diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index c9dbde986..feafde68d 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -4,7 +4,7 @@ #ifndef OPENMC_XSDATA_H #define OPENMC_XSDATA_H -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/hdf5_interface.h" #include "openmc/memory.h" @@ -69,26 +69,26 @@ private: public: // The following quantities have the following dimensions: // [angle][incoming group] - tensor::Tensor total; - tensor::Tensor absorption; - tensor::Tensor nu_fission; - tensor::Tensor prompt_nu_fission; - tensor::Tensor kappa_fission; - tensor::Tensor fission; - tensor::Tensor inverse_velocity; + xt::xtensor total; + xt::xtensor absorption; + xt::xtensor nu_fission; + xt::xtensor prompt_nu_fission; + xt::xtensor kappa_fission; + xt::xtensor fission; + xt::xtensor inverse_velocity; // decay_rate has the following dimensions: // [angle][delayed group] - tensor::Tensor decay_rate; + xt::xtensor decay_rate; // delayed_nu_fission has the following dimensions: // [angle][delayed group][incoming group] - tensor::Tensor delayed_nu_fission; + xt::xtensor delayed_nu_fission; // chi_prompt has the following dimensions: // [angle][incoming group][outgoing group] - tensor::Tensor chi_prompt; + xt::xtensor chi_prompt; // chi_delayed has the following dimensions: // [angle][incoming group][outgoing group][delayed group] - tensor::Tensor chi_delayed; + xt::xtensor chi_delayed; // scatter has the following dimensions: [angle] vector> scatter; diff --git a/man/man1/openmc.1 b/man/man1/openmc.1 index 3205b4340..6310750a2 100644 --- a/man/man1/openmc.1 +++ b/man/man1/openmc.1 @@ -8,10 +8,7 @@ sections are available. .SH SYNOPSIS \fBopenmc\fR [\fIoptions\fR] [\fIpath\fR] .PP -.I path -specifies either the path to a single model XML file containing the full model -or a directory containing either a model.xml file or a set of individual XML -files (settings.xml, materials.xml, geometry.xml). It is assumed that if no +It is assumed that if no .I path is specified, the XML input files are present in the current directory. .SH OPTIONS @@ -39,9 +36,6 @@ Use \fIN\fP OpenMP threads. .B "\-t\fR, \fP\-\-track" Write tracks for all particles (up to max_tracks). .TP -.BI \-q " V" "\fR,\fP \-\-verbosity" " V" -Set the output verbosity to \fIV\fP. -.TP .B "\-v\fR, \fP\-\-version" Show version information. .TP @@ -52,9 +46,6 @@ The behavior of .B openmc is affected by the following environment variables. .TP -.B OPENMC_CHAIN_FILE -Indicates the path to a depletion chain XML file. -.TP .B OPENMC_CROSS_SECTIONS Indicates the default path to the cross_sections.xml summary file that is used to locate HDF5 format cross section libraries if the user has not specified the @@ -66,7 +57,7 @@ Indicates the default path to an HDF5 file that contains multi-group cross section libraries if the user has not specified the tag in .I materials.xml\fP. .SH LICENSE -Copyright \(co 2011-2026 Massachusetts Institute of Technology, UChicago +Copyright \(co 2011-2022 Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors. .PP Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/openmc/__init__.py b/openmc/__init__.py index c204929c8..7ed9009a2 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -1,6 +1,4 @@ -import importlib.metadata from openmc.arithmetic import * -from openmc.bounding_box import * from openmc.cell import * from openmc.checkvalue import * from openmc.mesh import * @@ -12,12 +10,11 @@ from openmc.material import * from openmc.plots import * from openmc.region import * from openmc.volume import * +from openmc.source import * from openmc.weight_windows import * +from openmc.settings import * from openmc.surface import * from openmc.universe import * -from openmc.dagmc import * -from openmc.source import * -from openmc.settings import * from openmc.lattice import * from openmc.filter import * from openmc.filter_expansion import * @@ -34,12 +31,10 @@ from openmc.plotter import * from openmc.search import * from openmc.polynomial import * from openmc.tracks import * -from .config import * - -# Import a few names from the model module -from openmc.model import Model, SearchResult - from . import examples +# Import a few names from the model module +from openmc.model import rectangular_prism, hexagonal_prism, Model -__version__ = importlib.metadata.version("openmc") + +__version__ = '0.13.1' diff --git a/openmc/_sparse_compat.py b/openmc/_sparse_compat.py deleted file mode 100644 index c00777e19..000000000 --- a/openmc/_sparse_compat.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Compatibility module for scipy.sparse arrays - -This module provides a compatibility layer for working with scipy.sparse arrays -across different scipy versions. Sparse arrays were introduced gradually in -scipy, with full support arriving in scipy 1.15. This module provides a unified -API that uses sparse arrays when available and falls back to sparse matrices for -older scipy versions. - -For more information on the migration from sparse matrices to sparse arrays, -see: https://docs.scipy.org/doc/scipy/reference/sparse.migration_to_sparray.html -""" - -import scipy -from scipy import sparse as sp - -# Check scipy version for feature availability -_SCIPY_VERSION = tuple(map(int, scipy.__version__.split('.')[:2])) - -if _SCIPY_VERSION >= (1, 15): - # Use sparse arrays - csr_array = sp.csr_array - csc_array = sp.csc_array - dok_array = sp.dok_array - lil_array = sp.lil_array - eye_array = sp.eye_array - block_array = sp.block_array -else: - # Fall back to sparse matrices - csr_array = sp.csr_matrix - csc_array = sp.csc_matrix - dok_array = sp.dok_matrix - lil_array = sp.lil_matrix - eye_array = sp.eye - block_array = sp.bmat - -__all__ = [ - 'csr_array', - 'csc_array', - 'dok_array', - 'lil_array', - 'eye_array', - 'block_array', -] diff --git a/openmc/_xml.py b/openmc/_xml.py index 758d80525..32679fd89 100644 --- a/openmc/_xml.py +++ b/openmc/_xml.py @@ -1,40 +1,22 @@ -def clean_indentation(element, level=0, spaces_per_level=2, trailing_indent=True): - """Set indentation of XML element and its sub-elements. - Copied and pasted from https://effbot.org/zone/element-lib.htm#prettyprint. - It walks your tree and adds spaces and newlines so the tree is - printed in a nice way. - - Parameters - ---------- - level : int - Indentation level for the element passed in (default 0) - spaces_per_level : int - Number of spaces per indentation level (default 2) - trailing_indent : bool - Whether or not to add indentation after closing the element - +def clean_indentation(element, level=0, spaces_per_level=2): + """ + copy and paste from https://effbot.org/zone/element-lib.htm#prettyprint + it basically walks your tree and adds spaces and newlines so the tree is + printed in a nice way """ i = "\n" + level*spaces_per_level*" " - # ensure there's always some tail for the element passed in - if not element.tail: - element.tail = "" - if len(element): if not element.text or not element.text.strip(): element.text = i + spaces_per_level*" " - if trailing_indent and (not element.tail or not element.tail.strip()): + if not element.tail or not element.tail.strip(): element.tail = i for sub_element in element: - # `trailing_indent` is intentionally not forwarded to the recursive - # call. Any child element of the topmost element should add - # indentation at the end to ensure its parent's indentation is - # correct. clean_indentation(sub_element, level+1, spaces_per_level) if not sub_element.tail or not sub_element.tail.strip(): sub_element.tail = i else: - if trailing_indent and level and (not element.tail or not element.tail.strip()): + if level and (not element.tail or not element.tail.strip()): element.tail = i @@ -43,7 +25,7 @@ def get_text(elem, name, default=None): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element Element from which to search name : str Name of attribute/subelement @@ -63,24 +45,19 @@ def get_text(elem, name, default=None): return child.text if child is not None else default - -def get_elem_list(elem, name, dtype=int): - """Helper function to get a list of values from an elem +def reorder_attributes(root): + """Sort attributes in XML to preserve pre-Python 3.8 behavior Parameters ---------- - elem : lxml.etree._Element - XML element that should contain a tuple - name : str - Name of the subelement to obtain tuple from - dtype : data-type - The type of each element in the tuple + root : xml.etree.ElementTree.Element + Root element - Returns - ------- - list of dtype - Data read from the list """ - text = get_text(elem, name) - if text is not None: - return [dtype(x) for x in text.split()] + for el in root.iter(): + attrib = el.attrib + if len(attrib) > 1: + # adjust attribute order, e.g. by sorting + attribs = sorted(attrib.items()) + attrib.clear() + attrib.update(attribs) diff --git a/openmc/arithmetic.py b/openmc/arithmetic.py index 92c42284c..618c7c4a1 100644 --- a/openmc/arithmetic.py +++ b/openmc/arithmetic.py @@ -10,10 +10,10 @@ from .filter import _FILTER_TYPES # Acceptable tally arithmetic binary operations -_TALLY_ARITHMETIC_OPS = {'+', '-', '*', '/', '^'} +_TALLY_ARITHMETIC_OPS = ['+', '-', '*', '/', '^'] # Acceptable tally aggregation operations -_TALLY_AGGREGATE_OPS = {'sum', 'avg'} +_TALLY_AGGREGATE_OPS = ['sum', 'avg'] class CrossScore: @@ -54,32 +54,33 @@ class CrossScore: return str(other) == str(self) def __repr__(self): - return f'({self.left_score} {self.binary_op} {self.right_score})' + return '({} {} {})'.format(self.left_score, self.binary_op, + self.right_score) @property def left_score(self): return self._left_score + @property + def right_score(self): + return self._right_score + + @property + def binary_op(self): + return self._binary_op + @left_score.setter def left_score(self, left_score): cv.check_type('left_score', left_score, (str, CrossScore, AggregateScore)) self._left_score = left_score - @property - def right_score(self): - return self._right_score - @right_score.setter def right_score(self, right_score): cv.check_type('right_score', right_score, (str, CrossScore, AggregateScore)) self._right_score = right_score - @property - def binary_op(self): - return self._binary_op - @binary_op.setter def binary_op(self, binary_op): cv.check_type('binary_op', binary_op, str) @@ -93,9 +94,9 @@ class CrossNuclide: Parameters ---------- - left_nuclide : str or CrossNuclide + left_nuclide : openmc.Nuclide or CrossNuclide The left nuclide in the outer product - right_nuclide : str or CrossNuclide + right_nuclide : openmc.Nuclide or CrossNuclide The right nuclide in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -103,9 +104,9 @@ class CrossNuclide: Attributes ---------- - left_nuclide : str or CrossNuclide + left_nuclide : openmc.Nuclide or CrossNuclide The left nuclide in the outer product - right_nuclide : str or CrossNuclide + right_nuclide : openmc.Nuclide or CrossNuclide The right nuclide in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -131,36 +132,55 @@ class CrossNuclide: def left_nuclide(self): return self._left_nuclide - @left_nuclide.setter - def left_nuclide(self, left_nuclide): - cv.check_type('left_nuclide', left_nuclide, - (str, CrossNuclide, AggregateNuclide)) - self._left_nuclide = left_nuclide - @property def right_nuclide(self): return self._right_nuclide - @right_nuclide.setter - def right_nuclide(self, right_nuclide): - cv.check_type('right_nuclide', right_nuclide, - (str, CrossNuclide, AggregateNuclide)) - self._right_nuclide = right_nuclide - @property def binary_op(self): return self._binary_op + @property + def name(self): + + string = '' + + # If the Summary was linked, the left nuclide is a Nuclide object + if isinstance(self.left_nuclide, openmc.Nuclide): + string += '(' + self.left_nuclide.name + # If the Summary was not linked, the left nuclide is the ZAID + else: + string += '(' + str(self.left_nuclide) + + string += ' ' + self.binary_op + ' ' + + # If the Summary was linked, the right nuclide is a Nuclide object + if isinstance(self.right_nuclide, openmc.Nuclide): + string += self.right_nuclide.name + ')' + # If the Summary was not linked, the right nuclide is the ZAID + else: + string += str(self.right_nuclide) + ')' + + return string + + @left_nuclide.setter + def left_nuclide(self, left_nuclide): + cv.check_type('left_nuclide', left_nuclide, + (openmc.Nuclide, CrossNuclide, AggregateNuclide)) + self._left_nuclide = left_nuclide + + @right_nuclide.setter + def right_nuclide(self, right_nuclide): + cv.check_type('right_nuclide', right_nuclide, + (openmc.Nuclide, CrossNuclide, AggregateNuclide)) + self._right_nuclide = right_nuclide + @binary_op.setter def binary_op(self, binary_op): cv.check_type('binary_op', binary_op, str) cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) self._binary_op = binary_op - @property - def name(self): - return f'({self.left_nuclide} {self.binary_op} {self.right_nuclide})' - class CrossFilter: """A special-purpose filter used to encapsulate all combinations of two @@ -168,9 +188,9 @@ class CrossFilter: Parameters ---------- - left_filter : openmc.Filter or CrossFilter + left_filter : Filter or CrossFilter The left filter in the outer product - right_filter : openmc.Filter or CrossFilter + right_filter : Filter or CrossFilter The right filter in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -180,9 +200,9 @@ class CrossFilter: ---------- type : str The type of the crossfilter (e.g., 'energy / energy') - left_filter : openmc.Filter or CrossFilter + left_filter : Filter or CrossFilter The left filter in the outer product - right_filter : openmc.Filter or CrossFilter + right_filter : Filter or CrossFilter The right filter in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -221,37 +241,19 @@ class CrossFilter: def left_filter(self): return self._left_filter - @left_filter.setter - def left_filter(self, left_filter): - cv.check_type('left_filter', left_filter, - (openmc.Filter, CrossFilter, AggregateFilter)) - self._left_filter = left_filter - @property def right_filter(self): return self._right_filter - @right_filter.setter - def right_filter(self, right_filter): - cv.check_type('right_filter', right_filter, - (openmc.Filter, CrossFilter, AggregateFilter)) - self._right_filter = right_filter - @property def binary_op(self): return self._binary_op - @binary_op.setter - def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, str) - cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) - self._binary_op = binary_op - @property def type(self): left_type = self.left_filter.type right_type = self.right_filter.type - return f'({left_type} {self.binary_op} {right_type})' + return '({} {} {})'.format(left_type, self.binary_op, right_type) @property def bins(self): @@ -264,6 +266,24 @@ class CrossFilter: else: return 0 + @left_filter.setter + def left_filter(self, left_filter): + cv.check_type('left_filter', left_filter, + (openmc.Filter, CrossFilter, AggregateFilter)) + self._left_filter = left_filter + + @right_filter.setter + def right_filter(self, right_filter): + cv.check_type('right_filter', right_filter, + (openmc.Filter, CrossFilter, AggregateFilter)) + self._right_filter = right_filter + + @binary_op.setter + def binary_op(self, binary_op): + cv.check_type('binary_op', binary_op, str) + cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) + self._binary_op = binary_op + def get_bin_index(self, filter_bin): """Returns the index in the CrossFilter for some bin. @@ -392,21 +412,10 @@ class AggregateScore: def scores(self): return self._scores - @scores.setter - def scores(self, scores): - cv.check_iterable_type('scores', scores, str) - self._scores = scores - @property def aggregate_op(self): return self._aggregate_op - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, (str, CrossScore)) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - @property def name(self): @@ -414,6 +423,17 @@ class AggregateScore: string = '(' + ', '.join(self.scores) + ')' return string + @scores.setter + def scores(self, scores): + cv.check_iterable_type('scores', scores, str) + self._scores = scores + + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, (str, CrossScore)) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + class AggregateNuclide: """A special-purpose tally nuclide used to encapsulate an aggregate of a @@ -421,7 +441,7 @@ class AggregateNuclide: Parameters ---------- - nuclides : Iterable of str or CrossNuclide + nuclides : Iterable of str or openmc.Nuclide or CrossNuclide The nuclides included in the aggregation aggregate_op : str The tally aggregation operator (e.g., 'sum', 'avg', etc.) used @@ -429,7 +449,7 @@ class AggregateNuclide: Attributes ---------- - nuclides : Iterable of str or CrossNuclide + nuclides : Iterable of str or openmc.Nuclide or CrossNuclide The nuclides included in the aggregation aggregate_op : str The tally aggregation operator (e.g., 'sum', 'avg', etc.) used @@ -454,33 +474,42 @@ class AggregateNuclide: return str(other) == str(self) def __repr__(self): - return f'{self.aggregate_op}{self.name}' + + # Append each nuclide in the aggregate to the string + string = f'{self.aggregate_op}(' + names = [nuclide.name if isinstance(nuclide, openmc.Nuclide) + else str(nuclide) for nuclide in self.nuclides] + string += ', '.join(map(str, names)) + ')' + return string @property def nuclides(self): return self._nuclides + @property + def aggregate_op(self): + return self._aggregate_op + + @property + def name(self): + + # Append each nuclide in the aggregate to the string + names = [nuclide.name if isinstance(nuclide, openmc.Nuclide) + else str(nuclide) for nuclide in self.nuclides] + string = '(' + ', '.join(map(str, names)) + ')' + return string + @nuclides.setter def nuclides(self, nuclides): cv.check_iterable_type('nuclides', nuclides, (str, CrossNuclide)) self._nuclides = nuclides - @property - def aggregate_op(self): - return self._aggregate_op - @aggregate_op.setter def aggregate_op(self, aggregate_op): cv.check_type('aggregate_op', aggregate_op, str) cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) self._aggregate_op = aggregate_op - @property - def name(self): - # Append each nuclide in the aggregate to the string - names = [str(nuclide) for nuclide in self.nuclides] - return '(' + ', '.join(map(str, names)) + ')' - class AggregateFilter: """A special-purpose tally filter used to encapsulate an aggregate of a @@ -488,7 +517,7 @@ class AggregateFilter: Parameters ---------- - aggregate_filter : openmc.Filter or CrossFilter + aggregate_filter : Filter or CrossFilter The filter included in the aggregation bins : Iterable of tuple The filter bins included in the aggregation @@ -500,7 +529,7 @@ class AggregateFilter: ---------- type : str The type of the aggregatefilter (e.g., 'sum(energy)', 'sum(cell)') - aggregate_filter : openmc.Filter + aggregate_filter : filter The filter included in the aggregation aggregate_op : str The tally aggregation operator (e.g., 'sum', 'avg', etc.) used @@ -559,26 +588,22 @@ class AggregateFilter: def aggregate_filter(self): return self._aggregate_filter - @aggregate_filter.setter - def aggregate_filter(self, aggregate_filter): - cv.check_type('aggregate_filter', aggregate_filter, - (openmc.Filter, CrossFilter)) - self._aggregate_filter = aggregate_filter - @property def aggregate_op(self): return self._aggregate_op - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, str) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - @property def type(self): return self._type + @property + def bins(self): + return self._bins + + @property + def num_bins(self): + return len(self.bins) if self.aggregate_filter else 0 + @type.setter def type(self, filter_type): if filter_type not in _FILTER_TYPES: @@ -588,22 +613,22 @@ class AggregateFilter: self._type = filter_type - @property - def bins(self): - return self._bins + @aggregate_filter.setter + def aggregate_filter(self, aggregate_filter): + cv.check_type('aggregate_filter', aggregate_filter, + (openmc.Filter, CrossFilter)) + self._aggregate_filter = aggregate_filter @bins.setter def bins(self, bins): cv.check_iterable_type('bins', bins, Iterable) self._bins = list(map(tuple, bins)) - @property - def num_bins(self): - return len(self.bins) if self.aggregate_filter else 0 - - @property - def shape(self): - return (self.num_bins,) + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, str) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op def get_bin_index(self, filter_bin): """Returns the index in the AggregateFilter for some bin. diff --git a/openmc/bounding_box.py b/openmc/bounding_box.py deleted file mode 100644 index f0dc06a4a..000000000 --- a/openmc/bounding_box.py +++ /dev/null @@ -1,202 +0,0 @@ -from __future__ import annotations -from collections.abc import Iterable - -import numpy as np - -from .checkvalue import check_length - - -class BoundingBox: - """Axis-aligned bounding box. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - lower_left : iterable of float - The x, y, z coordinates of the lower left corner of the bounding box in [cm] - upper_right : iterable of float - The x, y, z coordinates of the upper right corner of the bounding box in [cm] - - Attributes - ---------- - center : numpy.ndarray - x, y, z coordinates of the center of the bounding box in [cm] - lower_left : numpy.ndarray - The x, y, z coordinates of the lower left corner of the bounding box in [cm] - upper_right : numpy.ndarray - The x, y, z coordinates of the upper right corner of the bounding box in [cm] - volume : float - The volume of the bounding box in [cm^3] - extent : dict - A dictionary of basis as keys and the extent (left, right, bottom, top) - as values. Intended use in Matplotlib plots when setting extent - width : iterable of float - The width of the x, y and z axis in [cm] - """ - - def __init__(self, lower_left: Iterable[float], upper_right: Iterable[float]): - check_length("lower_left", lower_left, 3, 3) - check_length("upper_right", upper_right, 3, 3) - self._bounds = np.asarray([lower_left, upper_right], dtype=float) - - def __repr__(self) -> str: - return "BoundingBox(lower_left={}, upper_right={})".format( - tuple(float(x) for x in self.lower_left), - tuple(float(x) for x in self.upper_right)) - - def __getitem__(self, key) -> np.ndarray: - return self._bounds[key] - - def __len__(self): - return 2 - - def __setitem__(self, key, val): - self._bounds[key] = val - - def __iand__(self, other: BoundingBox) -> BoundingBox: - """Updates the box be the intersection of itself and another box - - Parameters - ---------- - other : BoundingBox - The box used to resize this box - - Returns - ------- - An updated bounding box - """ - self.lower_left = np.maximum(self.lower_left, other.lower_left) - self.upper_right = np.minimum(self.upper_right, other.upper_right) - return self - - def __and__(self, other: BoundingBox) -> BoundingBox: - new = BoundingBox(*self) - new &= other - return new - - def __ior__(self, other: BoundingBox) -> BoundingBox: - """Updates the box be the union of itself and another box - - Parameters - ---------- - other : BoundingBox - The box used to resize this box - - Returns - ------- - An updated bounding box - """ - self.lower_left = np.minimum(self.lower_left, other.lower_left) - self.upper_right = np.maximum(self.upper_right, other.upper_right) - return self - - def __or__(self, other: BoundingBox) -> BoundingBox: - new = BoundingBox(*self) - new |= other - return new - - def __contains__(self, other): - """Check whether or not a point or another bounding box is in the bounding box. - - For another bounding box to be in the parent it must lie fully inside of it. - """ - # test for a single point - if isinstance(other, (tuple, list, np.ndarray)): - point = other - check_length("Point", point, 3, 3) - return all(point > self.lower_left) and all(point < self.upper_right) - elif isinstance(other, BoundingBox): - return all([p in self for p in [other.lower_left, other.upper_right]]) - else: - raise TypeError( - f"Unable to determine if {other} is in the bounding box." - f" Expected a tuple or a bounding box, but {type(other)} given" - ) - - @property - def center(self) -> np.ndarray: - return (self[0] + self[1]) / 2 - - @property - def lower_left(self) -> np.ndarray: - return self[0] - - @lower_left.setter - def lower_left(self, llc): - check_length('lower_left', llc, 3, 3) - self[0] = llc - - @property - def upper_right(self) -> np.ndarray: - return self[1] - - @upper_right.setter - def upper_right(self, urc): - check_length('upper_right', urc, 3, 3) - self[1] = urc - - @property - def volume(self) -> float: - return np.abs(np.prod(self[1] - self[0])) - - @property - def extent(self): - return { - "xy": ( - self.lower_left[0], - self.upper_right[0], - self.lower_left[1], - self.upper_right[1], - ), - "xz": ( - self.lower_left[0], - self.upper_right[0], - self.lower_left[2], - self.upper_right[2], - ), - "yz": ( - self.lower_left[1], - self.upper_right[1], - self.lower_left[2], - self.upper_right[2], - ), - } - - @property - def width(self): - return self.upper_right - self.lower_left - - def expand(self, padding_distance: float, inplace: bool = False) -> BoundingBox: - """Returns an expanded bounding box - - Parameters - ---------- - padding_distance : float - The distance to enlarge the bounding box by - inplace : bool - Whether or not to return a new BoundingBox instance or to modify the - current BoundingBox object. - - Returns - ------- - An expanded bounding box - """ - if inplace: - self[0] -= padding_distance - self[1] += padding_distance - return self - else: - return BoundingBox(self[0] - padding_distance, self[1] + padding_distance) - - @classmethod - def infinite(cls) -> BoundingBox: - """Create an infinite box. Useful as a starting point for determining - geometry bounds. - - Returns - ------- - An infinitely large bounding box. - """ - infs = np.full((3,), np.inf) - return cls(-infs, infs) diff --git a/openmc/cell.py b/openmc/cell.py index 499cf9504..4b419e1c6 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -1,19 +1,19 @@ +from collections import OrderedDict from collections.abc import Iterable +from copy import deepcopy from math import cos, sin, pi from numbers import Real +from xml.etree import ElementTree as ET -import lxml.etree as ET import numpy as np from uncertainties import UFloat import openmc import openmc.checkvalue as cv -from ._xml import get_elem_list, get_text +from ._xml import get_text from .mixin import IDManagerMixin -from .plots import add_plot_params from .region import Region, Complement from .surface import Halfspace -from .bounding_box import BoundingBox class Cell(IDManagerMixin): @@ -72,10 +72,6 @@ class Cell(IDManagerMixin): temperature : float or iterable of float Temperature of the cell in Kelvin. Multiple temperatures can be given to give each distributed cell instance a unique temperature. - density : float or iterable of float - Density of the cell in [g/cm3]. Multiple densities can be given to give - each distributed cell instance a unique density. Densities set here will - override the density set on materials used to fill the cell. translation : Iterable of float If the cell is filled with a universe, this array specifies a vector that is used to translate (shift) the universe. @@ -90,14 +86,12 @@ class Cell(IDManagerMixin): calculated in a stochastic volume calculation and added via the :meth:`Cell.add_volume_information` method. For 'distribmat' cells it is the total volume of all instances. - atoms : dict + atoms : collections.OrderedDict Mapping of nuclides to the total number of atoms for each nuclide present in the cell, or in all of its instances for a 'distribmat' fill. For example, {'U235': 1.0e22, 'U238': 5.0e22, ...}. .. versionadded:: 0.12 - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the cell """ @@ -113,7 +107,6 @@ class Cell(IDManagerMixin): self._rotation = None self._rotation_matrix = None self._temperature = None - self._density = None self._translation = None self._paths = None self._num_instances = None @@ -146,7 +139,6 @@ class Cell(IDManagerMixin): if self.fill_type == 'material': string += '\t{0: <15}=\t{1}\n'.format('Temperature', self.temperature) - string += '\t{0: <15}=\t{1}\n'.format('Density', self.density) string += '{: <16}=\t{}\n'.format('\tTranslation', self.translation) string += '{: <16}=\t{}\n'.format('\tVolume', self.volume) @@ -156,37 +148,10 @@ class Cell(IDManagerMixin): def name(self): return self._name - @name.setter - def name(self, name): - if name is not None: - cv.check_type('cell name', name, str) - self._name = name - else: - self._name = '' - @property def fill(self): return self._fill - @fill.setter - def fill(self, fill): - if fill is not None: - if isinstance(fill, Iterable): - for i, f in enumerate(fill): - if f is not None: - cv.check_type('cell.fill[i]', f, openmc.Material) - - elif not isinstance(fill, (openmc.Material, openmc.Lattice, - openmc.UniverseBase)): - msg = (f'Unable to set Cell ID="{self._id}" to use a ' - f'non-Material or Universe fill "{fill}"') - raise ValueError(msg) - self._fill = fill - - # Info about atom content can now be invalid - # (since fill has just changed) - self._atoms = None - @property def fill_type(self): if isinstance(self.fill, openmc.Material): @@ -204,37 +169,10 @@ class Cell(IDManagerMixin): def region(self): return self._region - @region.setter - def region(self, region): - if region is not None: - cv.check_type('cell region', region, Region) - self._region = region - @property def rotation(self): return self._rotation - @rotation.setter - def rotation(self, rotation): - cv.check_length('cell rotation', rotation, 3) - self._rotation = np.asarray(rotation) - - # Save rotation matrix -- the reason we do this instead of having it be - # automatically calculated when the rotation_matrix property is accessed - # is so that plotting on a rotated geometry can be done faster. - if self._rotation.ndim == 2: - # User specified rotation matrix directly - self._rotation_matrix = self._rotation - else: - phi, theta, psi = self.rotation*(-pi/180.) - c3, s3 = cos(phi), sin(phi) - c2, s2 = cos(theta), sin(theta) - c1, s1 = cos(psi), sin(psi) - self._rotation_matrix = np.array([ - [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], - [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], - [-s2, c2*s3, c2*c3]]) - @property def rotation_matrix(self): return self._rotation_matrix @@ -243,76 +181,14 @@ class Cell(IDManagerMixin): def temperature(self): return self._temperature - @temperature.setter - def temperature(self, temperature): - # Make sure temperatures are positive - cv.check_type('cell temperature', temperature, (Iterable, Real), none_ok=True) - if isinstance(temperature, Iterable): - cv.check_type('cell temperature', temperature, Iterable, Real) - for T in temperature: - cv.check_greater_than('cell temperature', T, 0.0, True) - elif isinstance(temperature, Real): - cv.check_greater_than('cell temperature', temperature, 0.0, True) - - # If this cell is filled with a universe or lattice, propagate - # temperatures to all cells contained. Otherwise, simply assign it. - if self.fill_type in ('universe', 'lattice'): - for c in self.get_all_cells().values(): - if c.fill_type == 'material': - c._temperature = temperature - else: - self._temperature = temperature - - @property - def density(self): - return self._density - - @density.setter - def density(self, density): - # Make sure densities are greater than zero - cv.check_type('cell density', density, (Iterable, Real), none_ok=True) - if isinstance(density, Iterable): - cv.check_type('cell density', density, Iterable, Real) - for rho in density: - cv.check_greater_than('cell density', rho, 0.0, True) - elif isinstance(density, Real): - cv.check_greater_than('cell density', density, 0.0, True) - - # If this cell is filled with a universe or lattice, propagate - # densities to all cells contained. Otherwise, simply assign it. - if self.fill_type in ('universe', 'lattice'): - for c in self.get_all_cells().values(): - if c.fill_type == 'material': - c._density = density - else: - self._density = density - @property def translation(self): return self._translation - @translation.setter - def translation(self, translation): - cv.check_type('cell translation', translation, Iterable, Real) - cv.check_length('cell translation', translation, 3) - self._translation = np.asarray(translation) - @property def volume(self): return self._volume - @volume.setter - def volume(self, volume): - if volume is not None: - cv.check_type('cell volume', volume, (Real, UFloat)) - cv.check_greater_than('cell volume', volume, 0.0, equality=True) - - self._volume = volume - - # Info about atom content can now be invalid - # (since volume has just changed) - self._atoms = None - @property def atoms(self): if self._atoms is None: @@ -346,7 +222,7 @@ class Cell(IDManagerMixin): # Assumes that volume is total volume of all instances # Also assumes that all instances have the same volume partial_volume = self.volume / len(self.fill) - self._atoms = {} + self._atoms = OrderedDict() for mat in self.fill: for key, atom_per_bcm in mat.get_nuclide_atom_densities().items(): # To account for overlap of nuclides between distribmat @@ -374,7 +250,8 @@ class Cell(IDManagerMixin): if self.region is not None: return self.region.bounding_box else: - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) @property def num_instances(self): @@ -384,6 +261,98 @@ class Cell(IDManagerMixin): 'Geometry.determine_paths() method.') return self._num_instances + @name.setter + def name(self, name): + if name is not None: + cv.check_type('cell name', name, str) + self._name = name + else: + self._name = '' + + @fill.setter + def fill(self, fill): + if fill is not None: + if isinstance(fill, Iterable): + for i, f in enumerate(fill): + if f is not None: + cv.check_type('cell.fill[i]', f, openmc.Material) + + elif not isinstance(fill, (openmc.Material, openmc.Lattice, + openmc.UniverseBase)): + msg = (f'Unable to set Cell ID="{self._id}" to use a ' + f'non-Material or Universe fill "{fill}"') + raise ValueError(msg) + self._fill = fill + + # Info about atom content can now be invalid + # (since fill has just changed) + self._atoms = None + + @rotation.setter + def rotation(self, rotation): + cv.check_length('cell rotation', rotation, 3) + self._rotation = np.asarray(rotation) + + # Save rotation matrix -- the reason we do this instead of having it be + # automatically calculated when the rotation_matrix property is accessed + # is so that plotting on a rotated geometry can be done faster. + if self._rotation.ndim == 2: + # User specified rotation matrix directly + self._rotation_matrix = self._rotation + else: + phi, theta, psi = self.rotation*(-pi/180.) + c3, s3 = cos(phi), sin(phi) + c2, s2 = cos(theta), sin(theta) + c1, s1 = cos(psi), sin(psi) + self._rotation_matrix = np.array([ + [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], + [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], + [-s2, c2*s3, c2*c3]]) + + @translation.setter + def translation(self, translation): + cv.check_type('cell translation', translation, Iterable, Real) + cv.check_length('cell translation', translation, 3) + self._translation = np.asarray(translation) + + @temperature.setter + def temperature(self, temperature): + # Make sure temperatures are positive + cv.check_type('cell temperature', temperature, (Iterable, Real)) + if isinstance(temperature, Iterable): + cv.check_type('cell temperature', temperature, Iterable, Real) + for T in temperature: + cv.check_greater_than('cell temperature', T, 0.0, True) + else: + cv.check_greater_than('cell temperature', temperature, 0.0, True) + + # If this cell is filled with a universe or lattice, propagate + # temperatures to all cells contained. Otherwise, simply assign it. + if self.fill_type in ('universe', 'lattice'): + for c in self.get_all_cells().values(): + if c.fill_type == 'material': + c._temperature = temperature + else: + self._temperature = temperature + + @region.setter + def region(self, region): + if region is not None: + cv.check_type('cell region', region, Region) + self._region = region + + @volume.setter + def volume(self, volume): + if volume is not None: + cv.check_type('cell volume', volume, (Real, UFloat)) + cv.check_greater_than('cell volume', volume, 0.0, equality=True) + + self._volume = volume + + # Info about atom content can now be invalid + # (since volume has just changed) + self._atoms = None + def add_volume_information(self, volume_calc): """Add volume information to a cell. @@ -418,13 +387,13 @@ class Cell(IDManagerMixin): Returns ------- - nuclides : dict + nuclides : collections.OrderedDict Dictionary whose keys are nuclide names and values are 2-tuples of (nuclide, density) """ - nuclides = {} + nuclides = OrderedDict() if self.fill_type == 'material': nuclides.update(self.fill.get_nuclide_densities()) @@ -434,8 +403,9 @@ class Cell(IDManagerMixin): if self._atoms is not None: volume = self.volume for name, atoms in self._atoms.items(): + nuclide = openmc.Nuclide(name) density = 1.0e-24 * atoms.n/volume # density in atoms/b-cm - nuclides[name] = (name, density) + nuclides[name] = (nuclide, density) else: raise RuntimeError( 'Volume information is needed to calculate microscopic ' @@ -451,18 +421,20 @@ class Cell(IDManagerMixin): Returns ------- - cells : dict + cells : collections.orderedDict Dictionary whose keys are cell IDs and values are :class:`Cell` instances """ - if memo is None: - memo = set() - elif self in memo: - return {} - memo.add(self) - cells = {} + cells = OrderedDict() + + if memo and self in memo: + return cells + + if memo is not None: + memo.add(self) + if self.fill_type in ('universe', 'lattice'): cells.update(self.fill.get_all_cells(memo)) @@ -473,12 +445,12 @@ class Cell(IDManagerMixin): Returns ------- - materials : dict + materials : collections.OrderedDict Dictionary whose keys are material IDs and values are :class:`Material` instances """ - materials = {} + materials = OrderedDict() if self.fill_type == 'material': materials[self.fill.id] = self.fill elif self.fill_type == 'distribmat': @@ -493,33 +465,29 @@ class Cell(IDManagerMixin): return materials - def get_all_universes(self, memo=None): + def get_all_universes(self): """Return all universes that are contained within this one if any of its cells are filled with a universe or lattice. Returns ------- - universes : dict + universes : collections.OrderedDict Dictionary whose keys are universe IDs and values are :class:`Universe` instances """ - if memo is None: - memo = set() - if self in memo: - return {} - memo.add(self) - universes = {} + universes = OrderedDict() + if self.fill_type == 'universe': universes[self.fill.id] = self.fill - universes.update(self.fill.get_all_universes(memo)) + universes.update(self.fill.get_all_universes()) elif self.fill_type == 'lattice': - universes.update(self.fill.get_all_universes(memo)) + universes.update(self.fill.get_all_universes()) return universes - def clone(self, clone_materials=True, clone_regions=True, memo=None): + def clone(self, clone_materials=True, clone_regions=True, memo=None): """Create a copy of this cell with a new unique ID, and clones the cell's region and fill. @@ -551,16 +519,8 @@ class Cell(IDManagerMixin): paths = self._paths self._paths = None - clone = openmc.Cell(name=self.name) - clone.volume = self.volume - if self.temperature is not None: - clone.temperature = self.temperature - if self.density is not None: - clone.density = self.density - if self.translation is not None: - clone.translation = self.translation - if self.rotation is not None: - clone.rotation = self.rotation + clone = deepcopy(self) + clone.id = None clone._num_instances = None # Restore paths on original instance @@ -592,25 +552,12 @@ class Cell(IDManagerMixin): return memo[self] - @add_plot_params - def plot(self, *args, **kwargs): - """Display a slice plot of the cell. - - .. versionadded:: 0.14.0 - """ - # Create dummy universe but preserve used_ids - next_id = openmc.UniverseBase.next_id - u = openmc.Universe(cells=[self]) - openmc.UniverseBase.used_ids.remove(u.id) - openmc.UniverseBase.next_id = next_id - return u.plot(*args, **kwargs) - def create_xml_subelement(self, xml_element, memo=None): """Add the cell's xml representation to an incoming xml element Parameters ---------- - xml_element : lxml.etree._Element + xml_element : xml.etree.ElementTree.Element XML element to be added to memo : set or None @@ -636,11 +583,8 @@ class Cell(IDManagerMixin): element.set("material", str(self.fill.id)) elif self.fill_type == 'distribmat': - material_subelement= ET.SubElement(element, "material") - matlist_str = " ".join( - ["void" if m is None else str(m.id) for m in self.fill] - ) - material_subelement.text = matlist_str + element.set("material", ' '.join(['void' if m is None else str(m.id) + for m in self.fill])) elif self.fill_type in ('universe', 'lattice'): element.set("fill", str(self.fill.id)) @@ -662,11 +606,10 @@ class Cell(IDManagerMixin): # thus far. def create_surface_elements(node, element, memo=None): if isinstance(node, Halfspace): - if memo is None: - memo = set() - elif node.surface in memo: + if memo and node.surface in memo: return - memo.add(node.surface) + if memo is not None: + memo.add(node.surface) xml_element.append(node.surface.to_xml_element()) elif isinstance(node, Complement): @@ -680,27 +623,17 @@ class Cell(IDManagerMixin): if self.temperature is not None: if isinstance(self.temperature, Iterable): - temperature_subelement= ET.SubElement(element, "temperature") - temperature_subelement.text = ' '.join(str(t) for t in self.temperature) + element.set("temperature", ' '.join( + str(t) for t in self.temperature)) else: element.set("temperature", str(self.temperature)) - if self.density is not None: - if isinstance(self.density, Iterable): - density_subelement= ET.SubElement(element, "density") - density_subelement.text = ' '.join(str(d) for d in self.density) - else: - element.set("density", str(self.density)) - if self.translation is not None: element.set("translation", ' '.join(map(str, self.translation))) if self.rotation is not None: element.set("rotation", ' '.join(map(str, self.rotation.ravel()))) - if self.volume is not None: - element.set("volume", str(self.volume)) - return element @classmethod @@ -709,13 +642,13 @@ class Cell(IDManagerMixin): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element `` element surfaces : dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances materials : dict - Dictionary mapping material ID strings to :class:`openmc.Material` - instances (defined in :meth:`openmc.Geometry.from_xml`) + Dictionary mapping material IDs to :class:`openmc.Material` + instances (defined in :math:`openmc.Geometry.from_xml`) get_universe : function Function returning universe (defined in :meth:`openmc.Geometry.from_xml`) @@ -731,8 +664,9 @@ class Cell(IDManagerMixin): c = cls(cell_id, name) # Assign material/distributed materials or fill - mat_ids = get_elem_list(elem, 'material', str) - if mat_ids is not None: + mat_text = get_text(elem, 'material') + if mat_text is not None: + mat_ids = mat_text.split() if len(mat_ids) > 1: c.fill = [materials[i] for i in mat_ids] else: @@ -747,16 +681,18 @@ class Cell(IDManagerMixin): c.region = Region.from_expression(region, surfaces) # Check for other attributes - v = get_text(elem, 'volume') - if v is not None: - c.volume = float(v) - for key in ('temperature', 'density', 'rotation', 'translation'): - values = get_elem_list(elem, key, float) - if values is not None: + t = get_text(elem, 'temperature') + if t is not None: + if ' ' in t: + c.temperature = [float(t_i) for t_i in t.split()] + else: + c.temperature = float(t) + for key in ('temperature', 'rotation', 'translation'): + value = get_text(elem, key) + if value is not None: + values = [float(x) for x in value.split()] if key == 'rotation' and len(values) == 9: values = np.array(values).reshape(3, 3) - elif len(values) == 1: - values = values[0] setattr(c, key, values) # Add this cell to appropriate universe diff --git a/openmc/checkvalue.py b/openmc/checkvalue.py index 5ff2cf9ac..d50b3fcae 100644 --- a/openmc/checkvalue.py +++ b/openmc/checkvalue.py @@ -1,12 +1,8 @@ import copy -import os from collections.abc import Iterable import numpy as np -# Type for arguments that accept file paths -PathLike = str | os.PathLike - def check_type(name, value, expected_type, expected_iter_type=None, *, none_ok=False): """Ensure that an object is of an expected type. Optionally, if the object is @@ -37,7 +33,7 @@ def check_type(name, value, expected_type, expected_iter_type=None, *, none_ok=F [t.__name__ for t in expected_type])) else: msg = (f'Unable to set "{name}" to "{value}" which is not of type "' - f'{expected_type}"') + f'{expected_type.__name__}"') raise TypeError(msg) if expected_iter_type: @@ -170,29 +166,6 @@ def check_length(name, value, length_min, length_max=None): raise ValueError(msg) -def check_increasing(name: str, value, equality: bool = False): - """Ensure that a list's elements are strictly or loosely increasing. - - Parameters - ---------- - name : str - Description of value being checked - value : iterable - Object to check if increasing - equality : bool, optional - Whether equality is allowed. Defaults to False. - - """ - if equality: - if not np.all(np.diff(value) >= 0.0): - raise ValueError(f'Unable to set "{name}" to "{value}" since its ' - 'elements must be increasing.') - elif not equality: - if not np.all(np.diff(value) > 0.0): - raise ValueError(f'Unable to set "{name}" to "{value}" since its ' - 'elements must be strictly increasing.') - - def check_value(name, value, accepted_values): """Ensure that an object's value is contained in a set of acceptable values. diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 8595d1e02..54c43f333 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -25,7 +25,6 @@ import openmc.lib from .checkvalue import (check_type, check_length, check_value, check_greater_than, check_less_than) from .exceptions import OpenMCError -from ._sparse_compat import csr_array # See if mpi4py module can be imported, define have_mpi global variable try: @@ -136,7 +135,7 @@ class CMFDMesh: return outstr def _get_repr(self, list_var, label): - outstr = f"\t{label:<11} = " + outstr = "\t{:<11} = ".format(label) if list(list_var): outstr += ", ".join(str(i) for i in list_var) return outstr @@ -243,11 +242,11 @@ class CMFDMesh: check_length('CMFD mesh grid', grid, grid_length) for i in range(grid_length): - check_type(f'CMFD mesh {dims[i]}-grid', grid[i], Iterable, + check_type('CMFD mesh {}-grid'.format(dims[i]), grid[i], Iterable, Real) - check_greater_than(f'CMFD mesh {dims[i]}-grid length', + check_greater_than('CMFD mesh {}-grid length'.format(dims[i]), len(grid[i]), 1) - self._grid = [np.array(g) for g in grid] + self._grid = np.array(grid) self._display_mesh_warning('rectilinear', 'CMFD mesh grid') def _display_mesh_warning(self, mesh_type, variable_label): @@ -613,7 +612,7 @@ class CMFDRun: for key, value in display.items(): check_value('display key', key, ('balance', 'entropy', 'dominance', 'source')) - check_type(f"display['{key}']", value, bool) + check_type("display['{}']".format(key), value, bool) self._display[key] = value @downscatter.setter @@ -929,7 +928,7 @@ class CMFDRun: with h5py.File(filename, 'a') as f: if 'cmfd' not in f: if openmc.lib.settings.verbosity >= 5: - print(f' Writing CMFD data to {filename}...') + print(' Writing CMFD data to {}...'.format(filename)) sys.stdout.flush() cmfd_group = f.create_group("cmfd") cmfd_group.attrs['cmfd_on'] = self._cmfd_on @@ -981,17 +980,16 @@ class CMFDRun: loss_row = self._loss_row loss_col = self._loss_col temp_data = np.ones(len(loss_row)) - temp_loss = csr_array((temp_data, (loss_row, loss_col)), shape=(n, n)) - temp_loss.sort_indices() + temp_loss = sparse.csr_matrix((temp_data, (loss_row, loss_col)), + shape=(n, n)) # Pass coremap as 1-d array of 32-bit integers coremap = np.swapaxes(self._coremap, 0, 2).flatten().astype(np.int32) - return openmc.lib._dll.openmc_initialize_linsolver( - temp_loss.indptr.astype(np.int32), len(temp_loss.indptr), - temp_loss.indices.astype(np.int32), len(temp_loss.indices), n, + args = temp_loss.indptr, len(temp_loss.indptr), \ + temp_loss.indices, len(temp_loss.indices), n, \ self._spectral, coremap, self._use_all_threads - ) + return openmc.lib._dll.openmc_initialize_linsolver(*args) def _write_cmfd_output(self): """Write CMFD output to buffer at the end of each batch""" @@ -1076,12 +1074,13 @@ class CMFDRun: # Get acceleration map, otherwise set all regions to be accelerated if self._mesh.map is not None: check_length('CMFD coremap', self._mesh.map, - np.prod(self._indices[:3])) + np.product(self._indices[0:3])) if openmc.lib.master(): self._coremap = np.array(self._mesh.map) else: if openmc.lib.master(): - self._coremap = np.ones(np.prod(self._indices[:3]), dtype=int) + self._coremap = np.ones((np.product(self._indices[0:3])), + dtype=int) # Check CMFD tallies accummulated before feedback turned on if self._feedback and self._solver_begin < self._tally_begin: @@ -1134,12 +1133,12 @@ class CMFDRun: with h5py.File(filename, 'r') as f: if 'cmfd' not in f: raise OpenMCError('Could not find CMFD parameters in ', - f'file {filename}') + 'file {}'.format(filename)) else: # Overwrite CMFD values from statepoint if (openmc.lib.master() and openmc.lib.settings.verbosity >= 5): - print(f' Loading CMFD data from {filename}...') + print(' Loading CMFD data from {}...'.format(filename)) sys.stdout.flush() cmfd_group = f['cmfd'] @@ -1310,6 +1309,9 @@ class CMFDRun: Whether or not to run an adjoint calculation """ + # Check for physical adjoint + physical_adjoint = adjoint and self._adjoint_type == 'physical' + # Start timer for build time_start_buildcmfd = time.time() @@ -1380,7 +1382,9 @@ class CMFDRun: """ # Write each element in vector to file - np.savetxt(f'{base_filename}.dat', vector, fmt='%.8f') + with open(base_filename+'.dat', 'w') as fh: + for val in vector: + fh.write('{:0.8f}\n'.format(val)) # Save as numpy format np.save(base_filename, vector) @@ -1409,7 +1413,8 @@ class CMFDRun: # Get all data entries for particular row in matrix data = matrix.data[matrix.indptr[row]:matrix.indptr[row+1]] for i in range(len(cols)): - fh.write(f'{row:3d}, {cols[i]:3d}, {data[i]:0.8f}\n') + fh.write('{:3d}, {:3d}, {:0.8f}\n'.format( + row, cols[i], data[i])) # Save matrix in scipy format sparse.save_npz(base_filename, matrix) @@ -1430,6 +1435,9 @@ class CMFDRun: # indices of the actual problem so that cmfd_flux can be multiplied by # nfissxs + # Calculate volume + vol = np.product(self._hxyz, axis=3) + # Reshape phi by number of groups phi = self._phi.reshape((n, ng)) @@ -1585,8 +1593,7 @@ class CMFDRun: # Create csr matrix loss_row = self._loss_row loss_col = self._loss_col - loss = csr_array((data, (loss_row, loss_col)), shape=(n, n)) - loss.sort_indices() + loss = sparse.csr_matrix((data, (loss_row, loss_col)), shape=(n, n)) return loss def _build_prod_matrix(self, adjoint): @@ -1612,8 +1619,7 @@ class CMFDRun: # Create csr matrix prod_row = self._prod_row prod_col = self._prod_col - prod = csr_array((data, (prod_row, prod_col)), shape=(n, n)) - prod.sort_indices() + prod = sparse.csr_matrix((data, (prod_row, prod_col)), shape=(n, n)) return prod def _execute_power_iter(self, loss, prod): @@ -2145,6 +2151,7 @@ class CMFDRun: is_accel = self._coremap != _CMFD_NOACCEL # Logical for determining whether a zero flux "albedo" b.c. should be # applied + is_zero_flux_alb = abs(self._albedo - _ZERO_FLUX) < _TINY_BIT x_inds, y_inds, z_inds = np.indices((nx, ny, nz)) # Define slice equivalent to is_accel[0,:,:] @@ -2310,8 +2317,8 @@ class CMFDRun: constant_values=_CMFD_NOACCEL)[:,:,1:] # Create empty row and column vectors to store for loss matrix - row = np.array([], dtype=int) - col = np.array([], dtype=int) + row = np.array([]) + col = np.array([]) # Store all indices used to populate production and loss matrix is_accel = self._coremap != _CMFD_NOACCEL @@ -2721,6 +2728,8 @@ class CMFDRun: # Define flux in each cell cell_flux = self._flux / dxdydz + # Extract indices of coremap that are accelerated + is_accel = self._coremap != _CMFD_NOACCEL # Define dhat at left surface for all mesh cells on left boundary boundary = self._first_x_accel diff --git a/openmc/config.py b/openmc/config.py deleted file mode 100644 index 23d8e23a7..000000000 --- a/openmc/config.py +++ /dev/null @@ -1,218 +0,0 @@ -"""Module for handling global configuration in OpenMC. - -This module exports a single object, `config`, that can be used to control -various settings, primarily paths to data files. It acts like a dictionary but -with special behaviors. - -Examples --------- ->>> import openmc ->>> openmc.config['cross_sections'] = '/path/to/my/cross_sections.xml' ->>> print(openmc.config) -{'resolve_paths': True, 'cross_sections': PosixPath('/path/to/my/cross_sections.xml')} - -""" -from collections.abc import MutableMapping -from contextlib import contextmanager -import os -from pathlib import Path -import warnings -from typing import Any, Dict, Iterator - -from openmc.data import DataLibrary -from openmc.data.decay import _DECAY_ENERGY, _DECAY_PHOTON_ENERGY - -__all__ = ["config"] - - -class _Config(MutableMapping): - """A configuration dictionary for OpenMC with special handling for path-like values. - - This class enforces valid configuration keys and synchronizes path-related - settings with their corresponding environment variables. - - Attributes - ---------- - cross_sections : pathlib.Path - Path to a cross_sections.xml file. Also sets/unsets the - OPENMC_CROSS_SECTIONS environment variable. - mg_cross_sections : pathlib.Path - Path to a multi-group cross_sections.h5 file. Also sets/unsets - the OPENMC_MG_CROSS_SECTIONS environment variable. - chain_file : pathlib.Path - Path to a depletion chain XML file. Also sets/unsets the - OPENMC_CHAIN_FILE environment variable. Setting or deleting this - clears internal decay data caches. - resolve_paths : bool - If True (default), all paths assigned are resolved to absolute - paths. If False, paths are stored as they are provided. - - """ - _PATH_KEYS: Dict[str, str] = { - 'cross_sections': 'OPENMC_CROSS_SECTIONS', - 'mg_cross_sections': 'OPENMC_MG_CROSS_SECTIONS', - 'chain_file': 'OPENMC_CHAIN_FILE' - } - - def __init__(self, data: dict = ()): - self._mapping: Dict[str, Any] = {'resolve_paths': True} - self.update(data) - - def __getitem__(self, key: str) -> Any: - return self._mapping[key] - - def __delitem__(self, key: str): - """Delete a configuration key. - - This also deletes the corresponding environment variable if the key is a - path-like key, and clears decay data caches if 'chain_file' is deleted. - 'resolve_paths' cannot be deleted. - - """ - if key == 'resolve_paths': - raise KeyError("'resolve_paths' cannot be deleted.") - del self._mapping[key] - if key in self._PATH_KEYS: - env_var = self._PATH_KEYS[key] - if env_var in os.environ: - del os.environ[env_var] - if key == 'chain_file': - _DECAY_PHOTON_ENERGY.clear() - _DECAY_ENERGY.clear() - - def __setitem__(self, key: str, value: Any): - """Set a configuration key and its corresponding value. - - For path-like keys, this method performs several actions: - 1. Resolves the path to an absolute path if `resolve_paths` is True. - 2. Stores the `pathlib.Path` object. - 3. Sets the corresponding environment variable (e.g., OPENMC_CROSS_SECTIONS). - 4. For 'chain_file', clears internal decay data caches. - 5. Issues a `UserWarning` if the final path does not exist. - - """ - if key in self._PATH_KEYS: - p = Path(value) - # Use .get() for robustness, defaulting to True - if self._mapping.get('resolve_paths', True): - stored_path = p.resolve(strict=False) - else: - stored_path = p - - self._mapping[key] = stored_path - os.environ[self._PATH_KEYS[key]] = str(stored_path) - - if key == 'chain_file': - _DECAY_PHOTON_ENERGY.clear() - _DECAY_ENERGY.clear() - - if not stored_path.exists(): - warnings.warn(f"Path '{stored_path}' does not exist.", UserWarning) - - elif key == 'resolve_paths': - if not isinstance(value, bool): - raise TypeError("'resolve_paths' must be a boolean.") - self._mapping[key] = value - else: - valid_keys = list(self._PATH_KEYS.keys()) + ['resolve_paths'] - raise KeyError( - f"Unrecognized config key: {key}. Acceptable keys are: " - f"{', '.join(repr(k) for k in valid_keys)}." - ) - - def __iter__(self) -> Iterator[str]: - return iter(self._mapping) - - def __len__(self) -> int: - return len(self._mapping) - - def __repr__(self) -> str: - return repr(self._mapping) - - def clear(self): - """Clear all configuration keys except for 'resolve_paths'. - - This ensures that the path resolution behavior is not accidentally reset - when clearing the configuration. - - """ - # Create a copy of keys to iterate over for safe deletion - keys_to_delete = [k for k in self._mapping if k != 'resolve_paths'] - for key in keys_to_delete: - del self[key] - - @contextmanager - def patch(self, key: str, value: Any): - """Context manager to temporarily change a configuration value. - - After the `with` block, the configuration is restored to its original - state. - - Parameters - ---------- - key : str - The key of the configuration value to change. - value - The new temporary value. - - Examples - -------- - >>> openmc.config['cross_sections'] = 'endf71.xml' - >>> with openmc.config.patch('cross_sections', 'fendl32.xml'): - ... # Code in this block sees the new value - ... print(f"Inside with block: {openmc.config['cross_sections']}") - >>> # Outside the block, the value is restored - >>> print(f"Outside with block: {openmc.config['cross_sections']}") - Inside with block: fendl32.xml - Outside with block: endf71.xml - - """ - previous_value = self.get(key) - self[key] = value - try: - yield - finally: - if previous_value is None: - del self[key] - else: - self[key] = previous_value - - -def _default_config(**kwargs) -> _Config: - """Create a configuration initialized from environment variables. - - This function checks for OPENMC_CROSS_SECTIONS, OPENMC_MG_CROSS_SECTIONS, - and OPENMC_CHAIN_FILE environment variables. It also has logic to find - a chain file within a `cross_sections.xml` file if one is not - explicitly set. - - Returns - ------- - _Config - A new configuration object. - - """ - config = _Config(kwargs) - for key,var in _Config._PATH_KEYS.items(): - if var in os.environ: - config[key] = os.environ[var] - - chain_file = config.get("chain_file") - xs_path = config.get("cross_sections") - if chain_file is None and xs_path is not None and xs_path.exists(): - try: - data = DataLibrary.from_xml(xs_path) - except Exception: - # Let this pass silently if cross_sections.xml can't be parsed - # or if a dependency like lxml is not available. - pass - else: - for lib in reversed(data.libraries): - if lib['type'] == 'depletion_chain': - config['chain_file'] = xs_path.parent / lib['path'] - break - return config - - -# Global configuration dictionary for OpenMC settings. -config = _default_config() diff --git a/openmc/dagmc.py b/openmc/dagmc.py deleted file mode 100644 index 75ead5e43..000000000 --- a/openmc/dagmc.py +++ /dev/null @@ -1,676 +0,0 @@ -from collections.abc import Iterable, Mapping -from numbers import Integral - -import h5py -import lxml.etree as ET -import numpy as np -import warnings - -import openmc -import openmc.checkvalue as cv -from ._xml import get_elem_list, get_text -from .checkvalue import check_type, check_value -from .surface import _BOUNDARY_TYPES -from .bounding_box import BoundingBox -from .utility_funcs import input_path -from .plots import add_plot_params - - -class DAGMCUniverse(openmc.UniverseBase): - """A reference to a DAGMC file to be used in the model. - - .. versionadded:: 0.13.0 - - Parameters - ---------- - filename : str - Path to the DAGMC file used to represent this universe. - universe_id : int, optional - Unique identifier of the universe. If not specified, an identifier will - automatically be assigned. - name : str, optional - Name of the universe. If not specified, the name is the empty string. - auto_geom_ids : bool - Set IDs automatically on initialization (True) or report overlaps in ID - space between CSG and DAGMC (False) - auto_mat_ids : bool - Set IDs automatically on initialization (True) or report overlaps in ID - space between OpenMC and UWUW materials (False) - Attributes - ---------- - id : int - Unique identifier of the universe - name : str - Name of the universe - filename : str - Path to the DAGMC file used to represent this universe. - auto_geom_ids : bool - Set IDs automatically on initialization (True) or report overlaps in ID - space between CSG and DAGMC (False) - auto_mat_ids : bool - Set IDs automatically on initialization (True) or report overlaps in ID - space between OpenMC and UWUW materials (False) - bounding_box : openmc.BoundingBox - Lower-left and upper-right coordinates of an axis-aligned bounding box - of the universe. - - .. versionadded:: 0.13.1 - material_names : list of str - Return a sorted list of materials names that are contained within the - DAGMC h5m file. This is useful when naming openmc.Material() objects as - each material name present in the DAGMC h5m file must have a matching - openmc.Material() with the same name. - - .. versionadded:: 0.13.2 - n_cells : int - The number of cells in the DAGMC model. This is the number of cells at - runtime and accounts for the implicit complement whether or not is it - present in the DAGMC file. - - .. versionadded:: 0.13.2 - n_surfaces : int - The number of surfaces in the model. - - .. versionadded:: 0.13.2 - """ - - def __init__(self, - filename: cv.PathLike, - universe_id=None, - name='', - auto_geom_ids=False, - auto_mat_ids=False): - super().__init__(universe_id, name) - # Initialize class attributes - self.filename = filename - self.auto_geom_ids = auto_geom_ids - self.auto_mat_ids = auto_mat_ids - - def __repr__(self): - string = super().__repr__() - string += '{: <16}=\t{}\n'.format('\tGeom', 'DAGMC') - string += '{: <16}=\t{}\n'.format('\tFile', self.filename) - return string - - @property - def bounding_box(self): - with h5py.File(self.filename) as dagmc_file: - coords = dagmc_file['tstt']['nodes']['coordinates'][()] - lower_left_corner = coords.min(axis=0) - upper_right_corner = coords.max(axis=0) - return openmc.BoundingBox(lower_left_corner, upper_right_corner) - - @property - def filename(self): - return self._filename - - @filename.setter - def filename(self, val: cv.PathLike): - cv.check_type('DAGMC filename', val, cv.PathLike) - self._filename = input_path(val) - - @property - def material_overrides(self): - raise AttributeError( - "DAGMCUniverse.material_overrides has been removed. Use " - "DAGMCCell objects added via add_cell() to manage per-cell " - "material assignments.") - - @material_overrides.setter - def material_overrides(self, val): - raise AttributeError( - "DAGMCUniverse.material_overrides has been removed. Use " - "DAGMCCell objects added via add_cell() to manage per-cell " - "material assignments.") - - def add_material_override(self, key, overrides=None): - """Add a material override to the universe. - - .. versionadded:: 0.15 - - Parameters - ---------- - key : openmc.DAGMCCell or int - Cell object or ID of the Cell to override - value : openmc.Material or Iterable of openmc.Material - Material(s) to be applied to the Cell passed as the key - - """ - # Ensure that they key is a valid type - if not isinstance(key, (int, openmc.DAGMCCell)): - raise ValueError("Unrecognized key type. " - "Must be an integer or openmc.DAGMCCell object") - - # Ensure that overrides is an iterable of openmc.Material - overrides = overrides if isinstance(overrides, openmc.Iterable) else [overrides] - cv.check_iterable_type('material objects', overrides, (openmc.Material, type(None))) - - # if a DAGMCCell is passed, redcue the key to the ID of the cell - if isinstance(key, openmc.DAGMCCell): - key = key.id - - if key not in self.cells: - raise ValueError(f"Cell ID '{key}' not found in DAGMC universe") - - if len(overrides) == 1: - self.cells[key].fill = overrides[0] - else: - self.cells[key].fill = list(overrides) - - @property - def auto_geom_ids(self): - return self._auto_geom_ids - - @auto_geom_ids.setter - def auto_geom_ids(self, val): - cv.check_type('DAGMC automatic geometry ids', val, bool) - self._auto_geom_ids = val - - @property - def auto_mat_ids(self): - return self._auto_mat_ids - - @auto_mat_ids.setter - def auto_mat_ids(self, val): - cv.check_type('DAGMC automatic material ids', val, bool) - self._auto_mat_ids = val - - @property - def material_names(self): - material_tags_ascii = [] - with h5py.File(self.filename) as dagmc_file_contents: - material_tags_hex = dagmc_file_contents['/tstt/tags/NAME'].get('values') - for tag in material_tags_hex: - candidate_tag = tag.tobytes().decode().replace('\x00', '') - # tags might be for temperature or reflective surfaces - if candidate_tag.startswith('mat:'): - # if name ends with _comp remove it, it is not parsed - if candidate_tag.endswith('_comp'): - candidate_tag = candidate_tag[:-5] - # removes first 4 characters as openmc.Material name should be - # set without the 'mat:' part of the tag - material_tags_ascii.append(candidate_tag[4:]) - return sorted(set(material_tags_ascii)) - - def _n_geom_elements(self, geom_type): - """ - Helper function for retrieving the number geometric entities in a DAGMC - file - - Parameters - ---------- - geom_type : str - The type of geometric entity to count. One of {'Volume', 'Surface'}. Returns - the runtime number of voumes in the DAGMC model (includes implicit complement). - - Returns - ------- - int - Number of geometry elements of the specified type - """ - cv.check_value('geometry type', geom_type, ('volume', 'surface')) - - def decode_str_tag(tag_val): - return tag_val.tobytes().decode().replace('\x00', '') - - with h5py.File(self.filename) as dagmc_file: - category_data = dagmc_file['tstt/tags/CATEGORY/values'] - category_strs = map(decode_str_tag, category_data) - n = sum([v == geom_type.capitalize() for v in category_strs]) - - # check for presence of an implicit complement in the file and - # increment the number of cells if it doesn't exist - if geom_type == 'volume': - name_data = dagmc_file['tstt/tags/NAME/values'] - name_strs = map(decode_str_tag, name_data) - if not sum(['impl_complement' in n for n in name_strs]): - n += 1 - return n - - @property - def n_cells(self): - return self._n_geom_elements('volume') - - @property - def n_surfaces(self): - return self._n_geom_elements('surface') - - def create_xml_subelement(self, xml_element, memo=None): - if memo is None: - memo = set() - - if self in memo: - return - - memo.add(self) - - # Set xml element values - dagmc_element = ET.Element('dagmc_universe') - dagmc_element.set('id', str(self.id)) - - if self.name: - dagmc_element.set('name', self.name) - if self.auto_geom_ids: - dagmc_element.set('auto_geom_ids', 'true') - if self.auto_mat_ids: - dagmc_element.set('auto_mat_ids', 'true') - dagmc_element.set('filename', str(self.filename)) - if self.cells: - for cell in self.cells.values(): - cell_element = cell.create_xml_subelement(xml_element, memo) - dagmc_element.append(cell_element) - xml_element.append(dagmc_element) - - def bounding_region( - self, - bounded_type: str = 'box', - boundary_type: str = 'vacuum', - starting_id: int = 10000, - padding_distance: float = 0. - ): - """Creates a either a spherical or box shaped bounding region around - the DAGMC geometry. - - .. versionadded:: 0.13.1 - - Parameters - ---------- - bounded_type : str - The type of bounding surface(s) to use when constructing the region. - Options include a single spherical surface (sphere) or a rectangle - made from six planes (box). - boundary_type : str - Boundary condition that defines the behavior for particles hitting - the surface. Defaults to vacuum boundary condition. Passed into the - surface construction. - starting_id : int - Starting ID of the surface(s) used in the region. For bounded_type - 'box', the next 5 IDs will also be used. Defaults to 10000 to reduce - the chance of an overlap of surface IDs with the DAGMC geometry. - padding_distance : float - Distance between the bounding region surfaces and the minimal - bounding box. Allows for the region to be larger than the DAGMC - geometry. - - Returns - ------- - openmc.Region - Region instance - """ - - check_type('boundary type', boundary_type, str) - check_value('boundary type', boundary_type, _BOUNDARY_TYPES) - check_type('starting surface id', starting_id, Integral) - check_type('bounded type', bounded_type, str) - check_value('bounded type', bounded_type, ('box', 'sphere')) - - bbox = self.bounding_box.expand(padding_distance, True) - - if bounded_type == 'sphere': - radius = np.linalg.norm(bbox.upper_right - bbox.center) - bounding_surface = openmc.Sphere( - surface_id=starting_id, - x0=bbox.center[0], - y0=bbox.center[1], - z0=bbox.center[2], - boundary_type=boundary_type, - r=radius, - ) - - return -bounding_surface - - if bounded_type == 'box': - # defines plane surfaces for all six faces of the bounding box - lower_x = openmc.XPlane(bbox[0][0], surface_id=starting_id) - upper_x = openmc.XPlane(bbox[1][0], surface_id=starting_id+1) - lower_y = openmc.YPlane(bbox[0][1], surface_id=starting_id+2) - upper_y = openmc.YPlane(bbox[1][1], surface_id=starting_id+3) - lower_z = openmc.ZPlane(bbox[0][2], surface_id=starting_id+4) - upper_z = openmc.ZPlane(bbox[1][2], surface_id=starting_id+5) - - region = +lower_x & -upper_x & +lower_y & -upper_y & +lower_z & -upper_z - - for surface in region.get_surfaces().values(): - surface.boundary_type = boundary_type - - return region - - def bounded_universe(self, bounding_cell_id=10000, **kwargs): - """Returns an openmc.Universe filled with this DAGMCUniverse and bounded - with a cell. Defaults to a box cell with a vacuum surface however this - can be changed using the kwargs which are passed directly to - DAGMCUniverse.bounding_region(). - - Parameters - ---------- - bounding_cell_id : int - The cell ID number to use for the bounding cell, defaults to 10000 to reduce - the chance of overlapping ID numbers with the DAGMC geometry. - - Returns - ------- - openmc.Universe - Universe instance - """ - bounding_cell = openmc.Cell( - fill=self, cell_id=bounding_cell_id, region=self.bounding_region(**kwargs)) - return openmc.Universe(cells=[bounding_cell]) - - @classmethod - def from_hdf5(cls, group): - """Create DAGMC universe from HDF5 group - - Parameters - ---------- - group : h5py.Group - Group in HDF5 file - - Returns - ------- - openmc.DAGMCUniverse - DAGMCUniverse instance - - """ - id = int(group.name.split('/')[-1].lstrip('universe ')) - fname = group['filename'][()].decode() - name = group['name'][()].decode() if 'name' in group else None - - out = cls(fname, universe_id=id, name=name) - - out.auto_geom_ids = bool(group.attrs['auto_geom_ids']) - out.auto_mat_ids = bool(group.attrs['auto_mat_ids']) - - return out - - @classmethod - def from_xml_element(cls, elem, mats=None): - """Generate DAGMC universe from XML element - - Parameters - ---------- - elem : lxml.etree._Element - `` element - mats : dict - Dictionary mapping material ID strings to :class:`openmc.Material` - instances (defined in :meth:`openmc.Geometry.from_xml`) - - Returns - ------- - openmc.DAGMCUniverse - DAGMCUniverse instance - - """ - id = int(get_text(elem, 'id')) - fname = get_text(elem, 'filename') - - out = cls(fname, universe_id=id) - - name = get_text(elem, 'name') - if name is not None: - out.name = name - - out.auto_geom_ids = bool(get_text(elem, "auto_geom_ids")) - out.auto_mat_ids = bool(get_text(elem, "auto_mat_ids")) - - has_overrides = elem.find('material_overrides') is not None - has_cells = elem.find('cell') is not None - - if has_overrides and has_cells: - raise ValueError( - "DAGMCUniverse cannot specify both and " - " sub-elements. Use elements only.") - - if has_overrides: - warnings.warn( - "DAGMCUniverse is deprecated and will be " - "removed in a future version. Use nested elements " - "instead.", DeprecationWarning, stacklevel=2) - out._parse_legacy_material_overrides(elem, mats) - elif has_cells: - out._parse_cell_overrides(elem, mats) - - return out - - def _parse_legacy_material_overrides(self, elem, mats): - """Parse the deprecated XML format and populate - the universe with equivalent DAGMCCell objects.""" - if mats is None: - raise ValueError( - "DAGMC material overrides found but no materials were " - "provided to populate the mapping.") - mo_elem = elem.find('material_overrides') - for co_elem in mo_elem.findall('cell_override'): - cell_id = int(get_text(co_elem, 'id')) - mat_ids = co_elem.find('material_ids').text.split() - fill_objs = [mats[mid] for mid in mat_ids] - fill = fill_objs[0] if len(fill_objs) == 1 else fill_objs - if cell_id in self.cells: - raise ValueError( - f"Duplicate DAGMC cell override specified for cell {cell_id}.") - self.add_cell(DAGMCCell(cell_id=cell_id, fill=fill)) - - def _parse_cell_overrides(self, elem, mats): - if mats is None: - raise ValueError("DAGMC cell overrides found in DAGMC universe but " - "no materials were provided to populate the " - "mapping.") - - for cell_elem in elem.findall('cell'): - cell_id = int(get_text(cell_elem, 'id')) - if cell_id in self.cells: - raise ValueError( - f"Duplicate DAGMC cell override specified for cell {cell_id}.") - DAGMCCell.from_xml_element(cell_elem, mats, self) - - def _partial_deepcopy(self): - """Clone all of the openmc.DAGMCUniverse object's attributes except for - its cells, as they are copied within the clone function. This should - only to be used within the openmc.UniverseBase.clone() context. - """ - clone = openmc.DAGMCUniverse(name=self.name, filename=self.filename) - clone.volume = self.volume - clone.auto_geom_ids = self.auto_geom_ids - clone.auto_mat_ids = self.auto_mat_ids - return clone - - def add_cell(self, cell): - """Add a cell to the universe. - - Parameters - ---------- - cell : openmc.DAGMCCell - Cell to add - - """ - if not isinstance(cell, openmc.DAGMCCell): - msg = f'Unable to add a DAGMCCell to DAGMCUniverse ' \ - f'ID="{self._id}" since "{cell}" is not a DAGMCCell' - raise TypeError(msg) - - cell_id = cell.id - - if cell_id not in self._cells: - self._cells[cell_id] = cell - - def remove_cell(self, cell): - """Remove a cell from the universe. - - Parameters - ---------- - cell : openmc.Cell - Cell to remove - - """ - - if not isinstance(cell, openmc.DAGMCCell): - msg = f'Unable to remove a Cell from Universe ID="{self._id}" ' \ - f'since "{cell}" is not a Cell' - raise TypeError(msg) - - # If the Cell is in the Universe's list of Cells, delete it - self._cells.pop(cell.id, None) - - def sync_dagmc_cells(self, mats: Iterable[openmc.Material]): - """Synchronize DAGMC cell information between Python and C API - - .. versionadded:: 0.15.1 - - Parameters - ---------- - mats : iterable of openmc.Material - Iterable of materials to assign to the DAGMC cells - - """ - import openmc.lib - if not openmc.lib.is_initialized: - raise RuntimeError("This universe must be part of an openmc.Model " - "initialized via Model.init_lib before calling " - "this method.") - - dagmc_cell_ids = openmc.lib.dagmc.dagmc_universe_cell_ids(self.id) - if len(dagmc_cell_ids) != self.n_cells: - raise ValueError( - f"Number of cells in DAGMC universe {self.id} does not match " - f"the number of cells in the Python universe." - ) - - mats_per_id = {mat.id: mat for mat in mats} - for dag_cell_id in dagmc_cell_ids: - dag_cell = openmc.lib.cells[dag_cell_id] - if isinstance(dag_cell.fill, Iterable): - fill = [mats_per_id[mat.id] for mat in dag_cell.fill if mat] - else: - fill = mats_per_id[dag_cell.fill.id] if dag_cell.fill else None - name = dag_cell.name - if dag_cell_id in self._cells: - self._cells[dag_cell_id].name = name - self._cells[dag_cell_id].fill = fill - else: - self.add_cell( - openmc.DAGMCCell(cell_id=dag_cell_id, name=name, fill=fill)) - - @add_plot_params - def plot(self, *args, **kwargs): - """Display a slice plot of the DAGMCUniverse. - """ - return openmc.Geometry(self).plot(*args, **kwargs) - - -class DAGMCCell(openmc.Cell): - """A cell class for DAGMC-based geometries. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - cell_id : int or None, optional - Unique identifier for the cell. If None, an identifier will be - automatically assigned. - name : str, optional - Name of the cell. - fill : openmc.Material or None, optional - Material filling the cell. If None, the cell is filled with vacuum. - - Attributes - ---------- - DAG_parent_universe : int - The parent universe of the cell. - - Notes - ----- - DAGMC geometries are composed of triangulated surfaces, which means cell - volumes can in principle be computed exactly (e.g. via mesh-based - integration). Manually specifying :attr:`volume` overrides any such - calculation and may introduce inconsistencies if the value does not - accurately reflect the true geometric volume. - - """ - def __init__(self, cell_id=None, name='', fill=None): - super().__init__(cell_id, name, fill, None) - - @property - def DAG_parent_universe(self): - """Get the parent universe of the cell.""" - return self._parent_universe - - @DAG_parent_universe.setter - def DAG_parent_universe(self, universe): - """Set the parent universe of the cell.""" - self._parent_universe = universe.id - - def bounding_box(self): - return BoundingBox.infinite() - - def get_all_cells(self, memo=None): - return {} - - def get_all_universes(self, memo=None): - return {} - - def clone(self, clone_materials=True, clone_regions=True, memo=None): - warnings.warn("clone is not available for cells in a DAGMC universe") - return self - - def plot(self, *args, **kwargs): - raise TypeError("plot is not available for DAGMC cells.") - - def create_xml_subelement(self, xml_element, memo=None): - if self.fill_type not in ('void', 'material', 'distribmat'): - raise TypeError("DAGMC cell overrides currently only support " - "material fills.") - if self.temperature is not None and self.fill_type not in ( - 'material', 'distribmat' - ): - raise TypeError("DAGMC cell temperature overrides require a " - "material fill.") - if self.density is not None and self.fill_type not in ('material', 'distribmat'): - raise TypeError("DAGMC cell density overrides require a " - "material fill.") - if any(getattr(self, attr) is not None for attr in ('translation', 'rotation')): - raise TypeError("DAGMC cell overrides do not support translation " - "or rotation.") - return super().create_xml_subelement(xml_element, memo) - - @classmethod - def from_xml_element(cls, elem, mats, universe): - """Generate a DAGMCCell from an XML override element. - - Parameters - ---------- - elem : lxml.etree._Element - `` element containing a DAGMC cell property override - mats : dict - Dictionary mapping material ID strings to :class:`openmc.Material` - instances - universe : DAGMCUniverse - Universe to add the parsed cell to. - - Returns - ------- - DAGMCCell - DAGMCCell instance - """ - if not isinstance(universe, DAGMCUniverse): - raise TypeError( - f"universe must be a DAGMCUniverse instance, " - f"got {type(universe).__name__}.") - - cell_id = int(get_text(elem, 'id')) - - # Validate attributes that are unsupported for DAGMC cell overrides - for tag in ('region', 'fill', 'universe'): - if get_text(elem, tag) is not None: - raise ValueError( - f"DAGMC cell {cell_id} override cannot specify '{tag}'.") - for tag in ('translation', 'rotation'): - if get_text(elem, tag) is not None: - raise ValueError( - f"DAGMC cell {cell_id} override does not support " - f"'{tag}'.") - if get_elem_list(elem, 'material', str) is None: - raise ValueError( - f"DAGMC cell {cell_id} must specify a material override.") - - return super().from_xml_element( - elem, surfaces={}, materials=mats, - get_universe=lambda _: universe) diff --git a/openmc/data/__init__.py b/openmc/data/__init__.py index 9b38d758e..c2d35565a 100644 --- a/openmc/data/__init__.py +++ b/openmc/data/__init__.py @@ -33,8 +33,5 @@ from .resonance_covariance import * from .multipole import * from .grid import * from .function import * -from .vectfit import * -from .dose.dose import dose_coefficients -from .dose.mass_attenuation import \ - mass_energy_absorption_coefficient, mass_attenuation_coefficient +from .effective_dose.dose import dose_coefficients diff --git a/openmc/data/_endf.pyx b/openmc/data/_endf.pyx new file mode 100644 index 000000000..991ee015b --- /dev/null +++ b/openmc/data/_endf.pyx @@ -0,0 +1,8 @@ +# cython: c_string_type=str, c_string_encoding=ascii + +cdef extern from "endf.c": + double cfloat_endf(const char* buffer, int n) + +def float_endf(s): + cdef const char* c_string = s + return cfloat_endf(c_string, len(s)) diff --git a/openmc/data/ace.py b/openmc/data/ace.py index d3de6a192..06c581b42 100644 --- a/openmc/data/ace.py +++ b/openmc/data/ace.py @@ -9,12 +9,13 @@ unresolved resonance region, and tabulated data in the fast region. After the ENDF data has been reconstructed and Doppler-broadened, the ACER module generates ACE-format cross sections. -.. _MCNP: https://mcnp.lanl.gov/ -.. _NJOY: https://www.njoy21.io/ -.. _ENDF: https://www.nndc.bnl.gov/endf-library/ +.. _MCNP: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/ +.. _NJOY: http://t2.lanl.gov/codes.shtml +.. _ENDF: http://www.nndc.bnl.gov/endf """ +from collections import OrderedDict import enum from pathlib import Path import struct @@ -23,8 +24,8 @@ import numpy as np import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from .data import ATOMIC_SYMBOL, gnds_name, EV_PER_MEV, K_BOLTZMANN -from endf.records import ENDF_FLOAT_RE +from .data import ATOMIC_SYMBOL, gnd_name, EV_PER_MEV, K_BOLTZMANN +from .endf import ENDF_FLOAT_RE def get_metadata(zaid, metastable_scheme='nndc'): @@ -87,7 +88,7 @@ def get_metadata(zaid, metastable_scheme='nndc'): # Determine name element = ATOMIC_SYMBOL[Z] - name = gnds_name(Z, mass_number, metastable) + name = gnd_name(Z, mass_number, metastable) return (name, element, Z, mass_number, metastable) @@ -143,7 +144,7 @@ def ascii_to_binary(ascii_file, binary_file): # that XSS will start at the second record nxs = [int(x) for x in ' '.join(lines[idx + 6:idx + 8]).split()] jxs = [int(x) for x in ' '.join(lines[idx + 8:idx + 12]).split()] - binary_file.write(struct.pack(str(f'=16i32i{record_length - 500}x'), + binary_file.write(struct.pack(str('=16i32i{}x'.format(record_length - 500)), *(nxs + jxs))) # Read/write XSS array. Null bytes are added to form a complete record @@ -152,7 +153,8 @@ def ascii_to_binary(ascii_file, binary_file): start = idx + _ACE_HEADER_SIZE xss = np.fromstring(' '.join(lines[start:start + n_lines]), sep=' ') extra_bytes = record_length - ((len(xss)*8 - 1) % record_length + 1) - binary_file.write(struct.pack(str(f'={nxs[0]}d{extra_bytes}x'), *xss)) + binary_file.write(struct.pack(str('={}d{}x'.format( + nxs[0], extra_bytes)), *xss)) # Advance to next table in file idx += _ACE_HEADER_SIZE + n_lines @@ -183,7 +185,8 @@ def get_table(filename, name=None): if lib.tables: return lib.tables[0] else: - raise ValueError(f'Could not find ACE table with name: {name}') + raise ValueError('Could not find ACE table with name: {}' + .format(name)) # The beginning of an ASCII ACE file consists of 12 lines that include the name, @@ -293,14 +296,14 @@ class Library(EqualityMixin): if verbose: kelvin = round(temperature * EV_PER_MEV / K_BOLTZMANN) - print(f"Loading nuclide {name} at {kelvin} K") + print("Loading nuclide {} at {} K".format(name, kelvin)) # Read JXS jxs = list(struct.unpack(str('=32i'), ace_file.read(128))) # Read XSS ace_file.seek(start_position + recl_length) - xss = list(struct.unpack(str(f'={length}d'), + xss = list(struct.unpack(str('={}d'.format(length)), ace_file.read(length*8))) # Insert zeros at beginning of NXS, JXS, and XSS arrays so that the @@ -391,7 +394,7 @@ class Library(EqualityMixin): if verbose: kelvin = round(temperature * EV_PER_MEV / K_BOLTZMANN) - print(f"Loading nuclide {name} at {kelvin} K") + print("Loading nuclide {} at {} K".format(name, kelvin)) # Insert zeros at beginning of NXS, JXS, and XSS arrays so that the # indexing will be the same as Fortran. This makes it easier to @@ -453,7 +456,8 @@ class TableType(enum.Enum): for member in cls: if suffix.endswith(member.value): return member - raise ValueError(f"Suffix '{suffix}' has no corresponding ACE table type.") + raise ValueError("Suffix '{}' has no corresponding ACE table type." + .format(suffix)) class Table(EqualityMixin): @@ -504,7 +508,7 @@ class Table(EqualityMixin): return TableType.from_suffix(xs[-1]) def __repr__(self): - return f"" + return "".format(self.name) def get_libraries_from_xsdir(path): @@ -540,7 +544,7 @@ def get_libraries_from_xsdir(path): # Create list of ACE libraries -- we use an ordered dictionary while # building to get O(1) membership checks while retaining insertion order - libraries = {} + libraries = OrderedDict() for line in lines: words = line.split() if len(words) < 3: @@ -572,7 +576,7 @@ def get_libraries_from_xsdata(path): with open(xsdata, 'r') as xsdata_file: # As in get_libraries_from_xsdir, we use a dict for O(1) membership # check while retaining insertion order - libraries = {} + libraries = OrderedDict() for line in xsdata_file: words = line.split() if len(words) >= 9: diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index 778139cc2..4d058bcb7 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -10,8 +10,8 @@ from openmc.mixin import EqualityMixin from openmc.stats import Univariate, Tabular, Uniform, Legendre from .function import INTERPOLATION_SCHEME from .data import EV_PER_MEV -from .endf import as_evaluation, get_head_record, get_cont_record, \ - get_tab1_record, get_list_record, get_tab2_record +from .endf import get_head_record, get_cont_record, get_tab1_record, \ + get_list_record, get_tab2_record class AngleDistribution(EqualityMixin): @@ -42,16 +42,16 @@ class AngleDistribution(EqualityMixin): def energy(self): return self._energy + @property + def mu(self): + return self._mu + @energy.setter def energy(self, energy): cv.check_type('angle distribution incoming energy', energy, Iterable, Real) self._energy = energy - @property - def mu(self): - return self._mu - @mu.setter def mu(self, mu): cv.check_type('angle distribution scattering cosines', mu, @@ -213,7 +213,7 @@ class AngleDistribution(EqualityMixin): Parameters ---------- - ev : openmc.data.endf.Evaluation or endf.Material + ev : openmc.data.endf.Evaluation ENDF evaluation mt : int The MT value of the reaction to get angular distributions for @@ -224,7 +224,6 @@ class AngleDistribution(EqualityMixin): Angular distribution """ - ev = as_evaluation(ev) file_obj = StringIO(ev.section[4, mt]) # Read HEAD record @@ -236,6 +235,7 @@ class AngleDistribution(EqualityMixin): items = get_cont_record(file_obj) li = items[2] nk = items[4] + center_of_mass = (items[3] == 2) # Check for obsolete energy transformation matrix. If present, just skip # it and keep reading @@ -259,6 +259,7 @@ class AngleDistribution(EqualityMixin): mu = [] for i in range(n_energy): items, al = get_list_record(file_obj) + temperature = items[0] energy[i] = items[1] coefficients = np.asarray([1.0] + al) mu.append(Legendre(coefficients)) @@ -272,6 +273,7 @@ class AngleDistribution(EqualityMixin): mu = [] for i in range(n_energy): params, f = get_tab1_record(file_obj) + temperature = params[0] energy[i] = params[1] if f.n_regions > 1: raise NotImplementedError('Angular distribution with multiple ' @@ -287,6 +289,7 @@ class AngleDistribution(EqualityMixin): mu = [] for i in range(n_energy_legendre): items, al = get_list_record(file_obj) + temperature = items[0] energy_legendre[i] = items[1] coefficients = np.asarray([1.0] + al) mu.append(Legendre(coefficients)) @@ -297,6 +300,7 @@ class AngleDistribution(EqualityMixin): energy_tabulated = np.zeros(n_energy_tabulated) for i in range(n_energy_tabulated): params, f = get_tab1_record(file_obj) + temperature = params[0] energy_tabulated[i] = params[1] if f.n_regions > 1: raise NotImplementedError('Angular distribution with multiple ' diff --git a/openmc/data/angle_energy.py b/openmc/data/angle_energy.py index 71ca47587..b8fde5478 100644 --- a/openmc/data/angle_energy.py +++ b/openmc/data/angle_energy.py @@ -112,6 +112,7 @@ class AngleEnergy(EqualityMixin, ABC): distribution = openmc.data.NBodyPhaseSpace.from_ace( ace, idx, rx.q_value) else: - raise ValueError(f"Unsupported ACE secondary energy distribution law {law}") + raise ValueError("Unsupported ACE secondary energy " + "distribution law {}".format(law)) return distribution diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index 2ff095a5c..1aa4c20c8 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -58,46 +58,46 @@ class CorrelatedAngleEnergy(AngleEnergy): def breakpoints(self): return self._breakpoints + @property + def interpolation(self): + return self._interpolation + + @property + def energy(self): + return self._energy + + @property + def energy_out(self): + return self._energy_out + + @property + def mu(self): + return self._mu + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('correlated angle-energy breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints - @property - def interpolation(self): - return self._interpolation - @interpolation.setter def interpolation(self, interpolation): cv.check_type('correlated angle-energy interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('correlated angle-energy incoming energy', energy, Iterable, Real) self._energy = energy - @property - def energy_out(self): - return self._energy_out - @energy_out.setter def energy_out(self, energy_out): cv.check_type('correlated angle-energy outgoing energy', energy_out, Iterable, Univariate) self._energy_out = energy_out - @property - def mu(self): - return self._mu - @mu.setter def mu(self, mu): cv.check_iterable_type('correlated angle-energy outgoing cosine', @@ -113,7 +113,7 @@ class CorrelatedAngleEnergy(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_(self._name) + group.attrs['type'] = np.string_(self._name) dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, diff --git a/openmc/data/data.py b/openmc/data/data.py index 6e4840990..71b93293e 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -1,26 +1,11 @@ -from __future__ import annotations - import itertools import json import os import re from pathlib import Path from math import sqrt, log -from typing import TYPE_CHECKING, Literal from warnings import warn -from endf.data import (ATOMIC_NUMBER, ATOMIC_SYMBOL, ELEMENT_SYMBOL, - EV_PER_MEV, K_BOLTZMANN, gnds_name, zam) - -import openmc -from openmc.checkvalue import PathLike - -if TYPE_CHECKING: - from openmc.deplete import Chain - -gnds_name.__module__ = __name__ -zam.__module__ = __name__ - # Isotopic abundances from Meija J, Coplen T B, et al, "Isotopic compositions # of the elements 2013 (IUPAC Technical Report)", Pure. Appl. Chem. 88 (3), # pp. 293-306 (2013). The "representative isotopic abundance" values from @@ -109,7 +94,7 @@ NATURAL_ABUNDANCE = { 'Yb174': 0.32025, 'Yb176': 0.12995, 'Lu175': 0.97401, 'Lu176': 0.02599, 'Hf174': 0.0016, 'Hf176': 0.0526, 'Hf177': 0.186, 'Hf178': 0.2728, 'Hf179': 0.1362, - 'Hf180': 0.3508, 'Ta180_m1': 0.0001201, 'Ta181': 0.9998799, + 'Hf180': 0.3508, 'Ta180': 0.0001201, 'Ta181': 0.9998799, 'W180': 0.0012, 'W182': 0.265, 'W183': 0.1431, 'W184': 0.3064, 'W186': 0.2843, 'Re185': 0.374, 'Re187': 0.626, 'Os184': 0.0002, 'Os186': 0.0159, @@ -127,97 +112,80 @@ NATURAL_ABUNDANCE = { 'U238': 0.992742 } -DADZ = { - '(n,2nd)': (-3, -1), - '(n,2n)': (-1, 0), - '(n,3n)': (-2, 0), - '(n,na)': (-4, -2), - '(n,n3a)': (-12, -6), - '(n,2na)': (-5, -2), - '(n,3na)': (-6, -2), - '(n,np)': (-1, -1), - '(n,n2a)': (-8, -4), - '(n,2n2a)': (-9, -4), - '(n,nd)': (-2, -1), - '(n,nt)': (-3, -1), - '(n,n3He)': (-3, -2), - '(n,nd2a)': (-10, -5), - '(n,nt2a)': (-11, -5), - '(n,4n)': (-3, 0), - '(n,2np)': (-2, -1), - '(n,3np)': (-3, -1), - '(n,n2p)': (-2, -2), - '(n,npa)': (-5, -3), - '(n,gamma)': (1, 0), - '(n,p)': (0, -1), - '(n,d)': (-1, -1), - '(n,t)': (-2, -1), - '(n,3He)': (-2, -2), - '(n,a)': (-3, -2), - '(n,2a)': (-7, -4), - '(n,3a)': (-11, -6), - '(n,2p)': (-1, -2), - '(n,pa)': (-4, -3), - '(n,t2a)': (-10, -5), - '(n,d2a)': (-9, -5), - '(n,pd)': (-2, -2), - '(n,pt)': (-3, -2), - '(n,da)': (-5, -3), - '(n,5n)': (-4, 0), - '(n,6n)': (-5, 0), - '(n,2nt)': (-4, -1), - '(n,ta)': (-6, -3), - '(n,4np)': (-4, -1), - '(n,3nd)': (-4, -1), - '(n,nda)': (-6, -3), - '(n,2npa)': (-6, -3), - '(n,7n)': (-6, 0), - '(n,8n)': (-7, 0), - '(n,5np)': (-5, -1), - '(n,6np)': (-6, -1), - '(n,7np)': (-7, -1), - '(n,4na)': (-7, -2), - '(n,5na)': (-8, -2), - '(n,6na)': (-9, -2), - '(n,7na)': (-10, -2), - '(n,4nd)': (-5, -1), - '(n,5nd)': (-6, -1), - '(n,6nd)': (-7, -1), - '(n,3nt)': (-5, -1), - '(n,4nt)': (-6, -1), - '(n,5nt)': (-7, -1), - '(n,6nt)': (-8, -1), - '(n,2n3He)': (-4, -2), - '(n,3n3He)': (-5, -2), - '(n,4n3He)': (-6, -2), - '(n,3n2p)': (-4, -2), - '(n,3n2a)': (-10, -4), - '(n,3npa)': (-7, -3), - '(n,dt)': (-4, -2), - '(n,npd)': (-3, -2), - '(n,npt)': (-4, -2), - '(n,ndt)': (-5, -2), - '(n,np3He)': (-4, -3), - '(n,nd3He)': (-5, -3), - '(n,nt3He)': (-6, -3), - '(n,nta)': (-7, -3), - '(n,2n2p)': (-3, -2), - '(n,p3He)': (-4, -3), - '(n,d3He)': (-5, -3), - '(n,3Hea)': (-6, -4), - '(n,4n2p)': (-5, -2), - '(n,4n2a)': (-11, -4), - '(n,4npa)': (-8, -3), - '(n,3p)': (-2, -3), - '(n,n3p)': (-3, -3), - '(n,3n2pa)': (-8, -4), - '(n,5n2p)': (-6, -2), -} +# Dictionary to give element symbols from IUPAC names +# (and some common mispellings) +ELEMENT_SYMBOL = {'neutron': 'n', 'hydrogen': 'H', 'helium': 'He', + 'lithium': 'Li', 'beryllium': 'Be', 'boron': 'B', + 'carbon': 'C', 'nitrogen': 'N', 'oxygen': 'O', 'fluorine': 'F', + 'neon': 'Ne', 'sodium': 'Na', 'magnesium': 'Mg', + 'aluminium': 'Al', 'aluminum': 'Al', 'silicon': 'Si', + 'phosphorus': 'P', 'sulfur': 'S', 'sulphur': 'S', + 'chlorine': 'Cl', 'argon': 'Ar', 'potassium': 'K', + 'calcium': 'Ca', 'scandium': 'Sc', 'titanium': 'Ti', + 'vanadium': 'V', 'chromium': 'Cr', 'manganese': 'Mn', + 'iron': 'Fe', 'cobalt': 'Co', 'nickel': 'Ni', 'copper': 'Cu', + 'zinc': 'Zn', 'gallium': 'Ga', 'germanium': 'Ge', + 'arsenic': 'As', 'selenium': 'Se', 'bromine': 'Br', + 'krypton': 'Kr', 'rubidium': 'Rb', 'strontium': 'Sr', + 'yttrium': 'Y', 'zirconium': 'Zr', 'niobium': 'Nb', + 'molybdenum': 'Mo', 'technetium': 'Tc', 'ruthenium': 'Ru', + 'rhodium': 'Rh', 'palladium': 'Pd', 'silver': 'Ag', + 'cadmium': 'Cd', 'indium': 'In', 'tin': 'Sn', 'antimony': 'Sb', + 'tellurium': 'Te', 'iodine': 'I', 'xenon': 'Xe', + 'caesium': 'Cs', 'cesium': 'Cs', 'barium': 'Ba', + 'lanthanum': 'La', 'cerium': 'Ce', 'praseodymium': 'Pr', + 'neodymium': 'Nd', 'promethium': 'Pm', 'samarium': 'Sm', + 'europium': 'Eu', 'gadolinium': 'Gd', 'terbium': 'Tb', + 'dysprosium': 'Dy', 'holmium': 'Ho', 'erbium': 'Er', + 'thulium': 'Tm', 'ytterbium': 'Yb', 'lutetium': 'Lu', + 'hafnium': 'Hf', 'tantalum': 'Ta', 'tungsten': 'W', + 'wolfram': 'W', 'rhenium': 'Re', 'osmium': 'Os', + 'iridium': 'Ir', 'platinum': 'Pt', 'gold': 'Au', + 'mercury': 'Hg', 'thallium': 'Tl', 'lead': 'Pb', + 'bismuth': 'Bi', 'polonium': 'Po', 'astatine': 'At', + 'radon': 'Rn', 'francium': 'Fr', 'radium': 'Ra', + 'actinium': 'Ac', 'thorium': 'Th', 'protactinium': 'Pa', + 'uranium': 'U', 'neptunium': 'Np', 'plutonium': 'Pu', + 'americium': 'Am', 'curium': 'Cm', 'berkelium': 'Bk', + 'californium': 'Cf', 'einsteinium': 'Es', 'fermium': 'Fm', + 'mendelevium': 'Md', 'nobelium': 'No', 'lawrencium': 'Lr', + 'rutherfordium': 'Rf', 'dubnium': 'Db', 'seaborgium': 'Sg', + 'bohrium': 'Bh', 'hassium': 'Hs', 'meitnerium': 'Mt', + 'darmstadtium': 'Ds', 'roentgenium': 'Rg', 'copernicium': 'Cn', + 'nihonium': 'Nh', 'flerovium': 'Fl', 'moscovium': 'Mc', + 'livermorium': 'Lv', 'tennessine': 'Ts', 'oganesson': 'Og'} + +ATOMIC_SYMBOL = {0: 'n', 1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C', + 7: 'N', 8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mg', 13: 'Al', + 14: 'Si', 15: 'P', 16: 'S', 17: 'Cl', 18: 'Ar', 19: 'K', + 20: 'Ca', 21: 'Sc', 22: 'Ti', 23: 'V', 24: 'Cr', 25: 'Mn', + 26: 'Fe', 27: 'Co', 28: 'Ni', 29: 'Cu', 30: 'Zn', 31: 'Ga', + 32: 'Ge', 33: 'As', 34: 'Se', 35: 'Br', 36: 'Kr', 37: 'Rb', + 38: 'Sr', 39: 'Y', 40: 'Zr', 41: 'Nb', 42: 'Mo', 43: 'Tc', + 44: 'Ru', 45: 'Rh', 46: 'Pd', 47: 'Ag', 48: 'Cd', 49: 'In', + 50: 'Sn', 51: 'Sb', 52: 'Te', 53: 'I', 54: 'Xe', 55: 'Cs', + 56: 'Ba', 57: 'La', 58: 'Ce', 59: 'Pr', 60: 'Nd', 61: 'Pm', + 62: 'Sm', 63: 'Eu', 64: 'Gd', 65: 'Tb', 66: 'Dy', 67: 'Ho', + 68: 'Er', 69: 'Tm', 70: 'Yb', 71: 'Lu', 72: 'Hf', 73: 'Ta', + 74: 'W', 75: 'Re', 76: 'Os', 77: 'Ir', 78: 'Pt', 79: 'Au', + 80: 'Hg', 81: 'Tl', 82: 'Pb', 83: 'Bi', 84: 'Po', 85: 'At', + 86: 'Rn', 87: 'Fr', 88: 'Ra', 89: 'Ac', 90: 'Th', 91: 'Pa', + 92: 'U', 93: 'Np', 94: 'Pu', 95: 'Am', 96: 'Cm', 97: 'Bk', + 98: 'Cf', 99: 'Es', 100: 'Fm', 101: 'Md', 102: 'No', + 103: 'Lr', 104: 'Rf', 105: 'Db', 106: 'Sg', 107: 'Bh', + 108: 'Hs', 109: 'Mt', 110: 'Ds', 111: 'Rg', 112: 'Cn', + 113: 'Nh', 114: 'Fl', 115: 'Mc', 116: 'Lv', 117: 'Ts', + 118: 'Og'} +ATOMIC_NUMBER = {value: key for key, value in ATOMIC_SYMBOL.items()} # Values here are from the Committee on Data for Science and Technology # (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/). +# The value of the Boltzman constant in units of eV / K +K_BOLTZMANN = 8.617333262e-5 + # Unit conversions +EV_PER_MEV = 1.0e6 JOULE_PER_EV = 1.602176634e-19 # Avogadro's constant @@ -227,17 +195,20 @@ AVOGADRO = 6.02214076e23 NEUTRON_MASS = 1.00866491595 # Used in atomic_mass function as a cache -_ATOMIC_MASS: dict[str, float] = {} +_ATOMIC_MASS = {} + +# Regex for GND nuclide names (used in zam function) +_GND_NAME_RE = re.compile(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)') # Used in half_life function as a cache -_HALF_LIFE: dict[str, float] = {} +_HALF_LIFE = {} _LOG_TWO = log(2.0) def atomic_mass(isotope): """Return atomic mass of isotope in atomic mass units. - Atomic mass data comes from the `Atomic Mass Evaluation 2020 - `_. + Atomic mass data comes from the `Atomic Mass Evaluation 2016 + `_. Parameters ---------- @@ -252,21 +223,21 @@ def atomic_mass(isotope): """ if not _ATOMIC_MASS: - # Load data from AME2020 file - mass_file = os.path.join(os.path.dirname(__file__), 'mass_1.mas20.txt') + # Load data from AME2016 file + mass_file = os.path.join(os.path.dirname(__file__), 'mass16.txt') with open(mass_file, 'r') as ame: - # Read lines in file starting at line 37 - for line in itertools.islice(ame, 36, None): - name = f'{line[20:22].strip()}{int(line[16:19])}' - mass = float(line[106:109]) + 1e-6*float( - line[110:116] + '.' + line[117:123]) + # Read lines in file starting at line 40 + for line in itertools.islice(ame, 39, None): + name = '{}{}'.format(line[20:22].strip(), int(line[16:19])) + mass = float(line[96:99]) + 1e-6*float( + line[100:106] + '.' + line[107:112]) _ATOMIC_MASS[name.lower()] = mass # For isotopes found in some libraries that represent all natural # isotopes of their element (e.g. C0), calculate the atomic mass as - # the sum of the atomic mass times the natural abundance of the isotopes + # the sum of the atomic mass times the natural abudance of the isotopes # that make up the element. - for element in ['C', 'Zn', 'Pt', 'Os', 'Tl', 'V']: + for element in ['C', 'Zn', 'Pt', 'Os', 'Tl']: isotope_zero = element.lower() + '0' _ATOMIC_MASS[isotope_zero] = 0. for iso, abundance in isotopes(element): @@ -302,50 +273,29 @@ def atomic_weight(element): if weight > 0.: return weight else: - raise ValueError(f"No naturally-occurring isotopes for element '{element}'.") + raise ValueError("No naturally-occurring isotopes for element '{}'." + .format(element)) -def half_life( - isotope: str, - chain_file: Literal[False] | None | PathLike | Chain = False -) -> float | None: +def half_life(isotope): """Return half-life of isotope in seconds or None if isotope is stable - By default, half-life values are from the `ENDF/B-VIII.0 decay sublibrary - `_. A depletion chain can - also be used as the source of half-life values. + Half-life values are from the `ENDF/B-VIII.0 decay sublibrary + `_. .. versionadded:: 0.13.1 - .. versionchanged:: 0.15.4 - Added the ``chain_file`` argument. - Parameters ---------- isotope : str Name of isotope, e.g., 'Pu239' - chain_file : False, None, PathLike, or openmc.deplete.Chain, optional - Source of half-life values. If ``False``, only ENDF/B-VIII.0 data is - used. If ``None``, the chain specified by - ``openmc.config['chain_file']`` is used when available. If a path or - :class:`openmc.deplete.Chain` is given, that chain is used. For ``None`` - or an explicit chain, nuclides absent from the chain fall back to - ENDF/B-VIII.0 data. Returns ------- - float or None - Half-life of isotope in [s], or None if the isotope is stable + float + Half-life of isotope in [s] """ - if chain_file is not False: - if chain_file is not None or openmc.config.get('chain_file') is not None: - # Local import avoids a circular dependency - from openmc.deplete.chain import _get_chain - chain = _get_chain(chain_file) - if isotope in chain: - return chain[isotope].half_life - global _HALF_LIFE if not _HALF_LIFE: # Load ENDF/B-VIII.0 data from JSON file @@ -355,10 +305,7 @@ def half_life( return _HALF_LIFE.get(isotope.lower()) -def decay_constant( - isotope: str, - chain_file: Literal[False] | None | PathLike | Chain = False -) -> float: +def decay_constant(isotope): """Return decay constant of isotope in [s^-1] Decay constants are based on half-life values from the @@ -367,20 +314,10 @@ def decay_constant( .. versionadded:: 0.13.1 - .. versionchanged:: 0.15.4 - Added the ``chain_file`` argument. - Parameters ---------- isotope : str Name of isotope, e.g., 'Pu239' - chain_file : False, None, PathLike, or openmc.deplete.Chain, optional - Source of half-life values. If ``False``, only ENDF/B-VIII.0 data is - used. If ``None``, the chain specified by - ``openmc.config['chain_file']`` is used when available. If a path or - :class:`openmc.deplete.Chain` is given, that chain is used. For ``None`` - or an explicit chain, nuclides absent from the chain fall back to - ENDF/B-VIII.0 data. Returns ------- @@ -392,7 +329,7 @@ def decay_constant( openmc.data.half_life """ - t = half_life(isotope, chain_file) + t = half_life(isotope) return _LOG_TWO / t if t else 0.0 @@ -500,17 +437,31 @@ def water_density(temperature, pressure=0.1013): return coeff / pi / gamma1_pi -def _get_element_symbol(element: str) -> str: - if len(element) > 2: - symbol = ELEMENT_SYMBOL.get(element.lower()) - if symbol is None: - raise ValueError(f'Element name "{element}" not recognized') - return symbol +def gnd_name(Z, A, m=0): + """Return nuclide name using GND convention + + Parameters + ---------- + Z : int + Atomic number + A : int + Mass number + m : int, optional + Metastable state + + Returns + ------- + str + Nuclide name in GND convention, e.g., 'Am242_m1' + + """ + if m > 0: + return '{}{}_m{}'.format(ATOMIC_SYMBOL[Z], A, m) else: - return element + return '{}{}'.format(ATOMIC_SYMBOL[Z], A) -def isotopes(element: str) -> list[tuple[str, float]]: +def isotopes(element): """Return naturally occurring isotopes and their abundances .. versionadded:: 0.12.1 @@ -531,12 +482,45 @@ def isotopes(element: str) -> list[tuple[str, float]]: If the element name is not recognized """ - element = _get_element_symbol(element) + # Convert name to symbol if needed + if len(element) > 2: + symbol = ELEMENT_SYMBOL.get(element.lower()) + if symbol is None: + raise ValueError('Element name "{}" not recognised'.format(element)) + element = symbol # Get the nuclides present in nature result = [] - for kv in NATURAL_ABUNDANCE.items(): + for kv in sorted(NATURAL_ABUNDANCE.items()): if re.match(r'{}\d+'.format(element), kv[0]): result.append(kv) return result + + +def zam(name): + """Return tuple of (atomic number, mass number, metastable state) + + Parameters + ---------- + name : str + Name of nuclide using GND convention, e.g., 'Am242_m1' + + Returns + ------- + 3-tuple of int + Atomic number, mass number, and metastable state + + """ + try: + symbol, A, state = _GND_NAME_RE.match(name).groups() + except AttributeError: + raise ValueError("'{}' does not appear to be a nuclide name in GND " + "format".format(name)) + + if symbol not in ATOMIC_NUMBER: + raise ValueError("'{}' is not a recognized element symbol" + .format(symbol)) + + metastable = int(state[2:]) if state else 0 + return (ATOMIC_NUMBER[symbol], int(A), metastable) diff --git a/openmc/data/decay.py b/openmc/data/decay.py index 5f95e1281..2c2505bf5 100644 --- a/openmc/data/decay.py +++ b/openmc/data/decay.py @@ -1,21 +1,18 @@ from collections.abc import Iterable -from functools import cached_property from io import StringIO from math import log +import re from warnings import warn import numpy as np from uncertainties import ufloat, UFloat -import openmc import openmc.checkvalue as cv -from openmc.exceptions import DataError from openmc.mixin import EqualityMixin -from openmc.stats import Discrete, Tabular, Univariate, combine_distributions -from .data import gnds_name, zam +from openmc.stats import Discrete, Tabular, combine_distributions +from .data import ATOMIC_SYMBOL, ATOMIC_NUMBER from .function import INTERPOLATION_SCHEME -from .endf import ( - as_evaluation, get_head_record, get_list_record, get_tab1_record) +from .endf import Evaluation, get_head_record, get_list_record, get_tab1_record # Gives name and (change in A, change in Z) resulting from decay @@ -76,7 +73,7 @@ class FissionProductYields(EqualityMixin): Parameters ---------- - ev_or_filename : str, openmc.data.endf.Evaluation, or endf.Material + ev_or_filename : str of openmc.data.endf.Evaluation ENDF fission product yield evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -126,7 +123,9 @@ class FissionProductYields(EqualityMixin): for j in range(n_products): Z, A = divmod(int(values[4*j]), 1000) isomeric_state = int(values[4*j + 1]) - name = gnds_name(Z, A, isomeric_state) + name = ATOMIC_SYMBOL[Z] + str(A) + if isomeric_state > 0: + name += '_m{}'.format(isomeric_state) yield_j = ufloat(values[4*j + 2], values[4*j + 3]) yields[name] = yield_j @@ -134,11 +133,15 @@ class FissionProductYields(EqualityMixin): return energies, data - ev = as_evaluation(ev_or_filename) + # Get evaluation if str is passed + if isinstance(ev_or_filename, Evaluation): + ev = ev_or_filename + else: + ev = Evaluation(ev_or_filename) # Assign basic nuclide properties self.nuclide = { - 'name': ev.gnds_name, + 'name': ev.gnd_name, 'atomic_number': ev.target['atomic_number'], 'mass_number': ev.target['mass_number'], 'isomeric_state': ev.target['isomeric_state'] @@ -161,7 +164,7 @@ class FissionProductYields(EqualityMixin): Parameters ---------- - ev_or_filename : str, openmc.data.endf.Evaluation, or endf.Material + ev_or_filename : str or openmc.data.endf.Evaluation ENDF fission product yield evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -222,6 +225,39 @@ class DecayMode(EqualityMixin): def branching_ratio(self): return self._branching_ratio + @property + def daughter(self): + # Determine atomic number and mass number of parent + symbol, A = re.match(r'([A-Zn][a-z]*)(\d+)', self.parent).groups() + A = int(A) + Z = ATOMIC_NUMBER[symbol] + + # Process changes + for mode in self.modes: + for name, changes in _DECAY_MODES.values(): + if name == mode: + if changes is not None: + delta_A, delta_Z = changes + A += delta_A + Z += delta_Z + + if self._daughter_state > 0: + return '{}{}_m{}'.format(ATOMIC_SYMBOL[Z], A, self._daughter_state) + else: + return '{}{}'.format(ATOMIC_SYMBOL[Z], A) + + @property + def energy(self): + return self._energy + + @property + def modes(self): + return self._modes + + @property + def parent(self): + return self._parent + @branching_ratio.setter def branching_ratio(self, branching_ratio): cv.check_type('branching ratio', branching_ratio, UFloat) @@ -234,38 +270,6 @@ class DecayMode(EqualityMixin): branching_ratio.std_dev, 0.0, True) self._branching_ratio = branching_ratio - @property - def daughter(self): - # Determine atomic number and mass number of parent - Z, A, _ = zam(self.parent) - - # Process changes - for mode in self.modes: - for name, changes in _DECAY_MODES.values(): - if name == mode: - if changes is not None: - delta_A, delta_Z = changes - A += delta_A - Z += delta_Z - break - else: - return None - - return gnds_name(Z, A, self._daughter_state) - - @property - def parent(self): - return self._parent - - @parent.setter - def parent(self, parent): - cv.check_type('parent nuclide', parent, str) - self._parent = parent - - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('decay energy', energy, UFloat) @@ -274,22 +278,23 @@ class DecayMode(EqualityMixin): energy.std_dev, 0.0, True) self._energy = energy - @property - def modes(self): - return self._modes - @modes.setter def modes(self, modes): cv.check_type('decay modes', modes, Iterable, str) self._modes = modes + @parent.setter + def parent(self, parent): + cv.check_type('parent nuclide', parent, str) + self._parent = parent + class Decay(EqualityMixin): """Radioactive decay data. Parameters ---------- - ev_or_filename : str, openmc.data.endf.Evaluation, or endf.Material + ev_or_filename : str of openmc.data.endf.Evaluation ENDF radioactive decay data evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -320,7 +325,11 @@ class Decay(EqualityMixin): """ def __init__(self, ev_or_filename): - ev = as_evaluation(ev_or_filename) + # Get evaluation if str is passed + if isinstance(ev_or_filename, Evaluation): + ev = ev_or_filename + else: + ev = Evaluation(ev_or_filename) file_obj = StringIO(ev.section[8, 457]) @@ -328,6 +337,7 @@ class Decay(EqualityMixin): self.modes = [] self.spectra = {} self.average_energies = {} + self._sources = None # Get head record items = get_head_record(file_obj) @@ -336,7 +346,11 @@ class Decay(EqualityMixin): self.nuclide['atomic_number'] = Z self.nuclide['mass_number'] = A self.nuclide['isomeric_state'] = metastable - self.nuclide['name'] = gnds_name(Z, A, metastable) + if metastable > 0: + self.nuclide['name'] = '{}{}_m{}'.format(ATOMIC_SYMBOL[Z], A, + metastable) + else: + self.nuclide['name'] = '{}{}'.format(ATOMIC_SYMBOL[Z], A) self.nuclide['mass'] = items[1] # AWR self.nuclide['excited_state'] = items[2] # State of the original nuclide self.nuclide['stable'] = (items[4] == 1) # Nucleus stability flag @@ -479,7 +493,7 @@ class Decay(EqualityMixin): Parameters ---------- - ev_or_filename : str, openmc.data.endf.Evaluation, or endf.Material + ev_or_filename : str or openmc.data.endf.Evaluation ENDF radioactive decay data evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -491,9 +505,14 @@ class Decay(EqualityMixin): """ return cls(ev_or_filename) - @cached_property + @property def sources(self): """Radioactive decay source distributions""" + # If property has been computed already, return it + # TODO: Replace with functools.cached_property when support is Python 3.9+ + if self._sources is not None: + return self._sources + sources = {} name = self.nuclide['name'] decay_constant = self.decay_constant.n @@ -536,9 +555,7 @@ class Decay(EqualityMixin): raise NotImplementedError("Multiple interpolation regions: {name}, {particle}") interpolation = INTERPOLATION_SCHEME[f.interpolation[0]] if interpolation not in ('histogram', 'linear-linear'): - warn( - f"Continuous spectra with {interpolation} interpolation " - f"({name}, {particle}) encountered.") + raise NotImplementedError("Continuous spectra with {interpolation} interpolation ({name}, {particle}) not supported") intensity = spectra['continuous_normalization'].n rates = decay_constant * intensity * f.y @@ -551,94 +568,5 @@ class Decay(EqualityMixin): merged_sources[particle_type] = combine_distributions( dist_list, [1.0]*len(dist_list)) - return merged_sources - - -_DECAY_PHOTON_ENERGY = {} - - -def decay_photon_energy(nuclide: str) -> Univariate | None: - """Get photon energy distribution resulting from the decay of a nuclide - - This function relies on data stored in a depletion chain. Before calling it - for the first time, you need to ensure that a depletion chain has been - specified in openmc.config['chain_file']. - - .. versionadded:: 0.13.2 - - Parameters - ---------- - nuclide : str - Name of nuclide, e.g., 'Co58' - - Returns - ------- - openmc.stats.Univariate or None - Distribution of energies in [eV] of photons emitted from decay, or None - if no photon source exists. Note that the probabilities represent - intensities, given as [Bq/atom] (in other words, decay constants). - """ - if not _DECAY_PHOTON_ENERGY: - chain_file = openmc.config.get('chain_file') - if chain_file is None: - raise DataError( - "A depletion chain file must be specified with " - "openmc.config['chain_file'] in order to load decay data." - ) - - from openmc.deplete import Chain - chain = Chain.from_xml(chain_file) - for nuc in chain.nuclides: - if 'photon' in nuc.sources: - _DECAY_PHOTON_ENERGY[nuc.name] = nuc.sources['photon'] - - # If the chain file contained no sources at all, warn the user - if not _DECAY_PHOTON_ENERGY: - warn(f"Chain file '{chain_file}' does not have any decay photon " - "sources listed.") - - return _DECAY_PHOTON_ENERGY.get(nuclide) - - -_DECAY_ENERGY = {} - - -def decay_energy(nuclide: str): - """Get decay energy value resulting from the decay of a nuclide - - This function relies on data stored in a depletion chain. Before calling it - for the first time, you need to ensure that a depletion chain has been - specified in openmc.config['chain_file']. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - nuclide : str - Name of nuclide, e.g., 'H3' - - Returns - ------- - float - Decay energy of nuclide in [eV]. If the nuclide is stable, a value of - 0.0 is returned. - """ - if not _DECAY_ENERGY: - chain_file = openmc.config.get('chain_file') - if chain_file is None: - raise DataError( - "A depletion chain file must be specified with " - "openmc.config['chain_file'] in order to load decay data." - ) - - from openmc.deplete import Chain - chain = Chain.from_xml(chain_file) - for nuc in chain.nuclides: - if nuc.decay_energy: - _DECAY_ENERGY[nuc.name] = nuc.decay_energy - - # If the chain file contained no decay energy, warn the user - if not _DECAY_ENERGY: - warn(f"Chain file '{chain_file}' does not have any decay energy.") - - return _DECAY_ENERGY.get(nuclide, 0.0) + self._sources = merged_sources + return self._sources diff --git a/openmc/data/dose/dose.py b/openmc/data/dose/dose.py deleted file mode 100644 index 87e0cf9ae..000000000 --- a/openmc/data/dose/dose.py +++ /dev/null @@ -1,146 +0,0 @@ -from pathlib import Path - -import numpy as np - -import openmc.checkvalue as cv - -_FULL_GEOMETRIES = ('AP', 'PA', 'LLAT', 'RLAT', 'ROT', 'ISO') -_LIMITED_GEOMETRIES = ('AP', 'PA', 'ISO') - -_TABLES = { - ('icrp74', 'effective', 'neutron'): ( - Path('icrp74') / 'neutrons.txt', _FULL_GEOMETRIES), - ('icrp74', 'effective', 'photon'): ( - Path('icrp74') / 'photons.txt', _FULL_GEOMETRIES), - ('icrp116', 'effective', 'electron'): ( - Path('icrp116') / 'electrons.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'helium'): ( - Path('icrp116') / 'helium_ions.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'mu-'): ( - Path('icrp116') / 'negative_muons.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'pi-'): ( - Path('icrp116') / 'negative_pions.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'neutron'): ( - Path('icrp116') / 'neutrons.txt', _FULL_GEOMETRIES), - ('icrp116', 'effective', 'photon'): ( - Path('icrp116') / 'photons.txt', _FULL_GEOMETRIES), - ('icrp116', 'effective', 'photon kerma'): ( - Path('icrp116') / 'photons_kerma.txt', _FULL_GEOMETRIES), - ('icrp116', 'effective', 'mu+'): ( - Path('icrp116') / 'positive_muons.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'pi+'): ( - Path('icrp116') / 'positive_pions.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'positron'): ( - Path('icrp116') / 'positrons.txt', _LIMITED_GEOMETRIES), - ('icrp116', 'effective', 'proton'): ( - Path('icrp116') / 'protons.txt', _FULL_GEOMETRIES), - ('icrp74', 'ambient', 'neutron'): ( - Path('icrp74') / 'neutrons_H10.txt', None), - ('icrp74', 'ambient', 'photon'): ( - Path('icrp74') / 'photons_H10.txt', None), -} - -_DOSE_TABLES = {} - - -def _load_dose_table(data_source: str, dose_quantity: str, particle: str): - """Load dose tables from text files. - - Parameters - ---------- - data_source : {'icrp74', 'icrp116'} - The dose conversion data source to use - dose_quantity : {'effective', 'ambient'} - Dose quantity to load. 'ambient' corresponds to ambient dose - equivalent H*(10). - particle : {'neutron', 'photon', 'photon kerma', 'electron', 'positron'} - Incident particle - - """ - key = (data_source, dose_quantity, particle) - path = Path(__file__).parent / _TABLES[key][0] - data = np.loadtxt(path, skiprows=3, encoding='utf-8') - data[:, 0] *= 1e6 # Change energies to eV - _DOSE_TABLES[key] = data - - -def dose_coefficients( - particle, geometry='AP', data_source='icrp116', dose_quantity='effective' -): - """Return dose conversion coefficients. - - This function provides fluence (and air kerma) to effective dose or ambient - dose equivalent (H*(10)) conversion coefficients for various types of - external exposures based on values in ICRP publications. Corrected values - found in a corrigendum are used rather than the values in the original - report. Available libraries include `ICRP Publication 74 - ` and `ICRP Publication 116 - `. - - For ICRP 74 data, the photon effective dose per fluence is determined by - multiplying the air kerma per fluence values (Table A.1) by the effective - dose per air kerma (Table A.17). The neutron effective dose per fluence is - found in Table A.41. For ICRP 116 data, the photon effective dose per - fluence is found in Table A.1 and the neutron effective dose per fluence is - found in Table A.5. - - Parameters - ---------- - particle : {'neutron', 'photon', 'photon kerma', 'electron', 'positron'} - Incident particle - geometry : {'AP', 'PA', 'LLAT', 'RLAT', 'ROT', 'ISO'} - Irradiation geometry assumed for effective dose coefficients. Refer to - ICRP-116 (Section 3.2) for the meaning of the options here. This - argument does not apply when ``dose_quantity`` is 'ambient'. - data_source : {'icrp74', 'icrp116'} - The data source for the dose conversion coefficients. - dose_quantity : {'effective', 'ambient'} - Dose quantity to return. 'effective' returns effective dose - coefficients; 'ambient' returns ambient dose equivalent (H*(10)) - coefficients. - - Returns - ------- - energy : numpy.ndarray - Energies at which dose conversion coefficients are given - dose_coeffs : numpy.ndarray - Dose coefficients in [pSv cm^2] at provided energies. For 'photon - kerma', the coefficients are given in [Sv/Gy]. - - """ - - cv.check_value('geometry', geometry, _FULL_GEOMETRIES) - cv.check_value('data_source', data_source, {'icrp74', 'icrp116'}) - cv.check_value('dose_quantity', dose_quantity, {'effective', 'ambient'}) - - key = (data_source, dose_quantity, particle) - if key not in _TABLES: - available_particles = sorted( - p for ds, dq, p in _TABLES - if ds == data_source and dq == dose_quantity - ) - msg = ( - f"'{particle}' has no {dose_quantity} dose data in data source " - f"{data_source}. Available particles for {data_source} " - f"with dose quantity {dose_quantity} are: {available_particles}" - ) - raise ValueError(msg) - elif key not in _DOSE_TABLES: - _load_dose_table(data_source, dose_quantity, particle) - - data = _DOSE_TABLES[key] - columns = _TABLES[key][1] - - if columns is None: - if geometry != 'AP': - raise ValueError( - "Irradiation geometry is not defined for ambient dose " - "equivalent coefficients. Use the default geometry='AP'." - ) - index = 0 - else: - index = columns.index(geometry) - - energy = data[:, 0].copy() - dose_coeffs = data[:, index + 1].copy() - return energy, dose_coeffs diff --git a/openmc/data/dose/icrp74/generate_photon_effective_dose.py b/openmc/data/dose/icrp74/generate_photon_effective_dose.py deleted file mode 100644 index f8e970137..000000000 --- a/openmc/data/dose/icrp74/generate_photon_effective_dose.py +++ /dev/null @@ -1,69 +0,0 @@ -from prettytable import PrettyTable -import numpy as np - -# Data from Table A.1 (air kerma per fluence) -energy_a1 = np.array([ - 0.01, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.1, 0.15, 0.2, - 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0 -]) -air_kerma = np.array([7.43, 3.12, 1.68, 0.721, 0.429, 0.323, 0.289, 0.307, 0.371, 0.599, 0.856, 1.38, - 1.89, 2.38, 2.84, 3.69, 4.47, 6.14, 7.55, 9.96, 12.1, 14.1, 16.1, 20.1, 24.0]) - -# Data from Table A.17 (effective dose per air kerma) -energy_a17 = np.array([ - 0.01, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.15, 0.2, 0.3, - 0.4, 0.5, 0.6, 0.8, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0 -]) -dose_per_airkerma = { - 'AP': np.array([ - 0.00653, 0.0402, 0.122, 0.416, 0.788, 1.106, 1.308, 1.407, 1.433, 1.394, - 1.256, 1.173, 1.093, 1.056, 1.036, 1.024, 1.010, 1.003, 0.992, 0.993, - 0.993, 0.991, 0.990 - ]), - 'PA': np.array([ - 0.00248, 0.00586, 0.0181, 0.128, 0.370, 0.640, 0.846, 0.966, 1.019, - 1.030, 0.959, 0.915, 0.880, 0.871, 0.869, 0.870, 0.875, 0.880, 0.901, - 0.918, 0.924, 0.927, 0.929 - ]), - 'RLAT': np.array([ - 0.00172, 0.00549, 0.0151, 0.0782, 0.205, 0.345, 0.455, 0.522, 0.554, - 0.571, 0.551, 0.549, 0.557, 0.570, 0.585, 0.600, 0.628, 0.651, 0.728, - 0.796, 0.827, 0.846, 0.860 - ]), - 'LLAT': np.array([ - 0.00172, 0.00549, 0.0155, 0.0904, 0.241, 0.405, 0.528, 0.598, 0.628, - 0.641, 0.620, 0.615, 0.615, 0.623, 0.635, 0.648, 0.670, 0.691, 0.757, - 0.813, 0.836, 0.850, 0.859 - ]), - 'ROT': np.array([ - 0.00326, 0.0153, 0.0462, 0.191, 0.426, 0.661, 0.828, 0.924, 0.961, - 0.960, 0.892, 0.854, 0.824, 0.814, 0.812, 0.814, 0.821, 0.831, 0.871, - 0.909, 0.925, 0.934, 0.941 - ]), - 'ISO': np.array([ - 0.00271, 0.0123, 0.0362, 0.143, 0.326, 0.511, 0.642, 0.720, 0.749, - 0.748, 0.700, 0.679, 0.664, 0.667, 0.675, 0.684, 0.703, 0.719, 0.774, - 0.824, 0.846, 0.859, 0.868 - ]) -} - -# Interpolate air kerma onto energy grid for Table A.17 -air_kerma = np.interp(energy_a17, energy_a1, air_kerma) - -# Compute effective dose per fluence -dose_per_fluence = { - geometry: air_kerma * dose_per_airkerma - for geometry, dose_per_airkerma in dose_per_airkerma.items() -} - -# Create table -table = PrettyTable() -table.field_names = ['Energy (MeV)', 'AP', 'PA', 'LLAT', 'RLAT', 'ROT', 'ISO'] -table.float_format = '.7' -for i, energy in enumerate(energy_a17): - row = [energy] - for geometry in table.field_names[1:]: - row.append(dose_per_fluence[geometry][i]) - table.add_row(row) -print('Photons: Effective dose per fluence, in units of pSv cm², for monoenergetic particles incident in various geometries.\n') -print(table.get_string(border=False)) diff --git a/openmc/data/dose/icrp74/neutrons.txt b/openmc/data/dose/icrp74/neutrons.txt deleted file mode 100644 index 14aab48bd..000000000 --- a/openmc/data/dose/icrp74/neutrons.txt +++ /dev/null @@ -1,50 +0,0 @@ -Neutrons: Effective dose per fluence, in units of pSv cm², for monoenergetic particles incident in various geometries. - -Energy (MeV) AP PA LLAT RLAT ROT ISO -1.00E-09 5.24 3.52 1.68 1.36 2.99 2.4 -1.00E-08 6.55 4.39 2.04 1.7 3.72 2.89 -2.50E-08 7.6 5.16 2.31 1.99 4.4 3.3 -1.00E-07 9.95 6.77 2.86 2.58 5.75 4.13 -2.00E-07 11.2 7.63 3.21 2.92 6.43 4.59 -5.00E-07 12.8 8.76 3.72 3.35 7.27 5.2 -1.00E-06 13.8 9.55 4.12 3.67 7.84 5.63 -2.00E-06 14.5 10.2 4.39 3.89 8.31 5.96 -5.00E-06 15 10.7 4.66 4.08 8.72 6.28 -1.00E-05 15.1 11 4.8 4.16 8.9 6.44 -2.00E-05 15.1 11.1 4.89 4.2 8.92 6.51 -5.00E-05 14.8 11.1 4.95 4.19 8.82 6.51 -1.00E-04 14.6 11 4.95 4.15 8.69 6.45 -2.00E-04 14.4 10.9 4.92 4.1 8.56 6.32 -5.00E-04 14.2 10.7 4.86 4.03 8.4 6.14 -1.00E-03 14.2 10.7 4.84 4 8.34 6.04 -2.00E-03 14.4 10.8 4.87 4 8.39 6.05 -5.00E-03 15.7 11.6 5.25 4.29 9.06 6.52 -1.00E-02 18.3 13.5 6.14 5.02 10.6 7.7 -2.00E-02 23.8 17.3 7.95 6.48 13.8 10.2 -3.00E-02 29 21 9.74 7.93 16.9 12.7 -5.00E-02 38.5 27.6 13.1 10.6 22.7 17.3 -7.00E-02 47.2 33.5 16.1 13.1 27.8 21.5 -1.00E-01 59.8 41.3 20.1 16.4 34.8 27.2 -1.50E-01 80.2 52.2 25.5 21.2 45.4 35.2 -2.00E-01 99 61.5 30.3 25.6 54.8 42.4 -3.00E-01 133 77.1 38.6 33.4 71.6 54.7 -5.00E-01 188 103 53.2 46.8 99.4 75 -7.00E-01 231 124 66.6 58.3 123 92.8 -9.00E-01 267 144 79.6 69.1 144 108 -1 282 154 86 74.5 154 116 -1.2 310 175 99.8 85.8 173 130 -2 383 247 153 129 234 178 -3 432 308 195 171 283 220 -4 458 345 224 198 315 250 -5 474 366 244 217 335 272 -6 483 380 261 232 348 282 -7 490 391 274 244 358 290 -8 494 399 285 253 366 297 -9 497 406 294 261 373 303 -1.00E+01 499 412 302 268 378 309 -1.20E+01 499 422 315 278 385 322 -1.40E+01 496 429 324 286 390 333 -1.50E+01 494 431 328 290 391 338 -1.60E+01 491 433 331 293 393 342 -1.80E+01 486 435 335 299 394 345 -2.00E+01 480 436 338 305 395 343 diff --git a/openmc/data/dose/icrp74/neutrons_H10.txt b/openmc/data/dose/icrp74/neutrons_H10.txt deleted file mode 100644 index fe0036cbc..000000000 --- a/openmc/data/dose/icrp74/neutrons_H10.txt +++ /dev/null @@ -1,50 +0,0 @@ -Neutrons: Ambient per fluence, in units of pSv cm², for monoenergetic particles incident. - -Energy (MeV) Dose - 1.00E-09 6.60 - 1.00E-08 9.00 - 2.53E-08 10.6 - 1.00E-07 12.9 - 2.00E-07 13.5 - 5.00E-07 13.6 - 1.00E-06 13.3 - 2.00E-06 12.9 - 5.00E-06 12.0 - 1.00E-05 11.3 - 2.00E-05 10.6 - 5.00E-05 9.90 - 1.00E-04 9.40 - 2.00E-04 8.90 - 5.00E-04 8.30 - 1.00E-03 7.90 - 2.00E-03 7.70 - 5.00E-03 8.00 - 1.00E-02 10.5 - 2.00E-02 16.6 - 3.00E-02 23.7 - 5.00E-02 41.1 - 7.00E-02 60.0 - 1.00E-01 88.0 - 1.50E-01 132 - 2.00E-01 170 - 3.00E-01 233 - 5.00E-01 322 - 7.00E-01 375 - 9.00E-01 400 - 1 416 - 1.2 425 - 2 420 - 3 412 - 4 408 - 5 405 - 6 400 - 7 405 - 8 409 - 9 420 - 10 440 - 12 480 - 14 520 - 15 540 - 16 555 - 18 570 - 20 600 \ No newline at end of file diff --git a/openmc/data/dose/icrp74/photons.txt b/openmc/data/dose/icrp74/photons.txt deleted file mode 100644 index 1ce3d67e0..000000000 --- a/openmc/data/dose/icrp74/photons.txt +++ /dev/null @@ -1,26 +0,0 @@ -Photons: Effective dose per fluence, in units of pSv cm², for monoenergetic particles incident in various geometries. - - Energy (MeV) AP PA LLAT RLAT ROT ISO - 0.0100000 0.0485179 0.0184264 0.0127796 0.0127796 0.0242218 0.0201353 - 0.0150000 0.1254240 0.0182832 0.0171288 0.0171288 0.0477360 0.0383760 - 0.0200000 0.2049600 0.0304080 0.0260400 0.0253680 0.0776160 0.0608160 - 0.0300000 0.2999360 0.0922880 0.0651784 0.0563822 0.1377110 0.1031030 - 0.0400000 0.3380520 0.1587300 0.1033890 0.0879450 0.1827540 0.1398540 - 0.0500000 0.3572380 0.2067200 0.1308150 0.1114350 0.2135030 0.1650530 - 0.0600000 0.3780120 0.2444940 0.1525920 0.1314950 0.2392920 0.1855380 - 0.0700000 0.4192860 0.2878680 0.1782040 0.1555560 0.2753520 0.2145600 - 0.0800000 0.4399310 0.3128330 0.1927960 0.1700780 0.2950270 0.2299430 - 0.1000000 0.5171740 0.3821300 0.2378110 0.2118410 0.3561600 0.2775080 - 0.1500000 0.7523440 0.5744410 0.3713800 0.3300490 0.5343080 0.4193000 - 0.2000000 1.0040880 0.7832400 0.5264400 0.4699440 0.7310240 0.5812240 - 0.3000000 1.5083400 1.2144000 0.8487000 0.7686600 1.1371200 0.9163200 - 0.4000000 1.9958400 1.6461900 1.1774700 1.0773000 1.5384600 1.2606300 - 0.5000000 2.4656800 2.0682200 1.5113000 1.3923000 1.9325600 1.6065000 - 0.6000000 2.9081600 2.4708000 1.8403200 1.7040000 2.3117600 1.9425600 - 0.8000000 3.7269000 3.2287500 2.4723000 2.3173200 3.0294900 2.5940700 - 1.0000000 4.4834100 3.9336000 3.0887700 2.9099700 3.7145700 3.2139300 - 2.0000000 7.4896000 6.8025500 5.7153500 5.4964000 6.5760500 5.8437000 - 4.0000000 12.0153000 11.1078000 9.8373000 9.6316000 10.9989000 9.9704000 - 6.0000000 15.9873000 14.8764000 13.4596000 13.3147000 14.8925000 13.6206000 - 8.0000000 19.9191000 18.6327000 17.0850000 17.0046000 18.7734000 17.2659000 - 10.0000000 23.7600000 22.2960000 20.6160000 20.6400000 22.5840000 20.8320000 diff --git a/openmc/data/dose/icrp74/photons_H10.txt b/openmc/data/dose/icrp74/photons_H10.txt deleted file mode 100644 index 66031b2f0..000000000 --- a/openmc/data/dose/icrp74/photons_H10.txt +++ /dev/null @@ -1,28 +0,0 @@ -Photons: Ambient dose (H*10) per fluence, in units of pSv cm² - -Energy (MeV) Dose -0.010 0.061 -0.015 0.83 -0.020 1.05 -0.030 0.81 -0.040 0.64 -0.050 0.55 -0.060 0.51 -0.080 0.53 -0.100 0.61 -0.150 0.89 -0.200 1.20 -0.300 1.80 -0.400 2.38 -0.500 2.93 -0.600 3.44 -0.800 4.38 -1 5.20 -1.5 6.90 -2 8.60 -3 11.1 -4 13.4 -5 15.5 -6 17.6 -8 21.6 -10 25.6 \ No newline at end of file diff --git a/openmc/data/dose/mass_attenuation.h5 b/openmc/data/dose/mass_attenuation.h5 deleted file mode 100644 index f62785140..000000000 Binary files a/openmc/data/dose/mass_attenuation.h5 and /dev/null differ diff --git a/openmc/data/dose/mass_attenuation.py b/openmc/data/dose/mass_attenuation.py deleted file mode 100644 index c4260480b..000000000 --- a/openmc/data/dose/mass_attenuation.py +++ /dev/null @@ -1,153 +0,0 @@ -from pathlib import Path - -import numpy as np -import h5py - -import openmc.checkvalue as cv -from openmc.data import EV_PER_MEV -from ..data import ATOMIC_NUMBER -from ..function import Tabulated1D - -# Embedded NIST-126 data -# Air (Dry Near Sea Level) — NIST Standard Reference Database 126 Table 4 (doi: 10.18434/T4D01F) -# Columns: Energy (MeV), μ_en/ρ (cm^2/g) -_NIST126_AIR = np.array([ - [1.00000e-03, 3.599e03], - [1.50000e-03, 1.188e03], - [2.00000e-03, 5.262e02], - [3.00000e-03, 1.614e02], - [3.20290e-03, 1.330e02], - [3.20290e-03, 1.460e02], - [4.00000e-03, 7.636e01], - [5.00000e-03, 3.931e01], - [6.00000e-03, 2.270e01], - [8.00000e-03, 9.446e00], - [1.00000e-02, 4.742e00], - [1.50000e-02, 1.334e00], - [2.00000e-02, 5.389e-01], - [3.00000e-02, 1.537e-01], - [4.00000e-02, 6.833e-02], - [5.00000e-02, 4.098e-02], - [6.00000e-02, 3.041e-02], - [8.00000e-02, 2.407e-02], - [1.00000e-01, 2.325e-02], - [1.50000e-01, 2.496e-02], - [2.00000e-01, 2.672e-02], - [3.00000e-01, 2.872e-02], - [4.00000e-01, 2.949e-02], - [5.00000e-01, 2.966e-02], - [6.00000e-01, 2.953e-02], - [8.00000e-01, 2.882e-02], - [1.00000e00, 2.789e-02], - [1.25000e00, 2.666e-02], - [1.50000e00, 2.547e-02], - [2.00000e00, 2.345e-02], - [3.00000e00, 2.057e-02], - [4.00000e00, 1.870e-02], - [5.00000e00, 1.740e-02], - [6.00000e00, 1.647e-02], - [8.00000e00, 1.525e-02], - [1.00000e01, 1.450e-02], - [1.50000e01, 1.353e-02], - [2.00000e01, 1.311e-02], -]) - -# Registry of embedded tables: (data_source, material) -> ndarray -# Table shape: (N, 2) with columns [Energy (MeV), μen/ρ (cm^2/g)] -_MUEN_TABLES = { - ("nist126", "air"): _NIST126_AIR, -} - - -def mass_energy_absorption_coefficient( - material: str, data_source: str = "nist126" -) -> Tabulated1D: - r"""Return the mass energy-absorption coefficient as a function of energy. - - The mass energy-absorption coefficient, :math:`\mu_\text{en}/\rho`, is - defined as the fraction of incident photon energy absorbed in a material per - unit mass less the energy carried away by scattered photons. It is obtained - from `NIST Standard Reference Database 126 - `_: X-Ray Mass Attenuation Coefficients. - - Parameters - ---------- - material : {'air'} - Material compound for which to load coefficients. - data_source : {'nist126'} - Source library. - - Returns - ------- - Tabulated1D - Mass energy-absorption coefficient [cm^2/g] as a function of photon - energy [eV], using log-log interpolation. - - """ - cv.check_value("material", material, {"air"}) - cv.check_value("data_source", data_source, {"nist126"}) - - key = (data_source, material) - if key not in _MUEN_TABLES: - available = sorted({m for (ds, m) in _MUEN_TABLES.keys() if ds == data_source}) - raise ValueError( - f"No mass energy-absorption data for '{material}' in data source " - f"'{data_source}'. Available materials: {available}" - ) - - data = _MUEN_TABLES[key] - energy = data[:, 0].copy() * EV_PER_MEV # MeV -> eV - mu_en_coeffs = data[:, 1].copy() - return Tabulated1D(energy, mu_en_coeffs, - breakpoints=[len(energy)], interpolation=[5]) - - -# Used in mass_attenuation_coefficient function as a cache. -# Maps atomic number Z (int) -> Tabulated1D of (mu/rho) [cm^2/g] vs E [eV] -_MASS_ATTENUATION: dict[int, object] = {} - - -def mass_attenuation_coefficient(element): - r"""Return the photon mass attenuation coefficient as a function of energy. - - The mass energy-absorption coefficient, :math:`\mu_\text{en}/\rho`, is - defined as the fraction of incident photon energy absorbed in a material per - unit mass. Values for each element are obtained from `NIST Standard - Reference Database 8 `_: XCOM Photon Cross - Sections Database. - - Parameters - ---------- - element : str or int - Element symbol (e.g., 'Fe') or atomic number (e.g., 26). - - Returns - ------- - Tabulated1D - Mass attenuation coefficient [cm^2/g] as a function of photon energy - [eV], using log-log interpolation. - - """ - if not _MASS_ATTENUATION: - data_file = Path(__file__).with_name('mass_attenuation.h5') - with h5py.File(data_file, 'r') as f: - for key, dataset in f.items(): - energies, mu_rho = dataset[()] # shape (2, N) - _MASS_ATTENUATION[int(key)] = Tabulated1D( - energies, mu_rho, - breakpoints=[len(energies)], - interpolation=[5] # log-log - ) - - # Resolve element argument to atomic number - if isinstance(element, str): - if element not in ATOMIC_NUMBER: - raise ValueError(f"'{element}' is not a recognized element symbol") - Z = ATOMIC_NUMBER[element] - else: - Z = int(element) - - if Z not in _MASS_ATTENUATION: - raise ValueError(f"No mass attenuation data available for Z={Z}") - - return _MASS_ATTENUATION[Z] diff --git a/openmc/data/dose/__init__.py b/openmc/data/effective_dose/__init__.py similarity index 100% rename from openmc/data/dose/__init__.py rename to openmc/data/effective_dose/__init__.py diff --git a/openmc/data/effective_dose/dose.py b/openmc/data/effective_dose/dose.py new file mode 100644 index 000000000..eb8fe9f35 --- /dev/null +++ b/openmc/data/effective_dose/dose.py @@ -0,0 +1,74 @@ +from pathlib import Path + +import numpy as np + +_FILES = ( + ('electron', 'electrons.txt'), + ('helium', 'helium_ions.txt'), + ('mu-', 'negative_muons.txt'), + ('pi-', 'negative_pions.txt'), + ('neutron', 'neutrons.txt'), + ('photon', 'photons.txt'), + ('photon kerma', 'photons_kerma.txt'), + ('mu+', 'positive_muons.txt'), + ('pi+', 'positive_pions.txt'), + ('positron', 'positrons.txt'), + ('proton', 'protons.txt') +) + +_DOSE_ICRP116 = {} + + +def _load_dose_icrp116(): + """Load effective dose tables from text files""" + for particle, filename in _FILES: + path = Path(__file__).parent / filename + data = np.loadtxt(path, skiprows=3, encoding='utf-8') + data[:, 0] *= 1e6 # Change energies to eV + _DOSE_ICRP116[particle] = data + + +def dose_coefficients(particle, geometry='AP'): + """Return effective dose conversion coefficients from ICRP-116 + + This function provides fluence (and air kerma) to effective dose conversion + coefficients for various types of external exposures based on values in + `ICRP Publication 116 `_. + Corrected values found in a correigendum are used rather than the values in + theoriginal report. + + Parameters + ---------- + particle : {'neutron', 'photon', 'photon kerma', 'electron', 'positron'} + Incident particle + geometry : {'AP', 'PA', 'LLAT', 'RLAT', 'ROT', 'ISO'} + Irradiation geometry assumed. Refer to ICRP-116 (Section 3.2) for the + meaning of the options here. + + Returns + ------- + energy : numpy.ndarray + Energies at which dose conversion coefficients are given + dose_coeffs : numpy.ndarray + Effective dose coefficients in [pSv cm^2] at provided energies. For + 'photon kerma', the coefficients are given in [Sv/Gy]. + + """ + if not _DOSE_ICRP116: + _load_dose_icrp116() + + # Get all data for selected particle + data = _DOSE_ICRP116.get(particle) + if data is None: + raise ValueError("{} has no effective dose data".format(particle)) + + # Determine index for selected geometry + if particle in ('neutron', 'photon', 'proton', 'photon kerma'): + index = ('AP', 'PA', 'LLAT', 'RLAT', 'ROT', 'ISO').index(geometry) + else: + index = ('AP', 'PA', 'ISO').index(geometry) + + # Pull out energy and dose from table + energy = data[:, 0].copy() + dose_coeffs = data[:, index + 1].copy() + return energy, dose_coeffs diff --git a/openmc/data/dose/icrp116/electrons.txt b/openmc/data/effective_dose/electrons.txt similarity index 100% rename from openmc/data/dose/icrp116/electrons.txt rename to openmc/data/effective_dose/electrons.txt diff --git a/openmc/data/dose/icrp116/helium_ions.txt b/openmc/data/effective_dose/helium_ions.txt similarity index 100% rename from openmc/data/dose/icrp116/helium_ions.txt rename to openmc/data/effective_dose/helium_ions.txt diff --git a/openmc/data/dose/icrp116/negative_muons.txt b/openmc/data/effective_dose/negative_muons.txt similarity index 100% rename from openmc/data/dose/icrp116/negative_muons.txt rename to openmc/data/effective_dose/negative_muons.txt diff --git a/openmc/data/dose/icrp116/negative_pions.txt b/openmc/data/effective_dose/negative_pions.txt similarity index 100% rename from openmc/data/dose/icrp116/negative_pions.txt rename to openmc/data/effective_dose/negative_pions.txt diff --git a/openmc/data/dose/icrp116/neutrons.txt b/openmc/data/effective_dose/neutrons.txt similarity index 100% rename from openmc/data/dose/icrp116/neutrons.txt rename to openmc/data/effective_dose/neutrons.txt diff --git a/openmc/data/dose/icrp116/photons.txt b/openmc/data/effective_dose/photons.txt similarity index 100% rename from openmc/data/dose/icrp116/photons.txt rename to openmc/data/effective_dose/photons.txt diff --git a/openmc/data/dose/icrp116/photons_kerma.txt b/openmc/data/effective_dose/photons_kerma.txt similarity index 100% rename from openmc/data/dose/icrp116/photons_kerma.txt rename to openmc/data/effective_dose/photons_kerma.txt diff --git a/openmc/data/dose/icrp116/positive_muons.txt b/openmc/data/effective_dose/positive_muons.txt similarity index 100% rename from openmc/data/dose/icrp116/positive_muons.txt rename to openmc/data/effective_dose/positive_muons.txt diff --git a/openmc/data/dose/icrp116/positive_pions.txt b/openmc/data/effective_dose/positive_pions.txt similarity index 100% rename from openmc/data/dose/icrp116/positive_pions.txt rename to openmc/data/effective_dose/positive_pions.txt diff --git a/openmc/data/dose/icrp116/positrons.txt b/openmc/data/effective_dose/positrons.txt similarity index 100% rename from openmc/data/dose/icrp116/positrons.txt rename to openmc/data/effective_dose/positrons.txt diff --git a/openmc/data/dose/icrp116/protons.txt b/openmc/data/effective_dose/protons.txt similarity index 100% rename from openmc/data/dose/icrp116/protons.txt rename to openmc/data/effective_dose/protons.txt diff --git a/openmc/data/endf.c b/openmc/data/endf.c new file mode 100644 index 000000000..936fd3bbb --- /dev/null +++ b/openmc/data/endf.c @@ -0,0 +1,57 @@ +#include + +//! Convert string representation of a floating point number into a double +// +//! This function handles converting floating point numbers from an ENDF 11 +//! character field into a double, covering all the corner cases. Floating point +//! numbers are allowed to contain whitespace (which is ignored). Also, in +//! exponential notation, it allows the 'e' to be omitted. A field containing +//! only whitespace is to be interpreted as a zero. +// +//! \param buffer character input from an ENDF file +//! \param n Length of character input +//! \return Floating point number + +double cfloat_endf(const char* buffer, int n) +{ + char arr[12]; // 11 characters plus a null terminator + int j = 0; // current position in arr + int found_significand = 0; + int found_exponent = 0; + + // limit n to 11 characters + n = n > 11 ? 11 : n; + + int i; + for (i = 0; i < n; ++i) { + char c = buffer[i]; + + // Skip whitespace characters + if (c == ' ') continue; + + if (found_significand) { + if (!found_exponent) { + if (c == '+' || c == '-') { + // In the case that we encounter +/- and we haven't yet encountered + // e/E, we manually add it + arr[j++] = 'e'; + found_exponent = 1; + + } else if (c == 'e' || c == 'E' || c == 'd' || c == 'D') { + arr[j++] = 'e'; + found_exponent = 1; + continue; + } + } + } else if (c == '.' || (c >= '0' && c <= '9')) { + found_significand = 1; + } + + // Copy character + arr[j++] = c; + } + + // Done copying. Add null terminator and convert to double + arr[j] = '\0'; + return atof(arr); +} diff --git a/openmc/data/endf.py b/openmc/data/endf.py index edd8afffb..f9b9d0694 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -1,47 +1,367 @@ """Module for parsing and manipulating data from ENDF evaluations. -All the classes and functions in this module are based on document ENDF-102 -titled "Data Formats and Procedures for the Evaluated Nuclear Data File ENDF-6". -The version from September 2023 can be found at -https://www.nndc.bnl.gov/endfdocs/ENDF-102-2023.pdf +All the classes and functions in this module are based on document +ENDF-102 titled "Data Formats and Procedures for the Evaluated Nuclear +Data File ENDF-6". The latest version from June 2009 can be found at +http://www-nds.iaea.org/ndspub/documents/endf/endf102/endf102.pdf """ import io from pathlib import PurePath import re -from .data import gnds_name +import numpy as np + +from .data import gnd_name from .function import Tabulated1D -from endf.material import ( - Material, - _LIBRARY, - _SUBLIBRARY, - get_materials as get_evaluations, -) -from endf.incident_neutron import SUM_RULES -from endf.records import ( - float_endf, - py_float_endf, - int_endf, - get_text_record, - get_cont_record, - get_head_record, - get_list_record, - get_tab1_record as _get_tab1_record, - get_tab2_record, - get_intg_record, -) +try: + from ._endf import float_endf + _CYTHON = True +except ImportError: + _CYTHON = False + + +_LIBRARY = {0: 'ENDF/B', 1: 'ENDF/A', 2: 'JEFF', 3: 'EFF', + 4: 'ENDF/B High Energy', 5: 'CENDL', 6: 'JENDL', + 17: 'TENDL', 18: 'ROSFOND', 21: 'SG-21', 31: 'INDL/V', + 32: 'INDL/A', 33: 'FENDL', 34: 'IRDF', 35: 'BROND', + 36: 'INGDB-90', 37: 'FENDL/A', 41: 'BROND'} + +_SUBLIBRARY = { + 0: 'Photo-nuclear data', + 1: 'Photo-induced fission product yields', + 3: 'Photo-atomic data', + 4: 'Radioactive decay data', + 5: 'Spontaneous fission product yields', + 6: 'Atomic relaxation data', + 10: 'Incident-neutron data', + 11: 'Neutron-induced fission product yields', + 12: 'Thermal neutron scattering data', + 19: 'Neutron standards', + 113: 'Electro-atomic data', + 10010: 'Incident-proton data', + 10011: 'Proton-induced fission product yields', + 10020: 'Incident-deuteron data', + 10030: 'Incident-triton data', + 20030: 'Incident-helion (3He) data', + 20040: 'Incident-alpha data' +} + +SUM_RULES = {1: [2, 3], + 3: [4, 5, 11, 16, 17, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, + 36, 37, 41, 42, 44, 45, 152, 153, 154, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, + 186, 187, 188, 189, 190, 194, 195, 196, 198, 199, 200], + 4: list(range(50, 92)), + 16: list(range(875, 892)), + 18: [19, 20, 21, 38], + 27: [18, 101], + 101: [102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, + 115, 116, 117, 155, 182, 191, 192, 193, 197], + 103: list(range(600, 650)), + 104: list(range(650, 700)), + 105: list(range(700, 750)), + 106: list(range(750, 800)), + 107: list(range(800, 850))} + +ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]) ?(\d+)') + + +def py_float_endf(s): + """Convert string of floating point number in ENDF to float. + + The ENDF-6 format uses an 'e-less' floating point number format, + e.g. -1.23481+10. Trying to convert using the float built-in won't work + because of the lack of an 'e'. This function allows such strings to be + converted while still allowing numbers that are not in exponential notation + to be converted as well. + + Parameters + ---------- + s : str + Floating-point number from an ENDF file + + Returns + ------- + float + The number + + """ + return float(ENDF_FLOAT_RE.sub(r'\1e\2\3', s)) + + +if not _CYTHON: + float_endf = py_float_endf + + +def int_endf(s): + """Convert string of integer number in ENDF to int. + + The ENDF-6 format technically allows integers to be represented by a field + of all blanks. This function acts like int(s) except when s is a string of + all whitespace, in which case zero is returned. + + Parameters + ---------- + s : str + Integer or spaces + + Returns + ------- + integer + The number or 0 + """ + return 0 if s.isspace() else int(s) + + +def get_text_record(file_obj): + """Return data from a TEXT record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + str + Text within the TEXT record + + """ + return file_obj.readline()[:66] + + +def get_cont_record(file_obj, skip_c=False): + """Return data from a CONT record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + skip_c : bool + Determine whether to skip the first two quantities (C1, C2) of the CONT + record. + + Returns + ------- + tuple + The six items within the CONT record + + """ + line = file_obj.readline() + if skip_c: + C1 = None + C2 = None + else: + C1 = float_endf(line[:11]) + C2 = float_endf(line[11:22]) + L1 = int_endf(line[22:33]) + L2 = int_endf(line[33:44]) + N1 = int_endf(line[44:55]) + N2 = int_endf(line[55:66]) + return (C1, C2, L1, L2, N1, N2) + + +def get_head_record(file_obj): + """Return data from a HEAD record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + tuple + The six items within the HEAD record + + """ + line = file_obj.readline() + ZA = int(float_endf(line[:11])) + AWR = float_endf(line[11:22]) + L1 = int_endf(line[22:33]) + L2 = int_endf(line[33:44]) + N1 = int_endf(line[44:55]) + N2 = int_endf(line[55:66]) + return (ZA, AWR, L1, L2, N1, N2) + + +def get_list_record(file_obj): + """Return data from a LIST record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + list + The six items within the header + list + The values within the list + + """ + # determine how many items are in list + items = get_cont_record(file_obj) + NPL = items[4] + + # read items + b = [] + for i in range((NPL - 1)//6 + 1): + line = file_obj.readline() + n = min(6, NPL - 6*i) + for j in range(n): + b.append(float_endf(line[11*j:11*(j + 1)])) + + return (items, b) def get_tab1_record(file_obj): """Return data from a TAB1 record in an ENDF-6 file. - This wraps the endf package's get_tab1_record to return an - openmc.data.Tabulated1D (which has HDF5 support and is a Function1D) - instead of endf.Tabulated1D. + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + list + The six items within the header + openmc.data.Tabulated1D + The tabulated function + """ - params, tab = _get_tab1_record(file_obj) - return params, Tabulated1D(tab.x, tab.y, tab.breakpoints, tab.interpolation) + # Determine how many interpolation regions and total points there are + line = file_obj.readline() + C1 = float_endf(line[:11]) + C2 = float_endf(line[11:22]) + L1 = int_endf(line[22:33]) + L2 = int_endf(line[33:44]) + n_regions = int_endf(line[44:55]) + n_pairs = int_endf(line[55:66]) + params = [C1, C2, L1, L2] + + # Read the interpolation region data, namely NBT and INT + breakpoints = np.zeros(n_regions, dtype=int) + interpolation = np.zeros(n_regions, dtype=int) + m = 0 + for i in range((n_regions - 1)//3 + 1): + line = file_obj.readline() + to_read = min(3, n_regions - m) + for j in range(to_read): + breakpoints[m] = int_endf(line[0:11]) + interpolation[m] = int_endf(line[11:22]) + line = line[22:] + m += 1 + + # Read tabulated pairs x(n) and y(n) + x = np.zeros(n_pairs) + y = np.zeros(n_pairs) + m = 0 + for i in range((n_pairs - 1)//3 + 1): + line = file_obj.readline() + to_read = min(3, n_pairs - m) + for j in range(to_read): + x[m] = float_endf(line[:11]) + y[m] = float_endf(line[11:22]) + line = line[22:] + m += 1 + + return params, Tabulated1D(x, y, breakpoints, interpolation) + + +def get_tab2_record(file_obj): + # Determine how many interpolation regions and total points there are + params = get_cont_record(file_obj) + n_regions = params[4] + + # Read the interpolation region data, namely NBT and INT + breakpoints = np.zeros(n_regions, dtype=int) + interpolation = np.zeros(n_regions, dtype=int) + m = 0 + for i in range((n_regions - 1)//3 + 1): + line = file_obj.readline() + to_read = min(3, n_regions - m) + for j in range(to_read): + breakpoints[m] = int(line[0:11]) + interpolation[m] = int(line[11:22]) + line = line[22:] + m += 1 + + return params, Tabulated2D(breakpoints, interpolation) + + +def get_intg_record(file_obj): + """ + Return data from an INTG record in an ENDF-6 file. Used to store the + covariance matrix in a compact format. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + numpy.ndarray + The correlation matrix described in the INTG record + """ + # determine how many items are in list and NDIGIT + items = get_cont_record(file_obj) + ndigit = items[2] + npar = items[3] # Number of parameters + nlines = items[4] # Lines to read + NROW_RULES = {2: 18, 3: 12, 4: 11, 5: 9, 6: 8} + nrow = NROW_RULES[ndigit] + + # read lines and build correlation matrix + corr = np.identity(npar) + for i in range(nlines): + line = file_obj.readline() + ii = int_endf(line[:5]) - 1 # -1 to account for 0 indexing + jj = int_endf(line[5:10]) - 1 + factor = 10**ndigit + for j in range(nrow): + if jj+j >= ii: + break + element = int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)]) + if element > 0: + corr[ii, jj] = (element+0.5)/factor + elif element < 0: + corr[ii, jj] = (element-0.5)/factor + + # Symmetrize the correlation matrix + corr = corr + corr.T - np.diag(corr.diagonal()) + return corr + + +def get_evaluations(filename): + """Return a list of all evaluations within an ENDF file. + + Parameters + ---------- + filename : str + Path to ENDF-6 formatted file + + Returns + ------- + list + A list of :class:`openmc.data.endf.Evaluation` instances. + + """ + evaluations = [] + with open(str(filename), 'r') as fh: + while True: + pos = fh.tell() + line = fh.readline() + if line[66:70] == ' -1': + break + fh.seek(pos) + evaluations.append(Evaluation(fh)) + return evaluations class Evaluation: @@ -49,7 +369,7 @@ class Evaluation: Parameters ---------- - filename_or_obj : str, file-like, or endf.Material + filename_or_obj : str or file-like Path to ENDF file to read or an open file positioned at the start of an ENDF material @@ -69,25 +389,17 @@ class Evaluation: """ def __init__(self, filename_or_obj): - self.section = {} - self.info = {} - self.target = {} - self.projectile = {} - self.reaction_list = [] - - if isinstance(filename_or_obj, Material): - self.section = dict(filename_or_obj.section_text) - self.section_data = filename_or_obj.section_data - self.material = filename_or_obj.MAT - self._read_header() - return - if isinstance(filename_or_obj, (str, PurePath)): fh = open(str(filename_or_obj), 'r') need_to_close = True else: fh = filename_or_obj need_to_close = False + self.section = {} + self.info = {} + self.target = {} + self.projectile = {} + self.reaction_list = [] # Skip TPID record. Evaluators sometimes put in TPID records that are # ill-formated because they lack MF/MT values or put them in the wrong @@ -137,7 +449,8 @@ class Evaluation: def __repr__(self): name = self.target['zsymam'].replace(' ', '') - return f"<{self.info['sublibrary']} for {name} {self.info['library']}>" + return '<{} for {} {}>'.format(self.info['sublibrary'], name, + self.info['library']) def _read_header(self): file_obj = io.StringIO(self.section[1, 451]) @@ -207,15 +520,29 @@ class Evaluation: self.reaction_list.append((mf, mt, nc, mod)) @property - def gnds_name(self): - return gnds_name(self.target['atomic_number'], - self.target['mass_number'], - self.target['isomeric_state']) + def gnd_name(self): + return gnd_name(self.target['atomic_number'], + self.target['mass_number'], + self.target['isomeric_state']) -def as_evaluation(ev_or_filename): - """Return an object supporting OpenMC's legacy Evaluation interface.""" - if isinstance(ev_or_filename, Evaluation): - return ev_or_filename - else: - return Evaluation(ev_or_filename) +class Tabulated2D: + """Metadata for a two-dimensional function. + + This is a dummy class that is not really used other than to store the + interpolation information for a two-dimensional function. Once we refactor + to adopt GND-like data containers, this will probably be removed or + extended. + + Parameters + ---------- + breakpoints : Iterable of int + Breakpoints for interpolation regions + interpolation : Iterable of int + Interpolation scheme identification number, e.g., 3 means y is linear in + ln(x). + + """ + def __init__(self, breakpoints, interpolation): + self.breakpoints = breakpoints + self.interpolation = interpolation diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index 069ab1b9b..3b6d325ef 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -53,7 +53,8 @@ class EnergyDistribution(EqualityMixin, ABC): elif energy_type == 'continuous': return ContinuousTabular.from_hdf5(group) else: - raise ValueError(f"Unknown energy distribution type: {energy_type}") + raise ValueError("Unknown energy distribution type: {}" + .format(energy_type)) @staticmethod def from_endf(file_obj, params): @@ -252,15 +253,15 @@ class MaxwellEnergy(EnergyDistribution): def theta(self): return self._theta + @property + def u(self): + return self._u + @theta.setter def theta(self, theta): cv.check_type('Maxwell theta', theta, Tabulated1D) self._theta = theta - @property - def u(self): - return self._u - @u.setter def u(self, u): cv.check_type('Maxwell restriction energy', u, Real) @@ -276,7 +277,7 @@ class MaxwellEnergy(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('maxwell') + group.attrs['type'] = np.string_('maxwell') group.attrs['u'] = self.u self.theta.to_hdf5(group, 'theta') @@ -385,15 +386,15 @@ class Evaporation(EnergyDistribution): def theta(self): return self._theta + @property + def u(self): + return self._u + @theta.setter def theta(self, theta): cv.check_type('Evaporation theta', theta, Tabulated1D) self._theta = theta - @property - def u(self): - return self._u - @u.setter def u(self, u): cv.check_type('Evaporation restriction energy', u, Real) @@ -409,7 +410,7 @@ class Evaporation(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('evaporation') + group.attrs['type'] = np.string_('evaporation') group.attrs['u'] = self.u self.theta.to_hdf5(group, 'theta') @@ -522,24 +523,24 @@ class WattEnergy(EnergyDistribution): def a(self): return self._a + @property + def b(self): + return self._b + + @property + def u(self): + return self._u + @a.setter def a(self, a): cv.check_type('Watt a', a, Tabulated1D) self._a = a - @property - def b(self): - return self._b - @b.setter def b(self, b): cv.check_type('Watt b', b, Tabulated1D) self._b = b - @property - def u(self): - return self._u - @u.setter def u(self, u): cv.check_type('Watt restriction energy', u, Real) @@ -555,7 +556,7 @@ class WattEnergy(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('watt') + group.attrs['type'] = np.string_('watt') group.attrs['u'] = self.u self.a.to_hdf5(group, 'a') self.b.to_hdf5(group, 'b') @@ -690,6 +691,14 @@ class MadlandNix(EnergyDistribution): def efl(self): return self._efl + @property + def efh(self): + return self._efh + + @property + def tm(self): + return self._tm + @efl.setter def efl(self, efl): name = 'Madland-Nix light fragment energy' @@ -697,10 +706,6 @@ class MadlandNix(EnergyDistribution): cv.check_greater_than(name, efl, 0.) self._efl = efl - @property - def efh(self): - return self._efh - @efh.setter def efh(self, efh): name = 'Madland-Nix heavy fragment energy' @@ -708,10 +713,6 @@ class MadlandNix(EnergyDistribution): cv.check_greater_than(name, efh, 0.) self._efh = efh - @property - def tm(self): - return self._tm - @tm.setter def tm(self, tm): cv.check_type('Madland-Nix maximum temperature', tm, Tabulated1D) @@ -727,7 +728,7 @@ class MadlandNix(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('madland-nix') + group.attrs['type'] = np.string_('madland-nix') group.attrs['efl'] = self.efl group.attrs['efh'] = self.efh self.tm.to_hdf5(group) @@ -777,6 +778,7 @@ class MadlandNix(EnergyDistribution): return cls(efl, efh, tm) + class DiscretePhoton(EnergyDistribution): """Discrete photon energy distribution @@ -812,24 +814,24 @@ class DiscretePhoton(EnergyDistribution): def primary_flag(self): return self._primary_flag + @property + def energy(self): + return self._energy + + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @primary_flag.setter def primary_flag(self, primary_flag): cv.check_type('discrete photon primary_flag', primary_flag, Integral) self._primary_flag = primary_flag - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('discrete photon energy', energy, Real) self._energy = energy - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) @@ -845,7 +847,7 @@ class DiscretePhoton(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('discrete_photon') + group.attrs['type'] = np.string_('discrete_photon') group.attrs['primary_flag'] = self.primary_flag group.attrs['energy'] = self.energy group.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio @@ -920,15 +922,15 @@ class LevelInelastic(EnergyDistribution): def threshold(self): return self._threshold + @property + def mass_ratio(self): + return self._mass_ratio + @threshold.setter def threshold(self, threshold): cv.check_type('level inelastic threhsold', threshold, Real) self._threshold = threshold - @property - def mass_ratio(self): - return self._mass_ratio - @mass_ratio.setter def mass_ratio(self, mass_ratio): cv.check_type('level inelastic mass ratio', mass_ratio, Real) @@ -944,7 +946,7 @@ class LevelInelastic(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('level') + group.attrs['type'] = np.string_('level') group.attrs['threshold'] = self.threshold group.attrs['mass_ratio'] = self.mass_ratio @@ -1027,36 +1029,36 @@ class ContinuousTabular(EnergyDistribution): def breakpoints(self): return self._breakpoints + @property + def interpolation(self): + return self._interpolation + + @property + def energy(self): + return self._energy + + @property + def energy_out(self): + return self._energy_out + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('continuous tabular breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints - @property - def interpolation(self): - return self._interpolation - @interpolation.setter def interpolation(self, interpolation): cv.check_type('continuous tabular interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('continuous tabular incoming energy', energy, Iterable, Real) self._energy = energy - @property - def energy_out(self): - return self._energy_out - @energy_out.setter def energy_out(self, energy_out): cv.check_type('continuous tabular outgoing energy', energy_out, @@ -1073,7 +1075,7 @@ class ContinuousTabular(EnergyDistribution): """ - group.attrs['type'] = np.bytes_('continuous') + group.attrs['type'] = np.string_('continuous') dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index e4fac087a..bdce84ff7 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -5,8 +5,7 @@ from io import StringIO import openmc.checkvalue as cv from openmc.mixin import EqualityMixin from .data import EV_PER_MEV -from .endf import ( - as_evaluation, get_cont_record, get_list_record, get_tab1_record) +from .endf import get_cont_record, get_list_record, get_tab1_record, Evaluation from .function import Function1D, Tabulated1D, Polynomial, sum_functions @@ -45,7 +44,7 @@ class FissionEnergyRelease(EqualityMixin): ---------- [1] D. G. Madland, "Total prompt energy release in the neutron-induced fission of ^235U, ^238U, and ^239Pu", Nuclear Physics A 772:113--137 (2006). - + Attributes ---------- @@ -101,65 +100,30 @@ class FissionEnergyRelease(EqualityMixin): def fragments(self): return self._fragments - @fragments.setter - def fragments(self, energy_release): - cv.check_type('fragments', energy_release, Callable) - self._fragments = energy_release - @property def prompt_neutrons(self): return self._prompt_neutrons - @prompt_neutrons.setter - def prompt_neutrons(self, energy_release): - cv.check_type('prompt_neutrons', energy_release, Callable) - self._prompt_neutrons = energy_release - @property def delayed_neutrons(self): return self._delayed_neutrons - @delayed_neutrons.setter - def delayed_neutrons(self, energy_release): - cv.check_type('delayed_neutrons', energy_release, Callable) - self._delayed_neutrons = energy_release - @property def prompt_photons(self): return self._prompt_photons - @prompt_photons.setter - def prompt_photons(self, energy_release): - cv.check_type('prompt_photons', energy_release, Callable) - self._prompt_photons = energy_release - @property def delayed_photons(self): return self._delayed_photons - @delayed_photons.setter - def delayed_photons(self, energy_release): - cv.check_type('delayed_photons', energy_release, Callable) - self._delayed_photons = energy_release - @property def betas(self): return self._betas - @betas.setter - def betas(self, energy_release): - cv.check_type('betas', energy_release, Callable) - self._betas = energy_release - @property def neutrinos(self): return self._neutrinos - @neutrinos.setter - def neutrinos(self, energy_release): - cv.check_type('neutrinos', energy_release, Callable) - self._neutrinos = energy_release - @property def recoverable(self): components = ['fragments', 'prompt_neutrons', 'delayed_neutrons', @@ -190,13 +154,48 @@ class FissionEnergyRelease(EqualityMixin): # Use a polynomial to subtract incident energy. return sum_functions([self.total, Polynomial((0.0, -1.0))]) + @fragments.setter + def fragments(self, energy_release): + cv.check_type('fragments', energy_release, Callable) + self._fragments = energy_release + + @prompt_neutrons.setter + def prompt_neutrons(self, energy_release): + cv.check_type('prompt_neutrons', energy_release, Callable) + self._prompt_neutrons = energy_release + + @delayed_neutrons.setter + def delayed_neutrons(self, energy_release): + cv.check_type('delayed_neutrons', energy_release, Callable) + self._delayed_neutrons = energy_release + + @prompt_photons.setter + def prompt_photons(self, energy_release): + cv.check_type('prompt_photons', energy_release, Callable) + self._prompt_photons = energy_release + + @delayed_photons.setter + def delayed_photons(self, energy_release): + cv.check_type('delayed_photons', energy_release, Callable) + self._delayed_photons = energy_release + + @betas.setter + def betas(self, energy_release): + cv.check_type('betas', energy_release, Callable) + self._betas = energy_release + + @neutrinos.setter + def neutrinos(self, energy_release): + cv.check_type('neutrinos', energy_release, Callable) + self._neutrinos = energy_release + @classmethod def from_endf(cls, ev, incident_neutron): """Generate fission energy release data from an ENDF file. Parameters ---------- - ev : openmc.data.endf.Evaluation or endf.Material + ev : openmc.data.endf.Evaluation ENDF evaluation incident_neutron : openmc.data.IncidentNeutron Corresponding incident neutron dataset @@ -207,7 +206,7 @@ class FissionEnergyRelease(EqualityMixin): Fission energy release data """ - ev = as_evaluation(ev) + cv.check_type('evaluation', ev, Evaluation) # Check to make sure this ENDF file matches the expected isomer. if ev.target['atomic_number'] != incident_neutron.atomic_number: diff --git a/openmc/data/function.py b/openmc/data/function.py index c5914f513..b0390d19c 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -255,38 +255,18 @@ class Tabulated1D(Function1D): def x(self): return self._x - @x.setter - def x(self, x): - cv.check_type('x values', x, Iterable, Real) - self._x = x - @property def y(self): return self._y - @y.setter - def y(self, y): - cv.check_type('y values', y, Iterable, Real) - self._y = y - @property def breakpoints(self): return self._breakpoints - @breakpoints.setter - def breakpoints(self, breakpoints): - cv.check_type('breakpoints', breakpoints, Iterable, Integral) - self._breakpoints = breakpoints - @property def interpolation(self): return self._interpolation - @interpolation.setter - def interpolation(self, interpolation): - cv.check_type('interpolation', interpolation, Iterable, Integral) - self._interpolation = interpolation - @property def n_pairs(self): return len(self.x) @@ -295,6 +275,26 @@ class Tabulated1D(Function1D): def n_regions(self): return len(self.breakpoints) + @x.setter + def x(self, x): + cv.check_type('x values', x, Iterable, Real) + self._x = x + + @y.setter + def y(self, y): + cv.check_type('y values', y, Iterable, Real) + self._y = y + + @breakpoints.setter + def breakpoints(self, breakpoints): + cv.check_type('breakpoints', breakpoints, Iterable, Integral) + self._breakpoints = breakpoints + + @interpolation.setter + def interpolation(self, interpolation): + cv.check_type('interpolation', interpolation, Iterable, Integral) + self._interpolation = interpolation + def integral(self): """Integral of the tabulated function over its tabulated range. @@ -364,7 +364,7 @@ class Tabulated1D(Function1D): """ dataset = group.create_dataset(name, data=np.vstack( [self.x, self.y])) - dataset.attrs['type'] = np.bytes_(type(self).__name__) + dataset.attrs['type'] = np.string_(type(self).__name__) dataset.attrs['breakpoints'] = self.breakpoints dataset.attrs['interpolation'] = self.interpolation @@ -460,7 +460,7 @@ class Polynomial(np.polynomial.Polynomial, Function1D): """ dataset = group.create_dataset(name, data=self.coef) - dataset.attrs['type'] = np.bytes_(type(self).__name__) + dataset.attrs['type'] = np.string_(type(self).__name__) @classmethod def from_hdf5(cls, dataset): @@ -592,7 +592,7 @@ class Sum(Function1D): """ sum_group = group.create_group(name) - sum_group.attrs['type'] = np.bytes_(type(self).__name__) + sum_group.attrs['type'] = np.string_(type(self).__name__) sum_group.attrs['n'] = len(self.functions) for i, f in enumerate(self.functions): f.to_hdf5(sum_group, f'func_{i+1}') @@ -664,15 +664,15 @@ class Regions1D(EqualityMixin): def functions(self): return self._functions + @property + def breakpoints(self): + return self._breakpoints + @functions.setter def functions(self, functions): cv.check_type('functions', functions, Iterable, Callable) self._functions = functions - @property - def breakpoints(self): - return self._breakpoints - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_iterable_type('breakpoints', breakpoints, Real) @@ -708,28 +708,50 @@ class ResonancesWithBackground(EqualityMixin): self.background = background self.mt = mt + def __call__(self, x): + # Get background cross section + xs = self.background(x) + + for r in self.resonances: + if not isinstance(r, openmc.data.resonance._RESOLVED): + continue + + if isinstance(x, Iterable): + # Determine which energies are within resolved resonance range + within = (r.energy_min <= x) & (x <= r.energy_max) + + # Get resonance cross sections and add to background + resonant_xs = r.reconstruct(x[within]) + xs[within] += resonant_xs[self.mt] + else: + if r.energy_min <= x <= r.energy_max: + resonant_xs = r.reconstruct(x) + xs += resonant_xs[self.mt] + + return xs + @property def background(self): return self._background + @property + def mt(self): + return self._mt + + @property + def resonances(self): + return self._resonances + @background.setter def background(self, background): cv.check_type('background cross section', background, Callable) self._background = background - @property - def mt(self): - return self._mt - @mt.setter def mt(self, mt): cv.check_type('MT value', mt, Integral) self._mt = mt - @property - def resonances(self): - return self._resonances - @resonances.setter def resonances(self, resonances): cv.check_type('resolved resonance parameters', resonances, diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index d92bf9c21..f98bb4186 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -302,56 +302,56 @@ class KalbachMann(AngleEnergy): def breakpoints(self): return self._breakpoints + @property + def interpolation(self): + return self._interpolation + + @property + def energy(self): + return self._energy + + @property + def energy_out(self): + return self._energy_out + + @property + def precompound(self): + return self._precompound + + @property + def slope(self): + return self._slope + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('Kalbach-Mann breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints - @property - def interpolation(self): - return self._interpolation - @interpolation.setter def interpolation(self, interpolation): cv.check_type('Kalbach-Mann interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('Kalbach-Mann incoming energy', energy, Iterable, Real) self._energy = energy - @property - def energy_out(self): - return self._energy_out - @energy_out.setter def energy_out(self, energy_out): cv.check_type('Kalbach-Mann distributions', energy_out, Iterable, Univariate) self._energy_out = energy_out - @property - def precompound(self): - return self._precompound - @precompound.setter def precompound(self, precompound): cv.check_type('Kalbach-Mann precompound factor', precompound, Iterable, Tabulated1D) self._precompound = precompound - @property - def slope(self): - return self._slope - @slope.setter def slope(self, slope): cv.check_type('Kalbach-Mann slope', slope, Iterable, Tabulated1D) @@ -366,7 +366,7 @@ class KalbachMann(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('kalbach-mann') + group.attrs['type'] = np.string_('kalbach-mann') dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, diff --git a/openmc/data/laboratory.py b/openmc/data/laboratory.py index c20b45968..87d9d2961 100644 --- a/openmc/data/laboratory.py +++ b/openmc/data/laboratory.py @@ -54,46 +54,45 @@ class LaboratoryAngleEnergy(AngleEnergy): def breakpoints(self): return self._breakpoints + @property + def interpolation(self): + return self._interpolation + @property + def energy(self): + return self._energy + + @property + def mu(self): + return self._mu + + @property + def energy_out(self): + return self._energy_out + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('laboratory angle-energy breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints - @property - def interpolation(self): - return self._interpolation - @interpolation.setter def interpolation(self, interpolation): cv.check_type('laboratory angle-energy interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('laboratory angle-energy incoming energy', energy, Iterable, Real) self._energy = energy - @property - def mu(self): - return self._mu - @mu.setter def mu(self, mu): cv.check_type('laboratory angle-energy outgoing cosine', mu, Iterable, Univariate) self._mu = mu - @property - def energy_out(self): - return self._energy_out - @energy_out.setter def energy_out(self, energy_out): cv.check_iterable_type('laboratory angle-energy outgoing energy', diff --git a/openmc/data/library.py b/openmc/data/library.py index b49757b0d..bf937e57a 100644 --- a/openmc/data/library.py +++ b/openmc/data/library.py @@ -1,33 +1,27 @@ import os +import xml.etree.ElementTree as ET import pathlib import h5py -import lxml.etree as ET -import openmc -from openmc._xml import get_elem_list, get_text, clean_indentation +from openmc.mixin import EqualityMixin +from openmc._xml import clean_indentation, reorder_attributes -class DataLibrary(list): +class DataLibrary(EqualityMixin): """Collection of cross section data libraries. - This class behaves like a list where each item is a dictionary summarizing - cross section data from a single file. The dictionary has keys 'path', - 'type', and 'materials'. - - .. versionchanged:: 0.14.0 - This class now behaves like a list rather than requiring you to access - the list of libraries through a special attribute. + Attributes + ---------- + libraries : list of dict + List in which each item is a dictionary summarizing cross section data + from a single file. The dictionary has keys 'path', 'type', and + 'materials'. """ def __init__(self): - super().__init__() - - @property - def libraries(self): - # For backwards compatibility - return self + self.libraries = [] def get_by_material(self, name, data_type='neutron'): """Return the library dictionary containing a given material. @@ -48,26 +42,11 @@ class DataLibrary(list): the dictionary has keys 'path', 'type', and 'materials'. """ - for library in self: + for library in self.libraries: if name in library['materials'] and data_type in library['type']: return library return None - def remove_by_material(self, name: str, data_type='neutron'): - """Remove the library dictionary containing a specific material - - Parameters - ---------- - name : str - Name of material, e.g. 'Am241' - data_type : str - Name of data type, e.g. 'neutron', 'photon', 'wmp', or 'thermal' - - """ - library = self.get_by_material(name, data_type) - if library is not None: - self.remove(library) - def register_file(self, filename): """Register a file with the data library. @@ -93,10 +72,11 @@ class DataLibrary(list): materials = list(h5file) else: raise ValueError( - f"File type {path.name} not supported by {self.__class__.__name__}") + "File type {} not supported by {}" + .format(path.name, self.__class__.__name__)) library = {'path': str(path), 'type': filetype, 'materials': materials} - self.append(library) + self.libraries.append(library) def export_to_xml(self, path='cross_sections.xml'): """Export cross section data library to an XML file. @@ -111,7 +91,7 @@ class DataLibrary(list): # Determine common directory for library paths common_dir = os.path.dirname(os.path.commonprefix( - [lib['path'] for lib in self])) + [lib['path'] for lib in self.libraries])) if common_dir == '': common_dir = '.' @@ -119,7 +99,7 @@ class DataLibrary(list): dir_element = ET.SubElement(root, "directory") dir_element.text = os.path.realpath(common_dir) - for library in self: + for library in self.libraries: if library['type'] == "depletion_chain": lib_element = ET.SubElement(root, "depletion_chain") else: @@ -132,6 +112,7 @@ class DataLibrary(list): clean_indentation(root) # Write XML file + reorder_attributes(root) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root) tree.write(str(path), xml_declaration=True, encoding='utf-8', method='xml') @@ -143,8 +124,8 @@ class DataLibrary(list): Parameters ---------- path : str, optional - Path to XML file to read. If not provided, - openmc.config['cross_sections'] will be used. + Path to XML file to read. If not provided, the + :envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used. Returns ------- @@ -155,14 +136,15 @@ class DataLibrary(list): data = cls() - # If path is None, get the cross sections from the global configuration + # If path is None, get the cross sections from the + # OPENMC_CROSS_SECTIONS environment variable if path is None: - path = openmc.config.get('cross_sections') + path = os.environ.get('OPENMC_CROSS_SECTIONS') - # Check to make sure we picked up cross sections + # Check to make sure there was an environmental variable. if path is None: - raise ValueError("Either path or openmc.config['cross_sections'] " - "must be set") + raise ValueError("Either path or OPENMC_CROSS_SECTIONS " + "environmental variable must be set") tree = ET.parse(path) root = tree.getroot() @@ -172,17 +154,18 @@ class DataLibrary(list): directory = os.path.dirname(path) for lib_element in root.findall('library'): - filename = os.path.join(directory, get_text(lib_element, "path")) - filetype = get_text(lib_element, "type") - materials = get_elem_list(lib_element, "materials", str) or [] + filename = os.path.join(directory, lib_element.attrib['path']) + filetype = lib_element.attrib['type'] + materials = lib_element.attrib['materials'].split() library = {'path': filename, 'type': filetype, 'materials': materials} data.libraries.append(library) # get depletion chain data + dep_node = root.find("depletion_chain") if dep_node is not None: - filename = os.path.join(directory, get_text(dep_node, "path")) + filename = os.path.join(directory, dep_node.attrib['path']) library = {'path': filename, 'type': 'depletion_chain', 'materials': []} data.libraries.append(library) diff --git a/openmc/data/mass16.txt b/openmc/data/mass16.txt new file mode 100644 index 000000000..4b479be45 --- /dev/null +++ b/openmc/data/mass16.txt @@ -0,0 +1,3475 @@ +1 a0boogfu A T O M I C M A S S A D J U S T M E N T +0 DATE 1 Mar 2017 TIME 17:26 +0 ********************* A= 0 TO 295 + * file : mass16.txt * + ********************* + + This is one file out of a series of 3 files published in: + "The Ame2016 atomic mass evaluation (I)" by W.J.Huang, G.Audi, M.Wang, F.G.Kondev, S.Naimi and X.Xu + Chinese Physics C41 030002, March 2017. + "The Ame2016 atomic mass evaluation (II)" by M.Wang, G.Audi, F.G.Kondev, W.J.Huang, S.Naimi and X.Xu + Chinese Physics C41 030003, March 2017. + for files : mass16.txt : atomic masses + rct1-16.txt : react and sep energies, part 1 + rct2-16.txt : react and sep energies, part 2 + A fourth file is the "Rounded" version of the atomic mass table (the first file) + mass16round.txt : atomic masses "Rounded" version + + All files are 3436 lines long with 124 character per line. + Headers are 39 lines long. + Values in files 1, 2 and 3 are unrounded copy of the published ones + Values in file 4 are exact copy of the published ones + + col 1 : Fortran character control: 1 = page feed 0 = line feed + format : a1,i3,i5,i5,i5,1x,a3,a4,1x,f13.5,f11.5,f11.3,f9.3,1x,a2,f11.3,f9.3,1x,i3,1x,f12.5,f11.5 + cc NZ N Z A el o mass unc binding unc B beta unc atomic_mass unc + Warnings : this format is identical to the ones used in Ame2003 and Ame2012 + in particular "Mass Excess" and "Atomic Mass" values are given now, when necessary, + with 5 digits after decimal point. + decimal point is replaced by # for (non-experimental) estimated values. + * in place of value : not calculable + +....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+...10....+...11....+...12.... + + + MASS LIST + for analysis + +1N-Z N Z A EL O MASS EXCESS BINDING ENERGY/A BETA-DECAY ENERGY ATOMIC MASS + (keV) (keV) (keV) (micro-u) +0 1 1 0 1 n 8071.31713 0.00046 0.0 0.0 B- 782.347 0.000 1 008664.91582 0.00049 + -1 0 1 1 H 7288.97061 0.00009 0.0 0.0 B- * 1 007825.03224 0.00009 +0 0 1 1 2 H 13135.72176 0.00011 1112.283 0.000 B- * 2 014101.77811 0.00012 +0 1 2 1 3 H 14949.80993 0.00022 2827.265 0.000 B- 18.592 0.000 3 016049.28199 0.00023 + -1 1 2 3 He 14931.21793 0.00021 2572.680 0.000 B- -13736# 2000# 3 016029.32265 0.00022 + -3 0 3 3 Li -pp 28667# 2000# -2267# 667# B- * 3 030775# 2147# +0 2 3 1 4 H -n 24621.127 100.000 1720.449 25.000 B- 22196.211 100.000 4 026431.868 107.354 + 0 2 2 4 He 2424.91561 0.00006 7073.915 0.000 B- -22898.273 212.132 4 002603.25413 0.00006 + -2 1 3 4 Li -p 25323.189 212.132 1153.760 53.033 B- * 4 027185.562 227.733 +0 3 4 1 5 H -nn 32892.444 89.443 1336.359 17.889 B- 21661.211 91.652 5 035311.493 96.020 + 1 3 2 5 He -n 11231.233 20.000 5512.132 4.000 B- -447.654 53.852 5 012057.224 21.470 + -1 2 3 5 Li -p 11678.886 50.000 5266.132 10.000 B- -25460# 2003# 5 012537.800 53.677 + -3 1 4 5 Be x 37139# 2003# 18# 401# B- * 5 039870# 2150# +0 4 5 1 6 H -3n 41875.721 254.127 961.639 42.354 B- 24283.626 254.127 6 044955.437 272.816 + 2 4 2 6 He 17592.095 0.053 4878.519 0.009 B- 3505.216 0.053 6 018885.891 0.057 + 0 3 3 6 Li 14086.87895 0.00144 5332.331 0.000 B- -4288.154 5.448 6 015122.88742 0.00155 + -2 2 4 6 Be - 18375.033 5.448 4487.247 0.908 B- -28945# 2003# 6 019726.409 5.848 + -4 1 5 6 B x 47320# 2003# -467# 334# B- * 6 050800# 2150# +0 5 6 1 7 H -nn 49135# 1004# 940# 143# B- 23062# 1004# 7 052749# 1078# + 3 5 2 7 He -n 26073.126 7.559 4123.057 1.080 B- 11166.021 7.559 7 027990.654 8.115 + 1 4 3 7 Li 14907.10529 0.00423 5606.439 0.001 B- -861.893 0.071 7 016003.43666 0.00454 + -1 3 4 7 Be 15768.999 0.071 5371.548 0.010 B- -11907.551 25.150 7 016928.717 0.076 + -3 2 5 7 B p4n 27676.550 25.150 3558.705 3.593 B- * 7 029712.000 27.000 +0 4 6 2 8 He 31609.681 0.089 3924.520 0.011 B- 10663.878 0.100 8 033934.390 0.095 + 2 5 3 8 Li 20945.804 0.047 5159.712 0.006 B- 16004.133 0.059 8 022486.246 0.050 + 0 4 4 8 Be -a 4941.671 0.035 7062.435 0.004 B- -17979.896 1.000 8 005305.102 0.037 + -2 3 5 8 B 22921.567 1.000 4717.155 0.125 B- -12142.701 18.270 8 024607.316 1.073 + -4 2 6 8 C 35064.268 18.243 3101.524 2.280 B- * 8 037643.042 19.584 +0 5 7 2 9 He 40935.826 46.816 3349.037 5.202 B- 15980.924 46.817 9 043946.419 50.259 + 3 6 3 9 Li -3n 24954.902 0.186 5037.768 0.021 B- 13606.449 0.201 9 026790.191 0.200 + 1 5 4 9 Be 11348.453 0.077 6462.668 0.009 B- -1068.035 0.899 9 012183.066 0.082 + -1 4 5 9 B - 12416.488 0.903 6257.070 0.100 B- -16494.484 2.319 9 013329.649 0.969 + -3 3 6 9 C -pp 28910.972 2.137 4337.423 0.237 B- * 9 031037.207 2.293 +0 6 8 2 10 He -nn 49197.143 92.848 2995.134 9.285 B- 16144.519 93.715 10 052815.308 99.676 + 4 7 3 10 Li -n 33052.624 12.721 4531.351 1.272 B- 20445.136 12.722 10 035483.453 13.656 + 2 6 4 10 Be 12607.488 0.081 6497.630 0.008 B- 556.878 0.082 10 013534.695 0.086 + 0 5 5 10 B 12050.609 0.015 6475.083 0.002 B- -3648.062 0.069 10 012936.862 0.016 + -2 4 6 10 C 15698.672 0.070 6032.042 0.007 B- -23101.355 400.000 10 016853.218 0.075 + -4 3 7 10 N -- 38800.026 400.000 3643.672 40.000 B- * 10 041653.543 429.417 +0 5 8 3 11 Li x 40728.254 0.615 4155.381 0.056 B- 20551.087 0.659 11 043723.581 0.660 + 3 7 4 11 Be 20177.167 0.238 5952.540 0.022 B- 11509.460 0.238 11 021661.081 0.255 + 1 6 5 11 B 8667.707 0.012 6927.732 0.001 B- -1981.689 0.061 11 009305.166 0.013 + -1 5 6 11 C 10649.396 0.060 6676.456 0.005 B- -13654.163 46.154 11 011432.597 0.064 + -3 4 7 11 N -p 24303.559 46.154 5364.046 4.196 B- * 11 026090.945 49.548 +0 6 9 3 12 Li -n 49009.571 30.006 3791.600 2.501 B- 23931.812 30.067 12 052613.941 32.213 + 4 8 4 12 Be 25077.760 1.909 5720.722 0.159 B- 11708.363 2.321 12 026922.083 2.048 + 2 7 5 12 B 13369.397 1.321 6631.223 0.110 B- 13369.397 1.321 12 014352.638 1.418 + 0 6 6 12 C 0.0 0.0 7680.144 0.000 B- -17338.068 1.000 12 000000.0 0.0 + -2 5 7 12 N 17338.068 1.000 6170.109 0.083 B- -14576.544 24.021 12 018613.182 1.073 + -4 4 8 12 O -pp 31914.613 24.000 4890.202 2.000 B- * 12 034261.747 25.765 +0 7 10 3 13 Li -nn 56980.888 70.003 3507.630 5.385 B- 23321.812 70.739 13 061171.503 75.150 + 5 9 4 13 Be -n 33659.077 10.180 5241.435 0.783 B- 17097.130 10.230 13 036134.507 10.929 + 3 8 5 13 B -nn 16561.947 1.000 6496.419 0.077 B- 13436.938 1.000 13 017779.981 1.073 + 1 7 6 13 C 3125.00888 0.00021 7469.849 0.000 B- -2220.472 0.270 13 003354.83521 0.00023 + -1 6 7 13 N 5345.481 0.270 7238.863 0.021 B- -17769.951 9.530 13 005738.609 0.289 + -3 5 8 13 O +3n 23115.432 9.526 5811.763 0.733 B- * 13 024815.437 10.226 +0 6 10 4 14 Be x 39954.498 132.245 4993.897 9.446 B- 16290.813 133.936 14 042892.920 141.970 + 4 9 5 14 B 23663.685 21.213 6101.644 1.515 B- 20643.792 21.213 14 025404.012 22.773 + 2 8 6 14 C 3019.89278 0.00376 7520.319 0.000 B- 156.476 0.004 14 003241.98843 0.00403 + 0 7 7 14 N 2863.41672 0.00019 7475.614 0.000 B- -5144.364 0.025 14 003074.00446 0.00021 + -2 6 8 14 O 8007.781 0.025 7052.278 0.002 B- -23956.622 41.119 14 008596.706 0.027 + -4 5 9 14 F -p 31964.402 41.119 5285.208 2.937 B- * 14 034315.199 44.142 +0 7 11 4 15 Be -n 49825.815 165.797 4540.970 11.053 B- 20867.573 167.126 15 053490.215 177.990 + 5 10 5 15 B 28958.242 21.032 5879.985 1.402 B- 19085.098 21.047 15 031087.953 22.578 + 3 9 6 15 C -n 9873.144 0.800 7100.169 0.053 B- 9771.705 0.800 15 010599.256 0.858 + 1 8 7 15 N 101.43871 0.00060 7699.460 0.000 B- -2754.166 0.491 15 000108.89894 0.00065 + -1 7 8 15 O 2855.605 0.491 7463.692 0.033 B- -13711.146 14.009 15 003065.618 0.526 + -3 6 9 15 F -p 16566.751 14.000 6497.459 0.933 B- -23648.622 68.138 15 017785.139 15.029 + -5 5 10 15 Ne -pp 40215.373 66.684 4868.728 4.446 B- * 15 043172.980 71.588 +0 8 12 4 16 Be -nn 57447.132 165.797 4285.285 10.362 B- 20334.623 167.608 16 061672.036 177.990 + 6 11 5 16 B 37112.510 24.569 5507.302 1.536 B- 23418.378 24.828 16 039841.920 26.375 + 4 10 6 16 C -nn 13694.132 3.578 6922.054 0.224 B- 8010.225 4.254 16 014701.256 3.840 + 2 9 7 16 N -n 5683.907 2.301 7373.796 0.144 B- 10420.908 2.301 16 006101.925 2.470 + 0 8 8 16 O -4737.00135 0.00016 7976.206 0.000 B- -15417.254 8.321 15 994914.61960 0.00017 + -2 7 9 16 F - 10680.253 8.321 6963.731 0.520 B- -13306.523 22.106 16 011465.723 8.932 + -4 6 10 16 Ne -- 23986.776 20.480 6083.177 1.280 B- * 16 025750.864 21.986 +0 7 12 5 17 B x 43716.317 204.104 5269.667 12.006 B- 22684.419 204.841 17 046931.399 219.114 + 5 11 6 17 C 2p-n 21031.898 17.365 6558.024 1.021 B- 13161.820 22.946 17 022578.672 18.641 + 3 10 7 17 N +p 7870.079 15.000 7286.229 0.882 B- 8678.842 15.000 17 008448.877 16.103 + 1 9 8 17 O -808.76348 0.00066 7750.728 0.000 B- -2760.465 0.248 16 999131.75664 0.00070 + -1 8 9 17 F 1951.702 0.248 7542.328 0.015 B- -14548.746 0.432 17 002095.238 0.266 + -3 7 10 17 Ne 16500.447 0.354 6640.499 0.021 B- -18672.766 1001.356 17 017713.959 0.380 + -5 6 11 17 Na x 35173.214 1001.356 5496.080 58.903 B- * 17 037760.000 1075.000 +0 8 13 5 18 B -n 51792.634 204.165 4976.630 11.342 B- 26873.370 206.357 18 055601.682 219.180 + 6 12 6 18 C ++ 24919.264 30.000 6426.131 1.667 B- 11806.096 35.282 18 026751.932 32.206 + 4 11 7 18 N + 13113.168 18.570 7038.562 1.032 B- 13895.984 18.570 18 014077.565 19.935 + 2 10 8 18 O -782.81560 0.00071 7767.097 0.000 B- -1655.929 0.463 17 999159.61284 0.00076 + 0 9 9 18 F 873.113 0.463 7631.638 0.026 B- -4444.501 0.589 18 000937.325 0.497 + -2 8 10 18 Ne 5317.614 0.363 7341.257 0.020 B- -19720.374 93.882 18 005708.693 0.390 + -4 7 11 18 Na 25037.988 93.881 6202.217 5.216 B- * 18 026879.386 100.785 +0 9 14 5 19 B x 59770.244 525.363 4719.634 27.651 B- 27356.492 534.496 19 064166.000 564.000 + 7 13 6 19 C -n 32413.752 98.389 6118.273 5.178 B- 16557.471 99.748 19 034797.596 105.625 + 5 12 7 19 N p-2n 15856.282 16.404 6948.543 0.863 B- 12523.424 16.614 19 017022.419 17.610 + 3 11 8 19 O -n 3332.858 2.637 7566.495 0.139 B- 4820.302 2.637 19 003577.970 2.830 + 1 10 9 19 F -1487.44420 0.00086 7779.018 0.000 B- -3239.494 0.160 18 998403.16288 0.00093 + -1 9 10 19 Ne +3n 1752.050 0.160 7567.343 0.008 B- -11177.340 10.536 19 001880.903 0.171 + -3 8 11 19 Na 12929.390 10.535 6937.885 0.554 B- -18898.998 51.099 19 013880.272 11.309 + -5 7 12 19 Mg -pp 31828.389 50.001 5902.025 2.632 B- * 19 034169.182 53.678 +0 10 15 5 20 B x 68450# 800# 4453# 40# B- 30946# 833# 20 073484# 859# + 8 14 6 20 C x 37503.563 230.625 5961.435 11.531 B- 15737.067 243.746 20 040261.732 247.585 + 6 13 7 20 N x 21766.496 78.894 6709.171 3.945 B- 17970.324 78.899 20 023367.295 84.696 + 4 12 8 20 O -nn 3796.172 0.885 7568.570 0.044 B- 3813.635 0.885 20 004075.358 0.950 + 2 11 9 20 F -n -17.463 0.030 7720.134 0.002 B- 7024.467 0.030 19 999981.252 0.031 + 0 10 10 20 Ne -7041.93055 0.00157 8032.240 0.000 B- -13892.535 1.114 19 992440.17619 0.00168 + -2 9 11 20 Na 6850.604 1.114 7298.496 0.056 B- -10627.088 2.171 20 007354.426 1.195 + -4 8 12 20 Mg +t 17477.692 1.863 6728.025 0.093 B- * 20 018763.075 2.000 +0 11 16 5 21 B x 77330# 900# 4203# 43# B- 31687# 1079# 21 083017# 966# + 9 15 6 21 C x 45643# 596# 5674# 28# B- 20411# 611# 21 049000# 640# + 7 14 7 21 N x 25231.913 134.048 6609.015 6.383 B- 17169.878 134.584 21 027087.573 143.906 + 5 13 8 21 O -3n 8062.035 12.000 7389.374 0.571 B- 8109.640 12.134 21 008654.950 12.882 + 3 12 9 21 F -nn -47.605 1.800 7738.293 0.086 B- 5684.171 1.800 20 999948.894 1.932 + 1 11 10 21 Ne -5731.776 0.038 7971.713 0.002 B- -3547.145 0.090 20 993846.685 0.041 + -1 10 11 21 Na -2184.631 0.098 7765.547 0.005 B- -13088.480 0.761 20 997654.702 0.105 + -3 9 12 21 Mg x 10903.850 0.755 7105.031 0.036 B- -16086# 596# 21 011705.764 0.810 + -5 8 13 21 Al x 26990# 596# 6302# 28# B- * 21 028975# 640# +0 10 16 6 22 C -nn 53611.197 231.490 5421.077 10.522 B- 21846.396 311.063 22 057553.990 248.515 + 8 15 7 22 N x 31764.801 207.779 6378.534 9.445 B- 22481.768 215.435 22 034100.918 223.060 + 6 14 8 22 O -4n 9283.033 56.921 7364.871 2.587 B- 6489.660 58.256 22 009965.746 61.107 + 4 13 9 22 F + 2793.373 12.399 7624.295 0.564 B- 10818.092 12.399 22 002998.809 13.310 + 2 12 10 22 Ne -8024.719 0.018 8080.465 0.001 B- -2843.207 0.171 21 991385.109 0.018 + 0 11 11 22 Na -5181.511 0.171 7915.667 0.008 B- -4781.578 0.321 21 994437.418 0.183 + -2 10 12 22 Mg -399.933 0.313 7662.761 0.014 B- -18601# 401# 21 999570.654 0.335 + -4 9 13 22 Al x 18201# 401# 6782# 18# B- -15137# 643# 22 019540# 430# + -6 8 14 22 Si x 33338# 503# 6058# 23# B- * 22 035790# 540# +0 11 17 6 23 C x 64171# 997# 5077# 43# B- 27450# 1082# 23 068890# 1070# + 9 16 7 23 N x 36720.425 420.570 6236.671 18.286 B- 22099.056 437.827 23 039421.000 451.500 + 7 15 8 23 O x 14621.369 121.712 7163.485 5.292 B- 11336.106 126.190 23 015696.686 130.663 + 5 14 9 23 F 3285.263 33.320 7622.344 1.449 B- 8439.312 33.321 23 003526.874 35.770 + 3 13 10 23 Ne -n -5154.049 0.104 7955.256 0.005 B- 4375.804 0.104 22 994466.900 0.112 + 1 12 11 23 Na -9529.85248 0.00181 8111.493 0.000 B- -4056.340 0.158 22 989769.28199 0.00194 + -1 11 12 23 Mg - -5473.513 0.158 7901.115 0.007 B- -12221.583 0.379 22 994123.941 0.170 + -3 10 13 23 Al -- 6748.070 0.345 7335.727 0.015 B- -16949# 503# 23 007244.351 0.370 + -5 9 14 23 Si x 23697# 503# 6565# 22# B- * 23 025440# 540# +0 10 17 7 24 N x 46938# 401# 5887# 17# B- 28438# 433# 24 050390# 430# + 8 16 8 24 O x 18500.402 164.874 7039.685 6.870 B- 10955.887 191.633 24 019861.000 177.000 + 6 15 9 24 F x 7544.515 97.670 7463.582 4.070 B- 13496.161 97.672 24 008099.370 104.853 + 4 14 10 24 Ne -nn -5951.646 0.513 7993.325 0.021 B- 2466.255 0.513 23 993610.645 0.550 + 2 13 11 24 Na -n -8417.901 0.017 8063.488 0.001 B- 5515.669 0.021 23 990963.011 0.017 + 0 12 12 24 Mg -13933.569 0.013 8260.709 0.001 B- -13884.704 0.233 23 985041.697 0.014 + -2 11 13 24 Al ep -48.865 0.233 7649.582 0.010 B- -10794.060 19.473 23 999947.541 0.250 + -4 10 14 24 Si -- 10745.195 19.472 7167.232 0.811 B- -22574# 503# 24 011535.441 20.904 + -6 9 15 24 P x 33320# 503# 6194# 21# B- * 24 035770# 540# +0 11 18 7 25 N x 55983# 503# 5613# 20# B- 28654# 529# 25 060100# 540# + 9 17 8 25 O -n 27329.027 165.084 6727.805 6.603 B- 15994.862 191.191 25 029338.919 177.225 + 7 16 9 25 F x 11334.166 96.442 7336.306 3.858 B- 13369.667 100.721 25 012167.727 103.535 + 5 15 10 25 Ne -2035.502 29.045 7839.799 1.162 B- 7322.312 29.070 24 997814.799 31.181 + 3 14 11 25 Na -nn -9357.813 1.200 8101.397 0.048 B- 3834.969 1.201 24 989953.973 1.288 + 1 13 12 25 Mg -13192.783 0.047 8223.502 0.002 B- -4276.808 0.045 24 985836.964 0.050 + -1 12 13 25 Al -8915.975 0.065 8021.136 0.003 B- -12743.299 10.000 24 990428.306 0.069 + -3 11 14 25 Si +3n 3827.324 10.000 7480.110 0.400 B- -15911# 401# 25 004108.801 10.735 + -5 10 15 25 P x 19738# 401# 6812# 16# B- * 25 021190# 430# +0 10 18 8 26 O -nn 34661.037 164.950 6497.478 6.344 B- 16012.161 198.932 26 037210.155 177.081 + 8 17 9 26 F x 18648.875 111.199 7083.240 4.277 B- 18167.762 112.716 26 020020.392 119.377 + 6 16 10 26 Ne x 481.114 18.429 7751.910 0.709 B- 7341.893 18.758 26 000516.496 19.784 + 4 15 11 26 Na x -6860.780 3.502 8004.201 0.135 B- 9353.763 3.502 25 992634.649 3.759 + 2 14 12 26 Mg -16214.542 0.030 8333.870 0.001 B- -4004.391 0.063 25 982592.971 0.032 + 0 13 13 26 Al -12210.151 0.067 8149.765 0.003 B- -5069.136 0.085 25 986891.863 0.071 + -2 12 14 26 Si - -7141.015 0.108 7924.708 0.004 B- -18114# 196# 25 992333.804 0.115 + -4 11 15 26 P x 10973# 196# 7198# 8# B- -16106# 627# 26 011780# 210# + -6 10 16 26 S x 27079# 596# 6548# 23# B- * 26 029070# 640# +0 11 19 8 27 O x 44670# 500# 6185# 19# B- 19220# 634# 27 047955# 537# + 9 18 9 27 F x 25450.279 389.830 6867.932 14.438 B- 18399.370 400.258 27 027322.000 418.500 + 7 17 10 27 Ne x 7050.909 90.770 7520.414 3.362 B- 12568.699 90.847 27 007569.462 97.445 + 5 16 11 27 Na ++ -5517.790 3.726 7956.946 0.138 B- 9068.821 3.727 26 994076.408 4.000 + 3 15 12 27 Mg -n -14586.611 0.050 8263.852 0.002 B- 2610.251 0.069 26 984340.628 0.053 + 1 14 13 27 Al -17196.861 0.047 8331.553 0.002 B- -4812.359 0.096 26 981538.408 0.050 + -1 13 14 27 Si - -12384.503 0.107 8124.341 0.004 B- -11662.044 26.340 26 986704.688 0.115 + -3 12 15 27 P p4n -722.458 26.340 7663.438 0.976 B- -17750# 400# 26 999224.409 28.277 + -5 11 16 27 S - 17028# 401# 6977# 15# B- * 27 018280# 430# +0 12 20 8 28 O x 52080# 699# 5988# 25# B- 18338# 802# 28 055910# 750# + 10 19 9 28 F -n 33741.596 393.024 6614.792 14.037 B- 22441.859 412.748 28 036223.095 421.928 + 8 18 10 28 Ne x 11299.737 126.068 7388.346 4.502 B- 12288.052 126.483 28 012130.767 135.339 + 6 17 11 28 Na x -988.315 10.246 7799.264 0.366 B- 14030.529 10.440 27 998939.000 11.000 + 4 16 12 28 Mg + -15018.845 2.001 8272.413 0.071 B- 1831.800 2.000 27 983876.606 2.148 + 2 15 13 28 Al -n -16850.645 0.077 8309.894 0.003 B- 4642.150 0.077 27 981910.087 0.083 + 0 14 14 28 Si -21492.79430 0.00049 8447.744 0.000 B- -14345.055 1.152 27 976926.53499 0.00052 + -2 13 15 28 P -7147.740 1.152 7907.479 0.041 B- -11220.945 160.004 27 992326.585 1.236 + -4 12 16 28 S -- 4073.206 160.000 7478.790 5.714 B- -23443# 617# 28 004372.766 171.767 + -6 11 17 28 Cl x 27516# 596# 6614# 21# B- * 28 029540# 640# +0 11 20 9 29 F x 40150.186 525.363 6444.031 18.116 B- 21750.385 546.221 29 043103.000 564.000 + 9 19 10 29 Ne x 18399.801 149.505 7167.067 5.155 B- 15719.807 149.685 29 019753.000 160.500 + 7 18 11 29 Na 2679.994 7.337 7682.151 0.253 B- 13282.824 13.557 29 002877.092 7.876 + 5 17 12 29 Mg x -10602.829 11.400 8113.202 0.393 B- 7604.931 11.405 28 988617.393 12.238 + 3 16 13 29 Al x -18207.760 0.345 8348.464 0.012 B- 3687.318 0.345 28 980453.164 0.370 + 1 15 14 29 Si -21895.07838 0.00056 8448.635 0.000 B- -4942.230 0.359 28 976494.66525 0.00060 + -1 14 15 29 P -16952.848 0.359 8251.236 0.012 B- -13796.432 50.001 28 981800.368 0.385 + -3 13 16 29 S +3n -3156.416 50.000 7748.520 1.724 B- -16318.592 195.192 28 996611.448 53.677 + -5 12 17 29 Cl -p 13162.176 188.680 7158.832 6.506 B- * 29 014130.178 202.555 +0 12 21 9 30 F x 48112# 596# 6233# 20# B- 24832# 648# 30 051650# 640# + 10 20 10 30 Ne 23280.117 253.250 7034.531 8.442 B- 14805.448 253.295 30 024992.235 271.875 + 8 19 11 30 Na 8474.670 4.727 7501.968 0.158 B- 17358.490 5.850 30 009097.932 5.074 + 6 18 12 30 Mg x -8883.820 3.447 8054.506 0.115 B- 6981.024 4.496 29 990462.826 3.700 + 4 17 13 30 Al x -15864.844 2.888 8261.128 0.096 B- 8568.116 2.888 29 982968.388 3.100 + 2 16 14 30 Si -n -24432.960 0.022 8520.654 0.001 B- -4232.106 0.061 29 973770.136 0.023 + 0 15 15 30 P - -20200.854 0.065 8353.506 0.002 B- -6141.601 0.196 29 978313.489 0.069 + -2 14 16 30 S - -14059.253 0.206 8122.707 0.007 B- -18502# 196# 29 984906.769 0.221 + -4 13 17 30 Cl x 4443# 196# 7480# 7# B- -16488# 284# 30 004770# 210# + -6 12 18 30 Ar -pp 20931.147 206.155 6904.204 6.872 B- * 30 022470.511 221.316 +0 13 22 9 31 F -nn 56143# 546# 6033# 18# B- 24961# 608# 31 060272# 587# + 11 21 10 31 Ne 31181.591 266.195 6813.090 8.587 B- 18935.559 266.562 31 033474.816 285.772 + 9 20 11 31 Na x 12246.031 13.972 7398.677 0.451 B- 15368.182 14.307 31 013146.656 15.000 + 7 19 12 31 Mg x -3122.151 3.074 7869.188 0.099 B- 11828.555 3.801 30 996648.232 3.300 + 5 18 13 31 Al x -14950.706 2.236 8225.517 0.072 B- 7998.330 2.236 30 983949.756 2.400 + 3 17 14 31 Si -n -22949.036 0.043 8458.291 0.001 B- 1491.505 0.043 30 975363.194 0.046 + 1 16 15 31 P -24440.54095 0.00067 8481.167 0.000 B- -5398.016 0.229 30 973761.99863 0.00072 + -1 15 16 31 S -19042.525 0.229 8281.800 0.007 B- -12007.974 3.454 30 979557.007 0.246 + -3 14 17 31 Cl -- -7034.551 3.447 7869.209 0.111 B- -18360# 200# 30 992448.098 3.700 + -5 13 18 31 Ar - 11325# 200# 7252# 6# B- * 31 012158# 215# +0 12 22 10 32 Ne x 36999# 503# 6671# 16# B- 18359# 504# 32 039720# 540# + 10 21 11 32 Na x 18640.151 37.260 7219.881 1.164 B- 19469.051 37.402 32 020011.026 40.000 + 8 20 12 32 Mg x -828.900 3.260 7803.840 0.102 B- 10270.467 7.879 31 999110.139 3.500 + 6 19 13 32 Al x -11099.367 7.173 8100.344 0.224 B- 12978.319 7.179 31 988084.339 7.700 + 4 18 14 32 Si x -24077.686 0.298 8481.468 0.009 B- 227.188 0.301 31 974151.539 0.320 + 2 17 15 32 P -n -24304.874 0.040 8464.120 0.001 B- 1710.660 0.040 31 973907.643 0.042 + 0 16 16 32 S -26015.53355 0.00132 8493.129 0.000 B- -12680.860 0.562 31 972071.17443 0.00141 + -2 15 17 32 Cl -13334.674 0.562 8072.404 0.018 B- -11134.323 1.857 31 985684.637 0.603 + -4 14 18 32 Ar x -2200.351 1.770 7700.008 0.055 B- -23299# 401# 31 997637.826 1.900 + -6 13 19 32 K x 21098# 401# 6947# 13# B- * 32 022650# 430# +0 13 23 10 33 Ne x 45997# 596# 6440# 18# B- 22217# 747# 33 049380# 640# + 11 22 11 33 Na x 23780.110 449.912 7089.926 13.634 B- 18817.813 449.921 33 025529.000 483.000 + 9 21 12 33 Mg x 4962.297 2.888 7636.455 0.088 B- 13459.677 7.559 33 005327.245 3.100 + 7 20 13 33 Al x -8497.380 6.986 8020.616 0.212 B- 12016.945 7.021 32 990877.687 7.500 + 5 19 14 33 Si x -20514.325 0.699 8361.059 0.021 B- 5823.021 1.295 32 977976.964 0.750 + 3 18 15 33 P + -26337.346 1.090 8513.806 0.033 B- 248.508 1.090 32 971725.694 1.170 + 1 17 16 33 S -26585.85434 0.00135 8497.630 0.000 B- -5582.517 0.391 32 971458.90985 0.00145 + -1 16 17 33 Cl -21003.337 0.391 8304.755 0.012 B- -11619.044 0.560 32 977451.989 0.419 + -3 15 18 33 Ar x -9384.292 0.401 7928.955 0.012 B- -16426# 196# 32 989925.547 0.430 + -5 14 19 33 K x 7042# 196# 7407# 6# B- * 33 007560# 210# +0 14 24 10 34 Ne -nn 52842# 513# 6287# 15# B- 21161# 789# 34 056728# 551# + 12 23 11 34 Na x 31680.111 599.416 6886.437 17.630 B- 23356.764 600.112 34 034010.000 643.500 + 10 22 12 34 Mg x 8323.348 28.876 7550.390 0.849 B- 11323.637 29.039 34 008935.481 31.000 + 8 21 13 34 Al x -3000.289 3.074 7860.428 0.090 B- 16956.563 14.448 33 996779.057 3.300 + 6 20 14 34 Si +pp -19956.852 14.118 8336.141 0.415 B- 4591.847 14.141 33 978575.437 15.155 + 4 19 15 34 P x -24548.698 0.810 8448.185 0.024 B- 5382.987 0.812 33 973645.887 0.870 + 2 18 16 34 S -29931.685 0.045 8583.498 0.001 B- -5491.603 0.038 33 967867.012 0.047 + 0 17 17 34 Cl -24440.082 0.049 8398.970 0.001 B- -6061.792 0.063 33 973762.491 0.052 + -2 16 18 34 Ar -18378.290 0.078 8197.672 0.002 B- -17158# 196# 33 980270.093 0.083 + -4 15 19 34 K x -1220# 196# 7670# 6# B- -15072# 357# 33 998690# 210# + -6 14 20 34 Ca x 13851# 298# 7204# 9# B- * 34 014870# 320# +0 13 24 11 35 Na -n 38231# 670# 6733# 19# B- 22592# 723# 35 041043# 720# + 11 23 12 35 Mg x 15639.784 269.668 7356.233 7.705 B- 15863.512 269.768 35 016790.000 289.500 + 9 22 13 35 Al x -223.728 7.359 7787.124 0.210 B- 14167.729 36.605 34 999759.817 7.900 + 7 21 14 35 Si 2p-n -14391.457 35.857 8169.563 1.024 B- 10466.342 35.905 34 984550.134 38.494 + 5 20 15 35 P +p -24857.799 1.866 8446.249 0.053 B- 3988.407 1.867 34 973314.053 2.003 + 3 19 16 35 S -28846.206 0.040 8537.850 0.001 B- 167.322 0.026 34 969032.322 0.043 + 1 18 17 35 Cl -29013.528 0.035 8520.278 0.001 B- -5966.243 0.679 34 968852.694 0.038 + -1 17 18 35 Ar - -23047.284 0.680 8327.461 0.019 B- -11874.394 0.852 34 975257.721 0.730 + -3 16 19 35 K 4n -11172.891 0.512 7965.840 0.015 B- -15961# 196# 34 988005.407 0.550 + -5 15 20 35 Ca x 4788# 196# 7487# 6# B- * 35 005140# 210# +0 14 25 11 36 Na -n 46303# 678# 6546# 19# B- 25923# 967# 36 049708# 728# + 12 24 12 36 Mg x 20380.157 690.237 7244.419 19.173 B- 14429.774 706.243 36 021879.000 741.000 + 10 23 13 36 Al x 5950.384 149.505 7623.515 4.153 B- 18386.508 165.851 36 006388.000 160.500 + 8 22 14 36 Si x -12436.124 71.797 8112.519 1.994 B- 7814.911 72.985 35 986649.271 77.077 + 6 21 15 36 P + -20251.034 13.114 8307.868 0.364 B- 10413.096 13.112 35 978259.619 14.078 + 4 20 16 36 S -30664.131 0.188 8575.389 0.005 B- -1142.126 0.189 35 967080.699 0.201 + 2 19 17 36 Cl -29522.005 0.036 8521.931 0.001 B- 709.535 0.045 35 968306.822 0.038 + 0 18 18 36 Ar -30231.540 0.027 8519.909 0.001 B- -12814.475 0.342 35 967545.105 0.028 + -2 17 19 36 K -17417.065 0.341 8142.219 0.009 B- -10965.916 40.001 35 981302.010 0.366 + -4 16 20 36 Ca 4n -6451.149 40.000 7815.879 1.111 B- -21802# 301# 35 993074.406 42.941 + -6 15 21 36 Sc x 15351# 298# 7189# 8# B- * 36 016480# 320# +0 15 26 11 37 Na -nn 53534# 687# 6392# 19# B- 25323# 980# 37 057471# 737# + 13 25 12 37 Mg -n 28211.474 698.947 7055.111 18.890 B- 18401.911 721.814 37 030286.265 750.350 + 11 24 13 37 Al x 9809.563 180.244 7531.315 4.871 B- 16381.075 213.168 37 010531.000 193.500 + 9 23 14 37 Si x -6571.511 113.809 7952.903 3.076 B- 12424.486 119.969 36 992945.191 122.179 + 7 22 15 37 P p-2n -18995.998 37.948 8267.555 1.026 B- 7900.419 37.947 36 979606.956 40.738 + 5 21 16 37 S -n -26896.417 0.198 8459.935 0.005 B- 4865.121 0.196 36 971125.507 0.212 + 3 20 17 37 Cl -31761.538 0.052 8570.281 0.001 B- -813.873 0.200 36 965902.584 0.055 + 1 19 18 37 Ar - -30947.664 0.207 8527.139 0.006 B- -6147.465 0.227 36 966776.314 0.221 + -1 18 19 37 K -p -24800.199 0.094 8339.847 0.003 B- -11664.133 0.641 36 973375.889 0.100 + -3 17 20 37 Ca x -13136.066 0.634 8003.456 0.017 B- -16656# 300# 36 985897.852 0.680 + -5 16 21 37 Sc x 3520# 300# 7532# 8# B- * 37 003779# 322# +0 14 26 12 38 Mg x 34074# 503# 6928# 13# B- 17864# 627# 38 036580# 540# + 12 25 13 38 Al x 16209.859 374.461 7377.097 9.854 B- 20380.157 388.847 38 017402.000 402.000 + 10 24 14 38 Si x -4170.299 104.793 7892.829 2.758 B- 10451.265 127.474 37 995523.000 112.500 + 8 23 15 38 P x -14621.563 72.581 8147.274 1.910 B- 12239.640 72.934 37 984303.105 77.918 + 6 22 16 38 S + -26861.203 7.172 8448.782 0.189 B- 2936.900 7.171 37 971163.310 7.699 + 4 21 17 38 Cl -n -29798.103 0.098 8505.481 0.003 B- 4916.718 0.218 37 968010.418 0.105 + 2 20 18 38 Ar -34714.821 0.195 8614.280 0.005 B- -5914.066 0.045 37 962732.104 0.209 + 0 19 19 38 K -28800.755 0.195 8438.058 0.005 B- -6742.256 0.063 37 969081.116 0.209 + -2 18 20 38 Ca -22058.499 0.194 8240.043 0.005 B- -17809# 200# 37 976319.226 0.208 + -4 17 21 38 Sc x -4249# 200# 7751# 5# B- -15119# 361# 37 995438# 215# + -6 16 22 38 Ti x 10870# 300# 7332# 8# B- * 38 011669# 322# +0 15 27 12 39 Mg -n 42275# 513# 6747# 13# B- 21625# 650# 39 045384# 551# + 13 26 13 39 Al x 20650# 400# 7281# 10# B- 18330# 422# 39 022169# 429# + 11 25 14 39 Si x 2320.352 135.532 7730.979 3.475 B- 15094.986 176.232 39 002491.000 145.500 + 9 24 15 39 P x -12774.634 112.645 8097.969 2.888 B- 10388.033 123.243 38 986285.865 120.929 + 7 23 16 39 S 2p-n -23162.667 50.000 8344.269 1.282 B- 6637.538 50.030 38 975133.852 53.677 + 5 22 17 39 Cl -nn -29800.205 1.732 8494.402 0.044 B- 3441.985 5.292 38 968008.162 1.859 + 3 21 18 39 Ar + -33242.190 5.000 8562.598 0.128 B- 565.000 5.000 38 964313.039 5.367 + 1 20 19 39 K -33807.19010 0.00458 8557.025 0.000 B- -6524.488 0.596 38 963706.48661 0.00492 + -1 19 20 39 Ca -27282.702 0.596 8369.670 0.015 B- -13109.993 24.007 38 970710.813 0.640 + -3 18 21 39 Sc 2n-p -14172.709 24.000 8013.456 0.615 B- -16373# 202# 38 984784.970 25.765 + -5 17 22 39 Ti x 2200# 200# 7574# 5# B- * 39 002362# 215# +0 16 28 12 40 Mg x 48350# 500# 6628# 13# B- 20760# 640# 40 051906# 537# + 14 27 13 40 Al x 27590# 400# 7127# 10# B- 22160# 528# 40 029619# 429# + 12 26 14 40 Si x 5429.679 345.119 7661.754 8.628 B- 13544.049 377.749 40 005829.000 370.500 + 10 25 15 40 P x -8114.370 153.582 7980.796 3.840 B- 14723.476 153.633 39 991288.865 164.876 + 8 24 16 40 S -22837.846 3.982 8329.325 0.100 B- 4719.967 32.312 39 975482.562 4.274 + 6 23 17 40 Cl + -27557.813 32.066 8427.765 0.802 B- 7482.082 32.066 39 970415.469 34.423 + 4 22 18 40 Ar -35039.89464 0.00224 8595.259 0.000 B- -1504.403 0.056 39 962383.12378 0.00240 + 2 21 19 40 K -33535.492 0.056 8538.090 0.001 B- 1310.893 0.060 39 963998.166 0.060 + 0 20 20 40 Ca -34846.384 0.021 8551.303 0.001 B- -14323.050 2.828 39 962590.865 0.022 + -2 19 21 40 Sc - -20523.335 2.828 8173.669 0.071 B- -11672.950 160.025 39 977967.292 3.036 + -4 18 22 40 Ti -- -8850.384 160.000 7862.286 4.000 B- -21020# 340# 39 990498.721 171.767 + -6 17 23 40 V x 12170# 300# 7317# 7# B- * 40 013065# 322# +0 15 28 13 41 Al x 33420# 500# 7008# 12# B- 21300# 747# 41 035878# 537# + 13 27 14 41 Si x 12119.668 554.705 7508.573 13.529 B- 17099.435 567.571 41 013011.000 595.500 + 11 26 15 41 P x -4979.767 120.163 7906.551 2.931 B- 14028.810 120.233 40 994654.000 129.000 + 9 25 16 41 S x -19008.577 4.099 8229.635 0.100 B- 8298.611 68.846 40 979593.451 4.400 + 7 24 17 41 Cl x -27307.189 68.723 8412.959 1.676 B- 5760.317 68.724 40 970684.525 73.777 + 5 23 18 41 Ar -n -33067.505 0.347 8534.372 0.008 B- 2492.038 0.347 40 964500.571 0.372 + 3 22 19 41 K -35559.54331 0.00380 8576.072 0.000 B- -421.653 0.138 40 961825.25796 0.00408 + 1 21 20 41 Ca -35137.890 0.138 8546.706 0.003 B- -6495.478 0.158 40 962277.921 0.147 + -1 20 21 41 Sc -28642.412 0.083 8369.198 0.002 B- -12944.875 27.945 40 969251.104 0.088 + -3 19 22 41 Ti x -15697.537 27.945 8034.388 0.682 B- -16018# 202# 40 983148.000 30.000 + -5 18 23 41 V x 320# 200# 7625# 5# B- * 41 000344# 215# +0 16 29 13 42 Al x 40100# 600# 6874# 14# B- 23630# 781# 42 043049# 644# + 14 28 14 42 Si x 16470# 500# 7418# 12# B- 15460# 591# 42 017681# 537# + 12 27 15 42 P x 1009.740 314.379 7767.866 7.485 B- 18647.485 314.392 42 001084.000 337.500 + 10 26 16 42 S x -17637.746 2.794 8193.227 0.067 B- 7194.021 59.681 41 981065.100 3.000 + 8 25 17 42 Cl x -24831.767 59.616 8345.886 1.419 B- 9590.908 59.895 41 973342.000 64.000 + 6 24 18 42 Ar x -34422.675 5.775 8555.613 0.138 B- 599.351 5.776 41 963045.736 6.200 + 4 23 19 42 K -n -35022.026 0.106 8551.256 0.003 B- 3525.219 0.183 41 962402.306 0.113 + 2 22 20 42 Ca -38547.245 0.149 8616.563 0.004 B- -6426.092 0.097 41 958617.828 0.159 + 0 21 21 42 Sc -32121.153 0.169 8444.933 0.004 B- -7016.479 0.224 41 965516.522 0.181 + -2 20 22 42 Ti -25104.674 0.277 8259.247 0.007 B- -17485# 196# 41 973049.022 0.297 + -4 19 23 42 V x -7620# 196# 7824# 5# B- -14350# 445# 41 991820# 210# + -6 18 24 42 Cr x 6730# 400# 7464# 10# B- * 42 007225# 429# +0 17 30 13 43 Al x 47020# 800# 6741# 19# B- 23919# 998# 43 050478# 859# + 15 29 14 43 Si x 23101# 596# 7279# 14# B- 18421# 814# 43 024800# 640# + 13 28 15 43 P x 4679.826 554.705 7689.572 12.900 B- 16875.285 554.727 43 005024.000 595.500 + 11 27 16 43 S x -12195.459 4.970 8063.827 0.116 B- 11964.049 62.058 42 986907.635 5.335 + 9 26 17 43 Cl x -24159.508 61.858 8323.866 1.439 B- 7850.300 62.086 42 974063.700 66.407 + 7 25 18 43 Ar x -32009.808 5.310 8488.237 0.123 B- 4565.581 5.325 42 965636.055 5.700 + 5 24 19 43 K -4n -36575.389 0.410 8576.220 0.010 B- 1833.434 0.469 42 960734.703 0.440 + 3 23 20 43 Ca -38408.822 0.228 8600.663 0.005 B- -2220.720 1.865 42 958766.430 0.244 + 1 22 21 43 Sc -p -36188.102 1.863 8530.825 0.043 B- -6867.020 7.481 42 961150.472 1.999 + -1 21 22 43 Ti -n2p -29321.082 7.245 8352.932 0.168 B- -11404.726 43.457 42 968522.521 7.777 + -3 20 23 43 V x -17916.356 42.849 8069.512 0.996 B- -15946# 402# 42 980766.000 46.000 + -5 19 24 43 Cr x -1970# 400# 7680# 9# B- * 42 997885# 429# +0 16 30 14 44 Si x 28513# 596# 7174# 14# B- 18063# 778# 44 030610# 640# + 14 29 15 44 P x 10450# 500# 7567# 11# B- 19655# 500# 44 011219# 537# + 12 28 16 44 S x -9204.233 5.216 7996.015 0.119 B- 11180.290 136.421 43 990118.848 5.600 + 10 27 17 44 Cl x -20384.523 136.321 8232.332 3.098 B- 12288.731 136.330 43 978116.312 146.346 + 8 26 18 44 Ar x -32673.255 1.584 8493.840 0.036 B- 3108.237 1.638 43 964923.816 1.700 + 6 25 19 44 K x -35781.492 0.419 8546.701 0.010 B- 5687.183 0.530 43 961586.986 0.450 + 4 24 20 44 Ca -41468.675 0.325 8658.175 0.007 B- -3652.690 1.757 43 955481.543 0.348 + 2 23 21 44 Sc -p -37815.985 1.756 8557.379 0.040 B- -267.416 1.890 43 959402.867 1.884 + 0 22 22 44 Ti -a -37548.569 0.700 8533.520 0.016 B- -13432.189 181.643 43 959689.951 0.751 + -2 21 23 44 V x -24116.380 181.641 8210.463 4.128 B- -10756# 351# 43 974110.000 195.000 + -4 20 24 44 Cr x -13360# 300# 7948# 7# B- -20390# 583# 43 985657# 322# + -6 19 25 44 Mn x 7030# 500# 7467# 11# B- * 44 007547# 537# +0 17 31 14 45 Si x 37490# 700# 6995# 16# B- 21890# 860# 45 040247# 751# + 15 30 15 45 P x 15600# 500# 7464# 11# B- 19589# 1150# 45 016747# 537# + 13 29 16 45 S x -3989.589 1035.356 7881.807 23.008 B- 14272.954 1044.271 44 995717.000 1111.500 + 11 28 17 45 Cl x -18262.543 136.163 8181.598 3.026 B- 11508.254 136.164 44 980394.353 146.177 + 9 27 18 45 Ar x -29770.796 0.512 8419.952 0.011 B- 6844.841 0.731 44 968039.733 0.550 + 7 26 19 45 K x -36615.638 0.522 8554.674 0.012 B- 4196.536 0.637 44 960691.493 0.560 + 5 25 20 45 Ca -40812.174 0.366 8630.545 0.008 B- 259.722 0.747 44 956186.326 0.392 + 3 24 21 45 Sc -41071.896 0.675 8618.931 0.015 B- -2062.056 0.509 44 955907.503 0.724 + 1 23 22 45 Ti -39009.840 0.845 8555.722 0.019 B- -7123.824 0.214 44 958121.211 0.907 + -1 22 23 45 V -31886.016 0.872 8380.029 0.019 B- -12371.217 35.408 44 965768.951 0.935 + -3 21 24 45 Cr x -19514.799 35.397 8087.728 0.787 B- -14265# 401# 44 979050.000 38.000 + -5 20 25 45 Mn x -5250# 400# 7753# 9# B- -19012# 565# 44 994364# 429# + -7 19 26 45 Fe -pp 13762# 400# 7313# 9# B- * 45 014774# 429# +0 16 31 15 46 P x 22970# 700# 7317# 15# B- 22630# 860# 46 024659# 751# + 14 30 16 46 S x 340# 500# 7792# 11# B- 14199# 542# 46 000365# 537# + 12 29 17 46 Cl x -13859.398 208.661 8083.480 4.536 B- 15913.528 208.664 45 985121.323 224.006 + 10 28 18 46 Ar x -29772.926 1.118 8412.419 0.024 B- 5640.997 1.333 45 968037.446 1.200 + 8 27 19 46 K x -35413.924 0.727 8518.042 0.016 B- 7725.438 2.350 45 961981.586 0.780 + 6 26 20 46 Ca -43139.361 2.235 8668.979 0.049 B- -1378.143 2.333 45 953687.988 2.399 + 4 25 21 46 Sc -n -41761.219 0.683 8622.012 0.015 B- 2366.581 0.667 45 955167.485 0.732 + 2 24 22 46 Ti -44127.799 0.165 8656.451 0.004 B- -7052.449 0.093 45 952626.856 0.176 + 0 23 23 46 V -37075.351 0.202 8486.130 0.004 B- -7603.784 11.455 45 960197.971 0.216 + -2 22 24 46 Cr -29471.567 11.453 8303.823 0.249 B- -16902# 400# 45 968360.970 12.295 + -4 21 25 46 Mn x -12570# 400# 7919# 9# B- -13480# 640# 45 986506# 429# + -6 20 26 46 Fe x 910# 500# 7609# 11# B- * 46 000977# 537# +0 17 32 15 47 P x 29710# 800# 7190# 17# B- 22340# 944# 47 031895# 859# + 15 31 16 47 S x 7370# 500# 7648# 11# B- 17150# 640# 47 007912# 537# + 13 30 17 47 Cl x -9780# 400# 7996# 9# B- 15587# 400# 46 989501# 429# + 11 29 18 47 Ar x -25366.338 1.118 8311.404 0.024 B- 10345.638 1.789 46 972768.114 1.200 + 9 28 19 47 K x -35711.976 1.397 8514.879 0.030 B- 6632.442 2.625 46 961661.614 1.500 + 7 27 20 47 Ca -42344.418 2.222 8639.349 0.047 B- 1992.177 1.185 46 954541.394 2.385 + 5 26 21 47 Sc -44336.595 1.933 8665.090 0.041 B- 600.769 1.929 46 952402.704 2.074 + 3 25 22 47 Ti -44937.364 0.115 8661.227 0.002 B- -2930.746 0.138 46 951757.752 0.123 + 1 24 23 47 V -42006.618 0.169 8582.225 0.004 B- -7444.040 6.032 46 954904.038 0.181 + -1 23 24 47 Cr -34562.578 6.030 8407.195 0.128 B- -11996.204 32.240 46 962895.544 6.473 + -3 22 25 47 Mn x -22566.374 31.671 8135.311 0.674 B- -15697# 501# 46 975774.000 34.000 + -5 21 26 47 Fe x -6870# 500# 7785# 11# B- -17240# 781# 46 992625# 537# + -7 20 27 47 Co x 10370# 600# 7401# 13# B- * 47 011133# 644# +0 16 32 16 48 S x 12761# 596# 7545# 12# B- 17042# 778# 48 013700# 640# + 14 31 17 48 Cl x -4280# 500# 7883# 10# B- 18001# 587# 47 995405# 537# + 12 30 18 48 Ar x -22281.337 307.393 8242.132 6.404 B- 10003.140 307.394 47 976080.000 330.000 + 10 29 19 48 K x -32284.477 0.773 8434.232 0.016 B- 11940.153 0.779 47 965341.186 0.830 + 8 28 20 48 Ca -44224.629 0.096 8666.686 0.002 B- 279.213 4.950 47 952522.904 0.103 + 6 27 21 48 Sc -44503.842 4.951 8656.204 0.103 B- 3988.866 4.950 47 952223.157 5.314 + 4 26 22 48 Ti -48492.709 0.109 8723.006 0.002 B- -4015.015 0.969 47 947940.932 0.117 + 2 25 23 48 V -44477.694 0.975 8623.061 0.020 B- -1655.673 7.388 47 952251.229 1.046 + 0 24 24 48 Cr +nn -42822.020 7.324 8572.269 0.153 B- -13525.682 10.087 47 954028.667 7.862 + -2 23 25 48 Mn -29296.338 6.939 8274.185 0.145 B- -11296# 400# 47 968549.085 7.449 + -4 22 26 48 Fe x -18000# 400# 8023# 8# B- -19500# 640# 47 980676# 429# + -6 21 27 48 Co x 1500# 500# 7600# 10# B- -15293# 708# 48 001610# 537# + -8 20 28 48 Ni -pp 16793# 502# 7265# 10# B- * 48 018028# 538# +0 17 33 16 49 S -n 21093# 667# 7385# 14# B- 20153# 897# 49 022644# 716# + 15 32 17 49 Cl x 940# 600# 7781# 12# B- 18130# 721# 49 001009# 644# + 13 31 18 49 Ar x -17190# 400# 8135# 8# B- 12422# 400# 48 981546# 429# + 11 30 19 49 K x -29611.490 0.801 8372.274 0.016 B- 11688.275 0.826 48 968210.755 0.860 + 9 29 20 49 Ca -n -41299.765 0.201 8594.844 0.004 B- 5261.500 2.702 48 955662.875 0.216 + 7 28 21 49 Sc -46561.265 2.698 8686.256 0.055 B- 2002.522 2.697 48 950014.423 2.896 + 5 27 22 49 Ti -48563.787 0.114 8711.157 0.002 B- -601.856 0.820 48 947864.627 0.122 + 3 26 23 49 V - -47961.931 0.828 8682.908 0.017 B- -2628.871 2.391 48 948510.746 0.889 + 1 25 24 49 Cr -45333.060 2.243 8613.291 0.046 B- -7712.426 0.233 48 951332.955 2.407 + -1 24 25 49 Mn -37620.634 2.255 8439.929 0.046 B- -12869.907 24.324 48 959612.585 2.420 + -3 23 26 49 Fe x -24750.727 24.219 8161.311 0.494 B- -14870# 501# 48 973429.000 26.000 + -5 22 27 49 Co x -9880# 500# 7842# 10# B- -18080# 781# 48 989393# 537# + -7 21 28 49 Ni x 8200# 600# 7457# 12# B- * 49 008803# 644# +0 16 33 17 50 Cl x 7740# 600# 7651# 12# B- 21069# 781# 50 008309# 644# + 14 32 18 50 Ar x -13330# 500# 8056# 10# B- 12398# 500# 49 985690# 537# + 12 31 19 50 K x -25727.848 7.731 8288.582 0.155 B- 13861.376 7.892 49 972380.017 8.300 + 10 30 20 50 Ca x -39589.224 1.584 8550.163 0.032 B- 4958.158 15.084 49 957499.217 1.700 + 8 29 21 50 Sc -pn -44547.382 15.000 8633.679 0.300 B- 6884.278 15.000 49 952176.415 16.103 + 6 28 22 50 Ti -51431.660 0.121 8755.718 0.002 B- -2207.647 0.426 49 944785.839 0.129 + 4 27 23 50 V +n -49224.013 0.409 8695.918 0.008 B- 1038.059 0.299 49 947155.845 0.438 + 2 26 24 50 Cr -50262.072 0.437 8701.032 0.009 B- -7634.477 0.067 49 946041.443 0.468 + 0 25 25 50 Mn -42627.595 0.442 8532.696 0.009 B- -8151.139 8.395 49 954237.391 0.474 + -2 24 26 50 Fe x -34476.456 8.383 8354.026 0.168 B- -16846# 400# 49 962988.000 9.000 + -4 23 27 50 Co x -17630# 400# 8001# 8# B- -13510# 640# 49 981073# 429# + -6 22 28 50 Ni x -4120# 500# 7716# 10# B- * 49 995577# 537# +0 17 34 17 51 Cl x 14290# 700# 7530# 14# B- 20980# 922# 51 015341# 751# + 15 33 18 51 Ar x -6690# 600# 7926# 12# B- 15826# 600# 50 992818# 644# + 13 32 19 51 K x -22516.196 13.047 8221.349 0.256 B- 13816.107 13.057 50 975827.867 14.006 + 11 31 20 51 Ca x -36332.304 0.522 8476.913 0.010 B- 6896.381 20.007 50 960995.665 0.560 + 9 30 21 51 Sc -p2n -43228.684 20.000 8596.796 0.392 B- 6504.153 20.006 50 953592.095 21.471 + 7 29 22 51 Ti -n -49732.837 0.505 8708.988 0.010 B- 2471.005 0.644 50 946609.600 0.541 + 5 28 23 51 V -52203.842 0.401 8742.099 0.008 B- -752.447 0.213 50 943956.867 0.430 + 3 27 24 51 Cr -51451.395 0.400 8712.005 0.008 B- -3207.518 0.346 50 944764.652 0.429 + 1 26 25 51 Mn -48243.877 0.502 8633.772 0.010 B- -8041.321 8.977 50 948208.065 0.539 + -1 25 26 51 Fe -40202.555 8.964 8460.759 0.176 B- -12860.412 49.260 50 956840.779 9.623 + -3 24 27 51 Co x -27342.143 48.438 8193.254 0.950 B- -15442# 503# 50 970647.000 52.000 + -5 23 28 51 Ni x -11900# 500# 7875# 10# B- * 50 987225# 537# +0 16 34 18 52 Ar x -1280# 600# 7825# 12# B- 15858# 601# 51 998626# 644# + 14 33 19 52 K x -17137.627 33.534 8115.029 0.645 B- 17128.639 33.540 51 981602.000 36.000 + 12 32 20 52 Ca x -34266.266 0.671 8429.381 0.013 B- 6177.013 81.855 51 963213.648 0.720 + 10 31 21 52 Sc x -40443.279 81.852 8533.125 1.574 B- 9026.541 82.157 51 956582.351 87.871 + 8 30 22 52 Ti -nn -49469.820 7.072 8691.667 0.136 B- 1973.948 7.085 51 946891.960 7.592 + 6 29 23 52 V -n -51443.769 0.420 8714.582 0.008 B- 3975.473 0.531 51 944772.839 0.450 + 4 28 24 52 Cr -55419.242 0.340 8775.989 0.007 B- -4711.958 1.851 51 940504.992 0.364 + 2 27 25 52 Mn -50707.284 1.845 8670.329 0.035 B- -2376.920 5.017 51 945563.488 1.980 + 0 26 26 52 Fe -48330.363 5.117 8609.574 0.098 B- -13969.413 9.822 51 948115.217 5.493 + -2 25 27 52 Co x -34360.951 8.383 8325.886 0.161 B- -12031# 400# 51 963112.000 9.000 + -4 24 28 52 Ni x -22330# 400# 8079# 8# B- -20049# 721# 51 976028# 429# + -6 23 29 52 Cu x -2280# 600# 7679# 12# B- * 51 997552# 644# +0 17 35 18 53 Ar x 6791# 699# 7677# 13# B- 19086# 708# 53 007290# 750# + 15 34 19 53 K x -12295.721 111.779 8022.848 2.109 B- 17091.983 120.047 52 986800.000 120.000 + 13 33 20 53 Ca x -29387.704 43.780 8330.577 0.826 B- 9519.104 103.774 52 968451.000 47.000 + 11 32 21 53 Sc x -38906.808 94.087 8495.421 1.775 B- 7924.253 137.339 52 958231.821 101.006 + 9 31 22 53 Ti + -46831.061 100.049 8630.174 1.888 B- 5020.000 100.000 52 949724.785 107.406 + 7 30 23 53 V +p -51851.061 3.120 8710.130 0.059 B- 3435.938 3.102 52 944335.593 3.349 + 5 29 24 53 Cr -55286.999 0.348 8760.198 0.007 B- -596.884 0.356 52 940646.961 0.373 + 3 28 25 53 Mn -54690.116 0.450 8734.175 0.009 B- -3742.586 1.686 52 941287.742 0.483 + 1 27 26 53 Fe -50947.530 1.656 8648.799 0.031 B- -8288.101 0.443 52 945305.574 1.777 + -1 26 27 53 Co -42659.428 1.713 8477.658 0.032 B- -13028.604 25.209 52 954203.217 1.839 + -3 25 28 53 Ni x -29630.824 25.150 8217.074 0.475 B- -16361# 501# 52 968190.000 27.000 + -5 24 29 53 Cu x -13270# 500# 7894# 9# B- * 52 985754# 537# +0 16 35 19 54 K x -5002# 596# 7889# 11# B- 20158# 598# 53 994630# 640# + 14 34 20 54 Ca x -25160.585 48.438 8247.496 0.897 B- 8730.315 277.066 53 972989.000 52.000 + 12 33 21 54 Sc x -33890.900 272.800 8394.681 5.052 B- 11731.081 284.990 53 963616.620 292.862 + 10 32 22 54 Ti x -45621.981 82.461 8597.435 1.527 B- 4271.192 83.815 53 951022.786 88.526 + 8 31 23 54 V + -49893.173 15.004 8662.043 0.278 B- 7041.592 15.000 53 946437.472 16.107 + 6 30 24 54 Cr -56934.765 0.353 8777.955 0.007 B- -1377.136 1.008 53 938878.012 0.378 + 4 29 25 54 Mn -p -55557.629 1.059 8737.965 0.020 B- 696.872 1.076 53 940356.429 1.136 + 2 28 26 54 Fe -56254.500 0.372 8736.382 0.007 B- -8244.547 0.089 53 939608.306 0.399 + 0 27 27 54 Co -48009.953 0.383 8569.217 0.007 B- -8731.646 4.673 53 948459.192 0.411 + -2 26 28 54 Ni x -39278.308 4.657 8393.032 0.086 B- -17868# 400# 53 957833.000 5.000 + -4 25 29 54 Cu x -21410# 400# 8048# 7# B- -15139# 565# 53 977015# 429# + -6 24 30 54 Zn -pp -6272# 400# 7753# 7# B- * 53 993267# 430# +0 17 36 19 55 K x 708# 699# 7788# 13# B- 19058# 760# 55 000760# 750# + 15 35 20 55 Ca x -18350# 300# 8120# 5# B- 11809# 544# 54 980300# 322# + 13 34 21 55 Sc x -30159.352 454.342 8320.955 8.261 B- 11508.735 482.226 54 967622.601 487.756 + 11 33 22 55 Ti -41668.088 161.602 8515.980 2.938 B- 7476.498 157.206 54 955267.465 173.486 + 9 32 23 55 V -49144.586 95.104 8637.692 1.729 B- 5965.125 95.103 54 947241.114 102.098 + 7 31 24 55 Cr -55109.710 0.399 8731.924 0.007 B- 2602.703 0.368 54 940837.289 0.428 + 5 30 25 55 Mn -57712.413 0.303 8765.022 0.006 B- -231.114 0.179 54 938043.172 0.325 + 3 29 26 55 Fe -57481.300 0.342 8746.595 0.006 B- -3451.417 0.324 54 938291.283 0.367 + 1 28 27 55 Co -54029.883 0.428 8669.618 0.008 B- -8694.034 0.578 54 941996.531 0.459 + -1 27 28 55 Ni - -45335.849 0.719 8497.320 0.013 B- -13700.449 155.561 54 951329.961 0.771 + -3 26 29 55 Cu x -31635.399 155.559 8233.996 2.828 B- -17065# 429# 54 966038.000 167.000 + -5 25 30 55 Zn x -14570# 400# 7909# 7# B- * 54 984358# 429# +0 18 37 19 56 K x 7927# 801# 7664# 14# B- 21825# 895# 56 008510# 860# + 16 36 20 56 Ca x -13898# 400# 8040# 7# B- 10954# 710# 55 985080# 429# + 14 35 21 56 Sc x -24852.260 586.841 8221.728 10.479 B- 14467.788 599.236 55 973320.000 630.000 + 12 34 22 56 Ti -39320.048 121.247 8466.110 2.165 B- 6834.833 194.550 55 957788.190 130.164 + 10 33 23 56 V -46154.881 176.898 8574.191 3.159 B- 9130.120 176.899 55 950450.694 189.907 + 8 32 24 56 Cr ++ -55285.001 0.603 8723.258 0.011 B- 1626.538 0.561 55 940649.107 0.647 + 6 31 25 56 Mn -n -56911.538 0.331 8738.333 0.006 B- 3695.544 0.207 55 938902.947 0.355 + 4 30 26 56 Fe -60607.082 0.302 8790.354 0.005 B- -4566.680 0.411 55 934935.617 0.324 + 2 29 27 56 Co -56040.402 0.493 8694.836 0.009 B- -2132.863 0.374 55 939838.150 0.529 + 0 28 28 56 Ni -53907.539 0.422 8642.779 0.008 B- -15264.511 14.910 55 942127.872 0.452 + -2 27 29 56 Cu x -38643.029 14.904 8356.227 0.266 B- -13253# 400# 55 958515.000 16.000 + -4 26 30 56 Zn x -25390# 400# 8106# 7# B- -22000# 640# 55 972743# 429# + -6 25 31 56 Ga x -3390# 500# 7699# 9# B- * 55 996361# 537# +0 17 37 20 57 Ca x -6874# 400# 7917# 7# B- 14121# 1364# 56 992620# 429# + 15 36 21 57 Sc x -20995.875 1304.092 8151.433 22.879 B- 12919.758 1329.062 56 977460.000 1400.000 + 13 35 22 57 Ti x -33915.633 256.417 8364.370 4.499 B- 10497.818 268.750 56 963590.068 275.274 + 11 34 23 57 V x -44413.450 80.479 8534.817 1.412 B- 8111.252 80.486 56 952320.197 86.397 + 9 33 24 57 Cr x -52524.702 1.068 8663.394 0.019 B- 4961.548 1.846 56 943612.409 1.146 + 7 32 25 57 Mn -57486.251 1.505 8736.713 0.026 B- 2695.589 1.526 56 938285.968 1.615 + 5 31 26 57 Fe -60181.839 0.304 8770.279 0.005 B- -836.276 0.451 56 935392.134 0.326 + 3 30 27 57 Co -59345.564 0.533 8741.882 0.009 B- -3261.731 0.642 56 936289.913 0.572 + 1 29 28 57 Ni -56083.833 0.582 8670.933 0.010 B- -8774.947 0.439 56 939791.525 0.624 + -1 28 29 57 Cu -47308.886 0.519 8503.262 0.009 B- -14759# 200# 56 949211.819 0.557 + -3 27 30 57 Zn x -32550# 200# 8231# 4# B- -17540# 447# 56 965056# 215# + -5 26 31 57 Ga x -15010# 400# 7909# 7# B- * 56 983886# 429# +0 18 38 20 58 Ca x -1919# 500# 7835# 9# B- 12957# 640# 57 997940# 537# + 16 37 21 58 Sc x -14876# 400# 8045# 7# B- 16234# 447# 57 984030# 429# + 14 36 22 58 Ti x -31110# 200# 8311# 3# B- 9292# 219# 57 966602# 215# + 12 35 23 58 V x -40401.753 89.374 8457.658 1.541 B- 11590.049 89.386 57 956626.932 95.947 + 10 34 24 58 Cr x -51991.801 1.490 8643.998 0.026 B- 3835.759 3.085 57 944184.502 1.600 + 8 33 25 58 Mn x -55827.560 2.701 8696.643 0.047 B- 6327.553 2.723 57 940066.646 2.900 + 6 32 26 58 Fe -62155.113 0.343 8792.250 0.006 B- -2307.955 1.139 57 933273.738 0.368 + 4 31 27 58 Co -59847.158 1.160 8738.969 0.020 B- 381.586 1.107 57 935751.429 1.245 + 2 30 28 58 Ni -60228.744 0.373 8732.059 0.006 B- -8561.019 0.443 57 935341.780 0.400 + 0 29 29 58 Cu -51667.725 0.578 8570.967 0.010 B- -9368.981 50.002 57 944532.413 0.621 + -2 28 30 58 Zn -- -42298.744 50.001 8395.944 0.862 B- -18759# 304# 57 954590.428 53.678 + -4 27 31 58 Ga x -23540# 300# 8059# 5# B- -16459# 583# 57 974729# 322# + -6 26 32 58 Ge x -7080# 500# 7762# 9# B- * 57 992399# 537# +0 17 38 21 59 Sc x -10302# 400# 7967# 7# B- 15208# 447# 58 988940# 429# + 15 37 22 59 Ti x -25510# 200# 8212# 3# B- 12322# 258# 58 972614# 215# + 13 36 23 59 V x -37832.015 161.874 8407.555 2.744 B- 10253.745 270.218 58 959385.659 173.778 + 11 35 24 59 Cr x -48085.760 216.367 8568.087 3.667 B- 7439.560 216.380 58 948377.810 232.279 + 9 34 25 59 Mn x -55525.320 2.329 8680.921 0.039 B- 5139.485 2.356 58 940391.113 2.500 + 7 33 26 59 Fe -60664.805 0.355 8754.771 0.006 B- 1564.903 0.369 58 934873.649 0.380 + 5 32 27 59 Co -62229.709 0.418 8768.035 0.007 B- -1073.002 0.194 58 933193.656 0.448 + 3 31 28 59 Ni -61156.707 0.374 8736.588 0.006 B- -4798.380 0.397 58 934345.571 0.402 + 1 30 29 59 Cu -56358.327 0.544 8642.000 0.009 B- -9142.775 0.602 58 939496.844 0.584 + -1 29 30 59 Zn -47215.551 0.771 8473.777 0.013 B- -13455# 170# 58 949312.017 0.827 + -3 28 31 59 Ga x -33760# 170# 8232# 3# B- -17890# 434# 58 963757# 183# + -5 27 32 59 Ge x -15870# 400# 7916# 7# B- * 58 982963# 429# +0 18 39 21 60 Sc x -4052# 500# 7865# 8# B- 18278# 583# 59 995650# 537# + 16 38 22 60 Ti x -22330# 300# 8157# 5# B- 10912# 372# 59 976028# 322# + 14 37 23 60 V x -33241.956 220.159 8325.450 3.669 B- 13427.621 293.169 59 964313.290 236.350 + 12 36 24 60 Cr x -46669.576 193.593 8536.205 3.227 B- 6298.361 193.607 59 949898.146 207.830 + 10 35 25 60 Mn x -52967.938 2.329 8628.138 0.039 B- 8445.079 4.128 59 943136.576 2.500 + 8 34 26 60 Fe -nn -61413.017 3.409 8755.851 0.057 B- 237.293 3.411 59 934070.411 3.659 + 6 33 27 60 Co -n -61650.309 0.424 8746.766 0.007 B- 2822.809 0.212 59 933815.667 0.455 + 4 32 28 60 Ni -64473.118 0.376 8780.774 0.006 B- -6127.982 1.573 59 930785.256 0.403 + 2 31 29 60 Cu - -58345.137 1.618 8665.602 0.027 B- -4170.797 1.629 59 937363.916 1.736 + 0 30 30 60 Zn -54174.340 0.564 8583.050 0.009 B- -14584# 200# 59 941841.450 0.605 + -2 29 31 60 Ga x -39590# 200# 8327# 3# B- -12501# 361# 59 957498# 215# + -4 28 32 60 Ge x -27090# 300# 8106# 5# B- -21620# 500# 59 970918# 322# + -6 27 33 60 As x -5470# 400# 7732# 7# B- * 59 994128# 429# +0 19 40 21 61 Sc x 931# 600# 7787# 10# B- 17281# 721# 61 001000# 644# + 17 39 22 61 Ti x -16350# 400# 8057# 7# B- 14157# 979# 60 982448# 429# + 15 38 23 61 V x -30506.429 894.234 8276.439 14.660 B- 11968.800 899.958 60 967250.000 960.000 + 13 37 24 61 Cr x -42475.229 101.341 8459.824 1.661 B- 9266.893 101.367 60 954400.963 108.793 + 11 36 25 61 Mn x -51742.122 2.329 8598.915 0.038 B- 7178.372 3.497 60 944452.544 2.500 + 9 35 26 61 Fe x -58920.494 2.608 8703.768 0.043 B- 3977.572 2.742 60 936746.244 2.800 + 7 34 27 61 Co p2n -62898.066 0.846 8756.148 0.014 B- 1323.839 0.790 60 932476.145 0.908 + 5 33 28 61 Ni -64221.905 0.378 8765.025 0.006 B- -2237.845 0.966 60 931054.945 0.405 + 3 32 29 61 Cu p2n -61984.059 0.953 8715.514 0.016 B- -5635.156 15.903 60 933457.371 1.023 + 1 31 30 61 Zn -56348.903 15.899 8610.309 0.261 B- -9214.245 37.679 60 939506.960 17.068 + -1 30 31 61 Ga -47134.659 37.994 8446.431 0.623 B- -13775# 302# 60 949398.859 40.787 + -3 29 32 61 Ge x -33360# 300# 8208# 5# B- -16459# 424# 60 964187# 322# + -5 28 33 61 As x -16900# 300# 7925# 5# B- * 60 981857# 322# +0 18 40 22 62 Ti x -12500# 400# 7995# 6# B- 12977# 499# 61 986581# 429# + 16 39 23 62 V x -25476# 298# 8192# 5# B- 15419# 333# 61 972650# 320# + 14 38 24 62 Cr x -40894.961 148.099 8428.069 2.389 B- 7628.996 148.244 61 956097.451 158.991 + 12 37 25 62 Mn IT -48523.957 6.542 8538.499 0.106 B- 10354.091 7.114 61 947907.386 7.023 + 10 36 26 62 Fe x -58878.048 2.794 8692.882 0.045 B- 2546.235 18.784 61 936791.812 3.000 + 8 35 27 62 Co + -61424.282 18.575 8721.332 0.300 B- 5322.040 18.570 61 934058.317 19.940 + 6 34 28 62 Ni -66746.323 0.439 8794.553 0.007 B- -3958.896 0.475 61 928344.871 0.470 + 4 33 29 62 Cu - -62787.426 0.647 8718.081 0.010 B- -1619.455 0.651 61 932594.921 0.694 + 2 32 30 62 Zn -61167.972 0.625 8679.343 0.010 B- -9181.066 0.376 61 934333.477 0.670 + 0 31 31 62 Ga -51986.906 0.647 8518.642 0.010 B- -10247# 140# 61 944189.757 0.694 + -2 30 32 62 Ge x -41740# 140# 8341# 2# B- -17420# 331# 61 955190# 150# + -4 29 33 62 As x -24320# 300# 8047# 5# B- * 61 973891# 322# +0 19 41 22 63 Ti x -5750# 500# 7889# 8# B- 16140# 640# 62 993827# 537# + 17 40 23 63 V x -21890# 400# 8133# 6# B- 14117# 537# 62 976500# 429# + 15 39 24 63 Cr x -36007.474 358.073 8344.828 5.684 B- 10879.579 358.092 62 961344.384 384.407 + 13 38 25 63 Mn x -46887.053 3.726 8505.101 0.059 B- 8748.568 5.692 62 949664.675 4.000 + 11 37 26 63 Fe -55635.621 4.302 8631.549 0.068 B- 6215.819 19.067 62 940272.700 4.618 + 9 36 27 63 Co -61851.440 18.575 8717.795 0.295 B- 3661.335 18.570 62 933599.744 19.941 + 7 35 28 63 Ni -65512.775 0.440 8763.493 0.007 B- 66.977 0.015 62 929669.139 0.472 + 5 34 29 63 Cu -65579.752 0.440 8752.138 0.007 B- -3366.355 1.546 62 929597.236 0.472 + 3 33 30 63 Zn -62213.397 1.561 8686.285 0.025 B- -5666.304 2.034 62 933211.167 1.676 + 1 32 31 63 Ga x -56547.093 1.304 8583.926 0.021 B- -9625.877 37.283 62 939294.195 1.400 + -1 31 32 63 Ge x -46921.216 37.260 8418.716 0.591 B- -13421# 204# 62 949628.000 40.000 + -3 30 33 63 As x -33500# 200# 8193# 3# B- * 62 964036# 215# +0 20 42 22 64 Ti x -1025# 600# 7818# 9# B- 15295# 721# 63 998900# 644# + 18 41 23 64 V x -16320# 400# 8045# 6# B- 17160# 594# 63 982480# 429# + 16 40 24 64 Cr x -33479.757 439.665 8301.058 6.870 B- 9509.277 439.679 63 964058.000 472.000 + 14 39 25 64 Mn x -42989.035 3.540 8437.417 0.055 B- 11980.510 6.140 63 953849.370 3.800 + 12 38 26 64 Fe x -54969.544 5.017 8612.388 0.078 B- 4822.785 20.625 63 940987.763 5.386 + 10 37 27 64 Co + -59792.329 20.006 8675.520 0.313 B- 7306.592 20.000 63 935810.291 21.476 + 8 36 28 64 Ni -67098.921 0.475 8777.461 0.007 B- -1674.376 0.225 63 927966.341 0.510 + 6 35 29 64 Cu -65424.545 0.448 8739.075 0.007 B- 579.469 0.650 63 929763.857 0.481 + 4 34 30 64 Zn -66004.014 0.647 8735.905 0.010 B- -7171.194 1.483 63 929141.772 0.694 + 2 33 31 64 Ga -58832.821 1.429 8611.631 0.022 B- -4517.325 3.991 63 936840.365 1.533 + 0 32 32 64 Ge x -54315.496 3.726 8528.823 0.058 B- -14783# 203# 63 941689.913 4.000 + -2 31 33 64 As -p -39532# 203# 8286# 3# B- -12832# 543# 63 957560# 218# + -4 30 34 64 Se x -26700# 503# 8073# 8# B- * 63 971336# 540# +0 19 42 23 65 V x -11780# 500# 7976# 8# B- 16440# 583# 64 987354# 537# + 17 41 24 65 Cr x -28220# 300# 8217# 5# B- 12748# 300# 64 969705# 322# + 15 40 25 65 Mn x -40967.339 3.726 8400.681 0.057 B- 10250.557 6.326 64 956019.750 4.000 + 13 39 26 65 Fe x -51217.895 5.112 8546.346 0.079 B- 7967.303 5.520 64 945015.324 5.487 + 11 38 27 65 Co x -59185.198 2.083 8656.884 0.032 B- 5940.487 2.141 64 936462.073 2.235 + 9 37 28 65 Ni -n -65125.685 0.495 8736.240 0.008 B- 2137.975 0.706 64 930084.697 0.531 + 7 36 29 65 Cu -67263.660 0.650 8757.096 0.010 B- -1351.640 0.360 64 927789.487 0.697 + 5 35 30 65 Zn -65912.019 0.650 8724.265 0.010 B- -3254.513 0.662 64 929240.532 0.697 + 3 34 31 65 Ga -62657.507 0.815 8662.160 0.013 B- -6179.291 2.313 64 932734.395 0.874 + 1 33 32 65 Ge -56478.216 2.165 8555.058 0.033 B- -9541.165 84.794 64 939368.137 2.323 + -1 32 33 65 As x -46937.051 84.766 8396.234 1.304 B- -13917# 312# 64 949611.000 91.000 + -3 31 34 65 Se x -33020# 300# 8170# 5# B- * 64 964552# 322# +0 20 43 23 66 V x -5610# 500# 7884# 8# B- 19110# 640# 65 993977# 537# + 18 42 24 66 Cr x -24720# 400# 8161# 6# B- 12030# 400# 65 973462# 429# + 16 41 25 66 Mn x -36750.387 11.178 8331.798 0.169 B- 13317.452 11.906 65 960546.834 12.000 + 14 40 26 66 Fe x -50067.839 4.099 8521.724 0.062 B- 6340.694 14.561 65 946249.960 4.400 + 12 39 27 66 Co x -56408.533 13.972 8605.941 0.212 B- 9597.752 14.042 65 939442.945 15.000 + 10 38 28 66 Ni x -66006.285 1.397 8739.508 0.021 B- 251.987 1.543 65 929139.334 1.500 + 8 37 29 66 Cu -66258.272 0.655 8731.472 0.010 B- 2640.888 0.931 65 928868.814 0.703 + 6 36 30 66 Zn -68899.160 0.749 8759.632 0.011 B- -5175.500 0.800 65 926033.704 0.804 + 4 35 31 66 Ga - -63723.660 1.096 8669.361 0.017 B- -2116.628 2.639 65 931589.832 1.176 + 2 34 32 66 Ge x -61607.032 2.401 8625.437 0.036 B- -9581.955 6.168 65 933862.126 2.577 + 0 33 33 66 As x -52025.077 5.682 8468.403 0.086 B- -10365# 200# 65 944148.779 6.100 + -2 32 34 66 Se x -41660# 200# 8300# 3# B- * 65 955276# 215# +0 21 44 23 67 V x -650# 600# 7812# 9# B- 18030# 721# 66 999302# 644# + 19 43 24 67 Cr x -18680# 400# 8070# 6# B- 14780# 500# 66 979946# 429# + 17 42 25 67 Mn x -33460# 300# 8279# 4# B- 12150# 404# 66 964079# 322# + 15 41 26 67 Fe x -45610.155 270.285 8448.469 4.034 B- 9711.620 270.362 66 951035.482 290.163 + 13 40 27 67 Co x -55321.775 6.443 8581.741 0.096 B- 8420.905 7.061 66 940609.628 6.917 + 11 39 28 67 Ni x -63742.680 2.888 8695.750 0.043 B- 3576.832 3.023 66 931569.414 3.100 + 9 38 29 67 Cu -67319.513 0.894 8737.458 0.013 B- 560.800 0.830 66 927729.526 0.959 + 7 37 30 67 Zn -67880.313 0.760 8734.152 0.011 B- -1001.265 1.122 66 927127.482 0.815 + 5 36 31 67 Ga -66879.048 1.181 8707.531 0.018 B- -4220.819 4.799 66 928202.384 1.268 + 3 35 32 67 Ge -n2p -62658.230 4.661 8632.857 0.070 B- -6071.005 4.682 66 932733.620 5.003 + 1 34 33 67 As -56587.225 0.443 8530.568 0.007 B- -10006.936 67.069 66 939251.111 0.475 + -1 33 34 67 Se x -46580.289 67.068 8369.534 1.001 B- -13790# 405# 66 949994.000 72.000 + -3 32 35 67 Br x -32790# 400# 8152# 6# B- * 66 964798# 429# +0 20 44 24 68 Cr x -14800# 500# 8013# 7# B- 13580# 640# 67 984112# 537# + 18 43 25 68 Mn x -28380# 400# 8201# 6# B- 15107# 541# 67 969533# 429# + 16 42 26 68 Fe x -43486.914 365.259 8411.698 5.371 B- 8443.751 411.489 67 953314.875 392.121 + 14 41 27 68 Co x -51930.665 189.497 8524.366 2.787 B- 11533.150 189.520 67 944250.135 203.433 + 12 40 28 68 Ni x -63463.814 2.981 8682.466 0.044 B- 2103.220 3.375 67 931868.789 3.200 + 10 39 29 68 Cu x -65567.035 1.584 8701.890 0.023 B- 4440.057 1.767 67 929610.889 1.700 + 8 38 30 68 Zn -70007.092 0.784 8755.680 0.012 B- -2921.100 1.200 67 924844.291 0.841 + 6 37 31 68 Ga - -67085.992 1.433 8701.218 0.021 B- -107.203 2.361 67 927980.221 1.538 + 4 36 32 68 Ge x -66978.789 1.876 8688.136 0.028 B- -8084.270 2.632 67 928095.308 2.014 + 2 35 33 68 As -58894.519 1.846 8557.745 0.027 B- -4705.078 1.911 67 936774.130 1.981 + 0 34 34 68 Se x -54189.441 0.496 8477.047 0.007 B- -15398# 259# 67 941825.239 0.532 + -2 33 35 68 Br -p -38791# 259# 8239# 4# B- * 67 958356# 278# +0 21 45 24 69 Cr x -8580# 500# 7924# 7# B- 16190# 640# 68 990789# 537# + 19 44 25 69 Mn x -24770# 400# 8147# 6# B- 14259# 565# 68 973408# 429# + 17 43 26 69 Fe x -39030# 400# 8342# 6# B- 11250# 424# 68 958100# 429# + 15 42 27 69 Co x -50279.157 140.506 8493.865 2.036 B- 9699.492 140.556 68 946023.102 150.839 + 13 41 28 69 Ni x -59978.648 3.726 8623.099 0.054 B- 5757.564 3.979 68 935610.268 4.000 + 11 40 29 69 Cu x -65736.213 1.397 8695.204 0.020 B- 2681.632 1.610 68 929429.268 1.500 + 9 39 30 69 Zn -n -68417.845 0.800 8722.729 0.012 B- 909.964 1.426 68 926550.418 0.858 + 7 38 31 69 Ga -69327.809 1.197 8724.579 0.017 B- -2227.146 0.550 68 925573.531 1.285 + 5 37 32 69 Ge -67100.663 1.318 8680.963 0.019 B- -3988.492 31.982 68 927964.471 1.414 + 3 36 33 69 As -63112.171 31.999 8611.821 0.464 B- -6677.465 32.021 68 932246.294 34.352 + 1 35 34 69 Se -56434.706 1.490 8503.707 0.022 B- -10175.236 42.029 68 939414.847 1.599 + -1 34 35 69 Br -p -46259.470 42.003 8344.902 0.609 B- -13825# 403# 68 950338.413 45.092 + -3 33 36 69 Kr x -32435# 401# 8133# 6# B- * 68 965180# 430# +0 22 46 24 70 Cr x -4480# 600# 7867# 9# B- 15020# 781# 69 995191# 644# + 20 45 25 70 Mn x -19500# 500# 8070# 7# B- 17010# 640# 69 979066# 537# + 18 44 26 70 Fe x -36510# 400# 8302# 6# B- 10120# 500# 69 960805# 429# + 16 43 27 70 Co x -46630# 300# 8436# 4# B- 12584# 300# 69 949941# 322# + 14 42 28 70 Ni x -59213.860 2.144 8604.291 0.031 B- 3762.513 2.401 69 936431.303 2.301 + 12 41 29 70 Cu x -62976.373 1.082 8646.865 0.015 B- 6588.362 2.202 69 932392.079 1.161 + 10 40 30 70 Zn -69564.735 1.918 8729.808 0.027 B- -654.595 1.574 69 925319.181 2.058 + 8 39 31 70 Ga -68910.140 1.201 8709.280 0.017 B- 1651.736 1.462 69 926021.917 1.289 + 6 38 32 70 Ge -70561.876 0.838 8721.700 0.012 B- -6220.000 50.000 69 924248.706 0.900 + 4 37 33 70 As - -64341.876 50.007 8621.666 0.714 B- -2411.985 50.032 69 930926.151 53.684 + 2 36 34 70 Se x -61929.891 1.584 8576.033 0.023 B- -10504.272 14.988 69 933515.523 1.700 + 0 35 35 70 Br x -51425.619 14.904 8414.796 0.213 B- -10325# 201# 69 944792.323 16.000 + -2 34 36 70 Kr x -41100# 200# 8256# 3# B- * 69 955877# 215# +0 21 46 25 71 Mn x -15570# 500# 8015# 7# B- 15860# 640# 70 983285# 537# + 19 45 26 71 Fe x -31430# 400# 8227# 6# B- 12940# 613# 70 966259# 429# + 17 44 27 71 Co x -44369.926 465.030 8398.734 6.550 B- 11036.302 465.035 70 952366.923 499.230 + 15 43 28 71 Ni x -55406.228 2.237 8543.156 0.032 B- 7304.899 2.688 70 940518.964 2.401 + 13 42 29 71 Cu x -62711.127 1.490 8635.022 0.021 B- 4617.651 3.044 70 932676.832 1.600 + 11 41 30 71 Zn -67328.777 2.654 8689.041 0.037 B- 2810.358 2.775 70 927719.580 2.849 + 9 40 31 71 Ga -70139.135 0.812 8717.604 0.011 B- -232.638 0.223 70 924702.536 0.871 + 7 39 32 71 Ge -69906.497 0.834 8703.309 0.012 B- -2013.400 4.082 70 924952.284 0.894 + 5 38 33 71 As - -67893.097 4.167 8663.932 0.059 B- -4746.590 5.017 70 927113.758 4.473 + 3 37 34 71 Se x -63146.507 2.794 8586.060 0.039 B- -6644.089 6.082 70 932209.432 3.000 + 1 36 35 71 Br -56502.418 5.402 8481.462 0.076 B- -10175.212 128.845 70 939342.156 5.799 + -1 35 36 71 Kr -46327.205 128.769 8327.130 1.814 B- -14267# 420# 70 950265.696 138.238 + -3 34 37 71 Rb x -32060# 400# 8115# 6# B- * 70 965582# 429# +0 22 47 25 72 Mn x -9900# 600# 7937# 8# B- 18530# 781# 71 989372# 644# + 20 46 26 72 Fe x -28430# 500# 8184# 7# B- 11769# 640# 71 969479# 537# + 18 45 27 72 Co x -40200# 400# 8336# 6# B- 14027# 400# 71 956844# 429# + 16 44 28 72 Ni x -54226.060 2.237 8520.211 0.031 B- 5556.938 2.637 71 941785.926 2.401 + 14 43 29 72 Cu x -59782.999 1.397 8586.525 0.019 B- 8362.487 2.558 71 935820.307 1.500 + 12 42 30 72 Zn x -68145.486 2.142 8691.805 0.030 B- 442.807 2.294 71 926842.807 2.300 + 10 41 31 72 Ga -68588.293 0.819 8687.089 0.011 B- 3997.607 0.822 71 926367.434 0.878 + 8 40 32 72 Ge -72585.900 0.076 8731.745 0.001 B- -4356.102 4.082 71 922075.826 0.081 + 6 39 33 72 As - -68229.798 4.083 8660.378 0.057 B- -361.618 4.528 71 926752.295 4.383 + 4 38 34 72 Se x -67868.180 1.956 8644.489 0.027 B- -8806.437 2.208 71 927140.507 2.100 + 2 37 35 72 Br x -59061.743 1.025 8511.312 0.014 B- -5121.168 8.076 71 936594.607 1.100 + 0 36 36 72 Kr x -53940.575 8.011 8429.319 0.111 B- -15611# 500# 71 942092.407 8.600 + -2 35 37 72 Rb x -38330# 500# 8202# 7# B- * 71 958851# 537# +0 21 47 26 73 Fe x -22900# 500# 8106# 7# B- 14518# 640# 72 975416# 537# + 19 46 27 73 Co x -37418# 400# 8295# 5# B- 12690# 400# 72 959830# 429# + 17 45 28 73 Ni x -50108.152 2.423 8457.652 0.033 B- 8879.285 3.104 72 946206.683 2.601 + 15 44 29 73 Cu -58987.437 1.942 8568.569 0.027 B- 6605.966 2.691 72 936674.378 2.084 + 13 43 30 73 Zn x -65593.402 1.863 8648.345 0.026 B- 4105.932 2.506 72 929582.582 2.000 + 11 42 31 73 Ga x -69699.335 1.677 8693.873 0.023 B- 1598.188 1.678 72 925174.682 1.800 + 9 41 32 73 Ge -71297.523 0.057 8705.049 0.001 B- -344.776 3.853 72 923458.956 0.061 + 7 40 33 73 As -70952.747 3.853 8689.609 0.053 B- -2725.360 7.399 72 923829.089 4.136 + 5 39 34 73 Se -68227.387 7.424 8641.558 0.102 B- -4579.912 10.388 72 926754.883 7.969 + 3 38 35 73 Br x -63647.475 7.266 8568.103 0.100 B- -7095.725 9.801 72 931671.621 7.800 + 1 37 36 73 Kr x -56551.751 6.578 8460.184 0.090 B- -10470# 200# 72 939289.195 7.061 + -1 36 37 73 Rb -p -46082# 200# 8306# 3# B- -14131# 448# 72 950529# 215# + -3 35 38 73 Sr x -31950# 401# 8102# 5# B- * 72 965700# 430# +0 22 48 26 74 Fe x -19590# 600# 8061# 8# B- 13230# 781# 73 978969# 644# + 20 47 27 74 Co x -32820# 500# 8229# 7# B- 15636# 537# 73 964766# 537# + 18 46 28 74 Ni x -48456# 196# 8430# 3# B- 7550# 196# 73 947980# 210# + 16 45 29 74 Cu x -56006.205 6.148 8521.562 0.083 B- 9750.507 6.642 73 939874.862 6.600 + 14 44 30 74 Zn x -65756.712 2.515 8642.754 0.034 B- 2292.905 3.910 73 929407.262 2.700 + 12 43 31 74 Ga x -68049.617 2.994 8663.167 0.040 B- 5372.824 2.994 73 926945.726 3.214 + 10 42 32 74 Ge -73422.442 0.013 8725.200 0.000 B- -2562.387 1.693 73 921177.762 0.013 + 8 41 33 74 As -70860.054 1.693 8680.001 0.023 B- 1353.147 1.693 73 923928.598 1.817 + 6 40 34 74 Se -72213.201 0.015 8687.715 0.000 B- -6925.049 5.835 73 922475.935 0.015 + 4 39 35 74 Br -65288.153 5.835 8583.561 0.079 B- -2956.317 6.173 73 929910.281 6.264 + 2 38 36 74 Kr -62331.836 2.013 8533.038 0.027 B- -10415.827 3.424 73 933084.017 2.161 + 0 37 37 74 Rb -51916.009 3.027 8381.712 0.041 B- -11089# 100# 73 944265.868 3.249 + -2 36 38 74 Sr x -40827# 100# 8221# 1# B- * 73 956170# 107# +0 23 49 26 75 Fe x -13640# 600# 7982# 8# B- 16010# 781# 74 985357# 644# + 21 48 27 75 Co x -29649# 500# 8185# 7# B- 14380# 583# 74 968170# 537# + 19 47 28 75 Ni x -44030# 300# 8366# 4# B- 10441# 300# 74 952732# 322# + 17 46 29 75 Cu x -54471.341 2.330 8495.094 0.031 B- 8087.567 3.042 74 941522.606 2.501 + 15 45 30 75 Zn x -62558.908 1.956 8592.497 0.026 B- 5905.672 3.113 74 932840.246 2.100 + 13 44 31 75 Ga x -68464.580 2.422 8660.808 0.032 B- 3392.384 2.422 74 926500.246 2.600 + 11 43 32 75 Ge -n -71856.965 0.052 8695.609 0.001 B- 1177.231 0.885 74 922858.371 0.055 + 9 42 33 75 As -73034.195 0.884 8700.874 0.012 B- -864.714 0.882 74 921594.562 0.948 + 7 41 34 75 Se -72169.481 0.073 8678.913 0.001 B- -3062.472 4.285 74 922522.871 0.078 + 5 40 35 75 Br x -69107.009 4.285 8627.649 0.057 B- -4783.385 9.167 74 925810.570 4.600 + 3 39 36 75 Kr x -64323.624 8.104 8553.439 0.108 B- -7104.929 8.189 74 930945.746 8.700 + 1 38 37 75 Rb x -57218.694 1.180 8448.275 0.016 B- -10600.000 220.000 74 938573.201 1.266 + -1 37 38 75 Sr - -46618.694 220.003 8296.511 2.933 B- -14799# 372# 74 949952.770 236.183 + -3 36 39 75 Y x -31820# 300# 8089# 4# B- * 74 965840# 322# +0 22 49 27 76 Co x -24510# 600# 8116# 8# B- 17120# 721# 75 973687# 644# + 20 48 28 76 Ni x -41630# 400# 8331# 5# B- 9346# 400# 75 955308# 429# + 18 47 29 76 Cu x -50975.985 6.707 8443.527 0.088 B- 11327.031 6.863 75 945275.025 7.200 + 16 46 30 76 Zn -62303.016 1.456 8582.273 0.019 B- 3993.624 2.438 75 933114.957 1.562 + 14 45 31 76 Ga x -66296.640 1.956 8624.526 0.026 B- 6916.249 1.956 75 928827.625 2.100 + 12 44 32 76 Ge -73212.889 0.018 8705.236 0.000 B- -921.512 0.886 75 921402.726 0.019 + 10 43 33 76 As -n -72291.377 0.886 8682.816 0.012 B- 2960.573 0.886 75 922392.010 0.951 + 8 42 34 76 Se -75251.950 0.016 8711.477 0.000 B- -4962.881 9.322 75 919213.704 0.017 + 6 41 35 76 Br - -70289.068 9.322 8635.882 0.123 B- -1275.355 10.149 75 924541.577 10.007 + 4 40 36 76 Kr -69013.714 4.013 8608.807 0.053 B- -8534.633 4.121 75 925910.726 4.308 + 2 39 37 76 Rb x -60479.081 0.938 8486.215 0.012 B- -6231.442 34.478 75 935073.032 1.006 + 0 38 38 76 Sr x -54247.639 34.465 8393.929 0.453 B- -15768# 302# 75 941762.761 37.000 + -2 37 39 76 Y x -38480# 300# 8176# 4# B- * 75 958690# 322# +0 23 50 27 77 Co x -21015# 600# 8070# 8# B- 15785# 781# 76 977440# 644# + 21 49 28 77 Ni x -36800# 500# 8265# 6# B- 11824# 522# 76 960494# 537# + 19 48 29 77 Cu x -48624# 149# 8408# 2# B- 10165# 149# 76 947800# 160# + 17 47 30 77 Zn -58789.195 1.973 8530.003 0.026 B- 7203.149 3.124 76 936887.199 2.117 + 15 46 31 77 Ga x -65992.344 2.422 8613.390 0.031 B- 5220.518 2.422 76 929154.300 2.600 + 13 45 32 77 Ge -n -71212.862 0.053 8671.028 0.001 B- 2703.456 1.694 76 923549.844 0.056 + 11 44 33 77 As -73916.318 1.693 8695.978 0.022 B- 683.170 1.693 76 920647.564 1.817 + 9 43 34 77 Se -74599.488 0.062 8694.690 0.001 B- -1364.680 2.810 76 919914.150 0.067 + 7 42 35 77 Br - -73234.809 2.811 8666.806 0.037 B- -3065.366 3.424 76 921379.194 3.017 + 5 41 36 77 Kr x -70169.443 1.956 8616.836 0.025 B- -5338.951 2.351 76 924670.000 2.100 + 3 40 37 77 Rb x -64830.492 1.304 8537.339 0.017 B- -7027.055 8.024 76 930401.600 1.400 + 1 39 38 77 Sr x -57803.436 7.918 8435.918 0.103 B- -11365# 203# 76 937945.455 8.500 + -1 38 39 77 Y -p -46439# 203# 8278# 3# B- -14399# 448# 76 950146# 218# + -3 37 40 77 Zr x -32040# 400# 8081# 5# B- * 76 965604# 429# +0 22 50 28 78 Ni x -33890# 600# 8225# 8# B- 10608# 783# 77 963618# 644# + 20 49 29 78 Cu x -44497.469 503.007 8350.925 6.449 B- 12985.766 503.011 77 952230.000 540.000 + 18 48 30 78 Zn -57483.235 1.944 8507.379 0.025 B- 6222.716 2.719 77 938289.205 2.086 + 16 47 31 78 Ga -63705.950 1.903 8577.127 0.024 B- 8156.099 4.015 77 931608.845 2.043 + 14 46 32 78 Ge -nn -71862.050 3.536 8671.663 0.045 B- 954.890 10.400 77 922852.912 3.795 + 12 45 33 78 As +pn -72816.940 9.781 8673.875 0.125 B- 4209.004 9.782 77 921827.795 10.500 + 10 44 34 78 Se -77025.944 0.179 8717.806 0.002 B- -3573.784 3.575 77 917309.243 0.191 + 8 43 35 78 Br - -73452.160 3.580 8661.959 0.046 B- 726.116 3.584 77 921145.859 3.842 + 6 42 36 78 Kr -74178.275 0.307 8661.238 0.004 B- -7242.857 3.252 77 920366.341 0.329 + 4 41 37 78 Rb x -66935.419 3.237 8558.350 0.042 B- -3761.477 8.125 77 928141.868 3.475 + 2 40 38 78 Sr x -63173.941 7.452 8500.096 0.096 B- -11001# 298# 77 932179.980 8.000 + 0 39 39 78 Y x -52173# 298# 8349# 4# B- -11323# 499# 77 943990# 320# + -2 38 40 78 Zr x -40850# 400# 8194# 5# B- * 77 956146# 429# +0 23 51 28 79 Ni x -27570# 600# 8143# 8# B- 14170# 671# 78 970402# 644# + 21 50 29 79 Cu x -41740# 300# 8312# 4# B- 11692# 300# 78 955190# 322# + 19 49 30 79 Zn -53432.295 2.225 8450.582 0.028 B- 9115.384 2.901 78 942638.068 2.388 + 17 48 31 79 Ga -62547.679 1.868 8556.063 0.024 B- 6978.913 37.147 78 932852.301 2.005 + 15 47 32 79 Ge -69526.592 37.181 8634.501 0.471 B- 4109.457 37.456 78 925360.129 39.915 + 13 46 33 79 As -73636.049 5.328 8676.616 0.067 B- 2281.410 5.331 78 920948.445 5.719 + 11 45 34 79 Se -n -75917.459 0.223 8695.592 0.003 B- 150.576 1.038 78 918499.251 0.238 + 9 44 35 79 Br +n -76068.035 1.021 8687.594 0.013 B- -1625.778 3.333 78 918337.601 1.095 + 7 43 36 79 Kr - -74442.257 3.486 8657.112 0.044 B- -3639.271 4.092 78 920082.945 3.742 + 5 42 37 79 Rb x -70802.985 2.142 8601.142 0.027 B- -5326.096 8.653 78 923989.864 2.300 + 3 41 38 79 Sr x -65476.889 8.383 8523.820 0.106 B- -7659.056 79.620 78 929707.664 9.000 + 1 40 39 79 Y x -57817.833 79.177 8416.967 1.002 B- -11048# 310# 78 937930.000 85.000 + -1 39 40 79 Zr x -46770# 300# 8267# 4# B- -15120# 583# 78 949790# 322# + -3 38 41 79 Nb x -31650# 500# 8066# 6# B- * 78 966022# 537# +0 24 52 28 80 Ni x -22630# 700# 8080# 9# B- 13570# 806# 79 975706# 751# + 22 51 29 80 Cu x -36200# 400# 8240# 5# B- 15449# 400# 79 961138# 429# + 20 50 30 80 Zn -51648.612 2.585 8423.545 0.032 B- 7575.055 3.877 79 944552.930 2.774 + 18 49 31 80 Ga x -59223.667 2.891 8508.454 0.036 B- 10311.639 3.541 79 936420.774 3.103 + 16 48 32 80 Ge x -69535.306 2.054 8627.570 0.026 B- 2679.187 3.915 79 925350.774 2.205 + 14 47 33 80 As x -72214.493 3.333 8651.280 0.042 B- 5544.964 3.445 79 922474.548 3.577 + 12 46 34 80 Se -77759.457 0.963 8710.813 0.012 B- -1870.464 0.310 79 916521.785 1.034 + 10 45 35 80 Br - -75888.993 1.012 8677.653 0.013 B- 2004.353 1.154 79 918529.810 1.086 + 8 44 36 80 Kr -77893.346 0.691 8692.928 0.009 B- -5717.879 1.987 79 916378.048 0.742 + 6 43 37 80 Rb x -72175.467 1.863 8611.675 0.023 B- -1864.009 3.933 79 922516.444 2.000 + 4 42 38 80 Sr x -70311.459 3.464 8578.596 0.043 B- -9163.307 7.139 79 924517.540 3.718 + 2 41 39 80 Y x -61148.152 6.242 8454.275 0.078 B- -6788# 300# 79 934354.755 6.701 + 0 40 40 80 Zr x -54360# 300# 8360# 4# B- -15940# 500# 79 941642# 322# + -2 39 41 80 Nb x -38420# 400# 8151# 5# B- * 79 958754# 429# +0 23 52 29 81 Cu x -31420# 500# 8179# 6# B- 14779# 500# 80 966269# 537# + 21 51 30 81 Zn x -46199.663 5.030 8351.925 0.062 B- 11428.292 5.996 80 950402.619 5.400 + 19 50 31 81 Ga x -57627.954 3.264 8483.357 0.040 B- 8663.733 3.851 80 938133.842 3.503 + 17 49 32 81 Ge x -66291.687 2.055 8580.658 0.025 B- 6241.617 3.344 80 928832.942 2.205 + 15 48 33 81 As -72533.304 2.644 8648.056 0.033 B- 3855.684 2.812 80 922132.290 2.838 + 13 47 34 81 Se -76388.988 0.992 8685.999 0.012 B- 1588.046 1.389 80 917993.044 1.065 + 11 46 35 81 Br -77977.034 0.978 8695.946 0.012 B- -280.853 0.471 80 916288.206 1.049 + 9 45 36 81 Kr -77696.181 1.074 8682.820 0.013 B- -2239.511 5.019 80 916589.714 1.152 + 7 44 37 81 Rb -75456.670 4.904 8645.513 0.061 B- -3928.545 5.817 80 918993.927 5.264 + 5 43 38 81 Sr x -71528.125 3.128 8587.354 0.039 B- -5815.214 6.245 80 923211.394 3.358 + 3 42 39 81 Y x -65712.912 5.405 8505.902 0.067 B- -8252.773 94.236 80 929454.283 5.802 + 1 41 40 81 Zr x -57460.139 94.081 8394.358 1.161 B- -11100# 411# 80 938314.000 101.000 + -1 40 41 81 Nb x -46360# 400# 8248# 5# B- -14610# 640# 80 950230# 429# + -3 39 42 81 Mo x -31750# 500# 8058# 6# B- * 80 965915# 537# +0 24 53 29 82 Cu x -25320# 600# 8103# 7# B- 16994# 600# 81 972818# 644# + 22 52 30 82 Zn x -42313.954 3.074 8301.117 0.037 B- 10616.764 3.916 81 954574.099 3.300 + 20 51 31 82 Ga x -52930.719 2.426 8421.049 0.030 B- 12484.348 3.296 81 943176.533 2.604 + 18 50 32 82 Ge x -65415.067 2.241 8563.756 0.027 B- 4690.352 4.345 81 929774.033 2.405 + 16 49 33 82 As x -70105.419 3.729 8611.414 0.045 B- 7488.463 3.758 81 924738.733 4.003 + 14 48 34 82 Se -77593.882 0.467 8693.196 0.006 B- -95.221 1.077 81 916699.537 0.500 + 12 47 35 82 Br -77498.661 0.971 8682.494 0.012 B- 3093.124 0.971 81 916801.760 1.042 + 10 46 36 82 Kr -80591.78515 0.00549 8710.675 0.000 B- -4403.982 3.009 81 913481.15520 0.00589 + 8 45 37 82 Rb IT -76187.803 3.009 8647.427 0.037 B- -177.751 6.705 81 918209.024 3.230 + 6 44 38 82 Sr -76010.053 5.992 8635.718 0.073 B- -7945.961 8.132 81 918399.847 6.432 + 4 43 39 82 Y x -68064.091 5.499 8529.275 0.067 B- -4432.804 12.457 81 926930.188 5.902 + 2 42 40 82 Zr x -63631.287 11.178 8465.676 0.136 B- -11541# 300# 81 931689.000 12.000 + 0 41 41 82 Nb x -52090# 300# 8315# 4# B- -11720# 500# 81 944079# 322# + -2 40 42 82 Mo x -40370# 400# 8163# 5# B- * 81 956661# 429# +0 23 53 30 83 Zn x -36290# 300# 8226# 4# B- 12967# 300# 82 961041# 322# + 21 52 31 83 Ga x -49257.122 2.613 8372.575 0.031 B- 11719.312 3.559 82 947120.301 2.804 + 19 51 32 83 Ge x -60976.435 2.427 8504.345 0.029 B- 8692.888 3.698 82 934539.101 2.605 + 17 50 33 83 As x -69669.323 2.799 8599.653 0.034 B- 5671.207 4.129 82 925206.901 3.004 + 15 49 34 83 Se -n -75340.530 3.036 8658.555 0.037 B- 3673.179 4.839 82 919118.609 3.259 + 13 48 35 83 Br -79013.709 3.795 8693.384 0.046 B- 976.924 3.795 82 915175.289 4.073 + 11 47 36 83 Kr -79990.633 0.009 8695.729 0.000 B- -920.004 2.329 82 914126.518 0.009 + 9 46 37 83 Rb -79070.630 2.329 8675.218 0.028 B- -2273.024 6.424 82 915114.182 2.500 + 7 45 38 83 Sr -76797.606 6.834 8638.407 0.082 B- -4591.941 19.844 82 917554.374 7.336 + 5 44 39 83 Y x -72205.665 18.631 8573.656 0.224 B- -6294.012 19.707 82 922484.025 20.000 + 3 43 40 83 Zr x -65911.654 6.430 8488.399 0.077 B- -8355.571 151.039 82 929240.925 6.902 + 1 42 41 83 Nb x -57556.083 150.902 8378.304 1.818 B- -11216# 428# 82 938211.000 162.000 + -1 41 42 83 Mo x -46340# 401# 8234# 5# B- -15020# 641# 82 950252# 430# + -3 40 43 83 Tc x -31320# 500# 8043# 6# B- * 82 966377# 537# +0 24 54 30 84 Zn x -31930# 400# 8172# 5# B- 12158# 447# 83 965722# 429# + 22 53 31 84 Ga x -44088# 200# 8307# 2# B- 14061# 200# 83 952670# 215# + 20 52 32 84 Ge x -58148.428 3.171 8465.524 0.038 B- 7705.132 4.479 83 937575.091 3.403 + 18 51 33 84 As x -65853.560 3.171 8547.938 0.038 B- 10094.161 3.722 83 929303.291 3.403 + 16 50 34 84 Se -75947.721 1.961 8658.793 0.023 B- 1835.363 25.765 83 918466.762 2.105 + 14 49 35 84 Br -77783.084 25.730 8671.329 0.306 B- 4656.251 25.730 83 916496.419 27.622 + 12 48 36 84 Kr -82439.33510 0.00379 8717.446 0.000 B- -2680.371 2.194 83 911497.72863 0.00407 + 10 47 37 84 Rb -79758.964 2.194 8676.224 0.026 B- 890.606 2.336 83 914375.225 2.355 + 8 46 38 84 Sr -80649.570 1.243 8677.512 0.015 B- -6755.139 4.411 83 913419.120 1.334 + 6 45 39 84 Y -73894.431 4.299 8587.780 0.051 B- -2472.745 6.977 83 920671.061 4.615 + 4 44 40 84 Zr x -71421.686 5.499 8549.029 0.065 B- -10202.968 14.153 83 923325.662 5.903 + 2 43 41 84 Nb x -61218.717 13.041 8418.252 0.155 B- -7049# 298# 83 934279.000 14.000 + 0 42 42 84 Mo x -54170# 298# 8325# 4# B- -16470# 499# 83 941846# 320# + -2 41 43 84 Tc x -37700# 400# 8120# 5# B- * 83 959527# 429# +0 25 55 30 85 Zn x -25230# 500# 8092# 6# B- 14619# 582# 84 972914# 537# + 23 54 31 85 Ga x -39849# 298# 8255# 4# B- 13274# 298# 84 957220# 320# + 21 53 32 85 Ge x -53123.420 3.729 8401.768 0.044 B- 10065.724 4.830 84 942969.659 4.003 + 19 52 33 85 As x -63189.144 3.078 8510.984 0.036 B- 9224.492 4.031 84 932163.659 3.304 + 17 51 34 85 Se +3p -72413.636 2.613 8610.304 0.031 B- 6161.833 4.031 84 922260.759 2.804 + 15 50 35 85 Br +n2p -78575.469 3.078 8673.592 0.036 B- 2904.861 3.671 84 915645.759 3.304 + 13 49 36 85 Kr + -81480.331 2.000 8698.562 0.024 B- 687.000 2.000 84 912527.262 2.147 + 11 48 37 85 Rb -82167.33050 0.00498 8697.441 0.000 B- -1064.051 2.813 84 911789.73760 0.00534 + 9 47 38 85 Sr -81103.280 2.813 8675.718 0.033 B- -3261.157 19.173 84 912932.043 3.020 + 7 46 39 85 Y x -77842.123 18.965 8628.148 0.223 B- -4666.934 20.026 84 916433.039 20.360 + 5 45 40 85 Zr x -73175.189 6.430 8564.039 0.076 B- -6895.514 7.625 84 921443.198 6.902 + 3 44 41 85 Nb x -66279.676 4.099 8473.711 0.048 B- -8769.923 16.357 84 928845.837 4.400 + 1 43 42 85 Mo x -57509.753 15.835 8361.331 0.186 B- -11660# 400# 84 938260.737 17.000 + -1 42 43 85 Tc x -45850# 400# 8215# 5# B- -14900# 640# 84 950778# 429# + -3 41 44 85 Ru x -30950# 500# 8030# 6# B- * 84 966774# 537# +0 24 55 31 86 Ga x -34080# 400# 8186# 5# B- 15320# 593# 85 963414# 429# + 22 54 32 86 Ge x -49399.922 437.802 8354.629 5.091 B- 9562.221 437.816 85 946967.000 470.000 + 20 53 33 86 As x -58962.142 3.450 8456.721 0.040 B- 11541.024 4.267 85 936701.533 3.703 + 18 52 34 86 Se x -70503.167 2.520 8581.822 0.029 B- 5129.085 3.972 85 924311.733 2.705 + 16 51 35 86 Br +pp -75632.252 3.078 8632.365 0.036 B- 7633.414 3.078 85 918805.433 3.304 + 14 50 36 86 Kr -83265.66564 0.00369 8712.029 0.000 B- -518.672 0.200 85 910610.62627 0.00396 + 12 49 37 86 Rb -n -82746.993 0.200 8696.901 0.002 B- 1776.096 0.200 85 911167.443 0.214 + 10 48 38 86 Sr -84523.08935 0.00522 8708.456 0.000 B- -5240.000 14.142 85 909260.72631 0.00561 + 8 47 39 86 Y - -79283.089 14.142 8638.428 0.164 B- -1314.075 14.585 85 914886.098 15.182 + 6 46 40 86 Zr -77969.014 3.566 8614.051 0.041 B- -8834.960 6.552 85 916296.815 3.827 + 4 45 41 86 Nb x -69134.054 5.499 8502.222 0.064 B- -5023.810 6.642 85 925781.535 5.903 + 2 44 42 86 Mo x -64110.245 3.726 8434.709 0.043 B- -12540# 300# 85 931174.817 4.000 + 0 43 43 86 Tc x -51570# 300# 8280# 3# B- -11800# 500# 85 944637# 322# + -2 42 44 86 Ru x -39770# 400# 8133# 5# B- * 85 957305# 429# +0 25 56 31 87 Ga x -29250# 500# 8129# 6# B- 14828# 583# 86 968599# 537# + 23 55 32 87 Ge x -44078# 300# 8290# 3# B- 11540# 300# 86 952680# 322# + 21 54 33 87 As x -55617.907 2.985 8413.851 0.034 B- 10808.218 3.726 86 940291.718 3.204 + 19 53 34 87 Se x -66426.125 2.241 8529.091 0.026 B- 7465.552 3.877 86 928688.618 2.405 + 17 52 35 87 Br 2p-n -73891.676 3.171 8605.910 0.036 B- 6817.845 3.181 86 920674.018 3.404 + 15 51 36 87 Kr -n -80709.522 0.246 8675.283 0.003 B- 3888.269 0.246 86 913354.759 0.264 + 13 50 37 87 Rb -84597.791 0.006 8710.983 0.000 B- 282.275 0.006 86 909180.531 0.006 + 11 49 38 87 Sr -84880.06595 0.00510 8705.236 0.000 B- -1861.690 1.128 86 908877.49615 0.00548 + 9 48 39 87 Y - -83018.376 1.128 8674.844 0.013 B- -3671.239 4.296 86 910876.102 1.210 + 7 47 40 87 Zr -79347.137 4.146 8623.654 0.048 B- -5472.651 7.963 86 914817.339 4.450 + 5 46 41 87 Nb x -73874.486 6.802 8551.757 0.078 B- -6989.678 7.378 86 920692.472 7.302 + 3 45 42 87 Mo -66884.808 2.857 8462.424 0.033 B- -9194.764 5.073 86 928196.201 3.067 + 1 44 43 87 Tc x -57690.044 4.192 8347.744 0.048 B- -12170# 400# 86 938067.187 4.500 + -1 43 44 87 Ru x -45520# 400# 8199# 5# B- * 86 951132# 429# +0 24 56 32 88 Ge x -40138# 400# 8243# 5# B- 10582# 445# 87 956910# 429# + 22 55 33 88 As x -50720# 196# 8354# 2# B- 13164# 196# 87 945550# 210# + 20 54 34 88 Se x -63884.195 3.357 8495.004 0.038 B- 6831.763 4.613 87 931417.491 3.604 + 18 53 35 88 Br ++ -70715.959 3.171 8563.747 0.036 B- 8975.327 4.106 87 924083.291 3.404 + 16 52 36 88 Kr x -79691.286 2.608 8656.849 0.030 B- 2917.709 2.613 87 914447.881 2.800 + 14 51 37 88 Rb -82608.995 0.159 8681.115 0.002 B- 5312.623 0.159 87 911315.591 0.171 + 12 50 38 88 Sr -87921.61793 0.00558 8732.595 0.000 B- -3622.600 1.500 87 905612.25561 0.00599 + 10 49 39 88 Y - -84299.018 1.500 8682.539 0.017 B- -670.147 5.608 87 909501.276 1.610 + 8 48 40 88 Zr -83628.871 5.403 8666.033 0.061 B- -7455.284 58.886 87 910220.709 5.800 + 6 47 41 88 Nb -76173.586 58.810 8572.424 0.668 B- -3487.042 58.933 87 918224.287 63.134 + 4 46 42 88 Mo x -72686.544 3.819 8523.908 0.043 B- -11005.229 149.088 87 921967.781 4.100 + 2 45 43 88 Tc x -61681.315 149.039 8389.958 1.694 B- -7342# 335# 87 933782.381 160.000 + 0 44 44 88 Ru x -54340# 300# 8298# 3# B- -17479# 500# 87 941664# 322# + -2 43 45 88 Rh x -36860# 400# 8090# 5# B- * 87 960429# 429# +0 25 57 32 89 Ge x -33729# 400# 8169# 4# B- 13069# 499# 88 963790# 429# + 23 56 33 89 As x -46798# 298# 8307# 3# B- 12194# 298# 88 949760# 320# + 21 55 34 89 Se x -58992.391 3.729 8435.279 0.042 B- 9281.872 4.951 88 936669.059 4.003 + 19 54 35 89 Br x -68274.263 3.264 8530.779 0.037 B- 8261.522 3.904 88 926704.559 3.504 + 17 53 36 89 Kr x -76535.785 2.142 8614.815 0.024 B- 5176.604 5.834 88 917835.450 2.300 + 15 52 37 89 Rb -81712.388 5.427 8664.189 0.061 B- 4496.628 5.427 88 912278.137 5.825 + 13 51 38 89 Sr -86209.017 0.092 8705.922 0.001 B- 1499.336 1.615 88 907450.808 0.098 + 11 50 39 89 Y -87708.352 1.612 8713.978 0.018 B- -2832.792 2.776 88 905841.205 1.730 + 9 49 40 89 Zr -84875.561 3.083 8673.359 0.035 B- -4250.351 23.743 88 908882.332 3.310 + 7 48 41 89 Nb -80625.209 23.631 8616.812 0.266 B- -5610.275 23.953 88 913445.272 25.369 + 5 47 42 89 Mo x -75014.935 3.912 8544.984 0.044 B- -7620.087 5.467 88 919468.150 4.200 + 3 46 43 89 Tc x -67394.848 3.819 8450.575 0.043 B- -9135# 298# 88 927648.650 4.100 + 1 45 44 89 Ru x -58260# 298# 8339# 3# B- -12400# 468# 88 937455# 320# + -1 44 45 89 Rh -p -45861# 361# 8191# 4# B- * 88 950767# 387# +0 26 58 32 90 Ge x -29221# 500# 8118# 6# B- 12109# 640# 89 968630# 537# + 24 57 33 90 As x -41330# 400# 8244# 4# B- 14470# 518# 89 955630# 429# + 22 56 34 90 Se x -55800.217 329.749 8395.766 3.664 B- 8200.081 329.766 89 940096.000 354.000 + 20 55 35 90 Br x -64000.298 3.357 8478.186 0.037 B- 10958.952 3.840 89 931292.850 3.604 + 18 54 36 90 Kr x -74959.250 1.863 8591.259 0.021 B- 4405.154 6.746 89 919527.930 2.000 + 16 53 37 90 Rb -79364.404 6.484 8631.512 0.072 B- 6583.723 6.544 89 914798.803 6.960 + 14 52 38 90 Sr -85948.127 2.124 8695.972 0.024 B- 545.934 1.406 89 907730.885 2.280 + 12 51 39 90 Y -86494.062 1.611 8693.345 0.018 B- 2278.474 1.609 89 907144.800 1.729 + 10 50 40 90 Zr -88772.535 0.118 8709.969 0.001 B- -6111.016 3.316 89 904698.758 0.126 + 8 49 41 90 Nb -82661.519 3.317 8633.376 0.037 B- -2489.016 3.316 89 911259.204 3.561 + 6 48 42 90 Mo -80172.503 3.463 8597.028 0.038 B- -9447.816 3.611 89 913931.272 3.717 + 4 47 43 90 Tc x -70724.687 1.025 8483.359 0.011 B- -5840.895 3.869 89 924073.921 1.100 + 2 46 44 90 Ru -64883.792 3.730 8409.768 0.041 B- -13184# 300# 89 930344.379 4.004 + 0 45 45 90 Rh x -51700# 300# 8255# 3# B- -11990# 500# 89 944498# 322# + -2 44 46 90 Pd x -39710# 400# 8113# 4# B- * 89 957370# 429# +0 25 58 33 91 As x -36896# 400# 8193# 4# B- 13684# 589# 90 960390# 429# + 23 57 34 91 Se x -50580.124 433.145 8334.837 4.760 B- 10527.169 433.159 90 945700.000 465.000 + 21 56 35 91 Br -n2p -61107.294 3.544 8441.923 0.039 B- 9866.671 4.190 90 934398.618 3.804 + 19 55 36 91 Kr x -70973.965 2.236 8541.751 0.025 B- 6771.072 8.115 90 923806.310 2.400 + 17 54 37 91 Rb -77745.037 7.801 8607.561 0.086 B- 5906.890 8.873 90 916537.265 8.375 + 15 53 38 91 Sr -83651.927 5.453 8663.875 0.060 B- 2699.369 5.247 90 910195.958 5.853 + 13 52 39 91 Y -86351.295 1.843 8684.941 0.020 B- 1544.271 1.840 90 907298.066 1.978 + 11 51 40 91 Zr -87895.566 0.105 8693.314 0.001 B- -1257.565 2.924 90 905640.223 0.112 + 9 50 41 91 Nb -86638.001 2.926 8670.897 0.032 B- -4429.180 6.744 90 906990.274 3.141 + 7 49 42 91 Mo -82208.821 6.238 8613.628 0.069 B- -6222.175 6.671 90 911745.195 6.696 + 5 48 43 91 Tc -75986.646 2.363 8536.655 0.026 B- -7746.824 3.242 90 918424.975 2.536 + 3 47 44 91 Ru -68239.823 2.221 8442.928 0.024 B- -9670# 298# 90 926741.532 2.384 + 1 46 45 91 Rh x -58570# 298# 8328# 3# B- -12639# 499# 90 937123# 320# + -1 45 46 91 Pd x -45930# 401# 8181# 4# B- * 90 950692# 430# +0 26 59 33 92 As x -30981# 500# 8127# 5# B- 15742# 640# 91 966740# 537# + 24 58 34 92 Se x -46724# 400# 8290# 4# B- 9509# 400# 91 949840# 429# + 22 57 35 92 Br x -56232.805 6.709 8384.911 0.073 B- 12536.514 7.232 91 939631.597 7.202 + 20 56 36 92 Kr x -68769.320 2.701 8512.674 0.029 B- 6003.118 6.692 91 926173.094 2.900 + 18 55 37 92 Rb -74772.438 6.123 8569.422 0.067 B- 8094.923 6.419 91 919728.481 6.573 + 16 54 38 92 Sr -82867.361 3.423 8648.906 0.037 B- 1949.132 9.384 91 911038.224 3.675 + 14 53 39 92 Y -84816.492 9.127 8661.589 0.099 B- 3642.535 9.127 91 908945.745 9.798 + 12 52 40 92 Zr -88459.028 0.102 8692.678 0.001 B- -2005.736 1.782 91 905035.322 0.109 + 10 51 41 92 Nb -86453.292 1.785 8662.372 0.019 B- 355.284 1.791 91 907188.568 1.915 + 8 50 42 92 Mo -86808.576 0.157 8657.730 0.002 B- -7882.884 3.106 91 906807.155 0.168 + 6 49 43 92 Tc -78925.693 3.102 8563.543 0.034 B- -4624.492 4.125 91 915269.779 3.330 + 4 48 44 92 Ru -74301.201 2.718 8504.773 0.030 B- -11302.114 5.153 91 920234.375 2.917 + 2 47 45 92 Rh x -62999.087 4.378 8373.420 0.048 B- -8419# 300# 91 932367.694 4.700 + 0 46 46 92 Pd x -54580# 300# 8273# 3# B- -17450# 583# 91 941406# 322# + -2 45 47 92 Ag x -37130# 500# 8075# 5# B- * 91 960139# 537# +0 25 59 34 93 Se x -40716# 400# 8223# 4# B- 12175# 588# 92 956290# 429# + 23 58 35 93 Br x -52890.230 430.816 8345.598 4.632 B- 11245.765 430.823 92 943220.000 462.500 + 21 57 36 93 Kr x -64135.994 2.515 8458.108 0.027 B- 8483.907 8.224 92 931147.174 2.700 + 19 56 37 93 Rb -72619.901 7.830 8540.920 0.084 B- 7465.938 8.876 92 922039.325 8.406 + 17 55 38 93 Sr -80085.838 7.554 8612.787 0.081 B- 4141.319 11.697 92 914024.311 8.109 + 15 54 39 93 Y -84227.157 10.488 8648.905 0.113 B- 2894.875 10.483 92 909578.422 11.259 + 13 53 40 93 Zr -87122.032 0.457 8671.620 0.005 B- 90.806 1.484 92 906470.646 0.490 + 11 52 41 93 Nb -87212.838 1.491 8664.184 0.016 B- -405.769 1.501 92 906373.161 1.600 + 9 51 42 93 Mo -n -86807.069 0.181 8651.409 0.002 B- -3200.963 1.004 92 906808.773 0.193 + 7 50 43 93 Tc -p -83606.106 1.012 8608.577 0.011 B- -6389.393 2.299 92 910245.149 1.086 + 5 49 44 93 Ru -77216.713 2.065 8531.462 0.022 B- -8204.913 3.343 92 917104.444 2.216 + 3 48 45 93 Rh -69011.800 2.629 8434.825 0.028 B- -10011# 301# 92 925912.781 2.821 + 1 47 46 93 Pd +p -59001# 300# 8319# 3# B- -12734# 501# 92 936660# 323# + -1 46 47 93 Ag x -46267# 401# 8173# 4# B- * 92 950330# 430# +0 26 60 34 94 Se x -36803# 500# 8180# 5# B- 10597# 583# 93 960490# 537# + 24 59 35 94 Br x -47400# 300# 8284# 3# B- 13948# 300# 93 949114# 322# + 22 58 36 94 Kr x -61347.772 12.109 8424.331 0.129 B- 7215.013 12.278 93 934140.454 13.000 + 20 57 37 94 Rb -68562.785 2.029 8492.764 0.022 B- 10282.926 2.623 93 926394.818 2.177 + 18 56 38 94 Sr -78845.711 1.663 8593.834 0.018 B- 3505.752 6.422 93 915355.643 1.785 + 16 55 39 94 Y -82351.463 6.380 8622.806 0.068 B- 4917.859 6.380 93 911592.063 6.849 + 14 54 40 94 Zr -87269.322 0.164 8666.801 0.002 B- -900.260 1.500 93 906312.524 0.175 + 12 53 41 94 Nb -86369.062 1.491 8648.901 0.016 B- 2045.002 1.494 93 907278.992 1.601 + 10 52 42 94 Mo -88414.065 0.141 8662.333 0.002 B- -4255.748 4.069 93 905083.592 0.151 + 8 51 43 94 Tc - -84158.317 4.071 8608.736 0.043 B- -1574.726 5.143 93 909652.325 4.370 + 6 50 44 94 Ru -82583.591 3.143 8583.661 0.033 B- -9675.978 4.615 93 911342.863 3.374 + 4 49 45 94 Rh -72907.613 3.379 8472.402 0.036 B- -6805.345 5.459 93 921730.453 3.627 + 2 48 46 94 Pd x -66102.268 4.287 8391.682 0.046 B- -13693# 400# 93 929036.292 4.602 + 0 47 47 94 Ag x -52410# 400# 8238# 4# B- -12270# 640# 93 943736# 429# + -2 46 48 94 Cd x -40140# 500# 8099# 5# B- * 93 956908# 537# +0 27 61 34 95 Se x -30460# 500# 8112# 5# B- 13311# 582# 94 967300# 537# + 25 60 35 95 Br x -43771# 298# 8244# 3# B- 12388# 299# 94 953010# 320# + 23 59 36 95 Kr x -56158.913 18.630 8365.995 0.196 B- 9732.580 27.513 94 939710.923 20.000 + 21 58 37 95 Rb -65891.493 20.245 8460.208 0.213 B- 9228.058 20.204 94 929262.568 21.734 + 19 57 38 95 Sr -75119.551 5.812 8549.111 0.061 B- 6089.296 7.240 94 919355.840 6.239 + 17 56 39 95 Y -81208.848 6.779 8604.973 0.071 B- 4451.092 6.772 94 912818.711 7.277 + 15 55 40 95 Zr -85659.940 0.869 8643.592 0.009 B- 1126.318 0.985 94 908040.267 0.933 + 13 54 41 95 Nb -86786.258 0.508 8647.212 0.005 B- 925.601 0.494 94 906831.115 0.545 + 11 53 42 95 Mo -87711.858 0.123 8648.720 0.001 B- -1690.518 5.078 94 905837.442 0.132 + 9 52 43 95 Tc -86021.341 5.080 8622.690 0.053 B- -2563.596 10.531 94 907652.287 5.453 + 7 51 44 95 Ru -83457.745 9.502 8587.470 0.100 B- -5117.138 10.266 94 910404.420 10.200 + 5 50 45 95 Rh -78340.606 3.886 8525.370 0.041 B- -8374.706 4.928 94 915897.895 4.171 + 3 49 46 95 Pd x -69965.900 3.031 8428.980 0.032 B- -10369# 298# 94 924888.512 3.253 + 1 48 47 95 Ag x -59597# 298# 8312# 3# B- -12966# 499# 94 936020# 320# + -1 47 48 95 Cd x -46631# 401# 8167# 4# B- * 94 949940# 430# +0 26 61 35 96 Br x -38163# 298# 8184# 3# B- 14916# 299# 95 959030# 320# + 24 60 36 96 Kr x -53079.678 20.493 8330.851 0.213 B- 8274.671 20.765 95 943016.618 22.000 + 22 59 37 96 Rb -61354.349 3.353 8408.896 0.035 B- 11569.808 9.115 95 934133.393 3.599 + 20 58 38 96 Sr -72924.157 8.475 8521.265 0.088 B- 5411.738 9.726 95 921712.692 9.098 + 18 57 39 96 Y -78335.895 6.088 8569.488 0.063 B- 7102.951 6.087 95 915902.953 6.535 + 16 56 40 96 Zr -85438.846 0.114 8635.327 0.001 B- 163.971 0.100 95 908277.621 0.122 + 14 55 41 96 Nb -85602.816 0.147 8628.886 0.002 B- 3192.059 0.107 95 908101.591 0.157 + 12 54 42 96 Mo -88794.876 0.120 8653.987 0.001 B- -2973.242 5.145 95 904674.774 0.128 + 10 53 43 96 Tc - -85821.634 5.146 8614.866 0.054 B- 258.738 5.146 95 907866.681 5.524 + 8 52 44 96 Ru -86080.372 0.170 8609.412 0.002 B- -6392.654 10.000 95 907588.914 0.182 + 6 51 45 96 Rh - -79687.718 10.001 8534.673 0.104 B- -3504.312 10.844 95 914451.710 10.737 + 4 50 46 96 Pd x -76183.406 4.194 8490.020 0.044 B- -11671.771 90.181 95 918213.744 4.502 + 2 49 47 96 Ag ep -64511.636 90.084 8360.290 0.938 B- -8939# 411# 95 930743.906 96.708 + 0 48 48 96 Cd x -55573# 401# 8259# 4# B- -17683# 641# 95 940340# 430# + -2 47 49 96 In x -37890# 500# 8067# 5# B- * 95 959323# 537# +0 27 62 35 97 Br x -34055# 401# 8140# 4# B- 13368# 421# 96 963440# 430# + 25 61 36 97 Kr x -47423.492 130.409 8269.864 1.344 B- 11095.645 130.423 96 949088.784 140.000 + 23 60 37 97 Rb -58519.137 1.912 8376.186 0.020 B- 10062.317 3.888 96 937177.118 2.052 + 21 59 38 97 Sr -68581.454 3.385 8471.856 0.035 B- 7539.969 7.521 96 926374.776 3.633 + 19 58 39 97 Y + -76121.424 6.719 8541.522 0.069 B- 6821.237 6.707 96 918280.286 7.213 + 17 57 40 97 Zr -82942.661 0.414 8603.779 0.004 B- 2663.115 4.248 96 910957.386 0.444 + 15 56 41 97 Nb -85605.776 4.249 8623.168 0.044 B- 1938.915 4.248 96 908098.414 4.561 + 13 55 42 97 Mo -87544.691 0.165 8635.092 0.002 B- -320.266 4.117 96 906016.903 0.176 + 11 54 43 97 Tc -87224.424 4.118 8623.725 0.042 B- -1103.873 4.956 96 906360.723 4.420 + 9 53 44 97 Ru -n -86120.552 2.763 8604.279 0.028 B- -3523.000 35.355 96 907545.779 2.965 + 7 52 45 97 Rh - -82597.552 35.463 8559.894 0.366 B- -4791.709 35.792 96 911327.876 38.071 + 5 51 46 97 Pd x -77805.843 4.844 8502.430 0.050 B- -6980.000 110.000 96 916471.987 5.200 + 3 50 47 97 Ag - -70825.843 110.107 8422.405 1.135 B- -10372# 318# 96 923965.326 118.204 + 1 49 48 97 Cd x -60454# 298# 8307# 3# B- -13264# 499# 96 935100# 320# + -1 48 49 97 In x -47189# 401# 8163# 4# B- * 96 949340# 430# +0 28 63 35 98 Br x -28250# 400# 8080# 4# B- 16061# 499# 97 969672# 429# + 26 62 36 98 Kr x -44311# 298# 8236# 3# B- 10058# 299# 97 952430# 320# + 24 61 37 98 Rb -54369.146 16.083 8330.729 0.164 B- 12053.958 16.403 97 941632.317 17.265 + 22 60 38 98 Sr -66423.104 3.226 8445.745 0.033 B- 5871.673 8.558 97 928691.860 3.463 + 20 59 39 98 Y p-2n -72294.777 7.929 8497.677 0.081 B- 8991.932 11.576 97 922388.360 8.511 + 18 58 40 98 Zr -81286.709 8.451 8581.448 0.086 B- 2237.890 9.819 97 912735.124 9.072 + 16 57 41 98 Nb -pn -83524.598 5.001 8596.301 0.051 B- 4591.373 5.003 97 910332.650 5.369 + 14 56 42 98 Mo -88115.972 0.174 8635.168 0.002 B- -1683.766 3.377 97 905403.608 0.186 + 12 55 43 98 Tc -86432.205 3.380 8610.004 0.034 B- 1792.653 7.157 97 907211.205 3.628 + 10 54 44 98 Ru -88224.858 6.463 8620.313 0.066 B- -5049.653 10.000 97 905286.713 6.937 + 8 53 45 98 Rh - -83175.205 11.906 8560.803 0.121 B- -1854.229 12.816 97 910707.740 12.782 + 6 52 46 98 Pd -81320.975 4.742 8533.899 0.048 B- -8254.560 33.098 97 912698.337 5.090 + 4 51 47 98 Ag -73066.415 32.907 8441.686 0.336 B- -5430.000 40.000 97 921559.972 35.327 + 2 50 48 98 Cd - -67636.415 51.797 8378.295 0.529 B- -13740# 303# 97 927389.317 55.605 + 0 49 49 98 In x -53896# 298# 8230# 3# B- * 97 942140# 320# +0 27 63 36 99 Kr x -38759# 401# 8178# 4# B- 12362# 401# 98 958390# 430# + 25 62 37 99 Rb x -51121.143 4.031 8295.300 0.041 B- 11400.258 6.223 98 945119.192 4.327 + 23 61 38 99 Sr -62521.401 4.741 8402.552 0.048 B- 8128.424 8.138 98 932880.511 5.089 + 21 60 39 99 Y x -70649.825 6.627 8476.755 0.067 B- 6970.792 12.409 98 924154.288 7.114 + 19 59 40 99 Zr -77620.617 10.502 8539.264 0.106 B- 4714.724 15.950 98 916670.835 11.274 + 17 58 41 99 Nb +p -82335.341 12.004 8578.985 0.121 B- 3634.758 12.006 98 911609.371 12.886 + 15 57 42 99 Mo -85970.098 0.229 8607.797 0.002 B- 1357.764 0.890 98 907707.298 0.245 + 13 56 43 99 Tc -87327.862 0.908 8613.610 0.009 B- 297.519 0.946 98 906249.678 0.974 + 11 55 44 99 Ru -87625.381 0.344 8608.712 0.003 B- -2044.081 6.690 98 905930.278 0.369 + 9 54 45 99 Rh -85581.300 6.697 8580.163 0.068 B- -3398.649 8.008 98 908124.690 7.189 + 7 53 46 99 Pd -82182.651 4.981 8537.930 0.050 B- -5470.178 8.004 98 911773.290 5.347 + 5 52 47 99 Ag x -76712.473 6.265 8474.774 0.063 B- -6781.350 6.462 98 917645.768 6.725 + 3 51 48 99 Cd x -69931.123 1.584 8398.373 0.016 B- -8555# 298# 98 924925.847 1.700 + 1 50 49 99 In x -61376# 298# 8304# 3# B- -13432# 585# 98 934110# 320# + -1 49 50 99 Sn x -47944# 503# 8160# 5# B- * 98 948530# 540# +0 28 64 36 100 Kr x -35052# 401# 8140# 4# B- 11195# 401# 99 962370# 430# + 26 63 37 100 Rb x -46247.064 19.561 8244.320 0.196 B- 13573.838 20.831 99 950351.731 21.000 + 24 62 38 100 Sr -59820.903 7.160 8372.234 0.072 B- 7506.493 13.273 99 935779.615 7.686 + 22 61 39 100 Y x -67327.396 11.186 8439.476 0.112 B- 9050.041 13.830 99 927721.063 12.008 + 20 60 40 100 Zr -76377.437 8.149 8522.153 0.081 B- 3419.963 11.398 99 918005.444 8.748 + 18 59 41 100 Nb IT -79797.399 7.986 8548.529 0.080 B- 6395.626 7.992 99 914333.963 8.573 + 16 58 42 100 Mo -86193.025 0.302 8604.662 0.003 B- -172.080 1.371 99 907467.976 0.323 + 14 57 43 100 Tc -n -86020.945 1.351 8595.118 0.014 B- 3206.444 1.376 99 907652.711 1.450 + 12 56 44 100 Ru -89227.389 0.343 8619.359 0.003 B- -3636.262 18.123 99 904210.452 0.368 + 10 55 45 100 Rh -85591.126 18.125 8575.172 0.181 B- -378.348 25.289 99 908114.141 19.458 + 8 54 46 100 Pd -85212.778 17.638 8563.566 0.176 B- -7074.819 18.333 99 908520.315 18.935 + 6 53 47 100 Ag x -78137.959 5.000 8484.994 0.050 B- -3943.363 5.273 99 916115.445 5.367 + 4 52 48 100 Cd -74194.596 1.677 8437.737 0.017 B- -9881.624 182.517 99 920348.820 1.799 + 2 51 49 100 In -64312.972 182.519 8331.097 1.825 B- -7030.000 240.000 99 930957.180 195.942 + 0 50 50 100 Sn - -57282.972 301.518 8252.974 3.015 B- * 99 938504.196 323.693 +0 29 65 36 101 Kr x -29128# 503# 8081# 5# B- 13717# 541# 100 968730# 540# + 27 64 37 101 Rb + -42845# 200# 8209# 2# B- 12480# 200# 100 954004# 215# + 25 63 38 101 Sr x -55324.907 8.480 8324.740 0.084 B- 9736.095 11.055 100 940606.266 9.103 + 23 62 39 101 Y x -65061.002 7.092 8413.391 0.070 B- 8104.955 10.933 100 930154.138 7.614 + 21 61 40 101 Zr -73165.957 8.339 8485.892 0.083 B- 5725.534 9.143 100 921453.110 8.951 + 19 60 41 101 Nb x -78891.491 3.749 8534.835 0.037 B- 4628.458 3.738 100 915306.496 4.024 + 17 59 42 101 Mo -n -83519.949 0.309 8572.915 0.003 B- 2824.645 24.002 100 910337.641 0.331 + 15 58 43 101 Tc + -86344.594 24.004 8593.136 0.238 B- 1613.520 24.000 100 907305.260 25.768 + 13 57 44 101 Ru -87958.114 0.415 8601.365 0.004 B- -545.697 5.852 100 905573.075 0.445 + 11 56 45 101 Rh -87412.416 5.841 8588.216 0.058 B- -1980.284 3.903 100 906158.905 6.270 + 9 55 46 101 Pd -85432.132 4.588 8560.864 0.045 B- -4097.759 6.668 100 908284.828 4.925 + 7 54 47 101 Ag x -81334.374 4.838 8512.546 0.048 B- -5497.918 5.063 100 912683.953 5.193 + 5 53 48 101 Cd x -75836.456 1.490 8450.365 0.015 B- -7223# 196# 100 918586.211 1.600 + 3 52 49 101 In x -68614# 196# 8371# 2# B- -8308# 358# 100 926340# 210# + 1 51 50 101 Sn ep -60305.626 300.005 8281.102 2.970 B- * 100 935259.244 322.068 +0 28 65 37 102 Rb x -37707# 298# 8157# 3# B- 14452# 306# 101 959520# 320# + 26 64 38 102 Sr x -52159.304 67.068 8291.220 0.658 B- 9013.873 67.191 101 944004.680 72.000 + 24 63 39 102 Y x -61173.177 4.077 8371.922 0.040 B- 10414.530 9.669 101 934327.889 4.377 + 22 62 40 102 Zr -71587.707 8.767 8466.355 0.086 B- 4716.837 9.053 101 923147.431 9.412 + 20 61 41 102 Nb -76304.544 2.545 8504.928 0.025 B- 7261.517 8.675 101 918083.697 2.732 + 18 60 42 102 Mo -83566.061 8.312 8568.450 0.081 B- 1006.817 12.373 101 910288.138 8.923 + 16 59 43 102 Tc -84572.878 9.166 8570.650 0.090 B- 4533.558 9.165 101 909207.275 9.840 + 14 58 44 102 Ru -89106.437 0.418 8607.427 0.004 B- -2323.119 6.396 101 904340.300 0.448 + 12 57 45 102 Rh - -86783.318 6.410 8576.981 0.063 B- 1119.853 6.406 101 906834.270 6.881 + 10 56 46 102 Pd -87903.171 0.554 8580.290 0.005 B- -5656.480 8.190 101 905632.058 0.594 + 8 55 47 102 Ag + -82246.691 8.171 8517.164 0.080 B- -2587.000 8.000 101 911704.540 8.771 + 6 54 48 102 Cd -79659.691 1.662 8484.131 0.016 B- -8964.807 4.865 101 914481.799 1.784 + 4 53 49 102 In -70694.884 4.573 8388.571 0.045 B- -5760.000 100.000 101 924105.916 4.909 + 2 52 50 102 Sn - -64934.884 100.105 8324.430 0.981 B- * 101 930289.530 107.466 +0 29 66 37 103 Rb x -33608# 401# 8117# 4# B- 13814# 446# 102 963920# 430# + 27 65 38 103 Sr x -47422# 196# 8243# 2# B- 11035# 196# 102 949090# 210# + 25 64 39 103 Y x -58457.575 11.204 8342.638 0.109 B- 9357.759 14.518 102 937243.208 12.028 + 23 63 40 103 Zr x -67815.334 9.232 8425.895 0.090 B- 7213.337 10.036 102 927197.240 9.911 + 21 62 41 103 Nb x -75028.671 3.935 8488.331 0.038 B- 5931.999 10.036 102 919453.403 4.224 + 19 61 42 103 Mo x -80960.670 9.232 8538.328 0.090 B- 3643.197 13.471 102 913085.140 9.911 + 17 60 43 103 Tc +p -84603.867 9.810 8566.103 0.095 B- 2663.304 9.808 102 909174.008 10.531 + 15 59 44 103 Ru -87267.171 0.443 8584.365 0.004 B- 764.538 2.260 102 906314.833 0.475 + 13 58 45 103 Rh -88031.708 2.301 8584.192 0.022 B- -574.519 2.420 102 905494.068 2.470 + 11 57 46 103 Pd -n -87457.189 0.950 8571.019 0.009 B- -2654.498 4.207 102 906110.840 1.019 + 9 56 47 103 Ag x -84802.692 4.099 8537.651 0.040 B- -4151.075 4.481 102 908960.560 4.400 + 7 55 48 103 Cd -80651.616 1.811 8489.754 0.018 B- -6019.026 9.754 102 913416.923 1.943 + 5 54 49 103 In -74632.591 9.625 8423.721 0.093 B- -7660.000 70.000 102 919878.613 10.332 + 3 53 50 103 Sn - -66972.591 70.659 8341.757 0.686 B- -10794# 306# 102 928101.962 75.855 + 1 52 51 103 Sb x -56178# 298# 8229# 3# B- * 102 939690# 320# +0 28 66 38 104 Sr x -44106# 298# 8210# 3# B- 9958# 499# 103 952650# 320# + 26 65 39 104 Y x -54064# 401# 8298# 4# B- 11660# 401# 103 941960# 430# + 24 64 40 104 Zr x -65724.060 9.325 8402.377 0.090 B- 6094.952 9.699 103 929442.315 10.011 + 22 63 41 104 Nb x -71819.012 2.737 8453.459 0.026 B- 8530.957 9.311 103 922899.115 2.938 + 20 62 42 104 Mo -80349.968 8.921 8527.965 0.086 B- 2153.476 24.167 103 913740.756 9.576 + 18 61 43 104 Tc -82503.444 24.888 8541.149 0.239 B- 5592.266 24.939 103 911428.905 26.718 + 16 60 44 104 Ru -88095.710 2.498 8587.399 0.024 B- -1136.362 3.364 103 905425.360 2.681 + 14 59 45 104 Rh -n -86959.348 2.303 8568.949 0.022 B- 2435.758 2.660 103 906645.295 2.472 + 12 58 46 104 Pd +n -89395.105 1.336 8584.848 0.013 B- -4278.654 4.000 103 904030.401 1.434 + 10 57 47 104 Ag - -85116.452 4.217 8536.184 0.041 B- -1148.072 4.537 103 908623.725 4.527 + 8 56 48 104 Cd -83968.380 1.673 8517.622 0.016 B- -7785.716 6.013 103 909856.230 1.795 + 6 55 49 104 In x -76182.665 5.775 8435.237 0.056 B- -4555.617 8.146 103 918214.540 6.200 + 4 54 50 104 Sn -71627.047 5.745 8383.911 0.055 B- -12453.427 122.579 103 923105.197 6.167 + 2 53 51 104 Sb -p -59173.620 122.444 8256.644 1.177 B- * 103 936474.502 131.449 +0 29 67 38 105 Sr x -38610# 503# 8156# 5# B- 12660# 1428# 104 958550# 540# + 27 66 39 105 Y x -51270.361 1336.694 8269.020 12.730 B- 10194.373 1336.749 104 944959.000 1435.000 + 25 65 40 105 Zr x -61464.734 12.118 8358.659 0.115 B- 8450.817 12.770 104 934014.890 13.008 + 23 64 41 105 Nb x -69915.551 4.028 8431.692 0.038 B- 7421.590 9.920 104 924942.564 4.324 + 21 63 42 105 Mo -77337.141 9.065 8494.923 0.086 B- 4952.947 35.031 104 916975.159 9.731 + 19 62 43 105 Tc -82290.088 35.264 8534.643 0.336 B- 3644.402 35.280 104 911657.952 37.857 + 17 61 44 105 Ru -85934.490 2.499 8561.900 0.024 B- 1916.752 2.851 104 907745.525 2.682 + 15 60 45 105 Rh -87851.243 2.502 8572.704 0.024 B- 566.646 2.346 104 905687.806 2.685 + 13 59 46 105 Pd -88417.888 1.138 8570.650 0.011 B- -1347.052 4.670 104 905079.487 1.222 + 11 58 47 105 Ag -87070.836 4.544 8550.370 0.043 B- -2736.997 4.362 104 906525.607 4.877 + 9 57 48 105 Cd -84333.839 1.392 8516.852 0.013 B- -4693.267 10.341 104 909463.895 1.494 + 7 56 49 105 In x -79640.572 10.246 8464.704 0.098 B- -6302.580 10.989 104 914502.324 11.000 + 5 55 50 105 Sn -73337.992 3.971 8397.228 0.038 B- -9322.510 22.185 104 921268.423 4.263 + 3 54 51 105 Sb +a -64015.482 21.827 8300.992 0.208 B- -11203.972 300.813 104 931276.549 23.431 + 1 53 52 105 Te -a -52811.510 300.020 8186.836 2.857 B- * 104 943304.508 322.084 +0 30 68 38 106 Sr x -34790# 600# 8119# 6# B- 11263# 783# 105 962651# 644# + 28 67 39 106 Y x -46053# 503# 8218# 5# B- 12497# 664# 105 950560# 540# + 26 66 40 106 Zr x -58549.987 433.145 8328.450 4.086 B- 7653.370 433.164 105 937144.000 465.000 + 24 65 41 106 Nb x -66203.357 4.122 8393.271 0.039 B- 9931.170 10.026 105 928927.768 4.424 + 22 64 42 106 Mo x -76134.528 9.140 8479.581 0.086 B- 3641.695 15.284 105 918266.218 9.812 + 20 63 43 106 Tc + -79776.223 12.250 8506.556 0.116 B- 6547.000 11.000 105 914356.697 13.150 + 18 62 44 106 Ru -86323.223 5.391 8560.940 0.051 B- 39.404 0.212 105 907328.203 5.787 + 16 61 45 106 Rh -86362.627 5.390 8553.931 0.051 B- 3544.901 5.335 105 907285.901 5.785 + 14 60 46 106 Pd -89907.527 1.106 8579.992 0.010 B- -2965.145 2.817 105 903480.293 1.186 + 12 59 47 106 Ag -86942.383 3.016 8544.639 0.028 B- 189.755 2.819 105 906663.507 3.237 + 10 58 48 106 Cd -87132.138 1.104 8539.048 0.010 B- -6524.004 12.176 105 906459.797 1.184 + 8 57 49 106 In - -80608.134 12.226 8470.120 0.115 B- -3254.447 13.244 105 913463.603 13.125 + 6 56 50 106 Sn -77353.687 5.091 8432.038 0.048 B- -10880.396 9.025 105 916957.396 5.465 + 4 55 51 106 Sb x -66473.292 7.452 8322.012 0.070 B- -8253.544 100.816 105 928637.982 8.000 + 2 54 52 106 Te -a -58219.748 100.541 8236.767 0.948 B- * 105 937498.526 107.934 +0 31 69 38 107 Sr x -28900# 700# 8064# 7# B- 13465# 862# 106 968975# 751# + 29 68 39 107 Y x -42364# 503# 8182# 5# B- 12015# 1230# 106 954520# 540# + 27 67 40 107 Zr x -54379.688 1122.450 8287.073 10.490 B- 9344.122 1122.479 106 941621.000 1205.000 + 25 66 41 107 Nb x -63723.810 8.023 8367.089 0.075 B- 8827.750 12.232 106 931589.672 8.612 + 23 65 42 107 Mo x -72551.560 9.233 8442.280 0.086 B- 6198.355 12.667 106 922112.692 9.912 + 21 64 43 107 Tc x -78749.914 8.673 8492.897 0.081 B- 5112.598 11.724 106 915458.485 9.310 + 19 63 44 107 Ru -nn -83862.512 8.673 8533.366 0.081 B- 3001.191 14.847 106 909969.885 9.310 + 17 62 45 107 Rh +p -86863.703 12.051 8554.103 0.113 B- 1508.936 12.111 106 906747.974 12.937 + 15 61 46 107 Pd -88372.639 1.201 8560.894 0.011 B- 34.031 2.318 106 905128.064 1.289 + 13 60 47 107 Ag -88406.670 2.382 8553.900 0.022 B- -1416.409 2.567 106 905091.531 2.557 + 11 59 48 107 Cd -86990.261 1.665 8533.351 0.016 B- -3426.000 11.000 106 906612.108 1.787 + 9 58 49 107 In - -83564.261 11.125 8494.021 0.104 B- -5052.033 12.327 106 910290.071 11.943 + 7 57 50 107 Sn x -78512.228 5.310 8439.494 0.050 B- -7858.989 6.738 106 915713.651 5.700 + 5 56 51 107 Sb -70653.239 4.148 8358.734 0.039 B- -10113.913 70.952 106 924150.624 4.452 + 3 55 52 107 Te -a -60539.326 70.830 8256.899 0.662 B- -11110# 308# 106 935008.356 76.039 + 1 54 53 107 I x -49430# 300# 8146# 3# B- * 106 946935# 322# +0 30 69 39 108 Y x -37297# 596# 8134# 6# B- 14056# 718# 107 959960# 640# + 28 68 40 108 Zr x -51353# 401# 8257# 4# B- 8193# 401# 107 944870# 430# + 26 67 41 108 Nb x -59545.765 8.237 8325.665 0.076 B- 11210.177 12.373 107 936074.988 8.842 + 24 66 42 108 Mo x -70755.942 9.233 8422.219 0.085 B- 5166.835 12.734 107 924040.367 9.912 + 22 65 43 108 Tc x -75922.778 8.769 8462.816 0.081 B- 7738.573 11.790 107 918493.541 9.413 + 20 64 44 108 Ru -3n -83661.350 8.680 8527.225 0.080 B- 1370.370 16.469 107 910185.841 9.318 + 18 63 45 108 Rh x -85031.721 13.996 8532.670 0.130 B- 4492.486 14.039 107 908714.688 15.024 + 16 62 46 108 Pd -89524.206 1.108 8567.023 0.010 B- -1917.444 2.633 107 903891.805 1.189 + 14 61 47 108 Ag -n -87606.763 2.388 8542.025 0.022 B- 1645.651 2.639 107 905950.266 2.563 + 12 60 48 108 Cd -89252.414 1.123 8550.019 0.010 B- -5132.595 8.584 107 904183.587 1.205 + 10 59 49 108 In -84119.819 8.641 8495.251 0.080 B- -2049.881 9.836 107 909693.655 9.276 + 8 58 50 108 Sn -82069.938 5.382 8469.027 0.050 B- -9624.607 7.692 107 911894.292 5.778 + 6 57 51 108 Sb x -72445.331 5.496 8372.666 0.051 B- -6663.664 7.712 107 922226.734 5.900 + 4 56 52 108 Te -65781.667 5.411 8303.721 0.050 B- -13132.062 132.370 107 929380.471 5.808 + 2 55 53 108 I -a -52649.605 132.260 8174.884 1.225 B- * 107 943478.321 141.986 +0 31 70 39 109 Y x -33200# 700# 8096# 6# B- 12992# 862# 108 964358# 751# + 29 69 40 109 Zr x -46193# 503# 8208# 5# B- 10497# 566# 108 950410# 540# + 27 68 41 109 Nb x -56689.794 258.490 8297.130 2.371 B- 9976.202 258.732 108 939141.000 277.500 + 25 67 42 109 Mo x -66665.996 11.188 8381.477 0.103 B- 7616.780 14.787 108 928431.106 12.010 + 23 66 43 109 Tc x -74282.775 9.669 8444.178 0.089 B- 6455.626 12.657 108 920254.156 10.380 + 21 65 44 109 Ru -4n -80738.401 8.954 8496.227 0.082 B- 4261.054 9.822 108 913323.756 9.612 + 19 64 45 109 Rh -84999.455 4.039 8528.142 0.037 B- 2607.021 4.187 108 908749.326 4.336 + 17 63 46 109 Pd -87606.476 1.114 8544.882 0.010 B- 1112.950 1.402 108 905950.574 1.195 + 15 62 47 109 Ag -88719.426 1.287 8547.915 0.012 B- -215.105 1.780 108 904755.773 1.381 + 13 61 48 109 Cd -88504.321 1.536 8538.764 0.014 B- -2014.809 4.066 108 904986.698 1.649 + 11 60 49 109 In -86489.511 3.969 8513.102 0.036 B- -3859.327 8.887 108 907149.685 4.261 + 9 59 50 109 Sn -82630.184 7.949 8470.518 0.073 B- -6379.206 8.807 108 911292.843 8.533 + 7 58 51 109 Sb -76250.977 5.265 8404.815 0.048 B- -8535.587 6.850 108 918141.204 5.652 + 5 57 52 109 Te -67715.390 4.382 8319.330 0.040 B- -10042.894 8.030 108 927304.534 4.704 + 3 56 53 109 I -p -57672.496 6.729 8220.016 0.062 B- -11502.948 300.183 108 938086.025 7.223 + 1 55 54 109 Xe -a -46169.548 300.108 8107.306 2.753 B- * 108 950434.948 322.178 +0 30 70 40 110 Zr x -42886# 596# 8177# 5# B- 9424# 1029# 109 953960# 640# + 28 69 41 110 Nb x -52309.909 838.345 8255.260 7.621 B- 12232.677 838.694 109 943843.000 900.000 + 26 68 42 110 Mo x -64542.585 24.223 8359.354 0.220 B- 6491.925 26.018 109 930710.680 26.004 + 24 67 43 110 Tc x -71034.510 9.497 8411.259 0.086 B- 9038.066 12.509 109 923741.312 10.195 + 22 66 44 110 Ru -80072.576 8.924 8486.311 0.081 B- 2756.110 19.404 109 914038.548 9.580 + 20 65 45 110 Rh -82828.686 17.805 8504.254 0.162 B- 5502.218 17.797 109 911079.742 19.114 + 18 64 46 110 Pd -88330.905 0.612 8547.162 0.006 B- -873.603 1.378 109 905172.868 0.657 + 16 63 47 110 Ag -87457.302 1.286 8532.108 0.012 B- 2890.667 1.277 109 906110.719 1.380 + 14 62 48 110 Cd -90347.969 0.380 8551.275 0.003 B- -3878.000 11.547 109 903007.460 0.407 + 12 61 49 110 In - -86469.969 11.553 8508.908 0.105 B- -627.985 17.980 109 907170.665 12.402 + 10 60 50 110 Sn x -85841.983 13.777 8496.087 0.125 B- -8392.250 15.012 109 907844.835 14.790 + 8 59 51 110 Sb x -77449.734 5.962 8412.681 0.054 B- -5219.923 8.875 109 916854.286 6.400 + 6 58 52 110 Te -72229.811 6.575 8358.115 0.060 B- -11765.635 50.978 109 922458.104 7.058 + 4 57 53 110 I -a -60464.176 50.552 8244.043 0.460 B- -8541.551 112.934 109 935089.033 54.270 + 2 56 54 110 Xe -a -51922.625 100.988 8159.280 0.918 B- * 109 944258.765 108.415 +0 31 71 40 111 Zr x -37560# 700# 8128# 6# B- 11316# 760# 110 959678# 751# + 29 70 41 111 Nb x -48875# 298# 8223# 3# B- 11064# 298# 110 947530# 320# + 27 69 42 111 Mo + -59939.761 12.578 8315.292 0.113 B- 9084.861 6.800 110 935652.016 13.502 + 25 68 43 111 Tc x -69024.622 10.581 8390.089 0.095 B- 7760.649 13.848 110 925899.016 11.359 + 23 67 44 111 Ru x -76785.271 9.682 8452.957 0.087 B- 5519.181 11.860 110 917567.616 10.394 + 21 66 45 111 Rh -82304.452 6.850 8495.631 0.062 B- 3681.435 6.887 110 911642.531 7.354 + 19 65 46 111 Pd -n -85985.888 0.731 8521.749 0.007 B- 2229.560 1.572 110 907690.347 0.785 + 17 64 47 111 Ag + -88215.447 1.459 8534.787 0.013 B- 1036.800 1.414 110 905296.816 1.565 + 15 63 48 111 Cd -89252.247 0.357 8537.079 0.003 B- -860.204 3.417 110 904183.766 0.383 + 13 62 49 111 In -88392.043 3.424 8522.282 0.031 B- -2453.456 6.337 110 905107.233 3.675 + 11 61 50 111 Sn +n -85938.587 5.336 8493.130 0.048 B- -5101.851 10.334 110 907741.126 5.728 + 9 60 51 111 Sb x -80836.736 8.849 8440.120 0.080 B- -7249.259 10.937 110 913218.189 9.500 + 7 59 52 111 Te x -73587.477 6.427 8367.763 0.058 B- -8633.692 7.994 110 921000.589 6.900 + 5 58 53 111 I -64953.785 4.754 8282.934 0.043 B- -10558.252 86.830 110 930269.239 5.103 + 3 57 54 111 Xe -a -54395.534 86.700 8180.766 0.781 B- -11575# 214# 110 941603.989 93.076 + 1 56 55 111 Cs x -42821# 196# 8069# 2# B- * 110 954030# 210# +0 32 72 40 112 Zr x -33810# 700# 8094# 6# B- 10463# 760# 111 963703# 751# + 30 71 41 112 Nb x -44274# 298# 8180# 3# B- 13190# 357# 111 952470# 320# + 28 70 42 112 Mo x -57464# 196# 8291# 2# B- 7795# 196# 111 938310# 210# + 26 69 43 112 Tc x -65258.938 5.515 8353.621 0.049 B- 10371.881 11.060 111 929941.644 5.920 + 24 68 44 112 Ru x -75630.818 9.599 8439.242 0.086 B- 4100.685 45.118 111 918806.972 10.305 + 22 67 45 112 Rh -79731.503 44.085 8468.870 0.394 B- 6590.059 43.927 111 914404.705 47.327 + 20 66 46 112 Pd -86321.562 6.544 8520.724 0.058 B- 262.156 6.978 111 907329.986 7.025 + 18 65 47 112 Ag x -86583.718 2.422 8516.080 0.022 B- 3991.141 2.435 111 907048.550 2.600 + 16 64 48 112 Cd -90574.859 0.250 8544.730 0.002 B- -2584.728 4.243 111 902763.883 0.268 + 14 63 49 112 In -87990.131 4.251 8514.667 0.038 B- 664.925 4.243 111 905538.704 4.563 + 12 62 50 112 Sn -88655.056 0.294 8513.618 0.003 B- -7056.091 17.832 111 904824.877 0.315 + 10 61 51 112 Sb x -81598.965 17.829 8443.632 0.159 B- -4031.457 19.702 111 912399.903 19.140 + 8 60 52 112 Te x -77567.508 8.383 8400.652 0.075 B- -10504.178 13.239 111 916727.850 9.000 + 6 59 53 112 I x -67063.330 10.246 8299.879 0.091 B- -7036.991 13.175 111 928004.550 11.000 + 4 58 54 112 Xe -a -60026.338 8.283 8230.064 0.074 B- -13736.062 87.190 111 935559.071 8.891 + 2 57 55 112 Cs -p -46290.277 86.796 8100.435 0.775 B- * 111 950305.341 93.178 +0 31 72 41 113 Nb x -40511# 401# 8146# 4# B- 11979# 500# 112 956510# 430# + 29 71 42 113 Mo x -52490# 300# 8245# 3# B- 10322# 300# 112 943650# 322# + 27 70 43 113 Tc x -62811.541 3.353 8329.464 0.030 B- 9056.578 37.028 112 932569.033 3.600 + 25 69 44 113 Ru -71868.119 36.875 8402.688 0.326 B- 6899.417 37.558 112 922846.396 39.587 + 23 68 45 113 Rh x -78767.536 7.130 8456.821 0.063 B- 4823.555 9.881 112 915439.567 7.653 + 21 67 46 113 Pd x -83591.092 6.945 8492.584 0.061 B- 3435.731 18.033 112 910261.267 7.455 + 19 66 47 113 Ag + -87026.822 16.643 8516.065 0.147 B- 2016.462 16.641 112 906572.858 17.866 + 17 65 48 113 Cd -89043.284 0.244 8526.987 0.002 B- 323.833 0.265 112 904408.097 0.262 + 15 64 49 113 In -89367.117 0.188 8522.929 0.002 B- -1038.985 1.573 112 904060.448 0.202 + 13 63 50 113 Sn -88328.132 1.575 8506.811 0.014 B- -3911.164 17.121 112 905175.845 1.690 + 11 62 51 113 Sb - -84416.968 17.193 8465.275 0.152 B- -6069.939 32.810 112 909374.652 18.457 + 9 61 52 113 Te x -78347.029 27.945 8404.636 0.247 B- -7227.522 29.070 112 915891.000 30.000 + 7 60 53 113 I x -71119.507 8.011 8333.752 0.071 B- -8915.889 10.533 112 923650.064 8.600 + 5 59 54 113 Xe -62203.618 6.840 8247.927 0.061 B- -10439.088 10.970 112 933221.666 7.342 + 3 58 55 113 Cs -p -51764.530 8.577 8148.622 0.076 B- -11980# 298# 112 944428.488 9.207 + 1 57 56 113 Ba x -39784# 298# 8036# 3# B- * 112 957290# 320# +0 32 73 41 114 Nb x -35387# 503# 8100# 4# B- 14420# 585# 113 962010# 540# + 30 72 42 114 Mo x -49807# 298# 8220# 3# B- 8793# 526# 113 946530# 320# + 28 71 43 114 Tc x -58600.288 433.145 8290.259 3.800 B- 11621.524 433.159 113 937090.000 465.000 + 26 70 44 114 Ru x -70221.811 3.550 8385.340 0.031 B- 5488.813 71.643 113 924613.780 3.811 + 24 69 45 114 Rh -75710.625 71.561 8426.624 0.628 B- 7780.319 71.891 113 918721.296 76.824 + 22 68 46 114 Pd x -83490.943 6.945 8488.010 0.061 B- 1439.856 8.311 113 910368.780 7.456 + 20 67 47 114 Ag x -84930.800 4.564 8493.778 0.040 B- 5084.133 4.573 113 908823.031 4.900 + 18 66 48 114 Cd -90014.932 0.276 8531.513 0.002 B- -1445.132 0.382 113 903364.990 0.296 + 16 65 49 114 In -88569.801 0.301 8511.973 0.003 B- 1989.923 0.302 113 904916.402 0.323 + 14 64 50 114 Sn -90559.723 0.029 8522.566 0.000 B- -6063.149 21.838 113 902780.132 0.031 + 12 63 51 114 Sb -84496.574 21.838 8462.518 0.192 B- -2608.005 35.466 113 909289.191 23.444 + 10 62 52 114 Te x -81888.569 27.945 8432.778 0.245 B- -9092# 152# 113 912089.000 30.000 + 8 61 53 114 I x -72796# 149# 8346# 1# B- -5710# 149# 113 921850# 160# + 6 60 54 114 Xe x -67085.890 11.178 8289.205 0.098 B- -12403.629 71.976 113 927980.331 12.000 + 4 59 55 114 Cs -a -54682.261 71.102 8173.538 0.624 B- -8776.835 124.892 113 941296.175 76.331 + 2 58 56 114 Ba -a -45905.426 102.676 8089.686 0.901 B- * 113 950718.495 110.227 +0 33 74 41 115 Nb x -31354# 503# 8065# 4# B- 13395# 643# 114 966340# 540# + 31 73 42 115 Mo x -44749# 401# 8175# 3# B- 11571# 885# 114 951960# 430# + 29 72 43 115 Tc x -56319.990 789.441 8268.527 6.865 B- 9869.744 794.386 114 939538.000 847.500 + 27 71 44 115 Ru x -66189.734 88.496 8347.547 0.770 B- 8040.097 88.790 114 928942.393 95.004 + 25 70 45 115 Rh x -74229.831 7.316 8410.658 0.064 B- 6196.554 15.350 114 920310.993 7.854 + 23 69 46 115 Pd -80426.386 13.546 8457.738 0.118 B- 4556.268 21.649 114 913658.718 14.541 + 21 68 47 115 Ag -84982.654 18.268 8490.555 0.159 B- 3101.825 18.274 114 908767.363 19.611 + 19 67 48 115 Cd -88084.479 0.651 8510.724 0.006 B- 1451.867 0.651 114 905437.417 0.699 + 17 66 49 115 In -89536.346 0.012 8516.546 0.000 B- 497.489 0.010 114 903878.773 0.012 + 15 65 50 115 Sn -90033.835 0.015 8514.069 0.000 B- -3030.432 16.025 114 903344.697 0.016 + 13 64 51 115 Sb x -87003.403 16.025 8480.915 0.139 B- -4940.644 32.214 114 906598.000 17.203 + 11 63 52 115 Te x -82062.759 27.945 8431.150 0.243 B- -5724.962 40.184 114 911902.000 30.000 + 9 62 53 115 I x -76337.797 28.876 8374.564 0.251 B- -7681.049 31.313 114 918048.000 31.000 + 7 61 54 115 Xe x -68656.748 12.109 8300.970 0.105 B- -8957# 103# 114 926293.945 13.000 + 5 60 55 115 Cs x -59699# 102# 8216# 1# B- -10680# 225# 114 935910# 110# + 3 59 56 115 Ba x -49020# 200# 8117# 2# B- * 114 947375# 215# +0 32 74 42 116 Mo x -41500# 500# 8146# 4# B- 9956# 582# 115 955448# 537# + 30 73 43 116 Tc x -51456# 298# 8225# 3# B- 12613# 298# 115 944760# 320# + 28 72 44 116 Ru x -64068.909 3.726 8326.883 0.032 B- 6667.213 73.926 115 931219.193 4.000 + 26 71 45 116 Rh -70736.122 73.832 8377.615 0.636 B- 9095.512 74.169 115 924061.645 79.261 + 24 70 46 116 Pd x -79831.635 7.132 8449.280 0.061 B- 2711.019 7.842 115 914297.210 7.656 + 22 69 47 116 Ag x -82542.653 3.260 8465.907 0.028 B- 6169.827 3.264 115 911386.812 3.500 + 20 68 48 116 Cd -88712.480 0.160 8512.350 0.001 B- -462.731 0.272 115 904763.230 0.172 + 18 67 49 116 In -n -88249.749 0.220 8501.617 0.002 B- 3276.221 0.240 115 905259.992 0.236 + 16 66 50 116 Sn -91525.970 0.096 8523.116 0.001 B- -4703.820 5.160 115 901742.824 0.103 + 14 65 51 116 Sb -86822.150 5.160 8475.821 0.044 B- -1553.189 28.417 115 906792.583 5.539 + 12 64 52 116 Te x -85268.961 27.945 8455.687 0.241 B- -7776.725 100.553 115 908460.000 30.000 + 10 63 53 116 I + -77492.236 96.592 8381.902 0.833 B- -4445.512 95.707 115 916808.658 103.695 + 8 62 54 116 Xe x -73046.724 13.041 8336.834 0.112 B- -11004# 101# 115 921581.112 14.000 + 6 61 55 116 Cs ea -62043# 100# 8235# 1# B- -7463# 224# 115 933395# 108# + 4 60 56 116 Ba x -54580# 200# 8164# 2# B- -13935# 371# 115 941406# 215# + 2 59 57 116 La -a -40645# 312# 8037# 3# B- * 115 956365# 335# +0 33 75 42 117 Mo x -36170# 500# 8100# 4# B- 12212# 641# 116 961170# 537# + 31 74 43 117 Tc x -48382# 401# 8197# 3# B- 11108# 590# 116 948060# 430# + 29 73 44 117 Ru x -59489.865 433.145 8285.562 3.702 B- 9407.508 433.236 116 936135.000 465.000 + 27 72 45 117 Rh x -68897.373 8.892 8359.281 0.076 B- 7527.104 11.411 116 926035.623 9.546 + 25 71 46 117 Pd -76424.477 7.252 8416.929 0.062 B- 5757.537 14.766 116 917954.944 7.785 + 23 70 47 117 Ag -82182.014 13.572 8459.452 0.116 B- 4236.375 13.610 116 911773.974 14.570 + 21 69 48 117 Cd -n -86418.389 1.013 8488.973 0.009 B- 2524.653 4.983 116 907226.038 1.087 + 19 68 49 117 In -88943.042 4.881 8503.865 0.042 B- 1454.709 4.857 116 904515.712 5.239 + 17 67 50 117 Sn -90397.751 0.483 8509.611 0.004 B- -1758.212 8.445 116 902954.017 0.518 + 15 66 51 117 Sb -88639.539 8.437 8487.897 0.072 B- -3544.128 13.079 116 904841.535 9.057 + 13 65 52 117 Te -85095.411 13.456 8450.919 0.115 B- -4659.334 28.673 116 908646.313 14.446 + 11 64 53 117 I -80436.077 26.196 8404.409 0.224 B- -6250.740 28.177 116 913648.314 28.123 + 9 63 54 117 Xe x -74185.337 10.378 8344.297 0.089 B- -7692.245 63.267 116 920358.760 11.141 + 7 62 55 117 Cs x -66493.092 62.410 8271.864 0.533 B- -9035.338 258.002 116 928616.726 67.000 + 5 61 56 117 Ba ep -57457.753 250.340 8187.953 2.140 B- -10987# 321# 116 938316.561 268.750 + 3 60 57 117 La -p -46471# 200# 8087# 2# B- * 116 950111# 215# +0 34 76 42 118 Mo x -32630# 500# 8069# 4# B- 11159# 641# 117 964970# 537# + 32 75 43 118 Tc x -43790# 401# 8157# 3# B- 13470# 448# 117 952990# 430# + 30 74 44 118 Ru x -57260# 200# 8265# 2# B- 7628# 202# 117 938529# 215# + 28 73 45 118 Rh x -64887.460 24.235 8322.858 0.205 B- 10501.286 24.342 117 930340.443 26.017 + 26 72 46 118 Pd -75388.746 2.491 8405.222 0.021 B- 4165.046 3.539 117 919066.847 2.673 + 24 71 47 118 Ag x -79553.792 2.515 8433.889 0.021 B- 7147.849 20.158 117 914595.487 2.700 + 22 70 48 118 Cd -nn -86701.641 20.001 8487.834 0.169 B- 526.570 21.450 117 906921.955 21.471 + 20 69 49 118 In -87228.211 7.752 8485.667 0.066 B- 4424.643 7.740 117 906356.659 8.322 + 18 68 50 118 Sn -91652.853 0.499 8516.533 0.004 B- -3656.640 2.975 117 901606.609 0.536 + 16 67 51 118 Sb - -87996.213 3.016 8478.915 0.026 B- -299.630 18.726 117 905532.174 3.238 + 14 66 52 118 Te +nn -87696.584 18.481 8469.746 0.157 B- -6725.536 27.056 117 905853.839 19.840 + 12 65 53 118 I x -80971.048 19.760 8406.120 0.167 B- -2891.991 22.320 117 913074.000 21.213 + 10 64 54 118 Xe x -78079.057 10.378 8374.981 0.088 B- -9669.689 16.442 117 916178.680 11.141 + 8 63 55 118 Cs IT -68409.367 12.753 8286.404 0.108 B- -6055# 196# 117 926559.519 13.690 + 6 62 56 118 Ba x -62354# 196# 8228# 2# B- -12794# 358# 117 933060# 210# + 4 61 57 118 La x -49560# 300# 8113# 3# B- * 117 946795# 322# +0 33 76 43 119 Tc x -40371# 503# 8128# 4# B- 12193# 585# 118 956660# 540# + 31 75 44 119 Ru x -52564# 298# 8224# 3# B- 10259# 298# 118 943570# 320# + 29 74 45 119 Rh x -62822.794 9.315 8303.394 0.078 B- 8585.108 12.440 118 932556.952 10.000 + 27 73 46 119 Pd x -71407.902 8.245 8368.964 0.069 B- 7237.863 16.855 118 923340.459 8.851 + 25 72 47 119 Ag -78645.765 14.703 8423.212 0.124 B- 5331.303 35.926 118 915570.293 15.783 + 23 71 48 119 Cd -83977.068 37.695 8461.438 0.317 B- 3722.212 38.088 118 909846.903 40.467 + 21 70 49 119 In -87699.281 7.307 8486.143 0.061 B- 2365.742 7.336 118 905850.944 7.844 + 19 69 50 119 Sn -90065.022 0.725 8499.449 0.006 B- -590.843 7.689 118 903311.216 0.778 + 17 68 51 119 Sb -89474.180 7.701 8487.910 0.065 B- -2293.000 2.000 118 903945.512 8.267 + 15 67 52 119 Te - -87181.180 7.957 8462.066 0.067 B- -3415.650 29.055 118 906407.148 8.541 + 13 66 53 119 I x -83765.530 27.945 8426.789 0.235 B- -4971.117 29.810 118 910074.000 30.000 + 11 65 54 119 Xe x -78794.413 10.378 8378.441 0.087 B- -6489.361 17.379 118 915410.713 11.141 + 9 64 55 119 Cs IT -72305.051 13.940 8317.334 0.117 B- -7714.965 200.754 118 922377.330 14.965 + 7 63 56 119 Ba ep -64590.086 200.269 8245.928 1.683 B- -9801# 361# 118 930659.686 214.997 + 5 62 57 119 La x -54790# 300# 8157# 3# B- -10849# 583# 118 941181# 322# + 3 61 58 119 Ce x -43940# 500# 8059# 4# B- * 118 952828# 537# +0 34 77 43 120 Tc x -35518# 503# 8087# 4# B- 14494# 643# 119 961870# 540# + 32 76 44 120 Ru x -50012# 401# 8201# 3# B- 8803# 446# 119 946310# 430# + 30 75 45 120 Rh x -58815# 196# 8268# 2# B- 11466# 196# 119 936860# 210# + 28 74 46 120 Pd -70280.050 2.291 8357.085 0.019 B- 5371.451 5.024 119 924551.258 2.459 + 26 73 47 120 Ag x -75651.502 4.471 8395.327 0.037 B- 8305.853 5.820 119 918784.767 4.800 + 24 72 48 120 Cd x -83957.354 3.726 8458.023 0.031 B- 1771.015 40.183 119 909868.067 4.000 + 22 71 49 120 In + -85728.369 40.010 8466.262 0.333 B- 5370.000 40.000 119 907966.805 42.952 + 20 70 50 120 Sn -91098.369 0.896 8504.492 0.007 B- -2680.608 7.140 119 902201.873 0.962 + 18 69 51 120 Sb - -88417.761 7.196 8475.635 0.060 B- 950.226 7.811 119 905079.624 7.725 + 16 68 52 120 Te -89367.987 3.085 8477.034 0.026 B- -5615.000 15.000 119 904059.514 3.311 + 14 67 53 120 I - -83752.987 15.314 8423.722 0.128 B- -1580.563 19.343 119 910087.465 16.440 + 12 66 54 120 Xe x -82172.423 11.817 8404.031 0.098 B- -8283.785 15.461 119 911784.270 12.686 + 10 65 55 120 Cs IT -73888.639 9.970 8328.480 0.083 B- -5000.000 300.000 119 920677.279 10.702 + 8 64 56 120 Ba - -68888.639 300.166 8280.294 2.501 B- -11319# 424# 119 926045.000 322.241 + 6 63 57 120 La x -57570# 300# 8179# 2# B- -7970# 583# 119 938196# 322# + 4 62 58 120 Ce x -49600# 500# 8107# 4# B- * 119 946752# 537# +0 35 78 43 121 Tc x -31780# 500# 8056# 4# B- 13267# 641# 120 965883# 537# + 33 77 44 121 Ru x -45047# 401# 8159# 3# B- 11203# 738# 120 951640# 430# + 31 76 45 121 Rh x -56250.128 619.444 8245.239 5.119 B- 9932.201 619.453 120 939613.000 665.000 + 29 75 46 121 Pd x -66182.329 3.353 8320.858 0.028 B- 8220.492 12.565 120 928950.343 3.600 + 27 74 47 121 Ag x -74402.821 12.109 8382.330 0.100 B- 6671.005 12.264 120 920125.282 13.000 + 25 73 48 121 Cd x -81073.826 1.942 8430.996 0.016 B- 4762.148 27.483 120 912963.663 2.085 + 23 72 49 121 In +p -85835.974 27.414 8463.887 0.227 B- 3361.291 27.408 120 907851.286 29.430 + 21 71 50 121 Sn -89197.265 0.955 8485.201 0.008 B- 403.057 2.690 120 904242.792 1.025 + 19 70 51 121 Sb -89600.321 2.582 8482.066 0.021 B- -1054.819 25.767 120 903810.093 2.771 + 17 69 52 121 Te -88545.502 25.850 8466.883 0.214 B- -2294.053 26.047 120 904942.488 27.751 + 15 68 53 121 I -86251.449 5.356 8441.458 0.044 B- -3770.463 11.558 120 907405.255 5.749 + 13 67 54 121 Xe -82480.986 10.243 8403.832 0.085 B- -5378.654 13.979 120 911453.014 10.995 + 11 66 55 121 Cs -77102.331 14.290 8352.914 0.118 B- -6357.495 141.176 120 917227.238 15.340 + 9 65 56 121 Ba - -70744.837 141.898 8293.907 1.173 B- -8555# 332# 120 924052.289 152.333 + 7 64 57 121 La x -62190# 300# 8217# 2# B- -9500# 500# 120 933236# 322# + 5 63 58 121 Ce x -52690# 401# 8132# 3# B- -11268# 641# 120 943435# 430# + 3 62 59 121 Pr -p -41422# 500# 8032# 4# B- * 120 955532# 537# +0 34 78 44 122 Ru x -42150# 500# 8135# 4# B- 9930# 583# 121 954750# 537# + 32 77 45 122 Rh x -52080# 300# 8210# 2# B- 12536# 301# 121 944090# 322# + 30 76 46 122 Pd x -64616.161 19.561 8305.975 0.160 B- 6489.948 42.909 121 930631.694 21.000 + 28 75 47 122 Ag x -71106.108 38.191 8352.758 0.313 B- 9506.265 38.260 121 923664.448 41.000 + 26 74 48 122 Cd -80612.374 2.299 8424.266 0.019 B- 2960.368 50.110 121 913459.052 2.468 + 24 73 49 122 In + -83572.741 50.057 8442.118 0.410 B- 6368.592 50.000 121 910280.966 53.738 + 22 72 50 122 Sn -89941.333 2.395 8487.907 0.020 B- -1605.963 3.384 121 903444.001 2.570 + 20 71 51 122 Sb -88335.370 2.578 8468.331 0.021 B- 1979.089 2.127 121 905168.074 2.768 + 18 70 52 122 Te -90314.460 1.507 8478.140 0.012 B- -4234.000 5.000 121 903043.434 1.617 + 16 69 53 122 I - -86080.460 5.222 8437.023 0.043 B- -725.483 12.277 121 907588.820 5.606 + 14 68 54 122 Xe x -85354.977 11.111 8424.664 0.091 B- -7210.218 35.472 121 908367.658 11.928 + 12 67 55 122 Cs -78144.759 33.687 8359.151 0.276 B- -3535.815 43.769 121 916108.145 36.164 + 10 66 56 122 Ba x -74608.944 27.945 8323.756 0.229 B- -10066# 299# 121 919904.000 30.000 + 8 65 57 122 La x -64543# 298# 8235# 2# B- -6669# 499# 121 930710# 320# + 6 64 58 122 Ce x -57874# 401# 8174# 3# B- -13094# 641# 121 937870# 430# + 4 63 59 122 Pr x -44780# 500# 8060# 4# B- * 121 951927# 537# +0 35 79 44 123 Ru x -37080# 500# 8093# 4# B- 12280# 640# 122 960193# 537# + 33 78 45 123 Rh x -49360# 400# 8186# 3# B- 11070# 885# 122 947010# 429# + 31 77 46 123 Pd x -60429.742 789.441 8270.031 6.418 B- 9118.336 790.039 122 935126.000 847.500 + 29 76 47 123 Ag x -69548.078 30.739 8337.803 0.250 B- 7866.103 30.857 122 925337.062 33.000 + 27 75 48 123 Cd -77414.181 2.696 8395.395 0.022 B- 6016.172 19.893 122 916892.453 2.894 + 25 74 49 123 In -83430.353 19.827 8437.946 0.161 B- 4385.828 19.839 122 910433.826 21.285 + 23 73 50 123 Sn -87816.181 2.416 8467.243 0.020 B- 1407.888 2.662 122 905725.446 2.594 + 21 72 51 123 Sb -89224.069 1.506 8472.328 0.012 B- -51.913 0.066 122 904214.016 1.616 + 19 71 52 123 Te -89172.156 1.505 8465.546 0.012 B- -1228.429 3.445 122 904269.747 1.615 + 17 70 53 123 I -87943.727 3.740 8449.198 0.030 B- -2695.027 9.690 122 905588.520 4.014 + 15 69 54 123 Xe -85248.701 9.537 8420.927 0.078 B- -4205.055 15.414 122 908481.750 10.238 + 13 68 55 123 Cs x -81043.646 12.109 8380.379 0.098 B- -5388.693 17.125 122 912996.062 13.000 + 11 67 56 123 Ba x -75654.953 12.109 8330.208 0.098 B- -7004# 196# 122 918781.062 13.000 + 9 66 57 123 La x -68651# 196# 8267# 2# B- -8365# 357# 122 926300# 210# + 7 65 58 123 Ce x -60286# 298# 8193# 2# B- -10056# 499# 122 935280# 320# + 5 64 59 123 Pr x -50230# 400# 8104# 3# B- * 122 946076# 429# +0 36 80 44 124 Ru x -33960# 600# 8068# 5# B- 10929# 721# 123 963542# 644# + 34 79 45 124 Rh x -44890# 400# 8149# 3# B- 13500# 499# 123 951809# 429# + 32 78 46 124 Pd x -58390# 298# 8252# 2# B- 7810# 390# 123 937316# 320# + 30 77 47 124 Ag x -66200.134 251.503 8308.655 2.028 B- 10501.538 251.521 123 928931.229 270.000 + 28 76 48 124 Cd -76701.672 2.995 8387.035 0.024 B- 4168.529 30.539 123 917657.363 3.215 + 26 75 49 124 In -80870.201 30.572 8414.343 0.247 B- 7363.992 30.576 123 913182.263 32.820 + 24 74 50 124 Sn -88234.193 1.014 8467.421 0.008 B- -613.944 1.513 123 905276.692 1.088 + 22 73 51 124 Sb -n -87620.248 1.507 8456.160 0.012 B- 2905.073 0.132 123 905935.789 1.618 + 20 72 52 124 Te -90525.321 1.502 8473.279 0.012 B- -3159.587 1.859 123 902817.064 1.612 + 18 71 53 124 I - -87365.734 2.390 8441.489 0.019 B- 295.686 2.846 123 906209.021 2.566 + 16 70 54 124 Xe -87661.421 1.793 8437.565 0.014 B- -5930.086 8.495 123 905891.588 1.924 + 14 69 55 124 Cs x -81731.334 8.304 8383.432 0.067 B- -2641.559 15.004 123 912257.798 8.914 + 12 68 56 124 Ba x -79089.775 12.497 8355.820 0.101 B- -8831.165 58.030 123 915093.629 13.416 + 10 67 57 124 La x -70258.610 56.669 8278.292 0.457 B- -5343# 303# 123 924574.275 60.836 + 8 66 58 124 Ce x -64916# 298# 8229# 2# B- -11765# 499# 123 930310# 320# + 6 65 59 124 Pr x -53151# 401# 8128# 3# B- -8626# 643# 123 942940# 430# + 4 64 60 124 Nd x -44525# 503# 8052# 4# B- * 123 952200# 540# +0 35 80 45 125 Rh x -42000# 500# 8126# 4# B- 12120# 640# 124 954911# 537# + 33 79 46 125 Pd x -54120# 400# 8216# 3# B- 10400# 589# 124 941900# 429# + 31 78 47 125 Ag x -64519.932 433.145 8293.314 3.465 B- 8828.163 433.154 124 930735.000 465.000 + 29 77 48 125 Cd -73348.095 2.885 8357.681 0.023 B- 7128.710 27.119 124 921257.577 3.097 + 27 76 49 125 In -80476.805 27.023 8408.452 0.216 B- 5419.571 27.011 124 913604.591 29.010 + 25 75 50 125 Sn -85896.376 1.033 8445.550 0.008 B- 2359.899 2.610 124 907786.442 1.109 + 23 74 51 125 Sb + -88256.274 2.599 8458.170 0.021 B- 766.700 2.121 124 905252.987 2.790 + 21 73 52 125 Te -89022.974 1.502 8458.045 0.012 B- -185.770 0.060 124 904429.900 1.612 + 19 72 53 125 I - -88837.204 1.504 8450.300 0.012 B- -1643.824 2.192 124 904629.333 1.614 + 17 71 54 125 Xe -87193.381 1.836 8430.890 0.015 B- -3105.430 7.831 124 906394.050 1.971 + 15 70 55 125 Cs -84087.950 7.744 8399.788 0.062 B- -4418.985 13.446 124 909727.867 8.313 + 13 69 56 125 Ba -79668.965 10.992 8358.178 0.088 B- -5909.481 27.631 124 914471.843 11.800 + 11 68 57 125 La -73759.484 25.997 8304.643 0.208 B- -7102# 197# 124 920815.932 27.909 + 9 67 58 125 Ce x -66658# 196# 8242# 2# B- -8718# 358# 124 928440# 210# + 7 66 59 125 Pr x -57940# 300# 8166# 2# B- -10341# 500# 124 937799# 322# + 5 65 60 125 Nd x -47599# 401# 8077# 3# B- * 124 948900# 430# +0 36 81 45 126 Rh x -37300# 500# 8088# 4# B- 14560# 640# 125 959957# 537# + 34 80 46 126 Pd x -51860# 400# 8197# 3# B- 8820# 447# 125 944326# 429# + 32 79 47 126 Ag x -60680# 200# 8261# 2# B- 11576# 200# 125 934857# 215# + 30 78 48 126 Cd -72256.802 2.476 8346.747 0.020 B- 5516.106 26.908 125 922429.127 2.658 + 28 77 49 126 In -77772.908 26.921 8384.317 0.214 B- 8242.332 27.078 125 916507.344 28.901 + 26 76 50 126 Sn -86015.240 10.447 8443.523 0.083 B- 378.000 30.000 125 907658.836 11.215 + 24 75 51 126 Sb - -86393.240 31.767 8440.314 0.252 B- 3672.108 31.787 125 907253.036 34.103 + 22 74 52 126 Te -90065.348 1.504 8463.248 0.012 B- -2154.031 3.677 125 903310.866 1.614 + 20 73 53 126 I -87911.318 3.809 8439.944 0.030 B- 1235.644 5.173 125 905623.313 4.089 + 18 72 54 126 Xe -89146.962 3.500 8443.541 0.028 B- -4796.133 10.671 125 904296.794 3.757 + 16 71 55 126 Cs -84350.829 10.401 8399.268 0.083 B- -1680.927 16.259 125 909445.655 11.166 + 14 70 56 126 Ba x -82669.902 12.497 8379.718 0.099 B- -7696.435 91.366 125 911250.204 13.416 + 12 69 57 126 La x -74973.468 90.508 8312.426 0.718 B- -4152.910 94.723 125 919512.667 97.163 + 10 68 58 126 Ce x -70820.558 27.945 8273.257 0.222 B- -10497# 198# 125 923971.000 30.000 + 8 67 59 126 Pr x -60324# 196# 8184# 2# B- -7331# 357# 125 935240# 210# + 6 66 60 126 Nd x -52993# 298# 8119# 2# B- -13643# 582# 125 943110# 320# + 4 65 61 126 Pm x -39350# 500# 8005# 4# B- * 125 957756# 537# +0 37 82 45 127 Rh x -34030# 600# 8062# 5# B- 13150# 781# 126 963467# 644# + 35 81 46 127 Pd x -47180# 500# 8159# 4# B- 11260# 539# 126 949350# 537# + 33 80 47 127 Ag x -58440# 200# 8242# 2# B- 10307# 201# 126 937262# 215# + 31 79 48 127 Cd x -68747.402 12.109 8316.945 0.095 B- 8148.782 24.378 126 926196.624 13.000 + 29 78 49 127 In -76896.184 21.157 8374.949 0.167 B- 6574.619 19.098 126 917448.546 22.713 + 27 77 50 127 Sn -83470.803 10.057 8420.557 0.079 B- 3228.674 10.875 126 910390.401 10.796 + 25 76 51 127 Sb -86699.477 5.126 8439.820 0.040 B- 1582.201 4.913 126 906924.277 5.502 + 23 75 52 127 Te -88281.678 1.514 8446.118 0.012 B- 702.231 3.575 126 905225.714 1.625 + 21 74 53 127 I -88983.909 3.647 8445.487 0.029 B- -662.349 2.044 126 904471.838 3.915 + 19 73 54 127 Xe -88321.560 4.110 8434.111 0.032 B- -2081.406 6.421 126 905182.899 4.412 + 17 72 55 127 Cs -86240.154 5.578 8411.562 0.044 B- -3422.210 12.653 126 907417.381 5.988 + 15 71 56 127 Ba -82817.944 11.357 8378.455 0.089 B- -4921.836 27.740 126 911091.275 12.192 + 13 70 57 127 La -77896.108 26.000 8333.540 0.205 B- -5916.772 38.857 126 916375.084 27.912 + 11 69 58 127 Ce x -71979.336 28.876 8280.791 0.227 B- -7436# 198# 126 922727.000 31.000 + 9 68 59 127 Pr x -64543# 196# 8216# 2# B- -9008# 357# 126 930710# 210# + 7 67 60 127 Nd x -55536# 298# 8139# 2# B- -10749# 499# 126 940380# 320# + 5 66 61 127 Pm x -44786# 401# 8048# 3# B- * 126 951920# 430# +0 36 82 46 128 Pd x -44490# 500# 8138# 4# B- 10130# 583# 127 952238# 537# + 34 81 47 128 Ag x -54620# 300# 8211# 2# B- 12622# 300# 127 941363# 322# + 32 80 48 128 Cd -67241.890 7.244 8303.264 0.057 B- 6904.051 153.554 127 927812.857 7.776 + 30 79 49 128 In -74145.941 153.479 8351.090 1.199 B- 9216.067 153.027 127 920401.053 164.766 + 28 78 50 128 Sn -83362.008 17.660 8416.979 0.138 B- 1268.278 13.796 127 910507.197 18.958 + 26 77 51 128 Sb IT -84630.286 19.119 8420.775 0.149 B- 4363.429 19.117 127 909145.645 20.525 + 24 76 52 128 Te -88993.716 0.866 8448.752 0.007 B- -1254.992 3.714 127 904461.311 0.929 + 22 75 53 128 I -87738.724 3.647 8432.836 0.028 B- 2121.575 3.748 127 905808.600 3.915 + 20 74 54 128 Xe -89860.298 1.061 8443.298 0.008 B- -3928.717 5.380 127 903530.996 1.138 + 18 73 55 128 Cs -85931.581 5.443 8406.493 0.043 B- -553.084 7.525 127 907748.648 5.843 + 16 72 56 128 Ba -85378.497 5.195 8396.060 0.041 B- -6753.066 54.695 127 908342.408 5.577 + 14 71 57 128 La x -78625.431 54.448 8337.190 0.425 B- -3091.513 61.200 127 915592.123 58.452 + 12 70 58 128 Ce x -75533.917 27.945 8306.925 0.218 B- -9203.161 40.859 127 918911.000 30.000 + 10 69 59 128 Pr x -66330.757 29.808 8228.913 0.233 B- -6017# 198# 127 928791.000 32.000 + 8 68 60 128 Nd x -60314# 196# 8176# 2# B- -12529# 357# 127 935250# 210# + 6 67 61 128 Pm x -47786# 298# 8072# 2# B- -9116# 582# 127 948700# 320# + 4 66 62 128 Sm x -38670# 500# 7994# 4# B- * 127 958486# 537# +0 37 83 46 129 Pd x -37610# 600# 8084# 5# B- 14370# 721# 128 959624# 644# + 35 82 47 129 Ag x -51980# 400# 8189# 3# B- 11078# 400# 128 944197# 429# + 33 81 48 129 Cd x -63058.046 16.767 8269.034 0.130 B- 9779.674 16.982 128 932304.399 18.000 + 31 80 49 129 In -72837.720 2.693 8338.780 0.021 B- 7753.183 17.302 128 921805.486 2.891 + 29 79 50 129 Sn -80590.903 17.277 8392.818 0.134 B- 4038.404 27.372 128 913482.102 18.547 + 27 78 51 129 Sb + -84629.307 21.231 8418.058 0.165 B- 2375.500 21.213 128 909146.696 22.792 + 25 77 52 129 Te -87004.807 0.869 8430.409 0.007 B- 1502.318 3.142 128 906596.492 0.933 + 23 76 53 129 I -88507.125 3.168 8435.990 0.025 B- 188.934 3.168 128 904983.687 3.401 + 21 75 54 129 Xe -88696.05896 0.00537 8431.390 0.000 B- -1196.813 4.555 128 904780.85892 0.00576 + 19 74 55 129 Cs -87499.246 4.555 8416.047 0.035 B- -2436.048 10.623 128 906065.690 4.889 + 17 73 56 129 Ba -85063.198 10.577 8391.098 0.082 B- -3738.625 21.639 128 908680.896 11.354 + 15 72 57 129 La -81324.573 21.351 8356.052 0.166 B- -5037.077 35.168 128 912694.475 22.920 + 13 71 58 129 Ce x -76287.496 27.945 8310.940 0.217 B- -6513.938 40.859 128 918102.000 30.000 + 11 70 59 129 Pr x -69773.558 29.808 8254.380 0.231 B- -7459# 204# 128 925095.000 32.000 + 9 69 60 129 Nd ep -62315# 202# 8190# 2# B- -9434# 360# 128 933102# 217# + 7 68 61 129 Pm x -52881# 298# 8111# 2# B- -10881# 582# 128 943230# 320# + 5 67 62 129 Sm x -42000# 500# 8021# 4# B- * 128 954911# 537# +0 36 83 47 130 Ag -nn -45697# 500# 8140# 4# B- 15420# 500# 129 950942# 537# + 34 82 48 130 Cd x -61117.589 22.356 8252.586 0.172 B- 8765.617 44.128 129 934387.566 24.000 + 32 81 49 130 In + -69883.206 38.046 8313.996 0.293 B- 10249.000 38.000 129 924977.288 40.844 + 30 80 50 130 Sn -80132.206 1.873 8386.816 0.014 B- 2153.470 14.113 129 913974.533 2.010 + 28 79 51 130 Sb -82285.676 14.212 8397.363 0.109 B- 5067.273 14.212 129 911662.688 15.257 + 26 78 52 130 Te -87352.949 0.011 8430.324 0.000 B- -416.811 3.168 129 906222.747 0.012 + 24 77 53 130 I -n -86936.138 3.168 8421.100 0.024 B- 2944.325 3.168 129 906670.211 3.401 + 22 76 54 130 Xe -89880.463 0.009 8437.731 0.000 B- -2980.720 8.357 129 903509.349 0.010 + 20 75 55 130 Cs -86899.743 8.357 8408.784 0.064 B- 361.801 8.738 129 906709.283 8.971 + 18 74 56 130 Ba -87261.544 2.553 8405.549 0.020 B- -5634.178 26.071 129 906320.874 2.741 + 16 73 57 130 La x -81627.366 25.946 8356.191 0.200 B- -2204.461 38.133 129 912369.413 27.854 + 14 72 58 130 Ce x -79422.905 27.945 8333.216 0.215 B- -8247.448 70.085 129 914736.000 30.000 + 12 71 59 130 Pr x -71175.457 64.273 8263.756 0.494 B- -4579.225 70.085 129 923590.000 69.000 + 10 70 60 130 Nd x -66596.232 27.945 8222.513 0.215 B- -11200# 198# 129 928506.000 30.000 + 8 69 61 130 Pm x -55396# 196# 8130# 2# B- -7890# 446# 129 940530# 210# + 6 68 62 130 Sm x -47506# 401# 8064# 3# B- -13823# 641# 129 949000# 430# + 4 67 63 130 Eu -p -33683# 500# 7951# 4# B- * 129 963840# 537# +0 37 84 47 131 Ag x -40380# 500# 8099# 4# B- 14839# 511# 130 956650# 537# + 35 83 48 131 Cd x -55218.965 102.464 8206.175 0.782 B- 12806.066 102.500 130 940720.000 110.000 + 33 82 49 131 In x -68025.030 2.701 8297.959 0.021 B- 9239.541 4.518 130 926972.122 2.900 + 31 81 50 131 Sn -77264.571 3.621 8362.517 0.028 B- 4716.830 3.962 130 917053.066 3.887 + 29 80 51 131 Sb -81981.401 2.084 8392.552 0.016 B- 3229.611 2.085 130 911989.341 2.236 + 27 79 52 131 Te -n -85211.012 0.061 8411.233 0.001 B- 2231.699 0.608 130 908522.211 0.065 + 25 78 53 131 I + -87442.710 0.605 8422.297 0.005 B- 970.848 0.605 130 906126.384 0.649 + 23 77 54 131 Xe -88413.558 0.009 8423.736 0.000 B- -354.772 4.974 130 905084.136 0.009 + 21 76 55 131 Cs -88058.786 4.974 8415.056 0.038 B- -1375.055 5.279 130 905464.999 5.340 + 19 75 56 131 Ba -86683.731 2.569 8398.587 0.020 B- -2914.475 28.063 130 906941.181 2.757 + 17 74 57 131 La x -83769.256 27.945 8370.367 0.213 B- -4060.816 43.092 130 910070.000 30.000 + 15 73 58 131 Ce -79708.440 32.802 8333.396 0.250 B- -5407.784 55.446 130 914429.465 35.214 + 13 72 59 131 Pr -74300.656 46.995 8286.143 0.359 B- -6532.623 53.081 130 920234.960 50.451 + 11 71 60 131 Nd -67768.033 27.517 8230.304 0.210 B- -8108# 202# 130 927248.020 29.541 + 9 70 61 131 Pm x -59660# 200# 8162# 2# B- -9527# 448# 130 935952# 215# + 7 69 62 131 Sm x -50133# 401# 8084# 3# B- -10863# 566# 130 946180# 430# + 5 68 63 131 Eu -p -39270# 401# 7995# 3# B- * 130 957842# 430# +0 38 85 47 132 Ag x -33790# 500# 8049# 4# B- 16473# 537# 131 963725# 537# + 36 84 48 132 Cd x -50263# 196# 8168# 1# B- 12148# 205# 131 946040# 210# + 34 83 49 132 In + -62411.542 60.033 8253.715 0.455 B- 14135.000 60.000 131 932998.449 64.447 + 32 82 50 132 Sn -76546.542 1.976 8354.872 0.015 B- 3088.729 3.161 131 917823.902 2.121 + 30 81 51 132 Sb -79635.271 2.467 8372.344 0.019 B- 5552.915 4.271 131 914508.015 2.648 + 28 80 52 132 Te -85188.186 3.486 8408.485 0.026 B- 515.304 3.483 131 908546.716 3.742 + 26 79 53 132 I -85703.490 4.065 8406.462 0.031 B- 3575.472 4.065 131 907993.514 4.364 + 24 78 54 132 Xe -89278.96179 0.00515 8427.622 0.000 B- -2126.280 1.036 131 904155.08697 0.00553 + 22 77 55 132 Cs -87152.681 1.036 8405.587 0.008 B- 1282.336 1.478 131 906437.743 1.112 + 20 76 56 132 Ba -88435.017 1.054 8409.375 0.008 B- -4711.367 36.354 131 905061.098 1.131 + 18 75 57 132 La -83723.650 36.359 8367.756 0.275 B- -1252.754 41.718 131 910118.959 39.032 + 16 74 58 132 Ce -82470.896 20.442 8352.338 0.155 B- -7243.440 35.380 131 911463.846 21.945 + 14 73 59 132 Pr x -75227.456 28.876 8291.537 0.219 B- -3801.648 37.679 131 919240.000 31.000 + 12 72 60 132 Nd x -71425.807 24.205 8256.810 0.183 B- -9798# 151# 131 923321.237 25.985 + 10 71 61 132 Pm x -61628# 149# 8177# 1# B- -6548# 333# 131 933840# 160# + 8 70 62 132 Sm x -55079# 298# 8121# 2# B- -12879# 499# 131 940870# 320# + 6 69 63 132 Eu x -42200# 400# 8018# 3# B- * 131 954696# 429# +0 37 85 48 133 Cd x -43920# 298# 8119# 2# B- 13544# 357# 132 952850# 320# + 35 84 49 133 In x -57464# 196# 8215# 1# B- 13410# 196# 132 938310# 210# + 33 83 50 133 Sn -70873.880 1.904 8310.088 0.014 B- 8049.623 3.662 132 923913.756 2.044 + 31 82 51 133 Sb -78923.503 3.128 8364.729 0.024 B- 4013.619 3.518 132 915272.130 3.357 + 29 81 52 133 Te -82937.122 2.066 8389.025 0.016 B- 2921.139 6.751 132 910963.332 2.218 + 27 80 53 133 I ++ -85858.260 6.427 8405.106 0.048 B- 1785.311 6.861 132 907827.361 6.900 + 25 79 54 133 Xe + -87643.571 2.400 8412.647 0.018 B- 427.360 2.400 132 905910.750 2.576 + 23 78 55 133 Cs -88070.931 0.008 8409.978 0.000 B- -517.319 0.992 132 905451.961 0.008 + 21 77 56 133 Ba -87553.613 0.992 8400.206 0.007 B- -2059.230 27.962 132 906007.325 1.065 + 19 76 57 133 La x -85494.383 27.945 8378.841 0.210 B- -3076.168 32.379 132 908218.000 30.000 + 17 75 58 133 Ce x -82418.214 16.354 8349.829 0.123 B- -4480.634 20.583 132 911520.402 17.557 + 15 74 59 133 Pr x -77937.581 12.497 8310.258 0.094 B- -5605.208 48.222 132 916330.561 13.416 + 13 73 60 133 Nd x -72332.372 46.575 8262.231 0.350 B- -6924.726 68.552 132 922348.000 50.000 + 11 72 61 133 Pm x -65407.646 50.301 8204.283 0.378 B- -8177# 302# 132 929782.000 54.000 + 9 71 62 133 Sm x -57231# 298# 8137# 2# B- -9995# 422# 132 938560# 320# + 7 70 63 133 Eu x -47236# 298# 8056# 2# B- -11376# 582# 132 949290# 320# + 5 69 64 133 Gd x -35860# 500# 7964# 4# B- * 132 961503# 537# +0 38 86 48 134 Cd x -38920# 400# 8082# 3# B- 12741# 499# 133 958218# 429# + 36 85 49 134 In x -51661# 298# 8171# 2# B- 14773# 298# 133 944540# 320# + 34 84 50 134 Sn x -66433.748 3.167 8275.171 0.024 B- 7586.794 3.597 133 928680.433 3.400 + 32 83 51 134 Sb x -74020.542 1.705 8325.950 0.013 B- 8513.200 3.233 133 920535.675 1.830 + 30 82 52 134 Te -82533.741 2.746 8383.643 0.020 B- 1509.687 4.933 133 911396.379 2.948 + 28 81 53 134 I -84043.429 4.857 8389.071 0.036 B- 4082.393 4.857 133 909775.663 5.213 + 26 80 54 134 Xe -88125.822 0.009 8413.699 0.000 B- -1234.667 0.018 133 905393.033 0.010 + 24 79 55 134 Cs -86891.154 0.016 8398.646 0.000 B- 2058.699 0.304 133 906718.503 0.017 + 22 78 56 134 Ba -88949.853 0.304 8408.171 0.002 B- -3731.204 19.932 133 904508.399 0.326 + 20 77 57 134 La x -85218.650 19.930 8374.488 0.149 B- -385.760 28.510 133 908514.011 21.395 + 18 76 58 134 Ce x -84832.889 20.387 8365.771 0.152 B- -6304.898 28.781 133 908928.142 21.886 + 16 75 59 134 Pr x -78527.991 20.316 8312.881 0.152 B- -2881.559 23.503 133 915696.729 21.810 + 14 74 60 134 Nd x -75646.432 11.817 8285.538 0.088 B- -8907.681 58.949 133 918790.210 12.686 + 12 73 61 134 Pm x -66738.751 57.753 8213.225 0.431 B- -5363# 204# 133 928353.000 62.000 + 10 72 62 134 Sm x -61376# 196# 8167# 1# B- -11448# 357# 133 934110# 210# + 8 71 63 134 Eu x -49928# 298# 8076# 2# B- -8626# 499# 133 946400# 320# + 6 70 64 134 Gd x -41302# 401# 8006# 3# B- * 133 955660# 430# +0 37 86 49 135 In x -46528# 401# 8132# 3# B- 14104# 401# 134 950050# 430# + 35 85 50 135 Sn x -60632.244 3.074 8230.687 0.023 B- 9058.079 4.052 134 934908.605 3.300 + 33 84 51 135 Sb -69690.323 2.640 8291.989 0.020 B- 8038.457 3.152 134 925184.357 2.834 + 31 83 52 135 Te -77728.780 1.722 8345.738 0.013 B- 6050.366 2.686 134 916554.718 1.848 + 29 82 53 135 I -83779.145 2.061 8384.760 0.015 B- 2634.005 3.868 134 910059.382 2.212 + 27 81 54 135 Xe -86413.151 3.720 8398.476 0.028 B- 1168.492 3.675 134 907231.661 3.993 + 25 80 55 135 Cs -87581.643 0.992 8401.336 0.007 B- 268.855 1.038 134 905977.234 1.064 + 23 79 56 135 Ba -87850.498 0.306 8397.533 0.002 B- -1207.181 9.430 134 905688.606 0.328 + 21 78 57 135 La -86643.317 9.434 8382.795 0.070 B- -2027.146 4.610 134 906984.568 10.127 + 19 77 58 135 Ce -84616.171 10.267 8361.984 0.076 B- -3680.310 15.655 134 909160.799 11.022 + 17 76 59 135 Pr x -80935.861 11.817 8328.928 0.088 B- -4722.252 22.484 134 913111.774 12.686 + 15 75 60 135 Nd x -76213.609 19.128 8288.153 0.142 B- -6161.534 77.838 134 918181.320 20.534 + 13 74 61 135 Pm x -70052.075 75.451 8236.717 0.559 B- -7194.860 172.054 134 924796.000 81.000 + 11 73 62 135 Sm x -62857.215 154.628 8177.626 1.145 B- -8709# 249# 134 932520.000 166.000 + 9 72 63 135 Eu x -54148# 196# 8107# 1# B- -9757# 445# 134 941870# 210# + 7 71 64 135 Gd x -44390# 400# 8029# 3# B- -11565# 566# 134 952345# 429# + 5 70 65 135 Tb -p -32825# 401# 7938# 3# B- * 134 964760# 430# +0 38 87 49 136 In x -40510# 400# 8087# 3# B- 15389# 499# 135 956511# 429# + 36 86 50 136 Sn x -55899# 298# 8195# 2# B- 8608# 298# 135 939990# 320# + 34 85 51 136 Sb -64506.880 5.830 8252.252 0.043 B- 9918.389 6.260 135 930749.011 6.258 + 32 84 52 136 Te -74425.269 2.281 8319.429 0.017 B- 5119.945 14.188 135 920101.182 2.448 + 30 83 53 136 I -79545.214 14.188 8351.323 0.104 B- 6883.945 14.188 135 914604.695 15.231 + 28 82 54 136 Xe -86429.159 0.007 8396.188 0.000 B- -90.462 1.882 135 907214.476 0.007 + 26 81 55 136 Cs + -86338.697 1.882 8389.770 0.014 B- 2548.224 1.857 135 907311.590 2.020 + 24 80 56 136 Ba -88886.921 0.306 8402.755 0.002 B- -2849.443 53.172 135 904575.959 0.328 + 22 79 57 136 La x -86037.479 53.171 8376.050 0.391 B- 470.893 53.173 135 907634.962 57.081 + 20 78 58 136 Ce -86508.372 0.408 8373.760 0.003 B- -5168.017 11.457 135 907129.438 0.438 + 18 77 59 136 Pr -81340.355 11.455 8330.008 0.084 B- -2141.068 16.458 135 912677.532 12.297 + 16 76 60 136 Nd x -79199.287 11.817 8308.512 0.087 B- -8029.371 70.076 135 914976.064 12.686 + 14 75 61 136 Pm x -71169.915 69.073 8243.720 0.508 B- -4359.026 70.194 135 923595.949 74.152 + 12 74 62 136 Sm x -66810.890 12.497 8205.916 0.092 B- -10567# 196# 135 928275.555 13.416 + 10 73 63 136 Eu x -56244# 196# 8122# 1# B- -7154# 357# 135 939620# 210# + 8 72 64 136 Gd x -49090# 298# 8064# 2# B- -12960# 582# 135 947300# 320# + 6 71 65 136 Tb x -36130# 500# 7963# 4# B- * 135 961213# 537# +0 39 88 49 137 In x -35040# 500# 8047# 4# B- 14748# 641# 136 962383# 537# + 37 87 50 137 Sn x -49788# 401# 8149# 3# B- 10272# 404# 136 946550# 430# + 35 86 51 137 Sb x -60060.384 52.164 8218.476 0.381 B- 9243.369 52.206 136 935522.522 56.000 + 33 85 52 137 Te -69303.753 2.100 8280.235 0.015 B- 7052.506 8.643 136 925599.357 2.254 + 31 84 53 137 I p-2n -76356.258 8.383 8326.002 0.061 B- 6027.145 8.384 136 918028.180 9.000 + 29 83 54 137 Xe -n -82383.404 0.103 8364.286 0.001 B- 4162.203 0.373 136 911557.773 0.111 + 27 82 55 137 Cs + -86545.606 0.358 8388.956 0.003 B- 1175.629 0.172 136 907089.464 0.384 + 25 81 56 137 Ba -87721.235 0.314 8391.827 0.002 B- -580.547 1.632 136 905827.375 0.337 + 23 80 57 137 La + -87140.688 1.659 8381.879 0.012 B- -1222.100 1.600 136 906450.618 1.780 + 21 79 58 137 Ce -85918.588 0.437 8367.248 0.003 B- -2716.895 8.133 136 907762.596 0.469 + 19 78 59 137 Pr -83201.693 8.137 8341.706 0.059 B- -3617.126 14.282 136 910679.304 8.735 + 17 77 60 137 Nd -79584.567 11.737 8309.593 0.086 B- -5511.719 17.545 136 914562.448 12.600 + 15 76 61 137 Pm x -74072.848 13.041 8263.651 0.095 B- -6046.323 44.355 136 920479.522 14.000 + 13 75 62 137 Sm -68026.525 42.395 8213.806 0.309 B- -7880.630 42.620 136 926970.517 45.512 + 11 74 63 137 Eu x -60145.895 4.378 8150.573 0.032 B- -8932# 298# 136 935430.722 4.700 + 9 73 64 137 Gd x -51214# 298# 8080# 2# B- -10246# 499# 136 945020# 320# + 7 72 65 137 Tb x -40967# 401# 7999# 3# B- * 136 956020# 430# +0 38 88 50 138 Sn x -44861# 503# 8113# 4# B- 9360# 1177# 137 951840# 540# + 36 87 51 138 Sb x -54220.403 1064.232 8175.091 7.712 B- 11475.582 1064.239 137 941792.000 1142.500 + 34 86 52 138 Te -65695.985 3.787 8252.578 0.027 B- 6283.914 7.063 137 929472.454 4.065 + 32 85 53 138 I x -71979.900 5.962 8292.444 0.043 B- 7992.334 6.588 137 922726.394 6.400 + 30 84 54 138 Xe -79972.233 2.804 8344.690 0.020 B- 2914.704 9.579 137 914146.271 3.010 + 28 83 55 138 Cs -82886.937 9.159 8360.142 0.066 B- 5374.700 9.159 137 911017.207 9.832 + 26 82 56 138 Ba -88261.638 0.317 8393.420 0.002 B- -1742.458 3.191 137 905247.229 0.339 + 24 81 57 138 La -86519.180 3.188 8375.125 0.023 B- 1051.742 4.038 137 907117.834 3.422 + 22 80 58 138 Ce -87570.922 4.931 8377.077 0.036 B- -4437.000 10.000 137 905988.743 5.293 + 20 79 59 138 Pr - -83133.922 11.150 8339.255 0.081 B- -1115.612 16.090 137 910752.059 11.969 + 18 78 60 138 Nd -82018.310 11.601 8325.502 0.084 B- -7077.827 28.756 137 911949.717 12.454 + 16 77 61 138 Pm -74940.483 27.739 8268.544 0.201 B- -3442.721 30.151 137 919548.077 29.778 + 14 76 62 138 Sm x -71497.762 11.817 8237.928 0.086 B- -9748.093 30.341 137 923243.990 12.686 + 12 75 63 138 Eu x -61749.669 27.945 8161.620 0.202 B- -5949# 198# 137 933709.000 30.000 + 10 74 64 138 Gd x -55800# 196# 8113# 1# B- -12132# 357# 137 940096# 210# + 8 73 65 138 Tb x -43668# 298# 8019# 2# B- -8737# 585# 137 953120# 320# + 6 72 66 138 Dy x -34931# 503# 7950# 4# B- * 137 962500# 540# +0 39 89 50 139 Sn x -38440# 500# 8066# 4# B- 11348# 641# 138 958733# 537# + 37 88 51 139 Sb x -49788# 401# 8142# 3# B- 10417# 401# 138 946550# 430# + 35 87 52 139 Te x -60205.072 3.540 8211.771 0.025 B- 8265.882 5.345 138 935367.193 3.800 + 33 86 53 139 I x -68470.954 4.005 8265.609 0.029 B- 7173.622 4.542 138 926493.403 4.300 + 31 85 54 139 Xe x -75644.576 2.142 8311.590 0.015 B- 5056.346 3.801 138 918792.203 2.300 + 29 84 55 139 Cs + -80700.921 3.140 8342.338 0.023 B- 4212.829 3.123 138 913363.992 3.370 + 27 83 56 139 Ba -84913.751 0.319 8367.017 0.002 B- 2312.461 2.013 138 908841.334 0.342 + 25 82 57 139 La -87226.212 2.009 8378.025 0.014 B- -278.350 6.953 138 906358.804 2.156 + 23 81 58 139 Ce -86947.862 7.230 8370.395 0.052 B- -2129.064 2.996 138 906657.625 7.761 + 21 80 59 139 Pr -84818.798 7.809 8349.449 0.056 B- -2804.856 28.033 138 908943.270 8.383 + 19 79 60 139 Nd -82013.942 27.600 8323.642 0.199 B- -4513.460 25.927 138 911954.407 29.630 + 17 78 61 139 Pm -77500.481 13.593 8285.543 0.098 B- -5120.263 17.414 138 916799.806 14.592 + 15 77 62 139 Sm x -72380.219 10.884 8243.078 0.078 B- -6982.177 17.071 138 922296.634 11.684 + 13 76 63 139 Eu x -65398.042 13.151 8187.218 0.095 B- -7767# 196# 138 929792.310 14.117 + 11 75 64 139 Gd x -57632# 196# 8126# 1# B- -9501# 357# 138 938130# 210# + 9 74 65 139 Tb x -48130# 298# 8052# 2# B- -10489# 585# 138 948330# 320# + 7 73 66 139 Dy x -37642# 503# 7971# 4# B- * 138 959590# 540# +0 38 89 51 140 Sb x -43939# 596# 8100# 4# B- 12638# 599# 139 952830# 640# + 36 88 52 140 Te x -56576.228 62.410 8184.847 0.446 B- 7029.985 63.574 139 939262.917 67.000 + 34 87 53 140 I x -63606.213 12.109 8229.473 0.086 B- 9380.238 12.331 139 931715.917 13.000 + 32 86 54 140 Xe x -72986.451 2.329 8290.887 0.017 B- 4063.654 8.525 139 921645.817 2.500 + 30 85 55 140 Cs -77050.105 8.201 8314.325 0.059 B- 6219.249 9.882 139 917283.305 8.804 + 28 84 56 140 Ba -83269.354 7.933 8353.160 0.057 B- 1046.517 7.993 139 910606.666 8.516 + 26 83 57 140 La -84315.871 2.009 8355.047 0.014 B- 3760.218 1.727 139 909483.184 2.156 + 24 82 58 140 Ce -88076.089 1.596 8376.317 0.011 B- -3388.000 6.000 139 905446.424 1.713 + 22 81 59 140 Pr - -84688.089 6.209 8346.529 0.044 B- -429.177 7.101 139 909083.592 6.665 + 20 80 60 140 Nd x -84258.912 3.447 8337.875 0.025 B- -6045.200 24.000 139 909544.332 3.700 + 18 79 61 140 Pm - -78213.712 24.246 8289.107 0.173 B- -2757.777 27.277 139 916034.122 26.029 + 16 78 62 140 Sm x -75455.935 12.497 8263.820 0.089 B- -8470.000 50.000 139 918994.717 13.416 + 14 77 63 140 Eu - -66985.935 51.538 8197.732 0.368 B- -5203.664 58.627 139 928087.637 55.328 + 12 76 64 140 Gd x -61782.271 27.945 8154.975 0.200 B- -11300.000 800.000 139 933674.000 30.000 + 10 75 65 140 Tb - -50482.271 800.488 8068.672 5.718 B- -7652# 895# 139 945805.049 859.359 + 8 74 66 140 Dy x -42830# 401# 8008# 3# B- -13571# 643# 139 954020# 430# + 6 73 67 140 Ho -p -29259# 503# 7906# 4# B- * 139 968589# 540# +0 39 90 51 141 Sb x -39110# 500# 8066# 4# B- 11377# 641# 140 958014# 537# + 37 89 52 141 Te x -50487# 401# 8141# 3# B- 9440# 401# 140 945800# 430# + 35 88 53 141 I x -59926.657 15.835 8202.255 0.112 B- 8270.642 16.097 140 935666.084 17.000 + 33 87 54 141 Xe x -68197.299 2.888 8255.364 0.020 B- 6280.224 9.638 140 926787.184 3.100 + 31 86 55 141 Cs -74477.523 9.195 8294.356 0.065 B- 5255.103 9.617 140 920045.086 9.871 + 29 85 56 141 Ba -79732.626 5.319 8326.078 0.038 B- 3199.010 6.600 140 914403.500 5.710 + 27 84 57 141 La -82931.636 4.219 8343.217 0.030 B- 2501.280 3.928 140 910969.222 4.528 + 25 83 58 141 Ce -85432.916 1.597 8355.408 0.011 B- 582.728 1.202 140 908283.987 1.714 + 23 82 59 141 Pr -86015.644 1.665 8353.992 0.012 B- -1823.014 2.809 140 907658.403 1.787 + 21 81 60 141 Nd - -84192.630 3.265 8335.515 0.023 B- -3669.709 14.349 140 909615.488 3.505 + 19 80 61 141 Pm x -80522.921 13.972 8303.940 0.099 B- -4589.012 16.375 140 913555.084 15.000 + 17 79 62 141 Sm -75933.909 8.539 8265.845 0.061 B- -6008.280 14.285 140 918481.591 9.167 + 15 78 63 141 Eu -69925.629 12.639 8217.684 0.090 B- -6701.405 23.456 140 924931.745 13.568 + 13 77 64 141 Gd x -63224.224 19.760 8164.608 0.140 B- -8683.387 107.098 140 932126.000 21.213 + 11 76 65 141 Tb x -54540.837 105.259 8097.475 0.747 B- -9158# 316# 140 941448.000 113.000 + 9 75 66 141 Dy x -45382# 298# 8027# 2# B- -11018# 499# 140 951280# 320# + 7 74 67 141 Ho -p -34364# 401# 7943# 3# B- * 140 963108# 430# +0 38 90 52 142 Te x -46370# 503# 8111# 4# B- 8400# 627# 141 950220# 540# + 36 89 53 142 I x -54769.984 374.461 8165.019 2.637 B- 10459.655 374.470 141 941202.000 402.000 + 34 88 54 142 Xe x -65229.639 2.701 8233.169 0.019 B- 5284.911 7.565 141 929973.098 2.900 + 32 87 55 142 Cs -70514.550 7.067 8264.877 0.050 B- 7327.714 8.363 141 924299.512 7.586 + 30 86 56 142 Ba -77842.264 5.920 8310.971 0.042 B- 2181.963 8.391 141 916432.888 6.355 + 28 85 57 142 La -80024.227 6.309 8320.828 0.044 B- 4508.961 5.845 141 914090.454 6.773 + 26 84 58 142 Ce -84533.188 2.509 8347.071 0.018 B- -745.712 2.500 141 909249.884 2.693 + 24 83 59 142 Pr -83787.476 1.665 8336.310 0.012 B- 2162.505 1.416 141 910050.440 1.786 + 22 82 60 142 Nd -85949.980 1.368 8346.030 0.010 B- -4807.936 23.629 141 907728.895 1.468 + 20 81 61 142 Pm -81142.044 23.597 8306.662 0.166 B- -2155.574 23.752 141 912890.428 25.332 + 18 80 62 142 Sm -78986.470 3.079 8285.972 0.022 B- -7673.000 30.000 141 915204.532 3.305 + 16 79 63 142 Eu - -71313.470 30.158 8226.427 0.212 B- -4353.955 41.114 141 923441.836 32.375 + 14 78 64 142 Gd x -66959.515 27.945 8190.256 0.197 B- -10400.000 700.000 141 928116.000 30.000 + 12 77 65 142 Tb - -56559.515 700.558 8111.507 4.934 B- -6440# 200# 141 939280.859 752.079 + 10 76 66 142 Dy - -50120# 729# 8061# 5# B- -12869# 831# 141 946194# 782# + 8 75 67 142 Ho x -37250# 401# 7965# 3# B- -9221# 641# 141 960010# 430# + 6 74 68 142 Er x -28030# 500# 7894# 4# B- * 141 969909# 537# +0 39 91 52 143 Te x -40278# 503# 8068# 4# B- 10353# 541# 142 956760# 540# + 37 90 53 143 I x -50630# 200# 8135# 1# B- 9572# 200# 142 945646# 215# + 35 89 54 143 Xe x -60202.873 4.657 8196.885 0.033 B- 7472.636 8.891 142 935369.553 5.000 + 33 88 55 143 Cs -67675.509 7.573 8243.670 0.053 B- 6261.688 9.730 142 927347.348 8.130 + 31 87 56 143 Ba -73937.197 6.756 8281.987 0.047 B- 4234.318 9.969 142 920625.150 7.253 + 29 86 57 143 La -78171.515 7.330 8306.127 0.051 B- 3435.156 7.595 142 916079.422 7.869 + 27 85 58 143 Ce -81606.671 2.508 8324.678 0.018 B- 1461.575 1.866 142 912391.630 2.692 + 25 84 59 143 Pr -83068.246 1.897 8329.428 0.013 B- 933.988 1.368 142 910822.564 2.037 + 23 83 60 143 Nd -84002.234 1.367 8330.488 0.010 B- -1041.583 2.682 142 909819.887 1.467 + 21 82 61 143 Pm -82960.651 2.996 8317.733 0.021 B- -3443.499 3.560 142 910938.073 3.216 + 19 81 62 143 Sm -79517.152 2.804 8288.182 0.020 B- -5275.851 11.338 142 914634.821 3.010 + 17 80 63 143 Eu x -74241.300 10.986 8245.817 0.077 B- -6010.000 200.000 142 920298.681 11.793 + 15 79 64 143 Gd - -68231.300 200.301 8198.318 1.401 B- -7812.117 206.750 142 926750.682 215.032 + 13 78 65 143 Tb x -60419.183 51.232 8138.217 0.358 B- -8250.242 52.866 142 935137.335 55.000 + 11 77 66 143 Dy x -52168.941 13.041 8075.052 0.091 B- -10121# 298# 142 943994.335 14.000 + 9 76 67 143 Ho x -42048# 298# 7999# 2# B- -10788# 499# 142 954860# 320# + 7 75 68 143 Er x -31260# 400# 7918# 3# B- * 142 966441# 429# +0 38 91 53 144 I x -45280# 401# 8098# 3# B- 11592# 401# 143 951390# 430# + 36 90 54 144 Xe x -56872.293 5.310 8172.884 0.037 B- 6399.060 20.820 143 938945.079 5.700 + 34 89 55 144 Cs -63271.353 20.132 8211.889 0.140 B- 8495.768 20.416 143 932075.404 21.612 + 32 88 56 144 Ba -71767.121 7.136 8265.454 0.050 B- 3082.530 14.774 143 922954.821 7.661 + 30 87 57 144 La x -74849.652 12.937 8281.428 0.090 B- 5582.219 13.254 143 919645.589 13.888 + 28 86 58 144 Ce + -80431.870 2.885 8314.760 0.020 B- 318.646 0.832 143 913652.830 3.096 + 26 85 59 144 Pr + -80750.517 2.762 8311.540 0.019 B- 2997.440 2.400 143 913310.750 2.965 + 24 84 60 144 Nd -83747.957 1.367 8326.922 0.009 B- -2331.863 2.646 143 910092.865 1.467 + 22 83 61 144 Pm -81416.093 2.964 8305.296 0.021 B- 549.442 2.668 143 912596.224 3.181 + 20 82 62 144 Sm -81965.535 1.554 8303.679 0.011 B- -6346.402 10.814 143 912006.373 1.668 + 18 81 63 144 Eu -75619.133 10.789 8254.173 0.075 B- -3859.630 29.955 143 918819.517 11.582 + 16 80 64 144 Gd x -71759.504 27.945 8221.937 0.194 B- -9391.323 39.520 143 922963.000 30.000 + 14 79 65 144 Tb x -62368.181 27.945 8151.287 0.194 B- -5798.098 28.851 143 933045.000 30.000 + 12 78 66 144 Dy x -56570.083 7.173 8105.589 0.050 B- -11960.569 11.104 143 939269.514 7.700 + 10 77 67 144 Ho x -44609.513 8.477 8017.097 0.059 B- -8002# 196# 143 952109.714 9.100 + 8 76 68 144 Er x -36608# 196# 7956# 1# B- -14349# 445# 143 960700# 210# + 6 75 69 144 Tm -p -22259# 400# 7851# 3# B- * 143 976104# 429# +0 39 92 53 145 I x -40939# 503# 8068# 3# B- 10554# 503# 144 956050# 540# + 37 91 54 145 Xe x -51493.329 11.178 8135.087 0.077 B- 8561.086 14.393 144 944719.634 12.000 + 35 90 55 145 Cs -60054.415 9.067 8188.733 0.063 B- 7461.761 12.412 144 935528.930 9.733 + 33 89 56 145 Ba x -67516.176 8.477 8234.798 0.058 B- 5319.141 14.912 144 927518.400 9.100 + 31 88 57 145 La -72835.317 12.269 8266.087 0.085 B- 4231.705 35.300 144 921808.066 13.170 + 29 87 58 145 Ce -77067.022 33.902 8289.875 0.234 B- 2558.918 33.635 144 917265.144 36.395 + 27 86 59 145 Pr -79625.940 7.169 8302.127 0.049 B- 1806.012 7.037 144 914518.033 7.696 + 25 85 60 145 Nd -81431.951 1.384 8309.187 0.010 B- -164.478 2.536 144 912579.199 1.485 + 23 84 61 145 Pm -81267.474 2.859 8302.657 0.020 B- -616.156 2.539 144 912755.773 3.068 + 21 83 62 145 Sm -80651.318 1.578 8293.013 0.011 B- -2659.810 2.723 144 913417.244 1.694 + 19 82 63 145 Eu -77991.507 3.106 8269.274 0.021 B- -5065.187 19.953 144 916272.668 3.334 + 17 81 64 145 Gd -72926.320 19.709 8228.946 0.136 B- -6537.909 108.066 144 921710.370 21.158 + 15 80 65 145 Tb -66388.411 109.174 8178.461 0.753 B- -8145.812 109.369 144 928729.105 117.203 + 13 79 66 145 Dy x -58242.599 6.520 8116.888 0.045 B- -9122.493 9.902 144 937473.994 7.000 + 11 78 67 145 Ho x -49120.105 7.452 8048.578 0.051 B- -9880# 200# 144 947267.394 8.000 + 9 77 68 145 Er x -39240# 200# 7975# 1# B- -11657# 280# 144 957874# 215# + 7 76 69 145 Tm -p -27583# 196# 7889# 1# B- * 144 970389# 210# +0 38 92 54 146 Xe x -47954.943 24.219 8110.415 0.166 B- 7355.429 24.391 145 948518.248 26.000 + 36 91 55 146 Cs x -55310.372 2.893 8155.436 0.020 B- 9636.714 21.063 145 940621.870 3.106 + 34 90 56 146 Ba -64947.086 20.863 8216.082 0.143 B- 4103.197 33.503 145 930276.431 22.397 + 32 89 57 146 La -69050.283 33.616 8238.828 0.230 B- 6585.107 34.456 145 925871.468 36.088 + 30 88 58 146 Ce -75635.389 16.306 8278.573 0.112 B- 1045.616 32.519 145 918802.065 17.504 + 28 87 59 146 Pr -76681.006 34.816 8280.376 0.238 B- 4244.861 34.830 145 917679.549 37.376 + 26 86 60 146 Nd -80925.867 1.386 8304.092 0.009 B- -1471.558 4.119 145 913122.503 1.488 + 24 85 61 146 Pm + -79454.309 4.308 8288.654 0.030 B- 1542.000 3.000 145 914702.286 4.624 + 22 84 62 146 Sm -80996.309 3.092 8293.857 0.021 B- -3878.768 5.869 145 913046.881 3.319 + 20 83 63 146 Eu -77117.541 6.026 8261.932 0.041 B- -1031.758 7.076 145 917210.909 6.468 + 18 82 64 146 Gd -76085.783 4.108 8249.506 0.028 B- -8322.173 44.749 145 918318.548 4.409 + 16 81 65 146 Tb -67763.610 44.862 8187.146 0.307 B- -5208.691 45.160 145 927252.768 48.161 + 14 80 66 146 Dy -62554.918 6.695 8146.112 0.046 B- -11316.699 9.392 145 932844.529 7.187 + 12 79 67 146 Ho -51238.219 6.587 8063.242 0.045 B- -6916.206 9.399 145 944993.506 7.071 + 10 78 68 146 Er -44322.012 6.705 8010.512 0.046 B- -13267# 200# 145 952418.359 7.197 + 8 77 69 146 Tm -p -31055# 200# 7914# 1# B- * 145 966661# 215# +0 39 93 54 147 Xe x -42360# 200# 8072# 1# B- 9560# 200# 146 954525# 215# + 37 92 55 147 Cs x -51920.064 8.383 8131.800 0.057 B- 8343.965 21.454 146 944261.515 9.000 + 35 91 56 147 Ba x -60264.029 19.748 8183.240 0.134 B- 6414.361 22.466 146 935303.900 21.200 + 33 90 57 147 La x -66678.390 10.712 8221.553 0.073 B- 5335.501 13.725 146 928417.800 11.500 + 31 89 58 147 Ce -72013.891 8.580 8252.527 0.058 B- 3430.176 15.533 146 922689.903 9.211 + 29 88 59 147 Pr -75444.067 15.857 8270.539 0.108 B- 2702.681 15.860 146 919007.458 17.023 + 27 87 60 147 Nd -78146.748 1.388 8283.603 0.009 B- 895.512 0.482 146 916106.010 1.490 + 25 86 61 147 Pm -79042.260 1.399 8284.372 0.010 B- 224.094 0.293 146 915144.638 1.501 + 23 85 62 147 Sm -79266.354 1.372 8280.575 0.009 B- -1721.598 2.281 146 914904.064 1.473 + 21 84 63 147 Eu -77544.756 2.630 8263.541 0.018 B- -2187.811 2.524 146 916752.276 2.823 + 19 83 64 147 Gd -75356.945 1.965 8243.336 0.013 B- -4614.280 8.147 146 919100.987 2.109 + 17 82 65 147 Tb -70742.665 8.100 8206.624 0.055 B- -6546.628 11.997 146 924054.620 8.695 + 15 81 66 147 Dy x -64196.038 8.849 8156.767 0.060 B- -8438.945 10.164 146 931082.715 9.500 + 13 80 67 147 Ho -55757.092 5.001 8094.037 0.034 B- -9149.286 38.517 146 940142.295 5.368 + 11 79 68 147 Er x -46607.807 38.191 8026.475 0.260 B- -10633.406 38.799 146 949964.458 41.000 + 9 78 69 147 Tm -35974.400 6.839 7948.817 0.047 B- * 146 961379.890 7.341 +0 40 94 54 148 Xe x -38600# 300# 8047# 2# B- 8311# 300# 147 958561# 322# + 38 93 55 148 Cs x -46910.942 13.041 8097.546 0.088 B- 10682.793 64.413 147 949639.029 14.000 + 36 92 56 148 Ba + -57593.735 63.079 8164.441 0.426 B- 5115.000 60.000 147 938170.578 67.718 + 34 91 57 148 La x -62708.735 19.468 8193.716 0.132 B- 7689.672 22.457 147 932679.400 20.900 + 32 90 58 148 Ce -70398.408 11.195 8240.387 0.076 B- 2137.016 12.567 147 924424.196 12.018 + 30 89 59 148 Pr -72535.424 15.043 8249.540 0.102 B- 4872.572 15.090 147 922130.015 16.148 + 28 88 60 148 Nd -77407.996 2.127 8277.177 0.014 B- -542.280 5.874 147 916899.093 2.283 + 26 87 61 148 Pm +p -76865.716 5.723 8268.226 0.039 B- 2470.548 5.642 147 917481.255 6.143 + 24 86 62 148 Sm -79336.264 1.367 8279.633 0.009 B- -3036.933 10.019 147 914829.012 1.467 + 22 85 63 148 Eu -76299.331 10.013 8253.827 0.068 B- -30.003 10.019 147 918089.294 10.748 + 20 84 64 148 Gd -76269.329 1.554 8248.338 0.011 B- -5732.246 12.529 147 918121.503 1.668 + 18 83 65 148 Tb -70537.082 12.464 8204.321 0.084 B- -2677.532 9.596 147 924275.323 13.380 + 16 82 66 148 Dy -67859.550 8.724 8180.943 0.059 B- -9868.393 84.287 147 927149.772 9.366 + 14 81 67 148 Ho x -57991.158 83.834 8108.979 0.566 B- -6512.169 84.458 147 937743.928 90.000 + 12 80 68 148 Er x -51478.989 10.246 8059.692 0.069 B- -12713.962 14.491 147 944735.029 11.000 + 10 79 69 148 Tm x -38765.027 10.246 7968.500 0.069 B- -8435# 400# 147 958384.029 11.000 + 8 78 70 148 Yb x -30330# 400# 7906# 3# B- * 147 967439# 429# +0 39 94 55 149 Cs x -43250# 400# 8073# 3# B- 9870# 593# 148 953569# 429# + 37 93 56 149 Ba x -53120.309 437.802 8133.793 2.938 B- 7099.605 481.431 148 942973.000 470.000 + 35 92 57 149 La + -60219.913 200.262 8176.191 1.344 B- 6450.000 200.000 148 935351.260 214.990 + 33 91 58 149 Ce x -66669.913 10.246 8214.229 0.069 B- 4369.452 14.230 148 928426.900 11.000 + 31 90 59 149 Pr x -71039.366 9.874 8238.303 0.066 B- 3336.100 10.101 148 923736.100 10.600 + 29 89 60 149 Nd -n -74375.466 2.128 8255.442 0.014 B- 1688.790 2.455 148 920154.648 2.284 + 27 88 61 149 Pm -76064.256 2.267 8261.526 0.015 B- 1071.481 1.875 148 918341.658 2.434 + 25 87 62 149 Sm -77135.737 1.311 8263.466 0.009 B- -694.625 3.788 148 917191.375 1.407 + 23 86 63 149 Eu -76441.112 3.951 8253.554 0.027 B- -1314.101 4.136 148 917937.086 4.241 + 21 85 64 149 Gd -75127.011 3.360 8239.484 0.023 B- -3638.343 4.339 148 919347.831 3.607 + 19 84 65 149 Tb -71488.669 3.667 8209.815 0.025 B- -3792.760 9.162 148 923253.753 3.936 + 17 83 66 149 Dy -67695.909 9.221 8179.109 0.062 B- -6049.330 12.803 148 927325.448 9.898 + 15 82 67 149 Ho -61646.578 11.990 8133.259 0.080 B- -7904.963 30.408 148 933819.672 12.871 + 13 81 68 149 Er x -53741.615 27.945 8074.955 0.188 B- -9859# 198# 148 942306.000 30.000 + 11 80 69 149 Tm x -43883# 196# 8004# 1# B- -10684# 358# 148 952890# 210# + 9 79 70 149 Yb x -33198# 300# 7927# 2# B- * 148 964360# 322# +0 40 95 55 150 Cs x -38170# 400# 8039# 3# B- 11730# 500# 149 959023# 429# + 38 94 56 150 Ba x -49900# 300# 8112# 2# B- 6230# 529# 149 946430# 322# + 36 93 57 150 La x -56129.966 435.473 8148.225 2.903 B- 8716.888 435.631 149 939742.000 467.500 + 34 92 58 150 Ce -64846.854 11.697 8201.122 0.078 B- 3453.625 14.291 149 930384.035 12.556 + 32 91 59 150 Pr -68300.479 9.015 8218.931 0.060 B- 5379.276 9.085 149 926676.415 9.678 + 30 90 60 150 Nd -73679.755 1.289 8249.577 0.009 B- -82.616 20.001 149 920901.525 1.384 + 28 89 61 150 Pm + -73597.139 20.041 8243.810 0.134 B- 3454.000 20.000 149 920990.217 21.514 + 26 88 62 150 Sm -77051.139 1.274 8261.621 0.009 B- -2258.905 6.181 149 917282.195 1.368 + 24 87 63 150 Eu -74792.234 6.253 8241.346 0.042 B- 971.700 3.543 149 919707.229 6.712 + 22 86 64 150 Gd -75763.934 6.076 8242.609 0.041 B- -4658.213 8.379 149 918664.066 6.523 + 20 85 65 150 Tb -71105.721 7.384 8206.338 0.049 B- -1796.122 8.389 149 923664.864 7.927 + 18 84 66 150 Dy -69309.600 4.348 8189.149 0.029 B- -7363.719 14.468 149 925593.080 4.667 + 16 83 67 150 Ho -61945.881 14.168 8134.842 0.094 B- -4114.568 13.591 149 933498.358 15.210 + 14 82 68 150 Er -57831.313 17.195 8102.195 0.115 B- -11340# 196# 149 937915.528 18.459 + 12 81 69 150 Tm x -46491# 196# 8021# 1# B- -7852# 358# 149 950090# 210# + 10 80 70 150 Yb x -38638# 300# 7964# 2# B- -13998# 424# 149 958520# 322# + 8 79 71 150 Lu -p -24640# 300# 7865# 2# B- * 149 973548# 322# +0 41 96 55 151 Cs x -34230# 500# 8013# 3# B- 10710# 640# 150 963253# 537# + 39 95 56 151 Ba x -44940# 400# 8079# 3# B- 8370# 591# 150 951755# 429# + 37 94 57 151 La x -53310.333 435.473 8129.043 2.884 B- 7914.718 435.833 150 942769.000 467.500 + 35 93 58 151 Ce x -61225.052 17.698 8176.277 0.117 B- 5554.578 21.189 150 934272.200 19.000 + 33 92 59 151 Pr -66779.630 11.651 8207.881 0.077 B- 4163.358 11.689 150 928309.114 12.507 + 31 91 60 151 Nd -70942.988 1.293 8230.272 0.009 B- 2443.075 4.473 150 923839.565 1.387 + 29 90 61 151 Pm -73386.063 4.653 8241.270 0.031 B- 1190.217 4.476 150 921216.817 4.994 + 27 89 62 151 Sm -74576.279 1.273 8243.971 0.008 B- 76.574 0.538 150 919939.066 1.367 + 25 88 63 151 Eu -74652.854 1.325 8239.297 0.009 B- -464.116 2.779 150 919856.860 1.422 + 23 87 64 151 Gd -74188.737 3.056 8231.043 0.020 B- -2565.233 3.762 150 920355.109 3.280 + 21 86 65 151 Tb -71623.504 4.137 8208.873 0.027 B- -2871.099 4.944 150 923109.001 4.441 + 19 85 66 151 Dy -a -68752.405 3.293 8184.678 0.022 B- -5129.667 8.756 150 926191.253 3.535 + 17 84 67 151 Ho -a -63622.738 8.302 8145.526 0.055 B- -5356.454 18.444 150 931698.177 8.912 + 15 83 68 151 Er x -58266.284 16.470 8104.872 0.109 B- -7493.528 25.460 150 937448.567 17.681 + 13 82 69 151 Tm +a -50772.756 19.416 8050.064 0.129 B- -9230.414 300.136 150 945493.201 20.843 + 11 81 70 151 Yb ep -41542.342 300.492 7983.755 1.990 B- -11434# 425# 150 955402.458 322.591 + 9 80 71 151 Lu -p -30108# 300# 7903# 2# B- * 150 967677# 322# +0 42 97 55 152 Cs x -28930# 500# 7979# 3# B- 12780# 640# 151 968942# 537# + 40 96 56 152 Ba x -41710# 400# 8057# 3# B- 7580# 500# 151 955222# 429# + 38 95 57 152 La x -49290# 300# 8102# 2# B- 9690# 361# 151 947085# 322# + 36 94 58 152 Ce x -58980# 200# 8161# 1# B- 4778# 201# 151 936682# 215# + 34 93 59 152 Pr x -63758.063 18.537 8187.104 0.122 B- 6391.344 30.710 151 931552.900 19.900 + 32 92 60 152 Nd -70149.407 24.485 8224.005 0.161 B- 1104.778 18.501 151 924691.509 26.285 + 30 91 61 152 Pm -71254.186 25.912 8226.127 0.170 B- 3508.417 25.886 151 923505.481 27.817 + 28 90 62 152 Sm -74762.603 1.212 8244.061 0.008 B- -1874.348 0.687 151 919739.040 1.301 + 26 89 63 152 Eu -72888.255 1.326 8226.583 0.009 B- 1818.661 0.702 151 921751.235 1.423 + 24 88 64 152 Gd -74706.916 1.206 8233.401 0.008 B- -3990.000 40.000 151 919798.822 1.294 + 22 87 65 152 Tb - -70716.916 40.018 8202.004 0.263 B- -599.044 40.258 151 924082.263 42.961 + 20 86 66 152 Dy -a -70117.873 4.624 8192.916 0.030 B- -6513.102 13.325 151 924725.363 4.963 + 18 85 67 152 Ho -63604.771 12.529 8144.919 0.082 B- -3104.394 9.815 151 931717.465 13.450 + 16 84 68 152 Er -60500.377 8.830 8119.349 0.058 B- -8780.104 54.743 151 935050.169 9.479 + 14 83 69 152 Tm -51720.273 54.027 8056.438 0.355 B- -5449.892 139.620 151 944476.000 58.000 + 12 82 70 152 Yb -46270.381 149.708 8015.436 0.985 B- -12848# 246# 151 950326.700 160.718 + 10 81 71 152 Lu x -33422# 196# 7926# 1# B- * 151 964120# 210# +0 41 97 56 153 Ba x -36470# 400# 8023# 3# B- 9590# 500# 152 960848# 429# + 39 96 57 153 La x -46060# 300# 8081# 2# B- 8850# 361# 152 950553# 322# + 37 95 58 153 Ce x -54910# 200# 8134# 1# B- 6659# 201# 152 941052# 215# + 35 94 59 153 Pr -61568.463 11.882 8172.036 0.078 B- 5761.834 12.190 152 933903.532 12.755 + 33 93 60 153 Nd -67330.297 2.747 8204.582 0.018 B- 3317.527 9.355 152 927717.949 2.948 + 31 92 61 153 Pm -70647.824 9.066 8221.152 0.059 B- 1911.862 9.093 152 924156.436 9.732 + 29 91 62 153 Sm -n -72559.686 1.219 8228.534 0.008 B- 807.536 0.708 152 922103.969 1.309 + 27 90 63 153 Eu -73367.222 1.330 8228.699 0.009 B- -484.671 0.717 152 921237.043 1.428 + 25 89 64 153 Gd -72882.551 1.203 8220.418 0.008 B- -1569.213 3.845 152 921757.359 1.291 + 23 88 65 153 Tb -71313.338 3.995 8205.048 0.026 B- -2170.394 1.933 152 923441.978 4.289 + 21 87 66 153 Dy -69142.943 4.048 8185.749 0.026 B- -4130.840 6.157 152 925771.992 4.346 + 19 86 67 153 Ho -a -65012.103 5.094 8153.637 0.033 B- -4543.499 9.916 152 930206.632 5.468 + 17 85 68 153 Er -60468.604 9.321 8118.827 0.061 B- -6495.276 12.891 152 935084.279 10.006 + 15 84 69 153 Tm -53973.329 11.983 8071.261 0.078 B- -6765# 196# 152 942057.244 12.864 + 13 83 70 153 Yb x -47208# 196# 8022# 1# B- -8835# 247# 152 949320# 210# + 11 82 71 153 Lu +a -38372.844 150.034 7959.070 0.981 B- -11073# 335# 152 958805.054 161.068 + 9 81 72 153 Hf x -27300# 300# 7882# 2# B- * 152 970692# 322# +0 42 98 56 154 Ba x -32820# 500# 8000# 3# B- 8709# 583# 153 964766# 537# + 40 97 57 154 La x -41530# 300# 8051# 2# B- 10690# 361# 153 955416# 322# + 38 96 58 154 Ce x -52220# 200# 8116# 1# B- 5885# 230# 153 943940# 215# + 36 95 59 154 Pr + -58104.976 113.009 8148.892 0.734 B- 7720.000 100.000 153 937621.738 121.320 + 34 94 60 154 Nd + -65824.976 52.642 8193.942 0.342 B- 2687.000 25.000 153 929333.977 56.513 + 32 93 61 154 Pm IT -68511.976 46.326 8206.310 0.301 B- 3943.200 46.303 153 926449.364 49.733 + 30 92 62 154 Sm -72455.176 1.462 8226.835 0.009 B- -717.056 1.103 153 922216.164 1.569 + 28 91 63 154 Eu -71738.121 1.346 8217.098 0.009 B- 1967.834 0.755 153 922985.955 1.444 + 26 90 64 154 Gd -73705.954 1.197 8224.796 0.008 B- -3549.651 45.298 153 920873.398 1.285 + 24 89 65 154 Tb - -70156.303 45.314 8196.666 0.294 B- 237.604 45.901 153 924684.106 48.646 + 22 88 66 154 Dy -70393.907 7.445 8193.129 0.048 B- -5754.596 10.178 153 924429.028 7.992 + 20 87 67 154 Ho -a -64639.311 8.228 8150.681 0.053 B- -2034.291 9.463 153 930606.841 8.833 + 18 86 68 154 Er -62605.020 4.986 8132.392 0.032 B- -8177.888 14.916 153 932790.743 5.353 + 16 85 69 154 Tm -a -54427.131 14.412 8074.208 0.094 B- -4495.048 13.953 153 941570.067 15.472 + 14 84 70 154 Yb -49932.083 17.281 8039.939 0.112 B- -10217# 197# 153 946395.701 18.552 + 12 83 71 154 Lu +a -39715# 196# 7969# 1# B- -7045# 358# 153 957364# 211# + 10 82 72 154 Hf x -32670# 300# 7918# 2# B- * 153 964927# 322# +0 41 98 57 155 La x -37930# 400# 8028# 3# B- 9850# 500# 154 959280# 429# + 39 97 58 155 Ce x -47780# 300# 8087# 2# B- 7635# 300# 154 948706# 322# + 37 96 59 155 Pr -55415.268 17.198 8131.039 0.111 B- 6868.456 19.472 154 940509.259 18.462 + 35 95 60 155 Nd -62283.724 9.153 8170.304 0.059 B- 4656.207 10.278 154 933135.668 9.826 + 33 94 61 155 Pm -66939.931 4.718 8195.296 0.030 B- 3250.888 4.946 154 928137.024 5.065 + 31 93 62 155 Sm -n -70190.819 1.487 8211.223 0.010 B- 1627.273 1.202 154 924647.051 1.595 + 29 92 63 155 Eu -71818.092 1.401 8216.674 0.009 B- 251.788 0.870 154 922900.102 1.504 + 27 91 64 155 Gd -72069.880 1.191 8213.251 0.008 B- -819.830 9.789 154 922629.796 1.278 + 25 90 65 155 Tb + -71250.050 9.849 8202.914 0.064 B- -2094.500 1.897 154 923509.921 10.573 + 23 89 66 155 Dy -69155.550 9.665 8184.354 0.062 B- -3116.011 16.590 154 925758.459 10.375 + 21 88 67 155 Ho -66039.539 17.474 8159.203 0.113 B- -3830.350 18.474 154 929103.634 18.759 + 19 87 68 155 Er -a -62209.189 6.098 8129.444 0.039 B- -5583.276 11.515 154 933215.684 6.546 + 17 86 69 155 Tm -a -56625.913 9.925 8088.375 0.064 B- -6123.305 19.341 154 939209.578 10.654 + 15 85 70 155 Yb -a -50502.608 16.600 8043.823 0.107 B- -7957.561 25.416 154 945783.217 17.820 + 13 84 71 155 Lu +a -42545.047 19.246 7987.436 0.124 B- -8375# 299# 154 954326.011 20.661 + 11 83 72 155 Hf x -34170# 298# 7928# 2# B- -10242# 423# 154 963317# 320# + 9 82 73 155 Ta -p -23928# 300# 7857# 2# B- * 154 974312# 322# +0 42 99 57 156 La x -33050# 400# 7997# 3# B- 11769# 500# 155 964519# 429# + 40 98 58 156 Ce x -44820# 300# 8068# 2# B- 6748# 361# 155 951884# 322# + 38 97 59 156 Pr x -51568# 200# 8106# 1# B- 8906# 283# 155 944640# 215# + 36 96 60 156 Nd + -60473.644 200.033 8158.066 1.282 B- 3690.000 200.000 155 935078.868 214.744 + 34 95 61 156 Pm -64163.644 3.631 8176.705 0.023 B- 5196.786 9.285 155 931117.490 3.897 + 32 94 62 156 Sm -69360.430 8.546 8205.003 0.055 B- 722.118 7.902 155 925538.511 9.174 + 30 93 63 156 Eu -70082.548 3.590 8204.617 0.023 B- 2452.366 3.409 155 924763.285 3.853 + 28 92 64 156 Gd -72534.914 1.190 8215.322 0.008 B- -2444.117 3.679 155 922130.562 1.277 + 26 91 65 156 Tb -70090.797 3.814 8194.639 0.024 B- 438.167 3.681 155 924754.430 4.094 + 24 90 66 156 Dy -70528.964 1.194 8192.433 0.008 B- -5050.000 60.000 155 924284.038 1.281 + 22 89 67 156 Ho - -65478.964 60.012 8155.046 0.385 B- -1267.255 64.869 155 929705.436 64.425 + 20 88 68 156 Er -64211.709 24.629 8141.908 0.158 B- -7377.159 26.710 155 931065.890 26.440 + 18 87 69 156 Tm -56834.550 14.279 8089.603 0.092 B- -3568.830 12.548 155 938985.597 15.328 + 16 86 70 156 Yb -53265.721 9.308 8061.711 0.060 B- -9566.176 54.916 155 942816.893 9.992 + 14 85 71 156 Lu -a -43699.544 54.122 7995.374 0.347 B- -5882.648 139.709 155 953086.606 58.102 + 12 84 72 156 Hf -37816.896 149.757 7952.650 0.960 B- -11956# 334# 155 959401.889 160.770 + 10 83 73 156 Ta -p -25861# 298# 7871# 2# B- * 155 972237# 320# +0 41 99 58 157 Ce x -39930# 400# 8037# 3# B- 8610# 500# 156 957133# 429# + 39 98 59 157 Pr x -48540# 300# 8086# 2# B- 7921# 301# 156 947890# 322# + 37 97 60 157 Nd -56461.543 24.918 8131.959 0.159 B- 5835.500 25.877 156 939386.037 26.750 + 35 96 61 157 Pm -62297.043 7.006 8164.145 0.045 B- 4380.534 8.265 156 933121.370 7.521 + 33 95 62 157 Sm -66677.577 4.433 8187.063 0.028 B- 2781.331 6.136 156 928418.673 4.759 + 31 94 63 157 Eu -69458.908 4.259 8199.795 0.027 B- 1364.565 4.203 156 925432.791 4.572 + 29 93 64 157 Gd -70823.473 1.189 8203.504 0.008 B- -60.043 0.297 156 923967.870 1.276 + 27 92 65 157 Tb -70763.430 1.222 8198.138 0.008 B- -1338.872 5.134 156 924032.328 1.311 + 25 91 66 157 Dy -69424.558 5.177 8184.627 0.033 B- -2591.725 23.787 156 925469.667 5.557 + 23 90 67 157 Ho -66832.832 23.469 8163.136 0.149 B- -3419.194 33.668 156 928251.999 25.195 + 21 89 68 157 Er -63413.639 26.505 8136.375 0.169 B- -4704.366 38.515 156 931922.655 28.454 + 19 88 69 157 Tm x -58709.273 27.945 8101.428 0.178 B- -5287.374 30.003 156 936973.000 30.000 + 17 87 70 157 Yb -53421.898 10.920 8062.767 0.070 B- -6981.376 14.241 156 942649.230 11.723 + 15 86 71 157 Lu -46440.523 12.078 8013.317 0.077 B- -7537# 196# 156 950144.045 12.965 + 13 85 72 157 Hf -a -38903# 196# 7960# 1# B- -9310# 247# 156 958236# 210# + 11 84 73 157 Ta IT -29593.330 150.069 7896.043 0.956 B- -10123# 427# 156 968230.251 161.105 + 9 83 74 157 W x -19470# 400# 7827# 3# B- * 156 979098# 429# +0 42 100 58 158 Ce x -36660# 400# 8016# 3# B- 7670# 500# 157 960644# 429# + 40 99 59 158 Pr x -44330# 300# 8060# 2# B- 9725# 361# 157 952410# 322# + 38 98 60 158 Nd x -54055# 200# 8116# 1# B- 5035# 201# 157 941970# 215# + 36 97 61 158 Pm -59089.209 13.453 8143.254 0.085 B- 6161.034 14.299 157 936565.121 14.442 + 34 96 62 158 Sm -65250.243 4.892 8177.297 0.031 B- 2004.945 10.369 157 929950.979 5.251 + 32 95 63 158 Eu -67255.188 10.255 8185.035 0.065 B- 3434.358 10.323 157 927798.581 11.008 + 30 94 64 158 Gd -70689.546 1.189 8201.819 0.008 B- -1218.878 0.987 157 924111.646 1.276 + 28 93 65 158 Tb -69470.668 1.401 8189.153 0.009 B- 936.681 2.495 157 925420.166 1.503 + 26 92 66 158 Dy -70407.349 2.365 8190.130 0.015 B- -4219.755 27.005 157 924414.597 2.538 + 24 91 67 158 Ho - -66187.593 27.108 8158.471 0.172 B- -883.785 37.025 157 928944.692 29.101 + 22 90 68 158 Er -65303.808 25.219 8147.926 0.160 B- -6600.615 31.341 157 929893.474 27.074 + 20 89 69 158 Tm -58703.194 25.219 8101.199 0.160 B- -2692.957 26.456 157 936979.525 27.074 + 18 88 70 158 Yb -56010.237 7.994 8079.203 0.051 B- -8798.047 16.872 157 939870.534 8.582 + 16 87 71 158 Lu -a -47212.190 15.125 8018.568 0.096 B- -5109.800 14.937 157 949315.626 16.237 + 14 86 72 158 Hf -42102.390 17.494 7981.276 0.111 B- -10936# 197# 157 954801.222 18.780 + 12 85 73 158 Ta +a -31167# 196# 7907# 1# B- -7534# 358# 157 966541# 210# + 10 84 74 158 W -a -23633# 300# 7854# 2# B- * 157 974629# 322# +0 41 100 59 159 Pr x -41088# 400# 8039# 3# B- 8719# 500# 158 955890# 429# + 39 99 60 159 Nd x -49807# 300# 8089# 2# B- 6747# 300# 158 946530# 322# + 37 98 61 159 Pm -56554.280 10.039 8126.859 0.063 B- 5653.495 11.644 158 939286.479 10.777 + 35 97 62 159 Sm -62207.775 5.934 8157.495 0.037 B- 3835.510 7.324 158 933217.202 6.369 + 33 96 63 159 Eu -66043.285 4.325 8176.697 0.027 B- 2518.150 4.391 158 929099.612 4.643 + 31 95 64 159 Gd -68561.436 1.192 8187.614 0.007 B- 970.927 0.759 158 926396.267 1.279 + 29 94 65 159 Tb -69532.363 1.256 8188.800 0.008 B- -365.229 1.162 158 925353.933 1.348 + 27 93 66 159 Dy -69167.134 1.528 8181.583 0.010 B- -1837.600 2.683 158 925746.023 1.640 + 25 92 67 159 Ho - -67329.534 3.088 8165.105 0.019 B- -2768.500 2.000 158 927718.768 3.314 + 23 91 68 159 Er - -64561.034 3.679 8142.773 0.023 B- -3990.637 28.186 158 930690.875 3.949 + 21 90 69 159 Tm x -60570.398 27.945 8112.754 0.176 B- -4731.792 33.129 158 934975.000 30.000 + 19 89 70 159 Yb x -55838.606 17.794 8078.074 0.112 B- -6130.002 41.655 158 940054.787 19.102 + 17 88 71 159 Lu x -49708.604 37.663 8034.600 0.237 B- -6856.004 41.246 158 946635.615 40.433 + 15 87 72 159 Hf -a -42852.600 16.813 7986.560 0.106 B- -8413.452 25.891 158 953995.838 18.049 + 13 86 73 159 Ta IT -34439.148 19.689 7928.725 0.124 B- -9145# 299# 158 963028.052 21.137 + 11 85 74 159 W -a -25295# 298# 7866# 2# B- -10550# 426# 158 972845# 320# + 9 84 75 159 Re IT -14745# 305# 7795# 2# B- * 158 984171# 327# +0 42 101 59 160 Pr x -36520# 400# 8011# 2# B- 10613# 500# 159 960794# 429# + 40 100 60 160 Nd x -47134# 300# 8073# 2# B- 5868# 361# 159 949400# 322# + 38 99 61 160 Pm x -53002# 200# 8104# 1# B- 7233# 200# 159 943100# 215# + 36 98 62 160 Sm -60234.793 5.934 8144.625 0.037 B- 3245.670 11.183 159 935335.286 6.370 + 34 97 63 160 Eu -63480.463 9.501 8160.021 0.059 B- 4461.278 9.586 159 931850.916 10.199 + 32 96 64 160 Gd -67941.741 1.278 8183.014 0.008 B- -105.483 1.022 159 927061.537 1.371 + 30 95 65 160 Tb -67836.257 1.262 8177.465 0.008 B- 1836.472 1.172 159 927174.778 1.354 + 28 94 66 160 Dy -69672.730 0.772 8184.054 0.005 B- -3290.000 15.000 159 925203.244 0.828 + 26 93 67 160 Ho - -66382.730 15.020 8158.602 0.094 B- -318.502 28.528 159 928735.204 16.124 + 24 92 68 160 Er -66064.228 24.254 8151.721 0.152 B- -5762.200 40.311 159 929077.130 26.037 + 22 91 69 160 Tm -60302.028 34.262 8110.818 0.214 B- -2139.322 35.017 159 935263.106 36.781 + 20 90 70 160 Yb -58162.706 7.233 8092.557 0.045 B- -7892.769 57.280 159 937559.763 7.764 + 18 89 71 160 Lu x -50269.937 56.821 8038.338 0.355 B- -4330.994 57.617 159 946033.000 61.000 + 16 88 72 160 Hf -45938.943 9.541 8006.380 0.060 B- -10115.249 55.147 159 950682.513 10.242 + 14 87 73 160 Ta -a -35823.695 54.316 7938.270 0.339 B- -6497.240 139.859 159 961541.679 58.310 + 12 86 74 160 W -29326.455 149.827 7892.772 0.936 B- -12588# 334# 159 968516.753 160.846 + 10 85 75 160 Re -a -16739# 298# 7809# 2# B- * 159 982030# 320# +0 41 101 60 161 Nd x -42588# 400# 8044# 2# B- 7648# 499# 160 954280# 429# + 39 100 61 161 Pm x -50235# 298# 8087# 2# B- 6436# 298# 160 946070# 320# + 37 99 62 161 Sm -56671.962 6.817 8122.041 0.042 B- 5119.562 12.415 160 939160.143 7.318 + 35 98 63 161 Eu -61791.524 10.399 8148.980 0.065 B- 3714.299 10.525 160 933664.066 11.164 + 33 97 64 161 Gd -n -65505.824 1.622 8167.191 0.010 B- 1955.765 1.442 160 929676.602 1.741 + 31 96 65 161 Tb -67461.589 1.350 8174.479 0.008 B- 594.212 1.260 160 927577.001 1.449 + 29 95 66 161 Dy -68055.801 0.768 8173.310 0.005 B- -858.530 2.166 160 926939.088 0.824 + 27 94 67 161 Ho -67197.270 2.242 8163.119 0.014 B- -1995.663 9.011 160 927860.759 2.406 + 25 93 68 161 Er +n -65201.608 8.780 8145.864 0.055 B- -3302.900 29.292 160 930003.191 9.425 + 23 92 69 161 Tm x -61898.708 27.945 8120.490 0.174 B- -4059.308 31.885 160 933549.000 30.000 + 21 91 70 161 Yb x -57839.400 15.354 8090.417 0.095 B- -5277.056 31.885 160 937906.846 16.483 + 19 90 71 161 Lu x -52562.344 27.945 8052.781 0.174 B- -6247.672 35.909 160 943572.000 30.000 + 17 89 72 161 Hf -46314.672 22.551 8009.117 0.140 B- -7535.674 33.097 160 950279.151 24.209 + 15 88 73 161 Ta +a -38778.997 24.382 7957.452 0.151 B- -8224# 197# 160 958369.031 26.175 + 13 87 74 161 W -a -30555# 196# 7902# 1# B- -9715# 247# 160 967197# 210# + 11 86 75 161 Re -20840.203 149.922 7836.312 0.931 B- -10861# 427# 160 977627.121 160.948 + 9 85 76 161 Os -a -9979# 400# 7764# 2# B- * 160 989287# 429# +0 42 102 60 162 Nd x -39550# 400# 8026# 2# B- 6819# 500# 161 957541# 429# + 40 101 61 162 Pm x -46370# 300# 8063# 2# B- 8160# 358# 161 950220# 322# + 38 100 62 162 Sm x -54530# 196# 8109# 1# B- 4174# 199# 161 941460# 210# + 36 99 63 162 Eu + -58703.401 35.229 8129.438 0.217 B- 5577.000 35.000 161 936979.303 37.819 + 34 98 64 162 Gd -nn -64280.401 4.009 8159.035 0.025 B- 1395.556 36.581 161 930992.146 4.303 + 32 97 65 162 Tb + -65675.958 36.372 8162.820 0.225 B- 2505.521 36.364 161 929493.955 39.046 + 30 96 66 162 Dy -68181.478 0.767 8173.457 0.005 B- -2139.937 3.113 161 926804.168 0.822 + 28 95 67 162 Ho -66041.541 3.166 8155.418 0.020 B- 292.978 3.127 161 929101.485 3.398 + 26 94 68 162 Er -66334.519 0.822 8152.397 0.005 B- -4856.728 26.047 161 928786.960 0.882 + 24 93 69 162 Tm - -61477.791 26.060 8117.588 0.161 B- -1651.444 30.240 161 934000.872 27.977 + 22 92 70 162 Yb x -59826.347 15.359 8102.565 0.095 B- -6994.593 76.592 161 935773.771 16.488 + 20 91 71 162 Lu x -52831.753 75.036 8054.559 0.463 B- -3662.746 75.570 161 943282.776 80.554 + 18 90 72 162 Hf -49169.008 8.968 8027.120 0.055 B- -9388.814 52.931 161 947214.896 9.627 + 16 89 73 162 Ta -a -39780.194 52.238 7964.335 0.322 B- -5780.987 52.239 161 957294.202 56.079 + 14 88 74 162 W -33999.207 17.658 7923.821 0.109 B- -11498# 197# 161 963500.347 18.956 + 12 87 75 162 Re +a -22501# 196# 7848# 1# B- -8061# 358# 161 975844# 210# + 10 86 76 162 Os -a -14440# 300# 7793# 2# B- * 161 984498# 322# +0 41 102 61 163 Pm x -43249# 400# 8044# 2# B- 7471# 499# 162 953570# 429# + 39 101 62 163 Sm x -50720# 298# 8085# 2# B- 5765# 305# 162 945550# 320# + 37 100 63 163 Eu + -56484.886 65.544 8115.471 0.402 B- 4829.000 65.000 162 939360.977 70.364 + 35 99 64 163 Gd -61313.886 8.426 8140.297 0.052 B- 3282.185 9.358 162 934176.832 9.045 + 33 98 65 163 Tb +p -64596.071 4.073 8155.633 0.025 B- 1785.099 4.001 162 930653.261 4.372 + 31 97 66 163 Dy -66381.170 0.765 8161.785 0.005 B- -2.834 0.019 162 928736.879 0.821 + 29 96 67 163 Ho -66378.335 0.765 8156.968 0.005 B- -1210.612 4.575 162 928739.921 0.821 + 27 95 68 163 Er -65167.723 4.639 8144.741 0.028 B- -2439.000 3.000 162 930039.567 4.980 + 25 94 69 163 Tm - -62728.723 5.524 8124.979 0.034 B- -3429.629 16.309 162 932657.941 5.930 + 23 93 70 163 Yb x -59299.094 15.364 8099.138 0.094 B- -4507.685 31.890 162 936339.800 16.493 + 21 92 71 163 Lu x -54791.409 27.945 8066.684 0.171 B- -5527.726 37.348 162 941179.000 30.000 + 19 91 72 163 Hf -49263.682 24.778 8027.972 0.152 B- -6729.054 45.416 162 947113.258 26.599 + 17 90 73 163 Ta -a -42534.629 38.061 7981.890 0.234 B- -7626.436 65.049 162 954337.195 40.860 + 15 89 74 163 W -a -34908.193 52.751 7930.302 0.324 B- -8905.949 55.912 162 962524.511 56.630 + 13 88 75 163 Re +a -26002.244 18.534 7870.865 0.114 B- -9810# 299# 162 972085.441 19.897 + 11 87 76 163 Os -a -16192# 298# 7806# 2# B- * 162 982617# 320# +0 42 103 61 164 Pm x -38870# 400# 8017# 2# B- 9232# 499# 163 958271# 429# + 40 102 62 164 Sm x -48102# 298# 8069# 2# B- 5279# 319# 163 948360# 320# + 38 101 63 164 Eu + -53381# 114# 8096# 1# B- 6393.000 50.000 163 942693# 122# + 36 100 64 164 Gd x -59774# 102# 8130# 1# B- 2304# 143# 163 935830# 110# + 34 99 65 164 Tb + -62077.965 100.003 8139.765 0.610 B- 3890.000 100.000 163 933356.559 107.357 + 32 98 66 164 Dy -65967.965 0.767 8158.714 0.005 B- -986.463 1.415 163 929180.472 0.823 + 30 97 67 164 Ho -64981.503 1.528 8147.929 0.009 B- 961.387 1.420 163 930239.483 1.639 + 28 96 68 164 Er -65942.890 0.775 8149.020 0.005 B- -4038.855 24.401 163 929207.392 0.832 + 26 95 69 164 Tm -61904.035 24.394 8119.623 0.149 B- -886.617 28.829 163 933543.281 26.188 + 24 94 70 164 Yb x -61017.418 15.369 8109.446 0.094 B- -6375.048 31.892 163 934495.103 16.499 + 22 93 71 164 Lu x -54642.370 27.945 8065.804 0.170 B- -2823.865 32.112 163 941339.000 30.000 + 20 92 72 164 Hf -51818.505 15.820 8043.814 0.096 B- -8535.704 32.112 163 944370.544 16.983 + 18 91 73 164 Ta x -43282.800 27.945 7986.997 0.170 B- -5047.041 29.572 163 953534.000 30.000 + 16 90 74 164 W -38235.759 9.674 7951.452 0.059 B- -10763.323 55.406 163 958952.222 10.385 + 14 89 75 164 Re -a -27472.436 54.555 7881.052 0.333 B- -7050.331 140.051 163 970507.124 58.566 + 12 88 76 164 Os -20422.106 149.919 7833.291 0.914 B- -13078# 348# 163 978075.966 160.945 + 10 87 77 164 Ir -a -7344# 314# 7749# 2# B- * 163 992116# 338# +0 41 103 62 165 Sm x -43808# 401# 8043# 2# B- 6916# 424# 164 952970# 430# + 39 102 63 165 Eu + -50724# 138# 8080# 1# B- 5729.000 65.000 164 945546# 148# + 37 101 64 165 Gd + -56453# 121# 8110# 1# B- 4113.000 65.000 164 939395# 130# + 35 100 65 165 Tb x -60566# 102# 8130# 1# B- 3047# 102# 164 934980# 110# + 33 99 66 165 Dy -n -63612.606 0.769 8143.909 0.005 B- 1286.400 0.829 164 931709.054 0.825 + 31 98 67 165 Ho -64899.006 1.010 8146.964 0.006 B- -377.396 1.033 164 930328.047 1.084 + 29 97 68 165 Er -64521.610 0.964 8139.936 0.006 B- -1591.990 1.538 164 930733.198 1.034 + 27 96 69 165 Tm -62929.621 1.671 8125.546 0.010 B- -2634.239 26.592 164 932442.269 1.793 + 25 95 70 165 Yb -60295.382 26.539 8104.839 0.161 B- -3853.140 35.432 164 935270.241 28.490 + 23 94 71 165 Lu -56442.242 26.539 8076.745 0.161 B- -4806.734 38.539 164 939406.758 28.490 + 21 93 72 165 Hf x -51635.507 27.945 8042.872 0.169 B- -5787.655 31.195 164 944567.000 30.000 + 19 92 73 165 Ta -45847.853 13.863 8003.054 0.084 B- -6986.830 28.566 164 950780.303 14.882 + 17 91 74 165 W -38861.022 24.977 7955.968 0.151 B- -8201.246 34.332 164 958280.974 26.813 + 15 90 75 165 Re +a -30659.776 23.594 7901.522 0.143 B- -8865# 197# 164 967085.375 25.329 + 13 89 76 165 Os -a -21795# 196# 7843# 1# B- -10202# 252# 164 976602# 210# + 11 88 77 165 Ir IT -11593# 158# 7776# 1# B- * 164 987555# 170# +0 42 104 62 166 Sm x -40730# 400# 8024# 2# B- 6478# 537# 165 956275# 429# + 40 103 63 166 Eu + -47208# 358# 8059# 2# B- 7322.000 300.000 165 949320# 384# + 38 102 64 166 Gd x -54530# 196# 8098# 1# B- 3355# 208# 165 941460# 210# + 36 101 65 166 Tb + -57884.789 70.005 8113.680 0.422 B- 4700.000 70.000 165 937858.119 75.153 + 34 100 66 166 Dy -n -62584.789 0.867 8137.280 0.005 B- 486.540 0.921 165 932812.461 0.930 + 32 99 67 166 Ho -63071.329 1.010 8135.499 0.006 B- 1854.713 0.922 165 932290.139 1.084 + 30 98 68 166 Er -64926.042 1.165 8141.959 0.007 B- -3037.667 11.547 165 930299.023 1.251 + 28 97 69 166 Tm - -61888.375 11.606 8118.946 0.070 B- -292.635 13.507 165 933560.092 12.459 + 26 96 70 166 Yb +nn -61595.740 7.101 8112.471 0.043 B- -5574.759 30.642 165 933874.249 7.623 + 24 95 71 166 Lu x -56020.981 29.808 8074.175 0.180 B- -2161.998 40.859 165 939859.000 32.000 + 22 94 72 166 Hf x -53858.983 27.945 8056.438 0.168 B- -7761.208 39.520 165 942180.000 30.000 + 20 93 73 166 Ta x -46097.775 27.945 8004.971 0.168 B- -4209.744 29.508 165 950512.000 30.000 + 18 92 74 166 W -41888.031 9.478 7974.898 0.057 B- -9994.553 72.879 165 955031.346 10.174 + 16 91 75 166 Re -a -31893.478 72.310 7909.977 0.436 B- -6461.961 72.387 165 965760.940 77.628 + 14 90 76 166 Os -25431.517 17.966 7866.336 0.108 B- -12078# 197# 165 972698.141 19.287 + 12 89 77 166 Ir -p -13354# 196# 7789# 1# B- -8624# 359# 165 985664# 210# + 10 88 78 166 Pt -a -4730# 300# 7732# 2# B- * 165 994923# 322# +0 41 104 63 167 Eu x -44010# 400# 8040# 2# B- 6803# 499# 166 952753# 429# + 39 103 64 167 Gd x -50813# 298# 8076# 2# B- 5114# 357# 166 945450# 320# + 37 102 65 167 Tb x -55927# 196# 8102# 1# B- 4004# 205# 166 939960# 210# + 35 101 66 167 Dy + -59930.626 60.228 8120.992 0.361 B- 2350.000 60.000 166 935661.823 64.657 + 33 100 67 167 Ho p2n -62280.626 5.234 8130.379 0.031 B- 1010.554 5.208 166 933138.994 5.618 + 31 99 68 167 Er -63291.180 1.166 8131.746 0.007 B- -747.539 1.501 166 932054.119 1.252 + 29 98 69 167 Tm -62543.641 1.298 8122.585 0.008 B- -1953.065 3.798 166 932856.635 1.393 + 27 97 70 167 Yb -60590.576 3.981 8106.205 0.024 B- -3089.451 31.920 166 934953.337 4.273 + 25 96 71 167 Lu x -57501.125 31.671 8083.021 0.190 B- -4033.369 42.237 166 938270.000 34.000 + 23 95 72 167 Hf x -53467.756 27.945 8054.184 0.167 B- -5116.697 39.520 166 942600.000 30.000 + 21 94 73 167 Ta x -48351.059 27.945 8018.861 0.167 B- -6253.001 33.382 166 948093.000 30.000 + 19 93 74 167 W -42098.058 18.261 7976.733 0.109 B- -7267# 44# 166 954805.873 19.603 + 17 92 75 167 Re +a -34831# 40# 7929# 0# B- -8329# 83# 166 962607# 43# + 15 91 76 167 Os -a -26501.993 72.682 7873.974 0.435 B- -9429.554 74.962 166 971548.938 78.027 + 13 90 77 167 Ir -17072.440 18.346 7812.825 0.110 B- -10460# 303# 166 981671.981 19.695 + 11 89 78 167 Pt -a -6612# 302# 7746# 2# B- * 166 992901# 325# +0 42 105 63 168 Eu x -39740# 500# 8014# 3# B- 8623# 641# 167 957337# 537# + 40 104 64 168 Gd x -48363# 401# 8061# 2# B- 4359# 499# 167 948080# 430# + 38 103 65 168 Tb x -52723# 298# 8082# 2# B- 5837# 329# 167 943400# 320# + 36 102 66 168 Dy +pp -58559.566 140.009 8112.536 0.833 B- 1501.605 143.186 167 937133.716 150.305 + 34 101 67 168 Ho + -60061.171 30.023 8116.817 0.179 B- 2930.000 30.000 167 935521.676 32.230 + 32 100 68 168 Er -62991.171 1.168 8129.601 0.007 B- -1678.250 1.870 167 932376.192 1.254 + 30 99 69 168 Tm -61312.921 1.709 8114.954 0.010 B- 268.980 1.887 167 934177.868 1.834 + 28 98 70 168 Yb -61581.901 1.195 8111.898 0.007 B- -4514.051 39.248 167 933889.106 1.282 + 26 97 71 168 Lu - -57067.850 39.266 8080.372 0.234 B- -1707.299 48.195 167 938735.139 42.153 + 24 96 72 168 Hf x -55360.552 27.945 8065.553 0.166 B- -6966.644 39.520 167 940568.000 30.000 + 22 95 73 168 Ta x -48393.908 27.945 8019.428 0.166 B- -3500.799 30.936 167 948047.000 30.000 + 20 94 74 168 W -44893.109 13.271 7993.933 0.079 B- -9098.224 33.556 167 951805.262 14.247 + 18 93 75 168 Re -a -35794.885 30.821 7935.120 0.183 B- -5799.672 32.373 167 961572.608 33.087 + 16 92 76 168 Os -29995.213 9.904 7895.941 0.059 B- -11328.987 56.098 167 967798.812 10.632 + 14 91 77 168 Ir -a -18666.226 55.216 7823.850 0.329 B- -7658.765 140.344 167 979960.981 59.277 + 12 90 78 168 Pt -a -11007.460 149.951 7773.605 0.893 B- * 167 988183.004 160.978 +0 41 105 64 169 Gd x -44153# 503# 8036# 3# B- 6176# 585# 168 952600# 540# + 39 104 65 169 Tb x -50329# 298# 8068# 2# B- 5269# 423# 168 945970# 320# + 37 103 66 169 Dy + -55597.177 300.670 8094.763 1.779 B- 3200.000 300.000 168 940313.971 322.782 + 35 102 67 169 Ho +p -58797.177 20.060 8109.068 0.119 B- 2125.927 20.053 168 936878.630 21.534 + 33 101 68 169 Er -n -60923.104 1.179 8117.019 0.007 B- 352.108 1.114 168 934596.353 1.265 + 31 100 69 169 Tm -61275.212 0.812 8114.473 0.005 B- -897.650 1.141 168 934218.350 0.871 + 29 99 70 169 Yb -n -60377.563 1.205 8104.532 0.007 B- -2293.000 3.000 168 935182.016 1.293 + 27 98 71 169 Lu - -58084.563 3.233 8086.335 0.019 B- -3367.673 28.131 168 937643.653 3.470 + 25 97 72 169 Hf x -54716.889 27.945 8061.778 0.165 B- -4426.460 39.520 168 941259.000 30.000 + 23 96 73 169 Ta x -50290.430 27.945 8030.957 0.165 B- -5372.557 31.925 168 946011.000 30.000 + 21 95 74 169 W -44917.873 15.436 7994.537 0.091 B- -6508.641 19.173 168 951778.677 16.571 + 19 94 75 169 Re +a -38409.232 11.374 7951.395 0.067 B- -7686.541 27.618 168 958765.991 12.210 + 17 93 76 169 Os -a -30722.691 25.167 7901.284 0.149 B- -8628.852 34.276 168 967017.833 27.017 + 15 92 77 169 Ir +a -22093.839 23.308 7845.596 0.138 B- -9581# 197# 168 976281.287 25.021 + 13 91 78 169 Pt -a -12512# 196# 7784# 1# B- -10724# 357# 168 986567# 210# + 11 90 79 169 Au x -1788# 298# 7716# 2# B- * 168 998080# 320# +0 42 106 64 170 Gd x -41380# 596# 8020# 4# B- 5344# 718# 169 955577# 640# + 40 105 65 170 Tb x -46724# 401# 8047# 2# B- 6940# 446# 169 949840# 430# + 38 104 66 170 Dy x -53663# 196# 8083# 1# B- 2575# 202# 169 942390# 210# + 36 103 67 170 Ho + -56238.681 50.024 8093.796 0.294 B- 3870.000 50.000 169 939625.289 53.702 + 34 102 68 170 Er -60108.681 1.546 8111.959 0.009 B- -312.828 1.821 169 935470.673 1.659 + 32 101 69 170 Tm -59795.853 0.801 8105.517 0.005 B- 968.066 0.801 169 935806.507 0.859 + 30 100 70 170 Yb -60763.919 0.010 8106.609 0.000 B- -3457.695 16.843 169 934767.245 0.011 + 28 99 71 170 Lu - -57306.224 16.843 8081.668 0.099 B- -1052.370 32.628 169 938479.234 18.081 + 26 98 72 170 Hf x -56253.854 27.945 8070.875 0.164 B- -6116.190 39.520 169 939609.000 30.000 + 24 97 73 170 Ta x -50137.665 27.945 8030.296 0.164 B- -2846.832 30.904 169 946175.000 30.000 + 22 96 74 170 W -47290.832 13.195 8008.948 0.078 B- -8377.639 26.611 169 949231.200 14.165 + 20 95 75 170 Re -38913.193 23.109 7955.065 0.136 B- -4986.946 25.091 169 958224.966 24.808 + 18 94 76 170 Os -33926.247 9.773 7921.128 0.057 B- -10567# 89# 169 963578.673 10.491 + 16 93 77 170 Ir -a -23360# 89# 7854# 1# B- -7060# 89# 169 974922# 95# + 14 92 78 170 Pt -16299.193 18.247 7808.236 0.107 B- -12547# 197# 169 982502.095 19.588 + 12 91 79 170 Au -p -3752# 196# 7730# 1# B- * 169 995972# 211# +0 41 106 65 171 Tb x -44032# 503# 8031# 3# B- 6157# 585# 170 952730# 540# + 39 105 66 171 Dy x -50189# 298# 8063# 2# B- 4330# 670# 170 946120# 320# + 37 104 67 171 Ho + -54518.956 600.002 8083.608 3.509 B- 3200.000 600.000 170 941471.490 644.128 + 35 103 68 171 Er -57718.956 1.557 8097.746 0.009 B- 1491.342 1.256 170 938036.148 1.670 + 33 102 69 171 Tm -59210.298 0.972 8101.893 0.006 B- 96.512 0.972 170 936435.126 1.043 + 31 101 70 171 Yb -59306.810 0.013 8097.882 0.000 B- -1478.414 1.862 170 936331.517 0.014 + 29 100 71 171 Lu -57828.395 1.862 8084.661 0.011 B- -2397.050 28.936 170 937918.660 1.998 + 27 99 72 171 Hf x -55431.345 28.876 8066.068 0.169 B- -3711.072 40.184 170 940492.000 31.000 + 25 98 73 171 Ta x -51720.273 27.945 8039.791 0.163 B- -4634.183 39.520 170 944476.000 30.000 + 23 97 74 171 W x -47086.090 27.945 8008.115 0.163 B- -5835.810 39.520 170 949451.000 30.000 + 21 96 75 171 Re x -41250.280 27.945 7969.412 0.163 B- -6948.339 33.145 170 955716.000 30.000 + 19 95 76 171 Os -34301.942 17.823 7924.204 0.104 B- -7889.916 42.395 170 963175.348 19.133 + 17 94 77 171 Ir -a -26412.025 38.466 7873.489 0.225 B- -8942.323 82.291 170 971645.522 41.295 + 15 93 78 171 Pt -a -17469.702 72.747 7816.619 0.425 B- -9907.407 75.639 170 981245.502 78.097 + 13 92 79 171 Au -p -7562.295 20.713 7754.106 0.121 B- -11043# 303# 170 991881.542 22.236 + 11 91 80 171 Hg -a 3480# 303# 7685# 2# B- * 171 003736# 325# +0 42 107 65 172 Tb x -39850# 503# 8007# 3# B- 8159# 585# 171 957219# 540# + 40 106 66 172 Dy x -48009# 298# 8050# 2# B- 3474# 357# 171 948460# 320# + 38 105 67 172 Ho x -51484# 196# 8066# 1# B- 5000# 196# 171 944730# 210# + 36 104 68 172 Er -56483.612 4.008 8090.410 0.023 B- 890.767 4.543 171 939362.344 4.302 + 34 103 69 172 Tm -57374.379 5.503 8091.041 0.032 B- 1881.067 5.503 171 938406.067 5.907 + 32 102 70 172 Yb -59255.446 0.014 8097.429 0.000 B- -2519.466 2.336 171 936386.658 0.014 + 30 101 71 172 Lu -56735.980 2.336 8078.232 0.014 B- -333.754 24.540 171 939091.417 2.507 + 28 100 72 172 Hf x -56402.226 24.428 8071.743 0.142 B- -5072.248 37.117 171 939449.716 26.224 + 26 99 73 172 Ta x -51329.977 27.945 8037.705 0.162 B- -2232.791 39.520 171 944895.000 30.000 + 24 98 74 172 W x -49097.186 27.945 8020.175 0.162 B- -7560.080 47.974 171 947292.000 30.000 + 22 97 75 172 Re -41537.106 38.995 7971.672 0.227 B- -4293.264 41.036 171 955408.079 41.862 + 20 96 76 172 Os -37243.842 12.782 7942.163 0.074 B- -9864.473 34.832 171 960017.088 13.721 + 18 95 77 172 Ir -a -27379.369 32.402 7880.263 0.188 B- -6272.449 34.023 171 970607.036 34.785 + 16 94 78 172 Pt -21106.920 10.377 7839.247 0.060 B- -11788.914 57.108 171 977340.788 11.139 + 14 93 79 172 Au -a -9318.006 56.158 7766.158 0.326 B- -8259.262 140.853 171 989996.708 60.287 + 12 92 80 172 Hg -a -1058.744 150.079 7713.591 0.873 B- * 171 998863.391 161.116 +0 41 107 66 173 Dy x -43939# 401# 8027# 2# B- 5412# 499# 172 952830# 430# + 39 106 67 173 Ho x -49351# 298# 8054# 2# B- 4304# 357# 172 947020# 320# + 37 105 68 173 Er x -53654# 196# 8074# 1# B- 2602# 196# 172 942400# 210# + 35 104 69 173 Tm p2n -56256.059 4.400 8084.463 0.025 B- 1295.166 4.400 172 939606.632 4.723 + 33 103 70 173 Yb -57551.225 0.011 8087.427 0.000 B- -670.310 1.567 172 938216.215 0.012 + 31 102 71 173 Lu -56880.916 1.567 8079.030 0.009 B- -1469.132 27.989 172 938935.822 1.682 + 29 101 72 173 Hf x -55411.784 27.945 8066.016 0.162 B- -3015.246 39.520 172 940513.000 30.000 + 27 100 73 173 Ta x -52396.538 27.945 8044.064 0.162 B- -3669.155 39.520 172 943750.000 30.000 + 25 99 74 173 W x -48727.383 27.945 8018.333 0.162 B- -5173.518 39.520 172 947689.000 30.000 + 23 98 75 173 Re x -43553.865 27.945 7983.906 0.162 B- -6115.608 31.697 172 953243.000 30.000 + 21 97 76 173 Os -37438.257 14.959 7944.033 0.086 B- -7169.822 18.583 172 959808.375 16.059 + 19 96 77 173 Ir -30268.435 11.026 7898.067 0.064 B- -8325.524 57.052 172 967505.496 11.837 + 17 95 78 173 Pt -a -21942.911 55.977 7845.420 0.324 B- -9110.471 60.421 172 976443.315 60.093 + 15 94 79 173 Au +a -12832.440 22.784 7788.237 0.132 B- -10123# 197# 172 986223.808 24.459 + 13 93 80 173 Hg -a -2710# 196# 7725# 1# B- * 172 997091# 210# +0 42 108 66 174 Dy x -41370# 503# 8012# 3# B- 4319# 585# 173 955587# 540# + 40 107 67 174 Ho x -45690# 298# 8033# 2# B- 6260# 422# 173 950950# 320# + 38 106 68 174 Er x -51949# 298# 8064# 2# B- 1915# 301# 173 944230# 320# + 36 105 69 174 Tm + -53864.512 44.721 8070.642 0.257 B- 3080.000 44.721 173 942174.064 48.010 + 34 104 70 174 Yb -56944.512 0.011 8083.847 0.000 B- -1374.317 1.567 173 938867.548 0.011 + 32 103 71 174 Lu -55570.195 1.567 8071.453 0.009 B- 274.286 2.169 173 940342.938 1.682 + 30 102 72 174 Hf -55844.481 2.259 8068.533 0.013 B- -4103.715 28.036 173 940048.480 2.424 + 28 101 73 174 Ta x -51740.766 27.945 8040.452 0.161 B- -1513.678 39.520 173 944454.000 30.000 + 26 100 74 174 W x -50227.088 27.945 8027.256 0.161 B- -6553.992 39.520 173 946079.000 30.000 + 24 99 75 174 Re x -43673.096 27.945 7985.094 0.161 B- -3677.681 29.767 173 953115.000 30.000 + 22 98 76 174 Os -39995.416 10.254 7959.461 0.059 B- -9131.924 26.395 173 957063.152 11.008 + 20 97 77 174 Ir -30863.492 24.322 7902.483 0.140 B- -5545.329 26.433 173 966866.676 26.111 + 18 96 78 174 Pt -a -25318.163 10.351 7866.117 0.059 B- -11083# 89# 173 972819.832 11.112 + 16 95 79 174 Au -a -14235# 89# 7798# 1# B- -7594# 89# 173 984718# 95# + 14 94 80 174 Hg -a -6641.009 19.211 7749.784 0.110 B- * 173 992870.583 20.624 +0 41 108 67 175 Ho x -43203# 401# 8019# 2# B- 5449# 566# 174 953620# 430# + 39 107 68 175 Er x -48652# 401# 8045# 2# B- 3659# 404# 174 947770# 430# + 37 106 69 175 Tm + -52310.549 50.000 8061.766 0.286 B- 2385.000 50.000 174 943842.313 53.677 + 35 105 70 175 Yb -54695.549 0.071 8070.925 0.000 B- 470.033 1.206 174 941281.910 0.076 + 33 104 71 175 Lu -55165.582 1.207 8069.140 0.007 B- -683.920 1.952 174 940777.308 1.295 + 31 103 72 175 Hf -54481.662 2.282 8060.761 0.013 B- -2073.015 28.038 174 941511.527 2.449 + 29 102 73 175 Ta x -52408.647 27.945 8044.445 0.160 B- -2775.852 39.520 174 943737.000 30.000 + 27 101 74 175 W x -49632.795 27.945 8024.112 0.160 B- -4344.488 39.520 174 946717.000 30.000 + 25 100 75 175 Re x -45288.307 27.945 7994.816 0.160 B- -5182.931 30.324 174 951381.000 30.000 + 23 99 76 175 Os -40105.376 11.775 7960.729 0.067 B- -6710.870 17.089 174 956945.105 12.640 + 21 98 77 175 Ir -33394.506 12.384 7917.910 0.071 B- -7681.040 22.001 174 964149.521 13.295 + 19 97 78 175 Pt -25713.466 18.185 7869.548 0.104 B- -8309.511 42.705 174 972395.457 19.522 + 17 96 79 175 Au -a -17403.955 38.640 7817.595 0.221 B- -9431.379 82.504 174 981316.085 41.481 + 15 95 80 175 Hg -a -7972.576 72.896 7759.231 0.417 B- * 174 991441.086 78.257 +0 42 109 67 176 Ho x -39290# 503# 7997# 3# B- 7340# 643# 175 957820# 540# + 40 108 68 176 Er x -46631# 401# 8034# 2# B- 2741# 413# 175 949940# 430# + 38 107 69 176 Tm + -49371.314 100.000 8045.121 0.568 B- 4120.000 100.000 175 946997.711 107.354 + 36 106 70 176 Yb -53491.314 0.015 8064.085 0.000 B- -109.078 1.212 175 942574.708 0.015 + 34 105 71 176 Lu -53382.236 1.212 8059.020 0.007 B- 1194.085 0.874 175 942691.809 1.301 + 32 104 72 176 Hf -54576.321 1.481 8061.359 0.008 B- -3210.948 30.775 175 941409.905 1.590 + 30 103 73 176 Ta x -51365.374 30.739 8038.670 0.175 B- -723.771 41.543 175 944857.000 33.000 + 28 102 74 176 W x -50641.603 27.945 8030.112 0.159 B- -5578.718 39.520 175 945634.000 30.000 + 26 101 75 176 Re x -45062.885 27.945 7993.970 0.159 B- -2964.945 39.520 175 951623.000 30.000 + 24 100 76 176 Os x -42097.940 27.945 7972.679 0.159 B- -8219.614 32.580 175 954806.000 30.000 + 22 99 77 176 Ir -33878.326 16.750 7921.531 0.095 B- -4944.459 21.035 175 963630.119 17.981 + 20 98 78 176 Pt -28933.867 12.724 7888.992 0.072 B- -10412.904 35.541 175 968938.214 13.660 + 18 97 79 176 Au -a -18520.963 33.185 7825.383 0.189 B- -6736.013 34.998 175 980116.927 35.625 + 16 96 80 176 Hg -11784.950 11.119 7782.665 0.063 B- -12366.544 75.904 175 987348.335 11.937 + 14 95 81 176 Tl -p 581.594 75.086 7707.955 0.427 B- * 176 000624.367 80.607 +0 41 109 68 177 Er x -42858# 503# 8013# 3# B- 4611# 585# 176 953990# 540# + 39 108 69 177 Tm x -47469# 298# 8035# 2# B- 3517# 298# 176 949040# 320# + 37 107 70 177 Yb -n -50986.397 0.220 8049.973 0.001 B- 1397.409 1.240 176 945263.848 0.236 + 35 106 71 177 Lu -52383.806 1.220 8053.448 0.007 B- 496.810 0.791 176 943763.668 1.310 + 33 105 72 177 Hf -52880.616 1.408 8051.835 0.008 B- -1166.000 3.000 176 943230.320 1.511 + 31 104 73 177 Ta - -51714.616 3.314 8040.827 0.019 B- -2012.890 28.141 176 944482.073 3.557 + 29 103 74 177 W x -49701.726 27.945 8025.035 0.158 B- -3432.555 39.520 176 946643.000 30.000 + 27 102 75 177 Re x -46269.170 27.945 8001.222 0.158 B- -4312.708 31.535 176 950328.000 30.000 + 25 101 76 177 Os +a -41956.462 14.613 7972.436 0.083 B- -5909.041 24.576 176 954957.882 15.687 + 23 100 77 177 Ir x -36047.421 19.760 7934.632 0.112 B- -6676.976 24.801 176 961301.500 21.213 + 21 99 78 177 Pt -29370.444 14.988 7892.489 0.085 B- -7825.341 18.297 176 968469.529 16.090 + 19 98 79 177 Au -21545.103 10.496 7843.858 0.059 B- -8762.561 75.786 176 976870.379 11.268 + 17 97 80 177 Hg -a -12782.542 75.056 7789.932 0.424 B- -9442.016 78.098 176 986277.376 80.575 + 15 96 81 177 Tl IT -3340.526 21.629 7732.167 0.122 B- * 176 996413.797 23.219 +0 42 110 68 178 Er x -40260# 596# 7999# 3# B- 3855# 718# 177 956779# 640# + 40 109 69 178 Tm x -44116# 401# 8016# 2# B- 5580# 401# 177 952640# 430# + 38 108 70 178 Yb -nn -49695.475 10.000 8042.841 0.056 B- 642.309 10.250 177 946649.710 10.735 + 36 107 71 178 Lu -50337.784 2.251 8042.054 0.013 B- 2097.451 2.057 177 945960.162 2.416 + 34 106 72 178 Hf -52435.236 1.412 8049.442 0.008 B- -1837# 52# 177 943708.456 1.516 + 32 105 73 178 Ta IT -50598# 52# 8035# 0# B- -191# 50# 177 945681# 56# + 30 104 74 178 W - -50406.936 15.199 8029.257 0.085 B- -4753.483 31.810 177 945885.925 16.316 + 28 103 75 178 Re x -45653.453 27.945 7998.157 0.157 B- -2109.183 31.093 177 950989.000 30.000 + 26 102 76 178 Os -43544.270 13.632 7981.912 0.077 B- -7292.386 24.006 177 953253.300 14.634 + 24 101 77 178 Ir x -36251.884 19.760 7936.549 0.111 B- -4254.365 22.207 177 961082.000 21.213 + 22 100 78 178 Pt -31997.519 10.133 7908.252 0.057 B- -9693.776 14.297 177 965649.248 10.878 + 20 99 79 178 Au -22303.743 10.086 7849.398 0.057 B- -5987.841 14.755 177 976055.945 10.827 + 18 98 80 178 Hg -a -16315.901 10.770 7811.363 0.061 B- -11526# 90# 177 982484.158 11.562 + 16 97 81 178 Tl -a -4790# 89# 7742# 1# B- -8365# 91# 177 994857# 96# + 14 96 82 178 Pb -a 3574.294 23.963 7690.830 0.135 B- * 178 003837.163 25.724 +0 41 110 69 179 Tm x -41601# 503# 8002# 3# B- 4937# 540# 178 955340# 540# + 39 109 70 179 Yb x -46537# 196# 8025# 1# B- 2521# 196# 178 950040# 210# + 37 108 71 179 Lu -49058.918 5.150 8035.073 0.029 B- 1403.989 5.067 178 947333.082 5.528 + 35 107 72 179 Hf -50462.907 1.413 8038.546 0.008 B- -105.584 0.409 178 945825.838 1.517 + 33 106 73 179 Ta -50357.323 1.463 8033.585 0.008 B- -1062.195 14.520 178 945939.187 1.571 + 31 105 74 179 W -49295.127 14.573 8023.281 0.081 B- -2710.847 26.802 178 947079.501 15.644 + 29 104 75 179 Re -46584.280 24.639 8003.766 0.138 B- -3564.785 29.656 178 949989.715 26.450 + 27 103 76 179 Os -43019.495 16.504 7979.480 0.092 B- -4937.781 19.180 178 953816.669 17.718 + 25 102 77 179 Ir -38081.714 9.771 7947.524 0.055 B- -5813.569 12.613 178 959117.596 10.489 + 23 101 78 179 Pt -32268.145 7.977 7910.675 0.045 B- -7279.578 14.157 178 965358.719 8.563 + 21 100 79 179 Au -24988.567 11.696 7865.637 0.065 B- -8060.433 29.669 178 973173.668 12.555 + 19 99 80 179 Hg -16928.134 27.267 7816.236 0.152 B- -8659.639 47.417 178 981826.899 29.272 + 17 98 81 179 Tl -a -8268.495 38.793 7763.487 0.217 B- -10319.134 84.963 178 991123.405 41.646 + 15 97 82 179 Pb -a 2050.639 75.590 7701.468 0.422 B- * 179 002201.452 81.149 +0 42 111 69 180 Tm x -37920# 503# 7982# 3# B- 6680# 585# 179 959291# 540# + 40 110 70 180 Yb x -44600# 298# 8015# 2# B- 2076# 306# 179 952120# 320# + 38 109 71 180 Lu + -46676.348 70.725 8022.038 0.393 B- 3103.000 70.711 179 949890.876 75.926 + 36 108 72 180 Hf -49779.348 1.419 8034.930 0.008 B- -846.471 2.269 179 946559.669 1.522 + 34 107 73 180 Ta +n -48932.877 1.939 8025.881 0.011 B- 703.238 2.281 179 947468.392 2.081 + 32 106 74 180 W -49636.115 1.436 8025.442 0.008 B- -3798.757 21.440 179 946713.435 1.542 + 30 105 75 180 Re x -45837.359 21.392 7999.991 0.119 B- -1479.549 26.950 179 950791.568 22.965 + 28 104 76 180 Os -44357.810 16.391 7987.425 0.091 B- -6380.284 27.200 179 952379.930 17.596 + 26 103 77 180 Ir x -37977.526 21.706 7947.633 0.121 B- -3541.649 24.323 179 959229.446 23.302 + 24 102 78 180 Pt +a -34435.877 10.974 7923.611 0.061 B- -8810.368 11.973 179 963031.563 11.781 + 22 101 79 180 Au -25625.509 4.786 7870.318 0.027 B- -5375.062 13.524 179 972489.883 5.137 + 20 100 80 180 Hg -20250.447 12.649 7836.110 0.070 B- -10863.800 61.329 179 978260.249 13.579 + 18 99 81 180 Tl -a -9386.647 60.010 7771.409 0.333 B- -7445.267 61.277 179 989923.019 64.423 + 16 98 82 180 Pb -a -1941.380 12.396 7725.700 0.069 B- * 179 997915.842 13.307 +0 43 112 69 181 Tm x -35170# 596# 7967# 3# B- 5918# 667# 180 962243# 640# + 41 111 70 181 Yb x -41088# 298# 7996# 2# B- 3709# 324# 180 955890# 320# + 39 110 71 181 Lu x -44797.410 125.752 8011.929 0.695 B- 2605.421 125.760 180 951908.000 135.000 + 37 109 72 181 Hf -n -47402.831 1.420 8022.002 0.008 B- 1035.480 1.834 180 949110.965 1.524 + 35 108 73 181 Ta -48438.311 1.403 8023.400 0.008 B- -204.493 1.854 180 947999.331 1.506 + 33 107 74 181 W -n -48233.818 1.445 8017.948 0.008 B- -1716.427 12.629 180 948218.863 1.551 + 31 106 75 181 Re 4n -46517.391 12.549 8004.143 0.069 B- -2967.428 28.275 180 950061.523 13.471 + 29 105 76 181 Os -43549.963 25.338 7983.426 0.140 B- -4086.935 25.876 180 953247.188 27.201 + 27 104 77 181 Ir +a -39463.028 5.245 7956.523 0.029 B- -5081.517 14.660 180 957634.694 5.631 + 25 103 78 181 Pt -34381.511 13.689 7924.126 0.076 B- -6510.375 24.216 180 963089.927 14.695 + 23 102 79 181 Au -a -27871.136 19.976 7883.835 0.110 B- -7210.000 25.212 180 970079.103 21.445 + 21 101 80 181 Hg -20661.136 15.382 7839.679 0.085 B- -7862.401 17.876 180 977819.357 16.513 + 19 100 81 181 Tl -12798.735 9.108 7791.918 0.050 B- -9681.385 75.959 180 986259.992 9.778 + 17 99 82 181 Pb -a -3117.350 75.411 7734.107 0.417 B- * 180 996653.386 80.957 +0 42 112 70 182 Yb x -38820# 401# 7984# 2# B- 3060# 446# 181 958325# 430# + 40 111 71 182 Lu x -41880# 196# 7996# 1# B- 4170# 196# 181 955040# 210# + 38 110 72 182 Hf -nn -46049.508 6.165 8014.837 0.034 B- 380.425 6.274 181 950563.816 6.618 + 36 109 73 182 Ta -46429.934 1.405 8012.628 0.008 B- 1816.126 1.399 181 950155.413 1.508 + 34 108 74 182 W -48246.060 0.738 8018.308 0.004 B- -2800.000 101.980 181 948205.721 0.791 + 32 107 75 182 Re IT -45446.060 101.983 7998.625 0.560 B- -836.955 104.276 181 951211.645 109.483 + 30 106 76 182 Os -44609.104 21.745 7989.728 0.119 B- -5557.426 30.207 181 952110.153 23.344 + 28 105 77 182 Ir -39051.679 20.967 7954.894 0.115 B- -2883.230 24.720 181 958076.296 22.509 + 26 104 78 182 Pt -36168.449 13.095 7934.754 0.072 B- -7867.680 24.123 181 961171.571 14.057 + 24 103 79 182 Au -a -28300.768 20.260 7887.226 0.111 B- -4723.846 22.501 181 969617.874 21.749 + 22 102 80 182 Hg -23576.922 9.790 7856.972 0.054 B- -10248.994 15.363 181 974689.132 10.510 + 20 101 81 182 Tl -a -13327.927 11.839 7796.360 0.065 B- -6502.815 16.927 181 985691.880 12.709 + 18 100 82 182 Pb -a -6825.112 12.098 7756.332 0.066 B- * 181 992672.940 12.987 +0 43 113 70 183 Yb x -35100# 401# 7964# 2# B- 4616# 408# 182 962319# 430# + 41 112 71 183 Lu x -39716.110 80.108 7984.812 0.438 B- 3566.687 85.553 182 957363.000 86.000 + 39 111 72 183 Hf + -43282.796 30.034 8000.027 0.164 B- 2010.000 30.000 182 953534.004 32.242 + 37 110 73 183 Ta -n -45292.796 1.419 8006.735 0.008 B- 1072.783 1.413 182 951376.180 1.523 + 35 109 74 183 W -46365.580 0.737 8008.322 0.004 B- -556.000 8.000 182 950224.500 0.790 + 33 108 75 183 Re - -45809.580 8.034 8001.009 0.044 B- -2145.537 50.405 182 950821.390 8.624 + 31 107 76 183 Os -43664.043 49.760 7985.010 0.272 B- -3460.732 52.733 182 953124.719 53.420 + 29 106 77 183 Ir -40203.311 24.398 7961.823 0.133 B- -4430.824 28.923 182 956839.968 26.191 + 27 105 78 183 Pt -35772.487 15.533 7933.336 0.085 B- -5581.004 18.168 182 961596.653 16.675 + 25 104 79 183 Au -30191.483 9.423 7898.564 0.051 B- -6386.809 11.789 182 967588.108 10.116 + 23 103 80 183 Hg -23804.674 7.084 7859.388 0.039 B- -7217.417 11.716 182 974444.629 7.604 + 21 102 81 183 Tl -16587.257 9.331 7815.673 0.051 B- -9012.038 29.657 182 982192.846 10.017 + 19 101 82 183 Pb -a -7575.218 28.151 7762.152 0.154 B- * 182 991867.668 30.221 +0 44 114 70 184 Yb x -32540# 503# 7951# 3# B- 3872# 585# 183 965067# 540# + 42 113 71 184 Lu x -36412# 298# 7967# 2# B- 5087# 301# 183 960910# 320# + 40 112 72 184 Hf + -41499.373 39.706 7990.722 0.216 B- 1340.000 30.000 183 955448.587 42.625 + 38 111 73 184 Ta + -42839.373 26.010 7993.752 0.141 B- 2866.000 26.000 183 954010.038 27.923 + 36 110 74 184 W -45705.373 0.731 8005.077 0.004 B- -1485.739 4.198 183 950933.260 0.785 + 34 109 75 184 Re -44219.634 4.275 7992.750 0.023 B- 32.898 4.140 183 952528.267 4.589 + 32 108 76 184 Os -44252.533 0.827 7988.677 0.005 B- -4641.682 27.957 183 952492.949 0.887 + 30 107 77 184 Ir x -39610.851 27.945 7959.198 0.152 B- -2276.608 31.997 183 957476.000 30.000 + 28 106 78 184 Pt -37334.243 15.584 7942.574 0.085 B- -7015.533 27.185 183 959920.039 16.730 + 26 105 79 184 Au -a -30318.710 22.275 7900.194 0.121 B- -3969.745 24.442 183 967451.524 23.912 + 24 104 80 184 Hg -26348.965 10.062 7874.367 0.055 B- -9465.723 14.200 183 971713.221 10.802 + 22 103 81 184 Tl -16883.242 10.020 7818.671 0.054 B- -5831.720 16.260 183 981875.093 10.757 + 20 102 82 184 Pb -11051.522 12.806 7782.725 0.070 B- -12114.590 79.153 183 988135.702 13.748 + 18 101 83 184 Bi -a 1063.068 78.110 7712.633 0.425 B- * 184 001141.250 83.854 +0 45 115 70 185 Yb x -28500# 503# 7929# 3# B- 5388# 585# 184 969404# 540# + 43 114 71 185 Lu x -33888# 298# 7954# 2# B- 4432# 305# 184 963620# 320# + 41 113 72 185 Hf x -38319.800 64.273 7973.970 0.347 B- 3074.492 65.815 184 958862.000 69.000 + 39 112 73 185 Ta + -41394.293 14.161 7986.360 0.077 B- 1993.500 14.142 184 955561.396 15.202 + 37 111 74 185 W -43387.793 0.733 7992.907 0.004 B- 431.234 0.661 184 953421.286 0.786 + 35 110 75 185 Re -43819.027 0.818 7991.009 0.004 B- -1013.147 0.419 184 952958.337 0.877 + 33 109 76 185 Os -42805.880 0.830 7981.304 0.004 B- -2470.326 27.957 184 954045.995 0.891 + 31 108 77 185 Ir x -40335.553 27.945 7963.722 0.151 B- -3647.414 38.055 184 956698.000 30.000 + 29 107 78 185 Pt -36688.140 25.832 7939.777 0.140 B- -4829.997 25.963 184 960613.659 27.731 + 27 106 79 185 Au x -31858.143 2.608 7909.440 0.014 B- -5674.477 13.886 184 965798.874 2.800 + 25 105 80 185 Hg -26183.666 13.639 7874.538 0.074 B- -6425.925 24.767 184 971890.676 14.641 + 23 104 81 185 Tl IT -19757.741 20.674 7835.575 0.112 B- -8216.521 26.249 184 978789.191 22.194 + 21 103 82 185 Pb -a -11541.220 16.175 7786.932 0.087 B- -9305# 83# 184 987609.989 17.364 + 19 102 83 185 Bi IT -2236# 81# 7732# 0# B- * 184 997600# 87# +0 44 115 71 186 Lu x -30210# 401# 7935# 2# B- 6214# 404# 185 967568# 430# + 42 114 72 186 Hf x -36424.210 51.232 7964.302 0.275 B- 2183.318 78.906 185 960897.000 55.000 + 40 113 73 186 Ta + -38607.528 60.012 7971.835 0.323 B- 3901.000 60.000 185 958553.111 64.425 + 38 112 74 186 W -42508.528 1.212 7988.601 0.007 B- -581.442 1.244 185 954365.215 1.300 + 36 111 75 186 Re -41927.086 0.826 7981.269 0.004 B- 1072.857 0.837 185 954989.419 0.886 + 34 110 76 186 Os -42999.943 0.761 7982.831 0.004 B- -3827.596 16.543 185 953837.660 0.816 + 32 109 77 186 Ir x -39172.346 16.526 7958.047 0.089 B- -1307.903 27.312 185 957946.754 17.740 + 30 108 78 186 Pt -37864.443 21.745 7946.809 0.117 B- -6149.591 30.207 185 959350.846 23.344 + 28 107 79 186 Au -31714.852 20.967 7909.540 0.113 B- -3175.756 23.987 185 965952.703 22.509 + 26 106 80 186 Hg -28539.097 11.650 7888.260 0.063 B- -8652.484 25.209 185 969362.017 12.507 + 24 105 81 186 Tl x -19886.613 22.356 7837.535 0.120 B- -5204.588 25.078 185 978650.841 24.000 + 22 104 82 186 Pb -a -14682.026 11.363 7805.347 0.061 B- -11535.814 20.329 185 984238.196 12.199 + 20 103 83 186 Bi -a -3146.212 16.857 7739.121 0.091 B- -7247.186 24.870 185 996622.402 18.096 + 18 102 84 186 Po -a 4100.974 18.286 7695.951 0.098 B- * 186 004402.577 19.630 +0 45 116 71 187 Lu x -27580# 401# 7922# 2# B- 5237# 499# 186 970392# 430# + 43 115 72 187 Hf x -32817# 298# 7946# 2# B- 4079# 303# 186 964770# 320# + 41 114 73 187 Ta x -36895.546 55.890 7963.212 0.299 B- 3008.424 55.903 186 960391.000 60.000 + 39 113 74 187 W -39903.970 1.212 7975.116 0.006 B- 1312.508 1.122 186 957161.323 1.300 + 37 112 75 187 Re -41216.478 0.736 7977.951 0.004 B- 2.467 0.002 186 955752.288 0.790 + 35 111 76 187 Os -41218.945 0.736 7973.780 0.004 B- -1669.572 27.955 186 955749.640 0.790 + 33 110 77 187 Ir x -39549.372 27.945 7960.668 0.149 B- -2864.323 36.868 186 957542.000 30.000 + 31 109 78 187 Pt -36685.050 24.048 7941.168 0.129 B- -3657.212 27.377 186 960616.976 25.816 + 29 108 79 187 Au -33027.838 22.308 7917.427 0.119 B- -4909.908 26.287 186 964543.155 23.948 + 27 107 80 187 Hg -28117.930 13.905 7886.987 0.074 B- -5673.343 16.067 186 969814.158 14.928 + 25 106 81 187 Tl -22444.587 8.048 7852.464 0.043 B- -7457.628 9.525 186 975904.743 8.640 + 23 105 82 187 Pb -14986.959 5.094 7808.400 0.027 B- -8603.688 11.227 186 983910.836 5.468 + 21 104 83 187 Bi -a -6383.271 10.005 7758.208 0.054 B- -9211.868 33.430 186 993147.276 10.740 + 19 103 84 187 Po -a 2828.597 31.898 7704.763 0.171 B- * 187 003036.624 34.243 +0 46 117 71 188 Lu x -23790# 503# 7902# 3# B- 7089# 585# 187 974460# 540# + 44 116 72 188 Hf x -30879# 298# 7936# 2# B- 2733# 303# 187 966850# 320# + 42 115 73 188 Ta x -33612.030 54.958 7946.321 0.292 B- 5055.781 55.045 187 963916.000 59.000 + 40 114 74 188 W + -38667.811 3.089 7969.052 0.016 B- 349.000 3.000 187 958488.395 3.316 + 38 113 75 188 Re -n -39016.811 0.738 7966.747 0.004 B- 2120.422 0.152 187 958113.728 0.791 + 36 112 76 188 Os -41137.233 0.734 7973.864 0.004 B- -2792.326 9.416 187 955837.361 0.787 + 34 111 77 188 Ir -38344.907 9.423 7954.850 0.050 B- -523.979 8.686 187 958835.046 10.116 + 32 110 78 188 Pt -37820.929 5.304 7947.902 0.028 B- -5449.621 5.953 187 959397.560 5.694 + 30 109 79 188 Au x -32371.308 2.701 7914.753 0.014 B- -2169.394 12.569 187 965247.969 2.900 + 28 108 80 188 Hg -30201.914 12.275 7899.052 0.065 B- -7865.513 32.325 187 967576.910 13.178 + 26 107 81 188 Tl x -22336.400 29.904 7853.053 0.159 B- -4521.198 31.734 187 976020.886 32.103 + 24 106 82 188 Pb -a -17815.202 10.622 7824.843 0.057 B- -10620.515 15.427 187 980874.592 11.403 + 22 105 83 188 Bi -a -7194.687 11.187 7764.189 0.060 B- -6650.374 22.892 187 992276.184 12.009 + 20 104 84 188 Po -a -544.313 19.973 7724.653 0.106 B- * 187 999415.655 21.441 +0 45 117 72 189 Hf x -27162# 298# 7917# 2# B- 4667# 357# 188 970840# 320# + 43 116 73 189 Ta x -31829# 196# 7938# 1# B- 3788# 200# 188 965830# 210# + 41 115 74 189 W x -35617.536 40.054 7953.454 0.212 B- 2361.507 40.883 188 961763.000 43.000 + 39 114 75 189 Re +p -37979.043 8.191 7961.809 0.043 B- 1007.702 8.167 188 959227.817 8.793 + 37 113 76 189 Os -38986.745 0.666 7963.002 0.004 B- -537.159 12.563 188 958146.005 0.715 + 35 112 77 189 Ir -38449.586 12.576 7956.020 0.067 B- -1980.238 13.636 188 958722.669 13.500 + 33 111 78 189 Pt -36469.348 10.090 7941.403 0.053 B- -2887.394 22.474 188 960848.542 10.832 + 31 110 79 189 Au x -33581.955 20.081 7921.987 0.106 B- -3955.554 37.401 188 963948.286 21.558 + 29 109 80 189 Hg -29626.401 31.553 7896.919 0.167 B- -5010.300 32.643 188 968194.748 33.873 + 27 108 81 189 Tl -24616.100 8.368 7866.270 0.044 B- -6772.066 16.364 188 973573.527 8.983 + 25 107 82 189 Pb -17844.035 14.062 7826.299 0.074 B- -7779.374 25.150 188 980843.639 15.096 + 23 106 83 189 Bi -a -10064.660 20.851 7780.999 0.110 B- -8642.656 30.354 188 989195.141 22.384 + 21 105 84 189 Po -a -1422.005 22.059 7731.131 0.117 B- * 188 998473.415 23.681 +0 46 118 72 190 Hf x -25030# 401# 7907# 2# B- 3483# 446# 189 973129# 430# + 44 117 73 190 Ta x -28513# 196# 7921# 1# B- 5869# 200# 189 969390# 210# + 42 116 74 190 W -34382.313 39.726 7947.573 0.209 B- 1253.517 63.522 189 963089.066 42.647 + 40 115 75 190 Re -35635.830 70.852 7950.053 0.373 B- 3071.941 70.854 189 961743.360 76.063 + 38 114 76 190 Os -38707.771 0.650 7962.104 0.003 B- -1954.227 1.213 189 958445.496 0.697 + 36 113 77 190 Ir +n -36753.544 1.370 7947.701 0.007 B- 552.906 1.282 189 960543.445 1.470 + 34 112 78 190 Pt -37306.450 0.657 7946.493 0.003 B- -4472.917 3.509 189 959949.876 0.704 + 32 111 79 190 Au x -32833.533 3.447 7918.834 0.018 B- -1462.836 16.276 189 964751.750 3.700 + 30 110 80 190 Hg -31370.697 15.907 7907.017 0.084 B- -6998.670 17.782 189 966322.169 17.076 + 28 109 81 190 Tl +a -24372.027 7.948 7866.064 0.042 B- -3955.382 14.825 189 973835.551 8.532 + 26 108 82 190 Pb -a -20416.645 12.514 7841.129 0.066 B- -9817.066 25.800 189 978081.828 13.434 + 24 107 83 190 Bi -a -10599.579 22.562 7785.342 0.119 B- -6035.742 26.275 189 988620.883 24.221 + 22 106 84 190 Po -a -4563.837 13.465 7749.458 0.071 B- * 189 995100.519 14.455 +0 45 118 73 191 Ta x -26492# 298# 7911# 2# B- 4684# 301# 190 971560# 320# + 43 117 74 191 W x -31176.173 41.917 7931.435 0.219 B- 3174.124 43.156 190 966531.000 45.000 + 41 116 75 191 Re +p -34350.296 10.265 7943.957 0.054 B- 2044.889 10.244 190 963123.437 11.019 + 39 115 76 191 Os -36395.185 0.659 7950.568 0.003 B- 313.570 1.141 190 960928.159 0.707 + 37 114 77 191 Ir -36708.756 1.311 7948.113 0.007 B- -1010.518 3.636 190 960591.527 1.406 + 35 113 78 191 Pt -35698.237 4.127 7938.727 0.022 B- -1900.333 6.426 190 961676.363 4.430 + 33 112 79 191 Au -33797.904 4.926 7924.681 0.026 B- -3206.008 22.710 190 963716.455 5.288 + 31 111 80 191 Hg -30591.896 22.280 7903.800 0.117 B- -4308.951 23.461 190 967158.247 23.918 + 29 110 81 191 Tl +a -26282.945 7.349 7877.144 0.038 B- -6051.827 37.978 190 971784.096 7.889 + 27 109 82 191 Pb x -20231.118 37.260 7841.363 0.195 B- -6991.772 38.005 190 978281.000 40.000 + 25 108 83 191 Bi -13239.347 7.487 7800.661 0.039 B- -8170.612 10.320 190 985786.975 8.037 + 23 107 84 191 Po -5068.735 7.103 7753.786 0.037 B- -8932.653 17.600 190 994558.488 7.624 + 21 106 85 191 At -a 3863.917 16.103 7702.923 0.084 B- * 191 004148.086 17.287 +0 46 119 73 192 Ta x -23064# 401# 7894# 2# B- 6586# 446# 191 975240# 430# + 44 118 74 192 W x -29649# 196# 7924# 1# B- 1939# 208# 191 968170# 210# + 42 117 75 192 Re x -31588.825 70.794 7930.238 0.369 B- 4293.366 70.831 191 966088.000 76.000 + 40 116 76 192 Os -35882.191 2.315 7948.525 0.012 B- -1046.630 2.397 191 961478.881 2.485 + 38 115 77 192 Ir -34835.561 1.314 7938.999 0.007 B- 1452.896 2.274 191 962602.485 1.410 + 36 114 78 192 Pt -36288.457 2.570 7942.491 0.013 B- -3516.341 15.617 191 961042.736 2.758 + 34 113 79 192 Au - -32772.116 15.827 7920.102 0.082 B- -760.563 22.178 191 964817.684 16.991 + 32 112 80 192 Hg x -32011.553 15.537 7912.066 0.081 B- -6139.307 35.277 191 965634.182 16.679 + 30 111 81 192 Tl x -25872.246 31.671 7876.016 0.165 B- -3316.226 34.348 191 972225.000 34.000 + 28 110 82 192 Pb -a -22556.020 13.295 7854.669 0.069 B- -9021.485 32.917 191 975785.115 14.273 + 26 109 83 192 Bi -a -13534.535 30.112 7803.608 0.157 B- -5463.873 32.096 191 985470.078 32.326 + 24 108 84 192 Po -a -8070.661 11.110 7771.075 0.058 B- -10996.516 30.008 191 991335.788 11.926 + 22 107 85 192 At -a 2925.854 27.876 7709.727 0.145 B- * 192 003141.034 29.926 +0 47 120 73 193 Ta x -20870# 401# 7884# 2# B- 5417# 446# 192 977595# 430# + 45 119 74 193 W x -26287# 196# 7908# 1# B- 3945# 199# 192 971780# 210# + 43 118 75 193 Re x -30231.638 39.123 7923.937 0.203 B- 3162.652 39.192 192 967545.000 42.000 + 41 117 76 193 Os -33394.289 2.321 7936.270 0.012 B- 1141.946 2.400 192 964149.753 2.491 + 39 116 77 193 Ir -34536.235 1.328 7938.133 0.007 B- -56.628 0.300 192 962923.824 1.425 + 37 115 78 193 Pt -34479.608 1.359 7933.786 0.007 B- -1074.787 8.768 192 962984.616 1.458 + 35 114 79 193 Au -33404.821 8.674 7924.164 0.045 B- -2342.642 14.370 192 964138.447 9.311 + 33 113 80 193 Hg -31062.179 15.505 7907.972 0.080 B- -3584.967 16.894 192 966653.377 16.645 + 31 112 81 193 Tl x -27477.212 6.707 7885.344 0.035 B- -5282.723 50.028 192 970501.997 7.200 + 29 111 82 193 Pb x -22194.490 49.577 7853.919 0.257 B- -6309.931 50.152 192 976173.234 53.222 + 27 110 83 193 Bi -15884.559 7.576 7817.171 0.039 B- -7559.241 16.387 192 982947.223 8.132 + 25 109 84 193 Po -a -8325.318 14.531 7773.950 0.075 B- -8257.998 26.059 192 991062.403 15.599 + 23 108 85 193 At -a -67.320 21.632 7727.109 0.112 B- -9110.231 33.144 192 999927.728 23.222 + 21 107 86 193 Rn -a 9042.911 25.112 7675.852 0.130 B- * 193 009707.964 26.958 +0 48 121 73 194 Ta x -17300# 503# 7866# 3# B- 7227# 585# 193 981428# 540# + 46 120 74 194 W x -24526# 298# 7899# 2# B- 2711# 357# 193 973670# 320# + 44 119 75 194 Re x -27237# 196# 7909# 1# B- 5198# 196# 193 970760# 210# + 42 118 76 194 Os + -32435.108 2.403 7932.022 0.012 B- 96.600 2.000 193 965179.477 2.579 + 40 117 77 194 Ir -n -32531.708 1.332 7928.487 0.007 B- 2228.362 1.257 193 965075.773 1.430 + 38 116 78 194 Pt -34760.070 0.496 7935.941 0.003 B- -2548.134 2.117 193 962683.527 0.532 + 36 115 79 194 Au +3n -32211.936 2.118 7918.774 0.011 B- -27.991 3.581 193 965419.062 2.273 + 34 114 80 194 Hg x -32183.945 2.888 7914.597 0.015 B- -5246.454 14.268 193 965449.111 3.100 + 32 113 81 194 Tl x -26937.491 13.972 7883.520 0.072 B- -2729.552 22.343 193 971081.411 15.000 + 30 112 82 194 Pb -24207.940 17.435 7865.418 0.090 B- -8179.128 18.498 193 974011.706 18.717 + 28 111 83 194 Bi +a -16028.811 6.178 7819.225 0.032 B- -5024.156 14.313 193 982792.362 6.632 + 26 110 84 194 Po -a -11004.655 12.911 7789.294 0.067 B- -10284.492 28.076 193 988186.015 13.860 + 24 109 85 194 At -a -720.163 24.931 7732.249 0.129 B- -6443.658 30.119 193 999226.872 26.764 + 22 108 86 194 Rn -a 5723.495 16.899 7695.001 0.087 B- * 194 006144.424 18.141 +0 47 121 74 195 W x -21010# 298# 7882# 2# B- 4569# 422# 194 977445# 320# + 45 120 75 195 Re x -25579# 298# 7902# 2# B- 3933# 303# 194 972540# 320# + 43 119 76 195 Os x -29511.593 55.890 7917.744 0.287 B- 2180.658 55.906 194 968318.000 60.000 + 41 118 77 195 Ir -n -31692.251 1.333 7924.915 0.007 B- 1101.598 1.264 194 965976.967 1.431 + 39 117 78 195 Pt -32793.849 0.503 7926.552 0.003 B- -226.817 1.000 194 964794.353 0.539 + 37 116 79 195 Au -32567.031 1.119 7921.377 0.006 B- -1553.638 23.156 194 965037.851 1.201 + 35 115 80 195 Hg -31013.393 23.142 7909.397 0.119 B- -2858.145 25.657 194 966705.751 24.843 + 33 114 81 195 Tl -28155.248 11.093 7890.728 0.057 B- -4447.555 21.106 194 969774.096 11.909 + 31 113 82 195 Pb -23707.693 17.960 7863.908 0.092 B- -5682.132 18.722 194 974548.743 19.280 + 29 112 83 195 Bi -18025.561 5.287 7830.757 0.027 B- -6969.303 37.737 194 980648.762 5.675 + 27 111 84 195 Po -a -11056.259 37.364 7791.005 0.192 B- -7585.964 38.571 194 988130.617 40.112 + 25 110 85 195 At -a -3470.295 9.573 7748.091 0.049 B- -8520.575 51.401 194 996274.485 10.276 + 23 109 86 195 Rn -a 5050.281 50.502 7700.383 0.259 B- * 195 005421.699 54.216 +0 48 122 74 196 W x -18880# 401# 7872# 2# B- 3662# 499# 195 979731# 430# + 46 121 75 196 Re x -22542# 298# 7887# 2# B- 5735# 301# 195 975800# 320# + 44 120 76 196 Os +pp -28277.105 40.055 7912.229 0.204 B- 1158.388 55.495 195 969643.277 43.000 + 42 119 77 196 Ir + -29435.493 38.414 7914.148 0.196 B- 3209.016 38.411 195 968399.696 41.239 + 40 118 78 196 Pt -32644.510 0.510 7926.529 0.003 B- -1505.803 2.960 195 964954.675 0.547 + 38 117 79 196 Au -31138.706 2.962 7914.855 0.015 B- 687.235 3.118 195 966571.221 3.179 + 36 116 80 196 Hg -31825.941 2.946 7914.369 0.015 B- -4329.349 12.463 195 965833.444 3.163 + 34 115 81 196 Tl x -27496.592 12.109 7888.289 0.062 B- -2148.280 14.356 195 970481.192 13.000 + 32 114 82 196 Pb -25348.312 7.710 7873.337 0.039 B- -7339.281 25.616 195 972787.466 8.277 + 30 113 83 196 Bi x -18009.031 24.428 7831.900 0.125 B- -4535.989 27.916 195 980666.509 26.224 + 28 112 84 196 Po -a -13473.042 13.512 7804.766 0.069 B- -9558.365 33.162 195 985536.094 14.506 + 26 111 85 196 At -a -3914.677 30.284 7752.007 0.155 B- -5885.668 33.540 195 995797.421 32.511 + 24 110 86 196 Rn -a 1970.991 14.417 7717.987 0.074 B- * 196 002115.945 15.476 +0 49 123 74 197 W x -15140# 401# 7854# 2# B- 5363# 499# 196 983747# 430# + 47 122 75 197 Re x -20502# 298# 7878# 2# B- 4807# 357# 196 977990# 320# + 45 121 76 197 Os x -25309# 196# 7898# 1# B- 2955# 197# 196 972830# 210# + 43 120 77 197 Ir +p -28264.105 20.110 7908.999 0.102 B- 2155.645 20.106 196 969657.233 21.588 + 41 119 78 197 Pt -30419.750 0.536 7915.971 0.003 B- 719.988 0.502 196 967343.053 0.575 + 39 118 79 197 Au -31139.738 0.542 7915.654 0.003 B- -599.509 3.202 196 966570.114 0.581 + 37 117 80 197 Hg -30540.229 3.207 7908.640 0.016 B- -2198.580 16.637 196 967213.713 3.442 + 35 116 81 197 Tl +a -28341.649 16.325 7893.508 0.083 B- -3596.247 17.014 196 969573.986 17.526 + 33 115 82 197 Pb -24745.401 4.804 7871.282 0.024 B- -5058.210 9.619 196 973434.717 5.157 + 31 114 83 197 Bi +a -19687.191 8.333 7841.634 0.042 B- -6329.202 50.373 196 978864.929 8.946 + 29 113 84 197 Po -a -13357.990 49.679 7805.535 0.252 B- -7002.739 50.317 196 985659.607 53.332 + 27 112 85 197 At -6355.250 7.983 7766.017 0.041 B- -7865.603 18.054 196 993177.357 8.570 + 25 111 86 197 Rn -a 1510.353 16.193 7722.118 0.082 B- -8743.618 56.762 197 001621.430 17.383 + 23 110 87 197 Fr -a 10253.971 54.404 7673.763 0.276 B- * 197 011008.090 58.404 +0 48 123 75 198 Re x -17139# 401# 7862# 2# B- 6697# 446# 197 981600# 430# + 46 122 76 198 Os x -23837# 196# 7891# 1# B- 1984# 277# 197 974410# 210# + 44 121 77 198 Ir x -25821# 196# 7897# 1# B- 4083# 196# 197 972280# 210# + 42 120 78 198 Pt -29903.999 2.100 7914.150 0.011 B- -323.219 2.059 197 967896.734 2.254 + 40 119 79 198 Au -29580.781 0.540 7908.567 0.003 B- 1373.530 0.490 197 968243.724 0.579 + 38 118 80 198 Hg -30954.310 0.458 7911.552 0.002 B- -3425.564 7.559 197 966769.179 0.491 + 36 117 81 198 Tl x -27528.746 7.545 7890.300 0.038 B- -1461.257 11.554 197 970446.673 8.100 + 34 116 82 198 Pb -26067.489 8.750 7878.969 0.044 B- -6698.003 29.283 197 972015.397 9.393 + 32 115 83 198 Bi x -19369.486 27.945 7841.189 0.141 B- -3896.134 32.932 197 979206.000 30.000 + 30 114 84 198 Po -15473.352 17.424 7817.561 0.088 B- -8758.839 18.386 197 983388.672 18.705 + 28 113 85 198 At x -6714.513 5.868 7769.373 0.030 B- -5484.155 14.647 197 992791.673 6.300 + 26 112 86 198 Rn -a -1230.358 13.420 7737.724 0.068 B- -10804.382 34.905 197 998679.156 14.406 + 24 111 87 198 Fr -a 9574.024 32.222 7679.205 0.163 B- * 198 010278.138 34.591 +0 49 124 75 199 Re x -14860# 401# 7851# 2# B- 5623# 446# 198 984047# 430# + 47 123 76 199 Os x -20484# 196# 7875# 1# B- 3915# 200# 198 978010# 210# + 45 122 77 199 Ir p-2n -24398.515 41.054 7891.206 0.206 B- 2990.167 41.003 198 973807.115 44.073 + 43 121 78 199 Pt -n -27388.682 2.159 7902.300 0.011 B- 1705.059 2.120 198 970597.038 2.317 + 41 120 79 199 Au -29093.741 0.542 7906.937 0.003 B- 452.327 0.613 198 968766.582 0.581 + 39 119 80 199 Hg -29546.068 0.526 7905.279 0.003 B- -1486.674 27.950 198 968280.989 0.564 + 37 118 81 199 Tl x -28059.394 27.945 7893.877 0.140 B- -2827.589 29.679 198 969877.000 30.000 + 35 117 82 199 Pb +a -25231.804 9.996 7875.736 0.050 B- -4434.239 14.547 198 972912.542 10.730 + 33 116 83 199 Bi -20797.566 10.568 7849.522 0.053 B- -5589.083 20.919 198 977672.893 11.345 + 31 115 84 199 Po -a -15208.483 18.060 7817.505 0.091 B- -6385.111 18.845 198 983673.021 19.387 + 29 114 85 199 At -8823.372 5.384 7781.488 0.027 B- -7323.921 37.972 198 990527.719 5.780 + 27 113 86 199 Rn -a -1499.451 37.588 7740.753 0.189 B- -8270.844 40.015 198 998390.273 40.352 + 25 112 87 199 Fr -a 6771.393 13.726 7695.259 0.069 B- * 199 007269.389 14.734 +0 48 124 76 200 Os x -18779# 298# 7868# 1# B- 2832# 357# 199 979840# 320# + 46 123 77 200 Ir x -21611# 196# 7878# 1# B- 4988# 197# 199 976800# 210# + 44 122 78 200 Pt -nn -26599.160 20.110 7899.198 0.101 B- 640.932 33.439 199 971444.625 21.588 + 42 121 79 200 Au -27240.092 26.717 7898.491 0.134 B- 2263.178 26.719 199 970756.556 28.681 + 40 120 80 200 Hg -29503.270 0.529 7905.895 0.003 B- -2456.040 5.735 199 968326.934 0.568 + 38 119 81 200 Tl - -27047.230 5.759 7889.703 0.029 B- -796.176 12.340 199 970963.602 6.182 + 36 118 82 200 Pb 4n -26251.054 10.927 7881.810 0.055 B- -5880.299 24.852 199 971818.332 11.730 + 34 117 83 200 Bi +a -20370.755 22.321 7848.497 0.112 B- -3428.994 23.573 199 978131.093 23.962 + 32 116 84 200 Po -16941.761 7.579 7827.440 0.038 B- -7953.869 25.612 199 981812.270 8.135 + 30 115 85 200 At -a -8987.892 24.465 7783.759 0.122 B- -4983.127 28.030 199 990351.100 26.264 + 28 114 86 200 Rn -a -4004.765 13.681 7754.932 0.068 B- -10137.263 33.529 199 995700.707 14.686 + 26 113 87 200 Fr -a 6132.498 30.611 7700.334 0.153 B- * 200 006583.507 32.861 +0 49 125 76 201 Os x -15239# 298# 7851# 1# B- 4657# 357# 200 983640# 320# + 47 124 77 201 Ir x -19897# 196# 7871# 1# B- 3844# 202# 200 978640# 210# + 45 123 78 201 Pt + -23740.714 50.103 7885.833 0.249 B- 2660.000 50.000 200 974513.293 53.788 + 43 122 79 201 Au -26400.714 3.218 7895.175 0.016 B- 1261.827 3.147 200 971657.665 3.454 + 41 121 80 201 Hg -27662.542 0.711 7897.560 0.004 B- -481.704 14.181 200 970303.038 0.763 + 39 120 81 201 Tl -27180.838 14.185 7891.271 0.071 B- -1909.802 18.530 200 970820.168 15.228 + 37 119 82 201 Pb -25271.036 13.747 7877.877 0.068 B- -3854.603 20.481 200 972870.425 14.758 + 35 118 83 201 Bi +a -21416.433 15.183 7854.808 0.076 B- -4895.248 15.962 200 977008.512 16.299 + 33 117 84 201 Po -16521.185 4.942 7826.561 0.025 B- -5731.747 9.561 200 982263.777 5.305 + 31 116 85 201 At +a -10789.438 8.184 7794.153 0.041 B- -6717.113 50.401 200 988417.061 8.786 + 29 115 86 201 Rn -a -4072.324 49.732 7756.842 0.247 B- -7660.902 50.554 200 995628.179 53.389 + 27 114 87 201 Fr -a 3588.577 9.080 7714.836 0.045 B- -8348.224 22.239 201 003852.496 9.747 + 25 113 88 201 Ra -a 11936.801 20.301 7669.410 0.101 B- * 201 012814.683 21.794 +0 50 126 76 202 Os x -13087# 401# 7842# 2# B- 3689# 499# 201 985950# 430# + 48 125 77 202 Ir x -16776# 298# 7856# 1# B- 5916# 299# 201 981990# 320# + 46 124 78 202 Pt x -22692.125 25.150 7881.560 0.125 B- 1660.854 34.276 201 975639.000 27.000 + 44 123 79 202 Au x -24352.979 23.287 7885.909 0.115 B- 2992.345 23.298 201 973856.000 25.000 + 42 122 80 202 Hg -27345.324 0.705 7896.850 0.003 B- -1365.108 1.636 201 970643.585 0.756 + 40 121 81 202 Tl -25980.216 1.606 7886.219 0.008 B- -39.602 4.096 201 972109.089 1.723 + 38 120 82 202 Pb -25940.614 3.796 7882.150 0.019 B- -5199.130 15.856 201 972151.604 4.075 + 36 119 83 202 Bi -20741.484 15.396 7852.539 0.076 B- -2799.868 17.666 201 977733.100 16.528 + 34 118 84 202 Po -17941.616 8.670 7834.805 0.043 B- -7350.884 29.289 201 980738.881 9.307 + 32 117 85 202 At -a -10590.732 27.977 7794.541 0.138 B- -4316.097 33.010 201 988630.380 30.034 + 30 116 86 202 Rn -a -6274.635 17.520 7769.301 0.087 B- -9370.871 18.881 201 993263.902 18.808 + 28 115 87 202 Fr -a 3096.237 7.040 7719.038 0.035 B- -5978.625 16.586 202 003323.946 7.557 + 26 114 88 202 Ra -a 9074.861 15.018 7685.568 0.074 B- * 202 009742.264 16.122 +0 51 127 76 203 Os x -7640# 401# 7816# 2# B- 7050# 566# 202 991798# 430# + 49 126 77 203 Ir x -14690# 401# 7847# 2# B- 4937# 446# 202 984230# 430# + 47 125 78 203 Pt x -19627# 196# 7867# 1# B- 3517# 196# 202 978930# 210# + 45 124 79 203 Au -23143.436 3.083 7880.864 0.015 B- 2125.829 3.451 202 975154.498 3.309 + 43 123 80 203 Hg -25269.265 1.627 7887.482 0.008 B- 492.112 1.225 202 972872.326 1.746 + 41 122 81 203 Tl -25761.377 1.166 7886.053 0.006 B- -974.820 6.461 202 972344.022 1.252 + 39 121 82 203 Pb -24786.557 6.554 7877.397 0.032 B- -3261.729 14.356 202 973390.535 7.036 + 37 120 83 203 Bi +a -21524.827 12.778 7857.475 0.063 B- -4213.939 15.433 202 976892.145 13.717 + 35 119 84 203 Po +a -17310.889 8.655 7832.863 0.043 B- -5148.332 13.666 202 981415.995 9.291 + 33 118 85 203 At -12162.557 10.576 7803.648 0.052 B- -6008.858 21.027 202 986942.957 11.353 + 31 117 86 203 Rn -a -6153.699 18.179 7770.193 0.090 B- -7030.116 19.218 202 993393.732 19.516 + 29 116 87 203 Fr 876.417 6.232 7731.708 0.031 B- -7785.309 38.630 203 000940.872 6.689 + 27 115 88 203 Ra -a 8661.726 38.124 7689.503 0.188 B- * 203 009298.745 40.928 +0 50 127 77 204 Ir x -9688# 401# 7824# 2# B- 8234# 446# 203 989600# 430# + 48 126 78 204 Pt x -17922# 196# 7860# 1# B- 2728# 280# 203 980760# 210# + 46 125 79 204 Au + -20650# 200# 7870# 1# B- 4040# 200# 203 977831# 215# + 44 124 80 204 Hg -24690.145 0.498 7885.545 0.002 B- -344.000 1.186 203 973494.037 0.534 + 42 123 81 204 Tl -24346.145 1.152 7880.023 0.006 B- 763.748 0.177 203 973863.337 1.236 + 40 122 82 204 Pb -25109.892 1.146 7879.932 0.006 B- -4463.996 9.248 203 973043.420 1.230 + 38 121 83 204 Bi +a -20645.896 9.180 7854.215 0.045 B- -2304.652 14.335 203 977835.717 9.854 + 36 120 84 204 Po -a -18341.244 11.013 7839.083 0.054 B- -6465.811 24.860 203 980309.863 11.822 + 34 119 85 204 At -11875.433 22.288 7803.552 0.109 B- -3905.240 23.498 203 987251.197 23.926 + 32 118 86 204 Rn -7970.193 7.444 7780.574 0.036 B- -8577.503 25.684 203 991443.644 7.991 + 30 117 87 204 Fr -a 607.310 24.581 7734.692 0.120 B- -5449.477 28.940 204 000651.974 26.389 + 28 116 88 204 Ra -a 6056.787 15.273 7704.144 0.075 B- * 204 006502.228 16.396 +0 51 128 77 205 Ir x -5960# 503# 7807# 2# B- 7007# 585# 204 993602# 540# + 49 127 78 205 Pt x -12966# 298# 7837# 1# B- 5803# 357# 204 986080# 320# + 47 126 79 205 Au x -18770# 196# 7861# 1# B- 3518# 196# 204 979850# 210# + 45 125 80 205 Hg -22287.740 3.654 7874.732 0.018 B- 1533.135 3.724 204 976073.125 3.923 + 43 124 81 205 Tl -23820.874 1.237 7878.394 0.006 B- -50.636 0.503 204 974427.237 1.328 + 41 123 82 205 Pb -23770.239 1.144 7874.331 0.006 B- -2705.734 5.107 204 974481.597 1.228 + 39 122 83 205 Bi -21064.504 5.111 7857.316 0.025 B- -3543.106 11.280 204 977386.323 5.487 + 37 121 84 205 Po -17521.398 10.059 7836.216 0.049 B- -4549.452 18.130 204 981190.004 10.798 + 35 120 85 205 At +a -12971.946 15.085 7810.207 0.074 B- -5262.161 15.913 204 986074.041 16.194 + 33 119 86 205 Rn -7709.786 5.080 7780.722 0.025 B- -6399.973 9.329 204 991723.204 5.453 + 31 118 87 205 Fr x -1309.813 7.824 7745.686 0.038 B- -7148.804 70.954 204 998593.858 8.399 + 29 117 88 205 Ra -a 5838.991 70.521 7706.998 0.344 B- -8267.702 86.923 205 006268.415 75.707 + 27 116 89 205 Ac -a 14106.693 50.818 7662.851 0.248 B- * 205 015144.158 54.555 +0 50 128 78 206 Pt x -9632# 298# 7822# 1# B- 4583# 422# 205 989660# 320# + 48 127 79 206 Au x -14215# 298# 7840# 1# B- 6731# 299# 205 984740# 320# + 46 126 80 206 Hg +a -20945.801 20.440 7869.172 0.099 B- 1307.566 20.410 205 977513.756 21.943 + 44 125 81 206 Tl -22253.367 1.284 7871.721 0.006 B- 1532.217 0.612 205 976110.026 1.378 + 42 124 82 206 Pb -23785.584 1.144 7875.362 0.006 B- -3757.306 7.546 205 974465.124 1.227 + 40 123 83 206 Bi - -20028.278 7.632 7853.324 0.037 B- -1839.604 8.600 205 978498.757 8.193 + 38 122 84 206 Po -a -18188.674 4.012 7840.597 0.019 B- -5758.956 15.580 205 980473.654 4.306 + 36 121 85 206 At -12429.718 15.056 7808.843 0.073 B- -3296.753 17.330 205 986656.148 16.162 + 34 120 86 206 Rn -9132.965 8.591 7789.041 0.042 B- -7890.549 29.475 205 990195.358 9.223 + 32 119 87 206 Fr -a -1242.416 28.195 7746.940 0.137 B- -4807.955 33.455 205 998666.211 30.268 + 30 118 88 206 Ra -a 3565.539 18.008 7719.802 0.087 B- -9913.913 53.608 206 003827.763 19.332 + 28 117 89 206 Ac -a 13479.452 50.493 7667.879 0.245 B- * 206 014470.787 54.206 +0 51 129 78 207 Pt x -4540# 401# 7798# 2# B- 6270# 500# 206 995126# 430# + 49 128 79 207 Au x -10810# 300# 7825# 1# B- 5677# 301# 206 988395# 322# + 47 127 80 207 Hg x -16487.444 29.808 7848.610 0.144 B- 4547.008 30.300 206 982300.000 32.000 + 45 126 81 207 Tl -21034.451 5.439 7866.797 0.026 B- 1417.595 5.402 206 977418.586 5.839 + 43 125 82 207 Pb -22452.047 1.147 7869.866 0.006 B- -2397.420 2.118 206 975896.735 1.230 + 41 124 83 207 Bi -20054.627 2.397 7854.505 0.012 B- -2908.852 6.614 206 978470.471 2.573 + 39 123 84 207 Po -17145.775 6.659 7836.673 0.032 B- -3918.358 14.075 206 981593.252 7.148 + 37 122 85 207 At +a -13227.416 12.406 7813.964 0.060 B- -4592.654 15.037 206 985799.783 13.318 + 35 121 86 207 Rn +a -8634.762 8.497 7787.998 0.041 B- -5790.421 19.458 206 990730.200 9.121 + 33 120 87 207 Fr -2844.341 17.505 7756.246 0.085 B- -6388.826 56.008 206 996946.474 18.792 + 31 119 88 207 Ra -a 3544.485 53.202 7721.602 0.257 B- -7601.748 73.276 207 003805.161 57.115 + 29 118 89 207 Ac -a 11146.233 50.387 7681.099 0.243 B- * 207 011965.973 54.092 +0 52 130 78 208 Pt x -990# 400# 7783# 2# B- 5111# 499# 207 998937# 429# + 50 129 79 208 Au x -6101# 298# 7804# 1# B- 7164# 300# 207 993450# 320# + 48 128 80 208 Hg x -13265.406 30.739 7834.191 0.148 B- 3484.726 30.795 207 985759.000 33.000 + 46 127 81 208 Tl +a -16750.132 1.854 7847.183 0.009 B- 4998.466 1.669 207 982017.992 1.990 + 44 126 82 208 Pb -21748.598 1.148 7867.453 0.006 B- -2878.375 2.013 207 976651.918 1.231 + 42 125 83 208 Bi +n -18870.223 2.304 7849.853 0.011 B- -1400.628 2.397 207 979741.981 2.473 + 40 124 84 208 Po -a -17469.596 1.737 7839.358 0.008 B- -4999.725 9.086 207 981245.616 1.864 + 38 123 85 208 At +a -12469.871 8.921 7811.560 0.043 B- -2814.279 14.269 207 986613.042 9.577 + 36 122 86 208 Rn -a -9655.591 11.138 7794.268 0.054 B- -6989.672 16.251 207 989634.295 11.957 + 34 121 87 208 Fr -2665.919 11.834 7756.903 0.057 B- -4393.774 14.881 207 997138.018 12.704 + 32 120 88 208 Ra -a 1727.856 9.023 7732.017 0.043 B- -9025.380 56.442 208 001854.929 9.686 + 30 119 89 208 Ac -a 10753.235 55.716 7684.865 0.268 B- -5930.495 65.370 208 011544.073 59.813 + 28 118 90 208 Th -a 16683.730 34.190 7652.592 0.164 B- * 208 017910.722 36.704 +0 51 130 79 209 Au x -2540# 400# 7788# 2# B- 6104# 426# 208 997273# 429# + 49 129 80 209 Hg x -8644# 149# 7813# 1# B- 5000# 149# 208 990720# 160# + 47 128 81 209 Tl +a -13644.757 6.110 7833.397 0.029 B- 3969.889 6.211 208 985351.750 6.559 + 45 127 82 209 Pb -17614.646 1.747 7848.648 0.008 B- 644.016 1.146 208 981089.898 1.875 + 43 126 83 209 Bi -18258.662 1.364 7847.987 0.007 B- -1892.570 1.564 208 980398.519 1.464 + 41 125 84 209 Po -a -16366.092 1.778 7835.188 0.009 B- -3483.478 5.287 208 982430.276 1.908 + 39 124 85 209 At -12882.613 5.102 7814.777 0.024 B- -3941.564 11.188 208 986169.944 5.477 + 37 123 86 209 Rn -8941.049 9.960 7792.175 0.048 B- -5171.477 17.713 208 990401.388 10.692 + 35 122 87 209 Fr x -3769.572 14.648 7763.688 0.070 B- -5627.791 15.730 208 995953.197 15.725 + 33 121 88 209 Ra -a 1858.219 5.747 7733.017 0.027 B- -6985.590 50.934 209 001994.879 6.169 + 31 120 89 209 Ac -a 8843.809 50.608 7695.850 0.242 B- -7523# 148# 209 009494.220 54.330 + 29 119 90 209 Th IT 16367# 140# 7656# 1# B- * 209 017571# 150# +0 52 131 79 210 Au x 2329# 401# 7766# 2# B- 7694# 446# 210 002500# 430# + 50 130 80 210 Hg x -5365# 196# 7799# 1# B- 3882# 196# 209 994240# 210# + 48 129 81 210 Tl +a -9246.969 11.604 7813.588 0.055 B- 5481.534 11.561 209 990072.970 12.456 + 46 128 82 210 Pb -14728.502 1.447 7835.965 0.007 B- 63.476 0.499 209 984188.301 1.553 + 44 127 83 210 Bi -14791.979 1.363 7832.542 0.006 B- 1161.159 0.766 209 984120.156 1.462 + 42 126 84 210 Po -15953.137 1.146 7834.346 0.005 B- -3980.960 7.610 209 982873.601 1.230 + 40 125 85 210 At -a -11972.177 7.695 7811.663 0.037 B- -2367.407 8.922 209 987147.338 8.261 + 38 124 86 210 Rn -a -9604.770 4.557 7796.665 0.022 B- -6271.565 15.824 209 989688.854 4.892 + 36 123 87 210 Fr -3333.205 15.154 7763.075 0.072 B- -3775.997 17.720 209 996421.657 16.268 + 34 122 88 210 Ra -a 442.792 9.193 7741.368 0.044 B- -8346.908 58.133 210 000475.356 9.868 + 32 121 89 210 Ac -a 8789.699 57.402 7697.896 0.273 B- -5269.747 60.436 210 009436.130 61.623 + 30 120 90 210 Th -a 14059.446 18.909 7669.076 0.090 B- * 210 015093.437 20.299 +0 51 131 80 211 Hg x -624# 196# 7778# 1# B- 5454# 200# 210 999330# 210# + 49 130 81 211 Tl x -6077.998 41.917 7799.791 0.199 B- 4414.950 41.978 210 993475.000 45.000 + 47 129 82 211 Pb -10492.948 2.261 7817.007 0.011 B- 1366.183 5.471 210 988735.356 2.426 + 45 128 83 211 Bi -11859.131 5.442 7819.774 0.026 B- 573.439 5.430 210 987268.698 5.842 + 43 127 84 211 Po -a -12432.571 1.255 7818.784 0.006 B- -785.307 2.539 210 986653.085 1.347 + 41 126 85 211 At -a -11647.264 2.729 7811.354 0.013 B- -2891.860 6.894 210 987496.147 2.929 + 39 125 86 211 Rn -a -8755.404 6.813 7793.941 0.032 B- -4615.155 13.786 210 990600.686 7.314 + 37 124 87 211 Fr -4140.249 11.991 7768.360 0.057 B- -4972.272 14.369 210 995555.259 12.872 + 35 123 88 211 Ra x 832.023 7.918 7741.087 0.038 B- -6370.191 53.564 211 000893.213 8.500 + 33 122 89 211 Ac -a 7202.214 52.976 7707.189 0.251 B- -6707.958 90.205 211 007731.894 56.871 + 31 121 90 211 Th -a 13910.171 73.010 7671.690 0.346 B- -8170# 126# 211 014933.183 78.379 + 29 120 91 211 Pa x 22080# 102# 7629# 0# B- * 211 023704# 110# +0 52 132 80 212 Hg x 2757# 298# 7763# 1# B- 4308# 359# 212 002960# 320# + 50 131 81 212 Tl +a -1551# 200# 7780# 1# B- 5998# 200# 211 998335# 215# + 48 130 82 212 Pb -7548.850 1.842 7804.319 0.009 B- 569.104 1.825 211 991895.975 1.977 + 46 129 83 212 Bi -8117.954 1.854 7803.313 0.009 B- 2251.533 1.667 211 991285.016 1.989 + 44 128 84 212 Po -10369.487 1.152 7810.243 0.005 B- -1741.266 2.107 211 988867.896 1.236 + 42 127 85 212 At -a -8628.221 2.384 7798.340 0.011 B- 31.387 3.605 211 990737.223 2.559 + 40 126 86 212 Rn -a -8659.608 3.145 7794.797 0.015 B- -5143.640 9.318 211 990703.528 3.376 + 38 125 87 212 Fr -3515.968 8.775 7766.845 0.041 B- -3317.000 14.276 211 996225.453 9.420 + 36 124 88 212 Ra -a -198.968 11.263 7747.508 0.053 B- -7476.266 52.601 211 999786.399 12.091 + 34 123 89 212 Ac -a 7277.298 51.381 7708.552 0.242 B- -4833.510 52.366 212 007812.501 55.160 + 32 122 90 212 Th -a 12110.808 10.109 7682.062 0.048 B- -9482.551 75.541 212 013001.487 10.852 + 30 121 91 212 Pa -a 21593.358 74.862 7633.643 0.353 B- * 212 023181.425 80.367 +0 53 133 80 213 Hg x 7666# 298# 7741# 1# B- 5882# 299# 213 008230# 320# + 51 132 81 213 Tl x 1783.811 27.013 7765.430 0.127 B- 4987.343 27.894 213 001915.000 29.000 + 49 131 82 213 Pb +a -3203.532 6.954 7785.172 0.033 B- 2028.103 8.371 212 996560.867 7.465 + 47 130 83 213 Bi -5231.635 5.082 7791.021 0.024 B- 1421.949 5.490 212 994383.608 5.456 + 45 129 84 213 Po -6653.584 3.053 7794.024 0.014 B- -73.989 5.465 212 992857.083 3.277 + 43 128 85 213 At -a -6579.595 4.898 7790.003 0.023 B- -883.569 5.724 212 992936.514 5.257 + 41 127 86 213 Rn -a -5696.026 3.370 7782.182 0.016 B- -2143.179 6.006 212 993885.064 3.617 + 39 126 87 213 Fr -3552.848 5.091 7768.447 0.024 B- -3898.405 11.057 212 996185.861 5.465 + 37 125 88 213 Ra 345.557 9.818 7746.472 0.046 B- -5809.134 18.156 213 000370.970 10.540 + 35 124 89 213 Ac -a 6154.692 15.272 7715.526 0.072 B- -5965.394 17.834 213 006607.333 16.395 + 33 123 90 213 Th -a 12120.086 9.217 7683.846 0.043 B- -7542.539 71.737 213 013011.447 9.895 + 31 122 91 213 Pa -a 19662.625 71.142 7644.762 0.334 B- * 213 021108.697 76.374 +0 54 134 80 214 Hg x 11178# 401# 7727# 2# B- 4713# 446# 214 012000# 430# + 52 133 81 214 Tl x 6465# 196# 7745# 1# B- 6647# 196# 214 006940# 210# + 50 132 82 214 Pb -182.769 1.975 7772.394 0.009 B- 1017.984 11.256 213 999803.788 2.120 + 48 131 83 214 Bi -1200.753 11.209 7773.495 0.052 B- 3269.293 11.165 213 998710.938 12.033 + 46 130 84 214 Po -4470.046 1.449 7785.116 0.007 B- -1090.215 4.107 213 995201.208 1.555 + 44 129 85 214 At -a -3379.831 4.298 7776.366 0.020 B- 939.911 10.014 213 996371.601 4.614 + 42 128 86 214 Rn -a -4319.742 9.187 7777.102 0.043 B- -3361.035 12.503 213 995362.566 9.862 + 40 127 87 214 Fr -a -958.707 8.634 7757.740 0.040 B- -1051.441 10.086 213 998970.785 9.268 + 38 126 88 214 Ra -a 92.734 5.250 7749.171 0.025 B- -6351.120 16.232 214 000099.554 5.636 + 36 125 89 214 Ac -a 6443.854 15.360 7715.837 0.072 B- -4251.030 18.693 214 006917.762 16.489 + 34 124 90 214 Th -a 10694.885 10.661 7692.317 0.050 B- -8790.630 76.867 214 011481.431 11.445 + 32 123 91 214 Pa -a 19485.515 76.125 7647.583 0.356 B- * 214 020918.561 81.723 +0 55 135 80 215 Hg x 16208# 401# 7705# 2# B- 6297# 499# 215 017400# 430# + 53 134 81 215 Tl x 9911# 298# 7730# 1# B- 5569# 303# 215 010640# 320# + 51 133 82 215 Pb +a 4342.244 52.448 7752.737 0.244 B- 2712.922 52.748 215 004661.590 56.304 + 49 132 83 215 Bi 1629.322 5.624 7761.717 0.026 B- 2171.028 5.530 215 001749.149 6.037 + 47 131 84 215 Po -541.706 2.121 7768.176 0.010 B- 714.049 6.819 214 999418.454 2.276 + 45 130 85 215 At -a -1255.756 6.799 7767.858 0.032 B- -87.195 10.168 214 998651.890 7.299 + 43 129 86 215 Rn -a -1168.561 7.672 7763.814 0.036 B- -1486.625 10.306 214 998745.498 8.236 + 41 128 87 215 Fr -a 318.065 7.066 7753.260 0.033 B- -2215.674 10.077 215 000341.456 7.585 + 39 127 88 215 Ra -a 2533.739 7.613 7739.316 0.035 B- -3496.877 14.551 215 002720.080 8.172 + 37 126 89 215 Ac -a 6030.615 12.406 7719.413 0.058 B- -4890.971 15.234 215 006474.132 13.318 + 35 125 90 215 Th -a 10921.586 8.840 7693.025 0.041 B- -6942.353 73.380 215 011724.805 9.490 + 33 124 91 215 Pa -a 17863.939 72.845 7657.096 0.339 B- -7059.147 114.616 215 019177.728 78.202 + 31 123 92 215 U -a 24923.087 88.490 7620.624 0.412 B- * 215 026756.035 94.997 +0 56 136 80 216 Hg x 19859# 401# 7690# 2# B- 5142# 499# 216 021320# 430# + 54 135 81 216 Tl x 14718# 298# 7710# 1# B- 7238# 357# 216 015800# 320# + 52 134 82 216 Pb x 7480# 196# 7740# 1# B- 1606# 196# 216 008030# 210# + 50 133 83 216 Bi x 5873.991 11.178 7743.499 0.052 B- 4091.571 11.324 216 006305.989 12.000 + 48 132 84 216 Po 1782.420 1.816 7758.819 0.008 B- -474.246 3.571 216 001913.506 1.949 + 46 131 85 216 At -a 2256.666 3.575 7753.002 0.017 B- 2003.799 6.836 216 002422.631 3.837 + 44 130 86 216 Rn -a 252.868 5.994 7758.657 0.028 B- -2718.082 7.126 216 000271.464 6.435 + 42 129 87 216 Fr -a 2970.950 4.173 7742.451 0.019 B- -320.128 9.548 216 003189.445 4.480 + 40 128 88 216 Ra -a 3291.077 8.737 7737.347 0.040 B- -4853.317 13.921 216 003533.117 9.379 + 38 127 89 216 Ac -a 8144.395 10.840 7711.256 0.050 B- -2153.937 16.201 216 008743.367 11.637 + 36 126 90 216 Th -a 10298.332 12.042 7697.662 0.056 B- -7500.882 54.864 216 011055.714 12.928 + 34 125 91 216 Pa -a 17799.214 53.526 7659.314 0.248 B- -5267.137 60.450 216 019108.242 57.462 + 32 124 92 216 U -a 23066.351 28.093 7631.307 0.130 B- * 216 024762.747 30.158 +0 55 136 81 217 Tl x 18313# 401# 7695# 2# B- 6073# 499# 217 019660# 430# + 53 135 82 217 Pb x 12240# 298# 7719# 1# B- 3510# 299# 217 013140# 320# + 51 134 83 217 Bi x 8729.962 17.698 7731.848 0.082 B- 2846.444 18.870 217 009372.000 19.000 + 49 133 84 217 Po +a 5883.518 6.544 7741.360 0.030 B- 1488.883 7.979 217 006316.216 7.025 + 47 132 85 217 At 4394.635 5.001 7744.616 0.023 B- 736.135 6.151 217 004717.835 5.369 + 45 131 86 217 Rn -a 3658.501 4.198 7744.403 0.019 B- -656.089 7.538 217 003927.562 4.506 + 43 130 87 217 Fr -a 4314.590 6.531 7737.775 0.030 B- -1575.067 9.588 217 004631.902 7.010 + 41 129 88 217 Ra -a 5889.656 7.202 7726.911 0.033 B- -2814.017 13.430 217 006322.806 7.731 + 39 128 89 217 Ac -a 8703.673 11.389 7710.338 0.052 B- -3502.107 15.566 217 009343.777 12.226 + 37 127 90 217 Th -a 12205.780 10.614 7690.594 0.049 B- -4862.630 19.132 217 013103.444 11.394 + 35 126 91 217 Pa -a 17068.410 15.918 7664.580 0.073 B- -5905# 73# 217 018323.692 17.089 + 33 125 92 217 U -a 22973# 71# 7634# 0# B- * 217 024663# 77# +0 56 137 81 218 Tl x 23180# 400# 7674# 2# B- 7727# 499# 218 024885# 429# + 54 136 82 218 Pb x 15453# 298# 7706# 1# B- 2237# 299# 218 016590# 320# + 52 135 83 218 Bi x 13216.037 27.013 7712.827 0.124 B- 4859.136 27.085 218 014188.000 29.000 + 50 134 84 218 Po 8356.901 1.973 7731.528 0.009 B- 258.738 11.649 218 008971.502 2.118 + 48 133 85 218 At -a 8098.162 11.604 7729.126 0.053 B- 2880.816 11.705 218 008693.735 12.456 + 46 132 86 218 Rn 5217.347 2.316 7738.752 0.011 B- -1841.770 4.942 218 005601.052 2.486 + 44 131 87 218 Fr -a 7059.117 4.757 7726.715 0.022 B- 407.947 12.039 218 007578.274 5.106 + 42 130 88 218 Ra -a 6651.170 11.176 7724.998 0.051 B- -4192.439 51.931 218 007140.325 11.997 + 40 129 89 218 Ac -a 10843.609 50.740 7702.177 0.233 B- -1523.132 51.815 218 011641.093 54.471 + 38 128 90 218 Th -a 12366.741 10.516 7691.602 0.048 B- -6317.029 21.130 218 013276.242 11.289 + 36 127 91 218 Pa -a 18683.770 18.329 7659.036 0.084 B- -3210.838 22.888 218 020057.853 19.676 + 34 126 92 218 U -a 21894.608 13.714 7640.719 0.063 B- * 218 023504.829 14.722 +0 55 137 82 219 Pb x 20279# 401# 7686# 2# B- 3996# 446# 219 021770# 430# + 53 136 83 219 Bi x 16283# 196# 7700# 1# B- 3601# 196# 219 017480# 210# + 51 135 84 219 Po x 12681.359 15.835 7713.333 0.072 B- 2285.283 16.163 219 013614.000 17.000 + 49 134 85 219 At 10396.076 3.237 7720.196 0.015 B- 1566.675 2.947 219 011160.647 3.474 + 47 133 86 219 Rn 8829.402 2.100 7723.777 0.010 B- 211.635 7.058 219 009478.753 2.254 + 45 132 87 219 Fr -a 8617.767 7.039 7721.171 0.032 B- -776.515 10.772 219 009251.553 7.556 + 43 131 88 219 Ra -a 9394.282 8.258 7714.053 0.038 B- -2175.199 51.142 219 010085.176 8.865 + 41 130 89 219 Ac -a 11569.480 50.497 7700.549 0.231 B- -2901.910 71.425 219 012420.348 54.210 + 39 129 90 219 Th -a 14471.390 50.576 7683.725 0.231 B- -4068.741 72.192 219 015535.677 54.295 + 37 128 91 219 Pa -a 18540.131 51.516 7661.574 0.235 B- -4746.439 72.333 219 019903.650 55.304 + 35 127 92 219 U -a 23286.569 50.775 7636.329 0.232 B- -6170.086 101.905 219 024999.161 54.509 + 33 126 93 219 Np -a 29456.655 88.354 7604.583 0.403 B- * 219 031623.021 94.851 +0 56 138 82 220 Pb x 23669# 401# 7672# 2# B- 2850# 499# 220 025410# 430# + 54 137 83 220 Bi x 20819# 298# 7682# 1# B- 5555# 299# 220 022350# 320# + 52 136 84 220 Po x 15263.461 17.698 7703.224 0.080 B- 887.714 22.549 220 016386.000 19.000 + 50 135 85 220 At x 14375.747 13.972 7703.703 0.064 B- 3763.670 14.090 220 015433.000 15.000 + 48 134 86 220 Rn 10612.077 1.815 7717.254 0.008 B- -870.242 4.026 220 011392.534 1.948 + 46 133 87 220 Fr -a 11482.320 4.028 7709.742 0.018 B- 1212.075 9.061 220 012326.778 4.324 + 44 132 88 220 Ra -a 10270.245 8.237 7711.696 0.037 B- -3473.437 10.141 220 011025.562 8.843 + 42 131 89 220 Ac -a 13743.682 6.129 7692.351 0.028 B- -925.417 22.941 220 014754.450 6.579 + 40 130 90 220 Th -a 14669.100 22.166 7684.589 0.101 B- -5549# 56# 220 015747.926 23.795 + 38 129 91 220 Pa -a 20218# 51# 7656# 0# B- -2715# 113# 220 021705# 55# + 36 128 92 220 U -a 22933# 101# 7640# 0# B- -7378# 220# 220 024620# 108# + 34 127 93 220 Np x 30311# 196# 7603# 1# B- * 220 032540# 210# +0 55 138 83 221 Bi x 24098# 298# 7668# 1# B- 4324# 299# 221 025870# 320# + 53 137 84 221 Po x 19773.755 19.561 7684.481 0.089 B- 2991.027 24.039 221 021228.000 21.000 + 51 136 85 221 At x 16782.727 13.972 7694.475 0.063 B- 2311.308 15.096 221 018017.000 15.000 + 49 135 86 221 Rn +a 14471.420 5.714 7701.393 0.026 B- 1194.130 7.231 221 015535.709 6.134 + 47 134 87 221 Fr 13277.290 4.886 7703.256 0.022 B- 313.479 6.386 221 014253.757 5.245 + 45 133 88 221 Ra -a 12963.811 4.630 7701.135 0.021 B- -1559.298 50.603 221 013917.224 4.970 + 43 132 89 221 Ac -a 14523.109 50.425 7690.539 0.228 B- -2417.261 51.056 221 015591.199 54.133 + 41 131 90 221 Th -a 16940.371 8.166 7676.061 0.037 B- -3435.918 51.915 221 018186.236 8.766 + 39 130 91 221 Pa -a 20376.288 51.281 7656.974 0.232 B- -4143.707 72.404 221 021874.846 55.052 + 37 129 92 221 U -a 24519.995 51.114 7634.684 0.231 B- -5330# 207# 221 026323.299 54.873 + 35 128 93 221 Np x 29850# 200# 7607# 1# B- * 221 032045# 215# +0 56 139 83 222 Bi x 28729# 300# 7649# 1# B- 6243# 303# 222 030842# 322# + 54 138 84 222 Po x 22486.265 40.054 7674.005 0.180 B- 1533.239 43.071 222 024140.000 43.000 + 52 137 85 222 At x 20953.026 15.835 7677.387 0.071 B- 4580.820 15.955 222 022494.000 17.000 + 50 136 86 222 Rn 16372.206 1.950 7694.497 0.009 B- -5.900 7.703 222 017576.286 2.093 + 48 135 87 222 Fr x 16378.105 7.452 7690.947 0.034 B- 2057.917 8.682 222 017582.620 8.000 + 46 134 88 222 Ra 14320.188 4.454 7696.692 0.020 B- -2301.285 6.637 222 015373.355 4.781 + 44 133 89 222 Ac -a 16621.474 5.174 7682.802 0.023 B- -581.637 13.228 222 017843.887 5.554 + 42 132 90 222 Th -a 17203.111 12.279 7676.658 0.055 B- -4951# 74# 222 018468.300 13.182 + 40 131 91 222 Pa -a 22155# 72# 7651# 0# B- -2118# 89# 222 023784# 78# + 38 130 92 222 U -a 24272.827 51.994 7637.764 0.234 B- -6746# 202# 222 026057.953 55.817 + 36 129 93 222 Np x 31019# 196# 7604# 1# B- * 222 033300# 210# +0 57 140 83 223 Bi x 32137# 401# 7636# 2# B- 5058# 446# 223 034500# 430# + 55 139 84 223 Po x 27079# 196# 7655# 1# B- 3651# 196# 223 029070# 210# + 53 138 85 223 At x 23428.006 13.972 7668.055 0.063 B- 3038.267 16.013 223 025151.000 15.000 + 51 137 86 223 Rn 20389.739 7.822 7678.171 0.035 B- 2007.344 8.057 223 021889.285 8.397 + 49 136 87 223 Fr 18382.394 1.932 7683.664 0.009 B- 1149.085 0.848 223 019734.313 2.073 + 47 135 88 223 Ra 17233.309 2.090 7685.309 0.009 B- -592.573 7.128 223 018500.719 2.244 + 45 134 89 223 Ac -a 17825.882 7.110 7679.143 0.032 B- -1559.948 11.563 223 019136.872 7.632 + 43 133 90 223 Th -a 19385.831 9.212 7668.640 0.041 B- -2934.845 71.639 223 020811.546 9.889 + 41 132 91 223 Pa -a 22320.676 71.063 7651.971 0.319 B- -3516.330 100.506 223 023962.232 76.289 + 39 131 92 223 U -a 25837.006 71.119 7632.694 0.319 B- -4763# 208# 223 027737.168 76.349 + 37 130 93 223 Np x 30600# 196# 7608# 1# B- * 223 032850# 210# +0 58 141 83 224 Bi x 36830# 400# 7617# 2# B- 6920# 445# 224 039539# 429# + 56 140 84 224 Po x 29910# 196# 7644# 1# B- 2199# 197# 224 032110# 210# + 54 139 85 224 At x 27711.015 22.356 7650.735 0.100 B- 5265.917 24.415 224 029749.000 24.000 + 52 138 86 224 Rn 22445.098 9.814 7670.751 0.044 B- 696.482 14.875 224 024095.804 10.536 + 50 137 87 224 Fr x 21748.616 11.178 7670.367 0.050 B- 2922.699 11.324 224 023348.100 12.000 + 48 136 88 224 Ra 18825.917 1.813 7679.922 0.008 B- -1408.219 4.087 224 020210.453 1.945 + 46 135 89 224 Ac -a 20234.135 4.089 7670.143 0.018 B- 240.401 10.823 224 021722.239 4.389 + 44 134 90 224 Th -a 19993.734 10.120 7667.724 0.045 B- -3868.544 12.546 224 021464.157 10.864 + 42 133 91 224 Pa -a 23862.278 7.587 7646.961 0.034 B- -1859.974 24.329 224 025617.210 8.145 + 40 132 92 224 U -a 25722.252 23.171 7635.165 0.103 B- -6153# 197# 224 027613.974 24.875 + 38 131 93 224 Np x 31876# 196# 7604# 1# B- * 224 034220# 210# +0 57 141 84 225 Po x 34530# 298# 7626# 1# B- 4136# 422# 225 037070# 320# + 55 140 85 225 At x 30395# 298# 7641# 1# B- 3861# 298# 225 032630# 320# + 53 139 86 225 Rn 26534.141 11.140 7654.357 0.050 B- 2713.531 16.349 225 028485.574 11.958 + 51 138 87 225 Fr 23820.610 11.967 7662.940 0.053 B- 1827.501 12.158 225 025572.478 12.847 + 49 137 88 225 Ra 21993.109 2.596 7667.586 0.012 B- 355.763 5.007 225 023610.574 2.787 + 47 136 89 225 Ac 21637.346 4.758 7665.690 0.021 B- -672.781 6.658 225 023228.647 5.107 + 45 135 90 225 Th -a 22310.127 5.093 7659.222 0.023 B- -2030.598 71.170 225 023950.907 5.467 + 43 134 91 225 Pa -a 24340.725 71.012 7646.720 0.316 B- -3039.196 71.827 225 026130.844 76.234 + 41 133 92 225 U -a 27379.921 10.909 7629.736 0.048 B- -4207.783 72.440 225 029393.555 11.711 + 39 132 93 225 Np -a 31587.704 71.622 7607.557 0.318 B- * 225 033910.797 76.889 +0 58 142 84 226 Po x 37549# 401# 7614# 2# B- 2934# 499# 226 040310# 430# + 56 141 85 226 At x 34614# 298# 7624# 1# B- 5867# 298# 226 037160# 320# + 54 140 86 226 Rn 28747.192 10.477 7646.410 0.046 B- 1226.653 12.190 226 030861.382 11.247 + 52 139 87 226 Fr 27520.539 6.230 7648.376 0.028 B- 3852.715 6.523 226 029544.515 6.688 + 50 138 88 226 Ra 23667.824 1.933 7661.962 0.009 B- -641.440 3.274 226 025408.455 2.075 + 48 137 89 226 Ac 24309.264 3.100 7655.662 0.014 B- 1111.630 4.563 226 026097.069 3.328 + 46 136 90 226 Th 23197.634 4.481 7657.119 0.020 B- -2835.642 12.165 226 024903.686 4.810 + 44 135 91 226 Pa -a 26033.276 11.420 7641.110 0.051 B- -1295.593 17.228 226 027947.872 12.259 + 42 134 92 226 U -a 27328.869 12.999 7631.916 0.058 B- -5448# 89# 226 029338.749 13.955 + 40 133 93 226 Np -a 32777# 88# 7604# 0# B- * 226 035188# 95# +0 59 143 84 227 Po x 42281# 401# 7596# 2# B- 4797# 499# 227 045390# 430# + 57 142 85 227 At x 37483# 298# 7613# 1# B- 4597# 298# 227 040240# 320# + 55 141 86 227 Rn 32885.834 14.091 7630.050 0.062 B- 3203.388 15.276 227 035304.396 15.127 + 53 140 87 227 Fr 29682.445 5.898 7640.715 0.026 B- 2504.734 6.213 227 031865.417 6.332 + 51 139 88 227 Ra -n 27177.711 1.952 7648.303 0.009 B- 1328.132 2.265 227 029176.474 2.095 + 49 138 89 227 Ac 25849.580 1.927 7650.707 0.008 B- 44.757 0.830 227 027750.666 2.068 + 47 137 90 227 Th 25804.823 2.088 7647.458 0.009 B- -1026.375 7.437 227 027702.618 2.241 + 45 136 91 227 Pa -a 26831.198 7.420 7639.490 0.033 B- -2214.264 12.146 227 028804.477 7.965 + 43 135 92 227 U -a 29045.462 9.705 7626.289 0.043 B- -3516.618 73.135 227 031181.587 10.419 + 41 134 93 227 Np -a 32562.080 72.506 7607.351 0.319 B- -4208# 123# 227 034956.832 77.838 + 39 133 94 227 Pu x 36770# 100# 7585# 0# B- * 227 039474# 107# +0 58 143 85 228 At x 41684# 401# 7597# 2# B- 6441# 401# 228 044750# 430# + 56 142 86 228 Rn 35243.465 17.677 7621.645 0.078 B- 1859.244 18.916 228 037835.418 18.977 + 54 141 87 228 Fr 33384.221 6.732 7626.368 0.030 B- 4443.953 7.021 228 035839.437 7.226 + 52 140 88 228 Ra +a 28940.268 1.996 7642.428 0.009 B- 45.540 0.634 228 031068.657 2.142 + 50 139 89 228 Ac - 28894.728 2.094 7639.196 0.009 B- 2123.743 2.645 228 031019.767 2.247 + 48 138 90 228 Th 26770.984 1.807 7645.080 0.008 B- -2152.602 4.340 228 028739.835 1.940 + 46 137 91 228 Pa -a 28923.586 4.340 7632.207 0.019 B- -298.640 14.929 228 031050.748 4.659 + 44 136 92 228 U -a 29222.226 14.354 7627.466 0.063 B- -4373.468 52.545 228 031371.351 15.409 + 42 135 93 228 Np -a 33595.694 50.572 7604.853 0.222 B- -2491.677 58.346 228 036066.462 54.291 + 40 134 94 228 Pu -a 36087.370 29.143 7590.493 0.128 B- * 228 038741.387 31.286 +0 59 144 85 229 At x 44823# 401# 7585# 2# B- 5461# 401# 229 048120# 430# + 57 143 86 229 Rn x 39362.400 13.041 7605.622 0.057 B- 3694.138 13.967 229 042257.276 14.000 + 55 142 87 229 Fr 35668.262 5.001 7618.337 0.022 B- 3106.298 16.231 229 038291.455 5.368 + 53 141 88 229 Ra x 32561.963 15.441 7628.485 0.067 B- 1872.030 19.623 229 034956.707 16.576 + 51 140 89 229 Ac x 30689.933 12.109 7633.244 0.053 B- 1104.350 12.346 229 032947.000 13.000 + 49 139 90 229 Th 29585.583 2.405 7634.650 0.011 B- -311.325 3.715 229 031761.431 2.581 + 47 138 91 229 Pa 29896.908 3.280 7629.874 0.014 B- -1313.646 6.655 229 032095.652 3.521 + 45 137 92 229 U -a 31210.554 5.938 7620.721 0.026 B- -2569.122 87.031 229 033505.909 6.374 + 43 136 93 229 Np -a 33779.675 86.848 7606.086 0.379 B- -3615.915 100.792 229 036263.974 93.235 + 41 135 94 229 Pu -a 37395.590 51.176 7586.880 0.223 B- -4754.430 101.230 229 040145.819 54.939 + 39 134 95 229 Am -a 42150.020 87.348 7562.702 0.381 B- * 229 045249.909 93.772 +0 58 144 86 230 Rn x 42048# 196# 7596# 1# B- 2561# 196# 230 045140# 210# + 56 143 87 230 Fr 39486.768 6.541 7603.704 0.028 B- 4970.462 12.198 230 042390.791 7.022 + 54 142 88 230 Ra x 34516.306 10.296 7621.914 0.045 B- 677.924 18.888 230 037054.780 11.053 + 52 141 89 230 Ac x 33838.383 15.835 7621.460 0.069 B- 2975.789 15.882 230 036327.000 17.000 + 50 140 90 230 Th 30862.593 1.210 7630.996 0.005 B- -1311.014 2.833 230 033132.358 1.299 + 48 139 91 230 Pa 32173.607 3.038 7621.895 0.013 B- 558.605 4.592 230 034539.789 3.261 + 46 138 92 230 U -a 31615.002 4.509 7620.922 0.020 B- -3621.290 51.461 230 033940.102 4.841 + 44 137 93 230 Np -a 35236.291 51.288 7601.776 0.223 B- -1698.101 53.363 230 037827.716 55.059 + 42 136 94 230 Pu -a 36934.392 14.824 7590.991 0.064 B- -5998# 134# 230 039650.703 15.913 + 40 135 95 230 Am -a 42932# 133# 7562# 1# B- * 230 046089# 143# +0 59 145 86 231 Rn x 46454# 298# 7579# 1# B- 4373# 298# 231 049870# 320# + 57 144 87 231 Fr x 42080.575 7.731 7594.500 0.033 B- 3864.089 13.749 231 045175.357 8.300 + 55 143 88 231 Ra 38216.486 11.370 7607.841 0.049 B- 2453.636 17.301 231 041027.086 12.206 + 53 142 89 231 Ac x 35762.849 13.041 7615.076 0.056 B- 1946.959 13.098 231 038393.000 14.000 + 51 141 90 231 Th 33815.891 1.218 7620.118 0.005 B- 391.487 1.460 231 036302.853 1.308 + 49 140 91 231 Pa 33424.404 1.772 7618.426 0.008 B- -381.611 2.033 231 035882.575 1.902 + 47 139 92 231 U -a 33806.015 2.670 7613.387 0.012 B- -1818.498 50.577 231 036292.252 2.866 + 45 138 93 231 Np -a 35624.513 50.547 7602.128 0.219 B- -2684.492 55.333 231 038244.490 54.264 + 43 137 94 231 Pu -a 38309.005 22.549 7587.120 0.098 B- -4101# 301# 231 041126.410 24.206 + 41 136 95 231 Am x 42410# 300# 7566# 1# B- -4860# 424# 231 045529# 322# + 39 135 96 231 Cm x 47270# 300# 7542# 1# B- * 231 050746# 322# +0 58 145 87 232 Fr x 46072.834 13.972 7579.347 0.060 B- 5575.880 16.702 232 049461.224 15.000 + 56 144 88 232 Ra 40496.953 9.151 7600.009 0.039 B- 1342.534 15.931 232 043475.270 9.823 + 54 143 89 232 Ac x 39154.419 13.041 7602.424 0.056 B- 3707.635 13.118 232 042034.000 14.000 + 52 142 90 232 Th 35446.784 1.422 7615.033 0.006 B- -499.850 7.734 232 038053.689 1.526 + 50 141 91 232 Pa + 35946.633 7.645 7609.506 0.033 B- 1337.103 7.428 232 038590.300 8.207 + 48 140 92 232 U 34609.530 1.809 7611.897 0.008 B- -2750# 100# 232 037154.860 1.942 + 46 139 93 232 Np - 37360# 100# 7597# 0# B- -1004# 102# 232 040107# 107# + 44 138 94 232 Pu -a 38363.140 17.595 7588.974 0.076 B- -4976# 300# 232 041184.526 18.888 + 42 137 95 232 Am x 43340# 300# 7564# 1# B- -2973# 362# 232 046527# 322# + 40 136 96 232 Cm -a 46312# 202# 7548# 1# B- * 232 049718# 217# +0 59 146 87 233 Fr x 48920.051 19.561 7569.239 0.084 B- 4585.991 21.369 233 052517.838 21.000 + 57 145 88 233 Ra 44334.060 8.603 7585.564 0.037 B- 3026.027 15.623 233 047594.573 9.235 + 55 144 89 233 Ac x 41308.033 13.041 7595.193 0.056 B- 2576.318 13.118 233 044346.000 14.000 + 53 143 90 233 Th 38731.715 1.425 7602.893 0.006 B- 1242.243 1.122 233 041580.208 1.529 + 51 142 91 233 Pa 37489.472 1.336 7604.866 0.006 B- 570.296 1.975 233 040246.605 1.434 + 49 141 92 233 U 36919.176 2.255 7603.956 0.010 B- -1029.415 51.005 233 039634.367 2.420 + 47 140 93 233 Np -a 37948.590 50.981 7596.181 0.219 B- -2103.179 71.642 233 040739.489 54.729 + 45 139 94 233 Pu -a 40051.769 50.351 7583.796 0.216 B- -3211# 113# 233 042997.345 54.054 + 43 138 95 233 Am -a 43263# 102# 7567# 0# B- -4031# 124# 233 046445# 109# + 41 137 96 233 Cm -a 47294.006 71.547 7545.998 0.307 B- -5567# 235# 233 050772.206 76.809 + 39 136 97 233 Bk -a 52861# 224# 7519# 1# B- * 233 056748# 240# +0 58 146 88 234 Ra x 46930.629 8.383 7576.543 0.036 B- 2089.439 16.294 234 050382.104 9.000 + 56 145 89 234 Ac x 44841.190 13.972 7582.129 0.060 B- 4228.181 14.210 234 048139.000 15.000 + 54 144 90 234 Th +a 40613.009 2.589 7596.855 0.011 B- 274.088 3.172 234 043599.860 2.779 + 52 143 91 234 Pa IT 40338.921 4.094 7594.683 0.017 B- 2193.896 4.000 234 043305.615 4.395 + 50 142 92 234 U 38145.025 1.130 7600.715 0.005 B- -1809.846 8.321 234 040950.370 1.213 + 48 141 93 234 Np - 39954.871 8.397 7589.637 0.036 B- -395.100 10.752 234 042893.320 9.014 + 46 140 94 234 Pu -a 40349.971 6.798 7584.605 0.029 B- -4111# 159# 234 043317.478 7.298 + 44 139 95 234 Am -a 44461# 159# 7564# 1# B- -2263# 159# 234 047731# 170# + 42 138 96 234 Cm -a 46724.633 17.394 7550.677 0.074 B- -6731# 143# 234 050160.959 18.673 + 40 137 97 234 Bk -a 53455# 142# 7519# 1# B- * 234 057387# 153# +0 59 147 88 235 Ra x 51130# 300# 7561# 1# B- 3773# 300# 235 054890# 322# + 57 146 89 235 Ac x 47357.155 13.972 7573.504 0.059 B- 3339.406 19.113 235 050840.000 15.000 + 55 145 90 235 Th x 44017.749 13.041 7584.385 0.055 B- 1728.853 19.113 235 047255.000 14.000 + 53 144 91 235 Pa x 42288.896 13.972 7588.413 0.059 B- 1370.050 14.017 235 045399.000 15.000 + 51 143 92 235 U 40918.846 1.117 7590.914 0.005 B- -124.262 0.852 235 043928.190 1.199 + 49 142 93 235 Np 41043.108 1.389 7587.056 0.006 B- -1139.302 20.499 235 044061.591 1.491 + 47 141 94 235 Pu -a 42182.410 20.521 7578.879 0.087 B- -2443.019 56.045 235 045284.682 22.030 + 45 140 95 235 Am -a 44625.429 52.192 7565.154 0.222 B- -3408# 208# 235 047907.371 56.030 + 43 139 96 235 Cm -a 48034# 201# 7547# 1# B- -4670# 448# 235 051567# 216# + 41 138 97 235 Bk x 52704# 401# 7524# 2# B- * 235 056580# 430# +0 58 147 89 236 Ac x 51220.992 38.191 7559.242 0.162 B- 4965.795 40.667 236 054988.000 41.000 + 56 146 90 236 Th x 46255.198 13.972 7576.968 0.059 B- 921.248 19.760 236 049657.000 15.000 + 54 145 91 236 Pa x 45333.950 13.972 7577.557 0.059 B- 2889.306 14.017 236 048668.000 15.000 + 52 144 92 236 U 42444.644 1.113 7586.484 0.005 B- -933.534 50.415 236 045566.201 1.194 + 50 143 93 236 Np IT 43378.178 50.421 7579.214 0.214 B- 476.585 50.389 236 046568.392 54.129 + 48 142 94 236 Pu 42901.593 1.811 7577.918 0.008 B- -3139# 112# 236 046056.756 1.944 + 46 141 95 236 Am -a 46041# 112# 7561# 0# B- -1814# 113# 236 049427# 120# + 44 140 96 236 Cm -a 47855.045 18.315 7550.299 0.078 B- -5687# 401# 236 051374.506 19.662 + 42 139 97 236 Bk x 53542# 401# 7523# 2# B- * 236 057480# 430# +0 59 148 89 237 Ac x 54020# 400# 7550# 2# B- 4065# 400# 237 057993# 429# + 57 147 90 237 Th x 49955.092 15.835 7563.443 0.067 B- 2427.473 20.514 237 053629.000 17.000 + 55 146 91 237 Pa x 47527.619 13.041 7570.384 0.055 B- 2137.425 13.096 237 051023.000 14.000 + 53 145 92 237 U 45390.194 1.203 7576.102 0.005 B- 518.534 0.520 237 048728.380 1.291 + 51 144 93 237 Np 44871.659 1.120 7574.989 0.005 B- -220.063 1.294 237 048171.710 1.202 + 49 143 94 237 Pu 45091.722 1.697 7570.759 0.007 B- -1478# 59# 237 048407.957 1.822 + 47 142 95 237 Am -a 46570# 59# 7561# 0# B- -2677# 93# 237 049995# 64# + 45 141 96 237 Cm -a 49247.085 70.960 7546.624 0.299 B- -3941# 235# 237 052868.923 76.178 + 43 140 97 237 Bk -a 53188# 224# 7527# 1# B- -4751# 241# 237 057100# 241# + 41 139 98 237 Cf -a 57938.921 87.287 7503.347 0.368 B- * 237 062199.993 93.706 +0 58 148 90 238 Th +a 52525# 283# 7555# 1# B- 1631# 284# 238 056388# 304# + 56 147 91 238 Pa x 50894.038 15.835 7558.344 0.067 B- 3586.255 15.906 238 054637.000 17.000 + 54 146 92 238 U 47307.783 1.493 7570.125 0.006 B- -146.874 1.201 238 050786.996 1.602 + 52 145 93 238 Np -n 47454.656 1.138 7566.221 0.005 B- 1291.443 0.457 238 050944.671 1.221 + 50 144 94 238 Pu 46163.213 1.139 7568.360 0.005 B- -2258.273 50.688 238 049558.250 1.222 + 48 143 95 238 Am -a 48421.487 50.700 7555.584 0.213 B- -1023.701 52.145 238 051982.607 54.428 + 46 142 96 238 Cm -a 49445.188 12.234 7547.996 0.051 B- -4771# 255# 238 053081.595 13.133 + 44 141 97 238 Bk -a 54216# 255# 7525# 1# B- -3061# 392# 238 058203# 274# + 42 140 98 238 Cf x 57278# 298# 7509# 1# B- * 238 061490# 320# +0 59 149 90 239 Th x 56450# 400# 7541# 2# B- 3113# 445# 239 060602# 429# + 57 148 91 239 Pa x 53337# 196# 7550# 1# B- 2765# 196# 239 057260# 210# + 55 147 92 239 U -n 50572.718 1.503 7558.561 0.006 B- 1261.661 1.493 239 054292.048 1.613 + 53 146 93 239 Np 49311.057 1.311 7560.567 0.005 B- 722.774 0.930 239 052937.599 1.407 + 51 145 94 239 Pu 48588.282 1.113 7560.318 0.005 B- -802.142 1.664 239 052161.669 1.195 + 49 144 95 239 Am -a 49390.424 1.982 7553.688 0.008 B- -1756.602 54.058 239 053022.803 2.128 + 47 143 96 239 Cm -a 51147.025 54.047 7543.065 0.226 B- -3103# 214# 239 054908.593 58.022 + 45 142 97 239 Bk -a 54250# 207# 7527# 1# B- -4019# 294# 239 058240# 222# + 43 141 98 239 Cf -a 58269# 209# 7507# 1# B- -5287# 364# 239 062554# 224# + 41 140 99 239 Es x 63556# 298# 7481# 1# B- * 239 068230# 320# +0 58 149 91 240 Pa x 56910# 200# 7538# 1# B- 4194# 200# 240 061095# 215# + 56 148 92 240 U 52715.505 2.553 7551.770 0.011 B- 399.233 17.083 240 056592.425 2.740 + 54 147 93 240 Np 52316.272 17.032 7550.173 0.071 B- 2190.891 17.015 240 056163.830 18.284 + 52 146 94 240 Pu 50125.380 1.106 7556.042 0.005 B- -1384.789 13.788 240 053811.812 1.187 + 50 145 95 240 Am +n 51510.169 13.832 7547.013 0.058 B- -214.137 13.897 240 055298.444 14.849 + 48 144 96 240 Cm 51724.306 1.906 7542.861 0.008 B- -3940# 150# 240 055528.329 2.046 + 46 143 97 240 Bk - 55664# 150# 7523# 1# B- -2327# 151# 240 059758# 161# + 44 142 98 240 Cf -a 57990.944 18.700 7510.230 0.078 B- -6208# 401# 240 062255.842 20.075 + 42 141 99 240 Es x 64199# 401# 7481# 2# B- * 240 068920# 430# +0 59 150 91 241 Pa x 59640# 300# 7528# 1# B- 3443# 358# 241 064026# 322# + 57 149 92 241 U x 56197# 196# 7539# 1# B- 1937# 208# 241 060330# 210# + 55 148 93 241 Np + 54260.175 70.719 7544.270 0.293 B- 1305.000 70.711 241 058250.697 75.920 + 53 147 94 241 Pu 52955.175 1.106 7546.439 0.005 B- 20.780 0.166 241 056849.722 1.187 + 51 146 95 241 Am 52934.395 1.114 7543.278 0.005 B- -767.434 1.168 241 056827.413 1.195 + 49 145 96 241 Cm 53701.830 1.608 7536.848 0.007 B- -2330# 200# 241 057651.288 1.726 + 47 144 97 241 Bk - 56032# 200# 7524# 1# B- -3295# 260# 241 060153# 215# + 45 143 98 241 Cf -a 59327# 166# 7507# 1# B- -4537# 280# 241 063690# 178# + 43 142 99 241 Es -a 63863# 225# 7485# 1# B- -5263# 374# 241 068560# 242# + 41 141 100 241 Fm x 69126# 298# 7460# 1# B- * 241 074210# 320# +0 58 150 92 242 U +a 58620# 201# 7532# 1# B- 1203# 283# 242 062931# 215# + 56 149 93 242 Np + 57416.932 200.004 7533.403 0.826 B- 2700.000 200.000 242 061639.615 214.713 + 54 148 94 242 Pu 54716.932 1.245 7541.327 0.005 B- -751.140 0.708 242 058741.045 1.336 + 52 147 95 242 Am -n 55468.072 1.119 7534.991 0.005 B- 664.309 0.414 242 059547.428 1.200 + 50 146 96 242 Cm 54803.764 1.142 7534.503 0.005 B- -2930# 200# 242 058834.263 1.225 + 48 145 97 242 Bk - 57734# 200# 7519# 1# B- -1653# 200# 242 061980# 215# + 46 144 98 242 Cf -a 59386.966 12.892 7509.098 0.053 B- -5414# 256# 242 063754.533 13.840 + 44 143 99 242 Es -a 64801# 256# 7483# 1# B- -3598# 475# 242 069567# 275# + 42 142 100 242 Fm x 68400# 401# 7465# 2# B- * 242 073430# 430# +0 59 151 92 243 U x 62360# 300# 7518# 1# B- 2484# 302# 243 066946# 322# + 57 150 93 243 Np IT 59876# 32# 7525# 0# B- 2121# 32# 243 064279# 34# + 55 149 94 243 Pu 57754.602 2.542 7531.008 0.010 B- 579.556 2.622 243 062002.119 2.728 + 53 148 95 243 Am 57175.046 1.388 7530.173 0.006 B- -6.952 1.569 243 061379.940 1.490 + 51 147 96 243 Cm -a 57181.998 1.496 7526.925 0.006 B- -1507.695 4.506 243 061387.403 1.606 + 49 146 97 243 Bk -a 58689.693 4.524 7517.501 0.019 B- -2300# 114# 243 063005.980 4.857 + 47 145 98 243 Cf -a 60990# 114# 7505# 0# B- -3757# 236# 243 065475# 123# + 45 144 99 243 Es -a 64747# 207# 7486# 1# B- -4640# 298# 243 069509# 222# + 43 143 100 243 Fm -a 69387# 215# 7464# 1# B- * 243 074490# 231# +0 58 151 93 244 Np x 63202# 298# 7514# 1# B- 3396# 298# 244 067850# 320# + 56 150 94 244 Pu 59806.028 2.346 7524.815 0.010 B- -73.168 2.686 244 064204.415 2.518 + 54 149 95 244 Am + 59879.196 1.492 7521.308 0.006 B- 1427.300 1.000 244 064282.964 1.601 + 52 148 96 244 Cm -a 58451.896 1.107 7523.952 0.005 B- -2261.989 14.357 244 062750.694 1.188 + 50 147 97 244 Bk -a 60713.885 14.399 7511.475 0.059 B- -764.294 14.572 244 065179.039 15.457 + 48 146 98 244 Cf 61478.179 2.618 7505.136 0.011 B- -4547# 181# 244 065999.543 2.810 + 46 145 99 244 Es -a 66026# 181# 7483# 1# B- -2940# 271# 244 070881# 195# + 44 144 100 244 Fm -a 68966# 201# 7468# 1# B- * 244 074038# 216# +0 59 152 93 245 Np x 65890# 300# 7505# 1# B- 2712# 300# 245 070736# 322# + 57 151 94 245 Pu -n 63178.179 13.620 7513.281 0.056 B- 1277.710 13.733 245 067824.568 14.621 + 55 150 95 245 Am +a 61900.469 1.887 7515.303 0.008 B- 895.889 1.549 245 066452.890 2.025 + 53 149 96 245 Cm 61004.580 1.150 7515.767 0.005 B- -809.256 1.496 245 065491.113 1.234 + 51 148 97 245 Bk -a 61813.836 1.793 7509.270 0.007 B- -1571.374 2.586 245 066359.885 1.924 + 49 147 98 245 Cf 63385.210 2.428 7499.663 0.010 B- -2981# 200# 245 068046.825 2.606 + 47 146 99 245 Es -a 66366# 200# 7484# 1# B- -3821# 279# 245 071247# 215# + 45 145 100 245 Fm -a 70187# 195# 7466# 1# B- -5085# 362# 245 075349# 209# + 43 144 101 245 Md -a 75272# 305# 7442# 1# B- * 245 080808# 328# +0 58 152 94 246 Pu 65394.801 14.985 7506.539 0.061 B- 401# 14# 246 070204.209 16.087 + 56 151 95 246 Am IT 64994# 18# 7505# 0# B- 2377# 18# 246 069774# 19# + 54 150 96 246 Cm 62616.967 1.526 7511.471 0.006 B- -1350.000 60.000 246 067222.082 1.638 + 52 149 97 246 Bk - 63966.967 60.019 7502.803 0.244 B- -123.325 60.020 246 068671.367 64.433 + 50 148 98 246 Cf 64090.292 1.515 7499.121 0.006 B- -3810# 224# 246 068803.762 1.626 + 48 147 99 246 Es -a 67901# 224# 7480# 1# B- -2288# 224# 246 072894# 240# + 46 146 100 246 Fm -a 70188.833 15.333 7467.970 0.062 B- -5926# 260# 246 075350.815 16.460 + 44 145 101 246 Md -a 76115# 259# 7441# 1# B- * 246 081713# 278# +0 59 153 94 247 Pu x 69108# 196# 7494# 1# B- 1954# 220# 247 074190# 210# + 57 152 95 247 Am + 67153# 100# 7499# 0# B- 1620# 100# 247 072092# 107# + 55 151 96 247 Cm 65533.143 3.797 7501.931 0.015 B- 43.581 6.324 247 070352.726 4.076 + 53 150 97 247 Bk -a 65489.562 5.189 7498.940 0.021 B- -614.341 16.188 247 070305.940 5.570 + 51 149 98 247 Cf +a 66103.903 15.334 7493.285 0.062 B- -2474.485 24.760 247 070965.462 16.461 + 49 148 99 247 Es +a 68578.388 19.441 7480.100 0.079 B- -3094# 116# 247 073621.932 20.870 + 47 147 100 247 Fm +a 71673# 115# 7464# 0# B- -4264# 237# 247 076944# 123# + 45 146 101 247 Md -a 75937# 207# 7444# 1# B- * 247 081521# 222# +0 58 153 95 248 Am + 70563# 200# 7487# 1# B- 3170# 200# 248 075752# 215# + 56 152 96 248 Cm 67392.755 2.358 7496.728 0.010 B- -687# 71# 248 072349.101 2.531 + 54 151 97 248 Bk IT 68080# 71# 7491# 0# B- 842# 71# 248 073087# 76# + 52 150 98 248 Cf -a 67238.012 5.121 7491.043 0.021 B- -3061# 53# 248 072182.978 5.497 + 50 149 99 248 Es -a 70299# 52# 7476# 0# B- -1599# 53# 248 075469# 56# + 48 148 100 248 Fm 71897.857 8.497 7465.944 0.034 B- -5250# 238# 248 077185.528 9.122 + 46 147 101 248 Md -a 77148# 237# 7442# 1# B- -3473# 327# 248 082822# 255# + 44 146 102 248 No -a 80621# 224# 7424# 1# B- * 248 086550# 241# +0 59 154 95 249 Am x 73104# 298# 7479# 1# B- 2353# 298# 249 078480# 320# + 57 153 96 249 Cm -n 70750.702 2.371 7485.550 0.010 B- 904.317 2.594 249 075954.006 2.545 + 55 152 97 249 Bk + 69846.384 1.249 7486.040 0.005 B- 123.600 0.400 249 074983.182 1.340 + 53 151 98 249 Cf 69722.784 1.183 7483.394 0.005 B- -1452# 30# 249 074850.491 1.270 + 51 150 99 249 Es -a 71175# 30# 7474# 0# B- -2344# 31# 249 076409# 32# + 49 149 100 249 Fm 73519.188 6.212 7461.864 0.025 B- -3713# 201# 249 078926.098 6.668 + 47 148 101 249 Md -a 77232# 201# 7444# 1# B- -4550# 344# 249 082912# 216# + 45 147 102 249 No -a 81782# 279# 7422# 1# B- * 249 087797# 300# +0 58 154 96 250 Cm -nn 72989.594 10.274 7478.938 0.041 B- 39.616 10.894 250 078357.556 11.029 + 56 153 97 250 Bk +a 72949.978 3.719 7475.967 0.015 B- 1779.587 3.386 250 078315.027 3.992 + 54 152 98 250 Cf -a 71170.391 1.538 7479.956 0.006 B- -2055# 100# 250 076404.561 1.651 + 52 151 99 250 Es - 73225# 100# 7469# 0# B- -847# 100# 250 078611# 107# + 50 150 100 250 Fm 74072.243 7.888 7462.090 0.032 B- -4558# 301# 250 079519.828 8.468 + 48 149 101 250 Md -a 78630# 301# 7441# 1# B- -2933# 362# 250 084413# 323# + 46 148 102 250 No -a 81564# 201# 7426# 1# B- * 250 087562# 215# +0 59 155 96 251 Cm + 76648.018 22.698 7466.722 0.090 B- 1420.000 20.000 251 082285.036 24.367 + 57 154 97 251 Bk + 75228.018 10.734 7469.263 0.043 B- 1093.000 10.000 251 080760.603 11.523 + 55 153 98 251 Cf -a 74135.018 3.901 7470.500 0.016 B- -377.259 7.057 251 079587.219 4.187 + 53 152 99 251 Es -a 74512.277 5.994 7465.881 0.024 B- -1441.641 16.342 251 079992.224 6.434 + 51 151 100 251 Fm +a 75953.919 15.203 7457.020 0.061 B- -3012.825 24.271 251 081539.889 16.320 + 49 150 101 251 Md +a 78966.744 18.919 7441.900 0.075 B- -3882# 116# 251 084774.291 20.310 + 47 149 102 251 No IT 82849# 114# 7423# 0# B- -4879# 319# 251 088942# 123# + 45 148 103 251 Lr x 87728# 298# 7401# 1# B- * 251 094180# 320# +0 60 156 96 252 Cm x 79056# 298# 7460# 1# B- 521# 359# 252 084870# 320# + 58 155 97 252 Bk + 78535# 200# 7459# 1# B- 2500# 200# 252 084310# 215# + 56 154 98 252 Cf -a 76034.617 2.358 7465.347 0.009 B- -1260.000 50.000 252 081626.523 2.531 + 54 153 99 252 Es - 77294.617 50.056 7457.242 0.199 B- 478.990 50.351 252 082979.189 53.736 + 52 152 100 252 Fm -a 76815.627 5.498 7456.038 0.022 B- -3695# 130# 252 082464.972 5.902 + 50 151 101 252 Md IT 80510# 130# 7438# 1# B- -2361# 131# 252 086432# 140# + 48 150 102 252 No 82871.427 9.292 7425.798 0.037 B- -5866# 238# 252 088966.141 9.975 + 46 149 103 252 Lr -a 88737# 238# 7399# 1# B- * 252 095263# 255# +0 59 156 97 253 Bk -a 80929# 359# 7451# 1# B- 1627# 359# 253 086880# 385# + 57 155 98 253 Cf -a 79301.567 4.257 7454.829 0.017 B- 291.030 4.385 253 085133.738 4.570 + 55 154 99 253 Es -a 79010.538 1.250 7452.887 0.005 B- -335.202 2.713 253 084821.305 1.341 + 53 153 100 253 Fm -a 79345.740 2.932 7448.470 0.012 B- -1827# 31# 253 085181.160 3.148 + 51 152 101 253 Md -a 81173# 31# 7438# 0# B- -3186# 32# 253 087143# 34# + 49 151 102 253 No 84358.735 6.912 7422.471 0.027 B- -4217# 202# 253 090562.831 7.420 + 47 150 103 253 Lr -a 88575# 202# 7403# 1# B- -4982# 457# 253 095089# 217# + 45 149 104 253 Rf -a 93557# 410# 7380# 2# B- * 253 100438# 440# +0 60 157 97 254 Bk x 84393# 298# 7440# 1# B- 3052# 298# 254 090600# 320# + 58 156 98 254 Cf -a 81341.401 11.462 7449.225 0.045 B- -649.193 12.113 254 087323.590 12.304 + 56 155 99 254 Es -a 81990.594 4.010 7443.589 0.016 B- 1087.800 3.202 254 088020.527 4.304 + 54 154 100 254 Fm -a 80902.794 2.414 7444.792 0.010 B- -2550# 100# 254 086852.726 2.591 + 52 153 101 254 Md - 83453# 100# 7432# 0# B- -1271# 100# 254 089590# 107# + 50 152 102 254 No 84723.347 9.658 7423.590 0.038 B- -5148# 301# 254 090954.259 10.367 + 48 151 103 254 Lr -a 89871# 301# 7400# 1# B- -3327# 414# 254 096481# 323# + 46 150 104 254 Rf -a 93199# 283# 7384# 1# B- * 254 100053# 304# +0 59 157 98 255 Cf + 84809# 200# 7438# 1# B- 720# 200# 255 091047# 215# + 57 156 99 255 Es -a 84089.274 10.817 7437.821 0.042 B- 289.620 10.247 255 090273.553 11.612 + 55 155 100 255 Fm -a 83799.654 4.291 7435.888 0.017 B- -1043.416 7.747 255 089962.633 4.607 + 53 154 101 255 Md -a 84843.070 6.553 7428.729 0.026 B- -1964.164 16.281 255 091082.787 7.035 + 51 153 102 255 No x 86807.234 14.904 7417.958 0.058 B- -3140.066 23.138 255 093191.404 16.000 + 49 152 103 255 Lr x 89947.300 17.698 7402.576 0.069 B- -4382# 116# 255 096562.404 19.000 + 47 151 104 255 Rf -a 94330# 115# 7382# 0# B- -5263# 377# 255 101267# 123# + 45 150 105 255 Db -a 99593# 359# 7359# 1# B- * 255 106918# 385# +0 60 158 98 256 Cf -a 87041# 314# 7432# 1# B- -146# 330# 256 093442# 338# + 58 157 99 256 Es + 87187# 100# 7428# 0# B- 1700# 100# 256 093599# 108# + 56 156 100 256 Fm -a 85486.817 5.600 7431.780 0.022 B- -1969# 123# 256 091773.878 6.012 + 54 155 101 256 Md IT 87456# 122# 7421# 0# B- -366# 123# 256 093888# 132# + 52 154 102 256 No -a 87822.062 7.743 7416.546 0.030 B- -3924.536 83.264 256 094280.866 8.312 + 50 153 103 256 Lr x 91746.598 82.903 7398.160 0.324 B- -2475.451 84.802 256 098494.029 89.000 + 48 152 104 256 Rf -a 94222.049 17.848 7385.434 0.070 B- -6276# 241# 256 101151.535 19.160 + 46 151 105 256 Db -a 100498# 240# 7358# 1# B- * 256 107889# 258# +0 59 158 99 257 Es -a 89403# 411# 7422# 2# B- 813# 411# 257 095979# 441# + 57 157 100 257 Fm -a 88590.033 4.486 7422.194 0.017 B- -403.020 4.715 257 095105.317 4.815 + 55 156 101 257 Md -a 88993.053 1.601 7417.582 0.006 B- -1254.202 6.661 257 095537.977 1.718 + 53 155 102 257 No -a 90247.256 6.678 7409.657 0.026 B- -2418# 45# 257 096884.419 7.169 + 51 154 103 257 Lr -a 92665# 44# 7397# 0# B- -3201# 45# 257 099480# 47# + 49 153 104 257 Rf -a 95866.427 10.817 7381.704 0.042 B- -4340# 203# 257 102916.848 11.612 + 47 152 105 257 Db -a 100207# 203# 7362# 1# B- * 257 107576# 218# +0 60 159 99 258 Es x 92702# 401# 7412# 2# B- 2276# 448# 258 099520# 430# + 58 158 100 258 Fm -a 90426# 200# 7418# 1# B- -1260# 200# 258 097077# 215# + 56 157 101 258 Md -a 91686.792 4.419 7409.675 0.017 B- 209# 100# 258 098429.825 4.743 + 54 156 102 258 No -a 91478# 100# 7407# 0# B- -3304# 143# 258 098205# 107# + 52 155 103 258 Lr -a 94782# 102# 7392# 0# B- -1559# 107# 258 101753# 109# + 50 154 104 258 Rf -a 96341.036 31.967 7382.538 0.124 B- -5456# 307# 258 103426.362 34.317 + 48 153 105 258 Db -a 101797# 305# 7358# 1# B- -3447# 513# 258 109284# 328# + 46 152 106 258 Sg -a 105244# 413# 7342# 2# B- * 258 112984# 443# +0 59 159 100 259 Fm -a 93704# 283# 7407# 1# B- 80# 346# 259 100596# 304# + 57 158 101 259 Md -a 93624# 200# 7405# 1# B- -454# 200# 259 100510# 215# + 55 157 102 259 No -a 94078.569 6.589 7399.974 0.025 B- -1773# 71# 259 100997.503 7.073 + 53 156 103 259 Lr -a 95852# 71# 7390# 0# B- -2510# 101# 259 102901# 76# + 51 155 104 259 Rf -a 98362# 72# 7377# 0# B- -3629# 90# 259 105596# 78# + 49 154 105 259 Db -a 101991.016 53.040 7360.362 0.205 B- -4529# 126# 259 109491.865 56.940 + 47 153 106 259 Sg -a 106520# 115# 7340# 0# B- * 259 114353# 123# +0 60 160 100 260 Fm -a 95766# 435# 7402# 2# B- -786# 537# 260 102809# 467# + 58 159 101 260 Md -a 96552# 316# 7396# 1# B- 940# 374# 260 103653# 340# + 56 158 102 260 No -a 95612# 200# 7397# 1# B- -2665# 235# 260 102643# 215# + 54 157 103 260 Lr -a 98277# 124# 7383# 0# B- -870# 236# 260 105504# 133# + 52 156 104 260 Rf -a 99147# 200# 7377# 1# B- -4526# 221# 260 106439# 215# + 50 155 105 260 Db -a 103673# 93# 7357# 0# B- -2875# 95# 260 111297# 100# + 48 154 106 260 Sg -a 106547.552 20.536 7342.562 0.079 B- -6776# 246# 260 114383.508 22.045 + 46 153 107 260 Bh -a 113323# 245# 7313# 1# B- * 260 121658# 263# +0 59 160 101 261 Md -a 98578# 509# 7391# 2# B- 123# 547# 261 105828# 546# + 57 159 102 261 No -a 98455# 200# 7388# 1# B- -1103# 283# 261 105696# 215# + 55 158 103 261 Lr -a 99558# 200# 7381# 1# B- -1761# 206# 261 106880# 215# + 53 157 104 261 Rf -a 101318.594 50.444 7371.384 0.193 B- -2990# 121# 261 108769.990 54.153 + 51 156 105 261 Db -a 104308# 110# 7357# 0# B- -3697# 112# 261 111980# 118# + 49 155 106 261 Sg -a 108005.043 18.494 7339.770 0.071 B- -5128# 210# 261 115948.188 19.853 + 47 154 107 261 Bh -a 113133# 209# 7317# 1# B- * 261 121454# 224# +0 60 161 101 262 Md -a 101627# 500# 7382# 2# B- 1526# 617# 262 109101# 537# + 58 160 102 262 No -a 100101# 361# 7385# 1# B- -2000# 412# 262 107463# 387# + 56 159 103 262 Lr -a 102102# 200# 7374# 1# B- -291# 300# 262 109611# 215# + 54 158 104 262 Rf -a 102393# 224# 7370# 1# B- -3861# 265# 262 109923# 240# + 52 157 105 262 Db -a 106253# 143# 7352# 1# B- -2112# 147# 262 114068# 154# + 50 156 106 262 Sg -a 108365.771 35.411 7341.185 0.135 B- -6176# 308# 262 116335.446 38.015 + 48 155 107 262 Bh -a 114541# 306# 7315# 1# B- * 262 122965# 328# +0 59 161 102 263 No -a 103129# 490# 7376# 2# B- -600# 566# 263 110714# 526# + 57 160 103 263 Lr -a 103729# 283# 7371# 1# B- -1027# 322# 263 111358# 304# + 55 159 104 263 Rf -a 104756# 153# 7364# 1# B- -2355# 227# 263 112460# 164# + 53 158 105 263 Db -a 107111# 168# 7352# 1# B- -3079# 193# 263 114988# 181# + 51 157 106 263 Sg -a 110190# 95# 7337# 0# B- -4306# 319# 263 118294# 102# + 49 156 107 263 Bh -a 114496# 305# 7318# 1# B- -5182# 329# 263 122916# 327# + 47 155 108 263 Hs -a 119678# 125# 7295# 0# B- * 263 128480# 134# +0 60 162 102 264 No -a 105011# 591# 7371# 2# B- -1366# 734# 264 112734# 634# + 58 161 103 264 Lr -a 106377# 436# 7363# 2# B- 300# 566# 264 114200# 468# + 56 160 104 264 Rf -a 106077# 361# 7361# 1# B- -3285# 431# 264 113878# 387# + 54 159 105 264 Db -a 109362# 235# 7346# 1# B- -1420# 368# 264 117405# 253# + 52 158 106 264 Sg -a 110782# 283# 7338# 1# B- -5276# 334# 264 118929# 304# + 50 157 107 264 Bh -a 116058# 177# 7315# 1# B- -3506# 180# 264 124593# 190# + 48 156 108 264 Hs -a 119563.222 28.881 7298.375 0.109 B- * 264 128356.405 31.005 +0 59 162 103 265 Lr -a 108233# 547# 7359# 2# B- -457# 655# 265 116193# 587# + 57 161 104 265 Rf -a 108690# 361# 7354# 1# B- -1793# 424# 265 116683# 387# + 55 160 105 265 Db -a 110483# 224# 7344# 1# B- -2312# 255# 265 118608# 240# + 53 159 106 265 Sg -a 112794# 123# 7333# 0# B- -3621# 264# 265 121090# 132# + 51 158 107 265 Bh -a 116415# 234# 7316# 1# B- -4485# 235# 265 124977# 251# + 49 157 108 265 Hs -a 120900.283 23.958 7296.247 0.090 B- -5778# 452# 265 129791.799 25.719 + 47 156 109 265 Mt -a 126678# 451# 7271# 2# B- * 265 135995# 484# +0 60 163 103 266 Lr -a 111622# 583# 7349# 2# B- 1546# 749# 266 119831# 626# + 58 162 104 266 Rf -a 110076# 469# 7352# 2# B- -2660# 548# 266 118172# 504# + 56 161 105 266 Db -a 112737# 283# 7339# 1# B- -881# 374# 266 121028# 304# + 54 160 106 266 Sg -a 113618# 245# 7332# 1# B- -4487# 294# 266 121973# 263# + 52 159 107 266 Bh -a 118104# 163# 7313# 1# B- -3032# 167# 266 126790# 175# + 50 158 108 266 Hs -a 121136.373 38.695 7298.273 0.145 B- -6826# 309# 266 130045.252 41.540 + 48 157 109 266 Mt -a 127962# 307# 7270# 1# B- * 266 137373# 329# +0 59 163 104 267 Rf -a 113444# 575# 7342# 2# B- -630# 707# 267 121787# 617# + 57 162 105 267 Db -a 114074# 412# 7336# 2# B- -1732# 486# 267 122464# 443# + 55 161 106 267 Sg -a 115806# 257# 7327# 1# B- -2960# 367# 267 124322# 276# + 53 160 107 267 Bh -a 118766# 263# 7313# 1# B- -3887# 279# 267 127500# 282# + 51 159 108 267 Hs -a 122653# 96# 7295# 0# B- -5138# 512# 267 131673# 103# + 49 158 109 267 Mt -a 127791# 503# 7273# 2# B- -6089# 521# 267 137189# 540# + 47 157 110 267 Ds -a 133880# 135# 7248# 1# B- * 267 143726# 145# +0 60 164 104 268 Rf -a 115476# 662# 7337# 2# B- -1586# 848# 268 123968# 711# + 58 163 105 268 Db -a 117062# 529# 7328# 2# B- 260# 707# 268 125671# 568# + 56 162 106 268 Sg -a 116802# 469# 7326# 2# B- -4005# 605# 268 125392# 504# + 54 161 107 268 Bh -a 120807# 381# 7308# 1# B- -2023# 475# 268 129691# 409# + 52 160 108 268 Hs -a 122830# 283# 7298# 1# B- -6321# 367# 268 131863# 304# + 50 159 109 268 Mt -a 129151# 233# 7271# 1# B- -4497# 381# 268 138649# 250# + 48 158 110 268 Ds -a 133648# 301# 7252# 1# B- * 268 143477# 324# +0 59 164 105 269 Db -a 119148# 624# 7323# 2# B- -614# 722# 269 127911# 669# + 57 163 106 269 Sg -a 119763# 364# 7318# 1# B- -1715# 522# 269 128570# 391# + 55 162 107 269 Bh -a 121478# 374# 7309# 1# B- -3086# 394# 269 130412# 402# + 53 161 108 269 Hs -a 124564# 124# 7294# 0# B- -4806# 480# 269 133725# 133# + 51 160 109 269 Mt -a 129370# 463# 7273# 2# B- -5465# 464# 269 138884# 497# + 49 159 110 269 Ds -a 134834.709 31.403 7250.154 0.117 B- * 269 144751.021 33.712 +0 60 165 105 270 Db -a 122307# 617# 7314# 2# B- 816# 831# 270 131302# 662# + 58 164 106 270 Sg -a 121491# 557# 7314# 2# B- -2735# 627# 270 130426# 598# + 56 163 107 270 Bh -a 124226# 287# 7301# 1# B- -886# 379# 270 133362# 308# + 54 162 108 270 Hs -a 125112# 248# 7295# 1# B- -5598# 301# 270 134314# 266# + 52 161 109 270 Mt -a 130710# 170# 7271# 1# B- -3968# 177# 270 140323# 183# + 50 160 110 270 Ds -a 134678.282 48.011 7253.775 0.178 B- * 270 144583.090 51.542 +0 59 165 106 271 Sg -a 124757# 585# 7305# 2# B- -1164# 718# 271 133932# 628# + 57 164 107 271 Bh -a 125921# 415# 7298# 2# B- -1819# 501# 271 135182# 446# + 55 163 108 271 Hs -a 127740# 280# 7288# 1# B- -3361# 433# 271 137135# 301# + 53 162 109 271 Mt -a 131101# 330# 7273# 1# B- -4847# 344# 271 140742# 354# + 51 161 110 271 Ds -a 135948# 97# 7252# 0# B- * 271 145946# 104# +0 60 166 106 272 Sg -a 126580# 727# 7301# 3# B- -2209# 901# 272 135890# 781# + 58 165 107 272 Bh -a 128789# 532# 7290# 2# B- -217# 737# 272 138261# 571# + 56 164 108 272 Hs -a 129006# 510# 7286# 2# B- -4575# 704# 272 138494# 547# + 54 163 109 272 Mt -a 133581# 485# 7267# 2# B- -2433# 637# 272 143406# 521# + 52 162 110 272 Ds -a 136015# 413# 7255# 2# B- -6758# 474# 272 146018# 443# + 50 161 111 272 Rg -a 142773# 233# 7227# 1# B- * 272 153273# 251# +0 61 167 106 273 Sg x 130018# 503# 7291# 2# B- -615# 855# 273 139580# 540# + 59 166 107 273 Bh -a 130633# 692# 7286# 3# B- -1257# 783# 273 140240# 743# + 57 165 108 273 Hs -a 131890# 367# 7279# 1# B- -2822# 561# 273 141590# 394# + 55 164 109 273 Mt -a 134713# 424# 7265# 2# B- -3643# 445# 273 144620# 455# + 53 163 110 273 Ds -a 138356# 134# 7249# 0# B- -4339# 543# 273 148531# 144# + 51 162 111 273 Rg -a 142695# 526# 7231# 2# B- * 273 153189# 565# +0 60 167 107 274 Bh -a 133682# 619# 7278# 2# B- 196# 856# 274 143513# 664# + 58 166 108 274 Hs -a 133486# 592# 7276# 2# B- -3760# 689# 274 143303# 635# + 56 165 109 274 Mt -a 137246# 354# 7259# 1# B- -1952# 526# 274 147339# 380# + 54 164 110 274 Ds -a 139197# 389# 7249# 1# B- -5416# 428# 274 149434# 418# + 52 163 111 274 Rg -a 144613# 177# 7227# 1# B- * 274 155249# 190# +0 61 168 107 275 Bh x 135691# 596# 7273# 2# B- -929# 837# 275 145670# 640# + 59 167 108 275 Hs -a 136620# 587# 7267# 2# B- -2209# 721# 275 146667# 631# + 57 166 109 275 Mt -a 138829# 418# 7256# 2# B- -2736# 586# 275 149039# 449# + 55 165 110 275 Ds -a 141565# 410# 7244# 1# B- -3731# 661# 275 151976# 441# + 53 164 111 275 Rg -a 145296# 519# 7227# 2# B- * 275 155981# 557# +0 60 168 108 276 Hs -a 138285# 754# 7264# 3# B- -3029# 923# 276 148455# 810# + 58 167 109 276 Mt -a 141315# 532# 7250# 2# B- -1227# 763# 276 151708# 571# + 56 166 110 276 Ds -a 142541# 548# 7243# 2# B- -4945# 834# 276 153024# 588# + 54 165 111 276 Rg -a 147486# 629# 7222# 2# B- -2866# 866# 276 158333# 675# + 52 164 112 276 Cn x 150352# 596# 7209# 2# B- * 276 161410# 640# +0 61 169 108 277 Hs -a 141493# 541# 7255# 2# B- -1475# 884# 277 151899# 581# + 59 168 109 277 Mt -a 142968# 699# 7247# 3# B- -2172# 798# 277 153483# 751# + 57 167 110 277 Ds -a 145140# 384# 7237# 1# B- -3197# 646# 277 155815# 412# + 55 166 111 277 Rg -a 148338# 520# 7222# 2# B- -4065# 539# 277 159247# 558# + 53 165 112 277 Cn -a 152403# 143# 7205# 1# B- * 277 163611# 153# +0 60 169 109 278 Mt -a 145736# 621# 7240# 2# B- -645# 881# 278 156454# 666# + 58 168 110 278 Ds -a 146381# 625# 7235# 2# B- -4136# 719# 278 157146# 671# + 56 167 111 278 Rg -a 150517# 357# 7218# 1# B- -2415# 565# 278 161587# 383# + 54 166 112 278 Cn -a 152932# 438# 7206# 2# B- -5957# 475# 278 164179# 470# + 52 165 113 278 Ed -a 158889# 184# 7182# 1# B- * 278 170574# 198# +0 61 170 109 279 Mt -a 147496# 667# 7237# 2# B- -1630# 896# 279 158343# 716# + 59 169 110 279 Ds -a 149126# 598# 7228# 2# B- -2649# 731# 279 160093# 642# + 57 168 111 279 Rg -a 151775# 421# 7216# 2# B- -3255# 621# 279 162937# 452# + 55 167 112 279 Cn -a 155030# 456# 7202# 2# B- -4209# 835# 279 166432# 490# + 53 166 113 279 Ed x 159239# 699# 7184# 3# B- * 279 170950# 750# +0 60 170 110 280 Ds -a 150520# 780# 7226# 3# B- -3366# 944# 280 161590# 838# + 58 169 111 280 Rg -a 153886# 532# 7212# 2# B- -1810# 789# 280 165203# 571# + 56 168 112 280 Cn -a 155696# 583# 7202# 2# B- -5444# 707# 280 167147# 626# + 54 167 113 280 Ed x 161140# 400# 7180# 1# B- * 280 172991# 429# +0 61 171 110 281 Ds -a 153431# 579# 7219# 2# B- -1866# 992# 281 164715# 622# + 59 170 111 281 Rg -a 155297# 806# 7210# 3# B- -2722# 894# 281 166718# 865# + 57 169 112 281 Cn -a 158019# 387# 7197# 1# B- -3790# 490# 281 169641# 416# + 55 168 113 281 Ed x 161810# 300# 7181# 1# B- * 281 173710# 322# +0 60 171 111 282 Rg -a 157800# 654# 7204# 2# B- -1176# 926# 282 169405# 702# + 58 170 112 282 Cn -a 158976# 656# 7197# 2# B- -4749# 748# 282 170668# 704# + 56 169 113 282 Ed -a 163725# 361# 7177# 1# B- * 282 175766# 387# +0 61 172 111 283 Rg -a 159281# 697# 7202# 2# B- -2205# 925# 283 170995# 748# + 59 171 112 283 Cn -a 161486# 608# 7191# 2# B- -3221# 748# 283 173362# 653# + 57 170 113 283 Ed -a 164707# 436# 7177# 2# B- * 283 176820# 468# +0 60 172 112 284 Cn -a 162545# 806# 7190# 3# B- -4046# 966# 284 174499# 865# + 58 171 113 284 Ed -a 166591# 534# 7173# 2# B- -2330# 846# 284 178843# 573# + 56 170 114 284 Fl -a 168921# 656# 7162# 2# B- * 284 181344# 704# +0 61 173 112 285 Cn -a 165173# 581# 7184# 2# B- -2557# 995# 285 177321# 624# + 59 172 113 285 Ed -a 167731# 807# 7173# 3# B- -3272# 897# 285 180066# 866# + 57 171 114 285 Fl -a 171003# 391# 7158# 1# B- * 285 183579# 419# +0 60 173 113 286 Ed -a 170014# 656# 7168# 2# B- -1758# 928# 286 182518# 704# + 58 172 114 286 Fl -a 171773# 657# 7159# 2# B- * 286 184406# 705# +0 61 174 113 287 Ed -a 171245# 725# 7167# 3# B- -2827# 948# 287 183840# 778# + 59 173 114 287 Fl -a 174073# 610# 7154# 2# B- -3823# 752# 287 186875# 655# + 57 172 115 287 Ef -a 177895# 439# 7138# 2# B- * 287 190978# 471# +0 60 174 114 288 Fl -a 175042# 806# 7154# 3# B- -4728# 968# 288 187916# 865# + 58 173 115 288 Ef -a 179771# 536# 7135# 2# B- * 288 192992# 576# +0 61 175 114 289 Fl -a 177564# 584# 7148# 2# B- -3102# 997# 289 190623# 626# + 59 174 115 289 Ef -a 180666# 809# 7135# 3# B- -3861# 947# 289 193953# 868# + 57 173 116 289 Lv -a 184528# 492# 7119# 2# B- * 289 198099# 529# +0 60 175 115 290 Ef -a 182894# 658# 7130# 2# B- -2304# 932# 290 196345# 706# + 58 174 116 290 Lv -a 185198# 660# 7120# 2# B- * 290 198818# 708# +0 61 176 115 291 Ef -a 183990# 784# 7130# 3# B- -3397# 995# 291 197522# 842# + 59 175 116 291 Lv -a 187387# 612# 7116# 2# B- -4413# 853# 291 201169# 658# + 57 174 117 291 Eh -a 191800# 594# 7098# 2# B- * 291 205906# 637# +0 60 176 116 292 Lv -a 188242# 806# 7116# 3# B- -5334# 1047# 292 202086# 865# + 58 175 117 292 Eh -a 193576# 669# 7095# 2# B- * 292 207812# 718# +0 61 177 116 293 Lv -a 190669# 586# 7111# 2# B- -3716# 1000# 293 204691# 629# + 59 176 117 293 Eh -a 194385# 810# 7095# 3# B- -4488# 1072# 293 208680# 870# + 57 175 118 293 Ei -a 198873# 702# 7077# 2# B- * 293 213498# 753# +0 60 177 117 294 Eh -a 196521# 660# 7092# 2# B- -2942# 936# 294 210974# 708# + 58 176 118 294 Ei -a 199463# 663# 7079# 2# B- * 294 214132# 712# +0 59 177 118 295 Ei -a 201512# 644# 7075# 2# B- * 295 216332# 692# diff --git a/openmc/data/mass_1.mas20.txt b/openmc/data/mass_1.mas20.txt deleted file mode 100644 index ce12b2c4a..000000000 --- a/openmc/data/mass_1.mas20.txt +++ /dev/null @@ -1,3594 +0,0 @@ -1 a0dsskgw A T O M I C M A S S A D J U S T M E N T -0 DATE 3 Mar 2021 TIME 22:41 -0 ********************* A= 0 TO 295 - * file : mass.mas20 * - ********************* - - This is one file out of a series of 3 files published in: - "The Ame2020 atomic mass evaluation (I)" by W.J.Huang, M.Wang, F.G.Kondev, G.Audi and S.Naimi - Chinese Physics C45, 030002, March 2021. - "The Ame2020 atomic mass evaluation (II)" by M.Wang, W.J.Huang, F.G.Kondev, G.Audi and S.Naimi - Chinese Physics C45, 030003, March 2021. - for files : mass.mas20 : atomic masses - rct1.mas20 : react and sep energies, part 1 - rct2.mas20 : react and sep energies, part 2 - A fourth file is the "Rounded" version of the atomic mass table (the first file) - massround.mas20 atomic masses "Rounded" version - - Values in files 1, 2 and 3 are unrounded version of the published ones - Values in file 4 are exact copy of the published ones - - col 1 : Fortran character control: 1 = page feed 0 = line feed - format : a1,i3,i5,i5,i5,1x,a3,a4,1x,f14.6,f12.6,f13.5,1x,f10.5,1x,a2,f13.5,f11.5,1x,i3,1x,f13.6,f12.6 - cc NZ N Z A el o mass unc binding unc B beta unc atomic_mass unc - Warnings : this format is not identical to that used in AME2016; - one more digit is added to the "BINDING ENERGY/A", "BETA-DECAY ENERGY" and "ATOMIC-MASS" values and their uncertainties; - # in a place of decimal point : estimated (non-experimental) value; - * in a place of value : the not calculable quantity - -....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+...10....+...11....+...12....+...13 - - - MASS LIST - for analysis - -1N-Z N Z A EL O MASS EXCESS BINDING ENERGY/A BETA-DECAY ENERGY ATOMIC MASS - (keV) (keV) (keV) (micro-u) -0 1 1 0 1 n 8071.31806 0.00044 0.0 0.0 B- 782.3470 0.0004 1 008664.91590 0.00047 - -1 0 1 1 H 7288.971064 0.000013 0.0 0.0 B- * 1 007825.031898 0.000014 -0 0 1 1 2 H 13135.722895 0.000015 1112.2831 0.0002 B- * 2 014101.777844 0.000015 -0 1 2 1 3 H 14949.81090 0.00008 2827.2654 0.0003 B- 18.59202 0.00006 3 016049.28132 0.00008 - -1 1 2 3 He 14931.21888 0.00006 2572.68044 0.00015 B- -13736# 2000# 3 016029.32197 0.00006 - -3 0 3 3 Li -pp 28667# 2000# -2267# 667# B- * 3 030775# 2147# -0 2 3 1 4 H -n 24621.129 100.000 1720.4491 25.0000 B- 22196.2131 100.0000 4 026431.867 107.354 - 0 2 2 4 He 2424.91587 0.00015 7073.9156 0.0002 B- -22898.2740 212.1320 4 002603.25413 0.00016 - -2 1 3 4 Li -p 25323.190 212.132 1153.7603 53.0330 B- * 4 027185.561 227.733 -0 3 4 1 5 H -nn 32892.447 89.443 1336.3592 17.8885 B- 21661.2131 91.6515 5 035311.492 96.020 - 1 3 2 5 He -n 11231.234 20.000 5512.1325 4.0000 B- -447.6529 53.8516 5 012057.224 21.470 - -1 2 3 5 Li -p 11678.887 50.000 5266.1325 10.0000 B- -25460# 2003# 5 012537.800 53.677 - -3 1 4 5 Be x 37139# 2003# 18# 401# B- * 5 039870# 2150# -0 4 5 1 6 H -3n 41875.725 254.127 961.6395 42.3545 B- 24283.6294 254.1268 6 044955.437 272.816 - 2 4 2 6 He 17592.095 0.053 4878.5199 0.0089 B- 3505.2147 0.0532 6 018885.889 0.057 - 0 3 3 6 Li 14086.88044 0.00144 5332.3312 0.0003 B- -4288.1534 5.4478 6 015122.88742 0.00155 - -2 2 4 6 Be - 18375.034 5.448 4487.2478 0.9080 B- -28945# 2003# 6 019726.409 5.848 - -4 1 5 6 B x 47320# 2003# -467# 334# B- * 6 050800# 2150# -0 5 6 1 7 H -nn 49135# 1004# 940# 143# B- 23062# 1004# 7 052749# 1078# - 3 5 2 7 He -n 26073.128 7.559 4123.0578 1.0799 B- 11166.0229 7.5595 7 027990.652 8.115 - 1 4 3 7 Li 14907.10463 0.00419 5606.4401 0.0006 B- -861.8930 0.0707 7 016003.43426 0.00450 - -1 3 4 7 Be 15768.998 0.071 5371.5487 0.0101 B- -11907.5551 25.1504 7 016928.714 0.076 - -3 2 5 7 B p4n 27676.553 25.150 3558.7055 3.5929 B- * 7 029712.000 27.000 -0 4 6 2 8 He 31609.683 0.089 3924.5210 0.0111 B- 10663.8784 0.1005 8 033934.388 0.095 - 2 5 3 8 Li 20945.805 0.047 5159.7124 0.0059 B- 16004.1329 0.0591 8 022486.244 0.050 - 0 4 4 8 Be -a 4941.672 0.035 7062.4356 0.0044 B- -17979.8973 1.0005 8 005305.102 0.037 - -2 3 5 8 B 22921.569 1.000 4717.1551 0.1250 B- -12142.7002 18.2704 8 024607.315 1.073 - -4 2 6 8 C 35064.269 18.243 3101.5242 2.2804 B- * 8 037643.039 19.584 -0 5 7 2 9 He 40935.826 46.816 3349.0380 5.2018 B- 15980.9213 46.8169 9 043946.414 50.259 - 3 6 3 9 Li -3n 24954.905 0.186 5037.7685 0.0207 B- 13606.4541 0.2014 9 026790.191 0.200 - 1 5 4 9 Be 11348.451 0.076 6462.6693 0.0085 B- -1068.0349 0.8994 9 012183.062 0.082 - -1 4 5 9 B - 12416.486 0.903 6257.0713 0.1003 B- -16494.4854 2.3195 9 013329.645 0.969 - -3 3 6 9 C -pp 28910.971 2.137 4337.4233 0.2374 B- * 9 031037.202 2.293 -0 6 8 2 10 He -nn 49197.147 92.848 2995.1340 9.2848 B- 16144.5191 93.7152 10 052815.306 99.676 - 4 7 3 10 Li -n 33052.628 12.721 4531.3512 1.2721 B- 20445.1411 12.7216 10 035483.453 13.656 - 2 6 4 10 Be 12607.487 0.081 6497.6306 0.0081 B- 556.8759 0.0822 10 013534.692 0.086 - 0 5 5 10 B 12050.611 0.015 6475.0835 0.0015 B- -3648.0623 0.0687 10 012936.862 0.016 - -2 4 6 10 C 15698.673 0.070 6032.0426 0.0070 B- -23101.3545 400.0000 10 016853.217 0.075 - -4 3 7 10 N -- 38800.027 400.000 3643.6724 40.0000 B- * 10 041653.540 429.417 -0 5 8 3 11 Li x 40728.259 0.615 4155.3817 0.0559 B- 20551.0898 0.6591 11 043723.581 0.660 - 3 7 4 11 Be 20177.169 0.238 5952.5402 0.0216 B- 11509.4607 0.2380 11 021661.080 0.255 - 1 6 5 11 B 8667.708 0.012 6927.7323 0.0011 B- -1981.6889 0.0608 11 009305.166 0.013 - -1 5 6 11 C 10649.397 0.060 6676.4563 0.0054 B- -13716.2469 5.0008 11 011432.597 0.064 - -3 4 7 11 N -p 24365.644 5.000 5358.4023 0.4546 B- -23373.2693 60.2459 11 026157.593 5.368 - -5 3 8 11 O -pp 47738.913 60.038 3162.4372 5.4580 B- * 11 051249.828 64.453 -0 6 9 3 12 Li -n 49009.577 30.006 3791.5999 2.5005 B- 23931.8152 30.0669 12 052613.942 32.213 - 4 8 4 12 Be 25077.761 1.909 5720.7223 0.1590 B- 11708.3636 2.3214 12 026922.082 2.048 - 2 7 5 12 B 13369.398 1.321 6631.2237 0.1101 B- 13369.3979 1.3214 12 014352.638 1.418 - 0 6 6 12 C 0.0 0.0 7680.1446 0.0002 B- -17338.0681 0.9999 12 000000.0 0.0 - -2 5 7 12 N 17338.068 1.000 6170.1100 0.0833 B- -14675.2668 12.0418 12 018613.180 1.073 - -4 4 8 12 O -pp 32013.335 12.000 4881.9755 1.0000 B- * 12 034367.726 12.882 -0 7 10 3 13 Li -nn 56980.895 70.003 3507.6307 5.3848 B- 23321.8152 70.7391 13 061171.503 75.150 - 5 9 4 13 Be -n 33659.080 10.180 5241.4359 0.7831 B- 17097.1315 10.2295 13 036134.506 10.929 - 3 8 5 13 B -nn 16561.948 1.000 6496.4194 0.0769 B- 13436.9387 1.0001 13 017779.981 1.073 - 1 7 6 13 C 3125.00933 0.00023 7469.8495 0.0002 B- -2220.4718 0.2695 13 003354.83534 0.00025 - -1 6 7 13 N -p 5345.481 0.270 7238.8634 0.0207 B- -17769.9506 9.5301 13 005738.609 0.289 - -3 5 8 13 O +3n 23115.432 9.526 5811.7636 0.7328 B- -18915# 500# 13 024815.435 10.226 - -5 4 9 13 F x 42030# 500# 4297# 38# B- * 13 045121# 537# -0 6 10 4 14 Be x 39954.502 132.245 4993.8973 9.4461 B- 16290.8166 133.9357 14 042892.920 141.970 - 4 9 5 14 B 23663.686 21.213 6101.6451 1.5152 B- 20643.7926 21.2133 14 025404.010 22.773 - 2 8 6 14 C 3019.89328 0.00375 7520.3198 0.0004 B- 156.4765 0.0037 14 003241.98862 0.00403 - 0 7 7 14 N 2863.41683 0.00022 7475.6148 0.0002 B- -5144.3643 0.0252 14 003074.00425 0.00024 - -2 6 8 14 O 8007.781 0.025 7052.2783 0.0018 B- -23956.6215 41.1187 14 008596.706 0.027 - -4 5 9 14 F -p 31964.403 41.119 5285.2091 2.9371 B- * 14 034315.196 44.142 -0 7 11 4 15 Be -n 49825.821 165.797 4540.9708 11.0532 B- 20868.4411 167.1256 15 053490.215 177.990 - 5 10 5 15 B 28957.379 21.029 5880.0438 1.4019 B- 19084.2343 21.0442 15 031087.023 22.575 - 3 9 6 15 C -n 9873.145 0.800 7100.1696 0.0533 B- 9771.7071 0.8000 15 010599.256 0.858 - 1 8 7 15 N 101.43809 0.00058 7699.4603 0.0002 B- -2754.1841 0.4902 15 000108.89827 0.00062 - -1 7 8 15 O 2855.622 0.490 7463.6915 0.0327 B- -13711.1300 14.0086 15 003065.636 0.526 - -3 6 9 15 F -p 16566.752 14.000 6497.4597 0.9333 B- -23648.6215 68.1377 15 017785.139 15.029 - -5 5 10 15 Ne -pp 40215.374 66.684 4868.7285 4.4456 B- * 15 043172.977 71.588 -0 8 12 4 16 Be -nn 57447.139 165.797 4285.2851 10.3623 B- 20335.4399 167.6075 16 061672.036 177.990 - 6 11 5 16 B 37111.699 24.566 5507.3535 1.5354 B- 23417.5656 24.8254 16 039841.045 26.373 - 4 10 6 16 C -nn 13694.133 3.578 6922.0546 0.2236 B- 8010.2260 4.2540 16 014701.255 3.840 - 2 9 7 16 N -n 5683.907 2.301 7373.7971 0.1438 B- 10420.9094 2.3014 16 006101.925 2.470 - 0 8 8 16 O -4737.00217 0.00030 7976.2072 0.0002 B- -15412.1840 5.3642 15 994914.61926 0.00032 - -2 7 9 16 F 10675.182 5.364 6964.0490 0.3353 B- -13311.5932 21.1709 16 011460.278 5.758 - -4 6 10 16 Ne -- 23986.775 20.480 6083.1777 1.2800 B- * 16 025750.860 21.986 -0 7 12 5 17 B x 43716.322 204.104 5269.6677 12.0061 B- 22684.4422 204.8410 17 046931.399 219.114 - 5 11 6 17 C 2p-n 21031.880 17.365 6558.0262 1.0215 B- 13161.8007 22.9464 17 022578.650 18.641 - 3 10 7 17 N +p 7870.079 15.000 7286.2294 0.8824 B- 8678.8430 15.0000 17 008448.876 16.103 - 1 9 8 17 O -808.76421 0.00064 7750.7291 0.0002 B- -2760.4655 0.2479 16 999131.75595 0.00069 - -1 8 9 17 F 1951.701 0.248 7542.3284 0.0146 B- -14548.7507 0.4323 17 002095.237 0.266 - -3 7 10 17 Ne 16500.452 0.354 6640.4991 0.0208 B- -18219.1277 59.6167 17 017713.962 0.380 - -5 6 11 17 Na x 34719.580 59.616 5522.7653 3.5068 B- * 17 037273.000 64.000 -0 8 13 5 18 B -n 51792.640 204.165 4976.6306 11.3425 B- 26873.3742 206.3572 18 055601.683 219.180 - 6 12 6 18 C ++ 24919.266 30.000 6426.1321 1.6667 B- 11806.0982 35.2821 18 026751.930 32.206 - 4 11 7 18 N + 13113.167 18.570 7038.5627 1.0316 B- 13895.9838 18.5695 18 014077.563 19.935 - 2 10 8 18 O -782.81634 0.00064 7767.0981 0.0002 B- -1655.9288 0.4633 17 999159.61214 0.00069 - 0 9 9 18 F 873.112 0.463 7631.6383 0.0257 B- -4444.5049 0.5888 18 000937.324 0.497 - -2 8 10 18 Ne 5317.617 0.363 7341.2577 0.0202 B- -19720.3745 93.8819 18 005708.696 0.390 - -4 7 11 18 Na 25037.992 93.881 6202.2176 5.2156 B- * 18 026879.388 100.785 -0 9 14 5 19 B x 59770.251 525.363 4719.6346 27.6507 B- 27356.4961 534.4964 19 064166.000 564.000 - 7 13 6 19 C -n 32413.754 98.389 6118.2740 5.1784 B- 16557.4995 99.7475 19 034797.594 105.625 - 5 12 7 19 N p-2n 15856.255 16.404 6948.5452 0.8634 B- 12523.3972 16.6143 19 017022.389 17.610 - 3 11 8 19 O -n 3332.858 2.637 7566.4952 0.1388 B- 4820.3029 2.6370 19 003577.969 2.830 - 1 10 9 19 F -1487.44512 0.00082 7779.0192 0.0002 B- -3239.4986 0.1601 18 998403.16207 0.00088 - -1 9 10 19 Ne +3n 1752.054 0.160 7567.3431 0.0084 B- -11177.3310 10.5364 19 001880.906 0.171 - -3 8 11 19 Na 12929.384 10.535 6937.8864 0.5545 B- -18909.0095 60.9189 19 013880.264 11.309 - -5 7 12 19 Mg -pp 31838.394 60.001 5901.4992 3.1579 B- * 19 034179.920 64.413 -0 10 15 5 20 B -n 69401.569 546.357 4405.6529 27.3178 B- 31898.0019 593.0377 20 074505.644 586.538 - 8 14 6 20 C x 37503.567 230.625 5961.4356 11.5312 B- 15737.0689 243.7459 20 040261.732 247.585 - 6 13 7 20 N x 21766.498 78.894 6709.1717 3.9447 B- 17970.3261 78.8991 20 023367.295 84.696 - 4 12 8 20 O -nn 3796.172 0.885 7568.5707 0.0442 B- 3813.6349 0.8854 20 004075.357 0.950 - 2 11 9 20 F -n -17.463 0.030 7720.1351 0.0015 B- 7024.4689 0.0297 19 999981.252 0.031 - 0 10 10 20 Ne -7041.93217 0.00154 8032.2412 0.0002 B- -13892.4207 1.1090 19 992440.17525 0.00165 - -2 9 11 20 Na 6850.489 1.109 7298.5028 0.0554 B- -10627.2054 2.1681 20 007354.301 1.190 - -4 8 12 20 Mg +t 17477.694 1.863 6728.0252 0.0931 B- * 20 018763.075 2.000 -0 11 16 5 21 B -nn 78382.887 558.664 4152.5265 26.6031 B- 32740# 817# 21 084147.485 599.750 - 9 15 6 21 C x 45643# 596# 5674# 28# B- 20411# 611# 21 049000# 640# - 7 14 7 21 N x 25231.915 134.048 6609.0159 6.3832 B- 17169.8816 134.5840 21 027087.573 143.906 - 5 13 8 21 O -3n 8062.034 12.000 7389.3747 0.5714 B- 8109.6390 12.1342 21 008654.948 12.882 - 3 12 9 21 F -nn -47.605 1.800 7738.2934 0.0857 B- 5684.1712 1.8004 20 999948.893 1.932 - 1 11 10 21 Ne -5731.776 0.038 7971.7136 0.0018 B- -3546.9190 0.0177 20 993846.685 0.041 - -1 10 11 21 Na -2184.857 0.042 7765.5581 0.0020 B- -13088.7080 0.7557 20 997654.459 0.045 - -3 9 12 21 Mg x 10903.851 0.755 7105.0317 0.0359 B- -16186# 600# 21 011705.764 0.810 - -5 8 13 21 Al x 27090# 600# 6297# 29# B- * 21 029082# 644# -0 10 16 6 22 C -nn 53611.203 231.490 5421.0778 10.5223 B- 21846.3983 311.0627 22 057553.990 248.515 - 8 15 7 22 N x 31764.805 207.779 6378.5347 9.4445 B- 22481.7725 215.4350 22 034100.918 223.060 - 6 14 8 22 O -4n 9283.032 56.921 7364.8722 2.5873 B- 6489.6562 58.2558 22 009965.744 61.107 - 4 13 9 22 F + 2793.376 12.399 7624.2954 0.5636 B- 10818.0916 12.3990 22 002998.812 13.310 - 2 12 10 22 Ne -8024.716 0.018 8080.4656 0.0008 B- -2843.3243 0.1325 21 991385.113 0.018 - 0 11 11 22 Na -5181.391 0.132 7915.6624 0.0060 B- -4781.4051 0.1631 21 994437.547 0.141 - -2 10 12 22 Mg -399.986 0.159 7662.7645 0.0072 B- -18601# 401# 21 999570.597 0.170 - -4 9 13 22 Al x 18201# 401# 6782# 18# B- -15439# 641# 22 019540# 430# - -6 8 14 22 Si x 33640# 500# 6044# 23# B- * 22 036114# 537# -0 11 17 6 23 C x 64171# 997# 5077# 43# B- 27450# 1082# 23 068890# 1070# - 9 16 7 23 N x 36720.429 420.570 6236.6721 18.2856 B- 22099.0584 437.8271 23 039421.000 451.500 - 7 15 8 23 O x 14621.371 121.712 7163.4856 5.2918 B- 11336.1072 126.1904 23 015696.686 130.663 - 5 14 9 23 F 3285.263 33.320 7622.3447 1.4487 B- 8439.3084 33.3206 23 003526.875 35.770 - 3 13 10 23 Ne -n -5154.045 0.104 7955.2561 0.0045 B- 4375.8085 0.1044 22 994466.905 0.112 - 1 12 11 23 Na -9529.85352 0.00181 8111.4936 0.0002 B- -4056.1790 0.0317 22 989769.28195 0.00194 - -1 11 12 23 Mg - -5473.675 0.032 7901.1229 0.0014 B- -12221.7457 0.3461 22 994123.768 0.034 - -3 10 13 23 Al -- 6748.071 0.345 7335.7275 0.0150 B- -17202# 500# 23 007244.351 0.370 - -5 9 14 23 Si x 23950# 500# 6554# 22# B- * 23 025711# 537# -0 10 17 7 24 N x 46938# 401# 5887# 17# B- 28438# 433# 24 050390# 430# - 8 16 8 24 O x 18500.404 164.874 7039.6855 6.8698 B- 10955.8885 191.6327 24 019861.000 177.000 - 6 15 9 24 F x 7544.516 97.670 7463.5831 4.0696 B- 13496.1583 97.6717 24 008099.370 104.853 - 4 14 10 24 Ne -nn -5951.642 0.513 7993.3252 0.0214 B- 2466.2583 0.5130 23 993610.649 0.550 - 2 13 11 24 Na -n -8417.901 0.017 8063.4882 0.0007 B- 5515.6774 0.0210 23 990963.012 0.017 - 0 12 12 24 Mg -13933.578 0.013 8260.7103 0.0006 B- -13884.7660 0.2282 23 985041.689 0.013 - -2 11 13 24 Al -48.812 0.228 7649.5806 0.0095 B- -10793.9978 19.4734 23 999947.598 0.244 - -4 10 14 24 Si -- 10745.186 19.472 7167.2329 0.8113 B- -23275# 501# 24 011535.430 20.904 - -6 9 15 24 P x 34020# 500# 6165# 21# B- * 24 036522# 537# -0 11 18 7 25 N x 55983# 503# 5613# 20# B- 28654# 529# 25 060100# 540# - 9 17 8 25 O -n 27329.030 165.084 6727.8058 6.6034 B- 15994.8633 191.1909 25 029338.919 177.225 - 7 16 9 25 F x 11334.167 96.442 7336.3065 3.8577 B- 13369.6698 100.7212 25 012167.727 103.535 - 5 15 10 25 Ne -2035.503 29.045 7839.7994 1.1618 B- 7322.3107 29.0701 24 997814.797 31.181 - 3 14 11 25 Na -nn -9357.814 1.200 8101.3979 0.0480 B- 3834.9684 1.2009 24 989953.974 1.288 - 1 13 12 25 Mg -13192.782 0.047 8223.5028 0.0019 B- -4276.8080 0.0447 24 985836.966 0.050 - -1 12 13 25 Al -8915.974 0.065 8021.1366 0.0026 B- -12743.2956 10.0002 24 990428.308 0.069 - -3 11 14 25 Si +3n 3827.322 10.000 7480.1109 0.4000 B- -16363# 400# 25 004108.798 10.735 - -5 10 15 25 P x 20190# 400# 6794# 16# B- * 25 021675# 429# -0 10 18 8 26 O -nn 34661.041 164.950 6497.4790 6.3442 B- 15986.3855 196.6301 26 037210.155 177.081 - 8 17 9 26 F 18674.655 107.027 7082.2497 4.1164 B- 18193.5414 108.6022 26 020048.065 114.898 - 6 16 10 26 Ne x 481.114 18.429 7751.9110 0.7088 B- 7341.8940 18.7585 26 000516.496 19.784 - 4 15 11 26 Na x -6860.780 3.502 8004.2013 0.1347 B- 9353.7631 3.5018 25 992634.649 3.759 - 2 14 12 26 Mg -16214.544 0.029 8333.8711 0.0011 B- -4004.4042 0.0629 25 982592.972 0.031 - 0 13 13 26 Al -12210.139 0.066 8149.7653 0.0026 B- -5069.1361 0.0849 25 986891.876 0.071 - -2 12 14 26 Si - -7141.003 0.108 7924.7083 0.0041 B- -18114# 196# 25 992333.818 0.115 - -4 11 15 26 P x 10973# 196# 7198# 8# B- -16707# 631# 26 011780# 210# - -6 10 16 26 S x 27680# 600# 6525# 23# B- * 26 029716# 644# -0 11 19 8 27 O x 44670# 500# 6185# 19# B- 19536# 514# 27 047955# 537# - 9 18 9 27 F 25133.478 120.198 6879.6662 4.4518 B- 18082.5680 150.6211 27 026981.897 129.037 - 7 17 10 27 Ne x 7050.910 90.770 7520.4151 3.3619 B- 12568.7005 90.8467 27 007569.462 97.445 - 5 16 11 27 Na ++ -5517.791 3.726 7956.9467 0.1380 B- 9068.8037 3.7266 26 994076.408 4.000 - 3 15 12 27 Mg -14586.594 0.047 8263.8525 0.0018 B- 2610.2694 0.0669 26 984340.647 0.050 - 1 14 13 27 Al -17196.864 0.047 8331.5533 0.0018 B- -4812.3583 0.0964 26 981538.408 0.050 - -1 13 14 27 Si - -12384.505 0.107 8124.3420 0.0040 B- -11725.4730 9.0013 26 986704.687 0.115 - -3 12 15 27 P -p -659.032 9.001 7661.0894 0.3334 B- -18150# 400# 26 999292.499 9.662 - -5 11 16 27 S - 17491# 400# 6960# 15# B- * 27 018777# 430# -0 12 20 8 28 O x 52080# 699# 5988# 25# B- 18676# 709# 28 055910# 750# - 10 19 9 28 F -n 33403.796 120.347 6626.8567 4.2981 B- 22104.0579 174.2886 28 035860.448 129.198 - 8 18 10 28 Ne x 11299.738 126.068 7388.3463 4.5024 B- 12288.0534 126.4833 28 012130.767 135.339 - 6 17 11 28 Na x -988.315 10.246 7799.2644 0.3659 B- 14031.6303 10.2498 27 998939.000 11.000 - 4 16 12 28 Mg x -15019.946 0.261 8272.4531 0.0093 B- 1830.7740 0.2653 27 983875.426 0.280 - 2 15 13 28 Al -n -16850.719 0.049 8309.8969 0.0018 B- 4642.0776 0.0486 27 981910.009 0.052 - 0 14 14 28 Si -21492.79711 0.00051 8447.7445 0.0002 B- -14344.9407 1.1473 27 976926.53442 0.00055 - -2 13 15 28 P -7147.856 1.147 7907.4842 0.0410 B- -11221.0593 160.0041 27 992326.460 1.231 - -4 12 16 28 S -- 4073.203 160.000 7478.7911 5.7143 B- -24197# 525# 28 004372.762 171.767 - -6 11 17 28 Cl -p 28270# 500# 6587# 18# B- * 28 030349# 537# -0 11 20 9 29 F x 40150.190 525.363 6444.0314 18.1160 B- 21750.3873 546.2212 29 043103.000 564.000 - 9 19 10 29 Ne x 18399.803 149.505 7167.0673 5.1553 B- 15719.8092 149.6847 29 019753.000 160.500 - 7 18 11 29 Na 2679.994 7.337 7682.1522 0.2530 B- 13292.3538 7.3447 29 002877.091 7.876 - 5 17 12 29 Mg -10612.360 0.345 8113.5317 0.0119 B- 7595.4023 0.4873 28 988607.163 0.369 - 3 16 13 29 Al x -18207.762 0.345 8348.4647 0.0119 B- 3687.3192 0.3447 28 980453.164 0.370 - 1 15 14 29 Si -21895.08154 0.00056 8448.6361 0.0002 B- -4942.2325 0.3589 28 976494.66434 0.00060 - -1 14 15 29 P -16952.849 0.359 8251.2368 0.0124 B- -13858.4257 13.0459 28 981800.368 0.385 - -3 13 16 29 S x -3094.423 13.041 7746.3826 0.4497 B- -17117# 189# 28 996678.000 14.000 - -5 12 17 29 Cl -p 14022# 189# 7129# 7# B- -23947# 478# 29 015053# 203# - -7 11 18 29 Ar -pp 37969# 439# 6276# 15# B- * 29 040761# 471# -0 12 21 9 30 F x 48960# 500# 6205# 17# B- 25680# 561# 30 052561# 537# - 10 20 10 30 Ne 23280.120 253.250 7034.5317 8.4417 B- 14805.4501 253.2946 30 024992.235 271.875 - 8 19 11 30 Na 8474.670 4.727 7501.9685 0.1576 B- 17356.0423 4.9011 30 009097.931 5.074 - 6 18 12 30 Mg -8881.373 1.295 8054.4250 0.0432 B- 6982.7440 2.3287 29 990465.454 1.390 - 4 17 13 30 Al -15864.116 1.936 8261.1049 0.0645 B- 8568.8459 1.9357 29 982969.171 2.077 - 2 16 14 30 Si -n -24432.962 0.022 8520.6549 0.0008 B- -4232.1065 0.0615 29 973770.137 0.023 - 0 15 15 30 P - -20200.856 0.065 8353.5064 0.0022 B- -6141.6014 0.1956 29 978313.490 0.069 - -2 14 16 30 S - -14059.254 0.206 8122.7081 0.0069 B- -18733.8020 23.8769 29 984906.770 0.221 - -4 13 17 30 Cl -p 4674.548 23.876 7472.1698 0.7959 B- -17397# 180# 30 005018.333 25.631 - -6 12 18 30 Ar -pp 22071# 179# 6866# 6# B- * 30 023694# 192# -0 13 22 9 31 F -nn 56843# 535# 6011# 17# B- 25661# 597# 31 061023# 574# - 11 21 10 31 Ne 31181.594 266.195 6813.0902 8.5869 B- 18935.5625 266.5617 31 033474.816 285.772 - 9 20 11 31 Na x 12246.031 13.972 7398.6778 0.4507 B- 15368.1833 14.3065 31 013146.654 15.000 - 7 19 12 31 Mg x -3122.152 3.074 7869.1886 0.0992 B- 11828.5569 3.8009 30 996648.232 3.300 - 5 18 13 31 Al x -14950.709 2.236 8225.5180 0.0721 B- 7998.3286 2.2360 30 983949.754 2.400 - 3 17 14 31 Si -n -22949.037 0.043 8458.2916 0.0014 B- 1491.5071 0.0434 30 975363.196 0.046 - 1 16 15 31 P -24440.54442 0.00075 8481.1677 0.0002 B- -5398.0130 0.2292 30 973761.99768 0.00080 - -1 15 16 31 S -19042.531 0.229 8281.8013 0.0074 B- -12007.9790 3.4541 30 979557.002 0.246 - -3 14 17 31 Cl -- -7034.552 3.447 7869.2101 0.1112 B- -18360# 200# 30 992448.097 3.700 - -5 13 18 31 Ar - 11325# 200# 7252# 6# B- -22935# 361# 31 012158# 215# - -7 12 19 31 K x 34260# 300# 6487# 10# B- * 31 036780# 322# -0 12 22 10 32 Ne x 36999# 503# 6671# 16# B- 18359# 504# 32 039720# 540# - 10 21 11 32 Na x 18640.152 37.260 7219.8815 1.1644 B- 19469.0523 37.4021 32 020011.024 40.000 - 8 20 12 32 Mg x -828.901 3.260 7803.8411 0.1019 B- 10270.4677 7.8787 31 999110.138 3.500 - 6 19 13 32 Al x -11099.368 7.173 8100.3449 0.2241 B- 12978.3208 7.1787 31 988084.338 7.700 - 4 18 14 32 Si x -24077.689 0.298 8481.4690 0.0093 B- 227.1872 0.3008 31 974151.538 0.320 - 2 17 15 32 P -n -24304.876 0.040 8464.1203 0.0013 B- 1710.6608 0.0400 31 973907.643 0.042 - 0 16 16 32 S -26015.53714 0.00131 8493.1301 0.0002 B- -12680.8313 0.5617 31 972071.17354 0.00141 - -2 15 17 32 Cl -13334.706 0.562 8072.4058 0.0176 B- -11134.3536 1.8568 31 985684.605 0.603 - -4 14 18 32 Ar x -2200.352 1.770 7700.0089 0.0553 B- -24190# 400# 31 997637.824 1.900 - -6 13 19 32 K x 21990# 400# 6920# 12# B- * 32 023607# 429# -0 13 23 10 33 Ne x 46130# 600# 6436# 18# B- 22350# 750# 33 049523# 644# - 11 22 11 33 Na x 23780.113 449.912 7089.9262 13.6337 B- 18817.2400 449.9195 33 025529.000 483.000 - 9 21 12 33 Mg 4962.873 2.663 7636.4382 0.0807 B- 13460.2550 7.4767 33 005327.862 2.859 - 7 20 13 33 Al x -8497.382 6.986 8020.6172 0.2117 B- 12016.9460 7.0211 32 990877.685 7.500 - 5 19 14 33 Si x -20514.328 0.699 8361.0596 0.0212 B- 5823.0223 1.2947 32 977976.964 0.750 - 3 18 15 33 P + -26337.350 1.090 8513.8073 0.0330 B- 248.5079 1.0900 32 971725.692 1.170 - 1 17 16 33 S -26585.85830 0.00134 8497.6304 0.0002 B- -5582.5182 0.3908 32 971458.90862 0.00144 - -1 16 17 33 Cl -21003.340 0.391 8304.7557 0.0118 B- -11619.0452 0.5596 32 977451.988 0.419 - -3 15 18 33 Ar x -9384.295 0.401 7928.9559 0.0121 B- -16925# 200# 32 989925.545 0.430 - -5 14 19 33 K x 7540# 200# 7392# 6# B- -23489# 447# 33 008095# 215# - -7 13 20 33 Ca x 31030# 400# 6657# 12# B- * 33 033312# 429# -0 14 24 10 34 Ne -nn 52842# 513# 6287# 15# B- 21161# 789# 34 056728# 551# - 12 23 11 34 Na x 31680.114 599.416 6886.4377 17.6299 B- 23356.7903 599.4561 34 034010.000 643.500 - 10 22 12 34 Mg x 8323.324 6.893 7550.3919 0.2027 B- 11320.9428 7.2072 34 008935.455 7.400 - 8 21 13 34 Al x -2997.619 2.105 7860.3506 0.0619 B- 16994.0653 2.2519 33 996781.924 2.259 - 6 20 14 34 Si x -19991.684 0.801 8337.1659 0.0236 B- 4557.0175 1.1395 33 978538.045 0.860 - 4 19 15 34 P x -24548.702 0.810 8448.1856 0.0238 B- 5382.9879 0.8116 33 973645.886 0.870 - 2 18 16 34 S -29931.689 0.045 8583.4986 0.0013 B- -5491.6037 0.0378 33 967867.011 0.047 - 0 17 17 34 Cl -24440.086 0.049 8398.9706 0.0014 B- -6061.7930 0.0631 33 973762.490 0.052 - -2 16 18 34 Ar -18378.293 0.078 8197.6724 0.0023 B- -17158# 196# 33 980270.092 0.083 - -4 15 19 34 K x -1220# 196# 7670# 6# B- -16110# 358# 33 998690# 210# - -6 14 20 34 Ca x 14890# 300# 7173# 9# B- * 34 015985# 322# -0 13 24 11 35 Na -n 37831# 670# 6745# 19# B- 22192# 723# 35 040614# 720# - 11 23 12 35 Mg x 15639.786 269.668 7356.2338 7.7048 B- 15863.5156 269.7679 35 016790.000 289.500 - 9 22 13 35 Al x -223.730 7.359 7787.1243 0.2103 B- 14167.7504 36.6047 34 999759.816 7.900 - 7 21 14 35 Si 2p-n -14391.480 35.857 8169.5644 1.0245 B- 10466.3291 35.9049 34 984550.111 38.494 - 5 20 15 35 P +p -24857.809 1.866 8446.2496 0.0533 B- 3988.4006 1.8667 34 973314.045 2.003 - 3 19 16 35 S -28846.210 0.040 8537.8511 0.0012 B- 167.3218 0.0257 34 969032.321 0.043 - 1 18 17 35 Cl -29013.532 0.035 8520.2790 0.0010 B- -5966.2429 0.6794 34 968852.694 0.038 - -1 17 18 35 Ar - -23047.289 0.680 8327.4621 0.0194 B- -11874.3955 0.8516 34 975257.719 0.730 - -3 16 19 35 K 4n -11172.893 0.512 7965.8409 0.0146 B- -16363# 200# 34 988005.406 0.550 - -5 15 20 35 Ca x 5190# 200# 7476# 6# B- -21910# 447# 35 005572# 215# - -7 14 21 35 Sc x 27100# 400# 6828# 11# B- * 35 029093# 429# -0 14 25 11 36 Na -n 45903# 687# 6557# 19# B- 25523# 974# 36 049279# 737# - 12 24 12 36 Mg x 20380.159 690.237 7244.4202 19.1733 B- 14429.7751 706.2429 36 021879.000 741.000 - 10 23 13 36 Al x 5950.384 149.505 7623.5154 4.1529 B- 18386.5096 165.8510 36 006388.000 160.500 - 8 22 14 36 Si x -12436.125 71.797 8112.5199 1.9944 B- 7814.9194 72.9852 35 986649.271 77.077 - 6 21 15 36 P + -20251.045 13.114 8307.8692 0.3643 B- 10413.0962 13.1124 35 978259.610 14.078 - 4 20 16 36 S -30664.141 0.188 8575.3900 0.0052 B- -1142.1329 0.1893 35 967080.692 0.201 - 2 19 17 36 Cl -29522.008 0.036 8521.9322 0.0010 B- 709.5343 0.0449 35 968306.822 0.038 - 0 18 18 36 Ar -30231.542 0.027 8519.9096 0.0008 B- -12814.3607 0.3259 35 967545.106 0.028 - -2 17 19 36 K -17417.182 0.325 8142.2233 0.0090 B- -10966.0155 40.0013 35 981301.887 0.349 - -4 16 20 36 Ca 4n -6451.166 40.000 7815.8799 1.1111 B- -22601# 303# 35 993074.388 42.941 - -6 15 21 36 Sc x 16150# 300# 7166# 8# B- * 36 017338# 322# -0 15 26 11 37 Na -nn 53134# 687# 6403# 19# B- 24923# 980# 37 057042# 737# - 13 25 12 37 Mg -n 28211.478 698.947 7055.1115 18.8905 B- 18401.9132 721.8139 37 030286.265 750.350 - 11 24 13 37 Al x 9809.564 180.244 7531.3160 4.8715 B- 16381.0765 213.1678 37 010531.000 193.500 - 9 23 14 37 Si x -6571.512 113.809 7952.9033 3.0759 B- 12424.5003 119.9691 36 992945.191 122.179 - 7 22 15 37 P p-2n -18996.012 37.948 8267.5561 1.0256 B- 7900.4135 37.9474 36 979606.942 40.738 - 5 21 16 37 S -n -26896.426 0.198 8459.9363 0.0054 B- 4865.1258 0.1965 36 971125.500 0.212 - 3 20 17 37 Cl -31761.552 0.052 8570.2816 0.0014 B- -813.8729 0.2000 36 965902.573 0.055 - 1 19 18 37 Ar - -30947.679 0.207 8527.1406 0.0056 B- -6147.4775 0.2270 36 966776.301 0.221 - -1 18 19 37 K -p -24800.201 0.094 8339.8480 0.0025 B- -11664.1314 0.6412 36 973375.890 0.100 - -3 17 20 37 Ca x -13136.070 0.634 8003.4567 0.0171 B- -16916# 300# 36 985897.849 0.680 - -5 16 21 37 Sc x 3780# 300# 7525# 8# B- -21390# 500# 37 004058# 322# - -7 15 22 37 Ti x 25170# 400# 6926# 11# B- * 37 027021# 429# -0 16 27 11 38 Na -n 61905# 715# 6216# 19# B- 27831# 875# 38 066458# 768# - 14 26 12 38 Mg x 34074# 503# 6928# 13# B- 17604# 525# 38 036580# 540# - 12 25 13 38 Al x 16470# 150# 7370# 4# B- 20640# 183# 38 017681# 161# - 10 24 14 38 Si x -4170.299 104.793 7892.8297 2.7577 B- 10451.2656 127.4736 37 995523.000 112.500 - 8 23 15 38 P x -14621.565 72.581 8147.2749 1.9100 B- 12239.6512 72.9340 37 984303.105 77.918 - 6 22 16 38 S + -26861.216 7.172 8448.7829 0.1887 B- 2936.9000 7.1714 37 971163.300 7.699 - 4 21 17 38 Cl -n -29798.116 0.098 8505.4817 0.0026 B- 4916.7109 0.2182 37 968010.408 0.105 - 2 20 18 38 Ar -34714.827 0.195 8614.2807 0.0051 B- -5914.0671 0.0448 37 962732.102 0.209 - 0 19 19 38 K -28800.760 0.195 8438.0593 0.0051 B- -6742.2563 0.0626 37 969081.114 0.209 - -2 18 20 38 Ca -22058.503 0.194 8240.0434 0.0051 B- -17809# 200# 37 976319.223 0.208 - -4 17 21 38 Sc x -4249# 200# 7751# 5# B- -15619# 361# 37 995438# 215# - -6 16 22 38 Ti x 11370# 300# 7319# 8# B- * 38 012206# 322# -0 17 28 11 39 Na -n 69977# 743# 6056# 19# B- 27201# 903# 39 075123# 797# - 15 27 12 39 Mg -n 42775# 513# 6734# 13# B- 21286# 594# 39 045921# 551# - 13 26 13 39 Al x 21490# 300# 7260# 8# B- 19169# 329# 39 023070# 322# - 11 25 14 39 Si x 2320.352 135.532 7730.9793 3.4752 B- 15094.9874 176.2324 39 002491.000 145.500 - 9 24 15 39 P x -12774.636 112.645 8097.9701 2.8883 B- 10388.0361 123.2430 38 986285.865 120.929 - 7 23 16 39 S 2p-n -23162.672 50.000 8344.2698 1.2821 B- 6637.5463 50.0300 38 975133.850 53.677 - 5 22 17 39 Cl -nn -29800.218 1.732 8494.4032 0.0444 B- 3441.9774 5.2915 38 968008.151 1.859 - 3 21 18 39 Ar + -33242.195 5.000 8562.5988 0.1282 B- 565.0000 5.0000 38 964313.037 5.367 - 1 20 19 39 K -33807.19535 0.00456 8557.0258 0.0003 B- -6524.4888 0.5962 38 963706.48482 0.00489 - -1 19 20 39 Ca -27282.707 0.596 8369.6711 0.0153 B- -13109.9804 24.0074 38 970710.811 0.640 - -3 18 21 39 Sc 2n-p -14172.726 24.000 8013.4575 0.6154 B- -16673# 202# 38 984784.953 25.765 - -5 17 22 39 Ti x 2500# 200# 7566# 5# B- -20070# 447# 39 002684# 215# - -7 16 23 39 V x 22570# 400# 7031# 10# B- * 39 024230# 429# -0 16 28 12 40 Mg x 49550# 500# 6598# 13# B- 20729# 583# 40 053194# 537# - 14 27 13 40 Al x 28820# 300# 7097# 7# B- 23154# 324# 40 030940# 322# - 12 26 14 40 Si x 5666.876 121.991 7655.8247 3.0498 B- 13806.0653 147.8912 40 006083.641 130.962 - 10 25 15 40 P x -8139.189 83.607 7981.4177 2.0902 B- 14698.6603 83.7017 39 991262.221 89.755 - 8 24 16 40 S -22837.850 3.982 8329.3255 0.0996 B- 4719.9687 32.3118 39 975482.561 4.274 - 6 23 17 40 Cl + -27557.818 32.066 8427.7660 0.8016 B- 7482.0816 32.0655 39 970415.466 34.423 - 4 22 18 40 Ar -35039.89997 0.00218 8595.2594 0.0002 B- -1504.4031 0.0559 39 962383.12204 0.00234 - 2 21 19 40 K -33535.497 0.056 8538.0907 0.0014 B- 1310.9051 0.0596 39 963998.165 0.060 - 0 20 20 40 Ca -34846.402 0.020 8551.3046 0.0006 B- -14323.0493 2.8281 39 962590.850 0.022 - -2 19 21 40 Sc - -20523.353 2.828 8173.6697 0.0707 B- -11529.9139 68.3023 39 977967.275 3.036 - -4 18 22 40 Ti -8993.439 68.244 7865.8632 1.7061 B- -21463# 308# 39 990345.146 73.262 - -6 17 23 40 V x 12470# 300# 7310# 7# B- * 40 013387# 322# -0 17 29 12 41 Mg x 58100# 500# 6425# 12# B- 23510# 640# 41 062373# 537# - 15 28 13 41 Al x 34590# 400# 6980# 10# B- 21390# 500# 41 037134# 429# - 13 27 14 41 Si x 13200# 300# 7482# 7# B- 18180# 323# 41 014171# 322# - 11 26 15 41 P x -4979.767 120.163 7906.5513 2.9308 B- 14028.8125 120.2326 40 994654.000 129.000 - 9 25 16 41 S x -19008.580 4.099 8229.6358 0.1000 B- 8298.6116 68.8456 40 979593.451 4.400 - 7 24 17 41 Cl x -27307.192 68.723 8412.9593 1.6762 B- 5760.3180 68.7243 40 970684.525 73.777 - 5 23 18 41 Ar -n -33067.510 0.347 8534.3733 0.0085 B- 2492.0392 0.3473 40 964500.570 0.372 - 3 22 19 41 K -35559.54880 0.00376 8576.0731 0.0003 B- -421.6406 0.1377 40 961825.25611 0.00403 - 1 21 20 41 Ca -35137.908 0.138 8546.7075 0.0034 B- -6495.5482 0.1553 40 962277.905 0.147 - -1 20 21 41 Sc -28642.360 0.077 8369.1979 0.0019 B- -12944.8214 27.9449 40 969251.163 0.083 - -3 19 22 41 Ti x -15697.539 27.945 8034.3889 0.6816 B- -16008# 202# 40 983148.000 30.000 - -5 18 23 41 V x 310# 200# 7625# 5# B- -20100# 447# 41 000333# 215# - -7 17 24 41 Cr x 20410# 400# 7116# 10# B- * 41 021911# 429# -0 16 29 13 42 Al x 41990# 500# 6829# 12# B- 25150# 583# 42 045078# 537# - 14 28 14 42 Si x 16840# 300# 7410# 7# B- 15748# 315# 42 018078# 322# - 12 27 15 42 P x 1091.842 95.009 7765.9122 2.2621 B- 18729.5899 95.0504 42 001172.140 101.996 - 10 26 16 42 S x -17637.748 2.794 8193.2275 0.0665 B- 7194.0221 59.6811 41 981065.100 3.000 - 8 25 17 42 Cl x -24831.770 59.616 8345.8864 1.4194 B- 9590.9082 59.8947 41 973342.000 64.000 - 6 24 18 42 Ar x -34422.678 5.775 8555.6141 0.1375 B- 599.3527 5.7763 41 963045.737 6.200 - 4 23 19 42 K -n -35022.031 0.106 8551.2571 0.0025 B- 3525.2626 0.1825 41 962402.305 0.113 - 2 22 20 42 Ca -38547.293 0.148 8616.5646 0.0035 B- -6426.2904 0.0485 41 958617.780 0.159 - 0 21 21 42 Sc -32121.003 0.154 8444.9303 0.0037 B- -7016.6496 0.2239 41 965516.686 0.165 - -2 20 22 42 Ti -25104.353 0.269 8259.2400 0.0064 B- -17485# 196# 41 973049.369 0.289 - -4 19 23 42 V x -7620# 196# 7824# 5# B- -14679# 358# 41 991820# 210# - -6 18 24 42 Cr x 7060# 300# 7456# 7# B- * 42 007579# 322# -0 17 30 13 43 Al x 48270# 600# 6712# 14# B- 23940# 721# 43 051820# 644# - 15 29 14 43 Si x 24330# 400# 7251# 9# B- 19289# 500# 43 026119# 429# - 13 28 15 43 P x 5040# 300# 7681# 7# B- 17236# 300# 43 005411# 322# - 11 27 16 43 S x -12195.461 4.970 8063.8276 0.1156 B- 11964.0500 62.0579 42 986907.635 5.335 - 9 26 17 43 Cl x -24159.510 61.859 8323.8672 1.4386 B- 7850.3002 62.0860 42 974063.700 66.407 - 7 25 18 43 Ar x -32009.811 5.310 8488.2382 0.1235 B- 4565.5836 5.3254 42 965636.056 5.700 - 5 24 19 43 K -4n -36575.394 0.410 8576.2204 0.0095 B- 1833.4783 0.4687 42 960734.701 0.440 - 3 23 20 43 Ca -38408.873 0.227 8600.6653 0.0053 B- -2220.7227 1.8650 42 958766.381 0.244 - 1 22 21 43 Sc -p -36188.150 1.863 8530.8265 0.0433 B- -6872.5591 6.0147 42 961150.425 1.999 - -1 21 22 43 Ti -29315.591 5.719 8352.8054 0.1330 B- -11399.2333 43.2287 42 968528.420 6.139 - -3 20 23 43 V x -17916.358 42.849 8069.5129 0.9965 B- -15946# 205# 42 980766.000 46.000 - -5 19 24 43 Cr x -1970# 200# 7680# 5# B- -19340# 447# 42 997885# 215# - -7 18 25 43 Mn x 17370# 400# 7213# 9# B- * 43 018647# 429# -0 16 30 14 44 Si x 29310# 500# 7156# 11# B- 18200# 640# 44 031466# 537# - 14 29 15 44 P x 11110# 400# 7552# 9# B- 20314# 400# 44 011927# 429# - 12 28 16 44 S x -9204.236 5.216 7996.0154 0.1186 B- 11274.7373 85.7253 43 990118.846 5.600 - 10 27 17 44 Cl x -20478.973 85.566 8234.4788 1.9447 B- 12194.2869 85.5811 43 978014.918 91.859 - 8 26 18 44 Ar x -32673.260 1.584 8493.8411 0.0360 B- 3108.2375 1.6381 43 964923.814 1.700 - 6 25 19 44 K x -35781.498 0.419 8546.7023 0.0095 B- 5687.2319 0.5303 43 961586.984 0.450 - 4 24 20 44 Ca -41468.730 0.325 8658.1769 0.0074 B- -3652.6948 1.7565 43 955481.489 0.348 - 2 23 21 44 Sc -p -37816.035 1.756 8557.3805 0.0399 B- -267.4488 1.8899 43 959402.818 1.884 - 0 22 22 44 Ti -a -37548.586 0.700 8533.5215 0.0159 B- -13740.5071 7.2986 43 959689.936 0.751 - -2 21 23 44 V -23808.079 7.265 8203.4567 0.1651 B- -10386.1805 51.7447 43 974440.977 7.799 - -4 20 24 44 Cr x -13421.899 51.232 7949.6265 1.1644 B- -20882# 304# 43 985591.000 55.000 - -6 19 25 44 Mn x 7460# 300# 7457# 7# B- * 44 008009# 322# -0 17 31 14 45 Si x 37090# 600# 7004# 13# B- 21130# 781# 45 039818# 644# - 15 30 15 45 P x 15960# 500# 7456# 11# B- 19301# 583# 45 017134# 537# - 13 29 16 45 S x -3340# 300# 7867# 7# B- 14922# 329# 44 996414# 322# - 11 28 17 45 Cl x -18262.544 136.163 8181.5991 3.0259 B- 11508.2568 136.1643 44 980394.353 146.177 - 9 27 18 45 Ar x -29770.801 0.512 8419.9526 0.0114 B- 6844.8422 0.7311 44 968039.731 0.550 - 7 26 19 45 K x -36615.643 0.522 8554.6747 0.0116 B- 4196.5868 0.6369 44 960691.491 0.560 - 5 25 20 45 Ca -40812.230 0.365 8630.5467 0.0081 B- 260.0910 0.7377 44 956186.270 0.392 - 3 24 21 45 Sc -41072.321 0.663 8618.9410 0.0147 B- -2062.0551 0.5086 44 955907.051 0.712 - 1 23 22 45 Ti -39010.266 0.836 8555.7321 0.0186 B- -7123.8247 0.2142 44 958120.758 0.897 - -1 22 23 45 V -31886.441 0.863 8380.0394 0.0192 B- -12371.6400 35.4073 44 965768.498 0.926 - -3 21 24 45 Cr x -19514.801 35.397 8087.7286 0.7866 B- -14535# 302# 44 979050.000 38.000 - -5 20 25 45 Mn x -4980# 300# 7747# 7# B- -19388# 412# 44 994654# 322# - -7 19 26 45 Fe -pp 14408# 283# 7299# 6# B- * 45 015467# 304# -0 16 31 15 46 P x 22840# 500# 7320# 11# B- 22200# 640# 46 024520# 537# - 14 30 16 46 S x 640# 400# 7785# 9# B- 14375# 411# 46 000687# 429# - 12 29 17 46 Cl x -13734.949 97.249 8080.7757 2.1141 B- 16036.3062 97.2766 45 985254.926 104.400 - 10 28 18 46 Ar x -29771.255 2.329 8412.3835 0.0506 B- 5642.6746 2.4394 45 968039.244 2.500 - 8 27 19 46 K x -35413.929 0.727 8518.0428 0.0158 B- 7725.6802 2.3490 45 961981.584 0.780 - 6 26 20 46 Ca -43139.610 2.234 8668.9848 0.0486 B- -1377.9665 2.3305 45 953687.726 2.398 - 4 25 21 46 Sc -n -41761.643 0.671 8622.0215 0.0146 B- 2366.6260 0.6666 45 955167.034 0.720 - 2 24 22 46 Ti -44128.269 0.090 8656.4623 0.0020 B- -7052.3723 0.0923 45 952626.356 0.097 - 0 23 23 46 V -37075.897 0.134 8486.1423 0.0029 B- -7604.3264 11.4538 45 960197.389 0.143 - -2 22 24 46 Cr -29471.570 11.453 8303.8233 0.2490 B- -17053.8226 87.3828 45 968360.969 12.295 - -4 21 25 46 Mn x -12417.748 86.629 7916.0805 1.8832 B- -13628# 312# 45 986669.000 93.000 - -6 20 26 46 Fe x 1210# 300# 7603# 7# B- * 46 001299# 322# -0 17 32 15 47 P x 28810# 600# 7209# 13# B- 21610# 721# 47 030929# 644# - 15 31 16 47 S x 7200# 400# 7652# 9# B- 16781# 447# 47 007730# 429# - 13 30 17 47 Cl x -9580# 200# 7992# 4# B- 15787# 200# 46 989715# 215# - 11 29 18 47 Ar x -25367.274 1.211 8311.4250 0.0258 B- 10344.7078 1.8490 46 972767.112 1.300 - 9 28 19 47 K x -35711.982 1.397 8514.8795 0.0297 B- 6632.6837 2.6237 46 961661.612 1.500 - 7 27 20 47 Ca -42344.665 2.221 8639.3548 0.0473 B- 1992.1770 1.1849 46 954541.134 2.384 - 5 26 21 47 Sc -44336.842 1.931 8665.0958 0.0411 B- 600.7694 1.9292 46 952402.444 2.072 - 3 25 22 47 Ti -44937.612 0.080 8661.2325 0.0017 B- -2930.5422 0.0879 46 951757.491 0.085 - 1 24 23 47 V -42007.070 0.110 8582.2348 0.0024 B- -7443.9769 5.1976 46 954903.558 0.118 - -1 23 24 47 Cr -34563.093 5.197 8407.2067 0.1106 B- -11996.7167 32.0943 46 962894.995 5.578 - -3 22 25 47 Mn x -22566.376 31.671 8135.3117 0.6738 B- -15437# 501# 46 975774.000 34.000 - -5 21 26 47 Fe x -7130# 500# 7790# 11# B- -17750# 781# 46 992346# 537# - -7 20 27 47 Co x 10620# 600# 7396# 13# B- * 47 011401# 644# -0 16 32 16 48 S x 12390# 500# 7552# 10# B- 16670# 707# 48 013301# 537# - 14 31 17 48 Cl x -4280# 500# 7883# 10# B- 18075# 500# 47 995405# 537# - 12 30 18 48 Ar x -22354.927 16.767 8243.6656 0.3493 B- 9929.5550 16.7847 47 976001.000 18.000 - 10 29 19 48 K x -32284.482 0.773 8434.2324 0.0161 B- 11940.3857 0.7734 47 965341.184 0.830 - 8 28 20 48 Ca -44224.868 0.018 8666.6916 0.0004 B- 279.2155 4.9499 47 952522.654 0.018 - 6 27 21 48 Sc -44504.083 4.950 8656.2097 0.1031 B- 3988.8685 4.9499 47 952222.903 5.313 - 4 26 22 48 Ti -48492.952 0.074 8723.0122 0.0016 B- -4014.9467 0.9691 47 947940.677 0.079 - 2 25 23 48 V -44478.005 0.972 8623.0686 0.0202 B- -1656.6918 7.3746 47 952250.900 1.043 - 0 24 24 48 Cr +nn -42821.313 7.311 8572.2553 0.1523 B- -13524.6692 9.9157 47 954029.431 7.848 - -2 23 25 48 Mn -29296.644 6.699 8274.1924 0.1396 B- -11288.0685 92.4609 47 968548.760 7.191 - -4 22 26 48 Fe x -18008.575 92.218 8022.7254 1.9212 B- -19738# 509# 47 980667.000 99.000 - -6 21 27 48 Co x 1730# 500# 7595# 10# B- -16448# 656# 48 001857# 537# - -8 20 28 48 Ni -pp 18178# 424# 7236# 9# B- * 48 019515# 455# -0 17 33 16 49 S -n 20391# 583# 7400# 12# B- 19652# 707# 49 021891# 626# - 15 32 17 49 Cl x 740# 400# 7785# 8# B- 17800# 565# 49 000794# 429# - 13 31 18 49 Ar x -17060# 400# 8132# 8# B- 12551# 400# 48 981685# 429# - 11 30 19 49 K x -29611.496 0.801 8372.2753 0.0164 B- 11688.5069 0.8205 48 968210.753 0.860 - 9 29 20 49 Ca -n -41300.003 0.178 8594.8500 0.0036 B- 5262.4445 2.2745 48 955662.625 0.190 - 7 28 21 49 Sc -46562.447 2.268 8686.2805 0.0463 B- 2001.5652 2.2684 48 950013.159 2.434 - 5 27 22 49 Ti -48564.012 0.078 8711.1625 0.0016 B- -601.8555 0.8203 48 947864.391 0.084 - 3 26 23 49 V - -47962.157 0.824 8682.9135 0.0168 B- -2629.8047 2.3487 48 948510.509 0.884 - 1 25 24 49 Cr -45332.352 2.202 8613.2777 0.0449 B- -7712.4265 0.2329 48 951333.720 2.363 - -1 24 25 49 Mn -37619.925 2.214 8439.9150 0.0452 B- -12869.1957 24.3199 48 959613.350 2.377 - -3 23 26 49 Fe x -24750.730 24.219 8161.3121 0.4943 B- -14971# 501# 48 973429.000 26.000 - -5 22 27 49 Co x -9780# 500# 7840# 10# B- -18309# 781# 48 989501# 537# - -7 21 28 49 Ni x 8530# 600# 7450# 12# B- * 49 009157# 644# -0 16 33 17 50 Cl x 7700# 400# 7651# 8# B- 20930# 640# 50 008266# 429# - 14 32 18 50 Ar x -13230# 500# 8054# 10# B- 12498# 500# 49 985797# 537# - 12 31 19 50 K x -25727.853 7.731 8288.5833 0.1546 B- 13861.3774 7.8919 49 972380.015 8.300 - 10 30 20 50 Ca x -39589.230 1.584 8550.1639 0.0317 B- 4947.8903 2.9723 49 957499.215 1.700 - 8 29 21 50 Sc -44537.120 2.515 8633.4747 0.0503 B- 6894.7470 2.5166 49 952187.437 2.700 - 6 28 22 50 Ti -51431.867 0.082 8755.7227 0.0017 B- -2208.6274 0.0579 49 944785.622 0.088 - 4 27 23 50 V -49223.240 0.093 8695.9032 0.0019 B- 1038.1240 0.0551 49 947156.681 0.099 - 2 26 24 50 Cr -50261.364 0.094 8701.0188 0.0019 B- -7634.4776 0.0672 49 946042.209 0.100 - 0 25 25 50 Mn -42626.886 0.115 8532.6823 0.0023 B- -8150.4267 8.3842 49 954238.157 0.123 - -2 24 26 50 Fe x -34476.460 8.383 8354.0268 0.1677 B- -16887.0566 126.0308 49 962988.000 9.000 - -4 23 27 50 Co x -17589.403 125.752 8000.6387 2.5150 B- -14130# 516# 49 981117.000 135.000 - -6 22 28 50 Ni x -3460# 500# 7702# 10# B- * 49 996286# 537# -0 17 34 17 51 Cl x 14290# 700# 7530# 14# B- 20780# 806# 51 015341# 751# - 15 33 18 51 Ar x -6490# 400# 7922# 8# B- 16026# 400# 50 993033# 429# - 13 32 19 51 K x -22515.457 13.041 8221.3350 0.2557 B- 13816.8529 13.0517 50 975828.664 14.000 - 11 31 20 51 Ca x -36332.310 0.522 8476.9135 0.0102 B- 6918.0432 2.5686 50 960995.663 0.560 - 9 30 21 51 Sc -43250.353 2.515 8597.2213 0.0493 B- 6482.6122 2.5612 50 953568.838 2.700 - 7 29 22 51 Ti -49732.965 0.484 8708.9912 0.0095 B- 2470.1402 0.4820 50 946609.468 0.519 - 5 28 23 51 V -52203.105 0.097 8742.0852 0.0019 B- -752.3907 0.1494 50 943957.664 0.104 - 3 27 24 51 Cr -51450.715 0.167 8711.9923 0.0033 B- -3207.4893 0.3256 50 944765.388 0.178 - 1 26 25 51 Mn -48243.225 0.304 8633.7602 0.0060 B- -8054.0400 1.4309 50 948208.770 0.326 - -1 25 26 51 Fe x -40189.185 1.398 8460.4977 0.0274 B- -12847.0389 48.4579 50 956855.137 1.501 - -3 24 27 51 Co x -27342.146 48.438 8193.2549 0.9498 B- -15692# 503# 50 970647.000 52.000 - -5 23 28 51 Ni x -11650# 500# 7870# 10# B- * 50 987493# 537# -0 18 35 17 52 Cl x 22360# 700# 7386# 13# B- 23739# 922# 52 024004# 751# - 16 34 18 52 Ar x -1380# 600# 7827# 12# B- 15758# 601# 51 998519# 644# - 14 33 19 52 K x -17137.628 33.534 8115.0303 0.6449 B- 17128.6431 33.5405 51 981602.000 36.000 - 12 32 20 52 Ca x -34266.272 0.671 8429.3821 0.0129 B- 6257.2889 3.1463 51 963213.646 0.720 - 10 31 21 52 Sc -40523.560 3.074 8534.6695 0.0591 B- 8954.1372 4.1223 51 956496.170 3.300 - 8 30 22 52 Ti -49477.698 2.747 8691.8193 0.0528 B- 1965.3340 2.7510 51 946883.509 2.948 - 6 29 23 52 V -n -51443.032 0.159 8714.5690 0.0031 B- 3976.4763 0.1601 51 944773.636 0.170 - 4 28 24 52 Cr -55419.508 0.112 8775.9946 0.0022 B- -4708.1214 0.0633 51 940504.714 0.120 - 2 27 25 52 Mn - -50711.387 0.129 8670.4087 0.0025 B- -2379.2912 0.1534 51 945559.090 0.138 - 0 26 26 52 Fe -- -48332.095 0.179 8609.6079 0.0035 B- -13988.1167 5.2831 51 948113.364 0.192 - -2 25 27 52 Co -34343.979 5.282 8325.5606 0.1016 B- -11784.1230 83.0710 51 963130.224 5.669 - -4 24 28 52 Ni x -22559.856 82.903 8083.8977 1.5943 B- -20680# 606# 51 975781.000 89.000 - -6 23 29 52 Cu x -1880# 600# 7671# 12# B- * 51 997982# 644# -0 17 35 18 53 Ar x 6791# 699# 7677# 13# B- 19086# 708# 53 007290# 750# - 15 34 19 53 K x -12295.722 111.779 8022.8488 2.1090 B- 17091.9853 120.0471 52 986800.000 120.000 - 13 33 20 53 Ca x -29387.707 43.780 8330.5778 0.8260 B- 9381.8471 47.2223 52 968451.000 47.000 - 11 32 21 53 Sc -38769.555 17.698 8492.8325 0.3339 B- 8111.8785 17.9325 52 958379.173 19.000 - 9 31 22 53 Ti x -46881.433 2.888 8631.1256 0.0545 B- 4970.2419 4.2386 52 949670.714 3.100 - 7 30 23 53 V +p -51851.675 3.103 8710.1425 0.0585 B- 3435.9426 3.1017 52 944334.940 3.331 - 5 29 24 53 Cr -55287.618 0.116 8760.2103 0.0022 B- -597.2679 0.3430 52 940646.304 0.124 - 3 28 25 53 Mn -54690.350 0.346 8734.1798 0.0065 B- -3742.8664 1.6971 52 941287.497 0.371 - 1 27 26 53 Fe -50947.483 1.669 8648.7985 0.0315 B- -8288.1073 0.4431 52 945305.629 1.792 - -1 26 27 53 Co -42659.376 1.727 8477.6578 0.0326 B- -13028.5485 25.2096 52 954203.278 1.854 - -3 25 28 53 Ni x -29630.827 25.150 8217.0749 0.4745 B- -16491# 501# 52 968190.000 27.000 - -5 24 29 53 Cu x -13140# 500# 7891# 9# B- * 52 985894# 537# -0 18 36 18 54 Ar x 12560# 800# 7578# 15# B- 17710# 894# 54 013484# 859# - 16 35 19 54 K x -5150# 400# 7891# 7# B- 20010# 403# 53 994471# 429# - 14 34 20 54 Ca x -25160.587 48.438 8247.4967 0.8970 B- 9277.3463 50.4129 53 972989.000 52.000 - 12 33 21 54 Sc x -34437.934 13.973 8404.8115 0.2588 B- 11305.8789 21.1188 53 963029.359 15.000 - 10 32 22 54 Ti x -45743.812 15.835 8599.6917 0.2932 B- 4154.4548 19.3840 53 950892.000 17.000 - 8 31 23 54 V -49898.267 11.180 8662.1382 0.2070 B- 7037.1118 11.1794 53 946432.009 12.001 - 6 30 24 54 Cr -56935.379 0.132 8777.9672 0.0025 B- -1377.1325 1.0051 53 938877.359 0.142 - 4 29 25 54 Mn -p -55558.247 1.007 8737.9768 0.0186 B- 696.3688 1.0587 53 940355.772 1.080 - 2 28 26 54 Fe -56254.615 0.343 8736.3846 0.0064 B- -8244.5478 0.0893 53 939608.189 0.368 - 0 27 27 54 Co -48010.068 0.355 8569.2199 0.0066 B- -8731.7558 4.6710 53 948459.075 0.380 - -2 26 28 54 Ni x -39278.312 4.657 8393.0328 0.0862 B- -18038# 400# 53 957833.000 5.000 - -4 25 29 54 Cu x -21240# 400# 8045# 7# B- -15538# 454# 53 977198# 429# - -6 24 30 54 Zn -pp -5702# 217# 7742# 4# B- * 53 993879# 232# -0 17 36 19 55 K x 470# 500# 7792# 9# B- 19121# 525# 55 000505# 537# - 15 35 20 55 Ca x -18650.375 160.217 8125.9260 2.9130 B- 12191.7329 171.9435 54 979978.000 172.000 - 13 34 21 55 Sc x -30842.108 62.411 8333.3694 1.1347 B- 10990.3608 68.7671 54 966889.637 67.000 - 11 33 22 55 Ti x -41832.469 28.876 8518.9696 0.5250 B- 7292.6673 39.5419 54 955091.000 31.000 - 9 32 23 55 V x -49125.136 27.013 8637.3391 0.4912 B- 5985.1877 27.0143 54 947262.000 29.000 - 7 31 24 55 Cr -n -55110.324 0.228 8731.9362 0.0042 B- 2602.2183 0.3219 54 940836.637 0.245 - 5 30 25 55 Mn -57712.542 0.260 8765.0247 0.0047 B- -231.1204 0.1786 54 938043.040 0.279 - 3 29 26 55 Fe -57481.422 0.308 8746.5981 0.0056 B- -3451.4254 0.3241 54 938291.158 0.330 - 1 28 27 55 Co -54029.996 0.405 8669.6204 0.0074 B- -8694.0350 0.5775 54 941996.416 0.434 - -1 27 28 55 Ni - -45335.961 0.705 8497.3225 0.0128 B- -13700.5585 155.5611 54 951329.846 0.757 - -3 26 29 55 Cu x -31635.403 155.560 8233.9970 2.8284 B- -17366# 429# 54 966038.000 167.000 - -5 25 30 55 Zn x -14270# 400# 7904# 7# B- * 54 984681# 429# -0 18 37 19 56 K x 7980# 600# 7663# 11# B- 21491# 650# 56 008567# 644# - 16 36 20 56 Ca x -13510.390 249.640 8033.1654 4.4579 B- 12005.4580 360.2029 55 985496.000 268.000 - 14 35 21 56 Sc x -25515.848 259.665 8233.5781 4.6369 B- 13907.1470 278.3271 55 972607.611 278.761 - 12 34 22 56 Ti -39422.995 100.201 8467.9495 1.7893 B- 6760.4051 188.1842 55 957677.675 107.569 - 10 33 23 56 V -46183.401 175.884 8574.7006 3.1408 B- 9101.7270 175.8854 55 950420.082 188.819 - 8 32 24 56 Cr ++ -55285.128 0.578 8723.2609 0.0103 B- 1626.5384 0.5524 55 940648.977 0.620 - 6 31 25 56 Mn -n -56911.666 0.293 8738.3358 0.0052 B- 3695.4973 0.2065 55 938902.816 0.314 - 4 30 26 56 Fe -60607.163 0.268 8790.3563 0.0048 B- -4566.6455 0.4104 55 934935.537 0.287 - 2 29 27 56 Co -56040.518 0.475 8694.8386 0.0085 B- -2132.8689 0.3735 55 939838.032 0.510 - 0 28 28 56 Ni -53907.649 0.399 8642.7811 0.0071 B- -15277.9163 6.4070 55 942127.761 0.428 - -2 27 29 56 Cu x -38629.733 6.395 8355.9907 0.1142 B- -13240# 400# 55 958529.278 6.864 - -4 26 30 56 Zn x -25390# 400# 8106# 7# B- -21550# 640# 55 972743# 429# - -6 25 31 56 Ga x -3840# 500# 7707# 9# B- * 55 995878# 537# -0 19 38 19 57 K x 14130# 600# 7563# 11# B- 20689# 721# 57 015169# 644# - 17 37 20 57 Ca x -6560# 400# 7912# 7# B- 14820# 438# 56 992958# 429# - 15 36 21 57 Sc x -21379.653 179.778 8158.1666 3.1540 B- 13022.1957 273.3249 56 977048.000 193.000 - 13 35 22 57 Ti x -34401.848 205.879 8372.9008 3.6119 B- 10033.2148 222.6466 56 963068.098 221.020 - 11 34 23 57 V x -44435.063 84.766 8535.1967 1.4871 B- 8089.9214 84.7864 56 952297.000 91.000 - 9 33 24 57 Cr x -52524.985 1.863 8663.3998 0.0327 B- 4961.2946 2.3948 56 943612.112 2.000 - 7 32 25 57 Mn -57486.279 1.505 8736.7146 0.0264 B- 2695.7375 1.5219 56 938285.944 1.615 - 5 31 26 57 Fe -60182.017 0.268 8770.2829 0.0047 B- -836.3589 0.4493 56 935391.950 0.287 - 3 30 27 57 Co -59345.658 0.516 8741.8845 0.0090 B- -3261.6970 0.6417 56 936289.819 0.553 - 1 29 28 57 Ni -56083.961 0.566 8670.9364 0.0099 B- -8774.9466 0.4393 56 939791.394 0.608 - -1 28 29 57 Cu -47309.014 0.501 8503.2646 0.0088 B- -14759# 200# 56 949211.686 0.537 - -3 27 30 57 Zn x -32550# 200# 8231# 4# B- -17140# 447# 56 965056# 215# - -5 26 31 57 Ga x -15410# 400# 7916# 7# B- * 56 983457# 429# -0 20 39 19 58 K x 21930# 700# 7437# 12# B- 23461# 860# 58 023543# 751# - 18 38 20 58 Ca x -1530# 500# 7828# 9# B- 13949# 535# 57 998357# 537# - 16 37 21 58 Sc x -15479.569 190.025 8054.9436 3.2763 B- 15438.0995 264.0509 57 983382.000 204.000 - 14 36 22 58 Ti x -30917.668 183.340 8307.6290 3.1610 B- 9512.9152 206.8675 57 966808.519 196.823 - 12 35 23 58 V x -40430.584 95.816 8458.1560 1.6520 B- 11561.2240 95.8625 57 956595.985 102.862 - 10 34 24 58 Cr x -51991.808 2.981 8643.9987 0.0514 B- 3835.7607 4.0227 57 944184.501 3.200 - 8 33 25 58 Mn x -55827.568 2.701 8696.6438 0.0466 B- 6327.7027 2.7198 57 940066.643 2.900 - 6 32 26 58 Fe -62155.271 0.316 8792.2534 0.0055 B- -2307.9785 1.1389 57 933273.575 0.339 - 4 31 27 58 Co -59847.292 1.153 8738.9719 0.0199 B- 381.5789 1.1071 57 935751.292 1.237 - 2 30 28 58 Ni -60228.871 0.349 8732.0621 0.0060 B- -8561.0204 0.4425 57 935341.650 0.374 - 0 29 29 58 Cu -51667.851 0.564 8570.9696 0.0097 B- -9368.9796 50.0020 57 944532.283 0.604 - -2 28 30 58 Zn -- -42298.871 50.001 8395.9467 0.8621 B- -18759# 304# 57 954590.296 53.678 - -4 27 31 58 Ga x -23540# 300# 8059# 5# B- -15960# 583# 57 974729# 322# - -6 26 32 58 Ge x -7580# 500# 7770# 9# B- * 57 991863# 537# -0 21 40 19 59 K x 28750# 800# 7332# 14# B- 22940# 1000# 59 030864# 859# - 19 39 20 59 Ca x 5810# 600# 7708# 10# B- 16639# 650# 59 006237# 644# - 17 38 21 59 Sc x -10829.550 249.640 7976.4073 4.2312 B- 15050# 390# 58 988374.000 268.000 - 15 37 22 59 Ti x -25880# 300# 8218# 5# B- 11731# 330# 58 972217# 322# - 13 36 23 59 V x -37610.617 137.400 8403.8034 2.3288 B- 10505.3137 137.4021 58 959623.343 147.505 - 11 35 24 59 Cr x -48115.931 0.671 8568.5995 0.0114 B- 7409.3977 2.4234 58 948345.426 0.720 - 9 34 25 59 Mn x -55525.328 2.329 8680.9224 0.0395 B- 5139.6290 2.3520 58 940391.111 2.500 - 7 33 26 59 Fe -60664.957 0.330 8754.7746 0.0056 B- 1564.8804 0.3690 58 934873.492 0.354 - 5 32 27 59 Co -62229.838 0.397 8768.0379 0.0067 B- -1073.0050 0.1944 58 933193.524 0.426 - 3 31 28 59 Ni -61156.833 0.351 8736.5912 0.0060 B- -4798.3786 0.3973 58 934345.442 0.376 - 1 30 29 59 Cu -56358.454 0.528 8642.0027 0.0090 B- -9142.7760 0.6018 58 939496.713 0.566 - -1 29 30 59 Zn -47215.678 0.759 8473.7802 0.0129 B- -13456# 170# 58 949311.886 0.814 - -3 28 31 59 Ga x -33760# 170# 8232# 3# B- -17390# 434# 58 963757# 183# - -5 27 32 59 Ge x -16370# 400# 7924# 7# B- * 58 982426# 429# -0 20 40 20 60 Ca x 11000# 700# 7627# 12# B- 15550# 860# 60 011809# 751# - 18 39 21 60 Sc x -4550# 500# 7873# 8# B- 17549# 555# 59 995115# 537# - 16 38 22 60 Ti x -22099.698 240.325 8152.7858 4.0054 B- 10987.7040 301.4311 59 976275.000 258.000 - 14 37 23 60 V x -33087.402 181.946 8322.8751 3.0324 B- 13821.0986 181.9496 59 964479.215 195.327 - 12 36 24 60 Cr x -46908.500 1.118 8540.1876 0.0186 B- 6059.4457 2.5831 59 949641.656 1.200 - 10 35 25 60 Mn x -52967.946 2.329 8628.1392 0.0388 B- 8445.2283 4.1261 59 943136.574 2.500 - 8 34 26 60 Fe -nn -61413.174 3.406 8755.8539 0.0568 B- 237.2633 3.4106 59 934070.249 3.656 - 6 33 27 60 Co -n -61650.437 0.403 8746.7692 0.0067 B- 2822.8058 0.2124 59 933815.536 0.433 - 4 32 28 60 Ni -64473.243 0.353 8780.7769 0.0059 B- -6127.9810 1.5735 59 930785.129 0.378 - 2 31 29 60 Cu - -58345.262 1.613 8665.6047 0.0269 B- -4170.7922 1.6286 59 937363.787 1.731 - 0 30 30 60 Zn -54174.470 0.548 8583.0524 0.0091 B- -14584# 200# 59 941841.317 0.588 - -2 29 31 60 Ga x -39590# 200# 8327# 3# B- -12060# 361# 59 957498# 215# - -4 28 32 60 Ge x -27530# 300# 8113# 5# B- -21890# 500# 59 970445# 322# - -6 27 33 60 As x -5640# 400# 7735# 7# B- * 59 993945# 429# -0 21 41 20 61 Ca x 19010# 800# 7503# 13# B- 18510# 1000# 61 020408# 859# - 19 40 21 61 Sc x 500# 600# 7794# 10# B- 16870# 671# 61 000537# 644# - 17 39 22 61 Ti x -16370# 300# 8058# 5# B- 13807# 381# 60 982426# 322# - 15 38 23 61 V x -30177.121 234.920 8271.0417 3.8511 B- 12319.3807 234.9272 60 967603.529 252.196 - 13 37 24 61 Cr x -42496.502 1.863 8460.1734 0.0305 B- 9245.6277 2.9822 60 954378.130 2.000 - 11 36 25 61 Mn x -51742.130 2.329 8598.9157 0.0382 B- 7178.3730 3.4965 60 944452.541 2.500 - 9 35 26 61 Fe x -58920.503 2.608 8703.7686 0.0428 B- 3977.6759 2.7399 60 936746.241 2.800 - 7 34 27 61 Co p2n -62898.179 0.839 8756.1510 0.0138 B- 1323.8504 0.7899 60 932476.031 0.901 - 5 33 28 61 Ni -64222.029 0.355 8765.0281 0.0058 B- -2237.9663 0.9617 60 931054.819 0.381 - 3 32 29 61 Cu p2n -61984.063 0.951 8715.5148 0.0156 B- -5635.1565 15.9028 60 933457.375 1.020 - 1 31 30 61 Zn -56348.906 15.899 8610.3098 0.2606 B- -9214.2438 37.6786 60 939506.964 17.068 - -1 30 31 61 Ga -47134.662 37.994 8446.4313 0.6228 B- -13345# 302# 60 949398.861 40.787 - -3 29 32 61 Ge x -33790# 300# 8215# 5# B- -16590# 424# 60 963725# 322# - -5 28 33 61 As x -17200# 300# 7930# 5# B- * 60 981535# 322# -0 20 41 21 62 Sc x 7310# 600# 7688# 10# B- 19510# 721# 62 007848# 644# - 18 40 22 62 Ti x -12200# 400# 7990# 6# B- 13013# 479# 61 986903# 429# - 16 39 23 62 V x -25213.164 264.287 8187.7565 4.2627 B- 15639.4478 264.3094 61 972932.556 283.723 - 14 38 24 62 Cr x -40852.611 3.447 8427.3871 0.0556 B- 7671.3532 7.3947 61 956142.920 3.700 - 12 37 25 62 Mn IT -48523.965 6.542 8538.5002 0.1055 B- 10354.0920 7.1142 61 947907.384 7.023 - 10 36 26 62 Fe x -58878.057 2.794 8692.8831 0.0451 B- 2546.3427 18.7834 61 936791.809 3.000 - 8 35 27 62 Co + -61424.399 18.574 8721.3347 0.2996 B- 5322.0404 18.5695 61 934058.198 19.940 - 6 34 28 62 Ni -66746.440 0.425 8794.5555 0.0069 B- -3958.8965 0.4751 61 928344.753 0.455 - 4 33 29 62 Cu - -62787.543 0.637 8718.0839 0.0103 B- -1619.4548 0.6507 61 932594.803 0.683 - 2 32 30 62 Zn -61168.088 0.615 8679.3451 0.0099 B- -9181.0666 0.3763 61 934333.359 0.660 - 0 31 31 62 Ga -51987.022 0.637 8518.6449 0.0103 B- -9847# 140# 61 944189.639 0.684 - -2 30 32 62 Ge x -42140# 140# 8347# 2# B- -17720# 331# 61 954761# 150# - -4 29 33 62 As x -24420# 300# 8049# 5# B- * 61 973784# 322# -0 21 42 21 63 Sc x 13070# 700# 7603# 11# B- 18930# 860# 63 014031# 751# - 19 41 22 63 Ti x -5860# 500# 7891# 8# B- 15880# 605# 62 993709# 537# - 17 40 23 63 V x -21740.141 339.995 8130.7809 5.3968 B- 14438.1586 347.6720 62 976661.000 365.000 - 15 39 24 63 Cr x -36178.299 72.657 8347.5398 1.1533 B- 10708.7611 72.7520 62 961161.000 78.000 - 13 38 25 63 Mn x -46887.061 3.726 8505.1020 0.0591 B- 8748.5685 5.6915 62 949664.672 4.000 - 11 37 26 63 Fe -55635.629 4.302 8631.5499 0.0683 B- 6215.9238 19.0668 62 940272.698 4.618 - 9 36 27 63 Co -61851.553 18.575 8717.7972 0.2948 B- 3661.3385 18.5704 62 933599.630 19.941 - 7 35 28 63 Ni -65512.891 0.426 8763.4955 0.0068 B- 66.9768 0.0149 62 929669.021 0.457 - 5 34 29 63 Cu -65579.868 0.426 8752.1404 0.0068 B- -3366.4392 1.5450 62 929597.119 0.457 - 3 33 30 63 Zn -62213.429 1.560 8686.2866 0.0248 B- -5666.3294 2.0330 62 933211.140 1.674 - 1 32 31 63 Ga x -56547.100 1.304 8583.9267 0.0207 B- -9625.8787 37.2826 62 939294.194 1.400 - -1 31 32 63 Ge x -46921.221 37.260 8418.7167 0.5914 B- -13421# 204# 62 949628.000 40.000 - -3 30 33 63 As x -33500# 200# 8193# 3# B- -16650# 539# 62 964036# 215# - -5 29 34 63 Se x -16850# 500# 7917# 8# B- * 62 981911# 537# -0 20 42 22 64 Ti x -1480# 600# 7826# 9# B- 14840# 721# 63 998411# 644# - 18 41 23 64 V x -16320# 400# 8045# 6# B- 17320# 500# 63 982480# 429# - 16 40 24 64 Cr x -33639.978 299.941 8303.5626 4.6866 B- 9349.0622 299.9620 63 963886.000 322.000 - 14 39 25 64 Mn x -42989.040 3.540 8437.4175 0.0553 B- 11980.5117 6.1402 63 953849.369 3.800 - 12 38 26 64 Fe x -54969.552 5.017 8612.3888 0.0784 B- 4822.8898 20.6249 63 940987.761 5.386 - 10 37 27 64 Co + -59792.442 20.005 8675.5223 0.3126 B- 7306.5921 20.0000 63 935810.176 21.476 - 8 36 28 64 Ni -67099.034 0.463 8777.4637 0.0072 B- -1674.6156 0.2055 63 927966.228 0.497 - 6 35 29 64 Cu -65424.418 0.427 8739.0736 0.0067 B- 579.5996 0.6447 63 929764.001 0.458 - 4 34 30 64 Zn -66004.018 0.644 8735.9057 0.0101 B- -7171.1912 1.4825 63 929141.776 0.690 - 2 33 31 64 Ga -58832.827 1.429 8611.6317 0.0223 B- -4517.3237 3.9905 63 936840.366 1.533 - 0 32 32 64 Ge x -54315.503 3.726 8528.8243 0.0582 B- -14783# 203# 63 941689.912 4.000 - -2 31 33 64 As -p -39532# 203# 8286# 3# B- -12673# 540# 63 957560# 218# - -4 30 34 64 Se x -26860# 500# 8075# 8# B- * 63 971165# 537# -0 21 43 22 65 Ti x 5210# 700# 7726# 11# B- 17320# 860# 65 005593# 751# - 19 42 23 65 V x -12110# 500# 7981# 8# B- 16200# 539# 64 986999# 537# - 17 41 24 65 Cr x -28310# 200# 8218# 3# B- 12657# 200# 64 969608# 215# - 15 40 25 65 Mn x -40967.344 3.726 8400.6822 0.0573 B- 10250.5576 6.3257 64 956019.749 4.000 - 13 39 26 65 Fe x -51217.902 5.112 8546.3470 0.0786 B- 7967.3036 5.5198 64 945015.323 5.487 - 11 38 27 65 Co x -59185.205 2.083 8656.8848 0.0320 B- 5940.5911 2.1379 64 936462.071 2.235 - 9 37 28 65 Ni -n -65125.796 0.483 8736.2424 0.0074 B- 2137.8808 0.6997 64 930084.585 0.518 - 7 36 29 65 Cu -67263.677 0.643 8757.0967 0.0099 B- -1351.6527 0.3557 64 927789.476 0.690 - 5 35 30 65 Zn -65912.024 0.646 8724.2660 0.0099 B- -3254.5380 0.6305 64 929240.534 0.693 - 3 34 31 65 Ga -62657.486 0.791 8662.1601 0.0122 B- -6179.2631 2.3046 64 932734.424 0.849 - 1 33 32 65 Ge -56478.223 2.165 8555.0584 0.0333 B- -9541.1670 84.7936 64 939368.136 2.323 - -1 32 33 65 As x -46937.056 84.766 8396.2351 1.3041 B- -13917# 312# 64 949611.000 91.000 - -3 31 34 65 Se x -33020# 300# 8170# 5# B- -16529# 583# 64 964552# 322# - -5 30 35 65 Br x -16490# 500# 7904# 8# B- * 64 982297# 537# -0 20 43 23 66 V x -6300# 500# 7894# 8# B- 18840# 583# 65 993237# 537# - 18 42 24 66 Cr x -25140# 300# 8168# 5# B- 11610# 300# 65 973011# 322# - 16 41 25 66 Mn x -36750.392 11.178 8331.7986 0.1694 B- 13317.4543 11.9056 65 960546.833 12.000 - 14 40 26 66 Fe x -50067.847 4.099 8521.7245 0.0621 B- 6340.6944 14.5611 65 946249.958 4.400 - 12 39 27 66 Co x -56408.541 13.972 8605.9419 0.2117 B- 9597.7522 14.0421 65 939442.943 15.000 - 10 38 28 66 Ni x -66006.293 1.397 8739.5086 0.0212 B- 251.9958 1.5405 65 929139.333 1.500 - 8 37 29 66 Cu -66258.289 0.649 8731.4730 0.0098 B- 2640.9396 0.9255 65 928868.804 0.696 - 6 36 30 66 Zn -68899.229 0.744 8759.6335 0.0113 B- -5175.5000 0.8000 65 926033.639 0.798 - 4 35 31 66 Ga - -63723.729 1.092 8669.3631 0.0166 B- -2116.6879 2.6376 65 931589.766 1.172 - 2 34 32 66 Ge x -61607.041 2.401 8625.4383 0.0364 B- -9581.9570 6.1685 65 933862.124 2.577 - 0 33 33 66 As x -52025.084 5.682 8468.4034 0.0861 B- -10365# 200# 65 944148.778 6.100 - -2 32 34 66 Se x -41660# 200# 8300# 3# B- -18091# 447# 65 955276# 215# - -4 31 35 66 Br x -23570# 400# 8014# 6# B- * 65 974697# 429# -0 21 44 23 67 V x -1744# 600# 7829# 9# B- 17526# 721# 66 998128# 644# - 19 43 24 67 Cr x -19270# 400# 8079# 6# B- 14311# 447# 66 979313# 429# - 17 42 25 67 Mn x -33580# 200# 8281# 3# B- 12128# 200# 66 963950# 215# - 15 41 26 67 Fe x -45708.416 3.819 8449.9359 0.0570 B- 9613.3678 7.4900 66 950930.000 4.100 - 13 40 27 67 Co x -55321.783 6.443 8581.7422 0.0962 B- 8420.9047 7.0607 66 940609.625 6.917 - 11 39 28 67 Ni x -63742.688 2.888 8695.7505 0.0431 B- 3576.8654 3.0223 66 931569.413 3.100 - 9 38 29 67 Cu -67319.553 0.892 8737.4597 0.0133 B- 560.8226 0.8296 66 927729.490 0.957 - 7 37 30 67 Zn -67880.376 0.755 8734.1534 0.0113 B- -1001.2201 1.1196 66 927127.422 0.810 - 5 36 31 67 Ga -66879.156 1.176 8707.5330 0.0176 B- -4205.4380 4.4066 66 928202.276 1.262 - 3 35 32 67 Ge -62673.718 4.319 8633.0884 0.0645 B- -6086.4858 4.3418 66 932716.999 4.636 - 1 34 33 67 As -56587.232 0.443 8530.5685 0.0066 B- -10006.9381 67.0690 66 939251.110 0.475 - -1 33 34 67 Se x -46580.294 67.068 8369.5344 1.0010 B- -14051# 307# 66 949994.000 72.000 - -3 32 35 67 Br x -32530# 300# 8148# 4# B- -16978# 520# 66 965078# 322# - -5 31 36 67 Kr -pp -15552# 424# 7883# 6# B- * 66 983305# 455# -0 20 44 24 68 Cr x -15690# 500# 8026# 7# B- 13230# 583# 67 983156# 537# - 18 43 25 68 Mn x -28920# 300# 8209# 4# B- 14977# 356# 67 968953# 322# - 16 42 26 68 Fe x -43897# 193# 8418# 3# B- 7746# 193# 67 952875# 207# - 14 41 27 68 Co -51642.591 3.859 8520.1301 0.0567 B- 11821.2318 4.8760 67 944559.401 4.142 - 12 40 28 68 Ni x -63463.822 2.981 8682.4667 0.0438 B- 2103.2205 3.3753 67 931868.787 3.200 - 10 39 29 68 Cu x -65567.043 1.584 8701.8913 0.0233 B- 4440.1115 1.7645 67 929610.887 1.700 - 8 38 30 68 Zn -70007.154 0.778 8755.6820 0.0115 B- -2921.1000 1.2000 67 924844.232 0.835 - 6 37 31 68 Ga - -67086.054 1.430 8701.2195 0.0210 B- -107.2555 2.3594 67 927980.161 1.535 - 4 36 32 68 Ge x -66978.799 1.876 8688.1371 0.0276 B- -8084.2715 2.6320 67 928095.305 2.014 - 2 35 33 68 As -58894.527 1.846 8557.7457 0.0271 B- -4705.0786 1.9112 67 936774.127 1.981 - 0 34 34 68 Se x -54189.449 0.496 8477.0482 0.0073 B- -15398# 259# 67 941825.236 0.532 - -2 33 35 68 Br -p -38791# 259# 8239# 4# B- -13165# 563# 67 958356# 278# - -4 32 36 68 Kr x -25626# 500# 8034# 7# B- * 67 972489# 537# -0 21 45 24 69 Cr x -9630# 500# 7939# 7# B- 15730# 640# 68 989662# 537# - 19 44 25 69 Mn x -25360# 400# 8155# 6# B- 13839# 447# 68 972775# 429# - 17 43 26 69 Fe x -39199# 200# 8345# 3# B- 11186# 218# 68 957918# 215# - 15 42 27 69 Co x -50385.447 85.697 8495.4062 1.2420 B- 9593.2084 85.7784 68 945909.000 92.000 - 13 41 28 69 Ni x -59978.656 3.726 8623.0998 0.0540 B- 5757.5650 3.9793 68 935610.267 4.000 - 11 40 29 69 Cu x -65736.221 1.397 8695.2044 0.0203 B- 2681.6854 1.6075 68 929429.267 1.500 - 9 39 30 69 Zn -n -68417.906 0.795 8722.7311 0.0115 B- 909.9134 1.4234 68 926550.360 0.853 - 7 38 31 69 Ga -69327.820 1.197 8724.5798 0.0174 B- -2227.1455 0.5500 68 925573.528 1.285 - 5 37 32 69 Ge -67100.674 1.318 8680.9640 0.0191 B- -3988.4927 31.9822 68 927964.467 1.414 - 3 36 33 69 As -63112.181 31.999 8611.8214 0.4638 B- -6677.4672 32.0215 68 932246.289 34.352 - 1 35 34 69 Se -56434.714 1.490 8503.7082 0.0216 B- -10175.2364 42.0293 68 939414.845 1.599 - -1 34 35 69 Br -p -46259.478 42.003 8344.9026 0.6087 B- -14119# 303# 68 950338.410 45.091 - -3 33 36 69 Kr x -32140# 300# 8129# 4# B- * 68 965496# 322# -0 22 46 24 70 Cr x -5640# 600# 7884# 9# B- 14810# 781# 69 993945# 644# - 20 45 25 70 Mn x -20450# 500# 8084# 7# B- 16440# 583# 69 978046# 537# - 18 44 26 70 Fe x -36890# 300# 8308# 4# B- 9635# 300# 69 960397# 322# - 16 43 27 70 Co x -46524.963 10.992 8434.1980 0.1570 B- 12688.9049 11.1987 69 950053.400 11.800 - 14 42 28 70 Ni x -59213.868 2.144 8604.2917 0.0306 B- 3762.5123 2.4011 69 936431.300 2.301 - 12 41 29 70 Cu x -62976.381 1.082 8646.8655 0.0155 B- 6588.3675 2.2018 69 932392.078 1.161 - 10 40 30 70 Zn -69564.748 1.918 8729.8086 0.0274 B- -654.5979 1.5737 69 925319.175 2.058 - 8 39 31 70 Ga -68910.150 1.201 8709.2808 0.0172 B- 1651.8861 1.4520 69 926021.914 1.289 - 6 38 32 70 Ge -70562.036 0.820 8721.7028 0.0117 B- -6228.0630 1.6200 69 924248.542 0.880 - 4 37 33 70 As x -64333.973 1.397 8621.5541 0.0200 B- -2404.0737 2.1118 69 930934.642 1.500 - 2 36 34 70 Se x -61929.900 1.584 8576.0338 0.0226 B- -10504.2727 14.9878 69 933515.521 1.700 - 0 35 35 70 Br x -51425.627 14.904 8414.7964 0.2129 B- -10325# 201# 69 944792.321 16.000 - -2 34 36 70 Kr x -41100# 200# 8256# 3# B- * 69 955877# 215# -0 21 46 25 71 Mn x -16620# 500# 8030# 7# B- 15310# 640# 70 982158# 537# - 19 45 26 71 Fe x -31930# 400# 8235# 6# B- 12440# 613# 70 965722# 429# - 17 44 27 71 Co x -44369.930 465.030 8398.7344 6.5497 B- 11036.3053 465.0353 70 952366.923 499.230 - 15 43 28 71 Ni x -55406.236 2.237 8543.1564 0.0315 B- 7304.8989 2.6879 70 940518.962 2.401 - 13 42 29 71 Cu x -62711.134 1.490 8635.0233 0.0210 B- 4617.6517 3.0437 70 932676.831 1.600 - 11 41 30 71 Zn -67328.786 2.654 8689.0417 0.0374 B- 2810.3405 2.7748 70 927719.578 2.849 - 9 40 31 71 Ga -70139.127 0.811 8717.6050 0.0114 B- -232.4698 0.0934 70 924702.554 0.870 - 7 39 32 71 Ge -69906.657 0.815 8703.3118 0.0115 B- -2013.4000 4.0825 70 924952.120 0.874 - 5 38 33 71 As - -67893.257 4.163 8663.9350 0.0586 B- -4746.7420 5.0140 70 927113.594 4.469 - 3 37 34 71 Se x -63146.515 2.794 8586.0606 0.0394 B- -6644.0883 6.0820 70 932209.431 3.000 - 1 36 35 71 Br -56502.426 5.402 8481.4629 0.0761 B- -10175.2155 128.8452 70 939342.153 5.799 - -1 35 36 71 Kr -46327.211 128.769 8327.1310 1.8136 B- -14037# 420# 70 950265.695 138.238 - -3 34 37 71 Rb x -32290# 400# 8118# 6# B- * 70 965335# 429# -0 22 47 25 72 Mn x -11170# 600# 7955# 8# B- 18080# 781# 71 988009# 644# - 20 46 26 72 Fe x -29250# 500# 8195# 7# B- 11050# 583# 71 968599# 537# - 18 45 27 72 Co x -40300# 300# 8338# 4# B- 13926# 300# 71 956736# 322# - 16 44 28 72 Ni x -54226.068 2.237 8520.2118 0.0311 B- 5556.9381 2.6374 71 941785.924 2.401 - 14 43 29 72 Cu x -59783.006 1.397 8586.5256 0.0194 B- 8362.4883 2.5578 71 935820.306 1.500 - 12 42 30 72 Zn x -68145.495 2.142 8691.8053 0.0298 B- 442.7892 2.2934 71 926842.806 2.300 - 10 41 31 72 Ga -68588.284 0.818 8687.0893 0.0114 B- 3997.6263 0.8217 71 926367.452 0.878 - 8 40 32 72 Ge -72585.910 0.076 8731.7459 0.0011 B- -4356.1019 4.0825 71 922075.824 0.081 - 6 39 33 72 As - -68229.808 4.083 8660.3786 0.0567 B- -361.6194 4.5276 71 926752.291 4.383 - 4 38 34 72 Se x -67868.189 1.956 8644.4902 0.0272 B- -8806.4384 2.2083 71 927140.506 2.100 - 2 37 35 72 Br x -59061.750 1.025 8511.3126 0.0142 B- -5121.1683 8.0761 71 936594.606 1.100 - 0 36 36 72 Kr x -53940.582 8.011 8429.3193 0.1113 B- -15611# 500# 71 942092.406 8.600 - -2 35 37 72 Rb x -38330# 500# 8202# 7# B- * 71 958851# 537# -0 23 48 25 73 Mn x -6700# 600# 7895# 8# B- 17289# 781# 72 992807# 644# - 21 47 26 73 Fe x -23990# 500# 8121# 7# B- 13980# 583# 72 974246# 537# - 19 46 27 73 Co x -37970# 300# 8302# 4# B- 12139# 300# 72 959238# 322# - 17 45 28 73 Ni x -50108.159 2.423 8457.6529 0.0332 B- 8879.2856 3.1038 72 946206.681 2.601 - 15 44 29 73 Cu -58987.445 1.942 8568.5699 0.0266 B- 6605.9659 2.6910 72 936674.376 2.084 - 13 43 30 73 Zn x -65593.411 1.863 8648.3455 0.0255 B- 4105.9329 2.5064 72 929582.580 2.000 - 11 42 31 73 Ga x -69699.343 1.677 8693.8740 0.0230 B- 1598.1889 1.6777 72 925174.680 1.800 - 9 41 32 73 Ge -71297.532 0.057 8705.0500 0.0008 B- -344.7759 3.8528 72 923458.954 0.061 - 7 40 33 73 As -70952.757 3.853 8689.6099 0.0528 B- -2725.3604 7.3993 72 923829.086 4.136 - 5 39 34 73 Se -68227.396 7.424 8641.5591 0.1017 B- -4581.6095 10.0278 72 926754.881 7.969 - 3 38 35 73 Br -63645.787 6.741 8568.0803 0.0923 B- -7094.0287 9.4187 72 931673.441 7.237 - 1 37 36 73 Kr x -56551.758 6.578 8460.1847 0.0901 B- -10540.1468 41.3212 72 939289.193 7.061 - -1 36 37 73 Rb -p -46011.611 40.794 8305.0821 0.5588 B- -14061# 403# 72 950604.506 43.794 - -3 35 38 73 Sr x -31950# 401# 8102# 5# B- * 72 965700# 430# -0 22 48 26 74 Fe x -20660# 500# 8076# 7# B- 12881# 640# 73 977821# 537# - 20 47 27 74 Co x -33540# 400# 8239# 5# B- 15160# 447# 73 963993# 429# - 18 46 28 74 Ni x -48700# 200# 8433# 3# B- 7306# 200# 73 947718# 215# - 16 45 29 74 Cu x -56006.213 6.148 8521.5633 0.0831 B- 9750.5077 6.6424 73 939874.860 6.600 - 14 44 30 74 Zn x -65756.720 2.515 8642.7547 0.0340 B- 2292.9057 3.9102 73 929407.260 2.700 - 12 43 31 74 Ga x -68049.626 2.994 8663.1676 0.0405 B- 5372.8249 2.9941 73 926945.725 3.214 - 10 42 32 74 Ge -73422.451 0.013 8725.2011 0.0003 B- -2562.3871 1.6931 73 921177.760 0.013 - 8 41 33 74 As -70860.064 1.693 8680.0020 0.0229 B- 1353.1467 1.6931 73 923928.596 1.817 - 6 40 34 74 Se -72213.210 0.015 8687.7155 0.0003 B- -6925.0492 5.8354 73 922475.933 0.015 - 4 39 35 74 Br -65288.161 5.835 8583.5615 0.0789 B- -2956.3173 6.1730 73 929910.279 6.264 - 2 38 36 74 Kr -62331.844 2.013 8533.0390 0.0272 B- -10415.8280 3.4240 73 933084.016 2.161 - 0 37 37 74 Rb -51916.016 3.027 8381.7123 0.0409 B- -11089# 100# 73 944265.867 3.249 - -2 36 38 74 Sr x -40827# 100# 8221# 1# B- * 73 956170# 107# -0 23 49 26 75 Fe x -14700# 600# 7996# 8# B- 15861# 721# 74 984219# 644# - 21 48 27 75 Co x -30560# 400# 8197# 5# B- 13680# 447# 74 967192# 429# - 19 47 28 75 Ni x -44240# 200# 8369# 3# B- 10230# 200# 74 952506# 215# - 17 46 29 75 Cu -54470.219 0.718 8495.0801 0.0096 B- 8088.6967 2.0837 74 941523.817 0.770 - 15 45 30 75 Zn x -62558.916 1.956 8592.4981 0.0261 B- 5901.7231 2.0679 74 932840.244 2.100 - 13 44 31 75 Ga x -68460.639 0.671 8660.7565 0.0089 B- 3396.3337 0.6727 74 926504.484 0.720 - 11 43 32 75 Ge -n -71856.973 0.052 8695.6096 0.0007 B- 1177.2301 0.8851 74 922858.370 0.055 - 9 42 33 75 As -73034.203 0.884 8700.8748 0.0118 B- -864.7139 0.8816 74 921594.562 0.948 - 7 41 34 75 Se -72169.489 0.073 8678.9139 0.0010 B- -3062.4694 4.2855 74 922522.870 0.078 - 5 40 35 75 Br x -69107.020 4.285 8627.6497 0.0571 B- -4783.3880 9.1671 74 925810.566 4.600 - 3 39 36 75 Kr x -64323.632 8.104 8553.4399 0.1081 B- -7104.9299 8.1895 74 930945.744 8.700 - 1 38 37 75 Rb x -57218.702 1.180 8448.2762 0.0157 B- -10600.0000 220.0000 74 938573.200 1.266 - -1 37 38 75 Sr - -46618.702 220.003 8296.5116 2.9334 B- -14799# 372# 74 949952.767 236.183 - -3 36 39 75 Y x -31820# 300# 8089# 4# B- * 74 965840# 322# -0 24 50 26 76 Fe x -10590# 600# 7943# 8# B- 15070# 781# 75 988631# 644# - 22 49 27 76 Co x -25660# 500# 8131# 7# B- 16530# 583# 75 972453# 537# - 20 48 28 76 Ni x -42190# 300# 8338# 4# B- 8791# 300# 75 954707# 322# - 18 47 29 76 Cu x -50981.627 0.913 8443.6018 0.0120 B- 11321.3964 1.7183 75 945268.974 0.980 - 16 46 30 76 Zn -62303.024 1.456 8582.2735 0.0192 B- 3993.6241 2.4384 75 933114.956 1.562 - 14 45 31 76 Ga x -66296.648 1.956 8624.5272 0.0257 B- 6916.2501 1.9562 75 928827.624 2.100 - 12 44 32 76 Ge -73212.898 0.018 8705.2364 0.0003 B- -921.5145 0.8864 75 921402.725 0.019 - 10 43 33 76 As -n -72291.384 0.886 8682.8172 0.0117 B- 2960.5756 0.8864 75 922392.011 0.951 - 8 42 34 76 Se -75251.959 0.016 8711.4781 0.0003 B- -4962.8810 9.3218 75 919213.702 0.017 - 6 41 35 76 Br - -70289.078 9.322 8635.8830 0.1227 B- -1275.3724 10.1490 75 924541.574 10.007 - 4 40 36 76 Kr -69013.706 4.013 8608.8077 0.0528 B- -8534.6172 4.1214 75 925910.743 4.308 - 2 39 37 76 Rb x -60479.089 0.938 8486.2161 0.0123 B- -6231.4432 34.4780 75 935073.031 1.006 - 0 38 38 76 Sr x -54247.645 34.465 8393.9294 0.4535 B- -15998# 302# 75 941762.760 37.000 - -2 37 39 76 Y x -38250# 300# 8173# 4# B- * 75 958937# 322# -0 23 50 27 77 Co x -21910# 600# 8082# 8# B- 15440# 721# 76 976479# 644# - 21 49 28 77 Ni x -37350# 400# 8272# 5# B- 11513# 400# 76 959903# 429# - 19 48 29 77 Cu x -48862.828 1.211 8411.2501 0.0157 B- 9926.3750 2.3148 76 947543.599 1.300 - 17 47 30 77 Zn -58789.203 1.973 8530.0037 0.0256 B- 7203.1495 3.1237 76 936887.197 2.117 - 15 46 31 77 Ga x -65992.352 2.422 8613.3907 0.0315 B- 5220.5176 2.4225 76 929154.299 2.600 - 13 45 32 77 Ge -n -71212.870 0.053 8671.0293 0.0007 B- 2703.4642 1.6926 76 923549.843 0.056 - 11 44 33 77 As -73916.334 1.692 8695.9789 0.0220 B- 683.1627 1.6920 76 920647.555 1.816 - 9 43 34 77 Se -74599.497 0.062 8694.6908 0.0008 B- -1364.6792 2.8099 76 919914.150 0.067 - 7 42 35 77 Br - -73234.818 2.811 8666.8073 0.0365 B- -3065.3663 3.4244 76 921379.193 3.017 - 5 41 36 77 Kr x -70169.451 1.956 8616.8370 0.0254 B- -5338.9516 2.3510 76 924669.999 2.100 - 3 40 37 77 Rb x -64830.500 1.304 8537.3396 0.0169 B- -7027.0566 8.0244 76 930401.599 1.400 - 1 39 38 77 Sr x -57803.443 7.918 8435.9188 0.1028 B- -11365# 203# 76 937945.454 8.500 - -1 38 39 77 Y -p -46439# 203# 8278# 3# B- -14839# 448# 76 950146# 218# - -3 37 40 77 Zr x -31600# 400# 8075# 5# B- * 76 966076# 429# -0 24 51 27 78 Co x -15320# 700# 7997# 9# B- 19560# 806# 77 983553# 751# - 22 50 28 78 Ni x -34880# 400# 8238# 5# B- 9910# 400# 77 962555# 429# - 20 49 29 78 Cu -44789.474 13.332 8354.6695 0.1709 B- 12693.7680 13.4727 77 951916.524 14.312 - 18 48 30 78 Zn -57483.242 1.944 8507.3800 0.0249 B- 6220.8433 2.2088 77 938289.204 2.086 - 16 47 31 78 Ga -63704.085 1.051 8577.1043 0.0135 B- 8157.9729 3.6884 77 931610.854 1.127 - 14 46 32 78 Ge -nn -71862.058 3.536 8671.6636 0.0453 B- 954.9114 10.3987 77 922852.911 3.795 - 12 45 33 78 As +pn -72816.970 9.779 8673.8760 0.1254 B- 4208.9819 9.7801 77 921827.771 10.498 - 10 44 34 78 Se -77025.952 0.179 8717.8072 0.0023 B- -3573.7836 3.5750 77 917309.244 0.191 - 8 43 35 78 Br - -73452.168 3.580 8661.9594 0.0459 B- 726.1153 3.5845 77 921145.858 3.842 - 6 42 36 78 Kr -74178.283 0.307 8661.2385 0.0039 B- -7242.8560 3.2520 77 920366.341 0.329 - 4 41 37 78 Rb x -66935.427 3.237 8558.3512 0.0415 B- -3761.4779 8.1248 77 928141.866 3.475 - 2 40 38 78 Sr x -63173.949 7.452 8500.0971 0.0955 B- -11001# 298# 77 932179.979 8.000 - 0 39 39 78 Y x -52173# 298# 8349# 4# B- -11323# 499# 77 943990# 320# - -2 38 40 78 Zr x -40850# 400# 8194# 5# B- * 77 956146# 429# -0 23 51 28 79 Ni x -28160# 500# 8150# 6# B- 14248# 511# 78 969769# 537# - 21 50 29 79 Cu x -42408.039 104.979 8320.9380 1.3289 B- 11024.2629 105.0030 78 954473.100 112.700 - 19 49 30 79 Zn -53432.302 2.225 8450.5825 0.0282 B- 9116.0536 2.5295 78 942638.067 2.388 - 17 48 31 79 Ga -62548.355 1.208 8556.0725 0.0153 B- 6978.8242 37.1467 78 932851.582 1.296 - 15 47 32 79 Ge -69527.180 37.161 8634.5089 0.4704 B- 4108.9014 37.4361 78 925359.506 39.893 - 13 46 33 79 As -73636.081 5.325 8676.6172 0.0674 B- 2281.3849 5.3284 78 920948.419 5.716 - 11 45 34 79 Se -n -75917.466 0.223 8695.5923 0.0028 B- 150.6016 1.0186 78 918499.252 0.238 - 9 44 35 79 Br -76068.067 1.001 8687.5956 0.0127 B- -1625.7778 3.3333 78 918337.574 1.074 - 7 43 36 79 Kr - -74442.290 3.480 8657.1130 0.0441 B- -3639.5114 3.9423 78 920082.919 3.736 - 5 42 37 79 Rb -70802.778 1.943 8601.1401 0.0246 B- -5323.1140 7.5630 78 923990.095 2.085 - 3 41 38 79 Sr -65479.664 7.421 8523.8558 0.0939 B- -7676.7291 80.4515 78 929704.692 7.967 - 1 40 39 79 Y x -57802.935 80.108 8416.7788 1.0140 B- -11033# 310# 78 937946.000 86.000 - -1 39 40 79 Zr x -46770# 300# 8267# 4# B- -15120# 583# 78 949790# 322# - -3 38 41 79 Nb x -31650# 500# 8066# 6# B- * 78 966022# 537# -0 24 52 28 80 Ni x -23240# 600# 8088# 7# B- 13440# 671# 79 975051# 644# - 22 51 29 80 Cu x -36679# 300# 8246# 4# B- 14969# 300# 79 960623# 322# - 20 50 30 80 Zn -51648.619 2.585 8423.5457 0.0323 B- 7575.0553 3.8774 79 944552.929 2.774 - 18 49 31 80 Ga x -59223.675 2.891 8508.4545 0.0361 B- 10311.6397 3.5409 79 936420.773 3.103 - 16 48 32 80 Ge x -69535.314 2.054 8627.5707 0.0257 B- 2679.2869 3.9156 79 925350.773 2.205 - 14 47 33 80 As x -72214.601 3.333 8651.2824 0.0417 B- 5544.8861 3.4412 79 922474.440 3.578 - 12 46 34 80 Se -77759.487 0.947 8710.8142 0.0118 B- -1870.4623 0.3095 79 916521.761 1.016 - 10 45 35 80 Br -75889.025 0.993 8677.6541 0.0124 B- 2004.4299 1.1413 79 918529.784 1.065 - 8 44 36 80 Kr -77893.455 0.695 8692.9301 0.0087 B- -5717.9785 1.9883 79 916377.940 0.745 - 6 43 37 80 Rb x -72175.476 1.863 8611.6760 0.0233 B- -1864.0090 3.9331 79 922516.442 2.000 - 4 42 38 80 Sr x -70311.467 3.464 8578.5966 0.0433 B- -9163.3050 7.1389 79 924517.538 3.718 - 2 41 39 80 Y x -61148.162 6.242 8454.2759 0.0780 B- -6388# 300# 79 934354.750 6.701 - 0 40 40 80 Zr x -54760# 300# 8365# 4# B- -16339# 500# 79 941213# 322# - -2 39 41 80 Nb x -38420# 400# 8151# 5# B- * 79 958754# 429# -0 25 53 28 81 Ni x -16090# 700# 8000# 9# B- 15820# 761# 80 982727# 751# - 23 52 29 81 Cu x -31910# 300# 8185# 4# B- 14289# 300# 80 965743# 322# - 21 51 30 81 Zn x -46199.669 5.030 8351.9262 0.0621 B- 11428.2924 5.9960 80 950402.617 5.400 - 19 50 31 81 Ga x -57627.962 3.264 8483.3576 0.0403 B- 8663.7335 3.8508 80 938133.841 3.503 - 17 49 32 81 Ge x -66291.695 2.055 8580.6587 0.0254 B- 6241.6189 3.3436 80 928832.941 2.205 - 15 48 33 81 As -72533.314 2.644 8648.0571 0.0326 B- 3855.7050 2.8072 80 922132.288 2.838 - 13 47 34 81 Se -76389.019 0.977 8685.9998 0.0121 B- 1588.0317 1.3787 80 917993.019 1.049 - 11 46 35 81 Br -77977.051 0.978 8695.9465 0.0121 B- -280.8517 0.4713 80 916288.197 1.049 - 9 45 36 81 Kr -77696.199 1.074 8682.8206 0.0133 B- -2239.4954 5.0188 80 916589.703 1.152 - 7 44 37 81 Rb -75456.704 4.904 8645.5139 0.0605 B- -3928.5695 5.8170 80 918993.900 5.265 - 5 43 38 81 Sr x -71528.134 3.128 8587.3545 0.0386 B- -5815.2156 6.2451 80 923211.393 3.358 - 3 42 39 81 Y x -65712.919 5.405 8505.9031 0.0667 B- -8188.5003 92.3762 80 929454.283 5.802 - 1 41 40 81 Zr x -57524.418 92.218 8395.1519 1.1385 B- -11164# 410# 80 938245.000 99.000 - -1 40 41 81 Nb x -46360# 400# 8248# 5# B- -14900# 640# 80 950230# 429# - -3 39 42 81 Mo x -31460# 500# 8054# 6# B- * 80 966226# 537# -0 26 54 28 82 Ni x -10720# 800# 7935# 10# B- 15010# 894# 81 988492# 859# - 24 53 29 82 Cu x -25730# 400# 8108# 5# B- 16584# 400# 81 972378# 429# - 22 52 30 82 Zn x -42313.960 3.074 8301.1175 0.0375 B- 10616.7652 3.9162 81 954574.097 3.300 - 20 51 31 82 Ga x -52930.725 2.426 8421.0494 0.0296 B- 12484.3497 3.2960 81 943176.531 2.604 - 18 50 32 82 Ge x -65415.075 2.240 8563.7567 0.0273 B- 4690.3523 4.3452 81 929774.031 2.405 - 16 49 33 82 As x -70105.427 3.729 8611.4153 0.0455 B- 7488.4677 3.7579 81 924738.731 4.003 - 14 48 34 82 Se -77593.895 0.466 8693.1973 0.0057 B- -95.2184 1.0767 81 916699.531 0.500 - 12 47 35 82 Br -77498.677 0.971 8682.4953 0.0118 B- 3093.1185 0.9714 81 916801.752 1.042 - 10 46 36 82 Kr -80591.79509 0.00551 8710.6754 0.0003 B- -4403.9824 3.0088 81 913481.15368 0.00591 - 8 45 37 82 Rb IT -76187.813 3.009 8647.4275 0.0367 B- -177.7503 6.7048 81 918209.023 3.230 - 6 44 38 82 Sr -76010.062 5.992 8635.7190 0.0731 B- -7945.9650 8.1324 81 918399.845 6.432 - 4 43 39 82 Y x -68064.097 5.499 8529.2762 0.0671 B- -4450.0341 5.7221 81 926930.189 5.902 - 2 42 40 82 Zr x -63614.063 1.584 8465.4666 0.0193 B- -11804# 300# 81 931707.497 1.700 - 0 41 41 82 Nb x -51810# 300# 8312# 4# B- -11440# 500# 81 944380# 322# - -2 40 42 82 Mo x -40370# 400# 8163# 5# B- * 81 956661# 429# -0 25 54 29 83 Cu x -20390# 500# 8044# 6# B- 15900# 583# 82 978110# 537# - 23 53 30 83 Zn x -36290# 300# 8226# 4# B- 12967# 300# 82 961041# 322# - 21 52 31 83 Ga x -49257.129 2.612 8372.5756 0.0315 B- 11719.3136 3.5592 82 947120.300 2.804 - 19 51 32 83 Ge x -60976.442 2.427 8504.3462 0.0292 B- 8692.8893 3.6979 82 934539.100 2.604 - 17 50 33 83 As x -69669.331 2.799 8599.6540 0.0337 B- 5671.2117 4.1290 82 925206.900 3.004 - 15 49 34 83 Se -n -75340.543 3.036 8658.5560 0.0366 B- 3673.1780 4.8392 82 919118.604 3.259 - 13 48 35 83 Br -79013.721 3.795 8693.3852 0.0457 B- 976.9222 3.7947 82 915175.285 4.073 - 11 47 36 83 Kr -79990.643 0.009 8695.7295 0.0003 B- -920.0039 2.3288 82 914126.516 0.009 - 9 46 37 83 Rb -79070.639 2.329 8675.2193 0.0281 B- -2273.0239 6.4245 82 915114.181 2.500 - 7 45 38 83 Sr -76797.616 6.834 8638.4076 0.0823 B- -4591.9435 19.8444 82 917554.372 7.336 - 5 44 39 83 Y x -72205.672 18.631 8573.6571 0.2245 B- -6294.0125 19.7074 82 922484.026 20.000 - 3 43 40 83 Zr x -65911.659 6.430 8488.3997 0.0775 B- -8298.7493 162.2075 82 929240.926 6.902 - 1 42 41 83 Nb x -57612.910 162.080 8378.9889 1.9528 B- -11273# 432# 82 938150.000 174.000 - -1 41 42 83 Mo x -46340# 401# 8234# 5# B- -15020# 641# 82 950252# 430# - -3 40 43 83 Tc x -31320# 500# 8043# 6# B- * 82 966377# 537# -0 26 55 29 84 Cu x -13720# 500# 7965# 6# B- 18110# 640# 83 985271# 537# - 24 54 30 84 Zn x -31830# 400# 8171# 5# B- 12264# 401# 83 965829# 429# - 22 53 31 84 Ga x -44094.136 29.808 8307.5250 0.3549 B- 14054.2989 29.9760 83 952663.000 32.000 - 20 52 32 84 Ge x -58148.435 3.171 8465.5244 0.0377 B- 7705.1329 4.4789 83 937575.090 3.403 - 18 51 33 84 As x -65853.568 3.171 8547.9385 0.0377 B- 10094.1624 3.7219 83 929303.290 3.403 - 16 50 34 84 Se -75947.731 1.961 8658.7935 0.0233 B- 1835.3638 25.7652 83 918466.761 2.105 - 14 49 35 84 Br -77783.094 25.730 8671.3294 0.3063 B- 4656.2510 25.7300 83 916496.417 27.622 - 12 48 36 84 Kr -82439.34527 0.00382 8717.4473 0.0003 B- -2680.3708 2.1940 83 911497.72708 0.00410 - 10 47 37 84 Rb -79758.975 2.194 8676.2244 0.0261 B- 890.6058 2.3356 83 914375.223 2.355 - 8 46 38 84 Sr -80649.580 1.243 8677.5132 0.0148 B- -6755.1411 4.4114 83 913419.118 1.334 - 6 45 39 84 Y -73894.439 4.299 8587.7812 0.0512 B- -2472.7471 6.9767 83 920671.060 4.615 - 4 44 40 84 Zr x -71421.692 5.499 8549.0301 0.0655 B- -10227.8497 5.5133 83 923325.663 5.903 - 2 43 41 84 Nb x -61193.842 0.401 8417.9563 0.0048 B- -7024# 298# 83 934305.711 0.430 - 0 42 42 84 Mo x -54170# 298# 8325# 4# B- -16470# 499# 83 941846# 320# - -2 41 43 84 Tc x -37700# 400# 8120# 5# B- * 83 959527# 429# -0 25 55 30 85 Zn x -25100# 500# 8090# 6# B- 14644# 502# 84 973054# 537# - 23 54 31 85 Ga x -39744.059 37.260 8253.5687 0.4384 B- 13379.3679 37.4459 84 957333.000 40.000 - 21 53 32 85 Ge x -53123.427 3.729 8401.7689 0.0439 B- 10065.7253 4.8303 84 942969.658 4.003 - 19 52 33 85 As x -63189.152 3.078 8510.9851 0.0362 B- 9224.4929 4.0313 84 932163.658 3.304 - 17 51 34 85 Se +3p -72413.645 2.613 8610.3045 0.0307 B- 6161.8335 4.0313 84 922260.758 2.804 - 15 50 35 85 Br +n2p -78575.478 3.078 8673.5926 0.0362 B- 2904.8622 3.6705 84 915645.758 3.304 - 13 49 36 85 Kr + -81480.341 2.000 8698.5633 0.0235 B- 687.0000 2.0000 84 912527.260 2.147 - 11 48 37 85 Rb -82167.34065 0.00500 8697.4416 0.0003 B- -1064.0510 2.8132 84 911789.73604 0.00537 - 9 47 38 85 Sr -81103.290 2.813 8675.7193 0.0331 B- -3261.1584 19.1729 84 912932.041 3.020 - 7 46 39 85 Y x -77842.131 18.965 8628.1486 0.2231 B- -4666.9352 20.0257 84 916433.039 20.360 - 5 45 40 85 Zr x -73175.196 6.430 8564.0394 0.0756 B- -6895.5120 7.6250 84 921443.199 6.902 - 3 44 41 85 Nb x -66279.684 4.099 8473.7117 0.0482 B- -8769.9238 16.3572 84 928845.836 4.400 - 1 43 42 85 Mo x -57509.760 15.835 8361.3320 0.1863 B- -11660# 400# 84 938260.736 17.000 - -1 42 43 85 Tc x -45850# 400# 8215# 5# B- -15220# 640# 84 950778# 429# - -3 41 44 85 Ru x -30630# 500# 8027# 6# B- * 84 967117# 537# -0 26 56 30 86 Zn x -20062# 500# 8032# 6# B- 13699# 640# 85 978463# 537# - 24 55 31 86 Ga x -33760# 400# 8182# 5# B- 15640# 593# 85 963757# 429# - 22 54 32 86 Ge x -49399.927 437.802 8354.6300 5.0907 B- 9562.2229 437.8158 85 946967.000 470.000 - 20 53 33 86 As x -58962.150 3.450 8456.7215 0.0401 B- 11541.0256 4.2666 85 936701.532 3.703 - 18 52 34 86 Se x -70503.175 2.520 8581.8224 0.0293 B- 5129.0860 3.9717 85 924311.732 2.705 - 16 51 35 86 Br +pp -75632.261 3.078 8632.3659 0.0358 B- 7633.4147 3.0779 85 918805.432 3.304 - 14 50 36 86 Kr -83265.67593 0.00372 8712.0295 0.0003 B- -518.6734 0.2000 85 910610.62468 0.00399 - 12 49 37 86 Rb -n -82747.003 0.200 8696.9014 0.0023 B- 1776.0972 0.2001 85 911167.443 0.214 - 10 48 38 86 Sr -84523.09977 0.00524 8708.4566 0.0003 B- -5240.0000 14.1421 85 909260.72473 0.00563 - 8 47 39 86 Y - -79283.100 14.142 8638.4293 0.1644 B- -1314.0763 14.5847 85 914886.095 15.182 - 6 46 40 86 Zr -77969.023 3.566 8614.0523 0.0415 B- -8834.9627 6.5521 85 916296.814 3.827 - 4 45 41 86 Nb x -69134.061 5.499 8502.2231 0.0639 B- -5023.1337 6.2316 85 925781.536 5.903 - 2 44 42 86 Mo x -64110.927 2.932 8434.7175 0.0341 B- -12541# 300# 85 931174.092 3.147 - 0 43 43 86 Tc x -51570# 300# 8280# 3# B- -11800# 500# 85 944637# 322# - -2 42 44 86 Ru x -39770# 400# 8133# 5# B- * 85 957305# 429# -0 25 56 31 87 Ga x -28870# 500# 8124# 6# B- 14720# 583# 86 969007# 537# - 23 55 32 87 Ge x -43590# 300# 8285# 3# B- 12028# 300# 86 953204# 322# - 21 54 33 87 As x -55617.914 2.985 8413.8521 0.0343 B- 10808.2192 3.7260 86 940291.716 3.204 - 19 53 34 87 Se x -66426.133 2.241 8529.0920 0.0258 B- 7465.5526 3.8766 86 928688.616 2.405 - 17 52 35 87 Br 2p-n -73891.685 3.171 8605.9105 0.0364 B- 6817.8455 3.1805 86 920674.016 3.404 - 15 51 36 87 Kr -n -80709.531 0.246 8675.2840 0.0028 B- 3888.2706 0.2463 86 913354.759 0.264 - 13 50 37 87 Rb -84597.802 0.006 8710.9843 0.0003 B- 282.2749 0.0063 86 909180.529 0.006 - 11 49 38 87 Sr -84880.07643 0.00513 8705.2363 0.0003 B- -1861.6894 1.1278 86 908877.49454 0.00550 - 9 48 39 87 Y - -83018.387 1.128 8674.8451 0.0130 B- -3671.2405 4.2962 86 910876.100 1.210 - 7 47 40 87 Zr -79347.147 4.146 8623.6545 0.0477 B- -5472.6536 7.9633 86 914817.338 4.450 - 5 46 41 87 Nb x -73874.493 6.802 8551.7579 0.0782 B- -6989.6757 7.3781 86 920692.473 7.302 - 3 45 42 87 Mo -66884.817 2.857 8462.4243 0.0328 B- -9194.7656 5.0729 86 928196.198 3.067 - 1 44 43 87 Tc x -57690.052 4.192 8347.7449 0.0482 B- -11960# 400# 86 938067.185 4.500 - -1 43 44 87 Ru x -45730# 400# 8201# 5# B- * 86 950907# 429# -0 26 57 31 88 Ga x -22390# 500# 8050# 6# B- 17129# 640# 87 975963# 537# - 24 56 32 88 Ge x -39520# 400# 8236# 5# B- 10930# 447# 87 957574# 429# - 22 55 33 88 As x -50450# 200# 8351# 2# B- 13434# 200# 87 945840# 215# - 20 54 34 88 Se x -63884.203 3.357 8495.0045 0.0382 B- 6831.7640 4.6125 87 931417.490 3.604 - 18 53 35 88 Br ++ -70715.967 3.171 8563.7479 0.0360 B- 8975.3282 4.1059 87 924083.290 3.404 - 16 52 36 88 Kr x -79691.295 2.608 8656.8499 0.0296 B- 2917.7090 2.6130 87 914447.879 2.800 - 14 51 37 88 Rb -82609.004 0.159 8681.1154 0.0018 B- 5312.6243 0.1590 87 911315.590 0.170 - 12 50 38 88 Sr -87921.62876 0.00561 8732.5958 0.0003 B- -3622.6000 1.5000 87 905612.253 0.006 - 10 49 39 88 Y - -84299.029 1.500 8682.5396 0.0170 B- -670.1549 5.6076 87 909501.274 1.610 - 8 48 40 88 Zr -83628.874 5.403 8666.0339 0.0614 B- -7457.3187 57.8921 87 910220.715 5.800 - 6 47 41 88 Nb -76171.555 57.808 8572.4013 0.6569 B- -3485.0021 57.9345 87 918226.476 62.059 - 4 46 42 88 Mo x -72686.553 3.819 8523.9087 0.0434 B- -11016.2515 5.6021 87 921967.779 4.100 - 2 45 43 88 Tc x -61670.301 4.099 8389.8338 0.0466 B- -7331# 300# 87 933794.211 4.400 - 0 44 44 88 Ru x -54340# 300# 8298# 3# B- -17479# 500# 87 941664# 322# - -2 43 45 88 Rh x -36860# 400# 8090# 5# B- * 87 960429# 429# -0 25 57 32 89 Ge x -33040# 400# 8161# 4# B- 13490# 500# 88 964530# 429# - 23 56 33 89 As x -46530# 300# 8304# 3# B- 12462# 300# 88 950048# 322# - 21 55 34 89 Se x -58992.398 3.729 8435.2799 0.0419 B- 9281.8730 4.9510 88 936669.058 4.003 - 19 54 35 89 Br x -68274.271 3.264 8530.7802 0.0367 B- 8261.5231 3.9045 88 926704.558 3.504 - 17 53 36 89 Kr x -76535.795 2.142 8614.8158 0.0241 B- 5176.6042 5.8342 88 917835.449 2.300 - 15 52 37 89 Rb -81712.399 5.427 8664.1895 0.0610 B- 4496.6278 5.4265 88 912278.136 5.825 - 13 51 38 89 Sr -86209.026 0.092 8705.9230 0.0011 B- 1502.1757 0.3510 88 907450.808 0.098 - 11 50 39 89 Y -87711.202 0.339 8714.0110 0.0038 B- -2833.2285 2.7652 88 905838.156 0.363 - 9 49 40 89 Zr -84877.974 2.780 8673.3865 0.0312 B- -4252.2191 23.7199 88 908879.751 2.983 - 7 48 41 89 Nb -80625.755 23.630 8616.8184 0.2655 B- -5610.8105 23.9513 88 913444.696 25.367 - 5 47 42 89 Mo x -75014.944 3.912 8544.9851 0.0440 B- -7620.0875 5.4673 88 919468.149 4.200 - 3 46 43 89 Tc x -67394.857 3.819 8450.5758 0.0429 B- -9025.4327 24.5181 88 927648.649 4.100 - 1 45 44 89 Ru x -58369.424 24.219 8340.3760 0.2721 B- -12719# 361# 88 937337.849 26.000 - -1 44 45 89 Rh -p -45651# 361# 8189# 4# B- * 88 950992# 387# -0 26 58 32 90 Ge x -28470# 500# 8109# 6# B- 12520# 640# 89 969436# 537# - 24 57 33 90 As x -40990# 400# 8240# 4# B- 14810# 518# 89 955995# 429# - 22 56 34 90 Se x -55800.223 329.749 8395.7672 3.6639 B- 8200.0834 329.7660 89 940096.000 354.000 - 20 55 35 90 Br x -64000.306 3.357 8478.1865 0.0373 B- 10958.9533 3.8396 89 931292.848 3.604 - 18 54 36 90 Kr x -74959.259 1.863 8591.2599 0.0207 B- 4406.3133 6.7158 89 919527.929 2.000 - 16 53 37 90 Rb -79365.573 6.452 8631.5262 0.0717 B- 6585.3721 6.4806 89 914797.557 6.926 - 14 52 38 90 Sr -85950.945 1.449 8696.0043 0.0161 B- 545.9674 1.4060 89 907727.870 1.555 - 12 51 39 90 Y -86496.912 0.354 8693.3778 0.0039 B- 2275.6350 0.3726 89 907141.749 0.379 - 10 50 40 90 Zr -88772.547 0.118 8709.9699 0.0013 B- -6111.0165 3.3163 89 904698.755 0.126 - 8 49 41 90 Nb -82661.531 3.317 8633.3770 0.0369 B- -2489.0165 3.3163 89 911259.201 3.561 - 6 48 42 90 Mo -80172.514 3.463 8597.0285 0.0385 B- -9447.8181 3.6110 89 913931.270 3.717 - 4 47 43 90 Tc x -70724.696 1.025 8483.3600 0.0114 B- -5840.8951 3.8685 89 924073.919 1.100 - 2 46 44 90 Ru -64883.801 3.730 8409.7684 0.0414 B- -13250# 200# 89 930344.378 4.004 - 0 45 45 90 Rh - -51634# 200# 8254# 2# B- -11924# 447# 89 944569# 215# - -2 44 46 90 Pd x -39710# 400# 8113# 4# B- * 89 957370# 429# -0 25 58 33 91 As x -36500# 400# 8189# 4# B- 14080# 589# 90 960816# 429# - 23 57 34 91 Se x -50580.130 433.145 8334.8382 4.7598 B- 10527.1716 433.1593 90 945700.000 465.000 - 21 56 35 91 Br -n2p -61107.301 3.543 8441.9242 0.0389 B- 9866.6724 4.1898 90 934398.617 3.804 - 19 55 36 91 Kr x -70973.974 2.236 8541.7519 0.0246 B- 6771.0748 8.1153 90 923806.309 2.400 - 17 54 37 91 Rb -77745.049 7.801 8607.5621 0.0857 B- 5906.9010 8.8732 90 916537.261 8.375 - 15 53 38 91 Sr -83651.950 5.453 8663.8759 0.0599 B- 2699.3714 5.2468 90 910195.942 5.853 - 13 52 39 91 Y -86351.321 1.843 8684.9421 0.0203 B- 1544.2710 1.8403 90 907298.048 1.978 - 11 51 40 91 Zr -87895.592 0.095 8693.3149 0.0011 B- -1257.5644 2.9243 90 905640.205 0.101 - 9 50 41 91 Nb -86638.028 2.926 8670.8983 0.0322 B- -4429.1934 6.7439 90 906990.256 3.140 - 7 49 42 91 Mo -82208.834 6.238 8613.6286 0.0686 B- -6222.1768 6.6706 90 911745.190 6.696 - 5 48 43 91 Tc -75986.657 2.363 8536.6558 0.0260 B- -7746.8246 3.2422 90 918424.972 2.536 - 3 47 44 91 Ru -68239.833 2.221 8442.9287 0.0244 B- -9670# 298# 90 926741.530 2.384 - 1 46 45 91 Rh x -58570# 298# 8328# 3# B- -12400# 300# 90 937123# 320# - -1 45 46 91 Pd - -46170# 423# 8183# 5# B- * 90 950435# 454# -0 26 59 33 92 As x -30380# 500# 8121# 5# B- 16344# 640# 91 967386# 537# - 24 58 34 92 Se x -46724# 400# 8290# 4# B- 9509# 400# 91 949840# 429# - 22 57 35 92 Br x -56232.812 6.709 8384.9123 0.0729 B- 12536.5161 7.2322 91 939631.595 7.202 - 20 56 36 92 Kr x -68769.329 2.701 8512.6750 0.0294 B- 6003.1210 6.6924 91 926173.092 2.900 - 18 55 37 92 Rb -74772.450 6.123 8569.4225 0.0666 B- 8094.9212 6.4187 91 919728.477 6.573 - 16 54 38 92 Sr -82867.371 3.423 8648.9070 0.0372 B- 1949.1237 9.3841 91 911038.222 3.675 - 14 53 39 92 Y -84816.494 9.127 8661.5894 0.0992 B- 3642.5294 9.1271 91 908945.752 9.798 - 12 52 40 92 Zr -88459.024 0.094 8692.6783 0.0011 B- -2005.7335 1.7823 91 905035.336 0.101 - 10 51 41 92 Nb -86453.290 1.784 8662.3731 0.0194 B- 355.2968 1.7911 91 907188.580 1.915 - 8 50 42 92 Mo -86808.587 0.157 8657.7312 0.0017 B- -7882.8841 3.1063 91 906807.153 0.168 - 6 49 43 92 Tc -78925.703 3.102 8563.5440 0.0337 B- -4624.4922 4.1246 91 915269.777 3.330 - 4 48 44 92 Ru -74301.211 2.718 8504.7740 0.0295 B- -11302.1155 5.1531 91 920234.373 2.917 - 2 47 45 92 Rh x -62999.095 4.378 8373.4211 0.0476 B- -8220.0000 345.0000 91 932367.692 4.700 - 0 46 46 92 Pd - -54779.095 345.028 8275.5695 3.7503 B- -17249# 528# 91 941192.225 370.402 - -2 45 47 92 Ag x -37530# 400# 8080# 4# B- * 91 959710# 429# -0 25 59 34 93 Se x -40860# 400# 8225# 4# B- 12030# 588# 92 956135# 429# - 23 58 35 93 Br x -52890.235 430.816 8345.5986 4.6324 B- 11245.7673 430.8234 92 943220.000 462.500 - 21 57 36 93 Kr x -64136.002 2.515 8458.1085 0.0270 B- 8483.8977 8.2243 92 931147.172 2.700 - 19 56 37 93 Rb -72619.900 7.830 8540.9209 0.0842 B- 7465.9434 8.8761 92 922039.334 8.406 - 17 55 38 93 Sr -80085.844 7.554 8612.7875 0.0812 B- 4141.3118 11.6972 92 914024.314 8.109 - 15 54 39 93 Y -84227.155 10.488 8648.9054 0.1128 B- 2894.8723 10.4830 92 909578.434 11.259 - 13 53 40 93 Zr -87122.028 0.456 8671.6207 0.0049 B- 90.8123 1.4838 92 906470.661 0.489 - 11 52 41 93 Nb -87212.840 1.490 8664.1849 0.0160 B- -405.7609 1.5012 92 906373.170 1.599 - 9 51 42 93 Mo -n -86807.079 0.181 8651.4095 0.0020 B- -3200.9629 1.0040 92 906808.772 0.193 - 7 50 43 93 Tc -p -83606.116 1.012 8608.5782 0.0109 B- -6389.3929 2.2995 92 910245.147 1.086 - 5 49 44 93 Ru -77216.723 2.065 8531.4627 0.0222 B- -8204.9136 3.3425 92 917104.442 2.216 - 3 48 45 93 Rh -69011.810 2.629 8434.8255 0.0283 B- -10030.0000 370.0000 92 925912.778 2.821 - 1 47 46 93 Pd - -58981.810 370.009 8318.5637 3.9786 B- -12582# 545# 92 936680.426 397.221 - -1 46 47 93 Ag x -46400# 401# 8175# 4# B- * 92 950188# 430# -0 26 60 34 94 Se x -36803# 500# 8180# 5# B- 10846# 539# 93 960490# 537# - 24 59 35 94 Br x -47650# 200# 8287# 2# B- 13698# 201# 93 948846# 215# - 22 58 36 94 Kr x -61347.780 12.109 8424.3318 0.1288 B- 7215.0114 12.2782 93 934140.452 13.000 - 20 57 37 94 Rb -68562.791 2.029 8492.7644 0.0216 B- 10282.9297 2.6230 93 926394.819 2.177 - 18 56 38 94 Sr -78845.721 1.663 8593.8344 0.0177 B- 3505.7517 6.4220 93 915355.641 1.785 - 16 55 39 94 Y -82351.473 6.380 8622.8068 0.0679 B- 4917.8589 6.3799 93 911592.062 6.849 - 14 54 40 94 Zr -87269.332 0.164 8666.8016 0.0018 B- -900.2684 1.5000 93 906312.523 0.175 - 12 53 41 94 Nb -86369.063 1.491 8648.9014 0.0159 B- 2045.0163 1.4937 93 907279.001 1.600 - 10 52 42 94 Mo -88414.079 0.141 8662.3341 0.0015 B- -4255.7476 4.0687 93 905083.586 0.151 - 8 51 43 94 Tc - -84158.332 4.071 8608.7373 0.0433 B- -1574.7296 5.1433 93 909652.319 4.370 - 6 50 44 94 Ru -82583.602 3.143 8583.6620 0.0334 B- -9675.9789 4.6150 93 911342.860 3.374 - 4 49 45 94 Rh -72907.623 3.379 8472.4033 0.0359 B- -6805.3428 5.4588 93 921730.450 3.627 - 2 48 46 94 Pd x -66102.281 4.287 8391.6832 0.0456 B- -13700# 400# 93 929036.286 4.602 - 0 47 47 94 Ag - -52402# 400# 8238# 4# B- -11962# 640# 93 943744# 429# - -2 46 48 94 Cd x -40440# 500# 8102# 5# B- * 93 956586# 537# -0 27 61 34 95 Se x -30460# 500# 8112# 5# B- 13390# 583# 94 967300# 537# - 25 60 35 95 Br x -43850# 300# 8245# 3# B- 12309# 301# 94 952925# 322# - 23 59 36 95 Kr x -56158.920 18.630 8365.9963 0.1961 B- 9731.3868 27.5124 94 939710.922 20.000 - 21 58 37 95 Rb -65890.307 20.245 8460.1967 0.2131 B- 9226.9772 20.2036 94 929263.849 21.733 - 19 57 38 95 Sr -75117.284 5.810 8549.0875 0.0612 B- 6090.6528 7.2395 94 919358.282 6.237 - 17 56 39 95 Y -81207.937 6.779 8604.9644 0.0714 B- 4452.0031 6.7718 94 912819.697 7.277 - 15 55 40 95 Zr -85659.940 0.869 8643.5924 0.0092 B- 1126.3312 0.9854 94 908040.276 0.933 - 13 54 41 95 Nb -86786.272 0.508 8647.2133 0.0054 B- 925.6009 0.4938 94 906831.110 0.545 - 11 53 42 95 Mo -87711.872 0.123 8648.7212 0.0013 B- -1690.5175 5.0782 94 905837.436 0.132 - 9 52 43 95 Tc -86021.355 5.080 8622.6911 0.0535 B- -2563.5961 10.5310 94 907652.281 5.453 - 7 51 44 95 Ru -83457.759 9.502 8587.4706 0.1000 B- -5117.1423 10.2656 94 910404.415 10.200 - 5 50 45 95 Rh -78340.616 3.886 8525.3707 0.0409 B- -8374.7035 4.9281 94 915897.893 4.171 - 3 49 46 95 Pd x -69965.913 3.031 8428.9807 0.0319 B- -10060# 400# 94 924888.506 3.253 - 1 48 47 95 Ag - -59906# 400# 8315# 4# B- -12850# 400# 94 935688# 429# - -1 47 48 95 Cd - -47056# 566# 8171# 6# B- * 94 949483# 607# -0 26 61 35 96 Br x -38210# 300# 8184# 3# B- 14872# 301# 95 958980# 322# - 24 60 36 96 Kr -53081.682 19.277 8330.8721 0.2008 B- 8272.6693 19.5669 95 943014.473 20.695 - 22 59 37 96 Rb -61354.351 3.353 8408.8963 0.0349 B- 11563.8970 9.1062 95 934133.398 3.599 - 20 58 38 96 Sr -72918.248 8.466 8521.2041 0.0882 B- 5411.7380 9.7257 95 921719.045 9.089 - 18 57 39 96 Y -78329.986 6.075 8569.4269 0.0633 B- 7108.8741 6.0740 95 915909.305 6.521 - 16 56 40 96 Zr -85438.860 0.114 8635.3283 0.0012 B- 163.9704 0.1000 95 908277.615 0.122 - 14 55 41 96 Nb -85602.830 0.147 8628.8868 0.0015 B- 3192.0590 0.1070 95 908101.586 0.157 - 12 54 42 96 Mo -88794.889 0.120 8653.9880 0.0013 B- -2973.2411 5.1450 95 904674.770 0.128 - 10 53 43 96 Tc - -85821.648 5.146 8614.8673 0.0536 B- 258.7369 5.1464 95 907866.675 5.524 - 8 52 44 96 Ru -86080.385 0.170 8609.4130 0.0018 B- -6392.6529 10.0000 95 907588.910 0.182 - 6 51 45 96 Rh - -79687.732 10.001 8534.6735 0.1042 B- -3504.3127 10.8442 95 914451.705 10.737 - 4 50 46 96 Pd x -76183.420 4.194 8490.0207 0.0437 B- -11671.7741 90.1814 95 918213.739 4.502 - 2 49 47 96 Ag ep -64511.645 90.084 8360.2903 0.9384 B- -8940# 400# 95 930743.903 96.708 - 0 48 48 96 Cd - -55572# 410# 8259# 4# B- -17482# 647# 95 940341# 440# - -2 47 49 96 In x -38090# 500# 8069# 5# B- * 95 959109# 537# -0 27 62 35 97 Br x -34000# 400# 8140# 4# B- 13423# 420# 96 963499# 429# - 25 61 36 97 Kr x -47423.499 130.409 8269.8645 1.3444 B- 11095.6460 130.4232 96 949088.782 140.000 - 23 60 37 97 Rb -58519.145 1.912 8376.1872 0.0197 B- 10061.5295 3.8872 96 937177.117 2.052 - 21 59 38 97 Sr -68580.674 3.385 8471.8489 0.0349 B- 7534.7807 7.5131 96 926375.621 3.633 - 19 58 39 97 Y + -76115.455 6.708 8541.4616 0.0692 B- 6821.2382 6.7068 96 918286.702 7.201 - 17 57 40 97 Zr -82936.693 0.121 8603.7182 0.0013 B- 2666.1038 4.2435 96 910963.802 0.130 - 15 56 41 97 Nb -85602.797 4.244 8623.1384 0.0438 B- 1941.9038 4.2435 96 908101.622 4.556 - 13 55 42 97 Mo -87544.700 0.165 8635.0926 0.0017 B- -320.2640 4.1169 96 906016.903 0.176 - 11 54 43 97 Tc -87224.436 4.118 8623.7254 0.0425 B- -1103.8722 4.9563 96 906360.720 4.420 - 9 53 44 97 Ru -n -86120.564 2.763 8604.2799 0.0285 B- -3523.0000 35.3553 96 907545.776 2.965 - 7 52 45 97 Rh - -82597.564 35.463 8559.8949 0.3656 B- -4791.7118 35.7924 96 911327.872 38.071 - 5 51 46 97 Pd x -77805.852 4.844 8502.4303 0.0499 B- -6901.8255 12.9558 96 916471.985 5.200 - 3 50 47 97 Ag x -70904.027 12.016 8423.2121 0.1239 B- -10170.0000 420.0000 96 923881.400 12.900 - 1 49 48 97 Cd - -60734.027 420.172 8310.3013 4.3317 B- -13344# 580# 96 934799.343 451.073 - -1 48 49 97 In x -47390# 401# 8165# 4# B- * 96 949125# 430# -0 28 63 35 98 Br x -28050# 400# 8078# 4# B- 16070# 500# 97 969887# 429# - 26 62 36 98 Kr x -44120# 300# 8234# 3# B- 10249# 300# 97 952635# 322# - 24 61 37 98 Rb -54369.152 16.083 8330.7294 0.1641 B- 12053.2361 16.4029 97 941632.317 17.265 - 22 60 38 98 Sr -66422.389 3.226 8445.7385 0.0329 B- 5866.3591 8.5504 97 928692.636 3.463 - 20 59 39 98 Y p-2n -72288.748 7.919 8497.6162 0.0808 B- 8993.0098 11.5755 97 922394.841 8.501 - 18 58 40 98 Zr -81281.757 8.445 8581.3984 0.0862 B- 2242.8547 9.8134 97 912740.448 9.065 - 16 57 41 98 Nb -pn -83524.612 5.001 8596.3016 0.0510 B- 4591.3681 5.0032 97 910332.645 5.369 - 14 56 42 98 Mo -88115.980 0.174 8635.1691 0.0018 B- -1683.7664 3.3768 97 905403.609 0.186 - 12 55 43 98 Tc -86432.214 3.380 8610.0047 0.0345 B- 1792.6575 7.1568 97 907211.206 3.628 - 10 54 44 98 Ru -88224.871 6.463 8620.3140 0.0659 B- -5049.6529 10.0000 97 905286.709 6.937 - 8 53 45 98 Rh - -83175.219 11.906 8560.8038 0.1215 B- -1854.2331 12.8161 97 910707.734 12.782 - 6 52 46 98 Pd -81320.985 4.742 8533.8999 0.0484 B- -8254.5607 33.0975 97 912698.335 5.090 - 4 51 47 98 Ag -73066.425 32.907 8441.6866 0.3358 B- -5430.0000 40.0000 97 921559.970 35.327 - 2 50 48 98 Cd - -67636.425 51.797 8378.2953 0.5285 B- -13730# 300# 97 927389.315 55.605 - 0 49 49 98 In - -53906# 304# 8230# 3# B- * 97 942129# 327# -0 27 63 36 99 Kr x -38400# 400# 8175# 4# B- 12721# 400# 98 958776# 429# - 25 62 37 99 Rb x -51121.150 4.031 8295.3010 0.0407 B- 11397.3767 6.2201 98 945119.190 4.327 - 23 61 38 99 Sr -62518.527 4.737 8402.5235 0.0479 B- 8125.2037 8.1353 98 932883.604 5.085 - 21 60 39 99 Y x -70643.730 6.615 8476.6938 0.0668 B- 6972.9398 12.4082 98 924160.839 7.101 - 19 59 40 99 Zr -77616.670 10.499 8539.2250 0.1061 B- 4718.6736 15.9474 98 916675.081 11.271 - 17 58 41 99 Nb +p -82335.344 12.004 8578.9859 0.1213 B- 3634.7623 12.0059 98 911609.377 12.886 - 15 57 42 99 Mo -85970.106 0.229 8607.7982 0.0023 B- 1357.7631 0.8905 98 907707.299 0.245 - 13 56 43 99 Tc -87327.869 0.908 8613.6105 0.0092 B- 297.5156 0.9453 98 906249.681 0.974 - 11 55 44 99 Ru -87625.385 0.343 8608.7132 0.0035 B- -2040.8632 19.4529 98 905930.284 0.368 - 9 54 45 99 Rh -85584.522 19.451 8580.1959 0.1965 B- -3401.6603 18.9153 98 908121.241 20.881 - 7 53 46 99 Pd -82182.861 5.107 8537.9332 0.0516 B- -5470.3785 8.0829 98 911773.073 5.482 - 5 52 47 99 Ag x -76712.483 6.265 8474.7744 0.0633 B- -6781.3511 6.4622 98 917645.766 6.725 - 3 51 48 99 Cd x -69931.132 1.584 8398.3734 0.0160 B- -8555# 298# 98 924925.845 1.700 - 1 50 49 99 In x -61376# 298# 8304# 3# B- -13400# 500# 98 934110# 320# - -1 49 50 99 Sn - -47976# 582# 8161# 6# B- * 98 948495# 625# -0 28 64 36 100 Kr x -34470# 400# 8134# 4# B- 11796# 400# 99 962995# 429# - 26 63 37 100 Rb -46265.884 13.124 8244.5085 0.1312 B- 13551.6204 14.8355 99 950331.532 14.089 - 24 62 38 100 Sr -59817.505 6.918 8372.2012 0.0692 B- 7503.7365 13.1453 99 935783.270 7.426 - 22 61 39 100 Y x -67321.241 11.179 8439.4151 0.1118 B- 9051.4949 13.8293 99 927727.678 12.000 - 20 60 40 100 Zr -76372.736 8.143 8522.1066 0.0814 B- 3418.5098 11.3976 99 918010.499 8.742 - 18 59 41 100 Nb IT -79791.246 7.976 8548.4683 0.0798 B- 6401.7829 7.9817 99 914340.578 8.562 - 16 58 42 100 Mo -86193.029 0.301 8604.6626 0.0030 B- -172.0776 1.3704 99 907467.982 0.322 - 14 57 43 100 Tc -n -86020.951 1.351 8595.1184 0.0135 B- 3206.4401 1.3760 99 907652.715 1.450 - 12 56 44 100 Ru -89227.391 0.342 8619.3593 0.0034 B- -3636.2612 18.1231 99 904210.460 0.367 - 10 55 45 100 Rh -85591.130 18.125 8575.1732 0.1813 B- -378.4577 25.2879 99 908114.147 19.458 - 8 54 46 100 Pd -85212.672 17.637 8563.5652 0.1764 B- -7074.7030 18.3319 99 908520.438 18.934 - 6 53 47 100 Ag x -78137.969 5.000 8484.9947 0.0500 B- -3943.3740 5.2735 99 916115.443 5.367 - 4 52 48 100 Cd x -74194.595 1.677 8437.7375 0.0168 B- -10016.4492 2.7945 99 920348.829 1.800 - 2 51 49 100 In x -64178.146 2.236 8329.7495 0.0224 B- -7030.0000 240.0000 99 931101.929 2.400 - 0 50 50 100 Sn - -57148.146 240.010 8251.6260 2.4001 B- * 99 938648.944 257.661 -0 29 65 36 101 Kr x -28580# 500# 8075# 5# B- 13987# 501# 100 969318# 537# - 27 64 37 101 Rb x -42567.417 20.493 8206.1753 0.2029 B- 12757.4969 22.1781 100 954302.000 22.000 - 25 63 38 101 Sr x -55324.914 8.480 8324.7411 0.0840 B- 9729.8721 11.0473 100 940606.264 9.103 - 23 62 39 101 Y x -65054.787 7.080 8413.3305 0.0701 B- 8106.2003 10.9331 100 930160.817 7.601 - 21 61 40 101 Zr -73160.987 8.332 8485.8439 0.0825 B- 5730.5011 9.1366 100 921458.454 8.944 - 19 60 41 101 Nb x -78891.488 3.749 8534.8355 0.0371 B- 4628.4637 3.7378 100 915306.508 4.024 - 17 59 42 101 Mo -n -83519.952 0.308 8572.9159 0.0031 B- 2824.6411 24.0018 100 910337.648 0.331 - 15 58 43 101 Tc + -86344.593 24.004 8593.1366 0.2377 B- 1613.5200 24.0000 100 907305.271 25.768 - 13 57 44 101 Ru -87958.113 0.413 8601.3660 0.0041 B- -545.6846 5.8518 100 905573.086 0.443 - 11 56 45 101 Rh -87412.428 5.841 8588.2172 0.0578 B- -1980.2833 3.9027 100 906158.903 6.270 - 9 55 46 101 Pd -85432.145 4.588 8560.8644 0.0454 B- -4097.7606 6.6679 100 908284.824 4.925 - 7 54 47 101 Ag x -81334.384 4.838 8512.5465 0.0479 B- -5497.9186 5.0625 100 912683.951 5.193 - 5 53 48 101 Cd x -75836.466 1.490 8450.3657 0.0148 B- -7291.5642 11.7569 100 918586.209 1.600 - 3 52 49 101 In x -68544.901 11.662 8370.4260 0.1155 B- -8239.2770 300.2313 100 926414.025 12.519 - 1 51 50 101 Sn ep -60305.624 300.005 8281.1030 2.9703 B- * 100 935259.252 322.068 -0 28 65 37 102 Rb x -37252.312 82.903 8152.7443 0.8128 B- 14906.9991 106.6347 101 960008.000 89.000 - 26 64 38 102 Sr x -52159.311 67.068 8291.2213 0.6575 B- 9013.3301 67.1916 101 944004.679 72.000 - 24 63 39 102 Y x -61172.641 4.081 8371.9172 0.0400 B- 10408.7856 9.6618 101 934328.471 4.381 - 22 62 40 102 Zr -71581.427 8.758 8466.2940 0.0859 B- 4716.8380 9.0530 101 923154.181 9.401 - 20 61 41 102 Nb -76298.265 2.511 8504.8675 0.0246 B- 7262.6008 8.6750 101 918090.447 2.695 - 18 60 42 102 Mo -83560.866 8.305 8568.3994 0.0814 B- 1012.0557 12.3682 101 910293.725 8.916 - 16 59 43 102 Tc -84572.921 9.166 8570.6514 0.0899 B- 4533.5134 9.1646 101 909207.239 9.840 - 14 58 44 102 Ru -89106.435 0.416 8607.4275 0.0041 B- -2323.1187 6.3960 101 904340.312 0.446 - 12 57 45 102 Rh - -86783.316 6.410 8576.9818 0.0628 B- 1119.6470 6.3962 101 906834.282 6.880 - 10 56 46 102 Pd -87902.963 0.419 8580.2887 0.0041 B- -5656.2615 8.1816 101 905632.292 0.449 - 8 55 47 102 Ag + -82246.702 8.171 8517.1650 0.0801 B- -2587.0000 8.0000 101 911704.538 8.771 - 6 54 48 102 Cd -79659.702 1.662 8484.1322 0.0163 B- -8964.8059 4.8654 101 914481.797 1.784 - 4 53 49 102 In -70694.896 4.573 8388.5719 0.0448 B- -5760.0000 100.0000 101 924105.911 4.909 - 2 52 50 102 Sn - -64934.896 100.105 8324.4313 0.9814 B- -13835# 412# 101 930289.525 107.466 - 0 51 51 102 Sb x -51100# 400# 8181# 4# B- * 101 945142# 429# -0 29 66 37 103 Rb x -33160# 400# 8112# 4# B- 14120# 447# 102 964401# 429# - 27 65 38 103 Sr x -47280# 200# 8242# 2# B- 11177# 201# 102 949243# 215# - 25 64 39 103 Y x -58457.034 11.206 8342.6336 0.1088 B- 9351.9600 14.5130 102 937243.796 12.029 - 23 63 40 103 Zr x -67808.993 9.223 8425.8337 0.0895 B- 7219.6740 10.0270 102 927204.054 9.900 - 21 62 41 103 Nb x -75028.667 3.935 8488.3320 0.0382 B- 5925.6639 10.0270 102 919453.416 4.224 - 19 61 42 103 Mo x -80954.331 9.223 8538.2672 0.0895 B- 3649.5889 13.4648 102 913091.954 9.900 - 17 60 43 103 Tc +p -84603.920 9.810 8566.1045 0.0952 B- 2663.2474 9.8086 102 909173.960 10.531 - 15 59 44 103 Ru -87267.168 0.441 8584.3656 0.0043 B- 764.5378 2.2598 102 906314.846 0.473 - 13 58 45 103 Rh -88031.705 2.301 8584.1927 0.0223 B- -574.7252 2.3928 102 905494.081 2.470 - 11 57 46 103 Pd -n -87456.980 0.878 8571.0173 0.0085 B- -2654.2778 4.1916 102 906111.074 0.942 - 9 56 47 103 Ag x -84802.702 4.099 8537.6520 0.0398 B- -4151.0761 4.4806 102 908960.558 4.400 - 7 55 48 103 Cd -80651.626 1.811 8489.7547 0.0176 B- -6019.2293 9.1242 102 913416.922 1.943 - 5 54 49 103 In -74632.397 8.980 8423.7199 0.0872 B- -7540# 100# 102 919878.830 9.640 - 3 53 50 103 Sn - -67092# 100# 8343# 1# B- -10422# 316# 102 927973# 108# - 1 52 51 103 Sb x -56670# 300# 8234# 3# B- * 102 939162# 322# -0 30 67 37 104 Rb x -27450# 500# 8057# 5# B- 16310# 583# 103 970531# 537# - 28 66 38 104 Sr x -43760# 300# 8206# 3# B- 10320# 361# 103 953022# 322# - 26 65 39 104 Y x -54080# 200# 8298# 2# B- 11638# 200# 103 941943# 215# - 24 64 40 104 Zr x -65717.660 9.316 8402.3159 0.0896 B- 6093.3367 9.4851 103 929449.193 10.000 - 22 63 41 104 Nb x -71810.997 1.784 8453.3832 0.0172 B- 8532.7512 9.0879 103 922907.728 1.915 - 20 62 42 104 Mo -80343.748 8.911 8527.9063 0.0857 B- 2155.2212 24.1665 103 913747.443 9.566 - 18 61 43 104 Tc -82498.969 24.886 8541.1070 0.2393 B- 5596.7945 24.9370 103 911433.718 26.716 - 16 60 44 104 Ru -88095.763 2.498 8587.3998 0.0240 B- -1136.4195 3.3643 103 905425.312 2.682 - 14 59 45 104 Rh -n -86959.344 2.303 8568.9501 0.0221 B- 2435.7789 2.6595 103 906645.309 2.471 - 12 58 46 104 Pd +n -89395.123 1.336 8584.8485 0.0129 B- -4278.6529 4.0000 103 904030.393 1.434 - 10 57 47 104 Ag - -85116.470 4.217 8536.1850 0.0406 B- -1148.0787 4.5370 103 908623.715 4.527 - 8 56 48 104 Cd -83968.391 1.673 8517.6232 0.0161 B- -7785.7166 6.0127 103 909856.228 1.795 - 6 55 49 104 In x -76182.675 5.775 8435.2380 0.0555 B- -4555.6174 8.1461 103 918214.538 6.200 - 4 54 50 104 Sn -71627.057 5.745 8383.9114 0.0552 B- -12332# 102# 103 923105.195 6.167 - 2 53 51 104 Sb +a -59295# 101# 8258# 1# B- -9668# 333# 103 936344# 109# - 0 52 52 104 Te -a -49626.831 317.609 8157.3256 3.0539 B- * 103 946723.408 340.967 -0 29 67 38 105 Sr x -38190# 500# 8152# 5# B- 12380# 640# 104 959001# 537# - 27 66 39 105 Y x -50570# 400# 8262# 4# B- 10888# 400# 104 945711# 429# - 25 65 40 105 Zr x -61458.274 12.110 8358.5980 0.1153 B- 8457.2728 12.7625 104 934021.832 13.000 - 23 64 41 105 Nb x -69915.547 4.028 8431.6925 0.0384 B- 7415.2411 9.9106 104 924942.577 4.324 - 21 63 42 105 Mo -77330.788 9.055 8494.8630 0.0862 B- 4955.5157 35.0307 104 916981.989 9.721 - 19 62 43 105 Tc -82286.303 35.263 8534.6074 0.3358 B- 3648.2396 35.2787 104 911662.024 37.856 - 17 61 44 105 Ru -85934.543 2.499 8561.9016 0.0238 B- 1916.7271 2.8508 104 907745.478 2.683 - 15 60 45 105 Rh -87851.270 2.502 8572.7053 0.0238 B- 566.6347 2.3459 104 905687.787 2.685 - 13 59 46 105 Pd -88417.905 1.138 8570.6509 0.0108 B- -1347.0564 4.6695 104 905079.479 1.222 - 11 58 47 105 Ag -87070.848 4.544 8550.3708 0.0433 B- -2736.9989 4.3618 104 906525.604 4.877 - 9 57 48 105 Cd -84333.849 1.392 8516.8532 0.0133 B- -4693.2673 10.3405 104 909463.893 1.494 - 7 56 49 105 In x -79640.582 10.246 8464.7045 0.0976 B- -6302.5807 10.9891 104 914502.322 11.000 - 5 55 50 105 Sn -73338.001 3.971 8397.2290 0.0378 B- -9322.5103 22.1849 104 921268.421 4.263 - 3 54 51 105 Sb +a -64015.491 21.827 8300.9923 0.2079 B- -11203.9825 300.8126 104 931276.547 23.431 - 1 53 52 105 Te -a -52811.509 300.020 8186.8368 2.8573 B- * 104 943304.516 322.084 -0 30 68 38 106 Sr x -34300# 600# 8114# 6# B- 11490# 781# 105 963177# 644# - 28 67 39 106 Y x -45790# 500# 8215# 5# B- 12959# 539# 105 950842# 537# - 26 66 40 106 Zr x -58749# 200# 8330# 2# B- 7453# 200# 105 936930# 215# - 24 65 41 106 Nb -66202.678 1.416 8393.2657 0.0134 B- 9925.3249 9.2388 105 928928.505 1.520 - 22 64 42 106 Mo x -76128.003 9.130 8479.5202 0.0861 B- 3648.2494 15.2778 105 918273.231 9.801 - 20 63 43 106 Tc + -79776.253 12.250 8506.5570 0.1156 B- 6547.0000 11.0000 105 914356.674 13.150 - 18 62 44 106 Ru -86323.253 5.391 8560.9406 0.0509 B- 39.4038 0.2121 105 907328.181 5.787 - 16 61 45 106 Rh -86362.656 5.390 8553.9317 0.0508 B- 3544.8865 5.3348 105 907285.879 5.786 - 14 60 46 106 Pd -89907.543 1.106 8579.9934 0.0104 B- -2965.1434 2.8172 105 903480.287 1.186 - 12 59 47 106 Ag -86942.399 3.016 8544.6397 0.0285 B- 189.7534 2.8190 105 906663.499 3.237 - 10 58 48 106 Cd -87132.153 1.104 8539.0492 0.0104 B- -6524.0031 12.1765 105 906459.791 1.184 - 8 57 49 106 In - -80608.150 12.226 8470.1213 0.1153 B- -3254.4521 13.2439 105 913463.596 13.125 - 6 56 50 106 Sn -77353.698 5.091 8432.0383 0.0480 B- -10880.3964 9.0249 105 916957.394 5.465 - 4 55 51 106 Sb x -66473.301 7.452 8322.0124 0.0703 B- -8253.5423 100.8163 105 928637.979 8.000 - 2 54 52 106 Te -a -58219.759 100.541 8236.7682 0.9485 B- -14920# 412# 105 937498.521 107.934 - 0 53 53 106 I x -43300# 400# 8089# 4# B- * 105 953516# 429# -0 31 69 38 107 Sr x -28250# 700# 8057# 7# B- 13720# 860# 106 969672# 751# - 29 68 39 107 Y x -41970# 500# 8178# 5# B- 12050# 583# 106 954943# 537# - 27 67 40 107 Zr x -54020# 300# 8284# 3# B- 9704# 300# 106 942007# 322# - 25 66 41 107 Nb x -63723.805 8.023 8367.0898 0.0750 B- 8821.1703 12.2239 106 931589.685 8.612 - 23 65 42 107 Mo x -72544.975 9.223 8442.2190 0.0862 B- 6204.9921 12.6599 106 922119.770 9.901 - 21 64 43 107 Tc x -78749.967 8.673 8492.8979 0.0811 B- 5112.5985 11.7243 106 915458.437 9.310 - 19 63 44 107 Ru -nn -83862.565 8.673 8533.3676 0.0811 B- 3001.1457 14.8473 106 909969.837 9.310 - 17 62 45 107 Rh +p -86863.711 12.051 8554.1040 0.1126 B- 1508.9427 12.1108 106 906747.975 12.937 - 15 61 46 107 Pd -88372.654 1.201 8560.8946 0.0112 B- 34.0458 2.3174 106 905128.058 1.289 - 13 60 47 107 Ag -88406.700 2.382 8553.9012 0.0223 B- -1416.3741 2.5654 106 905091.509 2.556 - 11 59 48 107 Cd -86990.325 1.660 8533.3524 0.0155 B- -3423.6586 9.5800 106 906612.049 1.782 - 9 58 49 107 In -83566.667 9.654 8494.0439 0.0902 B- -5054.4281 11.0175 106 910287.497 10.363 - 7 57 50 107 Sn x -78512.239 5.310 8439.4946 0.0496 B- -7858.9903 6.7377 106 915713.649 5.700 - 5 56 51 107 Sb -70653.248 4.148 8358.7344 0.0388 B- -9996# 101# 106 924150.621 4.452 - 3 55 52 107 Te -a -60657# 101# 8258# 1# B- -11227# 316# 106 934882# 108# - 1 54 53 107 I x -49430# 300# 8146# 3# B- * 106 946935# 322# -0 30 69 39 108 Y x -36780# 600# 8129# 6# B- 14170# 721# 107 960515# 644# - 28 68 40 108 Zr x -50950# 400# 8253# 4# B- 8595# 400# 107 945303# 429# - 26 67 41 108 Nb x -59545.198 8.239 8325.6604 0.0763 B- 11204.0998 12.3668 107 936075.604 8.844 - 24 66 42 108 Mo x -70749.297 9.223 8422.1581 0.0854 B- 5173.5330 12.7262 107 924047.508 9.901 - 22 65 43 108 Tc x -75922.831 8.769 8462.8172 0.0812 B- 7738.5736 11.7903 107 918493.493 9.413 - 20 64 44 108 Ru -3n -83661.404 8.680 8527.2267 0.0804 B- 1369.7517 16.4699 107 910185.793 9.318 - 18 63 45 108 Rh x -85031.156 13.997 8532.6657 0.1296 B- 4493.0596 14.0405 107 908715.304 15.026 - 16 62 46 108 Pd -89524.215 1.108 8567.0241 0.0103 B- -1917.4238 2.6323 107 903891.806 1.189 - 14 61 47 108 Ag -n -87606.792 2.388 8542.0262 0.0221 B- 1645.6311 2.6386 107 905950.245 2.563 - 12 60 48 108 Cd -89252.423 1.123 8550.0196 0.0104 B- -5132.5944 8.5845 107 904183.588 1.205 - 10 59 49 108 In -84119.828 8.641 8495.2516 0.0800 B- -2049.8794 9.8365 107 909693.654 9.276 - 8 58 50 108 Sn -82069.949 5.382 8469.0273 0.0498 B- -9624.6079 7.6925 107 911894.290 5.778 - 6 57 51 108 Sb x -72445.341 5.496 8372.6666 0.0509 B- -6663.6646 7.7125 107 922226.731 5.900 - 4 56 52 108 Te -65781.676 5.411 8303.7221 0.0501 B- -13011# 101# 107 929380.469 5.808 - 2 55 53 108 I -p -52771# 101# 8176# 1# B- -10139# 393# 107 943348# 109# - 0 54 54 108 Xe -a -42632.357 379.497 8074.8886 3.5139 B- * 107 954232.285 407.406 -0 31 70 39 109 Y x -32480# 700# 8089# 6# B- 13250# 860# 108 965131# 751# - 29 69 40 109 Zr x -45730# 500# 8204# 5# B- 10960# 660# 108 950907# 537# - 27 68 41 109 Nb x -56689.800 430.816 8297.1307 3.9524 B- 9969.4851 430.9610 108 939141.000 462.500 - 25 67 42 109 Mo x -66659.285 11.179 8381.4163 0.1026 B- 7623.5438 14.7805 108 928438.318 12.000 - 23 66 43 109 Tc x -74282.828 9.669 8444.1796 0.0887 B- 6455.6267 12.6574 108 920254.107 10.380 - 21 65 44 109 Ru -4n -80738.455 8.954 8496.2280 0.0821 B- 4260.7958 9.8229 108 913323.707 9.612 - 19 64 45 109 Rh -84999.251 4.040 8528.1404 0.0371 B- 2607.2327 4.1874 108 908749.555 4.336 - 17 63 46 109 Pd -87606.484 1.114 8544.8825 0.0102 B- 1112.9469 1.4024 108 905950.576 1.195 - 15 62 47 109 Ag -88719.431 1.287 8547.9155 0.0118 B- -215.1002 1.7795 108 904755.778 1.381 - 13 61 48 109 Cd -88504.330 1.536 8538.7646 0.0141 B- -2014.8047 4.0662 108 904986.697 1.649 - 11 60 49 109 In -86489.526 3.969 8513.1027 0.0364 B- -3859.3453 8.8866 108 907149.679 4.261 - 9 59 50 109 Sn -82630.180 7.949 8470.5183 0.0729 B- -6379.1940 8.8074 108 911292.857 8.533 - 7 58 51 109 Sb -76250.986 5.265 8404.8161 0.0483 B- -8535.5871 6.8502 108 918141.203 5.652 - 5 57 52 109 Te -67715.399 4.382 8319.3305 0.0402 B- -10042.8941 8.0301 108 927304.532 4.704 - 3 56 53 109 I -p -57672.505 6.729 8220.0164 0.0617 B- -11502.9589 300.1831 108 938086.022 7.223 - 1 55 54 109 Xe -a -46169.546 300.108 8107.3071 2.7533 B- * 108 950434.955 322.178 -0 30 70 40 110 Zr x -42220# 500# 8171# 5# B- 10090# 976# 109 954675# 537# - 28 69 41 110 Nb x -52309.914 838.345 8255.2607 7.6213 B- 12225.9002 838.6945 109 943843.000 900.000 - 26 68 42 110 Mo x -64535.814 24.219 8359.2930 0.2202 B- 6498.7491 26.0147 109 930717.956 26.000 - 24 67 43 110 Tc x -71034.564 9.497 8411.2603 0.0863 B- 9038.0654 12.5086 109 923741.263 10.195 - 22 66 44 110 Ru -80072.629 8.924 8486.3123 0.0811 B- 2756.0638 19.4044 109 914038.501 9.580 - 20 65 45 110 Rh -82828.693 17.805 8504.2551 0.1619 B- 5502.2116 17.7967 109 911079.745 19.114 - 18 64 46 110 Pd -88330.904 0.612 8547.1630 0.0056 B- -873.5982 1.3777 109 905172.878 0.657 - 16 63 47 110 Ag -87457.306 1.286 8532.1089 0.0117 B- 2890.6633 1.2771 109 906110.724 1.380 - 14 62 48 110 Cd -90347.969 0.380 8551.2755 0.0035 B- -3878.0000 11.5470 109 903007.470 0.407 - 12 61 49 110 In - -86469.969 11.553 8508.9087 0.1050 B- -627.9769 17.9802 109 907170.674 12.402 - 10 60 50 110 Sn x -85841.993 13.777 8496.0875 0.1252 B- -8392.2480 15.0117 109 907844.835 14.790 - 8 59 51 110 Sb x -77449.745 5.962 8412.6821 0.0542 B- -5219.9240 8.8753 109 916854.283 6.400 - 6 58 52 110 Te -72229.821 6.575 8358.1160 0.0598 B- -11761.9766 62.2875 109 922458.102 7.058 - 4 57 53 110 I -a -60467.844 61.940 8244.0767 0.5631 B- -8545.2075 118.4700 109 935085.102 66.494 - 2 56 54 110 Xe -a -51922.636 100.988 8159.2808 0.9181 B- * 109 944258.759 108.415 -0 31 71 40 111 Zr x -36480# 600# 8118# 5# B- 12480# 671# 110 960837# 644# - 29 70 41 111 Nb x -48960# 300# 8223# 3# B- 10980# 300# 110 947439# 322# - 27 69 42 111 Mo + -59939.813 12.578 8315.2932 0.1133 B- 9084.8620 6.7999 110 935651.966 13.503 - 25 68 43 111 Tc x -69024.675 10.582 8390.0906 0.0953 B- 7760.6500 13.8477 110 925898.966 11.359 - 23 67 44 111 Ru x -76785.325 9.682 8452.9582 0.0872 B- 5518.5456 11.8621 110 917567.566 10.394 - 21 66 45 111 Rh -82303.871 6.853 8495.6267 0.0617 B- 3682.0153 6.8899 110 911643.164 7.356 - 19 65 46 111 Pd -n -85985.886 0.731 8521.7498 0.0066 B- 2229.5607 1.5721 110 907690.358 0.785 - 17 64 47 111 Ag + -88215.447 1.459 8534.7878 0.0131 B- 1036.8000 1.4142 110 905296.827 1.565 - 15 63 48 111 Cd -89252.247 0.357 8537.0801 0.0032 B- -860.1972 3.4170 110 904183.776 0.383 - 13 62 49 111 In -88392.050 3.424 8522.2824 0.0308 B- -2453.4692 6.3368 110 905107.236 3.675 - 11 61 50 111 Sn +n -85938.581 5.336 8493.1310 0.0481 B- -5101.8340 10.3337 110 907741.143 5.728 - 9 60 51 111 Sb x -80836.747 8.849 8440.1203 0.0797 B- -7249.2597 10.9370 110 913218.187 9.500 - 7 59 52 111 Te x -73587.487 6.427 8367.7635 0.0579 B- -8633.6922 7.9943 110 921000.587 6.900 - 5 58 53 111 I -64953.795 4.754 8282.9343 0.0428 B- -10434# 116# 110 930269.236 5.103 - 3 57 54 111 Xe -a -54520# 115# 8182# 1# B- -11620# 231# 110 941470# 124# - 1 56 55 111 Cs x -42900# 200# 8070# 2# B- * 110 953945# 215# -0 32 72 40 112 Zr x -32420# 700# 8081# 6# B- 11650# 761# 111 965196# 751# - 30 71 41 112 Nb x -44070# 300# 8178# 3# B- 13410# 361# 111 952689# 322# - 28 70 42 112 Mo x -57480# 200# 8291# 2# B- 7779# 200# 111 938293# 215# - 26 69 43 112 Tc x -65258.932 5.515 8353.6217 0.0492 B- 10371.9409 11.0602 111 929941.658 5.920 - 24 68 44 112 Ru x -75630.873 9.600 8439.2431 0.0857 B- 4100.1790 45.1185 111 918806.922 10.305 - 22 67 45 112 Rh -79731.052 44.085 8468.8666 0.3936 B- 6589.9874 43.9269 111 914405.199 47.327 - 20 66 46 112 Pd -86321.039 6.546 8520.7205 0.0584 B- 262.6897 6.9799 111 907330.557 7.027 - 18 65 47 112 Ag x -86583.729 2.422 8516.0807 0.0216 B- 3991.1283 2.4348 111 907048.548 2.600 - 16 64 48 112 Cd -90574.857 0.250 8544.7306 0.0022 B- -2584.7306 4.2434 111 902763.896 0.268 - 14 63 49 112 In -87990.127 4.251 8514.6674 0.0380 B- 664.9224 4.2434 111 905538.718 4.563 - 12 62 50 112 Sn -88655.049 0.294 8513.6189 0.0026 B- -7056.0760 17.8317 111 904824.894 0.315 - 10 61 51 112 Sb x -81598.973 17.829 8443.6330 0.1592 B- -4031.4550 19.7019 111 912399.903 19.140 - 8 60 52 112 Te x -77567.518 8.383 8400.6527 0.0749 B- -10504.1795 13.2390 111 916727.848 9.000 - 6 59 53 112 I x -67063.339 10.246 8299.8801 0.0915 B- -7036.9910 13.1754 111 928004.548 11.000 - 4 58 54 112 Xe -a -60026.348 8.283 8230.0646 0.0740 B- -13612# 116# 111 935559.068 8.891 - 2 57 55 112 Cs -p -46415# 116# 8102# 1# B- * 111 950172# 124# -0 33 73 40 113 Zr x -26340# 300# 8027# 3# B- 13870# 500# 112 971723# 322# - 31 72 41 113 Nb x -40210# 400# 8143# 4# B- 12440# 500# 112 956833# 429# - 29 71 42 113 Mo x -52650# 300# 8246# 3# B- 10162# 300# 112 943478# 322# - 27 70 43 113 Tc x -62811.549 3.353 8329.4652 0.0297 B- 9056.2674 38.4285 112 932569.032 3.600 - 25 69 44 113 Ru -71867.816 38.282 8402.6857 0.3388 B- 6899.1276 38.9406 112 922846.729 41.097 - 23 68 45 113 Rh x -78766.944 7.132 8456.8165 0.0631 B- 4823.5559 9.8809 112 915440.212 7.656 - 21 67 46 113 Pd x -83590.500 6.947 8492.5795 0.0615 B- 3436.3252 18.0341 112 910261.912 7.458 - 19 66 47 113 Ag + -87026.825 16.643 8516.0660 0.1473 B- 2016.4615 16.6410 112 906572.865 17.866 - 17 65 48 113 Cd -89043.286 0.245 8526.9874 0.0022 B- 323.8370 0.2653 112 904408.105 0.262 - 15 64 49 113 In -89367.123 0.188 8522.9297 0.0017 B- -1038.9941 1.5733 112 904060.451 0.202 - 13 63 50 113 Sn -88328.129 1.575 8506.8117 0.0139 B- -3911.1637 17.1206 112 905175.857 1.690 - 11 62 51 113 Sb - -84416.966 17.193 8465.2762 0.1521 B- -6069.9281 32.8102 112 909374.664 18.457 - 9 61 52 113 Te x -78347.037 27.945 8404.6366 0.2473 B- -7227.5210 29.0704 112 915891.000 30.000 - 7 60 53 113 I x -71119.517 8.011 8333.7528 0.0709 B- -8915.8902 10.5334 112 923650.062 8.600 - 5 59 54 113 Xe -62203.626 6.840 8247.9277 0.0605 B- -10439.0876 10.9702 112 933221.663 7.342 - 3 58 55 113 Cs -p -51764.539 8.577 8148.6230 0.0759 B- -12055# 300# 112 944428.484 9.207 - 1 57 56 113 Ba x -39710# 300# 8035# 3# B- * 112 957370# 322# -0 32 73 41 114 Nb x -34960# 500# 8097# 4# B- 14720# 583# 113 962469# 537# - 30 72 42 114 Mo x -49680# 300# 8219# 3# B- 8920# 527# 113 946666# 322# - 28 71 43 114 Tc x -58600.294 433.145 8290.2599 3.7995 B- 11620.9190 433.1594 113 937090.000 465.000 - 26 70 44 114 Ru x -70221.213 3.556 8385.3351 0.0312 B- 5489.0622 71.6432 113 924614.430 3.817 - 24 69 45 114 Rh -75710.275 71.561 8426.6221 0.6277 B- 7780.0712 71.8915 113 918721.680 76.824 - 22 68 46 114 Pd x -83490.346 6.948 8488.0056 0.0610 B- 1440.4642 8.3133 113 910369.430 7.459 - 20 67 47 114 Ag x -84930.811 4.564 8493.7786 0.0400 B- 5084.1233 4.5727 113 908823.029 4.900 - 18 66 48 114 Cd -90014.934 0.276 8531.5135 0.0024 B- -1445.1268 0.3817 113 903364.998 0.296 - 16 65 49 114 In -88569.807 0.301 8511.9742 0.0027 B- 1989.9281 0.3018 113 904916.405 0.323 - 14 64 50 114 Sn -90559.735 0.029 8522.5671 0.0004 B- -6063.1189 19.7724 113 902780.130 0.031 - 12 63 51 114 Sb -84496.616 19.772 8462.5191 0.1734 B- -2606.9398 31.4275 113 909289.155 21.226 - 10 62 52 114 Te x -81889.676 24.428 8432.7885 0.2143 B- -9250.7417 31.5883 113 912087.820 26.224 - 8 61 53 114 I x -72638.935 20.027 8344.7790 0.1757 B- -5553.0360 22.9354 113 922018.900 21.500 - 6 60 54 114 Xe x -67085.899 11.178 8289.2054 0.0981 B- -12399.9706 85.7989 113 927980.329 12.000 - 4 59 55 114 Cs -a -54685.928 85.068 8173.5711 0.7462 B- -8780.4915 133.3375 113 941292.244 91.323 - 2 58 56 114 Ba -a -45905.437 102.676 8089.6865 0.9007 B- * 113 950718.489 110.227 -0 33 74 41 115 Nb x -30880# 500# 8061# 4# B- 13670# 640# 114 966849# 537# - 31 73 42 115 Mo x -44550# 400# 8173# 3# B- 11247# 445# 114 952174# 429# - 29 72 43 115 Tc x -55796# 196# 8264# 2# B- 10309# 197# 114 940100# 210# - 27 71 44 115 Ru x -66105.296 25.166 8346.8140 0.2188 B- 8123.9327 26.1788 114 929033.049 27.016 - 25 70 45 115 Rh x -74229.228 7.319 8410.6538 0.0636 B- 6196.5938 15.3503 114 920311.649 7.857 - 23 69 46 115 Pd -80425.822 13.547 8457.7342 0.1178 B- 4556.7647 21.6496 114 913659.333 14.543 - 21 68 47 115 Ag -84982.587 18.268 8490.5553 0.1589 B- 3101.8930 18.2744 114 908767.445 19.611 - 19 67 48 115 Cd -88084.480 0.651 8510.7252 0.0057 B- 1451.8768 0.6514 114 905437.426 0.699 - 17 66 49 115 In -89536.357 0.012 8516.5472 0.0003 B- 497.4892 0.0097 114 903878.772 0.012 - 15 65 50 115 Sn -90033.846 0.015 8514.0702 0.0003 B- -3030.4336 16.0253 114 903344.695 0.016 - 13 64 51 115 Sb x -87003.412 16.025 8480.9156 0.1394 B- -4940.6447 32.2137 114 906598.000 17.203 - 11 63 52 115 Te x -82062.767 27.945 8431.1504 0.2430 B- -5724.9628 40.1840 114 911902.000 30.000 - 9 62 53 115 I x -76337.805 28.876 8374.5651 0.2511 B- -7681.0475 31.3126 114 918048.000 31.000 - 7 61 54 115 Xe x -68656.757 12.109 8300.9704 0.1053 B- -8957# 103# 114 926293.943 13.000 - 5 60 55 115 Cs x -59699# 102# 8216# 1# B- -10779# 225# 114 935910# 110# - 3 59 56 115 Ba x -48920# 200# 8116# 2# B- * 114 947482# 215# -0 34 75 41 116 Nb x -25230# 300# 8012# 3# B- 15980# 583# 115 972914# 322# - 32 74 42 116 Mo x -41210# 500# 8143# 4# B- 10003# 582# 115 955759# 537# - 30 73 43 116 Tc x -51214# 298# 8223# 3# B- 12855# 298# 115 945020# 320# - 28 72 44 116 Ru x -64068.917 3.726 8326.8840 0.0321 B- 6666.8252 73.9257 115 931219.191 4.000 - 26 71 45 116 Rh -70735.742 73.832 8377.6123 0.6365 B- 9095.2839 74.1690 115 924062.060 79.261 - 24 70 46 116 Pd x -79831.026 7.135 8449.2755 0.0615 B- 2711.6378 7.8446 115 914297.872 7.659 - 22 69 47 116 Ag x -82542.664 3.260 8465.9073 0.0281 B- 6169.8248 3.2642 115 911386.809 3.500 - 20 68 48 116 Cd -88712.489 0.160 8512.3511 0.0014 B- -462.7305 0.2720 115 904763.230 0.172 - 18 67 49 116 In -n -88249.758 0.220 8501.6177 0.0019 B- 3276.2204 0.2397 115 905259.992 0.236 - 16 66 50 116 Sn -91525.979 0.096 8523.1166 0.0009 B- -4703.9591 5.1540 115 901742.825 0.103 - 14 65 51 116 Sb -86822.020 5.154 8475.8208 0.0444 B- -1558.2272 24.7485 115 906792.732 5.533 - 12 64 52 116 Te -85263.793 24.206 8455.6435 0.2087 B- -7843.1388 75.3230 115 908465.558 25.986 - 10 63 53 116 I -77420.654 75.037 8381.2858 0.6469 B- -4373.7764 75.8444 115 916885.513 80.555 - 8 62 54 116 Xe -73046.877 13.017 8336.8365 0.1122 B- -11004# 101# 115 921580.955 13.974 - 6 61 55 116 Cs ea -62043# 100# 8235# 1# B- -7663# 224# 115 933395# 108# - 4 60 56 116 Ba x -54380# 200# 8162# 2# B- -14330# 379# 115 941621# 215# - 2 59 57 116 La -a -40050# 321# 8032# 3# B- * 115 957005# 345# -0 33 75 42 117 Mo x -35689# 500# 8096# 4# B- 12450# 640# 116 961686# 537# - 31 74 43 117 Tc x -48140# 400# 8195# 3# B- 11350# 589# 116 948320# 429# - 29 73 44 117 Ru x -59489.871 433.145 8285.5625 3.7021 B- 9406.8875 433.2361 116 936135.000 465.000 - 27 72 45 117 Rh x -68896.758 8.895 8359.2766 0.0760 B- 7527.1313 11.4108 116 926036.291 9.548 - 25 71 46 117 Pd -76423.890 7.255 8416.9243 0.0620 B- 5758.0284 14.7674 116 917955.584 7.788 - 23 70 47 117 Ag -82181.918 13.572 8459.4515 0.1160 B- 4236.4790 13.6099 116 911774.086 14.570 - 21 69 48 117 Cd -n -86418.397 1.013 8488.9740 0.0087 B- 2524.6381 4.9829 116 907226.039 1.087 - 19 68 49 117 In -88943.035 4.881 8503.8653 0.0417 B- 1454.7073 4.8567 116 904515.729 5.239 - 17 67 50 117 Sn -90397.742 0.483 8509.6120 0.0041 B- -1758.1788 8.4449 116 902954.036 0.518 - 15 66 51 117 Sb -88639.564 8.437 8487.8981 0.0721 B- -3544.0634 13.0785 116 904841.519 9.057 - 13 65 52 117 Te -85095.500 13.455 8450.9203 0.1150 B- -4656.9321 28.1284 116 908646.227 14.444 - 11 64 53 117 I -80438.568 25.558 8404.4307 0.2184 B- -6253.2213 27.5845 116 913645.649 27.437 - 9 63 54 117 Xe x -74185.347 10.378 8344.2976 0.0887 B- -7692.2462 63.2672 116 920358.758 11.141 - 7 62 55 117 Cs x -66493.101 62.410 8271.8652 0.5334 B- -9035.1943 258.0009 116 928616.723 67.000 - 5 61 56 117 Ba ep -57457.906 250.339 8187.9546 2.1396 B- -11187# 321# 116 938316.403 268.749 - 3 60 57 117 La -p -46271# 200# 8086# 2# B- * 116 950326# 215# -0 34 76 42 118 Mo x -32370# 500# 8067# 4# B- 10920# 640# 117 965249# 537# - 32 75 43 118 Tc x -43290# 400# 8153# 3# B- 13710# 447# 117 953526# 429# - 30 74 44 118 Ru x -57000# 200# 8263# 2# B- 7887# 202# 117 938808# 215# - 28 73 45 118 Rh x -64886.840 24.236 8322.8539 0.2054 B- 10501.5182 24.3424 117 930341.116 26.018 - 26 72 46 118 Pd -75388.358 2.494 8405.2197 0.0211 B- 4165.4444 3.5419 117 919067.273 2.677 - 24 71 47 118 Ag x -79553.802 2.515 8433.8900 0.0213 B- 7147.8469 20.1582 117 914595.484 2.700 - 22 70 48 118 Cd -nn -86701.649 20.001 8487.8350 0.1695 B- 526.5277 21.4501 117 906921.956 21.471 - 20 69 49 118 In -87228.177 7.752 8485.6670 0.0657 B- 4424.6664 7.7396 117 906356.705 8.322 - 18 68 50 118 Sn -91652.843 0.499 8516.5341 0.0042 B- -3656.6393 2.9745 117 901606.630 0.536 - 16 67 51 118 Sb - -87996.204 3.016 8478.9156 0.0256 B- -305.4459 18.5521 117 905532.194 3.237 - 14 66 52 118 Te +nn -87690.758 18.306 8469.6970 0.1551 B- -6719.7015 26.9364 117 905860.104 19.652 - 12 65 53 118 I x -80971.056 19.760 8406.1203 0.1675 B- -2891.9893 22.3197 117 913074.000 21.213 - 10 64 54 118 Xe x -78079.067 10.378 8374.9819 0.0880 B- -9669.6905 16.4423 117 916178.678 11.141 - 8 63 55 118 Cs IT -68409.377 12.753 8286.4053 0.1081 B- -6210# 201# 117 926559.517 13.690 - 6 62 56 118 Ba x -62200# 200# 8227# 2# B- -12580# 361# 117 933226# 215# - 4 61 57 118 La x -49620# 300# 8114# 3# B- * 117 946731# 322# -0 35 77 42 119 Mo x -26580# 300# 8019# 3# B- 13590# 583# 118 971465# 322# - 33 76 43 119 Tc x -40170# 500# 8126# 4# B- 11910# 583# 118 956876# 537# - 31 75 44 119 Ru x -52080# 300# 8220# 3# B- 10743# 300# 118 944090# 322# - 29 74 45 119 Rh x -62822.802 9.315 8303.3953 0.0783 B- 8584.4751 12.4416 118 932556.951 10.000 - 27 73 46 119 Pd x -71407.277 8.248 8368.9594 0.0693 B- 7238.4816 16.8566 118 923341.138 8.854 - 25 72 47 119 Ag -78645.759 14.703 8423.2126 0.1236 B- 5331.1799 35.9259 118 915570.309 15.783 - 23 71 48 119 Cd -83976.939 37.695 8461.4381 0.3168 B- 3721.7197 38.0880 118 909847.052 40.467 - 21 70 49 119 In -87698.658 7.310 8486.1387 0.0614 B- 2366.3263 7.3381 118 905851.622 7.847 - 19 69 50 119 Sn -90064.985 0.725 8499.4494 0.0061 B- -589.4452 6.9937 118 903311.266 0.778 - 17 68 51 119 Sb -89475.539 6.998 8487.9218 0.0588 B- -2293.0000 2.0000 118 903944.062 7.512 - 15 67 52 119 Te - -87182.539 7.278 8462.0785 0.0612 B- -3404.8080 22.8941 118 906405.699 7.813 - 13 66 53 119 I x -83777.731 21.706 8426.8924 0.1824 B- -4983.2433 24.0598 118 910060.910 23.302 - 11 65 54 119 Xe -78794.488 10.378 8378.4420 0.0872 B- -6489.4269 17.3790 118 915410.641 11.141 - 9 64 55 119 Cs IT -72305.061 13.940 8317.3347 0.1171 B- -7714.9651 200.7537 118 922377.327 14.965 - 7 63 56 119 Ba ep -64590.096 200.269 8245.9287 1.6829 B- -9570# 361# 118 930659.683 214.997 - 5 62 57 119 La x -55020# 300# 8159# 3# B- -11199# 583# 118 940934# 322# - 3 61 58 119 Ce x -43820# 500# 8058# 4# B- * 118 952957# 537# -0 34 77 43 120 Tc x -35000# 500# 8083# 4# B- 14720# 640# 119 962426# 537# - 32 76 44 120 Ru x -49720# 400# 8199# 3# B- 8899# 447# 119 946623# 429# - 30 75 45 120 Rh x -58620# 200# 8266# 2# B- 11660# 200# 119 937069# 215# - 28 74 46 120 Pd -70279.604 2.296 8357.0817 0.0191 B- 5371.9076 5.0261 119 924551.745 2.464 - 26 73 47 120 Ag x -75651.512 4.471 8395.3281 0.0373 B- 8305.8535 5.8202 119 918784.765 4.800 - 24 72 48 120 Cd x -83957.365 3.726 8458.0240 0.0311 B- 1770.3754 40.1837 119 909868.065 4.000 - 22 71 49 120 In + -85727.741 40.011 8466.2575 0.3334 B- 5370.0000 40.0000 119 907967.489 42.953 - 20 70 50 120 Sn -91097.741 0.920 8504.4880 0.0077 B- -2680.6076 7.1399 119 902202.557 0.987 - 18 69 51 120 Sb - -88417.133 7.199 8475.6300 0.0600 B- 945.0271 7.3530 119 905080.308 7.728 - 16 68 52 120 Te -89362.160 1.751 8476.9857 0.0146 B- -5615.0000 15.0000 119 904065.779 1.880 - 14 67 53 120 I - -83747.160 15.102 8423.6745 0.1258 B- -1574.7260 19.1760 119 910093.729 16.212 - 12 66 54 120 Xe x -82172.434 11.817 8404.0322 0.0985 B- -8283.7857 15.4611 119 911784.267 12.686 - 10 65 55 120 Cs IT -73888.649 9.970 8328.4811 0.0831 B- -5000.0000 300.0000 119 920677.277 10.702 - 8 64 56 120 Ba - -68888.649 300.166 8280.2949 2.5014 B- -11319# 424# 119 926044.997 322.241 - 6 63 57 120 La x -57570# 300# 8179# 2# B- -7840# 583# 119 938196# 322# - 4 62 58 120 Ce x -49730# 500# 8108# 4# B- * 119 946613# 537# -0 35 78 43 121 Tc x -31540# 500# 8054# 4# B- 13080# 640# 120 966140# 537# - 33 77 44 121 Ru x -44620# 400# 8156# 3# B- 11630# 737# 120 952098# 429# - 31 76 45 121 Rh x -56250.134 619.444 8245.2397 5.1194 B- 9932.2030 619.4527 120 939613.000 665.000 - 29 75 46 121 Pd x -66182.337 3.353 8320.8584 0.0277 B- 8220.4934 12.5652 120 928950.342 3.600 - 27 74 47 121 Ag x -74402.831 12.109 8382.3306 0.1001 B- 6671.0057 12.2642 120 920125.279 13.000 - 25 73 48 121 Cd x -81073.837 1.942 8430.9972 0.0161 B- 4760.7564 27.4876 120 912963.660 2.085 - 23 72 49 121 In +p -85834.593 27.419 8463.8767 0.2266 B- 3362.0331 27.4098 120 907852.778 29.435 - 21 71 50 121 Sn -89196.626 0.978 8485.1964 0.0081 B- 402.5306 2.5239 120 904243.488 1.050 - 19 70 51 121 Sb -89599.157 2.506 8482.0574 0.0207 B- -1056.0462 25.7587 120 903811.353 2.690 - 17 69 52 121 Te -88543.111 25.835 8466.8641 0.2135 B- -2297.4615 25.9856 120 904945.065 27.734 - 15 68 53 121 I -86245.649 4.723 8441.4111 0.0390 B- -3764.6525 11.2790 120 907411.492 5.070 - 13 67 54 121 Xe -82480.997 10.243 8403.8326 0.0847 B- -5378.6549 13.9791 120 911453.012 10.995 - 11 66 55 121 Cs -77102.342 14.290 8352.9152 0.1181 B- -6357.4948 141.1765 120 917227.235 15.340 - 9 65 56 121 Ba - -70744.847 141.898 8293.9083 1.1727 B- -8555# 332# 120 924052.286 152.333 - 7 64 57 121 La x -62190# 300# 8217# 2# B- -9500# 500# 120 933236# 322# - 5 63 58 121 Ce x -52690# 401# 8132# 3# B- -11139# 641# 120 943435# 430# - 3 62 59 121 Pr -p -41551# 500# 8033# 4# B- * 120 955393# 537# -0 36 79 43 122 Tc x -26305# 300# 8011# 2# B- 15475# 583# 121 971760# 322# - 34 78 44 122 Ru x -41780# 500# 8132# 4# B- 10099# 583# 121 955147# 537# - 32 77 45 122 Rh x -51880# 300# 8208# 2# B- 12737# 301# 121 944305# 322# - 30 76 46 122 Pd x -64616.169 19.561 8305.9755 0.1603 B- 6489.9492 42.9094 121 930631.693 21.000 - 28 75 47 122 Ag x -71106.118 38.191 8352.7591 0.3130 B- 9506.2662 38.2604 121 923664.446 41.000 - 26 74 48 122 Cd -80612.384 2.299 8424.2667 0.0188 B- 2958.9765 50.1126 121 913459.050 2.468 - 24 73 49 122 In + -83571.361 50.060 8442.1079 0.4103 B- 6368.5921 50.0000 121 910282.458 53.741 - 22 72 50 122 Sn -89939.953 2.448 8487.8968 0.0201 B- -1605.7483 3.2135 121 903445.494 2.627 - 20 71 51 122 Sb -88334.205 2.503 8468.3222 0.0205 B- 1979.0772 2.1265 121 905169.335 2.687 - 18 70 52 122 Te -90313.282 1.357 8478.1315 0.0111 B- -4234.0000 5.0000 121 903044.708 1.456 - 16 69 53 122 I - -86079.282 5.181 8437.0139 0.0425 B- -724.2937 12.2596 121 907590.094 5.561 - 14 68 54 122 Xe x -85354.988 11.111 8424.6644 0.0911 B- -7210.2195 35.4720 121 908367.655 11.928 - 12 67 55 122 Cs -78144.769 33.687 8359.1515 0.2761 B- -3535.8170 43.7690 121 916108.144 36.164 - 10 66 56 122 Ba x -74608.952 27.945 8323.7567 0.2291 B- -10066# 299# 121 919904.000 30.000 - 8 65 57 122 La x -64543# 298# 8235# 2# B- -6669# 499# 121 930710# 320# - 6 64 58 122 Ce x -57874# 401# 8174# 3# B- -13094# 641# 121 937870# 430# - 4 63 59 122 Pr x -44780# 500# 8060# 4# B- * 121 951927# 537# -0 35 79 44 123 Ru x -36550# 500# 8089# 4# B- 12640# 640# 122 960762# 537# - 33 78 45 123 Rh x -49190# 400# 8185# 3# B- 11239# 885# 122 947192# 429# - 31 77 46 123 Pd x -60429.748 789.441 8270.0318 6.4182 B- 9138.8323 790.1142 122 935126.000 847.500 - 29 76 47 123 Ag x -69568.581 32.602 8337.9707 0.2651 B- 7845.6026 32.7136 122 925315.060 35.000 - 27 75 48 123 Cd -77414.183 2.696 8395.3955 0.0219 B- 6014.8503 19.8980 122 916892.460 2.894 - 25 74 49 123 In -83429.034 19.832 8437.9362 0.1612 B- 4385.6489 19.8392 122 910435.252 21.290 - 23 73 50 123 Sn -87814.683 2.479 8467.2313 0.0202 B- 1408.2079 2.4203 122 905727.065 2.661 - 21 72 51 123 Sb -89222.890 1.356 8472.3196 0.0110 B- -51.9128 0.0661 122 904215.292 1.456 - 19 71 52 123 Te -89170.978 1.355 8465.5370 0.0110 B- -1228.3898 3.4448 122 904271.022 1.454 - 17 70 53 123 I -87942.588 3.686 8449.1896 0.0300 B- -2694.3302 9.6829 122 905589.753 3.956 - 15 69 54 123 Xe -85248.258 9.534 8420.9239 0.0775 B- -4204.6012 15.4121 122 908482.235 10.234 - 13 68 55 123 Cs x -81043.657 12.109 8380.3796 0.0985 B- -5388.6934 17.1253 122 912996.060 13.000 - 11 67 56 123 Ba x -75654.963 12.109 8330.2086 0.0985 B- -7004# 196# 122 918781.060 13.000 - 9 66 57 123 La x -68651# 196# 8267# 2# B- -8365# 357# 122 926300# 210# - 7 65 58 123 Ce x -60286# 298# 8193# 2# B- -10056# 499# 122 935280# 320# - 5 64 59 123 Pr x -50230# 400# 8104# 3# B- * 122 946076# 429# -0 36 80 44 124 Ru x -33590# 600# 8065# 5# B- 11120# 721# 123 963940# 644# - 34 79 45 124 Rh x -44710# 400# 8148# 3# B- 13690# 500# 123 952002# 429# - 32 78 46 124 Pd x -58400# 300# 8252# 2# B- 7830# 391# 123 937305# 322# - 30 77 47 124 Ag x -66229.951 251.503 8308.8958 2.0283 B- 10469.4858 251.5169 123 928899.227 270.000 - 28 76 48 124 Cd -76699.436 2.609 8387.0179 0.0210 B- 4168.3420 30.5355 123 917659.772 2.800 - 26 75 49 124 In -80867.778 30.561 8414.3243 0.2465 B- 7363.6970 30.5668 123 913184.873 32.808 - 24 74 50 124 Sn -88231.475 1.314 8467.3997 0.0106 B- -612.4067 0.4101 123 905279.619 1.410 - 22 73 51 124 Sb -n -87619.069 1.358 8456.1517 0.0110 B- 2905.0730 0.1317 123 905937.065 1.457 - 20 72 52 124 Te -90524.142 1.352 8473.2705 0.0109 B- -3159.5870 1.8593 123 902818.341 1.451 - 18 71 53 124 I - -87364.555 2.299 8441.4807 0.0185 B- 302.8501 1.8639 123 906210.297 2.467 - 16 70 54 124 Xe -87667.405 1.358 8437.6138 0.0110 B- -5926.3445 9.2512 123 905885.174 1.457 - 14 69 55 124 Cs x -81741.060 9.151 8383.5114 0.0738 B- -2651.2748 15.4894 123 912247.366 9.823 - 12 68 56 124 Ba x -79089.786 12.497 8355.8209 0.1008 B- -8831.1685 58.0305 123 915093.627 13.416 - 10 67 57 124 La x -70258.617 56.669 8278.2926 0.4570 B- -5343# 303# 123 924574.275 60.836 - 8 66 58 124 Ce x -64916# 298# 8229# 2# B- -11765# 499# 123 930310# 320# - 6 65 59 124 Pr x -53151# 401# 8128# 3# B- -8321# 641# 123 942940# 430# - 4 64 60 124 Nd x -44830# 500# 8054# 4# B- * 123 951873# 537# -0 37 81 44 125 Ru x -28370# 300# 8023# 2# B- 13460# 583# 124 969544# 322# - 35 80 45 125 Rh x -41830# 500# 8124# 4# B- 12130# 640# 124 955094# 537# - 33 79 46 125 Pd x -53960# 400# 8215# 3# B- 10560# 589# 124 942072# 429# - 31 78 47 125 Ag x -64519.939 433.145 8293.3151 3.4652 B- 8828.1511 433.1544 124 930735.000 465.000 - 29 77 48 125 Cd x -73348.090 2.888 8357.6815 0.0231 B- 7064.2177 3.3869 124 921257.590 3.100 - 27 76 49 125 In x -80412.308 1.770 8407.9365 0.0142 B- 5481.3495 2.2131 124 913673.841 1.900 - 25 75 50 125 Sn -n -85893.657 1.329 8445.5285 0.0106 B- 2361.4366 2.1661 124 907789.370 1.426 - 23 74 51 125 Sb + -88255.094 2.515 8458.1612 0.0201 B- 766.7000 2.1213 124 905254.264 2.700 - 21 73 52 125 Te -89021.794 1.352 8458.0361 0.0108 B- -185.7700 0.0600 124 904431.178 1.451 - 19 72 53 125 I - -88836.024 1.353 8450.2911 0.0108 B- -1636.6632 0.4259 124 904630.610 1.452 - 17 71 54 125 Xe -87199.361 1.415 8430.9390 0.0113 B- -3109.6184 7.7879 124 906387.640 1.518 - 15 70 55 125 Cs -84089.742 7.736 8399.8033 0.0619 B- -4420.7663 13.4415 124 909725.953 8.304 - 13 69 56 125 Ba -79668.976 10.992 8358.1784 0.0879 B- -5909.4836 27.6308 124 914471.840 11.800 - 11 68 57 125 La -73759.492 25.997 8304.6438 0.2080 B- -7102# 197# 124 920815.931 27.909 - 9 67 58 125 Ce x -66658# 196# 8242# 2# B- -8587# 358# 124 928440# 210# - 7 66 59 125 Pr x -58070# 300# 8167# 2# B- -10001# 500# 124 937659# 322# - 5 65 60 125 Nd x -48070# 400# 8080# 3# B- * 124 948395# 429# -0 36 81 45 126 Rh x -37200# 500# 8087# 4# B- 14590# 640# 125 960064# 537# - 34 80 46 126 Pd x -51790# 400# 8197# 3# B- 8930# 447# 125 944401# 429# - 32 79 47 126 Ag x -60720# 200# 8261# 2# B- 11535# 200# 125 934814# 215# - 30 78 48 126 Cd -72255.727 2.304 8346.7393 0.0183 B- 5553.6500 4.7831 125 922430.290 2.473 - 28 77 49 126 In x -77809.377 4.192 8384.6067 0.0333 B- 8205.7585 11.4802 125 916468.202 4.500 - 26 76 50 126 Sn -nn -86015.135 10.688 8443.5227 0.0848 B- 378.0000 30.0000 125 907658.958 11.473 - 24 75 51 126 Sb - -86393.135 31.847 8440.3136 0.2528 B- 3671.0321 31.8223 125 907253.158 34.189 - 22 74 52 126 Te -90064.168 1.354 8463.2397 0.0107 B- -2153.6712 3.6717 125 903312.144 1.453 - 20 73 53 126 I -87910.496 3.778 8439.9379 0.0300 B- 1235.8904 3.7779 125 905624.205 4.055 - 18 72 54 126 Xe -89146.38687 0.00562 8443.5375 0.0003 B- -4795.7039 10.3587 125 904297.422 0.006 - 16 71 55 126 Cs -84350.683 10.359 8399.2673 0.0822 B- -1680.7697 16.2322 125 909445.821 11.120 - 14 70 56 126 Ba x -82669.913 12.497 8379.7187 0.0992 B- -7696.4376 91.3663 125 911250.202 13.416 - 12 69 57 126 La x -74973.476 90.508 8312.4268 0.7183 B- -4152.9106 94.7235 125 919512.667 97.163 - 10 68 58 126 Ce x -70820.565 27.945 8273.2581 0.2218 B- -10497# 198# 125 923971.000 30.000 - 8 67 59 126 Pr x -60324# 196# 8184# 2# B- -6943# 358# 125 935240# 210# - 6 66 60 126 Nd x -53380# 300# 8122# 2# B- -13631# 583# 125 942694# 322# - 4 65 61 126 Pm x -39750# 500# 8008# 4# B- * 125 957327# 537# -0 37 82 45 127 Rh x -33730# 600# 8060# 5# B- 13490# 781# 126 963789# 644# - 35 81 46 127 Pd x -47220# 500# 8160# 4# B- 11429# 539# 126 949307# 537# - 33 80 47 127 Ag x -58650# 200# 8244# 2# B- 10092# 200# 126 937037# 215# - 31 79 48 127 Cd x -68741.199 6.200 8316.8971 0.0488 B- 8138.6978 11.7675 126 926203.291 6.656 - 29 78 49 127 In -76879.897 10.001 8374.8212 0.0788 B- 6589.6810 12.0260 126 917466.040 10.736 - 27 77 50 127 Sn -83469.578 9.226 8420.5482 0.0726 B- 3228.7160 10.1668 126 910391.726 9.904 - 25 76 51 127 Sb -86698.294 5.083 8439.8110 0.0400 B- 1582.2030 4.9102 126 906925.557 5.457 - 23 75 52 127 Te -88280.497 1.365 8446.1090 0.0108 B- 702.7199 3.5652 126 905226.993 1.465 - 21 74 53 127 I -88983.217 3.621 8445.4820 0.0285 B- -662.3336 2.0442 126 904472.592 3.887 - 19 73 54 127 Xe -88320.883 4.088 8434.1066 0.0322 B- -2080.8562 6.4115 126 905183.636 4.388 - 17 72 55 127 Cs -86240.027 5.578 8411.5617 0.0439 B- -3422.0719 12.6525 126 907417.527 5.987 - 15 71 56 127 Ba -82817.955 11.357 8378.4560 0.0894 B- -4921.8386 27.7403 126 911091.272 12.192 - 13 70 57 127 La -77896.116 26.000 8333.5412 0.2047 B- -5916.7727 38.8567 126 916375.083 27.912 - 11 69 58 127 Ce x -71979.344 28.876 8280.7922 0.2274 B- -7436# 198# 126 922727.000 31.000 - 9 68 59 127 Pr x -64543# 196# 8216# 2# B- -8633# 358# 126 930710# 210# - 7 67 60 127 Nd x -55910# 300# 8142# 2# B- -10600# 500# 126 939978# 322# - 5 66 61 127 Pm x -45310# 400# 8052# 3# B- * 126 951358# 429# -0 38 83 45 128 Rh x -27340# 300# 8010# 2# B- 17050# 583# 127 970649# 322# - 36 82 46 128 Pd x -44390# 500# 8137# 4# B- 10320# 583# 127 952345# 537# - 34 81 47 128 Ag x -54710# 300# 8211# 2# B- 12528# 300# 127 941266# 322# - 32 80 48 128 Cd -67238.245 6.432 8303.2367 0.0503 B- 6951.8716 6.5665 127 927816.778 6.905 - 30 79 49 128 In x -74190.117 1.322 8351.4361 0.0103 B- 9171.3131 17.7194 127 920353.637 1.419 - 28 78 50 128 Sn -83361.430 17.682 8416.9749 0.1381 B- 1268.4219 13.3175 127 910507.828 18.982 - 26 77 51 128 Sb IT -84629.852 18.788 8420.7724 0.1468 B- 4363.9419 18.7862 127 909146.121 20.169 - 24 76 52 128 Te -88993.794 0.706 8448.7536 0.0055 B- -1255.7634 3.6807 127 904461.237 0.758 - 22 75 53 128 I -87738.030 3.621 8432.8309 0.0283 B- 2122.5041 3.6211 127 905809.355 3.887 - 20 74 54 128 Xe -89860.53427 0.00520 8443.3008 0.0003 B- -3928.7617 5.3762 127 903530.75341 0.00558 - 18 73 55 128 Cs -85931.773 5.376 8406.4953 0.0420 B- -562.6171 5.6122 127 907748.452 5.771 - 16 72 56 128 Ba -85369.156 1.610 8395.9878 0.0126 B- -6743.7167 54.4716 127 908352.446 1.728 - 14 71 57 128 La x -78625.439 54.448 8337.1904 0.4254 B- -3091.5136 61.2003 127 915592.123 58.452 - 12 70 58 128 Ce x -75533.925 27.945 8306.9259 0.2183 B- -9203.1617 40.8585 127 918911.000 30.000 - 10 69 59 128 Pr x -66330.764 29.808 8228.9141 0.2329 B- -5800# 202# 127 928791.000 32.000 - 8 68 60 128 Nd x -60530# 200# 8177# 2# B- -12311# 361# 127 935018# 215# - 6 67 61 128 Pm x -48220# 300# 8075# 2# B- -9070# 583# 127 948234# 322# - 4 66 62 128 Sm x -39150# 500# 7998# 4# B- * 127 957971# 537# -0 37 83 46 129 Pd x -37880# 600# 8086# 5# B- 13990# 721# 128 959334# 644# - 35 82 47 129 Ag x -51870# 400# 8188# 3# B- 11252# 400# 128 944315# 429# - 33 81 48 129 Cd x -63122.142 5.310 8269.5311 0.0412 B- 9712.7471 5.6637 128 932235.597 5.700 - 31 80 49 129 In -72834.889 1.971 8338.7590 0.0153 B- 7755.7081 17.2376 128 921808.534 2.116 - 29 79 50 129 Sn -80590.597 17.270 8392.8161 0.1339 B- 4038.7874 27.3634 128 913482.440 18.540 - 27 78 51 129 Sb + -84629.384 21.225 8418.0598 0.1645 B- 2375.5000 21.2132 128 909146.623 22.786 - 25 77 52 129 Te -87004.884 0.711 8430.4098 0.0055 B- 1502.2919 3.1358 128 906596.419 0.763 - 23 76 53 129 I -88507.176 3.153 8435.9908 0.0244 B- 188.8936 3.1534 128 904983.643 3.385 - 21 75 54 129 Xe -88696.06975 0.00505 8431.3904 0.0003 B- -1197.0197 4.5532 128 904780.85742 0.00542 - 19 74 55 129 Cs -87499.050 4.553 8416.0465 0.0353 B- -2438.1843 10.5627 128 906065.910 4.888 - 17 73 56 129 Ba -85060.866 10.504 8391.0811 0.0814 B- -3737.3247 21.6280 128 908683.409 11.276 - 15 72 57 129 La -81323.541 21.343 8356.0449 0.1655 B- -5036.0370 35.1633 128 912695.592 22.913 - 13 71 58 129 Ce x -76287.504 27.945 8310.9411 0.2166 B- -6513.9383 40.8585 128 918102.000 30.000 - 11 70 59 129 Pr x -69773.566 29.808 8254.3808 0.2311 B- -7399# 204# 128 925095.000 32.000 - 9 69 60 129 Nd ep -62375# 202# 8191# 2# B- -9195# 362# 128 933038# 217# - 7 68 61 129 Pm x -53180# 300# 8114# 2# B- -10850# 583# 128 942909# 322# - 5 67 62 129 Sm x -42330# 500# 8023# 4# B- * 128 954557# 537# -0 38 84 46 130 Pd x -32730# 300# 8046# 2# B- 13168# 520# 129 964863# 322# - 36 83 47 130 Ag -nn -45898# 424# 8142# 3# B- 15220# 425# 129 950727# 455# - 34 82 48 130 Cd x -61117.597 22.356 8252.5868 0.1720 B- 8788.9322 22.4274 129 934387.563 24.000 - 32 81 49 130 In -69906.530 1.790 8314.1760 0.0138 B- 10225.6870 2.5905 129 924952.257 1.921 - 30 80 50 130 Sn -80132.217 1.873 8386.8170 0.0144 B- 2153.4702 14.1129 129 913974.531 2.010 - 28 79 51 130 Sb -82285.687 14.212 8397.3641 0.1093 B- 5067.2728 14.2124 129 911662.686 15.257 - 26 78 52 130 Te -87352.960 0.011 8430.3251 0.0003 B- -416.7716 3.1537 129 906222.745 0.011 - 24 77 53 130 I -n -86936.188 3.154 8421.1011 0.0243 B- 2944.2864 3.1537 129 906670.168 3.385 - 22 76 54 130 Xe -89880.474 0.009 8437.7314 0.0003 B- -2980.7199 8.3567 129 903509.346 0.010 - 20 75 55 130 Cs -86899.754 8.357 8408.7848 0.0643 B- 357.0219 8.3617 129 906709.281 8.971 - 18 74 56 130 Ba -87256.776 0.287 8405.5130 0.0022 B- -5629.4021 25.9477 129 906326.002 0.308 - 16 73 57 130 La x -81627.374 25.946 8356.1919 0.1996 B- -2204.4611 38.1328 129 912369.413 27.854 - 14 72 58 130 Ce x -79422.913 27.945 8333.2164 0.2150 B- -8247.4488 70.0853 129 914736.000 30.000 - 12 71 59 130 Pr x -71175.464 64.273 8263.7565 0.4944 B- -4579.2250 70.0853 129 923590.000 69.000 - 10 70 60 130 Nd x -66596.239 27.945 8222.5136 0.2150 B- -11127# 202# 129 928506.000 30.000 - 8 69 61 130 Pm x -55470# 200# 8131# 2# B- -7770# 447# 129 940451# 215# - 6 68 62 130 Sm x -47700# 400# 8065# 3# B- -14187# 671# 129 948792# 429# - 4 67 63 130 Eu -p -33513# 539# 7950# 4# B- * 129 964022# 578# -0 39 85 46 131 Pd x -25740# 300# 7993# 2# B- 15010# 583# 130 972367# 322# - 37 84 47 131 Ag x -40750# 500# 8102# 4# B- 14462# 501# 130 956253# 537# - 35 83 48 131 Cd -55211.760 19.238 8206.1204 0.1469 B- 12812.6089 19.3644 130 940727.740 20.653 - 33 82 49 131 In -68024.369 2.205 8297.9544 0.0168 B- 9240.2095 4.2397 130 926972.839 2.367 - 31 81 50 131 Sn -77264.579 3.621 8362.5183 0.0276 B- 4716.8328 3.9621 130 917053.067 3.887 - 29 80 51 131 Sb -81981.412 2.084 8392.5525 0.0159 B- 3229.6099 2.0845 130 911989.339 2.236 - 27 79 52 131 Te -n -85211.022 0.061 8411.2339 0.0005 B- 2231.7057 0.6077 130 908522.210 0.065 - 25 78 53 131 I + -87442.727 0.605 8422.2977 0.0046 B- 970.8477 0.6046 130 906126.375 0.649 - 23 77 54 131 Xe -88413.57492 0.00512 8423.7367 0.0003 B- -358.0009 0.1771 130 905084.12808 0.00549 - 21 76 55 131 Cs +nn -88055.574 0.177 8415.0317 0.0014 B- -1376.6158 0.4515 130 905468.457 0.190 - 19 75 56 131 Ba -n -86678.958 0.415 8398.5511 0.0032 B- -2909.6936 27.9479 130 906946.315 0.445 - 17 74 57 131 La x -83769.265 27.945 8370.3676 0.2133 B- -4060.8167 43.0918 130 910070.000 30.000 - 15 73 58 131 Ce -79708.448 32.802 8333.3969 0.2504 B- -5407.7842 55.4462 130 914429.465 35.214 - 13 72 59 131 Pr -74300.664 46.995 8286.1439 0.3587 B- -6532.6235 53.0809 130 920234.960 50.451 - 11 71 60 131 Nd -67768.040 27.517 8230.3045 0.2101 B- -7998# 202# 130 927248.020 29.541 - 9 70 61 131 Pm x -59770# 200# 8163# 2# B- -9490# 447# 130 935834# 215# - 7 69 62 131 Sm x -50280# 400# 8085# 3# B- -10816# 565# 130 946022# 429# - 5 68 63 131 Eu -p -39464# 400# 7996# 3# B- * 130 957634# 429# -0 38 85 47 132 Ag x -34400# 500# 8053# 4# B- 16065# 504# 131 963070# 537# - 36 84 48 132 Cd x -50465.429 60.068 8169.1421 0.4551 B- 11946.1243 84.9236 131 945823.136 64.485 - 34 83 49 132 In + -62411.554 60.033 8253.7162 0.4548 B- 14135.0000 60.0000 131 932998.444 64.447 - 32 82 50 132 Sn -76546.554 1.976 8354.8726 0.0150 B- 3088.7280 3.1606 131 917823.898 2.121 - 30 81 51 132 Sb -79635.282 2.467 8372.3452 0.0187 B- 5552.9155 4.2708 131 914508.013 2.648 - 28 80 52 132 Te -85188.197 3.486 8408.4859 0.0264 B- 515.3046 3.4830 131 908546.713 3.742 - 26 79 53 132 I -85703.502 4.065 8406.4628 0.0308 B- 3575.4729 4.0654 131 907993.511 4.364 - 24 78 54 132 Xe -89278.97451 0.00507 8427.6229 0.0003 B- -2126.2813 1.0359 131 904155.08346 0.00544 - 22 77 55 132 Cs -87152.693 1.036 8405.5878 0.0079 B- 1282.2099 1.4773 131 906437.740 1.112 - 20 76 56 132 Ba -88434.903 1.053 8409.3747 0.0080 B- -4711.3256 36.3537 131 905061.231 1.130 - 18 75 57 132 La -83723.578 36.359 8367.7559 0.2754 B- -1254.8898 41.7025 131 910119.047 39.032 - 16 74 58 132 Ce -82468.688 20.407 8352.3223 0.1546 B- -7241.2240 35.3594 131 911466.226 21.907 - 14 73 59 132 Pr x -75227.464 28.876 8291.5377 0.2188 B- -3801.6487 37.6795 131 919240.000 31.000 - 12 72 60 132 Nd x -71425.815 24.205 8256.8104 0.1834 B- -9798# 151# 131 923321.237 25.985 - 10 71 61 132 Pm x -61628# 149# 8177# 1# B- -6488# 335# 131 933840# 160# - 8 70 62 132 Sm x -55140# 300# 8122# 2# B- -12939# 500# 131 940805# 322# - 6 69 63 132 Eu x -42200# 400# 8018# 3# B- * 131 954696# 429# -0 39 86 47 133 Ag x -29080# 500# 8013# 4# B- 15059# 539# 132 968781# 537# - 37 85 48 133 Cd x -44140# 200# 8121# 2# B- 13550# 283# 132 952614# 215# - 35 84 49 133 In x -57690# 200# 8217# 2# B- 13184# 200# 132 938067# 215# - 33 83 50 133 Sn -70873.890 1.904 8310.0890 0.0143 B- 8049.6228 3.6617 132 923913.753 2.043 - 31 82 51 133 Sb -78923.513 3.128 8364.7302 0.0235 B- 4013.6198 3.5179 132 915272.128 3.357 - 29 81 52 133 Te -82937.133 2.066 8389.0255 0.0155 B- 2920.1690 6.2531 132 910963.330 2.218 - 27 80 53 133 I -85857.302 5.902 8405.0993 0.0444 B- 1786.2812 6.3712 132 907828.400 6.335 - 25 79 54 133 Xe + -87643.583 2.400 8412.6477 0.0180 B- 427.3600 2.4000 132 905910.748 2.576 - 23 78 55 133 Cs -88070.943 0.008 8409.9786 0.0003 B- -517.4310 0.9920 132 905451.958 0.008 - 21 77 56 133 Ba -87553.512 0.992 8400.2059 0.0075 B- -2059.1203 27.9624 132 906007.443 1.065 - 19 76 57 133 La x -85494.392 27.945 8378.8415 0.2101 B- -3076.1685 32.3786 132 908218.000 30.000 - 17 75 58 133 Ce x -82418.223 16.354 8349.8301 0.1230 B- -4480.6319 20.5826 132 911520.402 17.557 - 15 74 59 133 Pr x -77937.591 12.497 8310.2588 0.0940 B- -5605.2112 48.2223 132 916330.558 13.416 - 13 73 60 133 Nd x -72332.380 46.575 8262.2320 0.3502 B- -6924.7272 68.5519 132 922348.000 50.000 - 11 72 61 133 Pm x -65407.653 50.301 8204.2841 0.3782 B- -8177# 302# 132 929782.000 54.000 - 9 71 62 133 Sm x -57231# 298# 8137# 2# B- -9995# 422# 132 938560# 320# - 7 70 63 133 Eu x -47236# 298# 8056# 2# B- -11176# 582# 132 949290# 320# - 5 69 64 133 Gd x -36060# 500# 7966# 4# B- * 132 961288# 537# -0 38 86 48 134 Cd x -39460# 300# 8086# 2# B- 12510# 361# 133 957638# 322# - 36 85 49 134 In x -51970# 200# 8173# 1# B- 14464# 200# 133 944208# 215# - 34 84 50 134 Sn x -66433.759 3.167 8275.1719 0.0236 B- 7585.2453 4.4136 133 928680.430 3.400 - 32 83 51 134 Sb x -74019.004 3.074 8325.9398 0.0229 B- 8514.7483 4.1221 133 920537.334 3.300 - 30 82 52 134 Te -82533.752 2.746 8383.6442 0.0205 B- 1509.6875 4.9335 133 911396.376 2.948 - 28 81 53 134 I -84043.440 4.857 8389.0722 0.0362 B- 4082.3946 4.8567 133 909775.660 5.213 - 26 80 54 134 Xe -88125.83443 0.00577 8413.6994 0.0003 B- -1234.6691 0.0160 133 905393.030 0.006 - 24 79 55 134 Cs -86891.165 0.016 8398.6470 0.0003 B- 2058.8368 0.2508 133 906718.501 0.017 - 22 78 56 134 Ba -88950.002 0.251 8408.1731 0.0019 B- -3731.3434 19.9312 133 904508.249 0.269 - 20 77 57 134 La x -85218.659 19.930 8374.4888 0.1487 B- -385.7605 28.5098 133 908514.011 21.395 - 18 76 58 134 Ce x -84832.898 20.387 8365.7716 0.1521 B- -6304.8987 28.7814 133 908928.142 21.886 - 16 75 59 134 Pr x -78528.000 20.316 8312.8817 0.1516 B- -2881.5569 23.5032 133 915696.729 21.810 - 14 74 60 134 Nd x -75646.443 11.817 8285.5391 0.0882 B- -8882.5343 43.5512 133 918790.207 12.686 - 12 73 61 134 Pm x -66763.908 41.917 8213.4131 0.3128 B- -5388# 200# 133 928326.000 45.000 - 10 72 62 134 Sm x -61376# 196# 8167# 1# B- -11576# 358# 133 934110# 210# - 8 71 63 134 Eu x -49800# 300# 8075# 2# B- -8271# 500# 133 946537# 322# - 6 70 64 134 Gd x -41530# 400# 8008# 3# B- * 133 955416# 429# -0 39 87 48 135 Cd x -32820# 400# 8036# 3# B- 14290# 500# 134 964766# 429# - 37 86 49 135 In x -47110# 300# 8136# 2# B- 13522# 300# 134 949425# 322# - 35 85 50 135 Sn x -60632.252 3.074 8230.6877 0.0228 B- 9058.0800 4.0522 134 934908.603 3.300 - 33 84 51 135 Sb -69690.332 2.640 8291.9894 0.0196 B- 8038.4581 3.1524 134 925184.354 2.834 - 31 83 52 135 Te -77728.790 1.722 8345.7384 0.0128 B- 6050.3894 2.6850 134 916554.715 1.848 - 29 82 53 135 I -83779.180 2.060 8384.7609 0.0153 B- 2634.1851 3.8284 134 910059.355 2.211 - 27 81 54 135 Xe -86413.365 3.668 8398.4783 0.0272 B- 1168.5917 3.6623 134 907231.441 3.938 - 25 80 55 135 Cs -87581.956 0.364 8401.3393 0.0027 B- 268.6983 0.2862 134 905976.907 0.390 - 23 79 56 135 Ba -87850.655 0.245 8397.5345 0.0018 B- -1207.1973 9.4299 134 905688.447 0.263 - 21 78 57 135 La -86643.458 9.432 8382.7972 0.0699 B- -2027.1499 4.6101 134 906984.427 10.126 - 19 77 58 135 Ce -84616.308 10.266 8361.9861 0.0760 B- -3680.4357 15.6540 134 909160.662 11.021 - 17 76 59 135 Pr x -80935.872 11.817 8328.9284 0.0875 B- -4722.2522 22.4837 134 913111.772 12.686 - 15 75 60 135 Nd x -76213.620 19.128 8288.1536 0.1417 B- -6151.2907 85.0809 134 918181.318 20.534 - 13 74 61 135 Pm x -70062.329 82.903 8236.7933 0.6141 B- -7205.1069 175.4501 134 924785.000 89.000 - 11 73 62 135 Sm x -62857.222 154.628 8177.6270 1.1454 B- -8709# 249# 134 932520.000 166.000 - 9 72 63 135 Eu x -54148# 196# 8107# 1# B- -9898# 445# 134 941870# 210# - 7 71 64 135 Gd x -44250# 400# 8028# 3# B- -11197# 565# 134 952496# 429# - 5 70 65 135 Tb -p -33053# 400# 7939# 3# B- * 134 964516# 429# -0 38 87 49 136 In x -40970# 300# 8091# 2# B- 15200# 361# 135 956017# 322# - 36 86 50 136 Sn x -56170# 200# 8197# 1# B- 8337# 200# 135 939699# 215# - 34 85 51 136 Sb -64506.890 5.830 8252.2533 0.0429 B- 9918.3897 6.2599 135 930749.009 6.258 - 32 84 52 136 Te -74425.279 2.281 8319.4301 0.0168 B- 5119.9455 14.1880 135 920101.180 2.448 - 30 83 53 136 I -79545.225 14.188 8351.3242 0.1043 B- 6883.9455 14.1880 135 914604.693 15.231 - 28 82 54 136 Xe -86429.170 0.007 8396.1889 0.0003 B- -90.3151 1.8730 135 907214.474 0.007 - 26 81 55 136 Cs + -86338.855 1.873 8389.7723 0.0138 B- 2548.2241 1.8570 135 907311.431 2.010 - 24 80 56 136 Ba -88887.079 0.245 8402.7566 0.0018 B- -2849.5915 53.1715 135 904575.800 0.262 - 22 79 57 136 La x -86037.488 53.171 8376.0512 0.3910 B- 471.0621 53.1720 135 907634.962 57.081 - 20 78 58 136 Ce -86508.550 0.324 8373.7624 0.0024 B- -5168.1290 11.4561 135 907129.256 0.348 - 18 77 59 136 Pr -81340.421 11.455 8330.0089 0.0842 B- -2141.1234 16.4578 135 912677.470 12.296 - 16 76 60 136 Nd x -79199.297 11.817 8308.5127 0.0869 B- -8029.3747 70.0764 135 914976.061 12.686 - 14 75 61 136 Pm x -71169.923 69.073 8243.7207 0.5079 B- -4359.0237 70.1942 135 923595.949 74.152 - 12 74 62 136 Sm x -66810.899 12.497 8205.9165 0.0919 B- -10567# 196# 135 928275.553 13.416 - 10 73 63 136 Eu x -56244# 196# 8122# 1# B- -7154# 357# 135 939620# 210# - 8 72 64 136 Gd x -49090# 298# 8064# 2# B- -13190# 582# 135 947300# 320# - 6 71 65 136 Tb x -35900# 500# 7961# 4# B- * 135 961460# 537# -0 39 88 49 137 In x -35830# 400# 8053# 3# B- 14320# 500# 136 961535# 429# - 37 87 50 137 Sn x -50150# 300# 8152# 2# B- 9911# 304# 136 946162# 322# - 35 86 51 137 Sb x -60060.392 52.164 8218.4764 0.3808 B- 9243.3698 52.2059 136 935522.519 56.000 - 33 85 52 137 Te -69303.762 2.100 8280.2357 0.0153 B- 7052.5063 8.6426 136 925599.354 2.254 - 31 84 53 137 I p-2n -76356.268 8.383 8326.0033 0.0612 B- 6027.1455 8.3841 136 918028.178 9.000 - 29 83 54 137 Xe -n -82383.414 0.104 8364.2865 0.0008 B- 4162.3582 0.3193 136 911557.771 0.111 - 27 82 55 137 Cs + -86545.772 0.302 8388.9581 0.0022 B- 1175.6285 0.1723 136 907089.296 0.324 - 25 81 56 137 Ba -87721.401 0.248 8391.8288 0.0018 B- -580.5356 1.6231 136 905827.207 0.266 - 23 80 57 137 La + -87140.865 1.640 8381.8807 0.0120 B- -1222.1000 1.6000 136 906450.438 1.760 - 21 79 58 137 Ce -85918.765 0.360 8367.2497 0.0026 B- -2716.9515 8.1328 136 907762.416 0.386 - 19 78 59 137 Pr -83201.814 8.135 8341.7074 0.0594 B- -3617.8447 14.2706 136 910679.183 8.733 - 17 77 60 137 Nd -79583.969 11.725 8309.5892 0.0856 B- -5511.1108 17.5366 136 914563.099 12.586 - 15 76 61 137 Pm x -74072.858 13.041 8263.6516 0.0952 B- -6081.2029 31.4460 136 920479.519 14.000 - 13 75 62 137 Sm -67991.655 28.614 8213.5527 0.2089 B- -7845.7518 28.9474 136 927007.959 30.718 - 11 74 63 137 Eu x -60145.904 4.378 8150.5738 0.0320 B- -8932# 298# 136 935430.719 4.700 - 9 73 64 137 Gd x -51214# 298# 8080# 2# B- -10246# 499# 136 945020# 320# - 7 72 65 137 Tb x -40967# 401# 7999# 3# B- * 136 956020# 430# -0 38 88 50 138 Sn x -45510# 400# 8118# 3# B- 9140# 500# 137 951143# 429# - 36 87 51 138 Sb x -54650# 300# 8178# 2# B- 11046# 300# 137 941331# 322# - 34 86 52 138 Te -65695.995 3.787 8252.5786 0.0274 B- 6283.9149 7.0625 137 929472.452 4.065 - 32 85 53 138 I x -71979.910 5.962 8292.4450 0.0432 B- 7992.3346 6.5881 137 922726.392 6.400 - 30 84 54 138 Xe -79972.244 2.804 8344.6913 0.0203 B- 2914.7839 9.5780 137 914146.268 3.010 - 28 83 55 138 Cs -82887.028 9.158 8360.1437 0.0664 B- 5374.7776 9.1584 137 911017.119 9.831 - 26 82 56 138 Ba -88261.806 0.249 8393.4222 0.0018 B- -1748.3977 0.3384 137 905247.059 0.267 - 24 81 57 138 La -86513.408 0.416 8375.0835 0.0030 B- 1052.4585 0.4018 137 907124.041 0.446 - 22 80 58 138 Ce -87565.867 0.499 8377.0408 0.0036 B- -4437.0000 10.0000 137 905994.180 0.536 - 20 79 59 138 Pr - -83128.867 10.012 8339.2195 0.0726 B- -1111.6847 15.3256 137 910757.495 10.748 - 18 78 60 138 Nd -82017.182 11.603 8325.4946 0.0841 B- -7102.8119 16.0995 137 911950.938 12.456 - 16 77 61 138 Pm -74914.370 11.603 8268.3558 0.0841 B- -3416.5976 16.5613 137 919576.119 12.456 - 14 76 62 138 Sm x -71497.772 11.817 8237.9286 0.0856 B- -9748.0968 30.3408 137 923243.988 12.686 - 12 75 63 138 Eu x -61749.676 27.945 8161.6211 0.2025 B- -6090# 202# 137 933709.000 30.000 - 10 74 64 138 Gd x -55660# 200# 8112# 1# B- -12059# 361# 137 940247# 215# - 8 73 65 138 Tb x -43600# 300# 8019# 2# B- -8669# 586# 137 953193# 322# - 6 72 66 138 Dy x -34931# 503# 7950# 4# B- * 137 962500# 540# -0 39 89 50 139 Sn x -39310# 400# 8073# 3# B- 10740# 565# 138 957799# 429# - 37 88 51 139 Sb x -50050# 400# 8144# 3# B- 10155# 400# 138 946269# 429# - 35 87 52 139 Te x -60205.080 3.540 8211.7716 0.0255 B- 8265.8835 5.3454 138 935367.191 3.800 - 33 86 53 139 I x -68470.964 4.005 8265.6100 0.0288 B- 7173.6224 4.5424 138 926493.400 4.300 - 31 85 54 139 Xe x -75644.586 2.142 8311.5904 0.0154 B- 5056.5023 3.7960 138 918792.200 2.300 - 29 84 55 139 Cs + -80701.088 3.134 8342.3397 0.0225 B- 4212.8293 3.1235 138 913363.822 3.364 - 27 83 56 139 Ba -n -84913.918 0.253 8367.0194 0.0018 B- 2308.4632 0.6571 138 908841.164 0.271 - 25 82 57 139 La -87222.381 0.607 8377.9987 0.0044 B- -264.6396 1.9989 138 906362.927 0.651 - 23 81 58 139 Ce -86957.741 2.089 8370.4664 0.0150 B- -2129.0890 2.9962 138 906647.029 2.242 - 21 80 59 139 Pr -84828.652 3.649 8349.5208 0.0263 B- -2811.7226 27.6166 138 908932.700 3.917 - 19 79 60 139 Nd -82016.930 27.521 8323.6642 0.1980 B- -4515.9014 25.8700 138 911951.208 29.545 - 17 78 61 139 Pm -77501.028 13.588 8285.5473 0.0978 B- -5120.7993 17.4098 138 916799.228 14.587 - 15 77 62 139 Sm x -72380.229 10.884 8243.0786 0.0783 B- -6982.1777 17.0705 138 922296.631 11.684 - 13 76 63 139 Eu x -65398.051 13.151 8187.2187 0.0946 B- -7767# 196# 138 929792.307 14.117 - 11 75 64 139 Gd x -57632# 196# 8126# 1# B- -9501# 357# 138 938130# 210# - 9 74 65 139 Tb x -48130# 298# 8052# 2# B- -10430# 582# 138 948330# 320# - 7 73 66 139 Dy x -37700# 500# 7971# 4# B- * 138 959527# 537# -0 40 90 50 140 Sn x -34490# 300# 8038# 2# B- 9900# 671# 139 962973# 322# - 38 89 51 140 Sb x -44390# 600# 8103# 4# B- 11977# 600# 139 952345# 644# - 36 88 52 140 Te -56367.449 14.377 8183.3567 0.1027 B- 7238.7734 18.7976 139 939487.057 15.434 - 34 87 53 140 I x -63606.223 12.109 8229.4740 0.0865 B- 9380.2388 12.3313 139 931715.914 13.000 - 32 86 54 140 Xe x -72986.461 2.329 8290.8875 0.0166 B- 4063.2768 8.5232 139 921645.814 2.500 - 30 85 55 140 Cs -77049.738 8.199 8314.3227 0.0586 B- 6218.1669 9.8671 139 917283.707 8.801 - 28 84 56 140 Ba -83267.905 7.900 8353.1500 0.0564 B- 1044.1542 7.9051 139 910608.231 8.480 - 26 83 57 140 La -84312.059 0.607 8355.0201 0.0043 B- 3762.1676 1.3364 139 909487.285 0.651 - 24 82 58 140 Ce -88074.227 1.313 8376.3045 0.0094 B- -3388.0000 6.0000 139 905448.433 1.409 - 22 81 59 140 Pr - -84686.227 6.142 8346.5163 0.0439 B- -428.9806 6.9536 139 909085.600 6.593 - 20 80 60 140 Nd x -84257.246 3.260 8337.8640 0.0233 B- -6045.2000 24.0000 139 909546.130 3.500 - 18 79 61 140 Pm - -78212.046 24.220 8289.0958 0.1730 B- -2756.1010 27.2546 139 916035.918 26.001 - 16 78 62 140 Sm x -75455.945 12.497 8263.8211 0.0893 B- -8470.0000 50.0000 139 918994.714 13.416 - 14 77 63 140 Eu - -66985.945 51.538 8197.7330 0.3681 B- -5203.6675 58.6268 139 928087.633 55.328 - 12 76 64 140 Gd x -61782.278 27.945 8154.9757 0.1996 B- -11300.0000 800.0000 139 933674.000 30.000 - 10 75 65 140 Tb - -50482.278 800.488 8068.6732 5.7178 B- -7652# 895# 139 945805.048 859.359 - 8 74 66 140 Dy x -42830# 401# 8008# 3# B- -13513# 641# 139 954020# 430# - 6 73 67 140 Ho -p -29317# 500# 7906# 4# B- * 139 968526# 537# -0 39 90 51 141 Sb x -39540# 500# 8069# 4# B- 11129# 640# 140 957552# 537# - 37 89 52 141 Te x -50670# 400# 8142# 3# B- 9257# 400# 140 945604# 429# - 35 88 53 141 I x -59926.666 15.835 8202.2562 0.1123 B- 8270.6430 16.0965 140 935666.081 17.000 - 33 87 54 141 Xe x -68197.309 2.888 8255.3647 0.0205 B- 6280.0423 9.6378 140 926787.181 3.100 - 31 86 55 141 Cs -74477.351 9.195 8294.3554 0.0652 B- 5255.1410 9.6174 140 920045.279 9.871 - 29 85 56 141 Ba -79732.492 5.318 8326.0774 0.0377 B- 3197.3515 6.5510 140 914403.653 5.709 - 27 84 57 141 La -82929.844 4.127 8343.2050 0.0293 B- 2501.2141 3.9279 140 910971.155 4.430 - 25 83 58 141 Ce -85431.058 1.315 8355.3956 0.0093 B- 583.4758 1.1784 140 908285.991 1.411 - 23 82 59 141 Pr -86014.533 1.498 8353.9852 0.0106 B- -1823.0137 2.8090 140 907659.604 1.607 - 21 81 60 141 Nd - -84191.520 3.183 8335.5074 0.0226 B- -3668.5879 14.3304 140 909616.690 3.417 - 19 80 61 141 Pm x -80522.932 13.972 8303.9405 0.0991 B- -4588.9724 16.3730 140 913555.081 15.000 - 17 79 62 141 Sm -75933.959 8.535 8265.8460 0.0605 B- -6008.3127 14.2829 140 918481.545 9.162 - 15 78 63 141 Eu -69925.647 12.639 8217.6853 0.0896 B- -6701.4161 23.4562 140 924931.734 13.568 - 13 77 64 141 Gd x -63224.231 19.760 8164.6090 0.1401 B- -8683.3880 107.0975 140 932126.000 21.213 - 11 76 65 141 Tb x -54540.843 105.259 8097.4761 0.7465 B- -9158# 316# 140 941448.000 113.000 - 9 75 66 141 Dy x -45382# 298# 8027# 2# B- -11018# 499# 140 951280# 320# - 7 74 67 141 Ho -p -34364# 401# 7943# 3# B- * 140 963108# 430# -0 40 91 51 142 Sb x -33610# 300# 8027# 2# B- 12939# 583# 141 963918# 322# - 38 90 52 142 Te x -46550# 500# 8113# 4# B- 8253# 500# 141 950027# 537# - 36 89 53 142 I x -54802.969 4.937 8165.2517 0.0348 B- 10426.6792 5.6276 141 941166.595 5.300 - 34 88 54 142 Xe x -65229.648 2.701 8233.1695 0.0190 B- 5284.9078 7.5655 141 929973.095 2.900 - 32 87 55 142 Cs -70514.556 7.067 8264.8777 0.0498 B- 7327.7007 8.3627 141 924299.514 7.586 - 30 86 56 142 Ba -77842.257 5.920 8310.9718 0.0417 B- 2181.6932 8.3754 141 916432.904 6.355 - 28 85 57 142 La -80023.950 6.286 8320.8263 0.0443 B- 4508.9455 5.8446 141 914090.760 6.748 - 26 84 58 142 Ce -84532.896 2.443 8347.0700 0.0172 B- -746.5288 2.4868 141 909250.208 2.623 - 24 83 59 142 Pr -83786.367 1.498 8336.3032 0.0106 B- 2163.6885 1.3656 141 910051.640 1.607 - 22 82 60 142 Nd -85950.055 1.256 8346.0310 0.0088 B- -4808.5196 23.6216 141 907728.824 1.348 - 20 81 61 142 Pm -81141.536 23.596 8306.6587 0.1662 B- -2159.6062 23.6524 141 912890.982 25.330 - 18 80 62 142 Sm -78981.930 1.866 8285.9407 0.0131 B- -7673.0000 30.0000 141 915209.415 2.002 - 16 79 63 142 Eu - -71308.930 30.058 8226.3960 0.2117 B- -4349.4074 41.0414 141 923446.719 32.268 - 14 78 64 142 Gd x -66959.522 27.945 8190.2569 0.1968 B- -10400.0000 700.0000 141 928116.000 30.000 - 12 77 65 142 Tb - -56559.522 700.558 8111.5080 4.9335 B- -6440# 200# 141 939280.858 752.079 - 10 76 66 142 Dy - -50120# 729# 8061# 5# B- -12869# 831# 141 946194# 782# - 8 75 67 142 Ho x -37250# 401# 7965# 3# B- -9321# 641# 141 960010# 430# - 6 74 68 142 Er x -27930# 500# 7893# 4# B- * 141 970016# 537# -0 39 91 52 143 Te x -40530# 500# 8070# 3# B- 10259# 539# 142 956489# 537# - 37 90 53 143 I x -50790# 200# 8137# 1# B- 9413# 200# 142 945475# 215# - 35 89 54 143 Xe x -60202.882 4.657 8196.8855 0.0326 B- 7472.6365 8.8908 142 935369.550 5.000 - 33 88 55 143 Cs -67675.519 7.573 8243.6707 0.0530 B- 6261.6865 9.7303 142 927347.346 8.130 - 31 87 56 143 Ba -73937.205 6.756 8281.9878 0.0472 B- 4234.2623 9.9682 142 920625.149 7.253 - 29 86 57 143 La -78171.467 7.329 8306.1271 0.0513 B- 3434.9108 7.5812 142 916079.482 7.868 - 27 85 58 143 Ce -81606.378 2.442 8324.6765 0.0171 B- 1461.8214 1.8649 142 912391.953 2.621 - 25 84 59 143 Pr -83068.200 1.816 8329.4280 0.0127 B- 934.1107 1.3673 142 910822.624 1.949 - 23 83 60 143 Nd -84002.310 1.255 8330.4893 0.0088 B- -1041.6463 2.6830 142 909819.815 1.347 - 21 82 61 143 Pm -82960.664 2.944 8317.7341 0.0206 B- -3443.5291 3.5604 142 910938.068 3.160 - 19 81 62 143 Sm -79517.135 2.750 8288.1825 0.0192 B- -5275.8240 11.3245 142 914634.848 2.951 - 17 80 63 143 Eu x -74241.311 10.986 8245.8177 0.0768 B- -6010.0000 200.0000 142 920298.678 11.793 - 15 79 64 143 Gd - -68231.311 200.301 8198.3188 1.4007 B- -7812.1185 206.7497 142 926750.678 215.032 - 13 78 65 143 Tb x -60419.192 51.232 8138.2176 0.3583 B- -8250.2433 52.8659 142 935137.332 55.000 - 11 77 66 143 Dy x -52168.949 13.041 8075.0527 0.0912 B- -10121# 298# 142 943994.332 14.000 - 9 76 67 143 Ho x -42048# 298# 7999# 2# B- -10887# 499# 142 954860# 320# - 7 75 68 143 Er x -31160# 400# 7917# 3# B- * 142 966548# 429# -0 40 92 52 144 Te x -36220# 300# 8040# 2# B- 9110# 500# 143 961116# 322# - 38 91 53 144 I x -45330# 400# 8098# 3# B- 11542# 400# 143 951336# 429# - 36 90 54 144 Xe x -56872.301 5.310 8172.8845 0.0369 B- 6399.0606 20.8203 143 938945.076 5.700 - 34 89 55 144 Cs -63271.362 20.132 8211.8894 0.1398 B- 8495.7679 20.4163 143 932075.402 21.612 - 32 88 56 144 Ba -71767.130 7.136 8265.4549 0.0496 B- 3082.5300 14.7744 143 922954.821 7.661 - 30 87 57 144 La x -74849.660 12.937 8281.4283 0.0898 B- 5582.2823 13.2432 143 919645.589 13.888 - 28 86 58 144 Ce + -80431.942 2.833 8314.7612 0.0197 B- 318.6462 0.8321 143 913652.763 3.041 - 26 85 59 144 Pr + -80750.588 2.708 8311.5411 0.0188 B- 2997.4400 2.4000 143 913310.682 2.907 - 24 84 60 144 Nd -83748.028 1.255 8326.9237 0.0087 B- -2331.9117 2.6464 143 910092.798 1.346 - 22 83 61 144 Pm -81416.116 2.912 8305.2969 0.0202 B- 549.5096 2.6679 143 912596.208 3.126 - 20 82 62 144 Sm -81965.626 1.459 8303.6800 0.0101 B- -6346.4515 10.8092 143 912006.285 1.566 - 18 81 63 144 Eu -75619.175 10.787 8254.1744 0.0749 B- -3859.6633 29.9546 143 918819.481 11.580 - 16 80 64 144 Gd x -71759.511 27.945 8221.9382 0.1941 B- -9391.3235 39.5199 143 922963.000 30.000 - 14 79 65 144 Tb x -62368.188 27.945 8151.2877 0.1941 B- -5798.0965 28.8506 143 933045.000 30.000 - 12 78 66 144 Dy x -56570.091 7.173 8105.5902 0.0498 B- -11960.5706 11.1039 143 939269.512 7.700 - 10 77 67 144 Ho x -44609.521 8.477 8017.0977 0.0589 B- -8002# 196# 143 952109.712 9.100 - 8 76 68 144 Er x -36608# 196# 7956# 1# B- -14448# 445# 143 960700# 210# - 6 75 69 144 Tm -p -22159# 400# 7850# 3# B- * 143 976211# 429# -0 41 93 52 145 Te x -30010# 300# 7998# 2# B- 11120# 583# 144 967783# 322# - 39 92 53 145 I x -41130# 500# 8069# 3# B- 10363# 500# 144 955845# 537# - 37 91 54 145 Xe x -51493.337 11.178 8135.0877 0.0771 B- 8561.0867 14.3929 144 944719.631 12.000 - 35 90 55 145 Cs -60054.424 9.067 8188.7342 0.0625 B- 7461.7591 12.4121 144 935528.927 9.733 - 33 89 56 145 Ba x -67516.183 8.477 8234.7991 0.0585 B- 5319.1425 14.9122 144 927518.400 9.100 - 31 88 57 145 La -72835.325 12.269 8266.0873 0.0846 B- 4231.7331 35.2977 144 921808.065 13.170 - 29 87 58 145 Ce -77067.059 33.900 8289.8762 0.2338 B- 2558.9318 33.6347 144 917265.113 36.393 - 27 86 59 145 Pr -79625.990 7.149 8302.1285 0.0493 B- 1806.0140 7.0370 144 914517.987 7.674 - 25 85 60 145 Nd -81432.004 1.271 8309.1883 0.0088 B- -164.4982 2.5361 144 912579.151 1.364 - 23 84 61 145 Pm -81267.506 2.805 8302.6583 0.0193 B- -616.0990 2.5390 144 912755.748 3.011 - 21 83 62 145 Sm -80651.407 1.485 8293.0139 0.0102 B- -2659.8832 2.7224 144 913417.157 1.594 - 19 82 63 145 Eu -77991.524 3.060 8269.2744 0.0211 B- -5064.8984 19.9521 144 916272.659 3.285 - 17 81 64 145 Gd -72926.626 19.716 8228.9485 0.1360 B- -6526.9329 109.7144 144 921710.051 21.165 - 15 80 65 145 Tb -66399.693 110.896 8178.5397 0.7648 B- -8157.0853 111.0872 144 928717.001 119.051 - 13 79 66 145 Dy x -58242.607 6.520 8116.8884 0.0450 B- -9122.4943 9.9019 144 937473.992 7.000 - 11 78 67 145 Ho x -49120.113 7.452 8048.5792 0.0514 B- -9880# 200# 144 947267.392 8.000 - 9 77 68 145 Er x -39240# 200# 7975# 1# B- -11657# 280# 144 957874# 215# - 7 76 69 145 Tm -p -27583# 196# 7889# 1# B- * 144 970389# 210# -0 40 93 53 146 I x -35540# 300# 8031# 2# B- 12415# 301# 145 961846# 322# - 38 92 54 146 Xe x -47954.950 24.219 8110.4154 0.1659 B- 7355.4298 24.3911 145 948518.245 26.000 - 36 91 55 146 Cs x -55310.380 2.893 8155.4365 0.0198 B- 9555.8882 3.3918 145 940621.867 3.106 - 34 90 56 146 Ba x -64866.269 1.770 8215.5293 0.0121 B- 4354.9052 2.4366 145 930363.200 1.900 - 32 89 57 146 La -69221.174 1.675 8239.9988 0.0115 B- 6404.6947 14.7146 145 925688.017 1.797 - 30 88 58 146 Ce -75625.868 14.665 8278.5081 0.1004 B- 1047.6178 32.4842 145 918812.294 15.743 - 28 87 59 146 Pr -76673.486 34.356 8280.3250 0.2353 B- 4252.4300 34.3686 145 917687.630 36.882 - 26 86 60 146 Nd -80925.916 1.273 8304.0927 0.0087 B- -1471.5560 4.1194 145 913122.459 1.366 - 24 85 61 146 Pm + -79454.360 4.275 8288.6550 0.0293 B- 1542.0000 3.0000 145 914702.240 4.589 - 22 84 62 146 Sm -80996.360 3.045 8293.8581 0.0209 B- -3878.7573 5.8685 145 913046.835 3.269 - 20 83 63 146 Eu -77117.603 6.009 8261.9327 0.0412 B- -1031.7798 7.0750 145 917210.852 6.451 - 18 82 64 146 Gd -76085.823 4.076 8249.5072 0.0279 B- -8322.1791 44.7488 145 918318.513 4.376 - 16 81 65 146 Tb -67763.644 44.860 8187.1474 0.3073 B- -5208.7165 45.1580 145 927252.739 48.159 - 14 80 66 146 Dy -62554.928 6.695 8146.1128 0.0459 B- -11316.7007 9.3917 145 932844.526 7.187 - 12 79 67 146 Ho -51238.227 6.587 8063.2426 0.0451 B- -6916.2074 9.3987 145 944993.503 7.071 - 10 78 68 146 Er -44322.019 6.705 8010.5127 0.0459 B- -13267# 200# 145 952418.357 7.197 - 8 77 69 146 Tm -p -31055# 200# 7914# 1# B- * 145 966661# 215# -0 41 94 53 147 I x -31200# 300# 8001# 2# B- 11199# 361# 146 966505# 322# - 39 93 54 147 Xe x -42400# 200# 8072# 1# B- 9520# 200# 146 954482# 215# - 37 92 55 147 Cs x -51920.073 8.383 8131.8010 0.0570 B- 8343.9631 21.4535 146 944261.512 9.000 - 35 91 56 147 Ba x -60264.036 19.748 8183.2405 0.1343 B- 6414.3615 22.4660 146 935303.900 21.200 - 33 90 57 147 La x -66678.397 10.712 8221.5536 0.0729 B- 5335.5046 13.7248 146 928417.800 11.500 - 31 89 58 147 Ce -72013.902 8.580 8252.5274 0.0584 B- 3430.1913 15.5317 146 922689.900 9.211 - 29 88 59 147 Pr -75444.093 15.855 8270.5400 0.1079 B- 2702.7013 15.8571 146 919007.438 17.020 - 27 87 60 147 Nd -78146.794 1.275 8283.6036 0.0087 B- 895.1896 0.5664 146 916105.969 1.368 - 25 86 61 147 Pm -79041.984 1.288 8284.3712 0.0088 B- 224.0638 0.2940 146 915144.944 1.382 - 23 85 62 147 Sm -79266.048 1.262 8280.5734 0.0086 B- -1721.4367 2.2832 146 914904.401 1.354 - 21 84 63 147 Eu -77544.611 2.569 8263.5409 0.0175 B- -2187.6833 2.5273 146 916752.440 2.758 - 19 83 64 147 Gd -75356.928 1.887 8243.3366 0.0128 B- -4614.2543 8.1414 146 919101.014 2.025 - 17 82 65 147 Tb -70742.674 8.096 8206.6250 0.0551 B- -6546.6266 11.9939 146 924054.620 8.691 - 15 81 66 147 Dy x -64196.047 8.849 8156.7680 0.0602 B- -8438.9460 10.1644 146 931082.712 9.500 - 13 80 67 147 Ho -55757.101 5.001 8094.0381 0.0340 B- -9149.2869 38.5173 146 940142.293 5.368 - 11 79 68 147 Er x -46607.814 38.191 8026.4760 0.2598 B- -10633.4071 38.7987 146 949964.456 41.000 - 9 78 69 147 Tm -35974.407 6.839 7948.8178 0.0465 B- * 146 961379.887 7.341 -0 40 94 54 148 Xe x -38650# 300# 8047# 2# B- 8261# 300# 147 958508# 322# - 38 93 55 148 Cs x -46910.950 13.041 8097.5469 0.0881 B- 10633.9614 13.1258 147 949639.026 14.000 - 36 92 56 148 Ba x -57544.911 1.490 8164.1118 0.0101 B- 5163.8307 19.5252 147 938223.000 1.600 - 34 91 57 148 La x -62708.742 19.468 8193.7165 0.1315 B- 7689.6824 22.4573 147 932679.400 20.900 - 32 90 58 148 Ce -70398.424 11.195 8240.3876 0.0756 B- 2137.0282 12.5663 147 924424.186 12.017 - 30 89 59 148 Pr -72535.452 15.041 8249.5409 0.1016 B- 4872.6133 15.0858 147 922129.992 16.147 - 28 88 60 148 Nd -77408.066 2.053 8277.1778 0.0139 B- -542.1891 5.8755 147 916899.027 2.203 - 26 87 61 148 Pm +p -76865.877 5.690 8268.2283 0.0384 B- 2470.1898 5.6409 147 917481.091 6.108 - 24 86 62 148 Sm -79336.067 1.246 8279.6326 0.0084 B- -3038.5844 9.9657 147 914829.233 1.337 - 22 85 63 148 Eu -76297.482 9.961 8253.8155 0.0673 B- -28.0630 9.9633 147 918091.288 10.693 - 20 84 64 148 Gd -76269.419 1.460 8248.3398 0.0099 B- -5732.4723 12.5208 147 918121.414 1.566 - 18 83 65 148 Tb -70536.947 12.463 8204.3207 0.0842 B- -2677.5501 9.5961 147 924275.476 13.379 - 16 82 66 148 Dy -67859.397 8.724 8180.9430 0.0589 B- -9868.2304 84.2872 147 927149.944 9.365 - 14 81 67 148 Ho x -57991.166 83.834 8108.9797 0.5664 B- -6512.1694 84.4583 147 937743.925 90.000 - 12 80 68 148 Er x -51478.997 10.246 8059.6924 0.0692 B- -12713.9630 14.4906 147 944735.026 11.000 - 10 79 69 148 Tm x -38765.034 10.246 7968.5011 0.0692 B- -8535# 400# 147 958384.026 11.000 - 8 78 70 148 Yb x -30230# 400# 7906# 3# B- * 147 967547# 429# -0 41 95 54 149 Xe x -33000# 300# 8009# 2# B- 10300# 500# 148 964573# 322# - 39 94 55 149 Cs x -43300# 400# 8073# 3# B- 9531# 400# 148 953516# 429# - 37 93 56 149 Ba x -52830.620 2.515 8131.8495 0.0169 B- 7389.3010 200.2781 148 943284.000 2.700 - 35 92 57 149 La + -60219.921 200.262 8176.1915 1.3440 B- 6450.0000 200.0000 148 935351.259 214.990 - 33 91 58 149 Ce x -66669.921 10.246 8214.2294 0.0688 B- 4369.4525 14.2296 148 928426.900 11.000 - 31 90 59 149 Pr x -71039.373 9.874 8238.3040 0.0663 B- 3336.1617 10.0853 148 923736.100 10.600 - 29 89 60 149 Nd -n -74375.535 2.054 8255.4437 0.0138 B- 1688.8697 2.4588 148 920154.583 2.205 - 27 88 61 149 Pm -76064.404 2.184 8261.5277 0.0147 B- 1071.4936 1.8747 148 918341.507 2.344 - 25 87 62 149 Sm -77135.898 1.157 8263.4683 0.0078 B- -694.5812 3.7881 148 917191.211 1.241 - 23 86 63 149 Eu -76441.317 3.903 8253.5560 0.0262 B- -1314.1437 4.1361 148 917936.875 4.190 - 21 85 64 149 Gd -75127.173 3.310 8239.4856 0.0222 B- -3638.5336 4.3388 148 919347.666 3.553 - 19 84 65 149 Tb -71488.639 3.629 8209.8153 0.0244 B- -3794.6493 9.1335 148 923253.792 3.895 - 17 83 66 149 Dy -67693.990 9.183 8179.0972 0.0616 B- -6048.1366 12.7928 148 927327.516 9.858 - 15 82 67 149 Ho -61645.854 11.985 8133.2550 0.0804 B- -7904.2328 30.4066 148 933820.457 12.866 - 13 81 68 149 Er x -53741.621 27.945 8074.9558 0.1875 B- -9801# 202# 148 942306.000 30.000 - 11 80 69 149 Tm x -43940# 200# 8004# 1# B- -10611# 361# 148 952828# 215# - 9 79 70 149 Yb x -33330# 300# 7927# 2# B- * 148 964219# 322# -0 42 96 54 150 Xe x -28990# 300# 7983# 2# B- 9180# 500# 149 968878# 322# - 40 95 55 150 Cs x -38170# 400# 8039# 3# B- 11720# 400# 149 959023# 429# - 38 94 56 150 Ba x -49889.799 5.682 8111.8405 0.0379 B- 6421.3477 6.2138 149 946441.100 6.100 - 36 93 57 150 La x -56311.147 2.515 8149.4339 0.0168 B- 8535.7155 11.9641 149 939547.500 2.700 - 34 92 58 150 Ce -64846.863 11.697 8201.1230 0.0780 B- 3453.6462 14.2913 149 930384.032 12.556 - 32 91 59 150 Pr -68300.509 9.015 8218.9316 0.0601 B- 5379.4422 9.0682 149 926676.391 9.677 - 30 90 60 150 Nd -73679.951 1.129 8249.5789 0.0075 B- -82.6155 20.0010 149 920901.322 1.211 - 28 89 61 150 Pm + -73597.336 20.031 8243.8125 0.1335 B- 3454.0000 20.0000 149 920990.014 21.504 - 26 88 62 150 Sm -77051.336 1.112 8261.6235 0.0074 B- -2258.9662 6.1803 149 917281.993 1.193 - 24 87 63 150 Eu -74792.369 6.231 8241.3481 0.0415 B- 971.6815 3.5428 149 919707.092 6.688 - 22 86 64 150 Gd -75764.051 6.055 8242.6103 0.0404 B- -4658.2621 8.3784 149 918663.949 6.500 - 20 85 65 150 Tb -71105.789 7.371 8206.3396 0.0491 B- -1796.1707 8.3886 149 923664.799 7.912 - 18 84 66 150 Dy -69309.618 4.319 8189.1495 0.0288 B- -7363.7264 14.4629 149 925593.068 4.636 - 16 83 67 150 Ho -61945.892 14.168 8134.8423 0.0945 B- -4114.5689 13.5910 149 933498.353 15.209 - 14 82 68 150 Er -57831.323 17.194 8102.1962 0.1146 B- -11340# 196# 149 937915.524 18.458 - 12 81 69 150 Tm x -46491# 196# 8021# 1# B- -7661# 358# 149 950090# 210# - 10 80 70 150 Yb x -38830# 300# 7965# 2# B- -14059# 424# 149 958314# 322# - 8 79 71 150 Lu -p -24771# 300# 7866# 2# B- * 149 973407# 322# -0 41 96 55 151 Cs x -34280# 500# 8013# 3# B- 10660# 640# 150 963199# 537# - 39 95 56 151 Ba x -44940# 400# 8079# 3# B- 8370# 591# 150 951755# 429# - 37 94 57 151 La x -53310.339 435.473 8129.0436 2.8839 B- 7914.7191 435.8330 150 942769.000 467.500 - 35 93 58 151 Ce x -61225.058 17.698 8176.2779 0.1172 B- 5554.6233 21.1885 150 934272.200 19.000 - 33 92 59 151 Pr -66779.681 11.650 8207.8824 0.0772 B- 4163.5021 11.6789 150 928309.066 12.506 - 31 91 60 151 Nd -70943.183 1.133 8230.2741 0.0075 B- 2443.0767 4.4734 150 923839.363 1.215 - 29 90 61 151 Pm -73386.260 4.611 8241.2723 0.0305 B- 1190.2198 4.4757 150 921216.613 4.949 - 27 89 62 151 Sm -74576.480 1.110 8243.9735 0.0074 B- 76.6182 0.5375 150 919938.859 1.191 - 25 88 63 151 Eu -74653.098 1.166 8239.2998 0.0077 B- -464.1779 2.7791 150 919856.606 1.251 - 23 87 64 151 Gd -74188.920 2.993 8231.0446 0.0198 B- -2565.3796 3.7615 150 920354.922 3.212 - 21 86 65 151 Tb -71623.541 4.094 8208.8743 0.0271 B- -2871.1525 4.9455 150 923108.970 4.395 - 19 85 66 151 Dy -a -68752.388 3.247 8184.6789 0.0215 B- -5129.6421 8.7507 150 926191.279 3.486 - 17 84 67 151 Ho -a -63622.746 8.298 8145.5267 0.0550 B- -5356.4558 18.4420 150 931698.176 8.908 - 15 83 68 151 Er x -58266.290 16.470 8104.8723 0.1091 B- -7494.6768 25.4292 150 937448.567 17.681 - 13 82 69 151 Tm -50771.613 19.375 8050.0576 0.1283 B- -9229.2615 300.1329 150 945494.433 20.799 - 11 81 70 151 Yb ep -41542.352 300.492 7983.7556 1.9900 B- -11242# 425# 150 955402.453 322.591 - 9 80 71 151 Lu -p -30300# 300# 7904# 2# B- * 150 967471# 322# -0 42 97 55 152 Cs x -29130# 500# 7980# 3# B- 12480# 640# 151 968728# 537# - 40 96 56 152 Ba x -41610# 400# 8057# 3# B- 7680# 500# 151 955330# 429# - 38 95 57 152 La x -49290# 300# 8102# 2# B- 9690# 361# 151 947085# 322# - 36 94 58 152 Ce x -58980# 200# 8161# 1# B- 4778# 201# 151 936682# 215# - 34 93 59 152 Pr x -63758.070 18.537 8187.1049 0.1220 B- 6391.5934 30.7035 151 931552.900 19.900 - 32 92 60 152 Nd -70149.663 24.476 8224.0078 0.1610 B- 1104.8050 18.5011 151 924691.242 26.276 - 30 91 61 152 Pm -71254.468 25.904 8226.1293 0.1704 B- 3508.5089 25.8859 151 923505.185 27.809 - 28 90 62 152 Sm -74762.977 1.016 8244.0645 0.0067 B- -1874.4774 0.6857 151 919738.646 1.090 - 26 89 63 152 Eu -72888.500 1.166 8226.5854 0.0077 B- 1818.8037 0.7002 151 921750.980 1.252 - 24 88 64 152 Gd -74707.304 1.007 8233.4042 0.0066 B- -3990.0000 40.0000 151 919798.414 1.081 - 22 87 65 152 Tb - -70717.304 40.013 8202.0072 0.2632 B- -599.3405 40.2575 151 924081.855 42.955 - 20 86 66 152 Dy -a -70117.963 4.593 8192.9171 0.0302 B- -6513.3275 13.3176 151 924725.274 4.930 - 18 85 67 152 Ho -63604.636 12.528 8144.9193 0.0824 B- -3104.4174 9.8150 151 931717.618 13.449 - 16 84 68 152 Er -60500.218 8.830 8119.3485 0.0581 B- -8779.9397 54.7434 151 935050.347 9.478 - 14 83 69 152 Tm -51720.279 54.027 8056.4387 0.3554 B- -5449.8923 139.6200 151 944476.000 58.000 - 12 82 70 152 Yb -46270.386 149.708 8015.4371 0.9849 B- -12848# 246# 151 950326.699 160.718 - 10 81 71 152 Lu x -33422# 196# 7926# 1# B- * 151 964120# 210# -0 41 97 56 153 Ba x -36470# 400# 8023# 3# B- 9590# 500# 152 960848# 429# - 39 96 57 153 La x -46060# 300# 8081# 2# B- 8850# 361# 152 950553# 322# - 37 95 58 153 Ce x -54910# 200# 8134# 1# B- 6659# 201# 152 941052# 215# - 35 94 59 153 Pr -61568.490 11.882 8172.0371 0.0777 B- 5761.8901 12.1896 152 933903.511 12.755 - 33 93 60 153 Nd -67330.380 2.747 8204.5832 0.0180 B- 3317.6236 9.3521 152 927717.868 2.949 - 31 92 61 153 Pm -70648.003 9.063 8221.1536 0.0592 B- 1912.0559 9.0829 152 924156.252 9.729 - 29 91 62 153 Sm -n -72560.059 1.025 8228.5373 0.0067 B- 807.4073 0.7063 152 922103.576 1.100 - 27 90 63 153 Eu -73367.466 1.171 8228.7011 0.0077 B- -484.5225 0.7150 152 921236.789 1.257 - 25 89 64 153 Gd -72882.944 1.002 8220.4209 0.0066 B- -1569.3340 3.8444 152 921756.945 1.075 - 23 88 65 153 Tb -71313.610 3.947 8205.0504 0.0258 B- -2170.4134 1.9335 152 923441.694 4.237 - 21 87 66 153 Dy -69143.197 4.001 8185.7514 0.0262 B- -4131.1229 6.1571 152 925771.729 4.295 - 19 86 67 153 Ho -a -65012.074 5.066 8153.6372 0.0331 B- -4545.3918 9.8899 152 930206.671 5.438 - 17 85 68 153 Er -60466.682 9.285 8118.8154 0.0607 B- -6494.0723 12.8812 152 935086.350 9.967 - 15 84 69 153 Tm -53972.610 11.979 8071.2571 0.0783 B- -6813# 201# 152 942058.023 12.860 - 13 83 70 153 Yb x -47160# 200# 8022# 1# B- -8784# 250# 152 949372# 215# - 11 82 71 153 Lu +a -38375.462 150.017 7959.0882 0.9805 B- -11075# 335# 152 958802.248 161.050 - 9 81 72 153 Hf x -27300# 300# 7882# 2# B- * 152 970692# 322# -0 42 98 56 154 Ba x -32920# 500# 8001# 3# B- 8610# 583# 153 964659# 537# - 40 97 57 154 La x -41530# 300# 8051# 2# B- 10690# 361# 153 955416# 322# - 38 96 58 154 Ce x -52220# 200# 8116# 1# B- 5640# 224# 153 943940# 215# - 36 95 59 154 Pr + -57859.602 100.005 8147.2994 0.6494 B- 7720.0000 100.0000 153 937885.165 107.360 - 34 94 60 154 Nd x -65579.602 1.025 8192.3491 0.0067 B- 2687.0000 25.0000 153 929597.404 1.100 - 32 93 61 154 Pm - -68266.602 25.021 8204.7170 0.1625 B- 4188.9614 25.0550 153 926712.791 26.861 - 30 92 62 154 Sm -72455.564 1.305 8226.8379 0.0085 B- -717.1969 1.1019 153 922215.756 1.400 - 28 91 63 154 Eu -71738.367 1.188 8217.1006 0.0077 B- 1967.9913 0.7535 153 922985.699 1.275 - 26 90 64 154 Gd -73706.358 0.994 8224.7996 0.0065 B- -3549.6514 45.2983 153 920872.974 1.066 - 24 89 65 154 Tb - -70156.707 45.309 8196.6697 0.2942 B- 237.3080 45.9008 153 924683.681 48.641 - 22 88 66 154 Dy -70394.015 7.431 8193.1305 0.0483 B- -5754.6363 10.1785 153 924428.920 7.977 - 20 87 67 154 Ho -a -64639.378 8.216 8150.6825 0.0534 B- -2034.4045 9.4621 153 930606.776 8.820 - 18 86 68 154 Er -62604.974 4.961 8132.3919 0.0322 B- -8177.8316 14.9113 153 932790.799 5.325 - 16 85 69 154 Tm -a -54427.142 14.412 8074.2090 0.0936 B- -4495.0495 13.9528 153 941570.062 15.471 - 14 84 70 154 Yb -49932.093 17.281 8039.9402 0.1122 B- -10265# 201# 153 946395.696 18.551 - 12 83 71 154 Lu +a -39667# 201# 7968# 1# B- -6937# 361# 153 957416# 216# - 10 82 72 154 Hf x -32730# 300# 7918# 2# B- * 153 964863# 322# -0 41 98 57 155 La x -37930# 400# 8028# 3# B- 9850# 500# 154 959280# 429# - 39 97 58 155 Ce x -47780# 300# 8087# 2# B- 7635# 300# 154 948706# 322# - 37 96 59 155 Pr -55415.335 17.198 8131.0398 0.1110 B- 6868.4609 19.4725 154 940509.193 18.462 - 35 95 60 155 Nd -62283.796 9.154 8170.3050 0.0591 B- 4656.2095 10.2781 154 933135.598 9.826 - 33 94 61 155 Pm -66940.006 4.719 8195.2977 0.0304 B- 3251.1999 4.9024 154 928136.951 5.065 - 31 93 62 155 Sm -n -70191.206 1.332 8211.2258 0.0086 B- 1627.1314 1.2016 154 924646.645 1.429 - 29 92 63 155 Eu -71818.337 1.252 8216.6760 0.0081 B- 251.9612 0.8682 154 922899.847 1.343 - 27 91 64 155 Gd -72070.298 0.983 8213.2541 0.0063 B- -819.8588 9.7884 154 922629.356 1.055 - 25 90 65 155 Tb + -71250.439 9.830 8202.9173 0.0634 B- -2094.5000 1.8974 154 923509.511 10.552 - 23 89 66 155 Dy -69155.939 9.645 8184.3570 0.0622 B- -3116.1405 16.5887 154 925758.049 10.354 - 21 88 67 155 Ho -66039.799 17.470 8159.2055 0.1127 B- -3830.6268 18.4730 154 929103.363 18.754 - 19 87 68 155 Er -a -62209.172 6.074 8129.4444 0.0392 B- -5583.2509 11.5109 154 933215.710 6.520 - 17 86 69 155 Tm -a -56625.921 9.921 8088.3760 0.0640 B- -6123.3072 19.3388 154 939209.576 10.651 - 15 85 70 155 Yb -a -50502.614 16.600 8043.8234 0.1071 B- -7957.5578 25.4153 154 945783.216 17.820 - 13 84 71 155 Lu -42545.056 19.245 7987.4369 0.1242 B- -8235# 301# 154 954326.005 20.660 - 11 83 72 155 Hf x -34310# 300# 7929# 2# B- -10322# 424# 154 963167# 322# - 9 82 73 155 Ta -p -23988# 300# 7858# 2# B- * 154 974248# 322# -0 42 99 57 156 La x -33050# 400# 7997# 3# B- 11769# 500# 155 964519# 429# - 40 98 58 156 Ce x -44820# 300# 8068# 2# B- 6630# 300# 155 951884# 322# - 38 97 59 156 Pr x -51449.307 1.025 8105.2337 0.0066 B- 8752.8229 1.6585 155 944766.900 1.100 - 36 96 60 156 Nd x -60202.130 1.304 8156.3265 0.0084 B- 3964.7175 1.7642 155 935370.358 1.400 - 34 95 61 156 Pm -64166.847 1.188 8176.7263 0.0076 B- 5193.8878 8.6044 155 931114.059 1.275 - 32 94 62 156 Sm -69360.735 8.522 8205.0054 0.0546 B- 722.1090 7.9025 155 925538.191 9.148 - 30 93 63 156 Eu -70082.844 3.532 8204.6192 0.0226 B- 2452.4891 3.4083 155 924762.976 3.791 - 28 92 64 156 Gd -72535.333 0.983 8215.3253 0.0063 B- -2444.3230 3.6774 155 922130.120 1.054 - 26 91 65 156 Tb -70091.010 3.768 8194.6415 0.0242 B- 438.3762 3.6789 155 924754.209 4.044 - 24 90 66 156 Dy -70529.386 0.988 8192.4366 0.0063 B- -4990.9836 38.4111 155 924283.593 1.060 - 22 89 67 156 Ho - -65538.403 38.424 8155.4280 0.2463 B- -1326.7201 45.6391 155 929641.634 41.249 - 20 88 68 156 Er -64211.683 24.629 8141.9084 0.1579 B- -7377.2657 26.7099 155 931065.926 26.440 - 18 87 69 156 Tm -56834.417 14.279 8089.6032 0.0915 B- -3568.8794 12.5484 155 938985.746 15.328 - 16 86 70 156 Yb -53265.538 9.308 8061.7107 0.0597 B- -9565.9880 54.9162 155 942817.096 9.992 - 14 85 71 156 Lu -a -43699.550 54.122 7995.3752 0.3469 B- -5880.0352 139.6908 155 953086.606 58.102 - 12 84 72 156 Hf -37819.514 149.740 7952.6676 0.9599 B- -11819# 335# 155 959399.083 160.752 - 10 83 73 156 Ta -p -26001# 300# 7872# 2# B- * 155 972087# 322# -0 43 100 57 157 La x -29070# 300# 7972# 2# B- 10860# 500# 156 968792# 322# - 41 99 58 157 Ce x -39930# 400# 8037# 3# B- 8504# 400# 156 957133# 429# - 39 98 59 157 Pr x -48434.806 3.167 8085.8170 0.0202 B- 8059.3109 3.8207 156 948003.100 3.400 - 37 97 60 157 Nd -56494.117 2.137 8132.1671 0.0136 B- 5802.9994 7.3246 156 939351.074 2.294 - 35 96 61 157 Pm -62297.116 7.006 8164.1458 0.0446 B- 4380.5376 8.2650 156 933121.298 7.521 - 33 95 62 157 Sm -66677.654 4.434 8187.0642 0.0282 B- 2781.4807 6.1191 156 928418.598 4.759 - 31 94 63 157 Eu -69459.134 4.234 8199.7975 0.0270 B- 1364.7614 4.1973 156 925432.556 4.545 - 29 93 64 157 Gd -70823.896 0.977 8203.5072 0.0062 B- -60.0473 0.2972 156 923967.424 1.048 - 27 92 65 157 Tb -70763.848 1.018 8198.1416 0.0065 B- -1339.1791 5.1297 156 924031.888 1.092 - 25 91 66 157 Dy -69424.669 5.154 8184.6287 0.0328 B- -2591.8068 23.7839 156 925469.555 5.532 - 23 90 67 157 Ho -66832.862 23.469 8163.1373 0.1495 B- -3419.2146 33.6675 156 928251.974 25.194 - 21 89 68 157 Er -63413.648 26.505 8136.3757 0.1688 B- -4704.3690 38.5152 156 931922.652 28.454 - 19 88 69 157 Tm x -58709.279 27.945 8101.4285 0.1780 B- -5289.3667 29.9971 156 936973.000 30.000 - 17 87 70 157 Yb -53419.912 10.905 8062.7551 0.0695 B- -6980.0942 14.2406 156 942651.368 11.706 - 15 86 71 157 Lu -46439.818 12.074 8013.3128 0.0769 B- -7585# 201# 156 950144.807 12.961 - 13 85 72 157 Hf -a -38855# 200# 7960# 1# B- -9259# 250# 156 958288# 215# - 11 84 73 157 Ta IT -29595.948 150.052 7896.0608 0.9557 B- -9906# 427# 156 968227.445 161.087 - 9 83 74 157 W x -19690# 400# 7828# 3# B- * 156 978862# 429# -0 42 100 58 158 Ce x -36540# 400# 8015# 3# B- 7610# 500# 157 960773# 429# - 40 99 59 158 Pr x -44150# 300# 8059# 2# B- 9685# 300# 157 952603# 322# - 38 98 60 158 Nd x -53835.123 1.304 8114.9529 0.0083 B- 5271.0196 1.5776 157 942205.620 1.400 - 36 97 61 158 Pm -59106.143 0.888 8143.3622 0.0056 B- 6145.7062 4.8634 157 936546.948 0.953 - 34 96 62 158 Sm -65251.849 4.782 8177.3075 0.0303 B- 2018.6123 5.1146 157 929949.262 5.133 - 32 95 63 158 Eu -67270.461 2.032 8185.1320 0.0129 B- 3419.5081 2.2547 157 927782.192 2.181 - 30 94 64 158 Gd -70689.969 0.976 8201.8229 0.0062 B- -1219.0862 0.9799 157 924111.200 1.048 - 28 93 65 158 Tb -69470.883 1.268 8189.1556 0.0080 B- 936.2686 2.4750 157 925419.942 1.360 - 26 92 66 158 Dy -70407.152 2.337 8190.1298 0.0148 B- -4219.7555 27.0048 157 924414.817 2.509 - 24 91 67 158 Ho - -66187.396 27.106 8158.4709 0.1716 B- -883.5812 37.0236 157 928944.910 29.099 - 22 90 68 158 Er -65303.815 25.219 8147.9270 0.1596 B- -6600.6151 31.3411 157 929893.474 27.074 - 20 89 69 158 Tm -58703.200 25.219 8101.1994 0.1596 B- -2693.5796 26.4499 157 936979.525 27.074 - 18 88 70 158 Yb -56009.620 7.973 8079.1999 0.0505 B- -8797.4201 16.8655 157 939871.202 8.559 - 16 87 71 158 Lu -a -47212.200 15.125 8018.5685 0.0957 B- -5109.8010 14.9373 157 949315.620 16.236 - 14 86 72 158 Hf -42102.399 17.494 7981.2764 0.1107 B- -10984# 201# 157 954801.217 18.780 - 12 85 73 158 Ta +a -31118# 201# 7907# 1# B- -7426# 361# 157 966593# 215# - 10 84 74 158 W -a -23693# 300# 7855# 2# B- * 157 974565# 322# -0 43 101 58 159 Ce x -31340# 500# 7983# 3# B- 9430# 640# 158 966355# 537# - 41 100 59 159 Pr x -40770# 400# 8037# 3# B- 8954# 401# 158 956232# 429# - 39 99 60 159 Nd x -49724.007 29.808 8088.8224 0.1875 B- 6830.3441 31.4529 158 946619.085 32.000 - 37 98 61 159 Pm -56554.351 10.039 8126.8601 0.0631 B- 5653.4982 11.6438 158 939286.409 10.777 - 35 97 62 159 Sm -62207.849 5.934 8157.4963 0.0373 B- 3835.5363 7.3211 158 933217.130 6.370 - 33 96 63 159 Eu -66043.386 4.320 8176.6987 0.0272 B- 2518.4717 4.3657 158 929099.512 4.637 - 31 95 64 159 Gd -68561.857 0.980 8187.6177 0.0062 B- 970.7242 0.7495 158 926395.822 1.051 - 29 94 65 159 Tb -69532.582 1.103 8188.8025 0.0069 B- -365.3613 1.1573 158 925353.707 1.184 - 27 93 66 159 Dy -69167.220 1.439 8181.5842 0.0091 B- -1837.6000 2.6833 158 925745.938 1.544 - 25 92 67 159 Ho - -67329.620 3.045 8165.1066 0.0192 B- -2768.5000 2.0000 158 927718.683 3.268 - 23 91 68 159 Er - -64561.120 3.643 8142.7742 0.0229 B- -3990.7162 28.1813 158 930690.790 3.910 - 21 90 69 159 Tm x -60570.404 27.945 8112.7549 0.1758 B- -4736.8869 33.0155 158 934975.000 30.000 - 19 89 70 159 Yb x -55833.517 17.582 8078.0428 0.1106 B- -6124.9081 41.5648 158 940060.257 18.874 - 17 88 71 159 Lu x -49708.609 37.663 8034.6009 0.2369 B- -6856.0030 41.2456 158 946635.615 40.433 - 15 87 72 159 Hf -a -42852.606 16.813 7986.5610 0.1057 B- -8413.4492 25.8909 158 953995.837 18.049 - 13 86 73 159 Ta IT -34439.157 19.689 7928.7258 0.1238 B- -9005# 301# 158 963028.046 21.137 - 11 85 74 159 W -a -25434# 300# 7867# 2# B- -10629# 427# 158 972696# 322# - 9 84 75 159 Re IT -14805# 305# 7795# 2# B- * 158 984106# 327# -0 42 101 59 160 Pr x -36200# 400# 8009# 2# B- 10525# 402# 159 961138# 429# - 40 100 60 160 Nd x -46724.515 46.575 8069.9662 0.2911 B- 6170.1238 46.6198 159 949839.172 50.000 - 38 99 61 160 Pm x -52894.639 2.049 8103.6398 0.0128 B- 7338.5338 2.8330 159 943215.272 2.200 - 36 98 62 160 Sm x -60233.172 1.956 8144.6159 0.0122 B- 3260.2763 2.1547 159 935337.032 2.100 - 34 97 63 160 Eu x -63493.449 0.904 8160.1030 0.0057 B- 4448.6112 1.4417 159 931836.982 0.970 - 32 96 64 160 Gd -67942.060 1.123 8183.0171 0.0070 B- -105.5863 1.0207 159 927061.202 1.206 - 30 95 65 160 Tb -67836.474 1.110 8177.4676 0.0069 B- 1835.9516 1.1011 159 927174.553 1.191 - 28 94 66 160 Dy -69672.425 0.700 8184.0526 0.0044 B- -3290.0000 15.0000 159 925203.578 0.751 - 26 93 67 160 Ho - -66382.425 15.016 8158.6004 0.0939 B- -318.2488 28.5197 159 928735.538 16.120 - 24 92 68 160 Er -66064.176 24.246 8151.7217 0.1515 B- -5763.1395 39.1333 159 929077.193 26.029 - 22 91 69 160 Tm -60301.037 32.686 8110.8124 0.2043 B- -2137.8101 33.1447 159 935264.177 35.089 - 20 90 70 160 Yb x -58163.227 5.496 8092.5614 0.0343 B- -7893.2846 57.0863 159 937559.210 5.900 - 18 89 71 160 Lu x -50269.942 56.821 8038.3387 0.3551 B- -4331.1951 57.6165 159 946033.000 61.000 - 16 88 72 160 Hf -45938.747 9.540 8006.3791 0.0596 B- -10115.0475 55.1472 159 950682.728 10.241 - 14 87 73 160 Ta -a -35823.700 54.316 7938.2704 0.3395 B- -6494.6267 139.8413 159 961541.678 58.310 - 12 86 74 160 W -29329.073 149.810 7892.7893 0.9363 B- -12451# 335# 159 968513.946 160.828 - 10 85 75 160 Re -a -16878# 300# 7810# 2# B- * 159 981880# 322# -0 43 102 59 161 Pr x -32490# 500# 7986# 3# B- 9741# 640# 160 965121# 537# - 41 101 60 161 Nd x -42230# 400# 8042# 2# B- 7856# 400# 160 954664# 429# - 39 100 61 161 Pm x -50086.589 9.035 8085.9977 0.0561 B- 6585.4546 11.3187 160 946229.837 9.700 - 37 99 62 161 Sm -56672.043 6.817 8122.0418 0.0423 B- 5119.5577 12.4147 160 939160.062 7.318 - 35 98 63 161 Eu -61791.601 10.400 8148.9810 0.0646 B- 3714.5406 10.5074 160 933663.991 11.164 - 33 97 64 161 Gd -n -65506.142 1.504 8167.1934 0.0093 B- 1955.6357 1.4402 160 929676.267 1.614 - 31 96 65 161 Tb -67461.778 1.218 8174.4809 0.0076 B- 593.7166 1.2010 160 927576.806 1.308 - 29 95 66 161 Dy -68055.494 0.697 8173.3093 0.0043 B- -859.2003 2.1368 160 926939.425 0.748 - 27 94 67 161 Ho -67196.294 2.151 8163.1134 0.0134 B- -1994.9954 9.0041 160 927861.815 2.309 - 25 93 68 161 Er +n -65201.298 8.774 8145.8628 0.0545 B- -3302.5839 29.2899 160 930003.530 9.419 - 23 92 69 161 Tm x -61898.715 27.945 8120.4906 0.1736 B- -4064.4665 31.7640 160 933549.000 30.000 - 21 91 70 161 Yb x -57834.248 15.101 8090.3861 0.0938 B- -5271.8989 31.7640 160 937912.384 16.211 - 19 90 71 161 Lu x -52562.349 27.945 8052.7821 0.1736 B- -6246.5319 36.4805 160 943572.000 30.000 - 17 89 72 161 Hf -46315.817 23.450 8009.1245 0.1457 B- -7537.2421 33.7278 160 950277.927 25.174 - 15 88 73 161 Ta +a -38778.575 24.381 7957.4500 0.1514 B- -8272# 202# 160 958369.489 26.174 - 13 87 74 161 W -a -30507# 200# 7901# 1# B- -9664# 250# 160 967249# 215# - 11 86 75 161 Re -20842.820 149.905 7836.3292 0.9311 B- -10647# 427# 160 977624.313 160.930 - 9 85 76 161 Os -a -10196# 400# 7765# 2# B- * 160 989054# 429# -0 42 102 60 162 Nd x -39010# 400# 8022# 2# B- 7030# 500# 161 958121# 429# - 40 101 61 162 Pm x -46040# 300# 8061# 2# B- 8339# 300# 161 950574# 322# - 38 100 62 162 Sm -54379.053 3.523 8107.5745 0.0218 B- 4343.8905 3.7605 161 941621.687 3.782 - 36 99 63 162 Eu -58722.944 1.314 8129.5593 0.0081 B- 5557.7761 4.1748 161 936958.329 1.410 - 34 98 64 162 Gd -nn -64280.720 3.963 8159.0373 0.0245 B- 1598.8278 4.4611 161 930991.812 4.254 - 32 97 65 162 Tb x -65879.548 2.049 8164.0773 0.0127 B- 2301.6217 2.1640 161 929275.400 2.200 - 30 96 66 162 Dy -68181.169 0.695 8173.4555 0.0043 B- -2140.6068 3.0926 161 926804.507 0.746 - 28 95 67 162 Ho -66040.563 3.102 8155.4126 0.0192 B- 293.6478 3.1069 161 929102.543 3.330 - 26 94 68 162 Er -66334.210 0.756 8152.3959 0.0047 B- -4856.7282 26.0475 161 928787.299 0.811 - 24 93 69 162 Tm - -61477.482 26.058 8117.5868 0.1609 B- -1656.3190 30.1127 161 934001.211 27.974 - 22 92 70 162 Yb x -59821.163 15.103 8102.5333 0.0932 B- -6989.4042 76.5406 161 935779.342 16.213 - 20 91 71 162 Lu x -52831.759 75.036 8054.5596 0.4632 B- -3663.3333 75.5679 161 943282.776 80.554 - 18 90 72 162 Hf -49168.426 8.952 8027.1171 0.0553 B- -9387.0211 63.8938 161 947215.526 9.610 - 16 89 73 162 Ta -a -39781.405 63.322 7964.3432 0.3909 B- -5782.1880 63.3235 161 957292.907 67.979 - 14 88 74 162 W -33999.217 17.657 7923.8214 0.1090 B- -11546# 201# 161 963500.341 18.955 - 12 87 75 162 Re +a -22453# 201# 7848# 1# B- -7953# 361# 161 975896# 215# - 10 86 76 162 Os -a -14500# 300# 7794# 2# B- * 161 984434# 322# -0 43 103 60 163 Nd x -34080# 500# 7992# 3# B- 8880# 640# 162 963414# 537# - 41 102 61 163 Pm x -42960# 400# 8042# 2# B- 7640# 400# 162 953881# 429# - 39 101 62 163 Sm x -50599.612 7.359 8084.1653 0.0451 B- 5974.2073 7.4141 162 945679.085 7.900 - 37 100 63 163 Eu x -56573.819 0.904 8116.0172 0.0056 B- 4814.7720 1.2046 162 939265.510 0.970 - 35 99 64 163 Gd -61388.591 0.797 8140.7560 0.0049 B- 3207.1628 4.1374 162 934096.640 0.855 - 33 98 65 163 Tb +p -64595.754 4.060 8155.6322 0.0249 B- 1785.1041 4.0006 162 930653.609 4.358 - 31 97 66 163 Dy -66380.858 0.693 8161.7840 0.0043 B- -2.8309 0.0222 162 928737.221 0.744 - 29 96 67 163 Ho -66378.027 0.693 8156.9670 0.0043 B- -1210.6141 4.5755 162 928740.260 0.744 - 27 95 68 163 Er -65167.413 4.628 8144.7403 0.0284 B- -2439.0000 3.0000 162 930039.908 4.967 - 25 94 69 163 Tm - -62728.413 5.515 8124.9774 0.0338 B- -3434.5345 16.0687 162 932658.282 5.920 - 23 93 70 163 Yb x -59293.878 15.105 8099.1069 0.0927 B- -4502.4636 31.7657 162 936345.406 16.215 - 21 92 71 163 Lu x -54791.415 27.945 8066.6848 0.1714 B- -5522.0944 37.9611 162 941179.000 30.000 - 19 91 72 163 Hf -49269.320 25.693 8028.0072 0.1576 B- -6734.6864 45.9217 162 947107.211 27.582 - 17 90 73 163 Ta -a -42534.634 38.061 7981.8905 0.2335 B- -7626.1952 69.7301 162 954337.194 40.860 - 15 89 74 163 W -a -34908.439 58.426 7930.3043 0.3584 B- -8906.1859 61.2953 162 962524.251 62.722 - 13 88 75 163 Re +a -26002.253 18.534 7870.8655 0.1137 B- -9666# 301# 162 972085.434 19.897 - 11 87 76 163 Os -a -16336# 300# 7807# 2# B- -11026# 500# 162 982462# 322# - 9 86 77 163 Ir x -5310# 400# 7734# 2# B- * 162 994299# 429# -0 42 103 61 164 Pm x -38360# 400# 8014# 2# B- 9565# 400# 163 958819# 429# - 40 102 62 164 Sm x -47925.314 4.099 8067.7803 0.0250 B- 5306.8315 4.5907 163 948550.061 4.400 - 38 101 63 164 Eu -53232.146 2.068 8095.3686 0.0126 B- 6461.5416 2.2969 163 942852.943 2.219 - 36 100 64 164 Gd -59693.688 1.000 8129.9978 0.0061 B- 2411.2959 2.1143 163 935916.193 1.073 - 34 99 65 164 Tb x -62104.983 1.863 8139.9304 0.0114 B- 3862.6653 1.9884 163 933327.561 2.000 - 32 98 66 164 Dy -65967.649 0.695 8158.7129 0.0042 B- -987.1315 1.3710 163 929180.819 0.746 - 30 97 67 164 Ho -64980.517 1.390 8147.9234 0.0085 B- 962.0559 1.3756 163 930240.548 1.492 - 28 96 68 164 Er -65942.573 0.704 8149.0191 0.0043 B- -4033.6302 25.0113 163 929207.739 0.755 - 26 95 69 164 Tm -61908.943 25.006 8119.6534 0.1525 B- -896.7722 29.2135 163 933538.019 26.845 - 24 94 70 164 Yb x -61012.171 15.106 8109.4149 0.0921 B- -6369.7952 31.7666 163 934500.743 16.217 - 22 93 71 164 Lu x -54642.376 27.945 8065.8043 0.1704 B- -2824.0194 32.1083 163 941339.000 30.000 - 20 92 72 164 Hf -51818.356 15.812 8043.8142 0.0964 B- -8535.5511 32.1083 163 944370.709 16.975 - 18 91 73 164 Ta x -43282.805 27.945 7986.9978 0.1704 B- -5047.2500 29.5717 163 953534.000 30.000 - 16 90 74 164 W -38235.555 9.673 7951.4515 0.0590 B- -10763.1138 55.4055 163 958952.445 10.384 - 14 89 75 164 Re -a -27472.441 54.555 7881.0523 0.3326 B- -7047.7180 140.0330 163 970507.122 58.566 - 12 88 76 164 Os -20424.723 149.903 7833.3080 0.9140 B- -12941# 350# 163 978073.158 160.927 - 10 87 77 164 Ir -a -7483# 316# 7750# 2# B- * 163 991966# 339# -0 43 104 61 165 Pm x -34670# 500# 7992# 3# B- 8840# 640# 164 962780# 537# - 41 103 62 165 Sm x -43510# 400# 8041# 2# B- 7219# 400# 164 953290# 429# - 39 102 63 165 Eu -50729.103 5.213 8080.0529 0.0316 B- 5796.6788 5.3733 164 945540.070 5.596 - 37 101 64 165 Gd -56525.782 1.304 8110.4428 0.0079 B- 4063.0674 2.0189 164 939317.080 1.400 - 35 100 65 165 Tb -60588.849 1.541 8130.3259 0.0093 B- 3023.4392 1.6915 164 934955.198 1.654 - 33 99 66 165 Dy -n -63612.289 0.697 8143.9083 0.0042 B- 1285.7287 0.7502 164 931709.402 0.748 - 31 98 67 165 Ho -64898.017 0.786 8146.9591 0.0048 B- -376.6648 0.9575 164 930329.116 0.844 - 29 97 68 165 Er -64521.353 0.918 8139.9348 0.0056 B- -1591.3282 1.4891 164 930733.482 0.985 - 27 96 69 165 Tm -62930.024 1.658 8125.5489 0.0101 B- -2634.6364 26.5907 164 932441.843 1.779 - 25 95 70 165 Yb -60295.388 26.539 8104.8399 0.1608 B- -3853.1403 35.4324 164 935270.241 28.490 - 23 94 71 165 Lu -56442.248 26.539 8076.7460 0.1608 B- -4806.7350 38.5387 164 939406.758 28.490 - 21 93 72 165 Hf x -51635.513 27.945 8042.8728 0.1694 B- -5787.6410 31.0668 164 944567.000 30.000 - 19 92 73 165 Ta -45847.872 13.573 8003.0547 0.0823 B- -6986.5555 29.1133 164 950780.287 14.571 - 17 91 74 165 W -38861.316 25.756 7955.9704 0.1561 B- -8201.9627 34.9116 164 958280.663 27.649 - 15 90 75 165 Re +a -30659.353 23.593 7901.5201 0.1430 B- -8913# 202# 164 967085.831 25.328 - 13 89 76 165 Os -a -21747# 200# 7843# 1# B- -10151# 255# 164 976654# 215# - 11 88 77 165 Ir IT -11595# 158# 7776# 1# B- -11277# 430# 164 987552# 170# - 9 87 78 165 Pt -a -318# 400# 7703# 2# B- * 164 999658# 429# -0 42 104 62 166 Sm x -40450# 400# 8023# 2# B- 6299# 412# 165 956575# 429# - 40 103 63 166 Eu + -46749# 100# 8056# 1# B- 7622# 100# 165 949813# 107# - 38 102 64 166 Gd x -54370.926 1.584 8097.2260 0.0095 B- 3437.8515 2.1558 165 941630.413 1.700 - 36 101 65 166 Tb -57808.778 1.463 8113.2230 0.0088 B- 4775.6930 1.6690 165 937939.727 1.570 - 34 100 66 166 Dy -n -62584.471 0.804 8137.2793 0.0048 B- 485.8684 0.8502 165 932812.810 0.862 - 32 99 67 166 Ho -63070.339 0.786 8135.4933 0.0047 B- 1853.8057 0.7792 165 932291.209 0.844 - 30 98 68 166 Er -64924.145 0.334 8141.9479 0.0020 B- -3037.6667 11.5470 165 930301.067 0.358 - 28 97 69 166 Tm - -61886.478 11.552 8118.9357 0.0696 B- -292.7714 13.5069 165 933562.136 12.401 - 26 96 70 166 Yb +nn -61593.706 7.001 8112.4591 0.0422 B- -5572.7197 30.6189 165 933876.439 7.515 - 24 95 71 166 Lu x -56020.987 29.808 8074.1756 0.1796 B- -2161.9978 40.8585 165 939859.000 32.000 - 22 94 72 166 Hf x -53858.989 27.945 8056.4386 0.1683 B- -7761.2089 39.5199 165 942180.000 30.000 - 20 93 73 166 Ta x -46097.780 27.945 8004.9714 0.1683 B- -4210.3092 29.5036 165 950512.000 30.000 - 18 92 74 166 W -41887.471 9.463 7974.8951 0.0570 B- -10050.1358 88.7072 165 955031.952 10.159 - 16 91 75 166 Re -a -31837.335 88.242 7909.6392 0.5316 B- -6405.8090 88.3046 165 965821.216 94.731 - 14 90 76 166 Os -25431.526 17.966 7866.3371 0.1082 B- -12126# 201# 165 972698.135 19.287 - 12 89 77 166 Ir -p -13306# 201# 7789# 1# B- -8523# 361# 165 985716# 215# - 10 88 78 166 Pt -a -4783# 300# 7733# 2# B- * 165 994866# 322# -0 43 105 62 167 Sm x -35330# 500# 7992# 3# B- 8440# 640# 166 962072# 537# - 41 104 63 167 Eu x -43770# 400# 8038# 2# B- 7006# 400# 166 953011# 429# - 39 103 64 167 Gd -50775.732 5.213 8075.5428 0.0312 B- 5107.3505 5.5584 166 945490.012 5.596 - 37 102 65 167 Tb -55883.082 1.929 8101.4410 0.0116 B- 4028.3686 4.4459 166 940007.046 2.071 - 35 101 66 167 Dy x -59911.451 4.005 8120.8782 0.0240 B- 2368.0076 6.5549 166 935682.415 4.300 - 33 100 67 167 Ho p2n -62279.459 5.189 8130.3732 0.0311 B- 1009.7971 5.1890 166 933140.254 5.570 - 31 99 68 167 Er -63289.256 0.286 8131.7352 0.0017 B- -746.1392 1.2633 166 932056.192 0.306 - 29 98 69 167 Tm -62543.117 1.258 8122.5826 0.0075 B- -1953.2162 3.7968 166 932857.206 1.350 - 27 97 70 167 Yb -60589.900 3.960 8106.2020 0.0237 B- -3063.6190 37.4696 166 934954.069 4.251 - 25 96 71 167 Lu x -57526.281 37.260 8083.1722 0.2231 B- -4058.5198 46.5747 166 938243.000 40.000 - 23 95 72 167 Hf x -53467.761 27.945 8054.1850 0.1673 B- -5116.6971 39.5199 166 942600.000 30.000 - 21 94 73 167 Ta x -48351.064 27.945 8018.8614 0.1673 B- -6257.8523 33.6262 166 948093.000 30.000 - 19 93 74 167 W -42093.212 18.703 7976.7045 0.1120 B- -7259# 44# 166 954811.080 20.078 - 17 92 75 167 Re +a -34834# 40# 7929# 0# B- -8335# 90# 166 962604# 43# - 15 91 76 167 Os -a -26498.860 80.892 7873.9557 0.4844 B- -9426.4121 82.9464 166 971552.304 86.841 - 13 90 77 167 Ir -17072.448 18.346 7812.8254 0.1099 B- -10319# 307# 166 981671.973 19.694 - 11 89 78 167 Pt -a -6753# 306# 7746# 2# B- * 166 992750# 329# -0 44 106 62 168 Sm x -31640# 300# 7971# 2# B- 7610# 500# 167 966033# 322# - 42 105 63 168 Eu x -39250# 400# 8012# 2# B- 8899# 500# 167 957863# 429# - 40 104 64 168 Gd x -48150# 300# 8060# 2# B- 4631# 300# 167 948309# 322# - 38 103 65 168 Tb x -52781.181 4.192 8082.7980 0.0250 B- 5777.2167 140.0696 167 943337.074 4.500 - 36 102 66 168 Dy +pp -58558.398 140.007 8112.5293 0.8334 B- 1500.8333 143.1849 167 937134.977 150.303 - 34 101 67 168 Ho + -60059.231 30.001 8116.8061 0.1786 B- 2930.0000 30.0000 167 935523.766 32.207 - 32 100 68 168 Er -62989.231 0.262 8129.5897 0.0016 B- -1676.8526 1.6858 167 932378.282 0.280 - 30 99 69 168 Tm -61312.379 1.677 8114.9516 0.0100 B- 267.4880 1.6782 167 934178.457 1.800 - 28 98 70 168 Yb -61579.867 0.093 8111.8870 0.0006 B- -4507.0351 37.9735 167 933891.297 0.100 - 26 97 71 168 Lu -57072.832 37.973 8080.4026 0.2260 B- -1712.2740 47.1476 167 938729.798 40.766 - 24 96 72 168 Hf x -55360.557 27.945 8065.5536 0.1663 B- -6966.6444 39.5199 167 940568.000 30.000 - 22 95 73 168 Ta x -48393.913 27.945 8019.4287 0.1663 B- -3500.9828 30.9307 167 948047.000 30.000 - 20 94 74 168 W -44892.930 13.259 7993.9327 0.0789 B- -9098.0411 33.5515 167 951805.459 14.233 - 18 93 75 168 Re -a -35794.889 30.821 7935.1208 0.1835 B- -5799.8944 32.3727 167 961572.607 33.087 - 16 92 76 168 Os -29994.995 9.903 7895.9408 0.0589 B- -11328.7644 56.0975 167 967799.050 10.631 - 14 91 77 168 Ir -a -18666.230 55.216 7823.8509 0.3287 B- -7656.1526 140.3258 167 979960.978 59.277 - 12 90 78 168 Pt -a -11010.078 149.934 7773.6217 0.8925 B- -13540# 427# 167 988180.196 160.960 - 10 89 79 168 Au x 2530# 400# 7688# 2# B- * 168 002716# 429# -0 43 106 63 169 Eu x -35660# 500# 7991# 3# B- 8230# 640# 168 961717# 537# - 41 105 64 169 Gd x -43890# 400# 8035# 2# B- 6590# 500# 168 952882# 429# - 39 104 65 169 Tb x -50480# 300# 8069# 2# B- 5116# 425# 168 945807# 322# - 37 103 66 169 Dy + -55596.010 300.669 8094.7566 1.7791 B- 3200.0000 300.0000 168 940315.231 322.781 - 35 102 67 169 Ho +p -58796.010 20.048 8109.0622 0.1186 B- 2125.1534 20.0483 168 936879.890 21.522 - 33 101 68 169 Er -n -60921.163 0.304 8117.0078 0.0018 B- 353.4910 0.7729 168 934598.444 0.326 - 31 100 69 169 Tm -61274.654 0.738 8114.4702 0.0044 B- -899.1270 0.7563 168 934218.956 0.792 - 29 99 70 169 Yb -n -60375.527 0.178 8104.5206 0.0011 B- -2293.0000 3.0000 168 935184.208 0.191 - 27 98 71 169 Lu - -58082.527 3.005 8086.3233 0.0178 B- -3365.6321 28.1060 168 937645.845 3.226 - 25 97 72 169 Hf x -54716.895 27.945 8061.7791 0.1654 B- -4426.4600 39.5199 168 941259.000 30.000 - 23 96 73 169 Ta x -50290.435 27.945 8030.9577 0.1654 B- -5372.5686 31.9246 168 946011.000 30.000 - 21 95 74 169 W -44917.866 15.436 7994.5381 0.0913 B- -6508.6195 19.1703 168 951778.689 16.571 - 19 94 75 169 Re +a -38409.247 11.369 7951.3963 0.0673 B- -7686.2626 28.3218 168 958765.979 12.204 - 17 93 76 169 Os -a -30722.984 25.940 7901.2862 0.1535 B- -8629.5684 34.8557 168 967017.521 27.847 - 15 92 77 169 Ir +a -22093.416 23.307 7845.5944 0.1379 B- -9629# 202# 168 976281.743 25.020 - 13 91 78 169 Pt -a -12464# 200# 7784# 1# B- -10676# 359# 168 986619# 215# - 11 90 79 169 Au x -1788# 298# 7716# 2# B- * 168 998080# 320# -0 44 107 63 170 Eu x -30860# 500# 7963# 3# B- 9989# 707# 169 966870# 537# - 42 106 64 170 Gd x -40850# 500# 8017# 3# B- 5860# 583# 169 956146# 537# - 40 105 65 170 Tb x -46710# 300# 8047# 2# B- 7000# 361# 169 949855# 322# - 38 104 66 170 Dy x -53710# 200# 8084# 1# B- 2528# 206# 169 942340# 215# - 36 103 67 170 Ho + -56237.514 50.019 8093.7902 0.2942 B- 3870.0000 50.0000 169 939626.548 53.697 - 34 102 68 170 Er -60107.514 1.387 8111.9529 0.0082 B- -312.1997 1.7852 169 935471.933 1.488 - 32 101 69 170 Tm -59795.314 0.732 8105.5144 0.0043 B- 968.6148 0.7319 169 935807.093 0.785 - 30 100 70 170 Yb -60763.929 0.010 8106.6101 0.0003 B- -3457.6950 16.8430 169 934767.242 0.011 - 28 99 71 170 Lu - -57306.234 16.843 8081.6686 0.0991 B- -1052.3734 32.6282 169 938479.230 18.081 - 26 98 72 170 Hf x -56253.860 27.945 8070.8762 0.1644 B- -6116.1903 39.5199 169 939609.000 30.000 - 24 97 73 170 Ta x -50137.670 27.945 8030.2965 0.1644 B- -2846.8656 30.9035 169 946175.000 30.000 - 22 96 74 170 W -47290.804 13.195 8008.9482 0.0776 B- -8386.8083 17.4557 169 949231.235 14.165 - 20 95 75 170 Re -38903.996 11.427 7955.0120 0.0672 B- -4978.3046 15.0274 169 958234.844 12.267 - 18 94 76 170 Os -33925.692 9.759 7921.1258 0.0574 B- -10743# 102# 169 963579.273 10.476 - 16 93 77 170 Ir -a -23182# 101# 7853# 1# B- -6883# 102# 169 975113# 109# - 14 92 78 170 Pt -16299.202 18.246 7808.2365 0.1073 B- -12596# 202# 169 982502.087 19.588 - 12 91 79 170 Au -p -3703# 201# 7730# 1# B- -9119# 362# 169 996024# 216# - 10 90 80 170 Hg -a 5415# 302# 7671# 2# B- * 170 005814# 324# -0 43 107 64 171 Gd x -36210# 500# 7990# 3# B- 7560# 640# 170 961127# 537# - 41 106 65 171 Tb x -43770# 400# 8030# 2# B- 6240# 447# 170 953011# 429# - 39 105 66 171 Dy x -50010# 200# 8062# 1# B- 4508# 633# 170 946312# 215# - 37 104 67 171 Ho + -54517.822 600.002 8083.6021 3.5088 B- 3200.0000 600.0000 170 941472.713 644.128 - 35 103 68 171 Er -57717.822 1.408 8097.7404 0.0082 B- 1492.4490 1.0788 170 938037.372 1.511 - 33 102 69 171 Tm -59210.271 0.972 8101.8931 0.0057 B- 96.5468 0.9715 170 936435.162 1.043 - 31 101 70 171 Yb -59306.818 0.013 8097.8826 0.0003 B- -1478.3526 1.8621 170 936331.515 0.013 - 29 100 71 171 Lu -57828.465 1.862 8084.6621 0.0109 B- -2397.1144 28.9363 170 937918.591 1.999 - 27 99 72 171 Hf x -55431.351 28.876 8066.0687 0.1689 B- -3711.0725 40.1840 170 940492.000 31.000 - 25 98 73 171 Ta x -51720.279 27.945 8039.7914 0.1634 B- -4634.1832 39.5199 170 944476.000 30.000 - 23 97 74 171 W x -47086.095 27.945 8008.1158 0.1634 B- -5835.8106 39.5199 170 949451.000 30.000 - 21 96 75 171 Re x -41250.285 27.945 7969.4131 0.1634 B- -6953.0469 33.3748 170 955716.000 30.000 - 19 95 76 171 Os -34297.238 18.247 7924.1769 0.1067 B- -7885.2079 42.5749 170 963180.402 19.589 - 17 94 77 171 Ir -a -26412.030 38.466 7873.4895 0.2249 B- -8945.4613 89.6251 170 971645.520 41.295 - 15 93 78 171 Pt -a -17466.569 80.951 7816.6017 0.4734 B- -9904.2655 83.5586 170 981248.868 86.904 - 13 92 79 171 Au -p -7562.303 20.713 7754.1069 0.1211 B- -10901# 307# 170 991881.533 22.236 - 11 91 80 171 Hg -a 3339# 307# 7686# 2# B- * 171 003585# 329# -0 44 108 64 172 Gd x -32970# 300# 7972# 2# B- 6720# 583# 171 964605# 322# - 42 107 65 172 Tb x -39690# 500# 8006# 3# B- 8070# 583# 171 957391# 537# - 40 106 66 172 Dy x -47760# 300# 8049# 2# B- 3724# 358# 171 948728# 322# - 38 105 67 172 Ho x -51484# 196# 8066# 1# B- 4999# 196# 171 944730# 210# - 36 104 68 172 Er -56482.578 3.962 8090.4052 0.0230 B- 890.9756 4.5418 171 939363.461 4.253 - 34 103 69 172 Tm -57373.554 5.481 8091.0367 0.0319 B- 1881.9024 5.4814 171 938406.959 5.884 - 32 102 70 172 Yb -59255.456 0.014 8097.4295 0.0003 B- -2519.3805 2.3360 171 936386.654 0.014 - 30 101 71 172 Lu -56736.076 2.336 8078.2334 0.0136 B- -333.8443 24.5396 171 939091.320 2.507 - 28 100 72 172 Hf x -56402.232 24.428 8071.7439 0.1420 B- -5072.2490 37.1167 171 939449.716 26.224 - 26 99 73 172 Ta x -51329.983 27.945 8037.7056 0.1625 B- -2232.7914 39.5199 171 944895.000 30.000 - 24 98 74 172 W x -49097.191 27.945 8020.1757 0.1625 B- -7530.3525 45.2323 171 947292.000 30.000 - 22 97 75 172 Re -41566.839 35.568 7971.8460 0.2068 B- -4323.1979 37.7890 171 955376.165 38.183 - 20 96 76 172 Os -37243.641 12.766 7942.1626 0.0742 B- -9864.2673 34.8263 171 960017.309 13.704 - 18 95 77 172 Ir -a -27379.373 32.402 7880.2637 0.1884 B- -6272.7035 34.0232 171 970607.035 34.785 - 16 94 78 172 Pt -21106.670 10.376 7839.2460 0.0603 B- -11788.6592 57.1082 171 977341.059 11.139 - 14 93 79 172 Au -a -9318.011 56.158 7766.1587 0.3265 B- -8256.6495 140.8350 171 989996.704 60.287 - 12 92 80 172 Hg -a -1061.361 150.062 7713.6064 0.8725 B- * 171 998860.581 161.098 -0 43 108 65 173 Tb x -36510# 500# 7988# 3# B- 7230# 640# 172 960805# 537# - 41 107 66 173 Dy x -43740# 400# 8026# 2# B- 5610# 499# 172 953043# 429# - 39 106 67 173 Ho x -49351# 298# 8054# 2# B- 4304# 357# 172 947020# 320# - 37 105 68 173 Er x -53654# 196# 8074# 1# B- 2602# 196# 172 942400# 210# - 35 104 69 173 Tm p2n -56256.067 4.400 8084.4633 0.0254 B- 1295.1669 4.4000 172 939606.630 4.723 - 33 103 70 173 Yb -57551.234 0.011 8087.4276 0.0003 B- -670.2201 1.5674 172 938216.211 0.012 - 31 102 71 173 Lu -56881.014 1.567 8079.0312 0.0091 B- -1469.2244 27.9887 172 938935.722 1.682 - 29 101 72 173 Hf x -55411.790 27.945 8066.0164 0.1615 B- -3015.2464 39.5199 172 940513.000 30.000 - 27 100 73 173 Ta x -52396.543 27.945 8044.0650 0.1615 B- -3669.1553 39.5199 172 943750.000 30.000 - 25 99 74 173 W x -48727.388 27.945 8018.3337 0.1615 B- -5173.5182 39.5199 172 947689.000 30.000 - 23 98 75 173 Re x -43553.870 27.945 7983.9068 0.1615 B- -6115.6196 31.6968 172 953243.000 30.000 - 21 97 76 173 Os -37438.250 14.959 7944.0341 0.0865 B- -7169.7944 18.2998 172 959808.387 16.059 - 19 96 77 173 Ir -30268.456 10.542 7898.0680 0.0609 B- -8331.6974 64.3014 172 967505.477 11.316 - 17 95 78 173 Pt -a -21936.758 63.431 7845.3856 0.3667 B- -9104.7415 67.3903 172 976449.922 68.096 - 15 94 79 173 Au +a -12832.017 22.783 7788.2348 0.1317 B- -10171# 202# 172 986224.263 24.458 - 13 93 80 173 Hg -a -2661# 201# 7725# 1# B- * 172 997143# 215# -0 44 109 65 174 Tb x -31970# 500# 7963# 3# B- 9160# 707# 173 965679# 537# - 42 108 66 174 Dy x -41130# 500# 8011# 3# B- 4739# 583# 173 955845# 537# - 40 107 67 174 Ho x -45870# 300# 8034# 2# B- 6080# 423# 173 950757# 322# - 38 106 68 174 Er x -51949# 298# 8064# 2# B- 1915# 301# 173 944230# 320# - 36 105 69 174 Tm + -53864.521 44.721 8070.6432 0.2570 B- 3080.0000 44.7214 173 942174.061 48.010 - 34 104 70 174 Yb -56944.521 0.011 8083.8481 0.0003 B- -1374.2287 1.5675 173 938867.545 0.011 - 32 103 71 174 Lu -55570.292 1.567 8071.4540 0.0090 B- 274.2911 2.1686 173 940342.840 1.682 - 30 102 72 174 Hf -55844.583 2.259 8068.5341 0.0130 B- -4103.8117 28.0360 173 940048.377 2.425 - 28 101 73 174 Ta x -51740.771 27.945 8040.4528 0.1606 B- -1513.6779 39.5199 173 944454.000 30.000 - 26 100 74 174 W x -50227.093 27.945 8027.2572 0.1606 B- -6553.9925 39.5199 173 946079.000 30.000 - 24 99 75 174 Re x -43673.101 27.945 7985.0944 0.1606 B- -3677.7177 29.7667 173 953115.000 30.000 - 22 98 76 174 Os -39995.383 10.254 7959.4618 0.0589 B- -9209.4466 15.2008 173 957063.192 11.008 - 20 97 77 174 Ir +a -30785.937 11.221 7902.0377 0.0645 B- -5468.3293 15.2578 173 966949.939 12.046 - 18 96 78 174 Pt -a -25317.608 10.338 7866.1143 0.0594 B- -11259# 102# 173 972820.431 11.098 - 16 95 79 174 Au -a -14058# 102# 7797# 1# B- -7417# 102# 173 984908# 109# - 14 94 80 174 Hg -a -6641.017 19.211 7749.7851 0.1104 B- * 173 992870.575 20.623 -0 43 109 66 175 Dy x -36730# 500# 7986# 3# B- 6570# 640# 174 960569# 537# - 41 108 67 175 Ho x -43300# 400# 8019# 2# B- 5352# 566# 174 953516# 429# - 39 107 68 175 Er x -48652# 401# 8045# 2# B- 3659# 404# 174 947770# 430# - 37 106 69 175 Tm + -52310.556 50.000 8061.7673 0.2857 B- 2385.0000 50.0000 174 943842.310 53.677 - 35 105 70 175 Yb -54695.556 0.071 8070.9253 0.0005 B- 470.1219 1.2068 174 941281.907 0.076 - 33 104 71 175 Lu -55165.678 1.207 8069.1412 0.0069 B- -683.9154 1.9516 174 940777.211 1.295 - 31 103 72 175 Hf -54481.763 2.283 8060.7625 0.0130 B- -2073.1103 28.0379 174 941511.424 2.450 - 29 102 73 175 Ta x -52408.653 27.945 8044.4456 0.1597 B- -2775.8524 39.5199 174 943737.000 30.000 - 27 101 74 175 W x -49632.800 27.945 8024.1130 0.1597 B- -4344.4885 39.5199 174 946717.000 30.000 - 25 100 75 175 Re x -45288.312 27.945 7994.8168 0.1597 B- -5182.9513 30.3243 174 951381.000 30.000 - 23 99 76 175 Os -40105.360 11.775 7960.7294 0.0673 B- -6710.8496 17.0887 174 956945.126 12.640 - 21 98 77 175 Ir -33394.511 12.384 7917.9112 0.0708 B- -7685.8265 22.3572 174 964149.519 13.295 - 19 97 78 175 Pt -25708.684 18.614 7869.5216 0.1064 B- -8304.9980 42.8203 174 972400.593 19.982 - 17 96 79 175 Au -a -17403.686 38.563 7817.5939 0.2204 B- -9434.2436 89.7876 174 981316.375 41.399 - 15 95 80 175 Hg -a -7969.443 81.085 7759.2134 0.4633 B- * 174 991444.451 87.047 -0 44 110 66 176 Dy x -33610# 500# 7969# 3# B- 5780# 707# 175 963918# 537# - 42 109 67 176 Ho x -39390# 500# 7997# 3# B- 7241# 641# 175 957713# 537# - 40 108 68 176 Er x -46631# 401# 8034# 2# B- 2741# 413# 175 949940# 430# - 38 107 69 176 Tm + -49371.322 100.000 8045.1214 0.5682 B- 4120.0000 100.0000 175 946997.707 107.354 - 36 106 70 176 Yb -53491.322 0.014 8064.0853 0.0003 B- -108.9895 1.2124 175 942574.706 0.015 - 34 105 71 176 Lu -53382.333 1.212 8059.0209 0.0069 B- 1194.0947 0.8744 175 942691.711 1.301 - 32 104 72 176 Hf -54576.428 1.482 8061.3604 0.0084 B- -3211.0484 30.7750 175 941409.797 1.591 - 30 103 73 176 Ta x -51365.379 30.739 8038.6706 0.1747 B- -723.7709 41.5430 175 944857.000 33.000 - 28 102 74 176 W x -50641.608 27.945 8030.1131 0.1588 B- -5578.7182 39.5199 175 945634.000 30.000 - 26 101 75 176 Re x -45062.890 27.945 7993.9707 0.1588 B- -2931.7058 30.0134 175 951623.000 30.000 - 24 100 76 176 Os -42131.184 10.949 7972.8681 0.0622 B- -8249.2618 13.6110 175 954770.315 11.754 - 22 99 77 176 Ir -33881.923 8.085 7921.5522 0.0459 B- -4948.0041 15.0657 175 963626.261 8.679 - 20 98 78 176 Pt -28933.918 12.712 7888.9934 0.0722 B- -10412.9516 35.5363 175 968938.162 13.647 - 18 97 79 176 Au -a -18520.967 33.185 7825.3837 0.1885 B- -6736.3283 34.9978 175 980116.925 35.625 - 16 96 80 176 Hg -11784.639 11.118 7782.6640 0.0632 B- -12369.3668 83.7993 175 987348.670 11.936 - 14 95 81 176 Tl -p 584.728 83.058 7707.9383 0.4719 B- * 176 000627.731 89.166 -0 43 110 67 177 Ho x -36280# 500# 7980# 3# B- 6578# 709# 176 961052# 537# - 41 109 68 177 Er x -42858# 503# 8013# 3# B- 4711# 541# 176 953990# 540# - 39 108 69 177 Tm x -47570# 200# 8035# 1# B- 3417# 200# 176 948932# 215# - 37 107 70 177 Yb -n -50986.404 0.220 8049.9741 0.0013 B- 1397.4983 1.2406 176 945263.846 0.236 - 35 106 71 177 Lu -52383.903 1.221 8053.4495 0.0069 B- 496.8425 0.7921 176 943763.570 1.310 - 33 105 72 177 Hf -52880.745 1.410 8051.8365 0.0080 B- -1166.0000 3.0000 176 943230.187 1.514 - 31 104 73 177 Ta - -51714.745 3.315 8040.8289 0.0187 B- -2013.0144 28.1408 176 944481.940 3.558 - 29 103 74 177 W x -49701.731 27.945 8025.0359 0.1579 B- -3432.5558 39.5199 176 946643.000 30.000 - 27 102 75 177 Re x -46269.175 27.945 8001.2229 0.1579 B- -4312.7271 31.5349 176 950328.000 30.000 - 25 101 76 177 Os +a -41956.448 14.613 7972.4371 0.0826 B- -5909.0234 24.5763 176 954957.902 15.687 - 23 100 77 177 Ir x -36047.425 19.760 7934.6328 0.1116 B- -6676.9880 24.8010 176 961301.500 21.213 - 21 99 78 177 Pt -29370.437 14.988 7892.4896 0.0847 B- -7824.7003 17.9991 176 968469.541 16.090 - 19 98 79 177 Au -21545.736 9.968 7843.8623 0.0563 B- -8769.9135 85.3061 176 976869.701 10.700 - 17 97 80 177 Hg -a -12775.823 84.722 7789.8947 0.4787 B- -9435.7198 87.4322 176 986284.590 90.952 - 15 96 81 177 Tl IT -3340.103 21.628 7732.1655 0.1222 B- * 176 996414.252 23.218 -0 44 111 67 178 Ho x -32130# 500# 7957# 3# B- 8130# 778# 177 965507# 537# - 42 110 68 178 Er x -40260# 596# 7999# 3# B- 3980# 667# 177 956779# 640# - 40 109 69 178 Tm x -44240# 300# 8017# 2# B- 5437# 300# 177 952506# 322# - 38 108 70 178 Yb -49677.139 6.588 8042.7386 0.0370 B- 660.7415 6.9617 177 946669.400 7.072 - 36 107 71 178 Lu -50337.881 2.251 8042.0554 0.0127 B- 2097.4851 2.0569 177 945960.065 2.416 - 34 106 72 178 Hf -52435.366 1.415 8049.4438 0.0080 B- -1837# 52# 177 943708.322 1.519 - 32 105 73 178 Ta IT -50598# 52# 8035# 0# B- -191# 50# 177 945680# 56# - 30 104 74 178 W - -50407.066 15.199 8029.2584 0.0854 B- -4753.6082 31.8106 177 945885.791 16.316 - 28 103 75 178 Re x -45653.457 27.945 7998.1576 0.1570 B- -2109.2143 31.0925 177 950989.000 30.000 - 26 102 76 178 Os -43544.243 13.632 7981.9128 0.0766 B- -7289.9295 23.2390 177 953253.334 14.634 - 24 101 77 178 Ir -36254.314 18.821 7936.5630 0.1057 B- -4256.8282 21.3752 177 961079.395 20.204 - 22 100 78 178 Pt -31997.486 10.133 7908.2530 0.0569 B- -9694.4567 14.4108 177 965649.288 10.878 - 20 99 79 178 Au x -22303.029 10.246 7849.3946 0.0576 B- -5987.6832 14.8566 177 976056.714 11.000 - 18 98 80 178 Hg -a -16315.346 10.758 7811.3607 0.0604 B- -11702# 103# 177 982484.756 11.548 - 16 97 81 178 Tl -a -4613# 102# 7741# 1# B- -8187# 103# 177 995047# 110# - 14 96 82 178 Pb -a 3573.371 23.184 7690.8359 0.1302 B- * 178 003836.171 24.889 -0 43 111 68 179 Er x -36080# 500# 7976# 3# B- 5821# 640# 178 961267# 537# - 41 110 69 179 Tm x -41900# 400# 8004# 2# B- 4739# 447# 178 955018# 429# - 39 109 70 179 Yb x -46640# 200# 8026# 1# B- 2419# 200# 178 949930# 215# - 37 108 71 179 Lu -49059.013 5.150 8035.0744 0.0288 B- 1404.0231 5.0672 178 947332.985 5.528 - 35 107 72 179 Hf -50463.036 1.416 8038.5474 0.0079 B- -105.5801 0.4088 178 945825.705 1.520 - 33 106 73 179 Ta -50357.456 1.466 8033.5869 0.0082 B- -1062.2093 14.5197 178 945939.050 1.574 - 31 105 74 179 W -49295.247 14.573 8023.2821 0.0814 B- -2710.9347 26.8021 178 947079.378 15.644 - 29 104 75 179 Re -46584.312 24.639 8003.7666 0.1376 B- -3564.1747 29.1116 178 949989.686 26.450 - 27 103 76 179 Os -43020.137 15.505 7979.4844 0.0866 B- -4938.4182 18.3271 178 953815.985 16.645 - 25 102 77 179 Ir -38081.719 9.771 7947.5248 0.0546 B- -5813.5920 12.6133 178 959117.594 10.489 - 23 101 78 179 Pt -32268.127 7.977 7910.6759 0.0446 B- -7279.5556 14.1567 178 965358.742 8.563 - 21 100 79 179 Au -24988.572 11.696 7865.6374 0.0653 B- -8055.6480 30.4559 178 973173.666 12.555 - 19 99 80 179 Hg -16932.924 28.121 7816.2631 0.1571 B- -8663.2918 47.7998 178 981821.759 30.188 - 17 98 81 179 Tl -a -8269.632 38.653 7763.4942 0.2159 B- -10321.2401 89.9571 178 991122.185 41.495 - 15 97 82 179 Pb -a 2051.608 81.229 7701.4630 0.4538 B- * 179 002202.492 87.203 -0 44 112 68 180 Er x -33180# 500# 7960# 3# B- 4990# 640# 179 964380# 537# - 42 111 69 180 Tm x -38170# 400# 7983# 2# B- 6550# 500# 179 959023# 429# - 40 110 70 180 Yb x -44720# 300# 8016# 2# B- 1956# 308# 179 951991# 322# - 38 109 71 180 Lu + -46676.476 70.725 8022.0394 0.3929 B- 3103.0000 70.7107 179 949890.744 75.926 - 36 108 72 180 Hf -49779.476 1.421 8034.9319 0.0079 B- -845.8453 2.3472 179 946559.537 1.525 - 34 107 73 180 Ta +n -48933.631 2.068 8025.8864 0.0115 B- 702.6122 2.3590 179 947467.589 2.219 - 32 106 74 180 W -49636.243 1.439 8025.4434 0.0080 B- -3798.8793 21.4404 179 946713.304 1.545 - 30 105 75 180 Re x -45837.364 21.392 7999.9922 0.1188 B- -1481.1659 26.5482 179 950791.568 22.965 - 28 104 76 180 Os -44356.198 15.722 7987.4171 0.0873 B- -6378.6679 26.8021 179 952381.665 16.878 - 26 103 77 180 Ir x -37977.530 21.706 7947.6337 0.1206 B- -3547.6546 23.9205 179 959229.446 23.302 - 24 102 78 180 Pt -34429.875 10.051 7923.5781 0.0558 B- -8804.2290 11.1207 179 963038.010 10.790 - 22 101 79 180 Au -25625.646 4.759 7870.3194 0.0264 B- -5375.1330 13.5105 179 972489.738 5.108 - 20 100 80 180 Hg -20250.513 12.645 7836.1111 0.0702 B- -10860.0750 71.0509 179 978260.180 13.574 - 18 99 81 180 Tl -a -9390.438 69.917 7771.4310 0.3884 B- -7449.3696 71.0069 179 989918.950 75.058 - 16 98 82 180 Pb -a -1941.069 12.395 7725.6993 0.0689 B- * 179 997916.177 13.306 -0 43 112 69 181 Tm x -35440# 500# 7969# 3# B- 5649# 582# 180 961954# 537# - 41 111 70 181 Yb x -41088# 298# 7996# 2# B- 3709# 324# 180 955890# 320# - 39 110 71 181 Lu x -44797.414 125.752 8011.9301 0.6948 B- 2605.5435 125.7598 180 951908.000 135.000 - 37 109 72 181 Hf -n -47402.958 1.423 8022.0030 0.0079 B- 1036.1061 1.9298 180 949110.834 1.527 - 35 108 73 181 Ta -48439.064 1.576 8023.4050 0.0087 B- -205.1193 1.9495 180 947998.528 1.692 - 33 107 74 181 W -n -48233.945 1.448 8017.9494 0.0080 B- -1716.5331 12.6289 180 948218.733 1.554 - 31 106 75 181 Re 4n -46517.412 12.549 8004.1434 0.0693 B- -2967.4438 28.2755 180 950061.507 13.471 - 29 105 76 181 Os -43549.968 25.338 7983.4263 0.1400 B- -4086.9327 25.8756 180 953247.188 27.201 - 27 104 77 181 Ir +a -39463.035 5.245 7956.5242 0.0290 B- -5081.5379 14.6597 180 957634.691 5.631 - 25 103 78 181 Pt -34381.497 13.689 7924.1271 0.0756 B- -6510.3575 24.2164 180 963089.946 14.695 - 23 102 79 181 Au -a -27871.140 19.976 7883.8359 0.1104 B- -7210.0126 25.2123 180 970079.102 21.445 - 21 101 80 181 Hg -20661.127 15.382 7839.6792 0.0850 B- -7862.3780 17.8730 180 977819.368 16.513 - 19 100 81 181 Tl -12798.749 9.102 7791.9183 0.0503 B- -9688.1182 85.5227 180 986259.978 9.771 - 17 99 82 181 Pb -a -3110.631 85.037 7734.0704 0.4698 B- * 180 996660.600 91.290 -0 44 113 69 182 Tm x -31490# 500# 7948# 3# B- 7410# 640# 181 966194# 537# - 42 112 70 182 Yb x -38900# 400# 7984# 2# B- 2870# 447# 181 958239# 429# - 40 111 71 182 Lu x -41770# 200# 7996# 1# B- 4280# 200# 181 955158# 215# - 38 110 72 182 Hf -nn -46049.636 6.166 8014.8381 0.0339 B- 381.0486 6.3027 181 950563.684 6.619 - 36 109 73 182 Ta -46430.685 1.578 8012.6332 0.0087 B- 1815.4592 1.5276 181 950154.612 1.693 - 34 108 74 182 W -48246.144 0.745 8018.3096 0.0041 B- -2800.0000 101.9804 181 948205.636 0.799 - 32 107 75 182 Re IT -45446.144 101.983 7998.6264 0.5603 B- -837.0348 104.2757 181 951211.560 109.483 - 30 106 76 182 Os -44609.109 21.745 7989.7287 0.1195 B- -5557.4266 30.2074 181 952110.154 23.344 - 28 105 77 182 Ir -39051.682 20.967 7954.8948 0.1152 B- -2883.2620 24.7202 181 958076.296 22.509 - 26 104 78 182 Pt -36168.420 13.095 7934.7541 0.0719 B- -7864.4447 22.8812 181 961171.605 14.057 - 24 103 79 182 Au -28303.976 18.764 7887.2442 0.1031 B- -4727.0905 21.1645 181 969614.433 20.143 - 22 102 80 182 Hg -23576.885 9.790 7856.9726 0.0538 B- -10249.6721 15.4687 181 974689.173 10.510 - 20 101 81 182 Tl -a -13327.213 11.976 7796.3571 0.0658 B- -6502.6567 17.0151 181 985692.649 12.856 - 18 100 82 182 Pb -a -6824.556 12.086 7756.3296 0.0664 B- * 181 992673.537 12.975 -0 43 113 70 183 Yb x -35000# 400# 7963# 2# B- 4716# 408# 182 962426# 429# - 41 112 71 183 Lu x -39716.114 80.108 7984.8125 0.4378 B- 3567.4325 85.5564 182 957363.000 86.000 - 39 111 72 183 Hf + -43283.547 30.042 8000.0315 0.1642 B- 2010.0000 30.0000 182 953533.203 32.251 - 37 110 73 183 Ta -n -45293.547 1.590 8006.7400 0.0087 B- 1072.1161 1.5405 182 951375.380 1.707 - 35 109 74 183 W -46365.663 0.743 8008.3234 0.0041 B- -556.0000 8.0000 182 950224.416 0.798 - 33 108 75 183 Re - -45809.663 8.034 8001.0101 0.0439 B- -2145.9028 50.4129 182 950821.306 8.625 - 31 107 76 183 Os -43663.760 49.769 7985.0087 0.2720 B- -3461.6215 52.8061 182 953125.028 53.428 - 29 106 77 183 Ir -40202.138 24.672 7961.8176 0.1348 B- -4428.9417 28.4743 182 956841.231 26.486 - 27 105 78 183 Pt -35773.197 14.216 7933.3406 0.0777 B- -5581.7092 17.0554 182 961595.895 15.261 - 25 104 79 183 Au -30191.488 9.423 7898.5644 0.0515 B- -6386.8322 11.7891 182 967588.106 10.116 - 23 103 80 183 Hg -23804.655 7.084 7859.3885 0.0387 B- -7217.3941 11.7158 182 974444.652 7.604 - 21 102 81 183 Tl -16587.261 9.331 7815.6741 0.0510 B- -9007.2534 30.4442 182 982192.843 10.017 - 19 101 82 183 Pb -a -7580.008 28.979 7762.1790 0.1584 B- * 182 991862.527 31.110 -0 44 114 70 184 Yb x -32600# 503# 7951# 3# B- 3700# 541# 183 965002# 540# - 42 113 71 184 Lu x -36300# 200# 7967# 1# B- 5199# 204# 183 961030# 215# - 40 112 72 184 Hf + -41499.453 39.706 7990.7228 0.2158 B- 1340.0000 30.0000 183 955448.507 42.625 - 38 111 73 184 Ta + -42839.453 26.010 7993.7535 0.1414 B- 2866.0000 26.0000 183 954009.958 27.923 - 36 110 74 184 W -45705.453 0.738 8005.0777 0.0040 B- -1485.6333 4.1971 183 950933.180 0.792 - 34 109 75 184 Re -44219.819 4.276 7992.7517 0.0232 B- 32.7460 4.1387 183 952528.073 4.590 - 32 108 76 184 Os -44252.565 0.829 7988.6778 0.0045 B- -4641.7101 27.9571 183 952492.919 0.890 - 30 107 77 184 Ir x -39610.855 27.945 7959.1992 0.1519 B- -2278.3688 31.5957 183 957476.000 30.000 - 28 106 78 184 Pt -37332.486 14.744 7942.5649 0.0801 B- -7013.7724 26.7122 183 959921.929 15.828 - 26 105 79 184 Au -a -30318.714 22.275 7900.1947 0.1211 B- -3973.9269 24.2296 183 967451.523 23.912 - 24 104 80 184 Hg -26344.787 9.535 7874.3454 0.0518 B- -9461.4321 13.8254 183 971717.709 10.235 - 22 103 81 184 Tl -16883.355 10.012 7818.6727 0.0544 B- -5831.7688 16.2517 183 981874.973 10.747 - 20 102 82 184 Pb -11051.586 12.802 7782.7264 0.0696 B- -12306# 123# 183 988135.634 13.743 - 18 101 83 184 Bi -a 1254# 122# 7712# 1# B- * 184 001347# 131# -0 45 115 70 185 Yb x -28480# 500# 7929# 3# B- 5480# 583# 184 969425# 537# - 43 114 71 185 Lu x -33960# 300# 7955# 2# B- 4359# 307# 184 963542# 322# - 41 113 72 185 Hf x -38319.804 64.273 7973.9711 0.3474 B- 3074.5667 65.8147 184 958862.000 69.000 - 39 112 73 185 Ta + -41394.371 14.161 7986.3615 0.0765 B- 1993.5000 14.1421 184 955561.317 15.202 - 37 111 74 185 W -43387.871 0.739 7992.9083 0.0040 B- 431.1764 0.6616 184 953421.206 0.793 - 35 110 75 185 Re -43819.047 0.820 7991.0101 0.0044 B- -1013.1393 0.4190 184 952958.320 0.879 - 33 109 76 185 Os -42805.908 0.832 7981.3047 0.0045 B- -2470.3505 27.9572 184 954045.969 0.893 - 31 108 77 185 Ir x -40335.558 27.945 7963.7226 0.1511 B- -3647.4137 38.0554 184 956698.000 30.000 - 29 107 78 185 Pt -36688.144 25.832 7939.7779 0.1396 B- -4829.9942 25.9635 184 960613.659 27.731 - 27 106 79 185 Au x -31858.150 2.608 7909.4410 0.0141 B- -5674.4989 13.8859 184 965798.871 2.800 - 25 105 80 185 Hg -26183.651 13.639 7874.5391 0.0737 B- -6425.9062 24.7674 184 971890.696 14.641 - 23 104 81 185 Tl IT -19757.745 20.674 7835.5756 0.1118 B- -8216.5333 26.2493 184 978789.189 22.194 - 21 103 82 185 Pb -a -11541.211 16.175 7786.9330 0.0874 B- -9305# 83# 184 987610.000 17.364 - 19 102 83 185 Bi IT -2236# 81# 7732# 0# B- * 184 997600# 87# -0 44 115 71 186 Lu x -30320# 400# 7936# 2# B- 6104# 403# 185 967450# 429# - 42 114 72 186 Hf x -36424.214 51.232 7964.3032 0.2754 B- 2183.3883 78.9063 185 960897.000 55.000 - 40 113 73 186 Ta + -38607.602 60.012 7971.8357 0.3226 B- 3901.0000 60.0000 185 958553.036 64.425 - 38 112 74 186 W -42508.602 1.213 7988.6026 0.0065 B- -581.2819 1.2386 185 954365.140 1.302 - 36 111 75 186 Re -41927.320 0.820 7981.2713 0.0044 B- 1072.7114 0.8337 185 954989.172 0.880 - 34 110 76 186 Os -43000.032 0.761 7982.8324 0.0041 B- -3827.6813 16.5430 185 953837.569 0.816 - 32 109 77 186 Ir x -39172.350 16.526 7958.0473 0.0888 B- -1307.9030 27.3122 185 957946.754 17.740 - 30 108 78 186 Pt -37864.447 21.745 7946.8094 0.1169 B- -6149.5913 30.2074 185 959350.845 23.344 - 28 107 79 186 Au -31714.856 20.967 7909.5409 0.1127 B- -3175.7972 23.9866 185 965952.703 22.509 - 26 106 80 186 Hg -28539.059 11.650 7888.2605 0.0626 B- -8656.1190 23.7974 185 969362.061 12.507 - 24 105 81 186 Tl -19882.940 20.751 7837.5161 0.1116 B- -5202.0427 23.4877 185 978654.787 22.276 - 22 104 82 186 Pb -a -14680.897 11.004 7805.3420 0.0592 B- -11535.3999 20.2118 185 984239.409 11.813 - 20 103 83 186 Bi -a -3145.497 16.954 7739.1175 0.0911 B- -7247.0279 24.9305 185 996623.169 18.200 - 18 102 84 186 Po -a 4101.531 18.278 7695.9488 0.0983 B- * 186 004403.174 19.622 -0 45 116 71 187 Lu x -27770# 400# 7923# 2# B- 5230# 447# 186 970188# 429# - 43 115 72 187 Hf x -33000# 200# 7947# 1# B- 3896# 208# 186 964573# 215# - 41 114 73 187 Ta x -36895.550 55.890 7963.2123 0.2989 B- 3008.4937 55.9028 186 960391.000 60.000 - 39 113 74 187 W -39904.044 1.213 7975.1168 0.0065 B- 1312.5048 1.1219 186 957161.249 1.302 - 37 112 75 187 Re -41216.548 0.737 7977.9519 0.0039 B- 2.4667 0.0016 186 955752.217 0.791 - 35 111 76 187 Os -41219.015 0.737 7973.7814 0.0039 B- -1669.6385 27.9545 186 955749.569 0.791 - 33 110 77 187 Ir x -39549.377 27.945 7960.6692 0.1494 B- -2864.0151 36.8802 186 957542.000 30.000 - 31 109 78 187 Pt -36685.361 24.067 7941.1699 0.1287 B- -3656.5811 27.4478 186 960616.646 25.837 - 29 108 79 187 Au -33028.780 22.499 7917.4323 0.1203 B- -4910.2713 25.9171 186 964542.147 24.153 - 27 107 80 187 Hg -28118.509 12.864 7886.9905 0.0688 B- -5673.9170 15.1746 186 969813.540 13.810 - 25 106 81 187 Tl -22444.592 8.048 7852.4650 0.0430 B- -7457.6370 9.5248 186 975904.740 8.640 - 23 105 82 187 Pb -14986.955 5.094 7808.4010 0.0272 B- -8603.6798 11.2268 186 983910.842 5.468 - 21 104 83 187 Bi -a -6383.275 10.005 7758.2083 0.0535 B- -9207.0832 34.1302 186 993147.272 10.740 - 19 103 84 187 Po -a 2823.808 32.631 7704.7889 0.1745 B- * 187 003031.482 35.030 -0 46 117 71 188 Lu x -23820# 400# 7903# 2# B- 7009# 500# 187 974428# 429# - 44 116 72 188 Hf x -30830# 300# 7936# 2# B- 3080# 361# 187 966903# 322# - 42 115 73 188 Ta x -33910# 200# 7948# 1# B- 4758# 200# 187 963596# 215# - 40 114 74 188 W + -38667.880 3.089 7969.0532 0.0164 B- 349.0000 3.0000 187 958488.325 3.316 - 38 113 75 188 Re -n -39016.880 0.738 7966.7481 0.0039 B- 2120.4209 0.1520 187 958113.658 0.792 - 36 112 76 188 Os -41137.301 0.734 7973.8656 0.0039 B- -2792.3457 9.4164 187 955837.292 0.788 - 34 111 77 188 Ir -38344.955 9.423 7954.8512 0.0501 B- -523.9860 8.6863 187 958834.999 10.116 - 32 110 78 188 Pt -37820.970 5.305 7947.9027 0.0282 B- -5449.6549 5.9528 187 959397.521 5.694 - 30 109 79 188 Au x -32371.315 2.701 7914.7537 0.0144 B- -2172.9634 7.3046 187 965247.966 2.900 - 28 108 80 188 Hg -30198.351 6.787 7899.0340 0.0361 B- -7861.9485 30.6643 187 967580.738 7.285 - 26 107 81 188 Tl x -22336.403 29.904 7853.0537 0.1591 B- -4525.3784 31.5712 187 976020.886 32.103 - 24 106 82 188 Pb -a -17811.024 10.124 7824.8211 0.0539 B- -10616.2241 15.0824 187 980879.079 10.868 - 22 105 83 188 Bi -a -7194.800 11.179 7764.1904 0.0595 B- -6650.4226 22.8861 187 992276.064 12.001 - 20 104 84 188 Po -a -544.378 19.970 7724.6544 0.1062 B- * 187 999415.586 21.438 -0 45 117 72 189 Hf x -27150# 300# 7917# 2# B- 4809# 361# 188 970853# 322# - 43 116 73 189 Ta x -31960# 200# 7938# 1# B- 3850# 283# 188 965690# 215# - 41 115 74 189 W + -35809# 200# 7954# 1# B- 2170# 200# 188 961557# 215# - 39 114 75 189 Re +p -37979.097 8.191 7961.8105 0.0433 B- 1007.7049 8.1671 188 959227.764 8.793 - 37 113 76 189 Os -38986.802 0.666 7963.0029 0.0035 B- -537.1494 12.5630 188 958145.949 0.715 - 35 112 77 189 Ir -38449.652 12.576 7956.0214 0.0665 B- -1980.2470 13.6363 188 958722.602 13.500 - 33 111 78 189 Pt -36469.405 10.090 7941.4045 0.0534 B- -2887.4471 22.4737 188 960848.485 10.832 - 31 110 79 189 Au x -33581.958 20.081 7921.9876 0.1063 B- -3955.5800 37.4009 188 963948.286 21.558 - 29 109 80 189 Hg -29626.378 31.553 7896.9192 0.1669 B- -5010.2727 32.6434 188 968194.776 33.873 - 27 108 81 189 Tl -24616.105 8.368 7866.2704 0.0443 B- -6772.0862 16.3636 188 973573.525 8.983 - 25 107 82 189 Pb -17844.019 14.062 7826.2999 0.0744 B- -7779.3555 25.1498 188 980843.658 15.096 - 23 106 83 189 Bi -a -10064.664 20.851 7780.9999 0.1103 B- -8642.6682 30.3542 188 989195.139 22.384 - 21 105 84 189 Po -a -1421.996 22.059 7731.1321 0.1167 B- * 188 998473.425 23.681 -0 46 118 72 190 Hf x -24800# 400# 7905# 2# B- 3920# 447# 189 973376# 429# - 44 117 73 190 Ta x -28720# 200# 7922# 1# B- 5649# 203# 189 969168# 215# - 42 116 74 190 W -34368.832 35.391 7947.5031 0.1863 B- 1214.1824 35.5545 189 963103.542 37.993 - 40 115 75 190 Re -35583.015 4.870 7949.7759 0.0256 B- 3124.8105 4.7864 189 961800.064 5.227 - 38 114 76 190 Os -38707.825 0.650 7962.1047 0.0034 B- -1954.2108 1.2131 189 958445.442 0.697 - 36 113 77 190 Ir +n -36753.614 1.370 7947.7017 0.0072 B- 552.8893 1.2822 189 960543.374 1.470 - 34 112 78 190 Pt -37306.504 0.657 7946.4941 0.0035 B- -4472.9637 3.5086 189 959949.823 0.705 - 32 111 79 190 Au x -32833.540 3.447 7918.8345 0.0181 B- -1462.9150 16.2760 189 964751.746 3.700 - 30 110 80 190 Hg -31370.625 15.907 7907.0174 0.0837 B- -7004.3892 17.4819 189 966322.250 17.076 - 28 109 81 190 Tl +a -24366.236 7.252 7866.0345 0.0382 B- -3949.6288 14.4634 189 973841.771 7.784 - 26 108 82 190 Pb -a -20416.607 12.514 7841.1294 0.0659 B- -9820.7014 24.4226 189 978081.872 13.434 - 24 107 83 190 Bi -a -10595.906 20.973 7785.3239 0.1104 B- -6033.1975 24.7615 189 988624.828 22.515 - 22 106 84 190 Po -a -4562.708 13.163 7749.4526 0.0693 B- * 189 995101.731 14.131 -0 45 118 73 191 Ta x -26520# 300# 7911# 2# B- 4657# 303# 190 971530# 322# - 43 117 74 191 W x -31176.176 41.917 7931.4359 0.2195 B- 3174.2318 43.1556 190 966531.000 45.000 - 41 116 75 191 Re +p -34350.408 10.264 7943.9588 0.0537 B- 2044.8311 10.2443 190 963123.322 11.019 - 39 115 76 191 Os -36395.239 0.659 7950.5687 0.0035 B- 313.5873 1.1410 190 960928.105 0.707 - 37 114 77 191 Ir -36708.826 1.310 7948.1144 0.0069 B- -1010.4903 3.6360 190 960591.455 1.406 - 35 113 78 191 Pt -35698.336 4.127 7938.7279 0.0216 B- -1900.4257 6.4260 190 961676.261 4.430 - 33 112 79 191 Au -33797.910 4.926 7924.6819 0.0258 B- -3206.0616 22.7103 190 963716.452 5.288 - 31 111 80 191 Hg -30591.849 22.280 7903.8002 0.1167 B- -4308.8981 23.4609 190 967158.301 23.918 - 29 110 81 191 Tl +a -26282.951 7.349 7877.1445 0.0385 B- -5991.7073 9.8864 190 971784.093 7.889 - 27 109 82 191 Pb -20291.243 6.613 7841.6782 0.0346 B- -7051.8922 9.9895 190 978216.455 7.099 - 25 108 83 191 Bi -13239.351 7.487 7800.6613 0.0392 B- -8170.6205 10.3201 190 985786.972 8.037 - 23 107 84 191 Po -5068.731 7.103 7753.7871 0.0372 B- -8932.6440 17.5997 190 994558.494 7.624 - 21 106 85 191 At -a 3863.913 16.103 7702.9233 0.0843 B- * 191 004148.081 17.287 -0 46 119 73 192 Ta x -23100# 400# 7894# 2# B- 6520# 447# 191 975201# 429# - 44 118 74 192 W x -29620# 200# 7924# 1# B- 1969# 212# 191 968202# 215# - 42 117 75 192 Re x -31588.828 70.794 7930.2389 0.3687 B- 4293.4750 70.8314 191 966088.000 76.000 - 40 116 76 192 Os -35882.303 2.314 7948.5260 0.0121 B- -1046.6722 2.3962 191 961478.765 2.484 - 38 115 77 192 Ir -34835.631 1.314 7938.9999 0.0068 B- 1452.8946 2.2739 191 962602.414 1.410 - 36 114 78 192 Pt -36288.525 2.570 7942.4923 0.0134 B- -3516.3415 15.6174 191 961042.667 2.758 - 34 113 79 192 Au - -32772.184 15.827 7920.1033 0.0824 B- -760.7028 22.1777 191 964817.615 16.991 - 32 112 80 192 Hg x -32011.481 15.537 7912.0666 0.0809 B- -6139.2324 35.2767 191 965634.263 16.679 - 30 111 81 192 Tl x -25872.249 31.671 7876.0167 0.1650 B- -3320.4029 32.1843 191 972225.000 34.000 - 28 110 82 192 Pb -22551.846 5.726 7854.6482 0.0298 B- -9017.3089 30.6518 191 975789.598 6.147 - 26 109 83 192 Bi -a -13534.537 30.112 7803.6084 0.1568 B- -5468.0534 31.9348 191 985470.077 32.326 - 24 108 84 192 Po -a -8066.483 10.634 7771.0542 0.0554 B- -10992.2252 29.8328 191 991340.274 11.416 - 22 107 85 192 At -a 2925.742 27.873 7709.7283 0.1452 B- * 192 003140.912 29.922 -0 47 120 73 193 Ta x -20810# 400# 7883# 2# B- 5380# 447# 192 977660# 429# - 45 119 74 193 W x -26190# 200# 7907# 1# B- 4042# 204# 192 971884# 215# - 43 118 75 193 Re x -30231.641 39.123 7923.9378 0.2027 B- 3162.7597 39.1915 192 967545.000 42.000 - 41 117 76 193 Os -33394.401 2.320 7936.2716 0.0120 B- 1141.9038 2.4000 192 964149.637 2.490 - 39 116 77 193 Ir -34536.305 1.327 7938.1346 0.0069 B- -56.6276 0.2997 192 962923.753 1.425 - 37 115 78 193 Pt -34479.677 1.359 7933.7875 0.0070 B- -1074.8477 8.7676 192 962984.546 1.458 - 35 114 79 193 Au -33404.829 8.674 7924.1648 0.0449 B- -2342.6641 14.3702 192 964138.442 9.311 - 33 113 80 193 Hg -31062.165 15.505 7907.9730 0.0803 B- -3584.9466 16.8938 192 966653.395 16.645 - 31 112 81 193 Tl x -27477.218 6.707 7885.3445 0.0348 B- -5247.9637 12.2808 192 970501.994 7.200 - 29 111 82 193 Pb -22229.255 10.288 7854.0994 0.0533 B- -6344.6913 12.7761 192 976135.914 11.044 - 27 110 83 193 Bi -15884.563 7.576 7817.1718 0.0393 B- -7559.2614 16.3874 192 982947.220 8.132 - 25 109 84 193 Po -a -8325.302 14.531 7773.9510 0.0753 B- -8257.9789 26.0594 192 991062.421 15.599 - 23 108 85 193 At -a -67.323 21.632 7727.1099 0.1121 B- -9110.2435 33.1444 192 999927.725 23.222 - 21 107 86 193 Rn -a 9042.920 25.112 7675.8530 0.1301 B- * 193 009707.973 26.958 -0 48 121 73 194 Ta x -17130# 500# 7865# 3# B- 7280# 583# 193 981610# 537# - 46 120 74 194 W x -24410# 300# 7899# 2# B- 2850# 361# 193 973795# 322# - 44 119 75 194 Re x -27260# 200# 7909# 1# B- 5175# 200# 193 970735# 215# - 42 118 76 194 Os + -32435.176 2.403 7932.0232 0.0124 B- 96.6000 2.0000 193 965179.407 2.579 - 40 117 77 194 Ir -n -32531.776 1.332 7928.4885 0.0069 B- 2228.3252 1.2569 193 965075.703 1.429 - 38 116 78 194 Pt -34760.101 0.496 7935.9420 0.0026 B- -2548.1518 2.1174 193 962683.498 0.532 - 36 115 79 194 Au +3n -32211.950 2.118 7918.7744 0.0109 B- -27.9978 3.5809 193 965419.051 2.273 - 34 114 80 194 Hg x -32183.952 2.888 7914.5974 0.0149 B- -5246.4542 14.2677 193 965449.108 3.100 - 32 113 81 194 Tl x -26937.498 13.972 7883.5211 0.0720 B- -2729.6315 22.3433 193 971081.408 15.000 - 30 112 82 194 Pb -24207.866 17.435 7865.4181 0.0899 B- -8184.8462 18.2094 193 974011.788 18.717 - 28 111 83 194 Bi +a -16023.020 5.252 7819.1955 0.0271 B- -5018.4029 13.9386 193 982798.581 5.638 - 26 110 84 194 Po -a -11004.617 12.911 7789.2947 0.0666 B- -10288.1273 26.8153 193 988186.058 13.860 - 24 109 85 194 At -a -716.490 23.502 7732.2304 0.1211 B- -6441.1134 28.8079 193 999230.816 25.230 - 22 108 86 194 Rn -a 5724.624 16.659 7694.9961 0.0859 B- * 194 006145.636 17.884 -0 47 121 74 195 W x -20740# 300# 7881# 2# B- 4820# 424# 194 977735# 322# - 45 120 75 195 Re x -25560# 300# 7901# 2# B- 3951# 305# 194 972560# 322# - 43 119 76 195 Os x -29511.596 55.890 7917.7449 0.2866 B- 2180.7220 55.9055 194 968318.000 60.000 - 41 118 77 195 Ir -n -31692.318 1.333 7924.9160 0.0068 B- 1101.5601 1.2637 194 965976.898 1.431 - 39 117 78 195 Pt -32793.878 0.503 7926.5530 0.0026 B- -226.8175 0.9998 194 964794.325 0.540 - 37 116 79 195 Au -32567.061 1.119 7921.3778 0.0057 B- -1553.7190 23.1562 194 965037.823 1.201 - 35 115 80 195 Hg -31013.342 23.142 7909.3980 0.1187 B- -2858.0499 25.6707 194 966705.809 24.843 - 33 114 81 195 Tl -28155.292 11.126 7890.7293 0.0571 B- -4417.2524 12.2333 194 969774.052 11.944 - 31 113 82 195 Pb -23738.039 5.088 7864.0647 0.0261 B- -5712.4729 7.3370 194 974516.167 5.461 - 29 112 83 195 Bi -18025.567 5.287 7830.7579 0.0271 B- -6908.9121 8.0284 194 980648.759 5.675 - 27 111 84 195 Po -11116.655 6.042 7791.3155 0.0310 B- -7646.3554 11.3199 194 988065.781 6.486 - 25 110 85 195 At -a -3470.299 9.573 7748.0914 0.0491 B- -8520.5842 52.5650 194 996274.480 10.276 - 23 109 86 195 Rn -a 5050.285 51.686 7700.3841 0.2651 B- * 195 005421.703 55.487 -0 48 122 74 196 W x -18740# 400# 7872# 2# B- 3620# 500# 195 979882# 429# - 46 121 75 196 Re x -22360# 300# 7886# 2# B- 5918# 303# 195 975996# 322# - 44 120 76 196 Os +pp -28277.123 40.055 7912.2301 0.2044 B- 1158.3989 55.4951 195 969643.261 43.000 - 42 119 77 196 Ir + -29435.522 38.414 7914.1487 0.1960 B- 3209.0164 38.4111 195 968399.669 41.239 - 40 118 78 196 Pt -32644.538 0.510 7926.5297 0.0026 B- -1505.8204 2.9605 195 964954.648 0.547 - 38 117 79 196 Au -31138.718 2.962 7914.8553 0.0151 B- 687.2263 3.1176 195 966571.213 3.179 - 36 116 80 196 Hg -31825.944 2.946 7914.3700 0.0150 B- -4329.3455 12.4627 195 965833.445 3.163 - 34 115 81 196 Tl x -27496.598 12.109 7888.2900 0.0618 B- -2148.3639 14.3556 195 970481.189 13.000 - 32 114 82 196 Pb -25348.234 7.710 7873.3374 0.0393 B- -7339.2020 25.6160 195 972787.552 8.277 - 30 113 83 196 Bi x -18009.032 24.428 7831.9009 0.1246 B- -4540.3012 25.0142 195 980666.509 26.224 - 28 112 84 196 Po -13468.731 5.383 7804.7445 0.0275 B- -9555.5564 30.7105 195 985540.722 5.778 - 26 111 85 196 At -a -3913.175 30.235 7752.0001 0.1543 B- -5888.3439 33.3417 195 995799.034 32.458 - 24 110 86 196 Rn -a 1975.169 14.054 7717.9660 0.0717 B- * 196 002120.431 15.087 -0 49 123 74 197 W x -14870# 400# 7853# 2# B- 5480# 500# 196 984036# 429# - 47 122 75 197 Re x -20350# 300# 7877# 2# B- 4729# 361# 196 978153# 322# - 45 121 76 197 Os x -25080# 200# 7897# 1# B- 3185# 201# 196 973076# 215# - 43 120 77 197 Ir +p -28264.123 20.110 7909.0003 0.1021 B- 2155.6519 20.1061 196 969657.217 21.588 - 41 119 78 197 Pt -30419.775 0.536 7915.9714 0.0027 B- 719.9769 0.5022 196 967343.030 0.575 - 39 118 79 197 Au -31139.751 0.542 7915.6548 0.0028 B- -599.5206 3.2022 196 966570.103 0.581 - 37 117 80 197 Hg -30540.231 3.207 7908.6402 0.0163 B- -2186.0092 13.9478 196 967213.715 3.442 - 35 116 81 197 Tl +a -28354.222 13.575 7893.5725 0.0689 B- -3608.8367 14.3969 196 969560.492 14.573 - 33 115 82 197 Pb -24745.385 4.804 7871.2822 0.0244 B- -5058.1894 9.6190 196 973434.737 5.157 - 31 114 83 197 Bi +a -19687.196 8.333 7841.6348 0.0423 B- -6294.1172 12.9103 196 978864.927 8.946 - 29 113 84 197 Po -13393.078 9.861 7805.7136 0.0501 B- -7037.8235 12.6871 196 985621.939 10.585 - 27 112 85 197 At -6355.255 7.983 7766.0174 0.0405 B- -7865.6231 18.0538 196 993177.353 8.570 - 25 111 86 197 Rn -a 1510.368 16.193 7722.1190 0.0822 B- -8743.5996 58.7110 197 001621.446 17.383 - 23 110 87 197 Fr -a 10253.968 56.434 7673.7640 0.2865 B- * 197 011008.086 60.584 -0 48 123 75 198 Re x -16990# 400# 7861# 2# B- 6610# 447# 197 981760# 429# - 46 122 76 198 Os x -23600# 200# 7890# 1# B- 2110# 283# 197 974664# 215# - 44 121 77 198 Ir x -25710# 200# 7897# 1# B- 4194# 200# 197 972399# 215# - 42 120 78 198 Pt -29904.018 2.100 7914.1512 0.0106 B- -323.2251 2.0595 197 967896.718 2.254 - 40 119 79 198 Au -29580.793 0.540 7908.5675 0.0027 B- 1373.5226 0.4905 197 968243.714 0.579 - 38 118 80 198 Hg -30954.315 0.458 7911.5532 0.0023 B- -3425.5625 7.5590 197 966769.177 0.491 - 36 117 81 198 Tl x -27528.753 7.545 7890.3011 0.0381 B- -1461.3103 11.5537 197 970446.669 8.100 - 34 116 82 198 Pb -26067.443 8.750 7878.9695 0.0442 B- -6693.5916 28.9259 197 972015.450 9.393 - 32 115 83 198 Bi -19373.851 27.571 7841.2123 0.1392 B- -3900.5727 32.6152 197 979201.316 29.598 - 30 114 84 198 Po -15473.278 17.424 7817.5611 0.0880 B- -8764.5316 18.1013 197 983388.753 18.705 - 28 113 85 198 At -6708.747 4.904 7769.3446 0.0248 B- -5478.4271 14.2879 197 992797.864 5.265 - 26 112 86 198 Rn -a -1230.320 13.420 7737.7245 0.0678 B- -10808.0177 33.8991 197 998679.197 14.406 - 24 111 87 198 Fr -a 9577.698 31.130 7679.1873 0.1572 B- * 198 010282.081 33.419 -0 49 124 75 199 Re x -14730# 400# 7850# 2# B- 5541# 447# 198 984187# 429# - 47 123 76 199 Os x -20270# 200# 7874# 1# B- 4128# 204# 198 978239# 215# - 45 122 77 199 Ir p-2n -24398.534 41.054 7891.2066 0.2063 B- 2990.1656 41.0030 198 973807.097 44.073 - 43 121 78 199 Pt -n -27388.700 2.159 7902.3011 0.0109 B- 1705.0525 2.1201 198 970597.022 2.317 - 41 120 79 199 Au -29093.752 0.542 7906.9379 0.0027 B- 452.3142 0.6126 198 968766.573 0.581 - 39 119 80 199 Hg -29546.066 0.526 7905.2794 0.0027 B- -1486.6695 27.9498 198 968280.994 0.564 - 37 118 81 199 Tl x -28059.397 27.945 7893.8773 0.1404 B- -2827.6624 28.7653 198 969877.000 30.000 - 35 117 82 199 Pb +a -25231.734 6.821 7875.7366 0.0343 B- -4434.1181 12.6179 198 972912.620 7.322 - 33 116 83 199 Bi -20797.616 10.615 7849.5232 0.0533 B- -5558.7875 11.9224 198 977672.841 11.395 - 31 115 84 199 Po -a -15238.829 5.429 7817.6582 0.0273 B- -6415.4515 7.6464 198 983640.445 5.828 - 29 114 85 199 At -8823.377 5.384 7781.4883 0.0271 B- -7263.5308 9.0686 198 990527.715 5.780 - 27 113 86 199 Rn -a -1559.846 7.297 7741.0568 0.0367 B- -8331.2349 15.5446 198 998325.436 7.833 - 25 112 87 199 Fr -a 6771.388 13.726 7695.2599 0.0690 B- * 199 007269.384 14.734 -0 48 124 76 200 Os x -18550# 300# 7867# 1# B- 3020# 358# 199 980086# 322# - 46 123 77 200 Ir x -21570# 196# 7878# 1# B- 5030# 197# 199 976844# 210# - 44 122 78 200 Pt -nn -26599.178 20.110 7899.1986 0.1006 B- 640.9158 33.4386 199 971444.609 21.588 - 42 121 79 200 Au -27240.094 26.717 7898.4915 0.1336 B- 2263.1737 26.7188 199 970756.558 28.681 - 40 120 80 200 Hg -29503.267 0.530 7905.8956 0.0027 B- -2456.0403 5.7346 199 968326.941 0.568 - 38 119 81 200 Tl - -27047.227 5.759 7889.7037 0.0288 B- -796.3695 11.5360 199 970963.608 6.182 - 36 118 82 200 Pb -26250.858 10.008 7881.8101 0.0500 B- -5880.2841 24.8094 199 971818.546 10.744 - 34 117 83 200 Bi +a -20370.574 22.701 7848.4969 0.1135 B- -3428.8901 23.9327 199 978131.290 24.370 - 32 116 84 200 Po -16941.683 7.579 7827.4407 0.0379 B- -7953.7897 25.6119 199 981812.355 8.136 - 30 115 85 200 At -a -8987.894 24.465 7783.7601 0.1223 B- -4987.4394 25.1411 199 990351.099 26.264 - 28 114 86 200 Rn -a -4000.454 5.792 7754.9111 0.0290 B- -10134.0327 31.0688 199 995705.335 6.217 - 26 113 87 200 Fr -a 6133.578 30.524 7700.3292 0.1526 B- * 200 006584.666 32.769 -0 49 125 76 201 Os x -14840# 300# 7849# 1# B- 5000# 361# 200 984069# 322# - 47 124 77 201 Ir x -19840# 200# 7870# 1# B- 3901# 206# 200 978701# 215# - 45 123 78 201 Pt + -23740.705 50.103 7885.8337 0.2493 B- 2660.0000 50.0000 200 974513.305 53.788 - 43 122 79 201 Au -26400.705 3.218 7895.1752 0.0160 B- 1261.8237 3.1471 200 971657.678 3.455 - 41 121 80 201 Hg -27662.529 0.712 7897.5607 0.0036 B- -481.7508 14.1815 200 970303.054 0.763 - 39 120 81 201 Tl -27180.778 14.185 7891.2717 0.0706 B- -1909.7458 18.5299 200 970820.235 15.228 - 37 119 82 201 Pb -25271.033 13.747 7877.8782 0.0684 B- -3842.0269 18.3637 200 972870.431 14.758 - 35 118 83 201 Bi +a -21429.006 12.177 7854.8713 0.0606 B- -4907.8397 13.1377 200 976995.017 13.072 - 33 117 84 201 Po -16521.166 4.942 7826.5619 0.0246 B- -5731.7247 9.5606 200 982263.799 5.305 - 31 116 85 201 At +a -10789.441 8.184 7794.1536 0.0407 B- -6682.0288 13.0163 200 988417.058 8.786 - 29 115 86 201 Rn -a -4107.413 10.121 7757.0174 0.0504 B- -7695.9856 13.5972 200 995590.511 10.865 - 27 114 87 201 Fr -a 3588.573 9.080 7714.8367 0.0452 B- -8348.2439 22.2391 201 003852.491 9.747 - 25 113 88 201 Ra -a 11936.817 20.301 7669.4108 0.1010 B- * 201 012814.699 21.794 -0 50 126 76 202 Os x -12530# 400# 7839# 2# B- 4110# 500# 201 986548# 429# - 48 125 77 202 Ir x -16640# 300# 7855# 1# B- 6052# 301# 201 982136# 322# - 46 124 78 202 Pt x -22692.128 25.150 7881.5609 0.1245 B- 1660.8540 34.2759 201 975639.000 27.000 - 44 123 79 202 Au x -24352.982 23.287 7885.9100 0.1153 B- 2992.3278 23.2980 201 973856.000 25.000 - 42 122 80 202 Hg -27345.310 0.705 7896.8505 0.0035 B- -1364.8906 1.8348 201 970643.604 0.757 - 40 121 81 202 Tl -25980.419 1.838 7886.2206 0.0091 B- -39.8110 4.1863 201 972108.874 1.972 - 38 120 82 202 Pb -25940.608 3.796 7882.1505 0.0188 B- -5189.7539 14.5070 201 972151.613 4.075 - 36 119 83 202 Bi -20750.854 14.002 7852.5857 0.0693 B- -2809.2850 16.4660 201 977723.042 15.032 - 34 118 84 202 Po -17941.569 8.670 7834.8053 0.0429 B- -7346.4628 28.9311 201 980738.934 9.307 - 32 117 85 202 At -10595.106 27.601 7794.5637 0.1366 B- -4320.5458 32.6924 201 988625.686 29.631 - 30 116 86 202 Rn -a -6274.561 17.520 7769.3018 0.0867 B- -9376.0984 18.5296 201 993263.982 18.808 - 28 115 87 202 Fr -a 3101.538 6.033 7719.0125 0.0299 B- -5973.3620 16.1841 202 003329.637 6.476 - 26 114 88 202 Ra -a 9074.900 15.018 7685.5684 0.0743 B- * 202 009742.305 16.122 -0 51 127 76 203 Os x -7270# 400# 7814# 2# B- 7100# 565# 202 992195# 429# - 49 126 77 203 Ir x -14370# 400# 7845# 2# B- 5140# 447# 202 984573# 429# - 47 125 78 203 Pt x -19510# 200# 7867# 1# B- 3633# 200# 202 979055# 215# - 45 124 79 203 Au -23143.444 3.083 7880.8650 0.0152 B- 2125.7592 3.4514 202 975154.492 3.309 - 43 123 80 203 Hg -25269.203 1.630 7887.4828 0.0080 B- 492.1062 1.2247 202 972872.396 1.750 - 41 122 81 203 Tl -25761.309 1.171 7886.0530 0.0058 B- -974.8265 6.4609 202 972344.098 1.257 - 39 121 82 203 Pb -24786.483 6.554 7877.3970 0.0323 B- -3261.5896 14.3559 202 973390.617 7.036 - 37 120 83 203 Bi +a -21524.893 12.778 7857.4762 0.0629 B- -4214.0744 13.5942 202 976892.077 13.717 - 35 119 84 203 Po -17310.819 4.640 7832.8632 0.0229 B- -5148.2116 11.5921 202 981416.072 4.981 - 33 118 85 203 At -12162.607 10.623 7803.6487 0.0523 B- -5978.5623 12.1098 202 986942.904 11.404 - 31 117 86 203 Rn -a -6184.045 5.815 7770.3437 0.0286 B- -7060.4572 8.5231 202 993361.155 6.242 - 29 116 87 203 Fr 876.412 6.232 7731.7092 0.0307 B- -7724.9182 11.5191 203 000940.867 6.689 - 27 115 88 203 Ra -a 8601.331 9.688 7689.8015 0.0477 B- * 203 009233.907 10.400 -0 50 127 77 204 Ir x -9570# 400# 7823# 2# B- 8050# 447# 203 989726# 429# - 48 126 78 204 Pt x -17620# 200# 7859# 1# B- 2770# 283# 203 981084# 215# - 46 125 79 204 Au + -20390# 200# 7868# 1# B- 4300# 200# 203 978110# 215# - 44 124 80 204 Hg -24690.148 0.498 7885.5455 0.0025 B- -344.0781 1.1876 203 973494.037 0.534 - 42 123 81 204 Tl -24346.070 1.154 7880.0238 0.0057 B- 763.7453 0.1768 203 973863.420 1.238 - 40 122 82 204 Pb -25109.815 1.147 7879.9326 0.0056 B- -4463.8883 9.2480 203 973043.506 1.231 - 38 121 83 204 Bi +a -20645.927 9.180 7854.2157 0.0450 B- -2304.8814 13.6253 203 977835.687 9.854 - 36 120 84 204 Po -18341.045 10.071 7839.0823 0.0494 B- -6465.7939 24.8047 203 980310.078 10.811 - 34 119 85 204 At -11875.252 22.668 7803.5522 0.1111 B- -3905.1360 23.8592 203 987251.393 24.335 - 32 118 86 204 Rn -7970.115 7.444 7780.5743 0.0365 B- -8577.4239 25.6840 203 991443.729 7.991 - 30 117 87 204 Fr -a 607.308 24.581 7734.6931 0.1205 B- -5453.7889 26.1514 204 000651.972 26.389 - 28 116 88 204 Ra -a 6061.097 8.924 7704.1238 0.0437 B- * 204 006506.855 9.580 -0 51 128 77 205 Ir x -5600# 500# 7805# 2# B- 7220# 583# 204 993988# 537# - 49 127 78 205 Pt x -12820# 300# 7836# 1# B- 5750# 361# 204 986237# 322# - 47 126 79 205 Au x -18570# 200# 7860# 1# B- 3717# 200# 204 980064# 215# - 45 125 80 205 Hg -22287.719 3.655 7874.7325 0.0178 B- 1533.0836 3.7238 204 976073.151 3.923 - 43 124 81 205 Tl -23820.802 1.239 7878.3946 0.0060 B- -50.6402 0.5033 204 974427.318 1.330 - 41 123 82 205 Pb -23770.162 1.145 7874.3313 0.0056 B- -2704.5927 4.8196 204 974481.682 1.228 - 39 122 83 205 Bi -21065.569 4.808 7857.3218 0.0235 B- -3544.1710 11.1458 204 977385.182 5.161 - 37 121 84 205 Po -17521.398 10.059 7836.2168 0.0491 B- -4536.8793 15.6996 204 981190.006 10.798 - 35 120 85 205 At +a -12984.519 12.055 7810.2694 0.0588 B- -5274.7547 13.0777 204 986060.546 12.941 - 33 119 86 205 Rn -7709.764 5.080 7780.7226 0.0248 B- -6399.9479 9.3288 204 991723.228 5.453 - 31 118 87 205 Fr x -1309.816 7.824 7745.6870 0.0382 B- -7113.6693 24.0784 204 998593.854 8.399 - 29 117 88 205 Ra -a 5803.853 22.772 7707.1698 0.1111 B- -8302.8357 63.5402 205 006230.692 24.446 - 27 116 89 205 Ac -a 14106.689 59.320 7662.8519 0.2894 B- * 205 015144.152 63.682 -0 50 128 78 206 Pt x -9240# 300# 7820# 1# B- 4950# 424# 205 990080# 322# - 48 127 79 206 Au x -14190# 300# 7840# 1# B- 6755# 301# 205 984766# 322# - 46 126 80 206 Hg +a -20945.728 20.441 7869.1723 0.0992 B- 1307.5659 20.4100 205 977513.837 21.943 - 44 125 81 206 Tl -22253.293 1.286 7871.7219 0.0062 B- 1532.2128 0.6117 205 976110.108 1.380 - 42 124 82 206 Pb -23785.506 1.144 7875.3620 0.0056 B- -3757.3057 7.5461 205 974465.210 1.228 - 40 123 83 206 Bi - -20028.201 7.632 7853.3249 0.0371 B- -1839.5323 8.6005 205 978498.843 8.193 - 38 122 84 206 Po -a -18188.668 4.012 7840.5973 0.0195 B- -5749.2803 14.1099 205 980473.662 4.306 - 36 121 85 206 At -12439.388 13.529 7808.8904 0.0657 B- -3306.4697 16.0227 205 986645.768 14.523 - 34 120 86 206 Rn -9132.918 8.591 7789.0417 0.0417 B- -7886.0592 29.1075 205 990195.409 9.223 - 32 119 87 206 Fr -1246.859 27.811 7746.9621 0.1350 B- -4812.4721 33.1318 205 998661.441 29.856 - 30 118 88 206 Ra -a 3565.613 18.008 7719.8028 0.0874 B- -9919.1406 67.5328 206 003827.842 19.332 - 28 117 89 206 Ac -a 13484.754 65.088 7667.8538 0.3160 B- * 206 014476.477 69.874 -0 51 129 78 207 Pt x -4140# 400# 7797# 2# B- 6501# 500# 206 995556# 429# - 49 128 79 207 Au x -10640# 300# 7824# 1# B- 5847# 301# 206 988577# 322# - 47 127 80 207 Hg x -16487.446 29.808 7848.6112 0.1440 B- 4546.9906 30.3000 206 982300.000 32.000 - 45 126 81 207 Tl -21034.436 5.439 7866.7979 0.0263 B- 1417.5323 5.4024 206 977418.605 5.839 - 43 125 82 207 Pb -22451.968 1.147 7869.8664 0.0055 B- -2397.4140 2.1175 206 975896.821 1.231 - 41 124 83 207 Bi -20054.554 2.397 7854.5053 0.0116 B- -2908.8541 6.6140 206 978470.551 2.573 - 39 123 84 207 Po -17145.700 6.659 7836.6734 0.0322 B- -3918.2186 14.0754 206 981593.334 7.148 - 37 122 85 207 At +a -13227.482 12.406 7813.9653 0.0599 B- -4592.7400 13.2815 206 985799.715 13.318 - 35 121 86 207 Rn -8634.742 4.742 7787.9987 0.0229 B- -5785.7211 18.1857 206 990730.224 5.090 - 33 120 87 207 Fr -2849.021 17.557 7756.2689 0.0848 B- -6363.0084 60.8726 206 996941.450 18.847 - 31 119 88 207 Ra -a 3513.988 58.286 7721.7503 0.2816 B- -7632.2404 81.0004 207 003772.420 62.572 - 29 118 89 207 Ac -a 11146.228 56.248 7681.1001 0.2717 B- * 207 011965.967 60.384 -0 52 130 78 208 Pt x -500# 400# 7780# 2# B- 5410# 500# 207 999463# 429# - 50 129 79 208 Au x -5910# 300# 7803# 1# B- 7355# 302# 207 993655# 322# - 48 128 80 208 Hg x -13265.408 30.739 7834.1914 0.1478 B- 3484.7131 30.7951 207 985759.000 33.000 - 46 127 81 208 Tl +a -16750.121 1.854 7847.1835 0.0089 B- 4998.3984 1.6693 207 982018.006 1.989 - 44 126 82 208 Pb -21748.519 1.148 7867.4530 0.0055 B- -2878.3680 2.0127 207 976652.005 1.232 - 42 125 83 208 Bi +n -18870.151 2.305 7849.8534 0.0111 B- -1400.9438 2.3787 207 979742.060 2.474 - 40 124 84 208 Po -17469.207 1.672 7839.3568 0.0080 B- -4999.3061 9.0736 207 981246.035 1.795 - 38 123 85 208 At +a -12469.901 8.921 7811.5604 0.0429 B- -2814.5118 13.5215 207 986613.011 9.577 - 36 122 86 208 Rn -9655.389 10.163 7794.2678 0.0489 B- -6990.4614 15.4656 207 989634.513 10.910 - 34 121 87 208 Fr -2664.928 11.657 7756.8985 0.0560 B- -4392.8615 14.7413 207 997139.082 12.514 - 32 120 88 208 Ra -a 1727.934 9.023 7732.0177 0.0434 B- -9032.9208 65.1111 208 001855.012 9.686 - 30 119 89 208 Ac -a 10760.854 64.483 7684.8289 0.3100 B- -5927.1868 71.9264 208 011552.251 69.225 - 28 118 90 208 Th -a 16688.041 31.865 7652.5716 0.1532 B- * 208 017915.348 34.208 -0 51 130 79 209 Au x -2230# 400# 7786# 2# B- 6380# 427# 208 997606# 429# - 49 129 80 209 Hg x -8610# 150# 7813# 1# B- 5035# 150# 208 990757# 161# - 47 128 81 209 Tl +a -13644.793 6.110 7833.3979 0.0292 B- 3969.7809 6.2115 208 985351.713 6.559 - 45 127 82 209 Pb -17614.574 1.747 7848.6488 0.0084 B- 644.0152 1.1462 208 981089.978 1.875 - 43 126 83 209 Bi -18258.589 1.365 7847.9869 0.0065 B- -1892.5741 1.5635 208 980398.599 1.465 - 41 125 84 209 Po -a -16366.015 1.778 7835.1882 0.0085 B- -3482.2417 4.9599 208 982430.361 1.909 - 39 124 85 209 At -12883.773 4.745 7814.7835 0.0227 B- -3942.7237 11.0298 208 986168.701 5.094 - 37 123 86 209 Rn -8941.049 9.960 7792.1755 0.0477 B- -5158.9051 15.2153 208 990401.389 10.692 - 35 122 87 209 Fr -3782.144 11.503 7763.7485 0.0550 B- -5640.3845 12.8549 208 995939.701 12.349 - 33 121 88 209 Ra -a 1858.240 5.747 7733.0177 0.0275 B- -6986.6464 56.1409 209 001994.902 6.169 - 31 120 89 209 Ac -a 8844.887 55.846 7695.8455 0.2672 B- -7550# 117# 209 009495.375 59.953 - 29 119 90 209 Th IT 16395# 103# 7656# 0# B- * 209 017601# 111# -0 52 131 79 210 Au x 2680# 400# 7764# 2# B- 7980# 447# 210 002877# 429# - 50 130 80 210 Hg x -5300# 200# 7799# 1# B- 3947# 201# 209 994310# 215# - 48 129 81 210 Tl +a -9246.996 11.603 7813.5890 0.0553 B- 5481.4334 11.5610 209 990072.942 12.456 - 46 128 82 210 Pb -14728.429 1.448 7835.9656 0.0069 B- 63.4758 0.4992 209 984188.381 1.554 - 44 127 83 210 Bi -14791.905 1.364 7832.5424 0.0065 B- 1161.1549 0.7662 209 984120.237 1.463 - 42 126 84 210 Po -15953.060 1.146 7834.3462 0.0055 B- -3980.9605 7.6101 209 982873.686 1.230 - 40 125 85 210 At -a -11972.099 7.695 7811.6638 0.0366 B- -2367.3352 8.9225 209 987147.423 8.261 - 38 124 86 210 Rn -a -9604.764 4.557 7796.6653 0.0217 B- -6261.2558 14.1720 209 989688.862 4.892 - 36 123 87 210 Fr -3343.508 13.420 7763.1243 0.0639 B- -3786.3467 16.2633 209 996410.596 14.407 - 34 122 88 210 Ra -a 442.839 9.193 7741.3687 0.0438 B- -8321.2403 62.8832 210 000475.406 9.868 - 32 121 89 210 Ac 8764.079 62.208 7698.0182 0.2962 B- -5295.4420 65.0180 210 009408.625 66.782 - 30 120 90 210 Th -a 14059.521 18.909 7669.0764 0.0900 B- * 210 015093.515 20.299 -0 51 131 80 211 Hg x -390# 200# 7777# 1# B- 5688# 205# 210 999581# 215# - 49 130 81 211 Tl x -6077.999 41.917 7799.7915 0.1987 B- 4415.0129 41.9781 210 993475.000 45.000 - 47 129 82 211 Pb -10493.012 2.260 7817.0079 0.0107 B- 1366.1041 5.4713 210 988735.288 2.426 - 45 128 83 211 Bi -11859.116 5.442 7819.7745 0.0258 B- 573.3763 5.4297 210 987268.715 5.842 - 43 127 84 211 Po -a -12432.492 1.255 7818.7842 0.0060 B- -785.3012 2.5385 210 986653.171 1.347 - 41 126 85 211 At -a -11647.191 2.729 7811.3545 0.0129 B- -2891.8615 6.8937 210 987496.226 2.929 - 39 125 86 211 Rn -a -8755.330 6.813 7793.9412 0.0323 B- -4615.0152 13.7862 210 990600.767 7.314 - 37 124 87 211 Fr -4140.314 11.991 7768.3613 0.0568 B- -4972.1844 12.9786 210 995555.189 12.872 - 35 123 88 211 Ra 831.870 4.966 7741.0887 0.0235 B- -6311.6152 53.9818 211 000893.049 5.331 - 33 122 89 211 Ac 7143.485 53.753 7707.4680 0.2548 B- -6732.9111 101.4758 211 007668.846 57.706 - 31 121 90 211 Th -a 13876.396 86.070 7671.8506 0.4079 B- -8175.8296 110.6091 211 014896.923 92.399 - 29 120 91 211 Pa -a 22052.226 69.472 7629.3948 0.3293 B- * 211 023674.036 74.581 -0 52 132 80 212 Hg x 3020# 300# 7762# 1# B- 4571# 361# 212 003242# 322# - 50 131 81 212 Tl +a -1551# 200# 7780# 1# B- 5998# 200# 211 998335# 215# - 48 130 82 212 Pb -7548.929 1.840 7804.3203 0.0087 B- 569.0133 1.8246 211 991895.891 1.975 - 46 129 83 212 Bi -8117.943 1.853 7803.3140 0.0087 B- 2251.4656 1.6671 211 991285.030 1.989 - 44 128 84 212 Po -10369.408 1.153 7810.2438 0.0054 B- -1741.2596 2.1066 211 988867.982 1.237 - 42 127 85 212 At -a -8628.149 2.385 7798.3400 0.0113 B- 31.0705 3.5927 211 990737.301 2.559 - 40 126 86 212 Rn -a -8659.219 3.110 7794.7963 0.0147 B- -5143.2210 9.3064 211 990703.946 3.338 - 38 125 87 212 Fr -3515.998 8.775 7766.8455 0.0414 B- -3317.2355 13.4939 211 996225.420 9.419 - 36 124 88 212 Ra -198.763 10.254 7747.5078 0.0484 B- -7498.3626 24.1666 211 999786.619 11.007 - 34 123 89 212 Ac 7299.600 21.883 7708.4479 0.1032 B- -4811.2864 24.1055 212 007836.442 23.492 - 32 122 90 212 Th -a 12110.886 10.109 7682.0628 0.0477 B- -9485.6366 88.1858 212 013001.570 10.852 - 30 121 91 212 Pa -a 21596.523 87.604 7633.6289 0.4132 B- * 212 023184.819 94.047 -0 53 133 80 213 Hg x 8200# 300# 7739# 1# B- 6416# 301# 213 008803# 322# - 51 132 81 213 Tl x 1783.811 27.013 7765.4311 0.1268 B- 4987.4088 27.8941 213 001915.000 29.000 - 49 131 82 213 Pb +a -3203.598 6.954 7785.1732 0.0326 B- 2028.0730 8.3708 212 996560.796 7.465 - 47 130 83 213 Bi -5231.671 5.082 7791.0217 0.0239 B- 1421.8481 5.4898 212 994383.570 5.455 - 45 129 84 213 Po -6653.519 3.053 7794.0240 0.0143 B- -73.9972 5.4646 212 992857.154 3.277 - 43 128 85 213 At -a -6579.522 4.898 7790.0036 0.0230 B- -883.5727 5.7243 212 992936.593 5.258 - 41 127 86 213 Rn -a -5695.949 3.370 7782.1824 0.0158 B- -2141.7493 5.6996 212 993885.147 3.618 - 39 126 87 213 Fr -3554.199 4.707 7768.4543 0.0221 B- -3899.7568 10.8862 212 996184.410 5.053 - 37 125 88 213 Ra 345.557 9.818 7746.4726 0.0461 B- -5795.4721 15.2463 213 000370.971 10.540 - 35 124 89 213 Ac 6141.029 11.665 7715.5908 0.0548 B- -5979.0781 14.8635 213 006592.665 12.522 - 33 123 90 213 Th -a 12120.108 9.217 7683.8470 0.0433 B- -7534.0866 57.9078 213 013011.470 9.895 - 31 122 91 213 Pa -a 19654.194 57.170 7644.8027 0.2684 B- * 213 021099.644 61.374 -0 54 134 80 214 Hg x 11770# 400# 7724# 2# B- 5306# 445# 214 012636# 429# - 52 133 81 214 Tl x 6465# 196# 7745# 1# B- 6648# 196# 214 006940# 210# - 50 132 82 214 Pb -183.019 1.969 7772.3955 0.0092 B- 1017.7611 11.2559 213 999803.521 2.114 - 48 131 83 214 Bi -1200.780 11.209 7773.4955 0.0524 B- 3269.1925 11.1649 213 998710.909 12.033 - 46 130 84 214 Po -4469.972 1.449 7785.1163 0.0068 B- -1090.8208 3.7750 213 995201.287 1.556 - 44 129 85 214 At -3379.151 3.982 7776.3632 0.0186 B- 940.5125 9.8827 213 996372.331 4.274 - 42 128 86 214 Rn -a -4319.664 9.187 7777.1023 0.0429 B- -3361.3369 12.4238 213 995362.650 9.862 - 40 127 87 214 Fr -a -958.327 8.519 7757.7393 0.0398 B- -1051.0675 9.9879 213 998971.193 9.145 - 38 126 88 214 Ra -a 92.740 5.250 7749.1719 0.0245 B- -6340.5313 14.5317 214 000099.560 5.636 - 36 125 89 214 Ac 6433.272 13.551 7715.8874 0.0633 B- -4261.6599 17.2389 214 006906.400 14.547 - 34 124 90 214 Th -a 10694.932 10.661 7692.3173 0.0498 B- -8764.9630 81.9051 214 011481.480 11.445 - 32 123 91 214 Pa -a 19459.895 81.208 7647.7037 0.3795 B- * 214 020891.055 87.180 -0 55 135 80 215 Hg x 17110# 400# 7701# 2# B- 7079# 500# 215 018368# 429# - 53 134 81 215 Tl x 10030# 300# 7730# 1# B- 5688# 305# 215 010768# 322# - 51 133 82 215 Pb +a 4342.245 52.685 7752.7381 0.2450 B- 2712.9729 52.9848 215 004661.591 56.560 - 49 132 83 215 Bi 1629.272 5.624 7761.7177 0.0262 B- 2171.0426 5.5297 215 001749.095 6.037 - 47 131 84 215 Po -541.771 2.120 7768.1768 0.0099 B- 714.8128 6.6491 214 999418.385 2.276 - 45 130 85 215 At -a -1256.583 6.629 7767.8627 0.0308 B- -87.5935 8.9062 214 998651.002 7.116 - 43 129 86 215 Rn -a -1168.990 6.090 7763.8164 0.0283 B- -1487.1274 9.1890 214 998745.037 6.538 - 41 128 87 215 Fr -a 318.137 7.066 7753.2607 0.0329 B- -2213.8573 9.7691 215 000341.534 7.585 - 39 127 88 215 Ra -a 2531.995 7.201 7739.3249 0.0335 B- -3498.5554 14.3395 215 002718.208 7.730 - 37 126 89 215 Ac -a 6030.550 12.406 7719.4137 0.0577 B- -4890.8833 13.9296 215 006474.061 13.318 - 35 125 90 215 Th -a 10921.434 6.335 7693.0266 0.0295 B- -6883.1037 82.6932 215 011724.640 6.800 - 33 124 91 215 Pa -a 17804.537 82.450 7657.3733 0.3835 B- -7084.7747 132.8246 215 019113.955 88.513 - 31 123 92 215 U -a 24889.312 104.136 7620.7821 0.4844 B- * 215 026719.774 111.794 -0 56 136 80 216 Hg x 20920# 400# 7685# 2# B- 6050# 500# 216 022459# 429# - 54 135 81 216 Tl x 14870# 300# 7709# 1# B- 7361# 361# 216 015964# 322# - 52 134 82 216 Pb x 7510# 200# 7740# 1# B- 1636# 201# 216 008062# 215# - 50 133 83 216 Bi x 5873.988 11.178 7743.4996 0.0518 B- 4091.6520 11.3243 216 006305.985 12.000 - 48 132 84 216 Po 1782.336 1.815 7758.8205 0.0084 B- -474.3423 3.5713 216 001913.416 1.948 - 46 131 85 216 At -a 2256.678 3.575 7753.0024 0.0166 B- 2003.3657 6.6383 216 002422.643 3.837 - 44 130 86 216 Rn -a 253.312 5.768 7758.6553 0.0267 B- -2717.7096 6.9366 216 000271.942 6.192 - 42 129 87 216 Fr -a 2971.022 4.174 7742.4513 0.0193 B- -320.4441 8.8904 216 003189.523 4.480 - 40 128 88 216 Ra -a 3291.466 8.004 7737.3458 0.0371 B- -4858.2701 12.2147 216 003533.534 8.592 - 38 127 89 216 Ac 8149.736 9.230 7711.2319 0.0427 B- -2148.8006 14.4375 216 008749.101 9.908 - 36 126 90 216 Th -a 10298.537 11.104 7697.6617 0.0514 B- -7525.2616 27.0327 216 011055.933 11.920 - 34 125 91 216 Pa -a 17823.799 24.647 7659.2006 0.1141 B- -5242.6308 37.3721 216 019134.633 26.459 - 32 124 92 216 U -a 23066.429 28.093 7631.3072 0.1301 B- * 216 024762.829 30.158 -0 55 136 81 217 Tl x 18660# 400# 7693# 2# B- 6399# 500# 217 020032# 429# - 53 135 82 217 Pb x 12260# 300# 7719# 1# B- 3530# 300# 217 013162# 322# - 51 134 83 217 Bi x 8729.963 17.698 7731.8491 0.0816 B- 2846.5103 18.8695 217 009372.000 19.000 - 49 133 84 217 Po +a 5883.452 6.544 7741.3614 0.0302 B- 1488.8543 7.9791 217 006316.145 7.025 - 47 132 85 217 At 4394.598 5.001 7744.6172 0.0230 B- 736.0320 6.1505 217 004717.794 5.368 - 45 131 86 217 Rn -a 3658.566 4.198 7744.4037 0.0193 B- -656.0967 7.5383 217 003927.632 4.506 - 43 130 87 217 Fr -a 4314.663 6.531 7737.7750 0.0301 B- -1574.8729 9.4723 217 004631.980 7.011 - 41 129 88 217 Ra -a 5889.536 7.047 7726.9122 0.0325 B- -2812.7853 13.2129 217 006322.676 7.564 - 39 128 89 217 Ac -a 8702.321 11.223 7710.3448 0.0517 B- -3503.4590 15.4454 217 009342.325 12.048 - 37 127 90 217 Th -a 12205.780 10.614 7690.5945 0.0489 B- -4848.9680 16.3966 217 013103.443 11.394 - 35 126 91 217 Pa -a 17054.748 12.498 7664.6438 0.0576 B- -5916# 81# 217 018309.024 13.417 - 33 125 92 217 U -a 22971# 81# 7634# 0# B- * 217 024660# 86# -0 56 137 81 218 Tl x 23710# 400# 7672# 2# B- 8081# 500# 218 025454# 429# - 54 136 82 218 Pb x 15630# 300# 7705# 1# B- 2414# 301# 218 016779# 322# - 52 135 83 218 Bi x 13216.038 27.013 7712.8280 0.1239 B- 4859.3866 27.0849 218 014188.000 29.000 - 50 134 84 218 Po 8356.652 1.967 7731.5300 0.0090 B- 256.4334 11.5490 218 008971.234 2.112 - 48 133 85 218 At -a 8100.218 11.503 7729.1175 0.0528 B- 2882.8048 11.6054 218 008695.941 12.349 - 46 132 86 218 Rn 5217.413 2.316 7738.7527 0.0106 B- -1842.0267 4.4418 218 005601.123 2.486 - 44 131 87 218 Fr -a 7059.440 4.235 7726.7143 0.0194 B- 413.8838 10.5603 218 007578.620 4.546 - 42 130 88 218 Ra -a 6645.556 9.807 7725.0241 0.0450 B- -4205.2887 58.4224 218 007134.297 10.528 - 40 129 89 218 Ac -a 10850.845 57.616 7702.1450 0.2643 B- -1515.9019 58.5648 218 011648.860 61.853 - 38 128 90 218 Th -a 12366.747 10.516 7691.6026 0.0482 B- -6282.8212 20.7132 218 013276.248 11.289 - 36 127 91 218 Pa -a 18649.568 17.846 7659.1935 0.0819 B- -3245.0869 22.5042 218 020021.133 19.158 - 34 126 92 218 U -a 21894.655 13.714 7640.7191 0.0629 B- * 218 023504.877 14.722 -0 55 137 82 219 Pb x 20620# 400# 7684# 2# B- 4300# 447# 219 022136# 429# - 53 136 83 219 Bi x 16320# 200# 7700# 1# B- 3638# 201# 219 017520# 215# - 51 135 84 219 Po x 12681.361 15.835 7713.3340 0.0723 B- 2285.3395 16.1628 219 013614.000 17.000 - 49 134 85 219 At 10396.021 3.237 7720.1970 0.0148 B- 1566.6838 2.9473 219 011160.587 3.474 - 47 133 86 219 Rn 8829.337 2.100 7723.7784 0.0096 B- 212.3984 6.8938 219 009478.683 2.254 - 45 132 87 219 Fr -a 8616.939 6.874 7721.1759 0.0314 B- -776.9137 9.5906 219 009250.664 7.380 - 43 131 88 219 Ra -a 9393.853 6.814 7714.0560 0.0311 B- -2175.7005 51.9016 219 010084.715 7.315 - 41 130 89 219 Ac -a 11569.553 51.477 7700.5489 0.2351 B- -2893.2268 76.3627 219 012420.425 55.263 - 39 129 90 219 Th -a 14462.780 56.460 7683.7655 0.2578 B- -4120.4434 89.7010 219 015526.432 60.611 - 37 128 91 219 Pa -a 18583.223 69.705 7661.3783 0.3183 B- -4712.7298 70.9693 219 019949.909 74.831 - 35 127 92 219 U -a 23295.953 13.338 7636.2867 0.0609 B- -6140.9976 92.9309 219 025009.233 14.319 - 33 126 93 219 Np -a 29436.951 91.969 7604.6732 0.4199 B- * 219 031601.865 98.732 -0 56 138 82 220 Pb x 24130# 400# 7670# 2# B- 3171# 500# 220 025905# 429# - 54 137 83 220 Bi x 20960# 300# 7681# 1# B- 5696# 300# 220 022501# 322# - 52 136 84 220 Po x 15263.462 17.698 7703.2244 0.0804 B- 887.7139 22.5491 220 016386.000 19.000 - 50 135 85 220 At x 14375.748 13.972 7703.7033 0.0635 B- 3763.7550 14.0896 220 015433.000 15.000 - 48 134 86 220 Rn 10611.994 1.814 7717.2552 0.0082 B- -870.3384 4.0256 220 011392.443 1.947 - 46 133 87 220 Fr -a 11482.332 4.028 7709.7430 0.0183 B- 1210.2406 8.4809 220 012326.789 4.324 - 44 132 88 220 Ra -a 10272.091 7.595 7711.6879 0.0345 B- -3471.6640 9.6266 220 011027.542 8.153 - 42 131 89 220 Ac -a 13743.755 6.129 7692.3515 0.0279 B- -945.7825 14.9144 220 014754.527 6.579 - 40 130 90 220 Th -a 14689.538 13.687 7684.4964 0.0622 B- -5588.8595 20.0508 220 015769.866 14.693 - 38 129 91 220 Pa -a 20278.397 14.655 7655.5364 0.0666 B- -2735# 102# 220 021769.753 15.732 - 36 128 92 220 U -a 23013# 101# 7640# 0# B- -7462# 105# 220 024706# 108# - 34 127 93 220 Np -a 30475.022 30.718 7602.0758 0.1396 B- * 220 032716.280 32.977 -0 55 138 83 221 Bi x 24200# 300# 7668# 1# B- 4426# 301# 221 025980# 322# - 53 137 84 221 Po x 19773.757 19.561 7684.4814 0.0885 B- 2991.0276 24.0390 221 021228.000 21.000 - 51 136 85 221 At x 16782.729 13.972 7694.4754 0.0632 B- 2311.3750 15.0957 221 018017.000 15.000 - 49 135 86 221 Rn +a 14471.354 5.714 7701.3941 0.0259 B- 1194.1032 7.2312 221 015535.637 6.134 - 47 134 87 221 Fr 13277.251 4.886 7703.2572 0.0221 B- 313.3741 6.3858 221 014253.714 5.245 - 45 133 88 221 Ra -a 12963.877 4.630 7701.1352 0.0210 B- -1567.1715 57.0591 221 013917.293 4.970 - 43 132 89 221 Ac -a 14531.048 56.901 7690.5039 0.2575 B- -2408.8773 57.4376 221 015599.721 61.086 - 41 131 90 221 Th -a 16939.926 7.994 7676.0640 0.0362 B- -3435.0112 59.9069 221 018185.757 8.582 - 39 130 91 221 Pa -a 20374.937 59.380 7656.9809 0.2687 B- -4145.0590 93.4311 221 021873.393 63.746 - 37 129 92 221 U -a 24519.996 72.135 7634.6849 0.3264 B- -5390# 213# 221 026323.297 77.440 - 35 128 93 221 Np x 29910# 200# 7607# 1# B- -6019# 361# 221 032110# 215# - 33 127 94 221 Pu x 35930# 300# 7576# 1# B- * 221 038572# 322# -0 56 139 83 222 Bi x 28950# 300# 7648# 1# B- 6464# 303# 222 031079# 322# - 54 138 84 222 Po x 22486.268 40.054 7674.0054 0.1804 B- 1533.2393 43.0709 222 024140.000 43.000 - 52 137 85 222 At x 20953.028 15.835 7677.3878 0.0713 B- 4581.0714 15.9542 222 022494.000 17.000 - 50 136 86 222 Rn 16371.957 1.944 7694.4991 0.0088 B- -6.1461 7.7013 222 017576.017 2.086 - 48 135 87 222 Fr x 16378.103 7.452 7690.9474 0.0336 B- 2057.8980 8.6816 222 017582.615 8.000 - 46 134 88 222 Ra 14320.205 4.454 7696.6931 0.0201 B- -2301.5922 6.2737 222 015373.371 4.781 - 44 133 89 222 Ac -a 16621.797 4.699 7682.8015 0.0212 B- -581.2415 11.1289 222 017844.232 5.044 - 42 132 90 222 Th -a 17203.039 10.216 7676.6592 0.0460 B- -4861.3220 87.1915 222 018468.220 10.966 - 40 131 91 222 Pa -a 22064.361 86.606 7651.2373 0.3901 B- -2208.4729 101.0129 222 023687.064 92.975 - 38 130 92 222 U -a 24272.834 51.994 7637.7651 0.2342 B- -7001.8072 64.4300 222 026057.957 55.817 - 36 129 93 222 Np -a 31274.641 38.051 7602.7013 0.1714 B- -3785# 302# 222 033574.706 40.849 - 34 128 94 222 Pu x 35060# 300# 7582# 1# B- * 222 037638# 322# -0 57 140 83 223 Bi x 32240# 400# 7636# 2# B- 5161# 445# 223 034611# 429# - 55 139 84 223 Po x 27079# 196# 7655# 1# B- 3651# 196# 223 029070# 210# - 53 138 85 223 At x 23428.008 13.972 7668.0557 0.0627 B- 3038.2698 16.0129 223 025151.000 15.000 - 51 137 86 223 Rn 20389.738 7.822 7678.1720 0.0351 B- 2007.4091 8.0568 223 021889.283 8.397 - 49 136 87 223 Fr 18382.329 1.931 7683.6655 0.0087 B- 1149.0844 0.8476 223 019734.241 2.073 - 47 135 88 223 Ra 17233.245 2.090 7685.3101 0.0094 B- -591.8099 6.9657 223 018500.648 2.243 - 45 134 89 223 Ac -a 17825.055 6.947 7679.1479 0.0312 B- -1560.3471 10.4712 223 019135.982 7.457 - 43 133 90 223 Th -a 19385.402 7.943 7668.6426 0.0356 B- -2952.2124 76.0305 223 020811.083 8.527 - 41 132 91 223 Pa -a 22337.614 75.632 7651.8957 0.3392 B- -3707.6637 95.9225 223 023980.414 81.193 - 39 131 92 223 U -a 26045.278 59.054 7631.7611 0.2648 B- -4613.3046 101.7520 223 027960.754 63.396 - 37 130 93 223 Np -a 30658.583 82.863 7607.5654 0.3716 B- -5462# 311# 223 032913.340 88.956 - 35 129 94 223 Pu x 36121# 300# 7580# 1# B- -6579# 424# 223 038777# 322# - 33 128 95 223 Am x 42700# 300# 7547# 1# B- * 223 045840# 322# -0 58 141 83 224 Bi x 37070# 400# 7616# 2# B- 7159# 445# 224 039796# 429# - 56 140 84 224 Po x 29910# 196# 7644# 1# B- 2199# 197# 224 032110# 210# - 54 139 85 224 At x 27711.018 22.356 7650.7354 0.0998 B- 5265.9197 24.4153 224 029749.000 24.000 - 52 138 86 224 Rn 22445.098 9.814 7670.7514 0.0438 B- 696.4840 14.8750 224 024095.803 10.536 - 50 137 87 224 Fr x 21748.614 11.178 7670.3680 0.0499 B- 2922.7819 11.3237 224 023348.096 12.000 - 48 136 88 224 Ra 18825.832 1.811 7679.9236 0.0081 B- -1408.3152 4.0869 224 020210.361 1.944 - 46 135 89 224 Ac -a 20234.148 4.089 7670.1438 0.0183 B- 238.5672 10.3428 224 021722.249 4.389 - 44 134 90 224 Th -a 19995.581 9.604 7667.7162 0.0429 B- -3866.7705 12.1339 224 021466.137 10.310 - 42 133 91 224 Pa -a 23862.351 7.587 7646.9612 0.0339 B- -1880.3393 16.9711 224 025617.286 8.145 - 40 132 92 224 U -a 25742.690 15.261 7635.0742 0.0681 B- -6289.5572 32.7036 224 027635.913 16.383 - 38 131 93 224 Np 32032.248 28.925 7603.5032 0.1291 B- -3248# 301# 224 034388.030 31.052 - 36 130 94 224 Pu x 35280# 300# 7586# 1# B- -7980# 500# 224 037875# 322# - 34 129 95 224 Am x 43260# 400# 7546# 2# B- * 224 046442# 429# -0 57 141 84 225 Po x 34580# 300# 7626# 1# B- 4280# 424# 225 037123# 322# - 55 140 85 225 At x 30300# 300# 7641# 1# B- 3765# 300# 225 032528# 322# - 53 139 86 225 Rn 26534.143 11.140 7654.3581 0.0495 B- 2713.5412 16.3492 225 028485.572 11.958 - 51 138 87 225 Fr 23820.602 11.967 7662.9412 0.0532 B- 1827.5584 12.1574 225 025572.466 12.847 - 49 137 88 225 Ra 21993.044 2.596 7667.5866 0.0115 B- 355.7386 5.0067 225 023610.502 2.786 - 47 136 89 225 Ac 21637.305 4.758 7665.6906 0.0211 B- -672.8878 6.6576 225 023228.601 5.107 - 45 135 90 225 Th -a 22310.193 5.093 7659.2229 0.0226 B- -2046.4473 82.0038 225 023950.975 5.467 - 43 134 91 225 Pa -a 24356.640 81.867 7646.6504 0.3639 B- -3015.3610 82.4514 225 026147.927 87.887 - 41 133 92 225 U -a 27372.001 9.934 7629.7717 0.0442 B- -4246.0969 92.1491 225 029385.050 10.664 - 39 132 93 225 Np -a 31618.098 91.618 7607.4231 0.4072 B- -4682# 314# 225 033943.422 98.355 - 37 131 94 225 Pu x 36300# 300# 7583# 1# B- -6090# 500# 225 038970# 322# - 35 130 95 225 Am x 42390# 400# 7553# 2# B- * 225 045508# 429# -0 58 142 84 226 Po x 37549# 401# 7614# 2# B- 2889# 500# 226 040310# 430# - 56 141 85 226 At x 34660# 300# 7624# 1# B- 5913# 300# 226 037209# 322# - 54 140 86 226 Rn 28747.194 10.477 7646.4108 0.0464 B- 1226.6542 12.1895 226 030861.380 11.247 - 52 139 87 226 Fr 27520.539 6.230 7648.3768 0.0276 B- 3852.9638 6.5215 226 029544.512 6.688 - 50 138 88 226 Ra 23667.576 1.927 7661.9636 0.0085 B- -641.6252 3.2730 226 025408.186 2.068 - 48 137 89 226 Ac 24309.201 3.100 7655.6628 0.0137 B- 1111.5517 4.5626 226 026096.999 3.327 - 46 136 90 226 Th 23197.649 4.481 7657.1195 0.0198 B- -2835.9504 11.9702 226 024903.699 4.810 - 44 135 91 226 Pa -a 26033.600 11.213 7641.1093 0.0496 B- -1295.1978 15.6747 226 027948.217 12.037 - 42 134 92 226 U -a 27328.797 11.071 7631.9166 0.0490 B- -5488.0792 102.6485 226 029338.669 11.884 - 40 133 93 226 Np -a 32816.877 102.063 7604.1714 0.4516 B- -2813# 225# 226 035230.364 109.568 - 38 132 94 226 Pu x 35630# 200# 7588# 1# B- -7340# 361# 226 038250# 215# - 36 131 95 226 Am x 42970# 300# 7552# 1# B- * 226 046130# 322# -0 59 143 84 227 Po x 42281# 401# 7596# 2# B- 4850# 500# 227 045390# 430# - 57 142 85 227 At x 37430# 300# 7613# 1# B- 4544# 300# 227 040183# 322# - 55 141 86 227 Rn 32885.835 14.091 7630.0508 0.0621 B- 3203.3894 15.2755 227 035304.393 15.127 - 53 140 87 227 Fr 29682.445 5.898 7640.7162 0.0260 B- 2504.9813 6.2112 227 031865.413 6.332 - 51 139 88 227 Ra -n 27177.464 1.946 7648.3048 0.0086 B- 1327.9489 2.2622 227 029176.205 2.089 - 49 138 89 227 Ac 25849.515 1.926 7650.7084 0.0085 B- 44.7559 0.8297 227 027750.594 2.068 - 47 137 90 227 Th 25804.759 2.088 7647.4591 0.0092 B- -1025.6117 7.2815 227 027702.546 2.241 - 45 136 91 227 Pa -a 26830.371 7.263 7639.4945 0.0320 B- -2214.6629 11.1118 227 028803.586 7.797 - 43 135 92 227 U -a 29045.034 8.510 7626.2918 0.0375 B- -3533.9848 77.4417 227 031181.124 9.136 - 41 134 93 227 Np -a 32579.018 76.989 7607.2771 0.3392 B- -4191# 126# 227 034975.012 82.651 - 39 133 94 227 Pu x 36770# 100# 7585# 0# B- -5410# 224# 227 039474# 107# - 37 132 95 227 Am x 42180# 200# 7558# 1# B- * 227 045282# 215# -0 58 143 85 228 At x 41880# 400# 7596# 2# B- 6637# 400# 228 044960# 429# - 56 142 86 228 Rn 35243.466 17.677 7621.6457 0.0775 B- 1859.2451 18.9157 228 037835.415 18.977 - 54 141 87 228 Fr 33384.221 6.732 7626.3689 0.0295 B- 4444.0270 7.0210 228 035839.433 7.226 - 52 140 88 228 Ra +a 28940.194 1.995 7642.4289 0.0088 B- 45.5402 0.6344 228 031068.574 2.141 - 50 139 89 228 Ac - 28894.654 2.093 7639.1973 0.0092 B- 2123.7545 2.6446 228 031019.685 2.247 - 48 138 90 228 Th 26770.899 1.806 7645.0807 0.0079 B- -2152.6993 4.3399 228 028739.741 1.938 - 46 137 91 228 Pa -a 28923.599 4.340 7632.2076 0.0190 B- -296.4020 14.0858 228 031050.758 4.659 - 44 136 92 228 U -a 29220.001 13.474 7627.4763 0.0591 B- -4605# 101# 228 031368.959 14.465 - 42 135 93 228 Np -a 33825# 100# 7604# 0# B- -2283# 103# 228 036313# 108# - 40 134 94 228 Pu -a 36107.809 23.352 7590.4039 0.1024 B- -6742# 202# 228 038763.325 25.069 - 38 133 95 228 Am x 42850# 200# 7557# 1# B- * 228 046001# 215# -0 59 144 85 229 At x 44890# 400# 7585# 2# B- 5527# 400# 229 048191# 429# - 57 143 86 229 Rn x 39362.400 13.041 7605.6227 0.0569 B- 3694.1465 13.9670 229 042257.272 14.000 - 55 142 87 229 Fr 35668.253 5.001 7618.3380 0.0218 B- 3106.2907 16.2305 229 038291.443 5.368 - 53 141 88 229 Ra x 32561.963 15.441 7628.4862 0.0674 B- 1872.0266 19.6229 229 034956.703 16.576 - 51 140 89 229 Ac x 30689.936 12.109 7633.2446 0.0529 B- 1104.4191 12.3458 229 032947.000 13.000 - 49 139 90 229 Th 29585.517 2.404 7634.6510 0.0105 B- -311.3310 3.7152 229 031761.357 2.581 - 47 138 91 229 Pa 29896.848 3.280 7629.8752 0.0143 B- -1313.7716 6.6554 229 032095.585 3.521 - 45 137 92 229 U -a 31210.620 5.938 7620.7218 0.0259 B- -2590.7577 101.3342 229 033505.976 6.374 - 43 136 93 229 Np -a 33801.378 101.177 7605.9921 0.4418 B- -3593.5462 117.9433 229 036287.269 108.618 - 41 135 94 229 Pu -a 37394.924 60.633 7586.8834 0.2648 B- -4785.4899 122.4147 229 040145.099 65.092 - 39 134 95 229 Am -a 42180.414 106.348 7562.5697 0.4644 B- * 229 045282.534 114.169 -0 58 144 86 230 Rn x 42170# 200# 7595# 1# B- 2683# 200# 230 045271# 215# - 56 143 87 230 Fr 39486.769 6.541 7603.7052 0.0284 B- 4970.4627 12.1984 230 042390.787 7.022 - 54 142 88 230 Ra x 34516.306 10.296 7621.9144 0.0448 B- 677.9196 18.8884 230 037054.776 11.053 - 52 141 89 230 Ac x 33838.386 15.835 7621.4604 0.0689 B- 2975.8745 15.8815 230 036327.000 17.000 - 50 140 90 230 Th 30862.512 1.209 7630.9974 0.0053 B- -1311.0313 2.8334 230 033132.267 1.297 - 48 139 91 230 Pa 32173.543 3.038 7621.8958 0.0132 B- 558.5262 4.5919 230 034539.717 3.261 - 46 138 92 230 U -a 31615.017 4.509 7620.9227 0.0196 B- -3621.5986 55.1683 230 033940.114 4.841 - 44 137 93 230 Np -a 35236.615 55.007 7601.7751 0.2392 B- -1695.5543 56.8505 230 037828.060 59.051 - 42 136 94 230 Pu -a 36932.170 14.451 7591.0016 0.0628 B- -5940# 144# 230 039648.313 15.514 - 40 135 95 230 Am -a 42872# 143# 7562# 1# B- * 230 046025# 153# -0 59 145 86 231 Rn x 46550# 300# 7579# 1# B- 4469# 300# 231 049973# 322# - 57 144 87 231 Fr x 42080.575 7.731 7594.5009 0.0335 B- 3864.0868 13.7495 231 045175.353 8.300 - 55 143 88 231 Ra 38216.488 11.370 7607.8418 0.0492 B- 2453.6351 17.3014 231 041027.085 12.206 - 53 142 89 231 Ac x 35762.853 13.041 7615.0768 0.0565 B- 1947.0425 13.0976 231 038393.000 14.000 - 51 141 90 231 Th 33815.811 1.217 7620.1188 0.0053 B- 391.4727 1.4598 231 036302.764 1.306 - 49 140 91 231 Pa 33424.338 1.771 7618.4267 0.0077 B- -381.6138 2.0325 231 035882.500 1.901 - 47 139 92 231 U -a 33805.952 2.670 7613.3879 0.0116 B- -1817.7347 51.1839 231 036292.180 2.866 - 45 138 93 231 Np -a 35623.686 51.154 7602.1321 0.2214 B- -2684.8905 55.6931 231 038243.598 54.916 - 43 137 94 231 Pu -a 38308.577 22.061 7587.1224 0.0955 B- -4101# 301# 231 041125.946 23.683 - 41 136 95 231 Am x 42410# 300# 7566# 1# B- -4860# 424# 231 045529# 322# - 39 135 96 231 Cm x 47270# 300# 7542# 1# B- * 231 050746# 322# -0 58 145 87 232 Fr x 46072.834 13.972 7579.3481 0.0602 B- 5575.8791 16.7023 232 049461.219 15.000 - 56 144 88 232 Ra 40496.955 9.151 7600.0099 0.0394 B- 1342.5322 15.9313 232 043475.267 9.823 - 54 143 89 232 Ac x 39154.423 13.041 7602.4245 0.0562 B- 3707.7131 13.1181 232 042034.000 14.000 - 52 142 90 232 Th 35446.710 1.421 7615.0338 0.0061 B- -499.8388 7.7338 232 038053.606 1.525 - 50 141 91 232 Pa + 35946.549 7.645 7609.5072 0.0330 B- 1337.1034 7.4278 232 038590.205 8.206 - 48 140 92 232 U 34609.445 1.808 7611.8984 0.0078 B- -2750# 100# 232 037154.765 1.941 - 46 139 93 232 Np - 37359# 100# 7597# 0# B- -1001# 101# 232 040107# 107# - 44 138 94 232 Pu -a 38360.915 16.885 7588.9839 0.0728 B- -5059# 300# 232 041182.133 18.126 - 42 137 95 232 Am x 43420# 300# 7564# 1# B- -2913# 361# 232 046613# 322# - 40 136 96 232 Cm -a 46333# 201# 7548# 1# B- * 232 049740# 216# -0 59 146 87 233 Fr x 48920.052 19.561 7569.2398 0.0840 B- 4585.9906 21.3694 233 052517.833 21.000 - 57 145 88 233 Ra 44334.062 8.603 7585.5644 0.0369 B- 3026.0244 15.6228 233 047594.570 9.235 - 55 144 89 233 Ac x 41308.037 13.041 7595.1939 0.0560 B- 2576.3950 13.1184 233 044346.000 14.000 - 53 143 90 233 Th 38731.642 1.424 7602.8937 0.0061 B- 1242.2320 1.1224 233 041580.126 1.528 - 51 142 91 233 Pa 37489.410 1.336 7604.8675 0.0057 B- 570.2993 1.9750 233 040246.535 1.433 - 49 141 92 233 U 36919.111 2.254 7603.9574 0.0097 B- -1029.4197 51.0050 233 039634.294 2.420 - 47 140 93 233 Np -a 37948.531 50.981 7596.1816 0.2188 B- -2103.3047 74.3811 233 040739.421 54.729 - 45 139 94 233 Pu -a 40051.836 54.178 7583.7968 0.2325 B- -3233# 126# 233 042997.411 58.162 - 43 138 95 233 Am -a 43285# 114# 7567# 0# B- -4008# 140# 233 046468# 123# - 41 137 96 233 Cm -a 47293.340 81.095 7546.0020 0.3480 B- -5478# 247# 233 050771.485 87.059 - 39 136 97 233 Bk -a 52771# 233# 7519# 1# B- * 233 056652# 250# -0 58 146 88 234 Ra x 46930.629 8.383 7576.5439 0.0358 B- 2089.4348 16.2945 234 050382.100 9.000 - 56 145 89 234 Ac x 44841.195 13.972 7582.1297 0.0597 B- 4228.2364 14.2103 234 048139.000 15.000 - 54 144 90 234 Th +a 40612.958 2.589 7596.8557 0.0111 B- 274.0882 3.1716 234 043599.801 2.779 - 52 143 91 234 Pa IT 40338.870 4.094 7594.6837 0.0175 B- 2193.9105 3.9998 234 043305.555 4.395 - 50 142 92 234 U 38144.959 1.129 7600.7160 0.0048 B- -1809.8462 8.3205 234 040950.296 1.212 - 48 141 93 234 Np - 39954.806 8.397 7589.6382 0.0359 B- -395.1807 10.7522 234 042893.245 9.014 - 46 140 94 234 Pu -a 40349.986 6.798 7584.6061 0.0291 B- -4112# 160# 234 043317.489 7.298 - 44 139 95 234 Am -a 44462# 160# 7564# 1# B- -2261# 161# 234 047731# 172# - 42 138 96 234 Cm -a 46722.411 17.078 7550.6868 0.0730 B- -6673# 154# 234 050158.568 18.333 - 40 137 97 234 Bk -a 53395# 153# 7519# 1# B- * 234 057322# 164# -0 59 147 88 235 Ra x 51130# 300# 7561# 1# B- 3773# 300# 235 054890# 322# - 57 146 89 235 Ac x 47357.160 13.972 7573.5051 0.0595 B- 3339.4064 19.1127 235 050840.000 15.000 - 55 145 90 235 Th x 44017.754 13.041 7584.3862 0.0555 B- 1728.8531 19.1127 235 047255.000 14.000 - 53 144 91 235 Pa x 42288.901 13.972 7588.4139 0.0595 B- 1370.1184 14.0169 235 045399.000 15.000 - 51 143 92 235 U 40918.782 1.116 7590.9151 0.0048 B- -124.2619 0.8524 235 043928.117 1.198 - 49 142 93 235 Np 41043.044 1.388 7587.0571 0.0059 B- -1139.3021 20.4992 235 044061.518 1.490 - 47 141 94 235 Pu -a 42182.346 20.521 7578.8799 0.0873 B- -2442.2558 56.5932 235 045284.609 22.030 - 45 140 95 235 Am -a 44624.602 52.780 7565.1582 0.2246 B- -3389# 115# 235 047906.478 56.661 - 43 139 96 235 Cm -a 48013# 102# 7547# 0# B- -4757# 413# 235 051545# 110# - 41 138 97 235 Bk x 52770# 401# 7524# 2# B- * 235 056651# 430# -0 58 147 89 236 Ac x 51220.998 38.191 7559.2423 0.1618 B- 4965.7951 40.6669 236 054988.000 41.000 - 56 146 90 236 Th x 46255.203 13.972 7576.9688 0.0592 B- 921.2477 19.7600 236 049657.000 15.000 - 54 145 91 236 Pa x 45333.955 13.972 7577.5573 0.0592 B- 2889.3730 14.0166 236 048668.000 15.000 - 52 144 92 236 U 42444.582 1.112 7586.4854 0.0047 B- -933.5116 50.4152 236 045566.130 1.193 - 50 143 93 236 Np IT 43378.094 50.421 7579.2148 0.2136 B- 476.5854 50.3887 236 046568.296 54.129 - 48 142 94 236 Pu 42901.508 1.810 7577.9192 0.0077 B- -3139# 119# 236 046056.661 1.942 - 46 141 95 236 Am -a 46041# 119# 7561# 1# B- -1812# 120# 236 049427# 127# - 44 140 96 236 Cm -a 47852.820 17.635 7550.3090 0.0747 B- -5689# 361# 236 051372.112 18.931 - 42 139 97 236 Bk -a 53542# 361# 7523# 2# B- * 236 057479# 387# -0 59 148 89 237 Ac x 54020# 400# 7550# 2# B- 4065# 400# 237 057993# 429# - 57 147 90 237 Th x 49955.097 15.835 7563.4433 0.0668 B- 2427.4736 20.5140 237 053629.000 17.000 - 55 146 91 237 Pa x 47527.624 13.041 7570.3847 0.0550 B- 2137.4905 13.0962 237 051023.000 14.000 - 53 145 92 237 U 45390.133 1.202 7576.1026 0.0051 B- 518.5338 0.5200 237 048728.309 1.290 - 51 144 93 237 Np 44871.599 1.120 7574.9895 0.0047 B- -220.0630 1.2944 237 048171.640 1.201 - 49 143 94 237 Pu 45091.662 1.697 7570.7599 0.0072 B- -1478# 59# 237 048407.888 1.821 - 47 142 95 237 Am -a 46570# 59# 7561# 0# B- -2677# 95# 237 049995# 64# - 45 141 96 237 Cm -a 49247.151 74.399 7546.6241 0.3139 B- -3963# 242# 237 052868.988 79.870 - 43 140 97 237 Bk -a 53210# 230# 7527# 1# B- -4728# 250# 237 057123# 247# - 41 139 98 237 Cf -a 57938.255 97.347 7503.3507 0.4107 B- * 237 062199.272 104.506 -0 58 148 90 238 Th +a 52525# 283# 7555# 1# B- 1631# 284# 238 056388# 304# - 56 147 91 238 Pa x 50894.043 15.835 7558.3449 0.0665 B- 3586.3111 15.9056 238 054637.000 17.000 - 54 146 92 238 U 47307.732 1.492 7570.1262 0.0063 B- -146.8652 1.2006 238 050786.936 1.601 - 52 145 93 238 Np -n 47454.597 1.137 7566.2220 0.0048 B- 1291.4491 0.4573 238 050944.603 1.220 - 50 144 94 238 Pu 46163.148 1.138 7568.3611 0.0048 B- -2258.2731 58.9005 238 049558.175 1.221 - 48 143 95 238 Am -a 48421.421 58.911 7555.5853 0.2475 B- -1023.7818 60.1587 238 051982.531 63.243 - 46 142 96 238 Cm -a 49445.203 12.234 7547.9966 0.0514 B- -4771# 256# 238 053081.606 13.133 - 44 141 97 238 Bk -a 54216# 256# 7525# 1# B- -3061# 393# 238 058204# 275# - 42 140 98 238 Cf x 57278# 298# 7509# 1# B- * 238 061490# 320# -0 59 149 90 239 Th x 56500# 400# 7540# 2# B- 3162# 445# 239 060655# 429# - 57 148 91 239 Pa x 53337# 196# 7550# 1# B- 2765# 196# 239 057260# 210# - 55 147 92 239 U -n 50572.668 1.502 7558.5624 0.0063 B- 1261.6634 1.4935 239 054291.989 1.612 - 53 146 93 239 Np 49311.005 1.310 7560.5680 0.0055 B- 722.7849 0.9304 239 052937.538 1.406 - 51 145 94 239 Pu 48588.220 1.112 7560.3187 0.0047 B- -802.1402 1.6635 239 052161.596 1.194 - 49 144 95 239 Am -a 49390.360 1.982 7553.6891 0.0083 B- -1756.6021 150.0740 239 053022.729 2.127 - 47 143 96 239 Cm -a 51146.962 150.070 7543.0659 0.6279 B- -3103# 256# 239 054908.519 161.107 - 45 142 97 239 Bk -a 54250# 207# 7527# 1# B- -3952# 239# 239 058239# 222# - 43 141 98 239 Cf -a 58202# 120# 7507# 1# B- -5429# 323# 239 062482# 129# - 41 140 99 239 Es x 63630# 300# 7481# 1# B- * 239 068310# 322# -0 58 149 91 240 Pa x 57010# 200# 7537# 1# B- 4295# 200# 240 061203# 215# - 56 148 92 240 U 52715.497 2.553 7551.7705 0.0106 B- 399.2685 17.0830 240 056592.411 2.740 - 54 147 93 240 Np 52316.229 17.032 7550.1743 0.0710 B- 2190.9095 17.0151 240 056163.778 18.284 - 52 146 94 240 Pu 50125.319 1.105 7556.0433 0.0046 B- -1384.7902 13.7882 240 053811.740 1.186 - 50 145 95 240 Am +n 51510.110 13.832 7547.0136 0.0576 B- -214.1127 13.8967 240 055298.374 14.849 - 48 144 96 240 Cm 51724.222 1.905 7542.8617 0.0079 B- -3940# 150# 240 055528.233 2.045 - 46 143 97 240 Bk - 55664# 150# 7523# 1# B- -2324# 151# 240 059758# 161# - 44 142 98 240 Cf -a 57988.719 18.034 7510.2400 0.0751 B- -6237# 366# 240 062253.447 19.360 - 42 141 99 240 Es -a 64225# 366# 7481# 2# B- * 240 068949# 393# -0 59 150 91 241 Pa x 59740# 300# 7528# 1# B- 3543# 358# 241 064134# 322# - 57 149 92 241 U x 56197# 196# 7539# 1# B- 1882# 220# 241 060330# 210# - 55 148 93 241 Np + 54315.115 100.006 7544.0426 0.4150 B- 1360.0000 100.0000 241 058309.671 107.360 - 53 147 94 241 Pu 52955.115 1.105 7546.4395 0.0046 B- 20.7799 0.1658 241 056849.651 1.186 - 51 146 95 241 Am 52934.335 1.113 7543.2795 0.0046 B- -767.4346 1.1685 241 056827.343 1.195 - 49 145 96 241 Cm 53701.770 1.607 7536.8488 0.0067 B- -2279# 165# 241 057651.218 1.725 - 47 144 97 241 Bk +a 55981# 165# 7524# 1# B- -3346# 235# 241 060098# 178# - 45 143 98 241 Cf -a 59327# 167# 7507# 1# B- -4567# 285# 241 063690# 180# - 43 142 99 241 Es -a 63893# 231# 7485# 1# B- -5327# 379# 241 068592# 248# - 41 141 100 241 Fm x 69220# 300# 7459# 1# B- * 241 074311# 322# -0 58 150 92 242 U +a 58620# 201# 7532# 1# B- 1203# 283# 242 062931# 215# - 56 149 93 242 Np + 57416.876 200.004 7533.4042 0.8265 B- 2700.0000 200.0000 242 061639.548 214.712 - 54 148 94 242 Pu 54716.876 1.245 7541.3284 0.0052 B- -751.1373 0.7080 242 058740.979 1.336 - 52 147 95 242 Am -n 55468.014 1.118 7534.9917 0.0046 B- 664.3145 0.4143 242 059547.358 1.199 - 50 146 96 242 Cm 54803.699 1.141 7534.5040 0.0047 B- -2948# 135# 242 058834.187 1.224 - 48 145 97 242 Bk IT 57752# 135# 7519# 1# B- -1635# 135# 242 061999# 144# - 46 144 98 242 Cf -a 59386.982 12.892 7509.0991 0.0533 B- -5414# 257# 242 063754.544 13.840 - 44 143 99 242 Es -a 64801# 257# 7483# 1# B- -3598# 476# 242 069567# 276# - 42 142 100 242 Fm x 68400# 401# 7465# 2# B- * 242 073430# 430# -0 59 151 92 243 U x 62480# 300# 7518# 1# B- 2674# 302# 243 067075# 322# - 57 150 93 243 Np IT 59806# 32# 7526# 0# B- 2051# 32# 243 064204# 34# - 55 149 94 243 Pu 57754.561 2.542 7531.0087 0.0105 B- 579.5559 2.6216 243 062002.068 2.728 - 53 148 95 243 Am 57175.005 1.388 7530.1742 0.0057 B- -6.9302 1.5692 243 061379.889 1.490 - 51 147 96 243 Cm -a 57181.936 1.496 7526.9261 0.0062 B- -1507.6936 4.5065 243 061387.329 1.605 - 49 146 97 243 Bk -a 58689.629 4.524 7517.5021 0.0186 B- -2300# 181# 243 063005.905 4.856 - 47 145 98 243 Cf -a 60990# 181# 7505# 1# B- -3757# 275# 243 065475# 194# - 45 144 99 243 Es -a 64747# 207# 7486# 1# B- -4569# 245# 243 069508# 222# - 43 143 100 243 Fm -a 69316# 130# 7464# 1# B- * 243 074414# 140# -0 58 151 93 244 Np x 63240# 100# 7514# 0# B- 3434# 100# 244 067891# 107# - 56 150 94 244 Pu 59806.021 2.346 7524.8154 0.0096 B- -73.1143 2.6856 244 064204.401 2.518 - 54 149 95 244 Am + 59879.135 1.491 7521.3095 0.0061 B- 1427.3000 1.0000 244 064282.892 1.600 - 52 148 96 244 Cm -a 58451.835 1.106 7523.9527 0.0045 B- -2261.9902 14.3567 244 062750.622 1.187 - 50 147 97 244 Bk -a 60713.825 14.399 7511.4759 0.0590 B- -764.2709 14.5724 244 065178.969 15.457 - 48 146 98 244 Cf 61478.096 2.617 7505.1373 0.0107 B- -4547# 181# 244 065999.447 2.809 - 46 145 99 244 Es -a 66026# 181# 7483# 1# B- -2938# 271# 244 070881# 195# - 44 144 100 244 Fm -a 68964# 201# 7468# 1# B- -6634# 425# 244 074036# 216# - 42 143 101 244 Md -a 75597# 374# 7438# 2# B- * 244 081157# 402# -0 59 152 93 245 Np x 65850# 200# 7506# 1# B- 2672# 201# 245 070693# 215# - 57 151 94 245 Pu -n 63178.173 13.620 7513.2822 0.0556 B- 1277.7559 13.7334 245 067824.554 14.621 - 55 150 95 245 Am +a 61900.417 1.886 7515.3043 0.0077 B- 895.8929 1.5491 245 066452.827 2.024 - 53 149 96 245 Cm 61004.524 1.149 7515.7677 0.0047 B- -809.2519 1.4964 245 065491.047 1.233 - 51 148 97 245 Bk -a 61813.776 1.792 7509.2714 0.0073 B- -1571.3755 2.5861 245 066359.814 1.923 - 49 147 98 245 Cf 63385.151 2.428 7499.6644 0.0099 B- -2930# 165# 245 068046.755 2.606 - 47 146 99 245 Es IT 66315# 165# 7485# 1# B- -3877# 256# 245 071192# 178# - 45 145 100 245 Fm -a 70192# 195# 7465# 1# B- -5133# 325# 245 075354# 210# - 43 144 101 245 Md -a 75325# 260# 7441# 1# B- * 245 080864# 279# -0 58 152 94 246 Pu 65394.772 14.985 7506.5401 0.0609 B- 401# 14# 246 070204.172 16.087 - 56 151 95 246 Am IT 64994# 18# 7505# 0# B- 2377# 18# 246 069774# 19# - 54 150 96 246 Cm 62616.912 1.525 7511.4716 0.0062 B- -1350.0000 60.0000 246 067222.016 1.637 - 52 149 97 246 Bk - 63966.912 60.019 7502.8035 0.2440 B- -123.3159 60.0198 246 068671.300 64.433 - 50 148 98 246 Cf 64090.228 1.514 7499.1220 0.0062 B- -3728.5741 89.9373 246 068803.685 1.625 - 48 147 99 246 Es 67818.802 89.925 7480.7849 0.3655 B- -2372.3848 90.9577 246 072806.474 96.538 - 46 146 100 246 Fm -a 70191.187 13.670 7467.9608 0.0556 B- -5924# 260# 246 075353.334 14.675 - 44 145 101 246 Md -a 76115# 260# 7441# 1# B- * 246 081713# 279# -0 59 153 94 247 Pu x 69210# 200# 7493# 1# B- 2057# 224# 247 074300# 215# - 57 152 95 247 Am + 67153# 100# 7499# 0# B- 1620# 100# 247 072092# 107# - 55 151 96 247 Cm 65533.105 3.797 7501.9318 0.0154 B- 43.5841 6.3245 247 070352.678 4.076 - 53 150 97 247 Bk -a 65489.521 5.189 7498.9408 0.0210 B- -619.8711 15.2376 247 070305.889 5.570 - 51 149 98 247 Cf +a 66109.392 14.327 7493.2638 0.0580 B- -2469.0006 24.1495 247 070971.348 15.380 - 49 148 99 247 Es +a 68578.393 19.441 7480.1005 0.0787 B- -3094# 182# 247 073621.929 20.870 - 47 147 100 247 Fm +a 71672# 181# 7464# 1# B- -4263# 275# 247 076944# 194# - 45 146 101 247 Md -a 75936# 207# 7444# 1# B- * 247 081520# 223# -0 58 153 95 248 Am + 70563# 200# 7487# 1# B- 3170# 200# 248 075752# 215# - 56 152 96 248 Cm 67392.748 2.358 7496.7291 0.0095 B- -738.3049 50.0026 248 072349.086 2.531 - 54 151 97 248 Bk +a 68131.053 50.058 7490.5975 0.2018 B- 893.1015 50.3143 248 073141.689 53.739 - 52 150 98 248 Cf -a 67237.951 5.121 7491.0440 0.0207 B- -3061# 53# 248 072182.905 5.497 - 50 149 99 248 Es -a 70299# 52# 7476# 0# B- -1599# 53# 248 075469# 56# - 48 148 100 248 Fm 71897.793 8.497 7465.9451 0.0343 B- -5050# 184# 248 077185.451 9.122 - 46 147 101 248 Md -a 76948# 184# 7442# 1# B- -3741# 290# 248 082607# 198# - 44 146 102 248 No -a 80689# 224# 7424# 1# B- * 248 086623# 241# -0 59 154 95 249 Am x 73104# 298# 7479# 1# B- 2353# 298# 249 078480# 320# - 57 153 96 249 Cm -n 70750.696 2.371 7485.5510 0.0095 B- 904.3630 2.5934 249 075953.992 2.545 - 55 152 97 249 Bk + 69846.333 1.248 7486.0410 0.0050 B- 123.6000 0.4000 249 074983.118 1.339 - 53 151 98 249 Cf 69722.733 1.182 7483.3954 0.0048 B- -1452# 30# 249 074850.428 1.269 - 51 150 99 249 Es -a 71175# 30# 7474# 0# B- -2344# 31# 249 076409# 32# - 49 149 100 249 Fm 73519.143 6.212 7461.8649 0.0249 B- -3661.8091 164.5418 249 078926.042 6.668 - 47 148 101 249 Md 77180.952 164.425 7444.0169 0.6603 B- -4606# 324# 249 082857.155 176.516 - 45 147 102 249 No -a 81787# 279# 7422# 1# B- * 249 087802# 300# -0 58 154 96 250 Cm -nn 72989.588 10.274 7478.9385 0.0411 B- 37.5820 10.6414 250 078357.541 11.029 - 56 153 97 250 Bk +a 72952.006 2.898 7475.9594 0.0116 B- 1781.6696 2.4561 250 078317.195 3.110 - 54 152 98 250 Cf -a 71170.336 1.538 7479.9567 0.0062 B- -2055# 100# 250 076404.494 1.650 - 52 151 99 250 Es - 73225# 100# 7469# 0# B- -847# 100# 250 078611# 107# - 50 150 100 250 Fm 74072.193 7.888 7462.0905 0.0316 B- -4326.9476 91.2615 250 079519.765 8.468 - 48 149 101 250 Md 78399.140 90.920 7441.6533 0.3637 B- -3167# 220# 250 084164.934 97.606 - 46 148 102 250 No -a 81566# 200# 7426# 1# B- * 250 087565# 215# -0 59 155 96 251 Cm + 76647.981 22.698 7466.7233 0.0904 B- 1420.0000 20.0000 251 082284.988 24.367 - 57 154 97 251 Bk + 75227.981 10.734 7469.2637 0.0428 B- 1093.0000 10.0000 251 080760.555 11.523 - 55 153 98 251 Cf -a 74134.981 3.901 7470.5014 0.0155 B- -376.5660 6.4677 251 079587.171 4.187 - 53 152 99 251 Es -a 74511.547 5.288 7465.8842 0.0211 B- -1447.2610 15.2387 251 079991.431 5.676 - 51 151 100 251 Fm 75958.808 14.292 7457.0013 0.0569 B- -3007.9406 23.7108 251 081545.130 15.342 - 49 150 101 251 Md +a 78966.749 18.919 7441.9005 0.0754 B- -3882# 182# 251 084774.287 20.310 - 47 149 102 251 No IT 82849# 181# 7423# 1# B- -4981# 270# 251 088942# 194# - 45 148 103 251 Lr x 87830# 200# 7400# 1# B- * 251 094289# 215# -0 60 156 96 252 Cm x 79056# 298# 7460# 1# B- 521# 359# 252 084870# 320# - 58 155 97 252 Bk + 78535# 200# 7459# 1# B- 2500# 200# 252 084310# 215# - 56 154 98 252 Cf -a 76034.610 2.358 7465.3474 0.0094 B- -1260.0000 50.0000 252 081626.507 2.531 - 54 153 99 252 Es - 77294.610 50.056 7457.2428 0.1986 B- 477.9998 50.3220 252 082979.173 53.736 - 52 152 100 252 Fm -a 76816.611 5.221 7456.0351 0.0207 B- -3650.5075 91.4356 252 082466.019 5.604 - 50 151 101 252 Md x 80467.118 91.286 7438.4444 0.3622 B- -2404.2523 91.7581 252 086385.000 98.000 - 48 150 102 252 No 82871.370 9.292 7425.7992 0.0369 B- -5666# 185# 252 088966.070 9.975 - 46 149 103 252 Lr -a 88537# 185# 7400# 1# B- * 252 095048# 198# -0 59 156 97 253 Bk -a 80929# 359# 7451# 1# B- 1627# 359# 253 086880# 385# - 57 155 98 253 Cf -a 79301.562 4.257 7454.8297 0.0168 B- 291.0753 4.3850 253 085133.723 4.570 - 55 154 99 253 Es -a 79010.486 1.249 7452.8879 0.0049 B- -335.0623 1.0782 253 084821.241 1.341 - 53 153 100 253 Fm -a 79345.549 1.549 7448.4712 0.0061 B- -1827# 31# 253 085180.945 1.662 - 51 152 101 253 Md -a 81173# 31# 7438# 0# B- -3186# 32# 253 087143# 34# - 49 151 102 253 No 84358.696 6.912 7422.4719 0.0273 B- -4164.7752 164.6791 253 090562.780 7.420 - 47 150 103 253 Lr 88523.471 164.534 7402.9180 0.6503 B- -5118# 442# 253 095033.850 176.634 - 45 149 104 253 Rf -a 93642# 410# 7380# 2# B- * 253 100528# 440# -0 60 157 97 254 Bk x 84393# 298# 7440# 1# B- 3052# 298# 254 090600# 320# - 58 156 98 254 Cf -a 81341.395 11.462 7449.2259 0.0451 B- -652.7561 11.8014 254 087323.575 12.304 - 56 155 99 254 Es -a 81994.151 2.936 7443.5759 0.0116 B- 1091.6300 2.2858 254 088024.337 3.152 - 54 154 100 254 Fm -a 80902.521 1.843 7444.7936 0.0073 B- -2550# 100# 254 086852.424 1.978 - 52 153 101 254 Md - 83453# 100# 7432# 0# B- -1271# 100# 254 089590# 107# - 50 152 102 254 No 84723.312 9.658 7423.5909 0.0380 B- -4922.5753 91.8208 254 090954.211 10.367 - 48 151 103 254 Lr -a 89645.887 91.312 7401.1306 0.3595 B- -3555# 298# 254 096238.813 98.026 - 46 150 104 254 Rf -a 93201# 283# 7384# 1# B- * 254 100055# 304# -0 59 157 98 255 Cf + 84809# 200# 7438# 1# B- 720# 200# 255 091046# 215# - 57 156 99 255 Es -a 84089.237 10.817 7437.8216 0.0424 B- 288.7717 10.1024 255 090273.504 11.612 - 55 155 100 255 Fm -a 83800.465 3.934 7435.8860 0.0154 B- -1041.6037 6.7172 255 089963.495 4.223 - 53 154 101 255 Md -a 84842.069 5.567 7428.7333 0.0218 B- -1969.8648 15.1096 255 091081.702 5.976 - 51 153 102 255 No 86811.934 14.047 7417.9403 0.0551 B- -3135.3716 22.5952 255 093196.439 15.079 - 49 152 103 255 Lr x 89947.305 17.698 7402.5767 0.0694 B- -4382# 182# 255 096562.399 19.000 - 47 151 104 255 Rf -a 94329# 181# 7382# 1# B- -5265# 336# 255 101267# 194# - 45 150 105 255 Db -a 99595# 283# 7359# 1# B- * 255 106919# 304# -0 60 158 98 256 Cf -a 87041# 314# 7432# 1# B- -144# 330# 256 093442# 338# - 58 157 99 256 Es + 87185# 100# 7428# 0# B- 1700# 100# 256 093597# 107# - 56 156 100 256 Fm -a 85484.796 3.020 7431.7888 0.0118 B- -1971# 124# 256 091771.699 3.241 - 54 155 101 256 Md IT 87456# 124# 7421# 0# B- -367# 124# 256 093888# 133# - 52 154 102 256 No -a 87823.046 7.548 7416.5429 0.0295 B- -3923.5573 83.2459 256 094281.912 8.103 - 50 153 103 256 Lr x 91746.603 82.903 7398.1605 0.3238 B- -2475.3893 84.8025 256 098494.024 89.000 - 48 152 104 256 Rf -a 94221.992 17.848 7385.4349 0.0697 B- -6076# 188# 256 101151.464 19.160 - 46 151 105 256 Db -a 100298# 187# 7359# 1# B- * 256 107674# 201# -0 59 158 99 257 Es -a 89403# 411# 7422# 2# B- 813# 411# 257 095979# 441# - 57 157 100 257 Fm -a 88590.137 4.350 7422.1942 0.0169 B- -402.3347 4.5748 257 095105.419 4.669 - 55 156 101 257 Md -a 88992.472 1.569 7417.5845 0.0061 B- -1254.5923 6.1695 257 095537.343 1.683 - 53 155 102 257 No -a 90247.064 6.197 7409.6587 0.0241 B- -2418# 45# 257 096884.203 6.652 - 51 154 103 257 Lr -a 92665# 44# 7397# 0# B- -3201# 45# 257 099480# 47# - 49 153 104 257 Rf -a 95866.389 10.817 7381.7053 0.0421 B- -4287.8969 164.9888 257 102916.796 11.612 - 47 152 105 257 Db 100154.285 164.634 7361.9767 0.6406 B- * 257 107520.042 176.741 -0 60 159 99 258 Es x 92702# 401# 7412# 2# B- 2276# 448# 258 099520# 430# - 58 158 100 258 Fm -a 90426# 200# 7418# 1# B- -1264# 200# 258 097077# 215# - 56 157 101 258 Md -a 91690.350 3.474 7409.6615 0.0135 B- 213# 100# 258 098433.634 3.729 - 54 156 102 258 No -a 91477# 100# 7407# 0# B- -3304# 143# 258 098205# 107# - 52 155 103 258 Lr -a 94782# 102# 7392# 0# B- -1562# 103# 258 101753# 109# - 50 154 104 258 Rf -a 96344.338 16.104 7382.5257 0.0624 B- -5163.3651 93.2584 258 103429.895 17.288 - 48 153 105 258 Db -a 101507.703 91.857 7359.4803 0.3560 B- -3788# 423# 258 108972.995 98.613 - 46 152 106 258 Sg -a 105296# 413# 7342# 2# B- * 258 113040# 443# -0 59 159 100 259 Fm -a 93704# 283# 7407# 1# B- 140# 300# 259 100596# 304# - 57 158 101 259 Md -a 93564# 101# 7405# 0# B- -515# 101# 259 100445# 108# - 55 157 102 259 No -a 94079.381 6.362 7399.9714 0.0246 B- -1771# 71# 259 100998.364 6.829 - 53 156 103 259 Lr -a 95851# 71# 7390# 0# B- -2516# 101# 259 102900# 76# - 51 155 104 259 Rf -a 98367# 72# 7377# 0# B- -3624# 92# 259 105601# 78# - 49 154 105 259 Db -a 101991.021 56.685 7360.3626 0.2189 B- -4528# 190# 259 109491.859 60.854 - 47 153 106 259 Sg -a 106519# 181# 7340# 1# B- * 259 114353# 194# -0 60 160 100 260 Fm -a 95766# 435# 7402# 2# B- -784# 537# 260 102809# 467# - 58 159 101 260 Md -a 96550# 316# 7396# 1# B- 940# 374# 260 103650# 339# - 56 158 102 260 No -a 95610# 200# 7397# 1# B- -2667# 236# 260 102641# 215# - 54 157 103 260 Lr -a 98277# 125# 7383# 0# B- -871# 236# 260 105504# 134# - 52 156 104 260 Rf -a 99148# 200# 7377# 1# B- -4525# 221# 260 106440# 215# - 50 155 105 260 Db -a 103673# 93# 7357# 0# B- -2875# 95# 260 111297# 100# - 48 154 106 260 Sg -a 106547.495 20.536 7342.5632 0.0790 B- -6576# 197# 260 114383.435 22.045 - 46 153 107 260 Bh -a 113123# 196# 7314# 1# B- * 260 121443# 211# -0 59 160 101 261 Md -a 98578# 509# 7391# 2# B- 123# 547# 261 105828# 546# - 57 159 102 261 No -a 98455# 200# 7388# 1# B- -1102# 283# 261 105696# 215# - 55 158 103 261 Lr -a 99557# 200# 7381# 1# B- -1761# 211# 261 106879# 215# - 53 157 104 261 Rf -a 101318.233 65.663 7371.3858 0.2516 B- -2990# 128# 261 108769.591 70.492 - 51 156 105 261 Db -a 104308# 110# 7357# 0# B- -3697# 112# 261 111979# 118# - 49 155 106 261 Sg -a 108005.004 18.494 7339.7710 0.0709 B- -5074.4052 180.7519 261 115948.135 19.853 - 47 154 107 261 Bh -a 113079.410 179.803 7317.3313 0.6889 B- * 261 121395.733 193.026 -0 60 161 101 262 Md -a 101667# 448# 7382# 2# B- 1566# 575# 262 109144# 481# - 58 160 102 262 No -a 100101# 361# 7385# 1# B- -2004# 412# 262 107463# 387# - 56 159 103 262 Lr -a 102105# 200# 7374# 1# B- -287# 300# 262 109615# 215# - 54 158 104 262 Rf -a 102392# 224# 7370# 1# B- -3861# 265# 262 109923# 240# - 52 157 105 262 Db -a 106253# 143# 7352# 1# B- -2116# 145# 262 114067# 154# - 50 156 106 262 Sg -a 108369.072 22.167 7341.1736 0.0846 B- -5883.0463 95.6774 262 116338.978 23.797 - 48 155 107 262 Bh -a 114252.119 93.074 7315.7331 0.3552 B- * 262 122654.688 99.919 -0 59 161 102 263 No -a 103129# 490# 7376# 2# B- -540# 539# 263 110714# 526# - 57 160 103 263 Lr -a 103669# 224# 7371# 1# B- -1087# 271# 263 111293# 240# - 55 159 104 263 Rf -a 104757# 153# 7364# 1# B- -2353# 227# 263 112461# 164# - 53 158 105 263 Db -a 107110# 168# 7352# 1# B- -3085# 193# 263 114987# 180# - 51 157 106 263 Sg -a 110195# 95# 7337# 0# B- -4301# 320# 263 118299# 101# - 49 156 107 263 Bh -a 114496# 305# 7318# 1# B- -5182# 363# 263 122916# 328# - 47 155 108 263 Hs -a 119678# 197# 7295# 1# B- * 263 128479# 212# -0 60 162 102 264 No -a 105011# 591# 7371# 2# B- -1364# 734# 264 112734# 634# - 58 161 103 264 Lr -a 106375# 436# 7363# 2# B- 300# 566# 264 114198# 468# - 56 160 104 264 Rf -a 106075# 361# 7361# 1# B- -3187# 431# 264 113876# 387# - 54 159 105 264 Db -a 109262# 236# 7346# 1# B- -1521# 368# 264 117297# 253# - 52 158 106 264 Sg -a 110783# 283# 7338# 1# B- -5175# 334# 264 118930# 304# - 50 157 107 264 Bh -a 115958# 177# 7315# 1# B- -3605# 180# 264 124486# 190# - 48 156 108 264 Hs -a 119563.165 28.881 7298.3762 0.1094 B- * 264 128356.330 31.005 -0 59 162 103 265 Lr -a 108233# 547# 7359# 2# B- -457# 655# 265 116193# 587# - 57 161 104 265 Rf -a 108690# 361# 7354# 1# B- -1692# 424# 265 116683# 387# - 55 160 105 265 Db -a 110382# 224# 7345# 1# B- -2412# 263# 265 118500# 240# - 53 159 106 265 Sg -a 112794# 139# 7333# 1# B- -3601# 277# 265 121089# 149# - 51 158 107 265 Bh -a 116395# 239# 7316# 1# B- -4505# 240# 265 124955# 257# - 49 157 108 265 Hs -a 120900.245 23.958 7296.2474 0.0904 B- -5724# 439# 265 129791.744 25.719 - 47 156 109 265 Mt -a 126624# 439# 7272# 2# B- * 265 135937# 471# -0 60 163 103 266 Lr -a 111662# 539# 7349# 2# B- 1526# 679# 266 119874# 579# - 58 162 104 266 Rf -a 110136# 412# 7351# 2# B- -2604# 500# 266 118236# 443# - 56 161 105 266 Db -a 112740# 283# 7339# 1# B- -877# 374# 266 121032# 304# - 54 160 106 266 Sg -a 113617# 245# 7332# 1# B- -4487# 294# 266 121973# 263# - 52 159 107 266 Bh -a 118104# 163# 7313# 1# B- -3036# 165# 266 126790# 175# - 50 158 108 266 Hs -a 121139.675 27.106 7298.2611 0.1019 B- -6533.0066 100.2087 266 130048.783 29.099 - 48 157 109 266 Mt -a 127672.681 96.473 7270.7598 0.3627 B- * 266 137062.253 103.568 -0 59 163 104 267 Rf -a 113444# 575# 7342# 2# B- -570# 686# 267 121787# 617# - 57 162 105 267 Db -a 114014# 374# 7337# 1# B- -1792# 457# 267 122399# 402# - 55 161 106 267 Sg -a 115806# 261# 7327# 1# B- -2958# 371# 267 124323# 281# - 53 160 107 267 Bh -a 118765# 263# 7313# 1# B- -3893# 279# 267 127499# 282# - 51 159 108 267 Hs -a 122658# 95# 7295# 0# B- -5133# 512# 267 131678# 102# - 49 158 109 267 Mt -a 127791# 503# 7273# 2# B- -6089# 543# 267 137189# 540# - 47 157 110 267 Ds -a 133880# 204# 7248# 1# B- * 267 143726# 219# -0 60 164 104 268 Rf -a 115476# 662# 7337# 2# B- -1584# 848# 268 123968# 711# - 58 163 105 268 Db -a 117060# 529# 7328# 2# B- 260# 707# 268 125669# 568# - 56 162 106 268 Sg -a 116800# 469# 7326# 2# B- -3907# 605# 268 125389# 504# - 54 161 107 268 Bh -a 120707# 382# 7309# 1# B- -2261# 486# 268 129584# 410# - 52 160 108 268 Hs -a 122968# 300# 7297# 1# B- -6183# 380# 268 132011# 322# - 50 159 109 268 Mt -a 129151# 233# 7271# 1# B- -4497# 381# 268 138649# 250# - 48 158 110 268 Ds -a 133648# 301# 7252# 1# B- * 268 143477# 324# -0 59 164 105 269 Db -a 119148# 624# 7323# 2# B- -544# 724# 269 127911# 669# - 57 163 106 269 Sg -a 119692# 368# 7318# 1# B- -1785# 525# 269 128495# 395# - 55 162 107 269 Bh -a 121477# 374# 7309# 1# B- -3016# 396# 269 130411# 402# - 53 161 108 269 Hs -a 124493# 131# 7294# 0# B- -4807# 338# 269 133649# 141# - 51 160 109 269 Mt -a 129300# 312# 7274# 1# B- -5535# 313# 269 138809# 335# - 49 159 110 269 Ds -a 134834.671 31.403 7250.1551 0.1167 B- * 269 144750.965 33.712 -0 60 165 105 270 Db -a 122397# 575# 7314# 2# B- 966# 735# 270 131399# 617# - 58 164 106 270 Sg -a 121431# 458# 7314# 2# B- -2799# 547# 270 130362# 492# - 56 163 107 270 Bh -a 124230# 299# 7301# 1# B- -882# 388# 270 133366# 320# - 54 162 108 270 Hs -a 125112# 248# 7295# 1# B- -5597# 313# 270 134313# 266# - 52 161 109 270 Mt -a 130709# 191# 7271# 1# B- -3973# 195# 270 140322# 205# - 50 160 110 270 Ds -a 134681.584 39.275 7253.7634 0.1455 B- * 270 144586.620 42.163 -0 59 165 106 271 Sg -a 124617# 591# 7305# 2# B- -1242# 705# 271 133782# 634# - 57 164 107 271 Bh -a 125859# 384# 7298# 1# B- -1832# 473# 271 135115# 412# - 55 163 108 271 Hs -a 127691# 276# 7288# 1# B- -3409# 430# 271 137082# 296# - 53 162 109 271 Mt -a 131100# 330# 7273# 1# B- -4853# 344# 271 140741# 354# - 51 161 110 271 Ds -a 135952# 97# 7252# 0# B- * 271 145951# 104# -0 60 166 106 272 Sg -a 126520# 692# 7301# 3# B- -2267# 873# 272 135825# 743# - 58 165 107 272 Bh -a 128787# 532# 7290# 2# B- -217# 737# 272 138259# 571# - 56 164 108 272 Hs -a 129004# 510# 7286# 2# B- -4477# 704# 272 138492# 547# - 54 163 109 272 Mt -a 133481# 485# 7267# 2# B- -2601# 645# 272 143298# 521# - 52 162 110 272 Ds -a 136083# 424# 7255# 2# B- -6690# 484# 272 146091# 456# - 50 161 111 272 Rg -a 142773# 233# 7227# 1# B- * 272 153273# 251# -0 61 167 106 273 Sg x 129920# 400# 7292# 1# B- -763# 767# 273 139475# 429# - 59 166 107 273 Bh -a 130683# 655# 7286# 2# B- -1084# 754# 273 140294# 703# - 57 165 108 273 Hs -a 131767# 374# 7279# 1# B- -3015# 565# 273 141458# 401# - 55 164 109 273 Mt -a 134782# 424# 7265# 2# B- -3503# 447# 273 144695# 455# - 53 163 110 273 Ds -a 138285# 142# 7250# 1# B- -4600# 424# 273 148455# 152# - 51 162 111 273 Rg -a 142885# 400# 7230# 1# B- * 273 153393# 429# -0 60 167 107 274 Bh -a 133762# 578# 7278# 2# B- 356# 744# 274 143599# 620# - 58 166 108 274 Hs -a 133406# 469# 7276# 2# B- -3843# 602# 274 143217# 504# - 56 165 109 274 Mt -a 137249# 377# 7259# 1# B- -1948# 542# 274 147343# 404# - 54 164 110 274 Ds -a 139197# 389# 7249# 1# B- -5415# 442# 274 149434# 418# - 52 163 111 274 Rg -a 144612# 209# 7227# 1# B- * 274 155247# 225# -0 61 168 107 275 Bh x 135780# 600# 7273# 2# B- -712# 844# 275 145766# 644# - 59 167 108 275 Hs -a 136492# 593# 7268# 2# B- -2275# 709# 275 146530# 637# - 57 166 109 275 Mt -a 138767# 387# 7257# 1# B- -2899# 516# 275 148972# 416# - 55 165 110 275 Ds -a 141666# 340# 7243# 1# B- -3729# 561# 275 152085# 366# - 53 164 111 275 Rg -a 145395# 446# 7227# 2# B- * 275 156088# 479# -0 62 169 107 276 Bh x 138950# 600# 7265# 2# B- 765# 937# 276 149169# 644# - 60 168 108 276 Hs -a 138185# 720# 7265# 3# B- -3127# 895# 276 148348# 773# - 58 167 109 276 Mt -a 141312# 532# 7250# 2# B- -1227# 764# 276 151705# 571# - 56 166 110 276 Ds -a 142539# 548# 7243# 2# B- -4847# 834# 276 153022# 588# - 54 165 111 276 Rg -a 147386# 629# 7223# 2# B- -2974# 804# 276 158226# 675# - 52 164 112 276 Cn x 150360# 500# 7209# 2# B- * 276 161418# 537# -0 63 170 107 277 Bh x 141100# 600# 7260# 2# B- -275# 748# 277 151477# 644# - 61 169 108 277 Hs -a 141375# 447# 7256# 2# B- -1633# 799# 277 151772# 480# - 59 168 109 277 Mt -a 143008# 662# 7247# 2# B- -2084# 770# 277 153525# 711# - 57 167 110 277 Ds -a 145092# 392# 7237# 1# B- -3315# 611# 277 155763# 421# - 55 166 111 277 Rg -a 148407# 469# 7222# 2# B- -3925# 493# 277 159322# 504# - 53 165 112 277 Cn -a 152332# 153# 7205# 1# B- * 277 163535# 165# -0 64 171 107 278 Bh x 144370# 400# 7251# 1# B- 1150# 500# 278 154988# 429# - 62 170 108 278 Hs x 143220# 300# 7252# 1# B- -2547# 652# 278 153753# 322# - 60 169 109 278 Mt -a 145767# 579# 7240# 2# B- -484# 771# 278 156487# 621# - 58 168 110 278 Ds -a 146251# 510# 7236# 2# B- -4270# 641# 278 157007# 548# - 56 167 111 278 Rg -a 150521# 389# 7218# 1# B- -2321# 585# 278 161590# 417# - 54 166 112 278 Cn -a 152842# 438# 7206# 2# B- -6188# 491# 278 164083# 470# - 52 165 113 278 Nh -a 159030# 224# 7181# 1# B- * 278 170725# 240# -0 63 171 108 279 Hs x 146500# 600# 7243# 2# B- -1085# 900# 279 157274# 644# - 61 170 109 279 Mt -a 147585# 671# 7237# 2# B- -1439# 903# 279 158439# 720# - 59 169 110 279 Ds -a 149024# 605# 7229# 2# B- -2697# 737# 279 159984# 649# - 57 168 111 279 Rg -a 151721# 422# 7216# 2# B- -3299# 578# 279 162880# 453# - 55 167 112 279 Cn -a 155021# 395# 7202# 1# B- -4439# 718# 279 166422# 424# - 53 166 113 279 Nh x 159460# 600# 7183# 2# B- * 279 171187# 644# -0 64 172 108 280 Hs x 148420# 600# 7239# 2# B- -2090# 848# 280 159335# 644# - 62 171 109 280 Mt x 150510# 600# 7229# 2# B- 190# 958# 280 161579# 644# - 60 170 110 280 Ds -a 150320# 748# 7227# 3# B- -3566# 918# 280 161375# 803# - 58 169 111 280 Rg -a 153886# 532# 7212# 2# B- -1768# 789# 280 165204# 571# - 56 168 112 280 Cn -a 155654# 583# 7202# 2# B- -5585# 707# 280 167102# 626# - 54 167 113 280 Nh x 161240# 400# 7180# 1# B- * 280 173098# 429# -0 63 172 109 281 Mt x 152400# 600# 7225# 2# B- -873# 776# 281 163608# 644# - 61 171 110 281 Ds -a 153273# 493# 7220# 2# B- -2060# 918# 281 164545# 529# - 59 170 111 281 Rg -a 155333# 774# 7209# 3# B- -2614# 870# 281 166757# 831# - 57 169 112 281 Cn -a 157947# 397# 7197# 1# B- -3863# 498# 281 169563# 427# - 55 168 113 281 Nh x 161810# 300# 7181# 1# B- * 281 173710# 322# -0 64 173 109 282 Mt -a 155455# 447# 7218# 2# B- 665# 538# 282 166888# 480# - 62 172 110 282 Ds x 154790# 300# 7217# 1# B- -2952# 660# 282 166174# 322# - 60 171 111 282 Rg -a 157742# 588# 7204# 2# B- -1084# 804# 282 169343# 631# - 58 170 112 282 Cn -a 158826# 548# 7197# 2# B- -4903# 678# 282 170507# 588# - 56 169 113 282 Nh -a 163729# 400# 7177# 1# B- * 282 175770# 430# -0 63 173 110 283 Ds x 157830# 500# 7210# 2# B- -1550# 843# 283 169437# 537# - 61 172 111 283 Rg -a 159380# 678# 7201# 2# B- -1957# 916# 283 171101# 728# - 59 171 112 283 Cn -a 161337# 615# 7192# 2# B- -3226# 754# 283 173202# 660# - 57 170 113 283 Nh -a 164563# 437# 7177# 2# B- * 283 176666# 469# -0 64 174 110 284 Ds x 159460# 500# 7207# 2# B- -2510# 707# 284 171187# 537# - 62 173 111 284 Rg x 161970# 500# 7195# 2# B- -445# 912# 284 173882# 537# - 60 172 112 284 Cn -a 162415# 762# 7191# 3# B- -4176# 931# 284 174360# 819# - 58 171 113 284 Nh -a 166591# 533# 7173# 2# B- -2188# 845# 284 178843# 573# - 56 170 114 284 Fl -a 168779# 656# 7163# 2# B- * 284 181192# 704# -0 63 174 111 285 Rg x 163730# 600# 7192# 2# B- -1357# 785# 285 175771# 644# - 61 173 112 285 Cn -a 165086# 507# 7185# 2# B- -2682# 926# 285 177227# 544# - 59 172 113 285 Nh -a 167768# 775# 7172# 3# B- -3164# 874# 285 180106# 832# - 57 171 114 285 Fl -a 170932# 404# 7159# 1# B- * 285 183503# 433# -0 64 175 111 286 Rg -a 166510# 458# 7185# 2# B- 61# 836# 286 178756# 492# - 62 174 112 286 Cn x 166450# 700# 7183# 2# B- -3507# 915# 286 178691# 751# - 60 173 113 286 Nh -a 169957# 590# 7168# 2# B- -1649# 806# 286 182456# 634# - 58 172 114 286 Fl -a 171606# 549# 7159# 2# B- * 286 184226# 590# -0 63 175 112 287 Cn x 169370# 700# 7176# 2# B- -2085# 995# 287 181826# 751# - 61 174 113 287 Nh -a 171455# 707# 7166# 2# B- -2474# 939# 287 184064# 759# - 59 173 114 287 Fl -a 173929# 617# 7155# 2# B- -3819# 759# 287 186720# 663# - 57 172 115 287 Mc -a 177748# 443# 7139# 2# B- * 287 190820# 475# -0 64 176 112 288 Cn x 170930# 700# 7174# 2# B- -3039# 989# 288 183501# 751# - 62 175 113 288 Nh x 173970# 700# 7160# 2# B- -947# 1035# 288 186764# 751# - 60 174 114 288 Fl -a 174917# 763# 7154# 3# B- -4749# 932# 288 187781# 819# - 58 173 115 288 Mc -a 179666# 536# 7135# 2# B- * 288 192879# 575# -0 63 176 113 289 Nh x 175550# 500# 7158# 2# B- -1915# 715# 289 188461# 537# - 61 175 114 289 Fl -a 177465# 511# 7149# 2# B- -3217# 929# 289 190517# 548# - 59 174 115 289 Mc -a 180683# 776# 7135# 3# B- -3774# 925# 289 193971# 834# - 57 173 116 289 Lv -a 184457# 503# 7119# 2# B- * 289 198023# 540# -0 64 177 113 290 Nh -a 178315# 469# 7152# 2# B- -416# 843# 290 191429# 503# - 62 176 114 290 Fl -a 178731# 700# 7147# 2# B- -4061# 917# 290 191875# 752# - 60 175 115 290 Mc -a 182792# 592# 7131# 2# B- -2236# 809# 290 196235# 635# - 58 174 116 290 Lv -a 185028# 552# 7120# 2# B- * 290 198635# 593# -0 63 177 114 291 Fl x 181500# 700# 7141# 2# B- -2680# 1015# 291 194848# 751# - 61 176 115 291 Mc -a 184180# 735# 7129# 3# B- -3064# 964# 291 197725# 789# - 59 175 116 291 Lv -a 187244# 623# 7116# 2# B- -4409# 863# 291 201014# 669# - 57 174 117 291 Ts -a 191653# 597# 7098# 2# B- * 291 205748# 640# -0 62 177 115 292 Mc x 186600# 700# 7124# 2# B- -1533# 1035# 292 200323# 751# - 60 176 116 292 Lv -a 188133# 763# 7116# 3# B- -5488# 1014# 292 201969# 819# - 58 175 117 292 Ts -a 193621# 669# 7095# 2# B- * 292 207861# 718# -0 61 177 116 293 Lv -a 190568# 515# 7111# 2# B- -3860# 933# 293 204583# 553# - 59 176 117 293 Ts -a 194428# 778# 7095# 3# B- -4374# 1053# 293 208727# 835# - 57 175 118 293 Og -a 198802# 709# 7078# 2# B- * 293 213423# 761# -0 60 177 117 294 Ts -a 196397# 593# 7092# 2# B- -2923# 811# 294 210840# 637# - 58 176 118 294 Og -a 199320# 553# 7079# 2# B- * 294 213979# 594# -0 59 177 118 295 Og -a 201369# 655# 7076# 2# B- * 295 216178# 703# diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index d843b5971..508c76ac4 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -1,12 +1,14 @@ from numbers import Real from math import exp, erf, pi, sqrt from copy import deepcopy +import warnings import os import h5py import pickle import numpy as np from scipy.signal import find_peaks +import matplotlib.pyplot as plt import openmc.checkvalue as cv from ..exceptions import DataError @@ -15,7 +17,7 @@ from . import WMP_VERSION, WMP_VERSION_MAJOR from .data import K_BOLTZMANN from .neutron import IncidentNeutron from .resonance import ResonanceRange -from .vectfit import vectfit, evaluate + # Constants that determine which value to access _MP_EA = 0 # Pole @@ -174,6 +176,10 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, (poles, residues) """ + + # import vectfit package: https://github.com/liangjg/vectfit + import vectfit as vf + ne = energy.size nmt = len(mts) if ce_xs.shape != (nmt, ne): @@ -190,8 +196,9 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, test_xs_ref[i] = np.interp(test_energy, energy, ce_xs[i]) if log: - print(f"\tenergy: {energy[0]:.3e} to {energy[-1]:.3e} eV ({ne} points)") - print(f"\terror tolerance: rtol={rtol}, atol={atol}") + print(" energy: {:.3e} to {:.3e} eV ({} points)".format( + energy[0], energy[-1], ne)) + print(" error tolerance: rtol={}, atol={}".format(rtol, atol)) # transform xs (sigma) and energy (E) to f (sigma*E) and s (sqrt(E)) to be # compatible with the multipole representation @@ -225,8 +232,8 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, orders = list(range(lowest_order, highest_order + 1, 2)) if log: - print(f"Found {n_peaks} peaks") - print(f"Fitting orders from {orders[0]} to {orders[-1]}") + print("Found {} peaks".format(n_peaks)) + print("Fitting orders from {} to {}".format(orders[0], orders[-1])) # perform VF with increasing orders found_ideal = False @@ -234,7 +241,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, best_quality = best_ratio = -np.inf for i, order in enumerate(orders): if log: - print(f"Order={order}({i}/{len(orders)})") + print("Order={}({}/{})".format(order, i, len(orders))) # initial guessed poles poles_r = np.linspace(s[0], s[-1], order//2) poles = poles_r + poles_r*0.01j @@ -244,10 +251,10 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, # fitting iteration for i_vf in range(n_vf_iter): if log >= DETAILED_LOGGING: - print(f"VF iteration {i_vf + 1}/{n_vf_iter}") + print("VF iteration {}/{}".format(i_vf + 1, n_vf_iter)) # call vf - poles, residues, *_ = vectfit(f, s, poles, weight) + poles, residues, cf, f_fit, rms = vf.vectfit(f, s, poles, weight) # convert real pole to conjugate pairs n_real_poles = 0 @@ -263,12 +270,12 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, # re-calculate residues if poles changed if n_real_poles > 0: if log >= DETAILED_LOGGING: - print(f" # real poles: {n_real_poles}") - new_poles, residues, *_ = \ - vectfit(f, s, new_poles, weight, skip_pole_update=True) + print(" # real poles: {}".format(n_real_poles)) + new_poles, residues, cf, f_fit, rms = \ + vf.vectfit(f, s, new_poles, weight, skip_pole=True) # assess the result on test grid - test_xs = evaluate(test_s, new_poles, residues) / test_energy + test_xs = vf.evaluate(test_s, new_poles, residues) / test_energy abserr = np.abs(test_xs - test_xs_ref) with np.errstate(invalid='ignore', divide='ignore'): relerr = abserr / test_xs_ref @@ -291,10 +298,10 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, quality = -np.inf if log >= DETAILED_LOGGING: - print(f" # poles: {new_poles.size}") - print(f" Max relative error: {maxre * 100:.3f}%") - print(f" Satisfaction: {ratio * 100:.1f}%, {ratio2 * 100:.1f}%") - print(f" Quality: {quality:.2f}") + print(" # poles: {}".format(new_poles.size)) + print(" Max relative error: {:.3f}%".format(maxre*100)) + print(" Satisfaction: {:.1f}%, {:.1f}%".format(ratio*100, ratio2*100)) + print(" Quality: {:.2f}".format(quality)) if quality > best_quality: if log >= DETAILED_LOGGING: @@ -349,7 +356,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, mp_residues = np.concatenate((best_residues[:, real_idx], best_residues[:, conj_idx]*2), axis=1)/1j if log: - print(f"Final number of poles: {mp_poles.size}") + print("Final number of poles: {}".format(mp_poles.size)) if path_out: if not os.path.exists(path_out): @@ -357,7 +364,6 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, for i, mt in enumerate(mts): if not test_xs_ref[i].any(): continue - import matplotlib.pyplot as plt fig, ax1 = plt.subplots() lns1 = ax1.loglog(test_energy, test_xs_ref[i], 'g', label="ACE xs") lns2 = ax1.loglog(test_energy, best_test_xs[i], 'b', label="VF xs") @@ -373,20 +379,20 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, ax2.set_ylabel('relative error', color='r') ax2.tick_params('y', colors='r') - plt.title(f"MT {mt} vector fitted with {mp_poles.size} poles") + plt.title("MT {} vector fitted with {} poles".format(mt, mp_poles.size)) fig.tight_layout() fig_file = os.path.join(path_out, "{:.0f}-{:.0f}_MT{}.png".format( energy[0], energy[-1], mt)) plt.savefig(fig_file) plt.close() if log: - print(f"Saved figure: {fig_file}") + print("Saved figure: {}".format(fig_file)) return (mp_poles, mp_residues) + def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, - log=False, path_out=None, mp_filename=None, - **kwargs): + log=False, path_out=None, mp_filename=None, **kwargs): r"""Generate multipole data for a nuclide from ENDF. Parameters @@ -418,7 +424,7 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, # make 0K ACE data using njoy if log: - print(f"Running NJOY to get 0K point-wise data (error={njoy_error})...") + print("Running NJOY to get 0K point-wise data (error={})...".format(njoy_error)) nuc_ce = IncidentNeutron.from_njoy(endf_file, temperatures=[0.0], error=njoy_error, broadr=False, heatr=False, purr=False) @@ -472,8 +478,9 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, mts = [2, 27] if log: - print(f" MTs: {mts}") - print(f" Energy range: {E_min:.3e} to {E_max:.3e} eV ({n_points} points)") + print(" MTs: {}".format(mts)) + print(" Energy range: {:.3e} to {:.3e} eV ({} points)".format( + E_min, E_max, n_points)) # ====================================================================== # PERFORM VECTOR FITTING @@ -494,7 +501,7 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, # VF piece by piece for i_piece in range(vf_pieces): if log: - print(f"Vector fitting piece {i_piece + 1}/{vf_pieces}...") + print("Vector fitting piece {}/{}...".format(i_piece + 1, vf_pieces)) # start E of this piece e_bound = (sqrt(E_min) + piece_width*(i_piece-0.5))**2 if i_piece == 0 or sqrt(alpha*e_bound) < 4.0: @@ -528,12 +535,12 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, if not os.path.exists(path_out): os.makedirs(path_out) if not mp_filename: - mp_filename = f"{nuc_ce.name}_mp.pickle" + mp_filename = "{}_mp.pickle".format(nuc_ce.name) mp_filename = os.path.join(path_out, mp_filename) with open(mp_filename, 'wb') as f: pickle.dump(mp_data, f) if log: - print(f"Dumped multipole data to file: {mp_filename}") + print("Dumped multipole data to file: {}".format(mp_filename)) return mp_data @@ -567,6 +574,10 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, format. """ + + # import vectfit package: https://github.com/liangjg/vectfit + import vectfit as vf + # unpack multipole data name = mp_data["name"] awr = mp_data["AWR"] @@ -595,8 +606,9 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, if log: print("Windowing:") - print(f" config: # windows={n_win}, spacing={spacing}, CF order={n_cf}") - print(f" error tolerance: rtol={rtol}, atol={atol}") + print(" config: # windows={}, spacing={}, CF order={}".format( + n_win, spacing, n_cf)) + print(" error tolerance: rtol={}, atol={}".format(rtol, atol)) # sort poles (and residues) by the real component of the pole for ip in range(n_pieces): @@ -612,7 +624,7 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, win_data = [] for iw in range(n_win): if log >= DETAILED_LOGGING: - print(f"Processing window {iw + 1}/{n_win}...") + print("Processing window {}/{}...".format(iw + 1, n_win)) # inner window boundaries inbegin = sqrt(E_min) + spacing * iw @@ -637,7 +649,7 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, # reference xs from multipole form, note the residue terms in the # multipole and vector fitting representations differ by a 1j - xs_ref = evaluate(energy_sqrt, poles, residues*1j) / energy + xs_ref = vf.evaluate(energy_sqrt, poles, residues*1j) / energy # curve fit matrix matrix = np.vstack([energy**(0.5*i - 1) for i in range(n_cf + 1)]).T @@ -647,11 +659,11 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, lp = rp = center_pole_ind while True: if log >= DETAILED_LOGGING: - print(f"Trying poles {lp} to {rp}") + print("Trying poles {} to {}".format(lp, rp)) # calculate the cross sections contributed by the windowed poles if rp > lp: - xs_wp = evaluate(energy_sqrt, poles[lp:rp], + xs_wp = vf.evaluate(energy_sqrt, poles[lp:rp], residues[:, lp:rp]*1j) / energy else: xs_wp = np.zeros_like(xs_ref) @@ -736,12 +748,12 @@ class WindowedMultipole(EqualityMixin): Parameters ---------- name : str - Name of the nuclide using the GNDS naming convention + Name of the nuclide using the GND naming convention Attributes ---------- name : str - Name of the nuclide using the GNDS naming convention + Name of the nuclide using the GND naming convention spacing : float The width of each window in sqrt(E)-space. For example, the frst window will end at (sqrt(E_min) + spacing)**2 and the second window at @@ -788,11 +800,6 @@ class WindowedMultipole(EqualityMixin): def name(self): return self._name - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - @property def fit_order(self): return self.curvefit.shape[1] - 1 @@ -817,6 +824,39 @@ class WindowedMultipole(EqualityMixin): def spacing(self): return self._spacing + @property + def sqrtAWR(self): + return self._sqrtAWR + + @property + def E_min(self): + return self._E_min + + @property + def E_max(self): + return self._E_max + + @property + def data(self): + return self._data + + @property + def windows(self): + return self._windows + + @property + def broaden_poly(self): + return self._broaden_poly + + @property + def curvefit(self): + return self._curvefit + + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + @spacing.setter def spacing(self, spacing): if spacing is not None: @@ -824,10 +864,6 @@ class WindowedMultipole(EqualityMixin): cv.check_greater_than('spacing', spacing, 0.0, equality=False) self._spacing = spacing - @property - def sqrtAWR(self): - return self._sqrtAWR - @sqrtAWR.setter def sqrtAWR(self, sqrtAWR): if sqrtAWR is not None: @@ -835,10 +871,6 @@ class WindowedMultipole(EqualityMixin): cv.check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) self._sqrtAWR = sqrtAWR - @property - def E_min(self): - return self._E_min - @E_min.setter def E_min(self, E_min): if E_min is not None: @@ -846,10 +878,6 @@ class WindowedMultipole(EqualityMixin): cv.check_greater_than('E_min', E_min, 0.0, equality=True) self._E_min = E_min - @property - def E_max(self): - return self._E_max - @E_max.setter def E_max(self, E_max): if E_max is not None: @@ -857,10 +885,6 @@ class WindowedMultipole(EqualityMixin): cv.check_greater_than('E_max', E_max, 0.0, equality=False) self._E_max = E_max - @property - def data(self): - return self._data - @data.setter def data(self, data): if data is not None: @@ -876,10 +900,6 @@ class WindowedMultipole(EqualityMixin): raise TypeError('Multipole data arrays must be complex dtype') self._data = data - @property - def windows(self): - return self._windows - @windows.setter def windows(self, windows): if windows is not None: @@ -891,10 +911,6 @@ class WindowedMultipole(EqualityMixin): ' dtype') self._windows = windows - @property - def broaden_poly(self): - return self._broaden_poly - @broaden_poly.setter def broaden_poly(self, broaden_poly): if broaden_poly is not None: @@ -906,10 +922,6 @@ class WindowedMultipole(EqualityMixin): ' dtype') self._broaden_poly = broaden_poly - @property - def curvefit(self): - return self._curvefit - @curvefit.setter def curvefit(self, curvefit): if curvefit is not None: @@ -1046,15 +1058,7 @@ class WindowedMultipole(EqualityMixin): return cls.from_multipole(mp_data, **wmp_options) @classmethod - def from_multipole( - cls, - mp_data, - search=None, - log=False, - search_n_win=20, - search_cf_orders=None, - **kwargs, - ): + def from_multipole(cls, mp_data, search=None, log=False, **kwargs): """Generate windowed multipole neutron data from multipole data. Parameters @@ -1066,14 +1070,8 @@ class WindowedMultipole(EqualityMixin): Defaults to True if no windowing parameters are specified. log : bool or int, optional Whether to print running logs (use int for verbosity control) - search_n_win : int, optional - Number of window sizes to consider in the search grid when - ``search`` is True. - search_cf_orders : iterable of int, optional - Curve-fit orders to consider in the search grid when ``search`` is - True. Defaults to integers from 10 down to 2. **kwargs - Keyword arguments passed to :func:`openmc.data.multipole._windowing`. + Keyword arguments passed to :func:`openmc.data.multipole._windowing` Returns ------- @@ -1104,19 +1102,14 @@ class WindowedMultipole(EqualityMixin): # search optimal WMP from a range of window sizes and CF orders if log: print("Start searching ...") - if search_cf_orders is None: - search_cf_orders = range(10, 1, -1) - n_poles = sum([p.size for p in mp_data["poles"]]) n_win_min = max(5, n_poles // 20) n_win_max = 2000 if n_poles < 2000 else 8000 best_wmp = best_metric = None - for n_w in np.unique( - np.linspace(n_win_min, n_win_max, search_n_win, dtype=int) - ): - for n_cf in search_cf_orders: + for n_w in np.unique(np.linspace(n_win_min, n_win_max, 20, dtype=int)): + for n_cf in range(10, 1, -1): if log: - print(f"Testing N_win={n_w} N_cf={n_cf}") + print("Testing N_win={} N_cf={}".format(n_w, n_cf)) # update arguments dictionary kwargs.update(n_win=n_w, n_cf=n_cf) @@ -1161,8 +1154,8 @@ class WindowedMultipole(EqualityMixin): Returns ------- 3-tuple of Real - Scattering, absorption, and fission microscopic cross sections - at the given energy and temperature. + Total, absorption, and fission microscopic cross sections at the + given energy and temperature. """ @@ -1177,11 +1170,10 @@ class WindowedMultipole(EqualityMixin): sqrtE = sqrt(E) invE = 1.0 / E - # Locate us. The i_window calc omits a + 1 present from the legacy - # Fortran version of OpenMC because of the 1-based vs. 0-based - # indexing. Similarly startw needs to be decreased by 1. endw does - # not need to be decreased because range(startw, endw) does not include - # endw. + # Locate us. The i_window calc omits a + 1 present in F90 because of + # the 1-based vs. 0-based indexing. Similarly startw needs to be + # decreased by 1. endw does not need to be decreased because + # range(startw, endw) does not include endw. i_window = min(self.n_windows - 1, int(np.floor((sqrtE - sqrt(self.E_min)) / self.spacing))) startw = self.windows[i_window, 0] - 1 @@ -1256,8 +1248,8 @@ class WindowedMultipole(EqualityMixin): Returns ------- 3-tuple of Real or 3-tuple of numpy.ndarray - Scattering, absorption, and fission microscopic cross sections - at the given energy and temperature. + Total, absorption, and fission microscopic cross sections at the + given energy and temperature. """ @@ -1282,7 +1274,7 @@ class WindowedMultipole(EqualityMixin): # Open file and write version. with h5py.File(str(path), mode, libver=libver) as f: - f.attrs['filetype'] = np.bytes_('data_wmp') + f.attrs['filetype'] = np.string_('data_wmp') f.attrs['version'] = np.array(WMP_VERSION) g = f.create_group(self.name) diff --git a/openmc/data/nbody.py b/openmc/data/nbody.py index ec1ac25c0..4db9934b9 100644 --- a/openmc/data/nbody.py +++ b/openmc/data/nbody.py @@ -43,6 +43,18 @@ class NBodyPhaseSpace(AngleEnergy): def total_mass(self): return self._total_mass + @property + def n_particles(self): + return self._n_particles + + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + + @property + def q_value(self): + return self._q_value + @total_mass.setter def total_mass(self, total_mass): name = 'N-body phase space total mass' @@ -50,10 +62,6 @@ class NBodyPhaseSpace(AngleEnergy): cv.check_greater_than(name, total_mass, 0.) self._total_mass = total_mass - @property - def n_particles(self): - return self._n_particles - @n_particles.setter def n_particles(self, n_particles): name = 'N-body phase space number of particles' @@ -61,10 +69,6 @@ class NBodyPhaseSpace(AngleEnergy): cv.check_greater_than(name, n_particles, 0) self._n_particles = n_particles - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): name = 'N-body phase space atomic weight ratio' @@ -72,10 +76,6 @@ class NBodyPhaseSpace(AngleEnergy): cv.check_greater_than(name, atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio - @property - def q_value(self): - return self._q_value - @q_value.setter def q_value(self, q_value): name = 'N-body phase space Q value' @@ -91,7 +91,7 @@ class NBodyPhaseSpace(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('nbody') + group.attrs['type'] = np.string_('nbody') group.attrs['total_mass'] = self.total_mass group.attrs['n_particles'] = self.n_particles group.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index f17bb3fe4..db78ce27b 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from collections.abc import Mapping, MutableMapping from io import StringIO from math import log10 @@ -11,13 +12,13 @@ import h5py from . import HDF5_VERSION, HDF5_VERSION_MAJOR from .ace import Library, Table, get_table, get_metadata -from .data import ATOMIC_SYMBOL, K_BOLTZMANN, EV_PER_MEV, gnds_name +from .data import ATOMIC_SYMBOL, K_BOLTZMANN, EV_PER_MEV from .endf import ( - Evaluation, SUM_RULES, as_evaluation, get_head_record, get_tab1_record, - get_evaluations) + Evaluation, SUM_RULES, get_head_record, get_tab1_record, get_evaluations) from .fission_energy import FissionEnergyRelease from .function import Tabulated1D, Sum, ResonancesWithBackground -from .njoy import make_ace, make_pendf +from .grid import linearize, thin +from .njoy import make_ace from .product import Product from .reaction import Reaction, _get_photon_products_ace, FISSION_MTS from . import resonance as res @@ -43,7 +44,7 @@ class IncidentNeutron(EqualityMixin): Parameters ---------- name : str - Name of the nuclide using the GNDS naming convention + Name of the nuclide using the GND naming convention atomic_number : int Number of protons in the target nucleus mass_number : int @@ -74,8 +75,8 @@ class IncidentNeutron(EqualityMixin): Metastable state of the target nucleus. A value of zero indicates ground state. name : str - Name of the nuclide using the GNDS naming convention - reactions : dict + Name of the nuclide using the GND naming convention + reactions : collections.OrderedDict Contains the cross sections, secondary angle and energy distributions, and other associated data for each reaction. The keys are the MT values and the values are Reaction objects. @@ -106,7 +107,7 @@ class IncidentNeutron(EqualityMixin): self.kTs = kTs self.energy = {} self._fission_energy = None - self.reactions = {} + self.reactions = OrderedDict() self._urr = {} self._resonances = None @@ -122,10 +123,10 @@ class IncidentNeutron(EqualityMixin): if len(mts) > 0: return self._get_redundant_reaction(mt, mts) else: - raise KeyError(f'No reaction with MT={mt}.') + raise KeyError('No reaction with MT={}.'.format(mt)) def __repr__(self): - return f"" + return "".format(self.name) def __iter__(self): return iter(self.reactions.values()) @@ -134,14 +135,54 @@ class IncidentNeutron(EqualityMixin): def name(self): return self._name + @property + def atomic_number(self): + return self._atomic_number + + @property + def mass_number(self): + return self._mass_number + + @property + def metastable(self): + return self._metastable + + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + + @property + def fission_energy(self): + return self._fission_energy + + @property + def reactions(self): + return self._reactions + + @property + def resonances(self): + return self._resonances + + @property + def resonance_covariance(self): + return self._resonance_covariance + + @property + def urr(self): + return self._urr + + @property + def temperatures(self): + return ["{}K".format(int(round(kT / K_BOLTZMANN))) for kT in self.kTs] + @name.setter def name(self, name): cv.check_type('name', name, str) self._name = name @property - def atomic_number(self): - return self._atomic_number + def atomic_symbol(self): + return ATOMIC_SYMBOL[self.atomic_number] @atomic_number.setter def atomic_number(self, atomic_number): @@ -149,78 +190,46 @@ class IncidentNeutron(EqualityMixin): cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number - @property - def mass_number(self): - return self._mass_number - @mass_number.setter def mass_number(self, mass_number): cv.check_type('mass number', mass_number, Integral) cv.check_greater_than('mass number', mass_number, 0, True) self._mass_number = mass_number - @property - def metastable(self): - return self._metastable - @metastable.setter def metastable(self, metastable): cv.check_type('metastable', metastable, Integral) cv.check_greater_than('metastable', metastable, 0, True) self._metastable = metastable - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) cv.check_greater_than('atomic weight ratio', atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio - @property - def fission_energy(self): - return self._fission_energy - @fission_energy.setter def fission_energy(self, fission_energy): cv.check_type('fission energy release', fission_energy, FissionEnergyRelease) self._fission_energy = fission_energy - @property - def reactions(self): - return self._reactions - @reactions.setter def reactions(self, reactions): cv.check_type('reactions', reactions, Mapping) self._reactions = reactions - @property - def resonances(self): - return self._resonances - @resonances.setter def resonances(self, resonances): cv.check_type('resonances', resonances, res.Resonances) self._resonances = resonances - @property - def resonance_covariance(self): - return self._resonance_covariance - @resonance_covariance.setter def resonance_covariance(self, resonance_covariance): cv.check_type('resonance covariance', resonance_covariance, res_cov.ResonanceCovariances) self._resonance_covariance = resonance_covariance - @property - def urr(self): - return self._urr - @urr.setter def urr(self, urr): cv.check_type('probability table dictionary', urr, MutableMapping) @@ -229,14 +238,6 @@ class IncidentNeutron(EqualityMixin): cv.check_type('probability tables', value, ProbabilityTables) self._urr = urr - @property - def temperatures(self): - return [f"{int(round(kT / K_BOLTZMANN))}K" for kT in self.kTs] - - @property - def atomic_symbol(self): - return ATOMIC_SYMBOL[self.atomic_number] - def add_temperature_from_ace(self, ace_or_filename, metastable_scheme='nndc'): """Append data from an ACE file at a different temperature. @@ -261,7 +262,7 @@ class IncidentNeutron(EqualityMixin): # Check if temprature already exists strT = data.temperatures[0] if strT in self.temperatures: - warn(f'Cross sections at T={strT} already exist.') + warn('Cross sections at T={} already exist.'.format(strT)) return # Check that name matches @@ -286,7 +287,7 @@ class IncidentNeutron(EqualityMixin): if strT in data.urr: self.urr[strT] = data.urr[strT] - def add_elastic_0K_from_endf(self, filename, overwrite=False, **kwargs): + def add_elastic_0K_from_endf(self, filename, overwrite=False): """Append 0K elastic scattering cross section from an ENDF file. Parameters @@ -297,8 +298,6 @@ class IncidentNeutron(EqualityMixin): If existing 0 K data is present, this flag can be used to indicate that it should be overwritten. Otherwise, an exception will be thrown. - **kwargs - Keyword arguments passed to :func:`openmc.data.njoy.make_pendf` Raises ------ @@ -311,22 +310,75 @@ class IncidentNeutron(EqualityMixin): if '0K' in self.energy and not overwrite: raise ValueError('0 K data already exists for this nuclide.') - with tempfile.TemporaryDirectory() as tmpdir: - # Set arguments for make_pendf - pendf_path = os.path.join(tmpdir, 'pendf') - kwargs.setdefault('output_dir', tmpdir) - kwargs.setdefault('pendf', pendf_path) + data = type(self).from_endf(filename) + if data.resonances is not None: + x = [] + y = [] + for rr in data.resonances: + if isinstance(rr, res.RMatrixLimited): + raise TypeError('R-Matrix Limited not supported.') + elif isinstance(rr, res.Unresolved): + continue - # Run NJOY to create a pointwise ENDF file - make_pendf(filename, **kwargs) + # Get energies/widths for resonances + e_peak = rr.parameters['energy'].values + if isinstance(rr, res.MultiLevelBreitWigner): + gamma = rr.parameters['totalWidth'].values + elif isinstance(rr, res.ReichMoore): + df = rr.parameters + gamma = (df['neutronWidth'] + + df['captureWidth'] + + abs(df['fissionWidthA']) + + abs(df['fissionWidthB'])).values - # Add 0K elastic scattering cross section - pendf = Evaluation(pendf_path) - file_obj = StringIO(pendf.section[3, 2]) - get_head_record(file_obj) - params, xs = get_tab1_record(file_obj) - self.energy['0K'] = xs.x - self[2].xs['0K'] = xs + # Determine peak energies and widths + e_min, e_max = rr.energy_min, rr.energy_max + in_range = (e_peak > e_min) & (e_peak < e_max) + e_peak = e_peak[in_range] + gamma = gamma[in_range] + + # Get midpoints between resonances (use min/max energy of + # resolved region as absolute lower/upper bound) + e_mid = np.concatenate( + ([e_min], (e_peak[1:] + e_peak[:-1])/2, [e_max])) + + # Add grid around each resonance that includes the peak +/- the + # width times each value in _RESONANCE_ENERGY_GRID. Values are + # constrained so that points around one resonance don't overlap + # with points around another. This algorithm is from Fudge + # (https://doi.org/10.1063/1.1945057). + energies = [] + for e, g, e_lower, e_upper in zip(e_peak, gamma, e_mid[:-1], + e_mid[1:]): + e_left = e - g*_RESONANCE_ENERGY_GRID + energies.append(e_left[e_left > e_lower][::-1]) + e_right = e + g*_RESONANCE_ENERGY_GRID[1:] + energies.append(e_right[e_right < e_upper]) + + # Concatenate all points + energies = np.concatenate(energies) + + # Create 1000 equal log-spaced energies over RRR, combine with + # resonance peaks and half-height energies + e_log = np.logspace(log10(e_min), log10(e_max), 1000) + energies = np.union1d(e_log, energies) + + # Linearize and thin cross section + xi, yi = linearize(energies, data[2].xs['0K']) + xi, yi = thin(xi, yi) + + # If there are multiple resolved resonance ranges (e.g. Pu239 in + # ENDF/B-VII.1), combine them + x = np.concatenate((x, xi)) + y = np.concatenate((y, yi)) + else: + energies = data[2].xs['0K'].x + x, y = linearize(energies, data[2].xs['0K']) + x, y = thin(x, y) + + # Set 0K energy grid and elastic scattering cross section + self.energy['0K'] = x + self[2].xs['0K'] = Tabulated1D(x, y) def get_reaction_components(self, mt): """Determine what reactions make up redundant reaction. @@ -374,7 +426,7 @@ class IncidentNeutron(EqualityMixin): # Open file and write version with h5py.File(str(path), mode, libver=libver) as f: - f.attrs['filetype'] = np.bytes_('data_neutron') + f.attrs['filetype'] = np.string_('data_neutron') f.attrs['version'] = np.array(HDF5_VERSION) # Write basic data @@ -410,7 +462,7 @@ class IncidentNeutron(EqualityMixin): if not (photon_rx or rx.mt in keep_mts): continue - rx_group = rxs_group.create_group(f'reaction_{rx.mt:03}') + rx_group = rxs_group.create_group('reaction_{:03}'.format(rx.mt)) rx.to_hdf5(rx_group) # Write total nu data if available @@ -542,7 +594,7 @@ class IncidentNeutron(EqualityMixin): zaid, xs = ace.name.split('.') if not xs.endswith('c'): raise TypeError( - f"{ace} is not a continuous-energy neutron ACE table.") + "{} is not a continuous-energy neutron ACE table.".format(ace)) name, element, Z, mass_number, metastable = \ get_metadata(int(zaid), metastable_scheme) @@ -653,7 +705,7 @@ class IncidentNeutron(EqualityMixin): Parameters ---------- - ev_or_filename : openmc.data.endf.Evaluation, endf.Material, or str + ev_or_filename : openmc.data.endf.Evaluation or str ENDF evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -667,7 +719,10 @@ class IncidentNeutron(EqualityMixin): Incident neutron continuous-energy data """ - ev = as_evaluation(ev_or_filename) + if isinstance(ev_or_filename, Evaluation): + ev = ev_or_filename + else: + ev = Evaluation(ev_or_filename) atomic_number = ev.target['atomic_number'] mass_number = ev.target['mass_number'] @@ -676,7 +731,11 @@ class IncidentNeutron(EqualityMixin): temperature = ev.target['temperature'] # Determine name - name = gnds_name(atomic_number, mass_number, metastable) + element = ATOMIC_SYMBOL[atomic_number] + if metastable > 0: + name = '{}{}_m{}'.format(element, mass_number, metastable) + else: + name = '{}{}'.format(element, mass_number) # Instantiate incident neutron data data = cls(name, atomic_number, mass_number, metastable, @@ -763,11 +822,6 @@ class IncidentNeutron(EqualityMixin): for table in lib.tables[1:]: data.add_temperature_from_ace(table) - # Use name based on ENDF evaluation. The name assigned by from_ace - # may be wrong for higher metastable states (e.g., Hf178_m2) - ev = evaluation if evaluation is not None else Evaluation(filename) - data.name = ev.gnds_name - # Add 0K elastic scattering cross section if '0K' not in data.energy: pendf = Evaluation(kwargs['pendf']) @@ -778,6 +832,7 @@ class IncidentNeutron(EqualityMixin): data[2].xs['0K'] = xs # Add fission energy release data + ev = evaluation if evaluation is not None else Evaluation(filename) if (1, 458) in ev.section: data.fission_energy = f = FissionEnergyRelease.from_endf(ev, data) else: @@ -803,7 +858,9 @@ class IncidentNeutron(EqualityMixin): # Helper function to get a cross section from an ENDF file on a # given energy grid def get_file3_xs(ev, mt, E): - xs = ev.section_data[3, mt]['sigma'] + file_obj = StringIO(ev.section[3, mt]) + get_head_record(file_obj) + _, xs = get_tab1_record(file_obj) return xs(E) heating_local = Reaction(901) @@ -811,8 +868,9 @@ class IncidentNeutron(EqualityMixin): heatr_evals = get_evaluations(kwargs["heatr"]) heatr_local_evals = get_evaluations(kwargs["heatr"] + "_local") + for ev, ev_local in zip(heatr_evals, heatr_local_evals): + temp = "{}K".format(round(ev.target["temperature"])) - for ev, ev_local, temp in zip(heatr_evals, heatr_local_evals, data.temperatures): # Get total KERMA (originally from ACE file) and energy grid kerma = data.reactions[301].xs[temp] E = kerma.x diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 7c99637f0..d8ecaae18 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -15,96 +15,24 @@ import openmc.data # identifiers. ThermalTuple = namedtuple('ThermalTuple', ['name', 'zaids', 'nmix']) _THERMAL_DATA = { - 'c_Ag': ThermalTuple('ag', [47107, 47109], 1), 'c_Al27': ThermalTuple('al27', [13027], 1), 'c_Al_in_Al2O3': ThermalTuple('asap00', [13027], 1), - 'c_Al_in_Y3Al5O12': ThermalTuple('alyag', [13027], 1), - 'c_Au': ThermalTuple('au', [79197], 1), 'c_Be': ThermalTuple('be', [4009], 1), - 'c_Be_distinct': ThermalTuple('besd', [4009], 1), 'c_Be_in_BeO': ThermalTuple('bebeo', [4009], 1), 'c_Be_in_Be2C': ThermalTuple('bebe2c', [4009], 1), - 'c_Be_in_BeF2': ThermalTuple('bebef2', [4009], 1), 'c_Be_in_FLiBe': ThermalTuple('beflib', [4009], 1), - 'c_BeO': ThermalTuple('beo', [4009, 8016, 8017, 8018], 2), - 'c_Bi': ThermalTuple('bi', [83209], 1), - 'c_Bi_in_Ge3Bi4O12': ThermalTuple('bigbo', [83209], 1), 'c_C6H6': ThermalTuple('benz', [1001, 6000, 6012], 2), - 'c_C_in_Be2C': ThermalTuple('cbe2c', [6000, 6012, 6013], 1), - 'c_C_in_C5O2H8': ThermalTuple('clucit', [6000, 6012, 6013], 1), - 'c_C_in_C8H8': ThermalTuple('cc8h8', [6000, 6012, 6013], 1), - 'c_C_in_C19H16_liquid': ThermalTuple('c19liq', [6000, 6012, 6013], 1), - 'c_C_in_C19H16_solid': ThermalTuple('c19sol', [6000, 6012, 6013], 1), - 'c_C_in_C2H6O_liquid': ThermalTuple('ethliq', [6000, 6012, 6013], 1), - 'c_C_in_C2H6O_solid': ThermalTuple('ethsol', [6000, 6012, 6013], 1), - 'c_C_in_C6H6_liquid': ThermalTuple('benzlq', [6000, 6012, 6013], 1), - 'c_C_in_C6H6_solid': ThermalTuple('benzsl', [6000, 6012, 6013], 1), - 'c_C_in_C7H8_liquid': ThermalTuple('tolliq', [6000, 6012, 6013], 1), - 'c_C_in_C7H8_solid': ThermalTuple('tolsol', [6000, 6012, 6013], 1), - 'c_C_in_C8H10_liquid': ThermalTuple('xylliq', [6000, 6012, 6013], 1), - 'c_C_in_C8H10_solid': ThermalTuple('xylsol', [6000, 6012, 6013], 1), - 'c_C_in_C9H12_liquid': ThermalTuple('mesliq', [6000, 6012, 6013], 1), - 'c_C_in_C9H12_solid': ThermalTuple('messol', [6000, 6012, 6013], 1), - 'c_C_in_CF2': ThermalTuple('ccf2', [6000, 6012, 6013], 1), - 'c_C_in_CH2': ThermalTuple('cch2', [6000, 6012, 6013], 1), - 'c_C_in_CH4_liquid': ThermalTuple('cch4lq', [6000, 6012, 6013], 1), - 'c_C_in_CH4_solid': ThermalTuple('cch4sl', [6000, 6012, 6013], 1), - 'c_C_in_Diamond': ThermalTuple('cdiam', [6000, 6012, 6013], 1), 'c_C_in_SiC': ThermalTuple('csic', [6000, 6012, 6013], 1), - 'c_C_in_UC_100p': ThermalTuple('cuc100', [6000, 6012, 6013], 1), - 'c_C_in_UC_10p': ThermalTuple('cuc10', [6000, 6012, 6013], 1), - 'c_C_in_UC_5p': ThermalTuple('cuc5', [6000, 6012, 6013], 1), - 'c_C_in_UC': ThermalTuple('cinuc', [6000, 6012, 6013], 1), - 'c_C_in_UC_HALEU': ThermalTuple('cuchal', [6000, 6012, 6013], 1), - 'c_C_in_UC_HEU': ThermalTuple('cucheu', [6000, 6012, 6013], 1), - 'c_C_in_ZrC': ThermalTuple('czrc', [6000, 6012, 6013], 1), - 'c_Ca': ThermalTuple('ca', [20040, 20042, 20043, 20044, 20046, 20048], 1), 'c_Ca_in_CaH2': ThermalTuple('cacah2', [20040, 20042, 20043, 20044, 20046, 20048], 1), - 'c_Ca_in_CaO2H2': ThermalTuple('cacaoh', [20040, 20042, 20043, 20044, 20046, 20048], 1), - 'c_Cr': ThermalTuple('cr', [24050, 24052, 24053, 24054], 1), - 'c_Cu': ThermalTuple('cu', [29063, 29065], 1), - 'c_D_in_7LiD': ThermalTuple('dlid', [1002], 1), 'c_D_in_D2O': ThermalTuple('dd2o', [1002], 1), 'c_D_in_D2O_solid': ThermalTuple('dice', [1002], 1), - 'c_D_in_MgD2': ThermalTuple('dmgd2', [1002], 1), - 'c_F_in_Be2': ThermalTuple('fbef2', [9019], 1), - 'c_F_in_CF2': ThermalTuple('fcf2', [9019], 1), 'c_F_in_FLiBe': ThermalTuple('fflibe', [9019], 1), - 'c_F_in_HF': ThermalTuple('f_hf', [9019], 1), - 'c_F_in_LiF': ThermalTuple('flif', [9019], 1), - 'c_F_in_MgF2': ThermalTuple('fmgf2', [9019], 1), 'c_Fe56': ThermalTuple('fe56', [26056], 1), - 'c_Fe_in_Fe_alpha': ThermalTuple('fealph', [26054, 26056, 26057, 26058], 1), - 'c_Fe_in_Fe_gamma': ThermalTuple('fegamm', [26054, 26056, 26057, 26058], 1), - 'c_Ga_in_GaN': ThermalTuple('gagan', [31069, 31071], 1), - 'c_Ga_in_GaSe': ThermalTuple('gagase', [31069, 31071], 1), - 'c_Ge': ThermalTuple('ge', [32070, 32072, 32073, 32074, 32076], 1), - 'c_Ge_in_Ge3Bi4O12': ThermalTuple('gegbo', [32070, 32072, 32073, 32074, 32076], 1), - 'c_Ge_in_GeTe': ThermalTuple('gegete', [32070, 32072, 32073, 32074, 32076], 1), 'c_Graphite': ThermalTuple('graph', [6000, 6012, 6013], 1), 'c_Graphite_10p': ThermalTuple('grph10', [6000, 6012, 6013], 1), - 'c_Graphite_20p': ThermalTuple('grph20', [6000, 6012, 6013], 1), 'c_Graphite_30p': ThermalTuple('grph30', [6000, 6012, 6013], 1), - 'c_Graphite_distinct': ThermalTuple('grphsd', [6000, 6012, 6013], 1), - 'c_H_in_7LiH': ThermalTuple('hlih', [1001], 1), 'c_H_in_C5O2H8': ThermalTuple('lucite', [1001], 1), - 'c_H_in_C8H8': ThermalTuple('hc8h8', [1001], 1), - 'c_H_in_C19H16_liquid': ThermalTuple('h19liq', [1001], 1), - 'c_H_in_C19H16_solid': ThermalTuple('h19sol', [1001], 1), - 'c_H_in_C2H6O_liquid': ThermalTuple('hetliq', [1001], 1), - 'c_H_in_C2H6O_solid': ThermalTuple('hetsol', [1001], 1), - 'c_H_in_C6H6_liquid': ThermalTuple('hbzliq', [1001], 1), - 'c_H_in_C6H6_solid': ThermalTuple('hbzsol', [1001], 1), - 'c_H_in_C7H8_liquid': ThermalTuple('htlliq', [1001], 1), - 'c_H_in_C7H8_solid': ThermalTuple('htlsol', [1001], 1), - 'c_H_in_C8H10_liquid': ThermalTuple('hxyliq', [1001], 1), - 'c_H_in_C8H10_solid': ThermalTuple('hxysol', [1001], 1), - 'c_H_in_C9H12_liquid': ThermalTuple('hmsliq', [1001], 1), - 'c_H_in_C9H12_solid': ThermalTuple('hmssol', [1001], 1), 'c_H_in_CaH2': ThermalTuple('hcah2', [1001], 1), - 'c_H_in_CaO2H2': ThermalTuple('hcaoh', [1001], 1), - 'c_H1_in_CaH2': ThermalTuple('h1cah2', [1001], 1), - 'c_H2_in_CaH2': ThermalTuple('h2cah2', [1001], 1), 'c_H_in_CH2': ThermalTuple('hch2', [1001], 1), 'c_H_in_CH4_liquid': ThermalTuple('lch4', [1001], 1), 'c_H_in_CH4_solid': ThermalTuple('sch4', [1001], 1), @@ -112,124 +40,33 @@ _THERMAL_DATA = { 'c_H_in_H2O': ThermalTuple('hh2o', [1001], 1), 'c_H_in_H2O_solid': ThermalTuple('hice', [1001], 1), 'c_H_in_HF': ThermalTuple('hhf', [1001], 1), - 'c_H_in_KOH': ThermalTuple('hkoh', [1001], 1), - 'c_H_in_LiH': ThermalTuple('hlih2', [1001], 1), 'c_H_in_Mesitylene': ThermalTuple('mesi00', [1001], 1), 'c_H_in_ParaffinicOil': ThermalTuple('hparaf', [1001], 1), 'c_H_in_Toluene': ThermalTuple('tol00', [1001], 1), - 'c_H_in_MgH2': ThermalTuple('hmgh2', [1001], 1), - 'c_H_in_MgOH2': ThermalTuple('hmgoh', [1001], 1), - 'c_H_in_NaMgH3': ThermalTuple('hnamg', [1001], 1), - 'c_H_in_NaOH': ThermalTuple('hnaoh', [1001], 1), - 'c_H_in_SrH2': ThermalTuple('hsrh2', [1001], 1), 'c_H_in_UH3': ThermalTuple('huh3', [1001], 1), 'c_H_in_YH2': ThermalTuple('hyh2', [1001], 1), 'c_H_in_ZrH': ThermalTuple('hzrh', [1001], 1), 'c_H_in_ZrH2': ThermalTuple('hzrh2', [1001], 1), 'c_H_in_ZrHx': ThermalTuple('hzrhx', [1001], 1), - 'c_I_in_NaI': ThermalTuple('inai', [53127], 1), - 'c_K': ThermalTuple('k', [19039, 19040, 19041], 1), - 'c_K_in_KOH': ThermalTuple('kkoh', [19039, 19040, 19041], 1), 'c_Li_in_FLiBe': ThermalTuple('liflib', [3006, 3007], 1), - 'c_Li_in_7LiD': ThermalTuple('lilid', [3007], 1), - 'c_Li_in_7LiH': ThermalTuple('lilih', [3007], 1), - 'c_Li_in_LiF': ThermalTuple('lilif', [3006, 3007], 1), - 'c_Li_in_LiH': ThermalTuple('lilih2', [3006, 3007], 1), 'c_Mg24': ThermalTuple('mg24', [12024], 1), - 'c_Mg_in_MgF2': ThermalTuple('mgmgf2', [12024, 12025, 12026], 1), - 'c_Mg_in_MgO': ThermalTuple('mgmgo', [12024, 12025, 12026], 1), - 'c_Mg_in_MgD2': ThermalTuple('mgmgd2', [12024, 12025, 12026], 1), - 'c_Mg_in_MgH2': ThermalTuple('mgmgh2', [12024, 12025, 12026], 1), - 'c_Mg_in_MgOH2': ThermalTuple('mgoh2', [12024, 12025, 12026], 1), - 'c_Mg_in_NaMgH3': ThermalTuple('mgnamg', [12024, 12025, 12026], 1), - 'c_Mo': ThermalTuple('mo', [42092, 42094, 42095, 42096, 42097, 42098, 42100], 1), - 'c_N_in_GaN': ThermalTuple('ngan', [7014, 7015], 1), - 'c_N_in_UN_100p': ThermalTuple('nun100', [7014, 7015], 1), - 'c_N_in_UN_10p': ThermalTuple('nun10', [7014, 7015], 1), - 'c_N_in_UN_5p': ThermalTuple('nun5', [7014, 7015], 1), 'c_N_in_UN': ThermalTuple('n-un', [7014, 7015], 1), - 'c_N_in_UN_HALEU': ThermalTuple('nunhal', [7014, 7015], 1), - 'c_N_in_UN_HEU': ThermalTuple('nunheu', [7014, 7015], 1), - 'c_Na': ThermalTuple('na', [11023], 1), - 'c_Na_in_NaI': ThermalTuple('nanai', [11023], 1), - 'c_Na_in_NaMgH3': ThermalTuple('nanamg', [11023], 1), - 'c_Na_in_NaOH': ThermalTuple('nanaoh', [11023], 1), - 'c_Nb': ThermalTuple('nb', [41093], 1), - 'c_Ni': ThermalTuple('ni', [28058, 28060, 28061, 28062, 28064], 1), - 'c_O_in_Al2O3': ThermalTuple('osap00', [8016, 8017, 8018], 1), + 'c_O_in_Al2O3': ThermalTuple('osap00', [92238], 1), 'c_O_in_BeO': ThermalTuple('obeo', [8016, 8017, 8018], 1), - 'c_O_in_C5O2H8': ThermalTuple('olucit', [8016, 8017, 8018], 1), - 'c_O_in_C2H6O_liquid': ThermalTuple('oetliq', [8016, 8017, 8018], 1), - 'c_O_in_C2H6O_solid': ThermalTuple('oetsol', [8016, 8017, 8018], 1), - 'c_O_in_CaO2H2': ThermalTuple('ocaoh', [8016, 8017, 8018], 1), 'c_O_in_D2O': ThermalTuple('od2o', [8016, 8017, 8018], 1), 'c_O_in_H2O_solid': ThermalTuple('oice', [8016, 8017, 8018], 1), - 'c_O_in_MgO': ThermalTuple('omgo', [8016, 8017, 8018], 1), - 'c_O_in_Ge3Bi4O12': ThermalTuple('ogbo', [8016, 8017, 8018], 1), - 'c_O_in_H2O': ThermalTuple('oh2o', [8016, 8017, 8018], 1), - 'c_O_in_KOH': ThermalTuple('okoh', [8016, 8017, 8018], 1), - 'c_O_in_MgOH2': ThermalTuple('omgoh', [8016, 8017, 8018], 1), - 'c_O_in_NaOH': ThermalTuple('onaoh', [8016, 8017, 8018], 1), - 'c_O_in_PuO2': ThermalTuple('opuo2', [8016, 8017, 8018], 1), - 'c_O_in_SiO2_alpha': ThermalTuple('osio2a', [8016, 8017, 8018], 1), - 'c_O_in_UO2_100p': ThermalTuple('ouo200', [8016, 8017, 8018], 1), - 'c_O_in_UO2_10p': ThermalTuple('ouo210', [8016, 8017, 8018], 1), - 'c_O_in_UO2_5p': ThermalTuple('ouo25', [8016, 8017, 8018], 1), 'c_O_in_UO2': ThermalTuple('ouo2', [8016, 8017, 8018], 1), - 'c_O_in_UO2_HALEU': ThermalTuple('ouo2hl', [8016, 8017, 8018], 1), - 'c_O_in_UO2_HEU': ThermalTuple('ouo2he', [8016, 8017, 8018], 1), - 'c_O_in_Y3Al5O12': ThermalTuple('oyag', [8016, 8017, 8018], 1), 'c_ortho_D': ThermalTuple('orthod', [1002], 1), 'c_ortho_H': ThermalTuple('orthoh', [1001], 1), 'c_para_D': ThermalTuple('parad', [1002], 1), 'c_para_H': ThermalTuple('parah', [1001], 1), - 'c_Pb': ThermalTuple('pb', [82204, 82206, 82207, 82208], 1), - 'c_Pd': ThermalTuple('pd', [46102, 46104, 46105, 46106, 46108, 46110], 1), - 'c_Pt': ThermalTuple('pt', [78190, 78192, 78194, 78195, 78196, 78198], 1), - 'c_Pu_in_PuO2': ThermalTuple('puo2', [94239, 94240, 94241, 94242, 94243], 1), 'c_Si28': ThermalTuple('si00', [14028], 1), 'c_Si_in_SiC': ThermalTuple('sisic', [14028, 14029, 14030], 1), - 'c_Si_in_SiO2_alpha': ThermalTuple('si_o2a', [14028, 14029, 14030], 1), 'c_SiO2_alpha': ThermalTuple('sio2-a', [8016, 8017, 8018, 14028, 14029, 14030], 3), 'c_SiO2_beta': ThermalTuple('sio2-b', [8016, 8017, 8018, 14028, 14029, 14030], 3), - 'c_S_in_ZnS': ThermalTuple('szns', [16032, 16033, 16034, 16036], 1), - 'c_Se_in_GaSe': ThermalTuple('segase', [34074, 34076, 34077, 34078, 34080, 34082], 1), - 'c_Sn': ThermalTuple('sn', [50112, 50114, 50115, 50116, 50117, 50118, 50119, 50120, 50122, 50124], 1), - 'c_Sr_in_SrH2': ThermalTuple('srsrh2', [38084, 38086, 38087, 38088], 1), - 'c_Te_in_GeTe': ThermalTuple('tegete', [52120, 52122, 52123, 52124, 52125, 52126, 52128, 52130], 1), - 'c_Ti': ThermalTuple('ti', [22046, 22047, 22048, 22049, 22050], 1), - 'c_U_metal_100p': ThermalTuple('u-100p', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_metal_10p': ThermalTuple('u-10p', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_metal_5p': ThermalTuple('u-5p', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_metal': ThermalTuple('umetal', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_metal_HALEU': ThermalTuple('uhaleu', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_metal_HEU': ThermalTuple('u-heu', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UC_100p': ThermalTuple('uc-100', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UC_10p': ThermalTuple('uc-10', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UC_5p': ThermalTuple('uc-5', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UC': ThermalTuple('uc-nat', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UC_HALEU': ThermalTuple('uc-hal', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UC_HEU': ThermalTuple('uc-heu', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UN_100p': ThermalTuple('un-100', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UN_10p': ThermalTuple('un-10', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UN_5p': ThermalTuple('un-5', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UN': ThermalTuple('u-un', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UN_HALEU': ThermalTuple('un-hal', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UN_HEU': ThermalTuple('un-heu', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UO2_100p': ThermalTuple('uo2100', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UO2_10p': ThermalTuple('uo2-10', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UO2_5p': ThermalTuple('uo2-5', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UO2': ThermalTuple('uuo2', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UO2_HALEU': ThermalTuple('uo2hal', [92233, 92234, 92235, 92236, 92238], 1), - 'c_U_in_UO2_HEU': ThermalTuple('uo2heu', [92233, 92234, 92235, 92236, 92238], 1), - 'c_V': ThermalTuple('v', [23050, 23051], 1), - 'c_W': ThermalTuple('w', [74180, 74182, 74183, 74184, 74186], 1), - 'c_Y_in_Y3Al5O12': ThermalTuple('yyag', [39089], 1), + 'c_U_in_UN': ThermalTuple('u-un', [92238], 1), + 'c_U_in_UO2': ThermalTuple('uuo2', [8016, 8017, 8018], 1), 'c_Y_in_YH2': ThermalTuple('yyh2', [39089], 1), - 'c_Zn': ThermalTuple('zn', [30064, 30066, 30067, 30068, 30070], 1), - 'c_Zn_in_ZnS': ThermalTuple('znzns', [30064, 30066, 30067, 30068, 30070], 1), - 'c_Zr': ThermalTuple('zr', [40090, 40091, 40092, 40094, 40096], 1), - 'c_Zr_in_ZrC': ThermalTuple('zrzrc', [40000, 40090, 40091, 40092, 40094, 40096], 1), 'c_Zr_in_ZrH': ThermalTuple('zrzrh', [40000, 40090, 40091, 40092, 40094, 40096], 1), 'c_Zr_in_ZrH2': ThermalTuple('zrzrh2', [40000, 40090, 40091, 40092, 40094, 40096], 1), 'c_Zr_in_ZrHx': ThermalTuple('zrzrhx', [40000, 40090, 40091, 40092, 40094, 40096], 1), @@ -259,14 +96,14 @@ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% _TEMPLATE_HEATR = """ heatr / %%%%%%%%%%%%%%%%%%%%%%%%% Add heating kerma %%%%%%%%%%%%%%%%%%%%%%%%%%%% {nendf} {nheatr_in} {nheatr} / -{mat} 4 0 0 0 0 {ed}/ +{mat} 4 0 0 0 / 302 318 402 444 / """ _TEMPLATE_HEATR_LOCAL = """ heatr / %%%%%%%%%%%%%%%%% Add heating kerma (local photons) %%%%%%%%%%%%%%%%%%%% {nendf} {nheatr_in} {nheatr_local} / -{mat} 4 0 0 1 0 {ed}/ +{mat} 4 0 0 1 / 302 318 402 444 / """ @@ -297,12 +134,12 @@ acer / %%%%%%%%%%%%%%%%%%%%%%%% Write out in ACE format %%%%%%%%%%%%%%%%%%%%%%%% _THERMAL_TEMPLATE_THERMR = """ thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (free gas) %%%%%%%%%%%%%%% 0 {nthermr1_in} {nthermr1} -0 {mat} {nbin} {num_temp} 1 0 {iform} 1 221 1/ +0 {mat} 12 {num_temp} 1 0 {iform} 1 221 1/ {temps} {error} {energy_max} thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (bound) %%%%%%%%%%%%%%%%%% {nthermal_endf} {nthermr2_in} {nthermr2} -{mat_thermal} {mat} {nbin} {num_temp} {inelastic} {elastic} {iform} {natom} 222 1/ +{mat_thermal} {mat} 16 {num_temp} {inelastic} {elastic} {iform} {natom} 222 1/ {temps} {error} {energy_max} """ @@ -351,7 +188,7 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False, with tempfile.TemporaryDirectory() as tmpdir: # Copy evaluations to appropriates 'tapes' for tape_num, filename in tapein.items(): - tmpfilename = os.path.join(tmpdir, f'tape{tape_num}') + tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num)) shutil.copy(str(filename), tmpfilename) # Start up NJOY process @@ -379,12 +216,12 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False, # Copy output files back to original directory for tape_num, filename in tapeout.items(): - tmpfilename = os.path.join(tmpdir, f'tape{tape_num}') + tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num)) if os.path.isfile(tmpfilename): shutil.move(tmpfilename, str(filename)) -def make_pendf(filename, pendf='pendf', **kwargs): +def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): """Generate pointwise ENDF file from an ENDF file Parameters @@ -393,9 +230,10 @@ def make_pendf(filename, pendf='pendf', **kwargs): Path to ENDF file pendf : str, optional Path of pointwise ENDF file to write - **kwargs - Keyword arguments passed to :func:`openmc.data.njoy.make_ace`. All NJOY - module arguments other than pendf default to False. + error : float, optional + Fractional error tolerance for NJOY processing + stdout : bool + Whether to display NJOY standard output Raises ------ @@ -403,15 +241,15 @@ def make_pendf(filename, pendf='pendf', **kwargs): If the NJOY process returns with a non-zero status """ - for key in ('broadr', 'heatr', 'gaspr', 'purr', 'acer'): - kwargs.setdefault(key, False) - make_ace(filename, pendf=pendf, **kwargs) + + make_ace(filename, pendf=pendf, error=error, broadr=False, + heatr=False, purr=False, acer=False, stdout=stdout) def make_ace(filename, temperatures=None, acer=True, xsdir=None, output_dir=None, pendf=False, error=0.001, broadr=True, heatr=True, gaspr=True, purr=True, evaluation=None, - smoothing=True, displacement_energy=None, **kwargs): + smoothing=True, **kwargs): """Generate incident neutron ACE file from an ENDF file File names can be passed to @@ -463,9 +301,6 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, indicates which evaluation should be used. smoothing : bool, optional If the smoothing option (ACER card 6) is on (True) or off (False). - displacement_energy : float, optional - Threshold displacement energy in [eV]. Used in HEATR to calculate - damage-energy cross section. When None, use NJOY defaults. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -482,7 +317,7 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, else: output_dir = Path(output_dir) if not output_dir.is_dir(): - raise IOError(f"{output_dir} is not a directory") + raise IOError("{} is not a directory".format(output_dir)) ev = evaluation if evaluation is not None else endf.Evaluation(filename) mat = ev.material @@ -518,7 +353,6 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, # heatr if heatr: - ed = displacement_energy if displacement_energy is not None else 0 nheatr_in = nlast nheatr_local = nheatr_in + 1 tapeout[nheatr_local] = (output_dir / "heatr_local") if heatr is True \ @@ -555,12 +389,12 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, # Extend input with an ACER run for each temperature nace = nacer_in + 1 + 2*i ndir = nace + 1 - ext = f'{i + 1:02}' + ext = '{:02}'.format(i + 1) commands += _TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run - tapeout[nace] = output_dir / f"ace_{temperature:.1f}" - tapeout[ndir] = output_dir / f"xsdir_{temperature:.1f}" + tapeout[nace] = output_dir / "ace_{:.1f}".format(temperature) + tapeout[ndir] = output_dir / "xsdir_{:.1f}".format(temperature) commands += 'stop\n' run(commands, tapein, tapeout, **kwargs) @@ -570,7 +404,7 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, with ace.open('w') as ace_file, xsdir.open('w') as xsdir_file: for temperature in temperatures: # Get contents of ACE file - text = (output_dir / f"ace_{temperature:.1f}").read_text() + text = (output_dir / "ace_{:.1f}".format(temperature)).read_text() # If the target is metastable, make sure that ZAID in the ACE # file reflects this by adding 400 @@ -583,19 +417,19 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, ace_file.write(text) # Concatenate into destination xsdir file - xsdir_in = output_dir / f"xsdir_{temperature:.1f}" + xsdir_in = output_dir / "xsdir_{:.1f}".format(temperature) xsdir_file.write(xsdir_in.read_text()) # Remove ACE/xsdir files for each temperature for temperature in temperatures: - (output_dir / f"ace_{temperature:.1f}").unlink() - (output_dir / f"xsdir_{temperature:.1f}").unlink() + (output_dir / "ace_{:.1f}".format(temperature)).unlink() + (output_dir / "xsdir_{:.1f}".format(temperature)).unlink() def make_ace_thermal(filename, filename_thermal, temperatures=None, - ace=None, xsdir=None, output_dir=None, error=0.001, + ace='ace', xsdir=None, output_dir=None, error=0.001, iwt=2, evaluation=None, evaluation_thermal=None, - table_name=None, zaids=None, nmix=None, nbin=16, **kwargs): + table_name=None, zaids=None, nmix=None, **kwargs): """Generate thermal scattering ACE file from ENDF files Parameters @@ -608,7 +442,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, Temperatures in Kelvin to produce data at. If omitted, data is produced at all temperatures given in the ENDF thermal scattering sublibrary. ace : str, optional - Path of ACE file to write. Default to ``"ace"``. + Path of ACE file to write xsdir : str, optional Path of xsdir file to write. Defaults to ``"xsdir"`` in the same directory as ``ace`` @@ -619,7 +453,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, error : float, optional Fractional error tolerance for NJOY processing iwt : int - `iwt` parameter used in NJOY/ACER card 9 + `iwt` parameter used in NJOR/ACER card 9 evaluation : openmc.data.endf.Evaluation, optional If the ENDF neutron sublibrary file contains multiple material evaluations, this argument indicates which evaluation to use. @@ -632,8 +466,6 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, ZAIDs that the thermal scattering data applies to nmix : int, optional Number of atom types in mixed moderator - nbin : int, optional - Number of equi-probable angles **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -648,7 +480,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, else: output_dir = Path(output_dir) if not output_dir.is_dir(): - raise IOError(f"{output_dir} is not a directory") + raise IOError("{} is not a directory".format(output_dir)) ev = evaluation if evaluation is not None else endf.Evaluation(filename) mat = ev.material @@ -665,7 +497,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, else: with warnings.catch_warnings(record=True) as w: proper_name = openmc.data.get_thermal_name(zsymam_thermal) - if w or proper_name not in _THERMAL_DATA: + if w: raise RuntimeError( f"Thermal scattering material {zsymam_thermal} not " "recognized. Please contact OpenMC developers at " @@ -749,27 +581,27 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, # Extend input with an ACER run for each temperature nace = nthermal_acer_in + 1 + 2*i ndir = nace + 1 - ext = f'{i + 1:02}' + ext = '{:02}'.format(i + 1) commands += _THERMAL_TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run - tapeout[nace] = output_dir / f"ace_{temperature:.1f}" - tapeout[ndir] = output_dir / f"xsdir_{temperature:.1f}" + tapeout[nace] = output_dir / "ace_{:.1f}".format(temperature) + tapeout[ndir] = output_dir / "xsdir_{:.1f}".format(temperature) commands += 'stop\n' run(commands, tapein, tapeout, **kwargs) - ace = (output_dir / "ace") if ace is None else Path(ace) + ace = output_dir / ace xsdir = (ace.parent / "xsdir") if xsdir is None else Path(xsdir) with ace.open('w') as ace_file, xsdir.open('w') as xsdir_file: # Concatenate ACE and xsdir files together for temperature in temperatures: - ace_in = output_dir / f"ace_{temperature:.1f}" + ace_in = output_dir / "ace_{:.1f}".format(temperature) ace_file.write(ace_in.read_text()) - xsdir_in = output_dir / f"xsdir_{temperature:.1f}" + xsdir_in = output_dir / "xsdir_{:.1f}".format(temperature) xsdir_file.write(xsdir_in.read_text()) # Remove ACE/xsdir files for each temperature for temperature in temperatures: - (output_dir / f"ace_{temperature:.1f}").unlink() - (output_dir / f"xsdir_{temperature:.1f}").unlink() + (output_dir / "ace_{:.1f}".format(temperature)).unlink() + (output_dir / "xsdir_{:.1f}".format(temperature)).unlink() diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 13cd3ec95..48ecc3748 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from collections.abc import Mapping, Callable from copy import deepcopy from io import StringIO @@ -12,11 +13,10 @@ from scipy.interpolate import CubicSpline import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from . import HDF5_VERSION, HDF5_VERSION_MAJOR +from . import HDF5_VERSION from .ace import Table, get_metadata, get_table from .data import ATOMIC_SYMBOL, EV_PER_MEV -from .endf import ( - as_evaluation, get_head_record, get_tab1_record, get_list_record) +from .endf import Evaluation, get_head_record, get_tab1_record, get_list_record from .function import Tabulated1D @@ -29,10 +29,10 @@ CM_PER_ANGSTROM = 1.0e-8 R0 = CM_PER_ANGSTROM * PLANCK_C / (2.0 * pi * FINE_STRUCTURE * MASS_ELECTRON_EV) # Electron subshell labels -_SUBSHELLS = (None, 'K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5', +_SUBSHELLS = [None, 'K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5', 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'O7', 'O8', 'O9', 'P1', 'P2', 'P3', 'P4', - 'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11', 'Q1', 'Q2', 'Q3') + 'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11', 'Q1', 'Q2', 'Q3'] _REACTION_NAME = { 501: ('Total photon interaction', 'total'), @@ -125,7 +125,7 @@ class AtomicRelaxation(EqualityMixin): Dictionary indicating the number of electrons in a subshell when neutral (values) for given subshells (keys). The subshells should be given as strings, e.g., 'K', 'L1', 'L2', etc. - transitions : dict of str to pandas.DataFrame + transitions : pandas.DataFrame Dictionary indicating allowed transitions and their probabilities (values) for given subshells (keys). The subshells should be given as strings, e.g., 'K', 'L1', 'L2', etc. The transitions are represented as @@ -143,8 +143,6 @@ class AtomicRelaxation(EqualityMixin): Dictionary indicating the number of electrons in a subshell when neutral (values) for given subshells (keys). The subshells should be given as strings, e.g., 'K', 'L1', 'L2', etc. - subshells : list - List of subshells as strings, e.g. ``['K', 'L1', ...]`` transitions : pandas.DataFrame Dictionary indicating allowed transitions and their probabilities (values) for given subshells (keys). The subshells should be given as @@ -168,6 +166,18 @@ class AtomicRelaxation(EqualityMixin): def binding_energy(self): return self._binding_energy + @property + def num_electrons(self): + return self._num_electrons + + @property + def subshells(self): + return list(sorted(self.binding_energy.keys())) + + @property + def transitions(self): + return self._transitions + @binding_energy.setter def binding_energy(self, binding_energy): cv.check_type('binding energies', binding_energy, Mapping) @@ -177,10 +187,6 @@ class AtomicRelaxation(EqualityMixin): cv.check_greater_than('binding energy', energy, 0.0, True) self._binding_energy = binding_energy - @property - def num_electrons(self): - return self._num_electrons - @num_electrons.setter def num_electrons(self, num_electrons): cv.check_type('number of electrons', num_electrons, Mapping) @@ -190,23 +196,13 @@ class AtomicRelaxation(EqualityMixin): cv.check_greater_than('number of electrons', num, 0.0, True) self._num_electrons = num_electrons - @property - def subshells(self): - return list(sorted(self.binding_energy.keys())) - - @property - def transitions(self): - return self._transitions - @transitions.setter def transitions(self, transitions): cv.check_type('transitions', transitions, Mapping) for subshell, df in transitions.items(): cv.check_value('subshell', subshell, _SUBSHELLS) cv.check_type('transitions', df, pd.DataFrame) - self._transitions = { - subshell: df.convert_dtypes() for subshell, df in transitions.items() - } + self._transitions = transitions @classmethod def from_ace(cls, ace): @@ -273,7 +269,7 @@ class AtomicRelaxation(EqualityMixin): Parameters ---------- - ev_or_filename : str, openmc.data.endf.Evaluation, or endf.Material + ev_or_filename : str or openmc.data.endf.Evaluation ENDF atomic relaxation evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -283,7 +279,10 @@ class AtomicRelaxation(EqualityMixin): Atomic relaxation data """ - ev = as_evaluation(ev_or_filename) + if isinstance(ev_or_filename, Evaluation): + ev = ev_or_filename + else: + ev = Evaluation(ev_or_filename) # Atomic relaxation data is always MF=28, MT=533 if (28, 533) not in ev.section: @@ -363,9 +362,8 @@ class AtomicRelaxation(EqualityMixin): df = pd.DataFrame(sub_group['transitions'][()], columns=columns) # Replace float indexes back to subshell strings - with pd.option_context('future.no_silent_downcasting', True): - df[columns[:2]] = df[columns[:2]].replace( - np.arange(float(len(_SUBSHELLS))), _SUBSHELLS) + df[columns[:2]] = df[columns[:2]].replace( + np.arange(float(len(_SUBSHELLS))), _SUBSHELLS) transitions[shell] = df return cls(binding_energy, num_electrons, transitions) @@ -388,9 +386,8 @@ class AtomicRelaxation(EqualityMixin): # Write transition data with replacements if shell in self.transitions: - with pd.option_context('future.no_silent_downcasting', True): - df = self.transitions[shell].replace( - _SUBSHELLS, range(len(_SUBSHELLS))) + df = self.transitions[shell].replace( + _SUBSHELLS, range(len(_SUBSHELLS))) group.create_dataset('transitions', data=df.values.astype(float)) @@ -433,7 +430,7 @@ class IncidentPhoton(EqualityMixin): the projection of the electron momentum on the scattering vector, :math:`p_z` for each subshell). Note that subshell occupancies may not match the atomic relaxation data. - reactions : dict + reactions : collections.OrderedDict Contains the cross sections for each photon reaction. The keys are MT values and the values are instances of :class:`PhotonReaction`. @@ -442,7 +439,7 @@ class IncidentPhoton(EqualityMixin): def __init__(self, atomic_number): self.atomic_number = atomic_number self._atomic_relaxation = None - self.reactions = {} + self.reactions = OrderedDict() self.compton_profiles = {} self.bremsstrahlung = {} @@ -453,10 +450,10 @@ class IncidentPhoton(EqualityMixin): if mt in self.reactions: return self.reactions[mt] else: - raise KeyError(f'No reaction with MT={mt}.') + raise KeyError('No reaction with MT={}.'.format(mt)) def __repr__(self): - return f"" + return "".format(self.name) def __iter__(self): return iter(self.reactions.values()) @@ -465,26 +462,26 @@ class IncidentPhoton(EqualityMixin): def atomic_number(self): return self._atomic_number + @property + def atomic_relaxation(self): + return self._atomic_relaxation + + @property + def name(self): + return ATOMIC_SYMBOL[self.atomic_number] + @atomic_number.setter def atomic_number(self, atomic_number): cv.check_type('atomic number', atomic_number, Integral) cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number - @property - def atomic_relaxation(self): - return self._atomic_relaxation - @atomic_relaxation.setter def atomic_relaxation(self, atomic_relaxation): cv.check_type('atomic relaxation data', atomic_relaxation, AtomicRelaxation) self._atomic_relaxation = atomic_relaxation - @property - def name(self): - return ATOMIC_SYMBOL[self.atomic_number] - @classmethod def from_ace(cls, ace_or_filename): """Generate incident photon data from an ACE table @@ -510,18 +507,18 @@ class IncidentPhoton(EqualityMixin): # Get atomic number based on name of ACE table zaid, xs = ace.name.split('.') if not xs.endswith('p'): - raise TypeError(f"{ace} is not a photoatomic transport ACE table.") + raise TypeError("{} is not a photoatomic transport ACE table.".format(ace)) Z = get_metadata(int(zaid))[2] # Read each reaction data = cls(Z) - for mt in (502, 504, 517, 522, 525): + for mt in (502, 504, 515, 522, 525): data.reactions[mt] = PhotonReaction.from_ace(ace, mt) # Get heating cross sections [eV-barn] from factors [eV per collision] # by multiplying with total xs data.reactions[525].xs.y *= sum([data.reactions[mt].xs.y for mt in - (502, 504, 517, 522)]) + (502, 504, 515, 522)]) # Compton profiles n_shell = ace.nxs[5] @@ -604,10 +601,10 @@ class IncidentPhoton(EqualityMixin): Parameters ---------- - photoatomic : str, openmc.data.endf.Evaluation, or endf.Material + photoatomic : str or openmc.data.endf.Evaluation ENDF photoatomic data evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. - relaxation : str, openmc.data.endf.Evaluation, or endf.Material, optional + relaxation : str or openmc.data.endf.Evaluation, optional ENDF atomic relaxation data evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. @@ -617,7 +614,10 @@ class IncidentPhoton(EqualityMixin): Photon interaction data """ - ev = as_evaluation(photoatomic) + if isinstance(photoatomic, Evaluation): + ev = photoatomic + else: + ev = Evaluation(photoatomic) Z = ev.target['atomic_number'] data = cls(Z) @@ -637,7 +637,7 @@ class IncidentPhoton(EqualityMixin): with h5py.File(filename, 'r') as f: _COMPTON_PROFILES['pz'] = f['pz'][()] for i in range(1, 101): - group = f[f'{i:03}'] + group = f['{:03}'.format(i)] num_electrons = group['num_electrons'][()] binding_energy = group['binding_energy'][()]*EV_PER_MEV J = group['J'][()] @@ -712,7 +712,7 @@ class IncidentPhoton(EqualityMixin): # Check for necessary reactions for mt in (502, 504, 522): - assert mt in data, f"Reaction {mt} not found" + assert mt in data, "Reaction {} not found".format(mt) # Read atomic relaxation data.atomic_relaxation = AtomicRelaxation.from_hdf5(group['subshells']) @@ -763,7 +763,7 @@ class IncidentPhoton(EqualityMixin): """ with h5py.File(str(path), mode, libver=libver) as f: # Write filetype and version - f.attrs['filetype'] = np.bytes_('data_photon') + f.attrs['filetype'] = np.string_('data_photon') if 'version' not in f.attrs: f.attrs['version'] = np.array(HDF5_VERSION) @@ -835,7 +835,7 @@ class IncidentPhoton(EqualityMixin): filename = os.path.join(os.path.dirname(__file__), 'density_effect.h5') with h5py.File(filename, 'r') as f: for i in range(1, 101): - group = f[f'{i:03}'] + group = f['{:03}'.format(i)] _BREMSSTRAHLUNG[i] = { 'I': group.attrs['I'], 'num_electrons': group['num_electrons'][()], @@ -923,43 +923,44 @@ class PhotonReaction(EqualityMixin): def __repr__(self): if self.mt in _REACTION_NAME: - return f"" + return "".format( + self.mt, _REACTION_NAME[self.mt][0]) else: - return f"" + return "".format(self.mt) @property def anomalous_real(self): return self._anomalous_real + @property + def anomalous_imag(self): + return self._anomalous_imag + + @property + def scattering_factor(self): + return self._scattering_factor + + @property + def xs(self): + return self._xs + @anomalous_real.setter def anomalous_real(self, anomalous_real): cv.check_type('real part of anomalous scattering factor', anomalous_real, Callable) self._anomalous_real = anomalous_real - @property - def anomalous_imag(self): - return self._anomalous_imag - @anomalous_imag.setter def anomalous_imag(self, anomalous_imag): cv.check_type('imaginary part of anomalous scattering factor', anomalous_imag, Callable) self._anomalous_imag = anomalous_imag - @property - def scattering_factor(self): - return self._scattering_factor - @scattering_factor.setter def scattering_factor(self, scattering_factor): cv.check_type('scattering factor', scattering_factor, Callable) self._scattering_factor = scattering_factor - @property - def xs(self): - return self._xs - @xs.setter def xs(self, xs): cv.check_type('reaction cross section', xs, Callable) @@ -997,7 +998,7 @@ class PhotonReaction(EqualityMixin): elif mt == 504: # Incoherent scattering idx = ace.jxs[1] + n - elif mt == 517: + elif mt == 515: # Pair production idx = ace.jxs[1] + 4*n elif mt == 522: @@ -1018,9 +1019,6 @@ class PhotonReaction(EqualityMixin): else: nonzero = (xs != 0.0) xs[nonzero] = np.exp(xs[nonzero]) - - # Replace zero elements to small non-zero to enable log-log - xs[~nonzero] = np.exp(-500.0) rx.xs = Tabulated1D(energy, xs, [n], [5]) # Get form factors for incoherent/coherent scattering @@ -1066,7 +1064,7 @@ class PhotonReaction(EqualityMixin): Parameters ---------- - ev : openmc.data.endf.Evaluation or endf.Material + ev : openmc.data.endf.Evaluation ENDF photo-atomic interaction data evaluation mt : int The MT value of the reaction to get data for @@ -1077,7 +1075,6 @@ class PhotonReaction(EqualityMixin): Photon reaction data """ - ev = as_evaluation(ev) rx = cls(mt) # Read photon cross section diff --git a/openmc/data/product.py b/openmc/data/product.py index 88c83b81f..a6b2fd89e 100644 --- a/openmc/data/product.py +++ b/openmc/data/product.py @@ -61,55 +61,55 @@ class Product(EqualityMixin): def applicability(self): return self._applicability + @property + def decay_rate(self): + return self._decay_rate + + @property + def distribution(self): + return self._distribution + + @property + def emission_mode(self): + return self._emission_mode + + @property + def particle(self): + return self._particle + + @property + def yield_(self): + return self._yield + @applicability.setter def applicability(self, applicability): cv.check_type('product distribution applicability', applicability, Iterable, Tabulated1D) self._applicability = applicability - @property - def decay_rate(self): - return self._decay_rate - @decay_rate.setter def decay_rate(self, decay_rate): cv.check_type('product decay rate', decay_rate, Real) cv.check_greater_than('product decay rate', decay_rate, 0.0, True) self._decay_rate = decay_rate - @property - def distribution(self): - return self._distribution - @distribution.setter def distribution(self, distribution): cv.check_type('product angle-energy distribution', distribution, Iterable, AngleEnergy) self._distribution = distribution - @property - def emission_mode(self): - return self._emission_mode - @emission_mode.setter def emission_mode(self, emission_mode): cv.check_value('product emission mode', emission_mode, ('prompt', 'delayed', 'total')) self._emission_mode = emission_mode - @property - def particle(self): - return self._particle - @particle.setter def particle(self, particle): cv.check_type('product particle type', particle, str) self._particle = particle - @property - def yield_(self): - return self._yield - @yield_.setter def yield_(self, yield_): cv.check_type('product yield', yield_, Function1D) @@ -124,8 +124,8 @@ class Product(EqualityMixin): HDF5 group to write to """ - group.attrs['particle'] = np.bytes_(self.particle) - group.attrs['emission_mode'] = np.bytes_(self.emission_mode) + group.attrs['particle'] = np.string_(self.particle) + group.attrs['emission_mode'] = np.string_(self.emission_mode) if self.decay_rate > 0.0: group.attrs['decay_rate'] = self.decay_rate @@ -135,7 +135,7 @@ class Product(EqualityMixin): # Write applicability/distribution group.attrs['n_distribution'] = len(self.distribution) for i, d in enumerate(self.distribution): - dgroup = group.create_group(f'distribution_{i}') + dgroup = group.create_group('distribution_{}'.format(i)) if self.applicability: self.applicability[i].to_hdf5(dgroup, 'applicability') d.to_hdf5(dgroup) @@ -170,7 +170,7 @@ class Product(EqualityMixin): distribution = [] applicability = [] for i in range(n_distribution): - dgroup = group[f'distribution_{i}'] + dgroup = group['distribution_{}'.format(i)] if 'applicability' in dgroup: applicability.append(Tabulated1D.from_hdf5( dgroup['applicability'])) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index 44ced5511..a2431cf1c 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -13,24 +13,23 @@ from .angle_distribution import AngleDistribution from .angle_energy import AngleEnergy from .correlated import CorrelatedAngleEnergy from .data import ATOMIC_SYMBOL, K_BOLTZMANN, EV_PER_MEV -from .endf import as_evaluation, get_head_record, get_tab1_record, \ - get_list_record, get_tab2_record, get_cont_record +from .endf import get_head_record, get_tab1_record, get_list_record, \ + get_tab2_record, get_cont_record from .energy_distribution import EnergyDistribution, LevelInelastic, \ DiscretePhoton from .function import Tabulated1D, Polynomial from .kalbach_mann import KalbachMann from .laboratory import LaboratoryAngleEnergy from .nbody import NBodyPhaseSpace -from .photon import _SUBSHELLS from .product import Product from .uncorrelated import UncorrelatedAngleEnergy -REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 3: "(n,nonelastic)", - 4: '(n,level)', 5: '(n,misc)', 11: '(n,2nd)', 16: '(n,2n)', - 17: '(n,3n)', 18: '(n,fission)', 19: '(n,f)', 20: '(n,nf)', - 21: '(n,2nf)', 22: '(n,na)', 23: '(n,n3a)', 24: '(n,2na)', - 25: '(n,3na)', 27: '(n,absorption)', 28: '(n,np)', 29: '(n,n2a)', +REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 4: '(n,level)', + 5: '(n,misc)', 11: '(n,2nd)', 16: '(n,2n)', 17: '(n,3n)', + 18: '(n,fission)', 19: '(n,f)', 20: '(n,nf)', 21: '(n,2nf)', + 22: '(n,na)', 23: '(n,n3a)', 24: '(n,2na)', 25: '(n,3na)', + 27: '(n,absorption)', 28: '(n,np)', 29: '(n,n2a)', 30: '(n,2n2a)', 32: '(n,nd)', 33: '(n,nt)', 34: '(n,n3He)', 35: '(n,nd2a)', 36: '(n,nt2a)', 37: '(n,4n)', 38: '(n,3nf)', 41: '(n,2np)', 42: '(n,3np)', 44: '(n,n2p)', 45: '(n,npa)', @@ -55,29 +54,18 @@ REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 3: "(n,nonelastic)", 198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 203: '(n,Xp)', 204: '(n,Xd)', 205: '(n,Xt)', 206: '(n,X3He)', 207: '(n,Xa)', 301: 'heating', 444: 'damage-energy', - 501: 'photon-total', 502: 'coherent-scatter', - 504: 'incoherent-scatter', 515: 'pair-production-electron', - 516: 'pair-production', 517: 'pair-production-nuclear', - 522: 'photoelectric', 649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)', 849: '(n,ac)', 891: '(n,2nc)', 901: 'heating-local'} -REACTION_NAME.update({i: f'(n,n{i - 50})' for i in range(51, 91)}) -REACTION_NAME.update({i: f'(n,p{i - 600})' for i in range(600, 649)}) -REACTION_NAME.update({i: f'(n,d{i - 650})' for i in range(650, 699)}) -REACTION_NAME.update({i: f'(n,t{i - 700})' for i in range(700, 749)}) -REACTION_NAME.update({i: f'(n,3He{i - 750})' for i in range(750, 799)}) -REACTION_NAME.update({i: f'(n,a{i - 800})' for i in range(800, 849)}) -REACTION_NAME.update({i: f'(n,2n{i - 875})' for i in range(875, 891)}) -REACTION_NAME.update( - {534 + i: f'photoelectric-{shell}' for i, shell in enumerate(_SUBSHELLS[1:])} -) +REACTION_NAME.update({i: '(n,n{})'.format(i - 50) for i in range(51, 91)}) +REACTION_NAME.update({i: '(n,p{})'.format(i - 600) for i in range(600, 649)}) +REACTION_NAME.update({i: '(n,d{})'.format(i - 650) for i in range(650, 699)}) +REACTION_NAME.update({i: '(n,t{})'.format(i - 700) for i in range(700, 749)}) +REACTION_NAME.update({i: '(n,3He{})'.format(i - 750) for i in range(750, 799)}) +REACTION_NAME.update({i: '(n,a{})'.format(i - 800) for i in range(800, 849)}) +REACTION_NAME.update({i: '(n,2n{})'.format(i - 875) for i in range(875, 891)}) REACTION_MT = {name: mt for mt, name in REACTION_NAME.items()} -REACTION_MT['total'] = 1 -REACTION_MT['elastic'] = 2 REACTION_MT['fission'] = 18 -REACTION_MT['absorption'] = 27 -REACTION_MT['capture'] = 102 FISSION_MTS = (18, 19, 20, 21, 38) @@ -121,6 +109,7 @@ def _get_products(ev, mt): za = int(params[0]) awr = params[1] + lip = params[2] law = params[3] if za == 0: @@ -131,7 +120,7 @@ def _get_products(ev, mt): p = Product('electron') else: Z, A = divmod(za, 1000) - p = Product(f'{ATOMIC_SYMBOL[Z]}{A}') + p = Product('{}{}'.format(ATOMIC_SYMBOL[Z], A)) p.yield_ = yield_ @@ -566,12 +555,12 @@ def _get_activation_products(ev, rx): Z, A = divmod(items[2], 1000) excited_state = items[3] - # Get GNDS name for product + # Get GND name for product symbol = ATOMIC_SYMBOL[Z] if excited_state > 0: - name = f'{symbol}{A}_e{excited_state}' + name = '{}{}_e{}'.format(symbol, A, excited_state) else: - name = f'{symbol}{A}' + name = '{}{}'.format(symbol, A) p = Product(name) if mf == 9: @@ -668,7 +657,8 @@ def _get_photon_products_ace(ace, rx): photon.yield_ = Tabulated1D(energy, yield_) else: - raise ValueError(f"MFTYPE must be 12, 13, 16. Got {mftype}") + raise ValueError("MFTYPE must be 12, 13, 16. Got {0}".format( + mftype)) # ================================================================== # Photon energy distribution @@ -857,60 +847,60 @@ class Reaction(EqualityMixin): def __repr__(self): if self.mt in REACTION_NAME: - return f"" + return "".format(self.mt, REACTION_NAME[self.mt]) else: - return f"" + return "".format(self.mt) @property def center_of_mass(self): return self._center_of_mass + @property + def redundant(self): + return self._redundant + + @property + def q_value(self): + return self._q_value + + @property + def products(self): + return self._products + + @property + def derived_products(self): + return self._derived_products + + @property + def xs(self): + return self._xs + @center_of_mass.setter def center_of_mass(self, center_of_mass): cv.check_type('center of mass', center_of_mass, (bool, np.bool_)) self._center_of_mass = center_of_mass - @property - def redundant(self): - return self._redundant - @redundant.setter def redundant(self, redundant): cv.check_type('redundant', redundant, (bool, np.bool_)) self._redundant = redundant - @property - def q_value(self): - return self._q_value - @q_value.setter def q_value(self, q_value): cv.check_type('Q value', q_value, Real) self._q_value = q_value - @property - def products(self): - return self._products - @products.setter def products(self, products): cv.check_type('reaction products', products, Iterable, Product) self._products = products - @property - def derived_products(self): - return self._derived_products - @derived_products.setter def derived_products(self, derived_products): cv.check_type('reaction derived products', derived_products, Iterable, Product) self._derived_products = derived_products - @property - def xs(self): - return self._xs - @xs.setter def xs(self, xs): cv.check_type('reaction cross section dictionary', xs, MutableMapping) @@ -931,9 +921,9 @@ class Reaction(EqualityMixin): group.attrs['mt'] = self.mt if self.mt in REACTION_NAME: - group.attrs['label'] = np.bytes_(REACTION_NAME[self.mt]) + group.attrs['label'] = np.string_(REACTION_NAME[self.mt]) else: - group.attrs['label'] = np.bytes_(self.mt) + group.attrs['label'] = np.string_(self.mt) group.attrs['Q_value'] = self.q_value group.attrs['center_of_mass'] = 1 if self.center_of_mass else 0 group.attrs['redundant'] = 1 if self.redundant else 0 @@ -944,7 +934,7 @@ class Reaction(EqualityMixin): threshold_idx = getattr(self.xs[T], '_threshold_idx', 0) dset.attrs['threshold_idx'] = threshold_idx for i, p in enumerate(self.products): - pgroup = group.create_group(f'product_{i}') + pgroup = group.create_group('product_{}'.format(i)) p.to_hdf5(pgroup) @classmethod @@ -996,7 +986,7 @@ class Reaction(EqualityMixin): # Read reaction products for i in range(n_product): - pgroup = group[f'product_{i}'] + pgroup = group['product_{}'.format(i)] rx.products.append(Product.from_hdf5(pgroup)) return rx @@ -1151,7 +1141,7 @@ class Reaction(EqualityMixin): Parameters ---------- - ev : openmc.data.endf.Evaluation or endf.Material + ev : openmc.data.endf.Evaluation ENDF evaluation mt : int The MT value of the reaction to get data for @@ -1162,7 +1152,6 @@ class Reaction(EqualityMixin): Reaction data """ - ev = as_evaluation(ev) rx = Reaction(mt) # Integrated cross section diff --git a/openmc/data/reconstruct.pyx b/openmc/data/reconstruct.pyx new file mode 100644 index 000000000..cd0bbc38b --- /dev/null +++ b/openmc/data/reconstruct.pyx @@ -0,0 +1,522 @@ +from libc.stdlib cimport malloc, calloc, free +from libc.math cimport cos, sin, sqrt, atan, M_PI + +cimport numpy as np +import numpy as np +from numpy.linalg import inv +cimport cython + + +cdef extern from "complex.h": + double cabs(double complex) + double complex conj(double complex) + double creal(complex double) + double cimag(complex double) + double complex cexp(double complex) + +# Physical constants are from CODATA 2014 +cdef double NEUTRON_MASS_ENERGY = 939.5654133e6 # eV/c^2 +cdef double HBAR_C = 197.3269788e5 # eV-b^0.5 + + +@cython.cdivision(True) +def wave_number(double A, double E): + r"""Neutron wave number in center-of-mass system. + + ENDF-102 defines the neutron wave number in the center-of-mass system in + Equation D.10 as + + .. math:: + k = \frac{2m_n}{\hbar} \frac{A}{A + 1} \sqrt{|E|} + + Parameters + ---------- + A : double + Ratio of target mass to neutron mass + E : double + Energy in eV + + Returns + ------- + double + Neutron wave number in b^-0.5 + + """ + return A/(A + 1)*sqrt(2*NEUTRON_MASS_ENERGY*abs(E))/HBAR_C + +@cython.cdivision(True) +cdef double _wave_number(double A, double E): + return A/(A + 1)*sqrt(2*NEUTRON_MASS_ENERGY*abs(E))/HBAR_C + + +@cython.cdivision(True) +cdef double phaseshift(int l, double rho): + """Calculate hardsphere phase shift as given in ENDF-102, Equation D.13 + + Parameters + ---------- + l : int + Angular momentum quantum number + rho : float + Product of the wave number and the channel radius + + Returns + ------- + double + Hardsphere phase shift + + """ + if l == 0: + return rho + elif l == 1: + return rho - atan(rho) + elif l == 2: + return rho - atan(3*rho/(3 - rho**2)) + elif l == 3: + return rho - atan((15*rho - rho**3)/(15 - 6*rho**2)) + elif l == 4: + return rho - atan((105*rho - 10*rho**3)/(105 - 45*rho**2 + rho**4)) + + +@cython.cdivision(True) +def penetration_shift(int l, double rho): + r"""Calculate shift and penetration factors as given in ENDF-102, Equations D.11 + and D.12. + + Parameters + ---------- + l : int + Angular momentum quantum number + rho : float + Product of the wave number and the channel radius + + Returns + ------- + double + Penetration factor for given :math:`l` + double + Shift factor for given :math:`l` + + """ + cdef double den + + if l == 0: + return rho, 0. + elif l == 1: + den = 1 + rho**2 + return rho**3/den, -1/den + elif l == 2: + den = 9 + 3*rho**2 + rho**4 + return rho**5/den, -(18 + 3*rho**2)/den + elif l == 3: + den = 225 + 45*rho**2 + 6*rho**4 + rho**6 + return rho**7/den, -(675 + 90*rho**2 + 6*rho**4)/den + elif l == 4: + den = 11025 + 1575*rho**2 + 135*rho**4 + 10*rho**6 + rho**8 + return rho**9/den, -(44100 + 4725*rho**2 + 270*rho**4 + 10*rho**6)/den + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +def reconstruct_mlbw(mlbw, double E): + """Evaluate cross section using MLBW data. + + Parameters + ---------- + mlbw : openmc.data.MultiLevelBreitWigner + Multi-level Breit-Wigner resonance parameters + E : double + Energy in eV at which to evaluate the cross section + + Returns + ------- + elastic : double + Elastic scattering cross section in barns + capture : double + Radiative capture cross section in barns + fission : double + Fission cross section in barns + + """ + cdef int i, nJ, ij, l, n_res, i_res + cdef double elastic, capture, fission + cdef double A, k, rho, rhohat, I + cdef double P, S, phi, cos2phi, sin2phi + cdef double Ex, Q, rhoc, rhochat, P_c, S_c + cdef double jmin, jmax, j, Dl + cdef double E_r, gt, gn, gg, gf, gx, P_r, S_r, P_rx + cdef double gnE, gtE, Eprime, x, f + cdef double *g + cdef double (*s)[2] + cdef double [:,:] params + + I = mlbw.target_spin + A = mlbw.atomic_weight_ratio + k = _wave_number(A, E) + + elastic = 0. + capture = 0. + fission = 0. + + for i, l in enumerate(mlbw._l_values): + params = mlbw._parameter_matrix[l] + + rho = k*mlbw.channel_radius[l](E) + rhohat = k*mlbw.scattering_radius[l](E) + P, S = penetration_shift(l, rho) + phi = phaseshift(l, rhohat) + cos2phi = cos(2*phi) + sin2phi = sin(2*phi) + + # Determine shift and penetration at modified energy + if mlbw._competitive[i]: + Ex = E + mlbw.q_value[l]*(A + 1)/A + rhoc = mlbw.channel_radius[l](Ex) + rhochat = mlbw.scattering_radius[l](Ex) + P_c, S_c = penetration_shift(l, rhoc) + if Ex < 0: + P_c = 0 + + # Determine range of total angular momentum values based on equation + # 41 in LA-UR-12-27079 + jmin = abs(abs(I - l) - 0.5) + jmax = I + l + 0.5 + nJ = int(jmax - jmin + 1) + + # Determine Dl factor using Equation 43 in LA-UR-12-27079 + Dl = 2*l + 1 + g = malloc(nJ*sizeof(double)) + for ij in range(nJ): + j = jmin + ij + g[ij] = (2*j + 1)/(4*I + 2) + Dl -= g[ij] + + s = calloc(2*nJ, sizeof(double)) + for i_res in range(params.shape[0]): + # Copy resonance parameters + E_r = params[i_res, 0] + j = params[i_res, 2] + ij = int(j - jmin) + gt = params[i_res, 3] + gn = params[i_res, 4] + gg = params[i_res, 5] + gf = params[i_res, 6] + gx = params[i_res, 7] + P_r = params[i_res, 8] + S_r = params[i_res, 9] + P_rx = params[i_res, 10] + + # Calculate neutron and total width at energy E + gnE = P*gn/P_r # ENDF-102, Equation D.7 + gtE = gnE + gg + gf + if gx > 0: + gtE += gx*P_c/P_rx + + Eprime = E_r + (S_r - S)/(2*P_r)*gn # ENDF-102, Equation D.9 + x = 2*(E - Eprime)/gtE # LA-UR-12-27079, Equation 26 + f = 2*gnE/(gtE*(1 + x*x)) # Common factor in Equation 40 + s[ij][0] += f # First sum in Equation 40 + s[ij][1] += f*x # Second sum in Equation 40 + capture += f*g[ij]*gg/gtE + if gf > 0: + fission += f*g[ij]*gf/gtE + + for ij in range(nJ): + # Add all but last term of LA-UR-12-27079, Equation 40 + elastic += g[ij]*((1 - cos2phi - s[ij][0])**2 + + (sin2phi + s[ij][1])**2) + + # Add final term with Dl from Equation 40 + elastic += 2*Dl*(1 - cos2phi) + + # Free memory + free(g) + free(s) + + capture *= 2*M_PI/(k*k) + fission *= 2*M_PI/(k*k) + elastic *= M_PI/(k*k) + + return (elastic, capture, fission) + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +def reconstruct_slbw(slbw, double E): + """Evaluate cross section using SLBW data. + + Parameters + ---------- + slbw : openmc.data.SingleLevelBreitWigner + Single-level Breit-Wigner resonance parameters + E : double + Energy in eV at which to evaluate the cross section + + Returns + ------- + elastic : double + Elastic scattering cross section in barns + capture : double + Radiative capture cross section in barns + fission : double + Fission cross section in barns + + """ + cdef int i, l, i_res + cdef double elastic, capture, fission + cdef double A, k, rho, rhohat, I + cdef double P, S, phi, cos2phi, sin2phi, sinphi2 + cdef double Ex, rhoc, rhochat, P_c, S_c + cdef double E_r, J, gt, gn, gg, gf, gx, P_r, S_r, P_rx + cdef double gnE, gtE, Eprime, f + cdef double x, theta, psi, chi + cdef double [:,:] params + + I = slbw.target_spin + A = slbw.atomic_weight_ratio + k = _wave_number(A, E) + + elastic = 0. + capture = 0. + fission = 0. + + for i, l in enumerate(slbw._l_values): + params = slbw._parameter_matrix[l] + + rho = k*slbw.channel_radius[l](E) + rhohat = k*slbw.scattering_radius[l](E) + P, S = penetration_shift(l, rho) + phi = phaseshift(l, rhohat) + cos2phi = cos(2*phi) + sin2phi = sin(2*phi) + sinphi2 = sin(phi)**2 + + # Add potential scattering -- first term in ENDF-102, Equation D.2 + elastic += 4*M_PI/(k*k)*(2*l + 1)*sinphi2 + + # Determine shift and penetration at modified energy + if slbw._competitive[i]: + Ex = E + slbw.q_value[l]*(A + 1)/A + rhoc = k*slbw.channel_radius[l](Ex) + rhochat = k*slbw.scattering_radius[l](Ex) + P_c, S_c = penetration_shift(l, rhoc) + if Ex < 0: + P_c = 0 + + for i_res in range(params.shape[0]): + # Copy resonance parameters + E_r = params[i_res, 0] + J = params[i_res, 2] + gt = params[i_res, 3] + gn = params[i_res, 4] + gg = params[i_res, 5] + gf = params[i_res, 6] + gx = params[i_res, 7] + P_r = params[i_res, 8] + S_r = params[i_res, 9] + P_rx = params[i_res, 10] + + # Calculate neutron and total width at energy E + gnE = P*gn/P_r # Equation D.7 + gtE = gnE + gg + gf + if gx > 0: + gtE += gx*P_c/P_rx + + Eprime = E_r + (S_r - S)/(2*P_r)*gn # Equation D.9 + gJ = (2*J + 1)/(4*I + 2) # Mentioned in section D.1.1.4 + + # Calculate common factor for elastic, capture, and fission + # cross sections + f = M_PI/(k*k)*gJ*gnE/((E - Eprime)**2 + gtE**2/4) + + # Add contribution to elastic per Equation D.2 + elastic += f*(gnE*cos2phi - 2*(gg + gf)*sinphi2 + + 2*(E - Eprime)*sin2phi) + + # Add contribution to capture per Equation D.3 + capture += f*gg + + # Add contribution to fission per Equation D.6 + if gf > 0: + fission += f*gf + + return (elastic, capture, fission) + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +def reconstruct_rm(rm, double E): + """Evaluate cross section using Reich-Moore data. + + Parameters + ---------- + rm : openmc.data.ReichMoore + Reich-Moore resonance parameters + E : double + Energy in eV at which to evaluate the cross section + + Returns + ------- + elastic : double + Elastic scattering cross section in barns + capture : double + Radiative capture cross section in barns + fission : double + Fission cross section in barns + + """ + cdef int i, l, m, n, i_res + cdef int i_s, num_s, i_J, num_J + cdef double elastic, capture, fission, total + cdef double A, k, rho, rhohat, I + cdef double P, S, phi + cdef double smin, smax, s, Jmin, Jmax, J, j + cdef double E_r, gn, gg, gfa, gfb, P_r + cdef double E_diff, abs_value, gJ + cdef double Kr, Ki, x + cdef double complex Ubar, U_, factor + cdef bint hasfission + cdef np.ndarray[double, ndim=2] one + cdef np.ndarray[double complex, ndim=2] K, Imat, U + cdef double [:,:] params + + # Get nuclear spin + I = rm.target_spin + + elastic = 0. + fission = 0. + total = 0. + A = rm.atomic_weight_ratio + k = _wave_number(A, E) + one = np.eye(3) + K = np.zeros((3,3), dtype=complex) + + for i, l in enumerate(rm._l_values): + # Check for l-dependent scattering radius + rho = k*rm.channel_radius[l](E) + rhohat = k*rm.scattering_radius[l](E) + + # Calculate shift and penetrability + P, S = penetration_shift(l, rho) + + # Calculate phase shift + phi = phaseshift(l, rhohat) + + # Calculate common factor on collision matrix terms (term outside curly + # braces in ENDF-102, Eq. D.27) + Ubar = cexp(-2j*phi) + + # The channel spin is the vector sum of the target spin, I, and the + # neutron spin, 1/2, so can take on values of |I - 1/2| < s < I + 1/2 + smin = abs(I - 0.5) + smax = I + 0.5 + num_s = int(smax - smin + 1) + + for i_s in range(num_s): + s = i_s + smin + + # Total angular momentum is the vector sum of l and s and can assume + # values between |l - s| < J < l + s + Jmin = abs(l - s) + Jmax = l + s + num_J = int(Jmax - Jmin + 1) + + for i_J in range(num_J): + J = i_J + Jmin + + # Initialize K matrix + for m in range(3): + for n in range(3): + K[m,n] = 0.0 + + hasfission = False + if (l, J) in rm._parameter_matrix: + params = rm._parameter_matrix[l, J] + + for i_res in range(params.shape[0]): + # Sometimes, the same (l, J) quantum numbers can occur + # for different values of the channel spin, s. In this + # case, the sign of the channel spin indicates which + # spin is to be used. If the spin is negative assume + # this resonance comes from the I - 1/2 channel and vice + # versa. + j = params[i_res, 2] + if l > 0: + if (j < 0 and s != smin) or (j > 0 and s != smax): + continue + + # Copy resonance parameters + E_r = params[i_res, 0] + gn = params[i_res, 3] + gg = params[i_res, 4] + gfa = params[i_res, 5] + gfb = params[i_res, 6] + P_r = params[i_res, 7] + + # Calculate neutron width at energy E + gn = sqrt(P*gn/P_r) + + # Calculate j/2 * inverse of denominator of K matrix terms + factor = 0.5j/(E_r - E - 0.5j*gg) + + # Upper triangular portion of K matrix -- see ENDF-102, + # Equation D.28 + K[0,0] = K[0,0] + gn*gn*factor + if gfa != 0.0 or gfb != 0.0: + # Negate fission widths if necessary + gfa = (-1 if gfa < 0 else 1)*sqrt(abs(gfa)) + gfb = (-1 if gfb < 0 else 1)*sqrt(abs(gfb)) + + K[0,1] = K[0,1] + gn*gfa*factor + K[0,2] = K[0,2] + gn*gfb*factor + K[1,1] = K[1,1] + gfa*gfa*factor + K[1,2] = K[1,2] + gfa*gfb*factor + K[2,2] = K[2,2] + gfb*gfb*factor + hasfission = True + + # Get collision matrix + gJ = (2*J + 1)/(4*I + 2) + if hasfission: + # Copy upper triangular portion of K to lower triangular + K[1,0] = K[0,1] + K[2,0] = K[0,2] + K[2,1] = K[1,2] + + Imat = inv(one - K) + U = Ubar*(2*Imat - one) # ENDF-102, Eq. D.27 + elastic += gJ*cabs(1 - U[0,0])**2 # ENDF-102, Eq. D.24 + total += 2*gJ*(1 - creal(U[0,0])) # ENDF-102, Eq. D.23 + + # Calculate fission from ENDF-102, Eq. D.26 + fission += 4*gJ*(cabs(Imat[1,0])**2 + cabs(Imat[2,0])**2) + else: + U_ = Ubar*(2/(1 - K[0,0]) - 1) + if abs(creal(K[0,0])) < 3e-4 and abs(phi) < 3e-4: + # If K and phi are both very small, the calculated cross + # sections can lose precision because the real part of U + # ends up very close to unity. To get around this, we + # use Euler's formula to express Ubar by real and + # imaginary parts, expand cos(2phi) = 1 - 2phi^2 + + # O(phi^4), and then simplify + Kr = creal(K[0,0]) + Ki = cimag(K[0,0]) + x = 2*(-Kr + (Kr*Kr + Ki*Ki)*(1 - phi*phi) + phi*phi - + sin(2*phi)*Ki)/((1 - Kr)*(1 - Kr) + Ki*Ki) + total += 2*gJ*x + elastic += gJ*(x*x + cimag(U_)**2) + else: + total += 2*gJ*(1 - creal(U_)) # ENDF-102, Eq. D.23 + elastic += gJ*cabs(1 - U_)**2 # ENDF-102, Eq. D.24 + + # Calculate capture as difference of other cross sections as per ENDF-102, + # Equation D.25 + capture = total - elastic - fission + + elastic *= M_PI/(k*k) + capture *= M_PI/(k*k) + fission *= M_PI/(k*k) + + return (elastic, capture, fission) diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 52ee7f1a9..7d27ea7cc 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -7,9 +7,7 @@ import pandas as pd import openmc.checkvalue as cv from .data import NEUTRON_MASS -from .endf import ( - as_evaluation, get_head_record, get_cont_record, get_tab1_record, - get_list_record) +from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record try: from .reconstruct import wave_number, penetration_shift, reconstruct_mlbw, \ reconstruct_slbw, reconstruct_rm @@ -48,12 +46,6 @@ class Resonances: def ranges(self): return self._ranges - @ranges.setter - def ranges(self, ranges): - cv.check_type('resonance ranges', ranges, MutableSequence) - self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', - ranges) - @property def resolved(self): resolved_ranges = [r for r in self.ranges @@ -73,13 +65,19 @@ class Resonances: else: return None + @ranges.setter + def ranges(self, ranges): + cv.check_type('resonance ranges', ranges, MutableSequence) + self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + ranges) + @classmethod def from_endf(cls, ev): """Generate resonance data from an ENDF evaluation. Parameters ---------- - ev : openmc.data.endf.Evaluation or endf.Material + ev : openmc.data.endf.Evaluation ENDF evaluation Returns @@ -88,7 +86,6 @@ class Resonances: Resonance data """ - ev = as_evaluation(ev) file_obj = io.StringIO(ev.section[2, 151]) # Determine whether discrete or continuous representation @@ -96,8 +93,9 @@ class Resonances: n_isotope = items[4] # Number of isotopes ranges = [] - for _ in range(n_isotope): + for iso in range(n_isotope): items = get_cont_record(file_obj) + abundance = items[1] fission_widths = (items[3] == 1) # fission widths are given? n_ranges = items[4] # number of resonance energy ranges @@ -426,12 +424,14 @@ class MultiLevelBreitWigner(ResonanceRange): # Determine penetration and shift corresponding to resonance energy k = wave_number(A, E) rho = k*self.channel_radius[l](E) + rhohat = k*self.scattering_radius[l](E) p[i], s[i] = penetration_shift(l, rho) # Determine penetration at modified energy for competitive reaction if gx > 0: Ex = E + self.q_value[l]*(A + 1)/A rho = k*self.channel_radius[l](Ex) + rhohat = k*self.scattering_radius[l](Ex) px[i], sx[i] = penetration_shift(l, rho) else: px[i] = sx[i] = 0.0 @@ -680,6 +680,7 @@ class ReichMoore(ResonanceRange): # Determine penetration and shift corresponding to resonance energy k = wave_number(A, E) rho = k*self.channel_radius[l](E) + rhohat = k*self.scattering_radius[l](E) p[i], s[i] = penetration_shift(l, rho) df['p'] = p @@ -833,7 +834,7 @@ class RMatrixLimited(ResonanceRange): elif mt == 102: columns.append('captureWidth') else: - columns.append(f'width (MT={mt})') + columns.append('width (MT={})'.format(mt)) # Create Pandas dataframe with resonance parameters parameters = pd.DataFrame.from_records(records, columns=columns) @@ -899,7 +900,7 @@ class SpinGroup: self.parameters = parameters def __repr__(self): - return f'' + return ''.format(self.spin, self.parity) class Unresolved(ResonanceRange): diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index aa86ae33c..9e80e52f2 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -74,7 +74,7 @@ class ResonanceCovariances(Resonances): Parameters ---------- - ev : openmc.data.endf.Evaluation or endf.Material + ev : openmc.data.endf.Evaluation ENDF evaluation resonances : openmc.data.Resonance object openmc.data.Resonanance object generated from the same evaluation @@ -86,7 +86,6 @@ class ResonanceCovariances(Resonances): Resonance covariance data """ - ev = endf.as_evaluation(ev) file_obj = io.StringIO(ev.section[32, 151]) # Determine whether discrete or continuous representation @@ -94,8 +93,10 @@ class ResonanceCovariances(Resonances): n_isotope = items[4] # Number of isotopes ranges = [] - for _ in range(n_isotope): + for iso in range(n_isotope): items = endf.get_cont_record(file_obj) + abundance = items[1] + fission_widths = (items[3] == 1) # Flag for fission widths n_ranges = items[4] # Number of resonance energy ranges for j in range(n_ranges): @@ -240,14 +241,14 @@ class ResonanceCovarianceRange: samples = [] # Handling MLBW/SLBW sampling - rng = np.random.default_rng() if formalism == 'mlbw' or formalism == 'slbw': params = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] param_list = params[:mpar] mean_array = parameters[param_list].values mean = mean_array.flatten() - par_samples = rng.multivariate_normal(mean, cov, size=n_samples) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) spin = parameters['J'].values l_value = parameters['L'].values for sample in par_samples: @@ -278,7 +279,8 @@ class ResonanceCovarianceRange: param_list = params[:mpar] mean_array = parameters[param_list].values mean = mean_array.flatten() - par_samples = rng.multivariate_normal(mean, cov, size=n_samples) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) spin = parameters['J'].values l_value = parameters['L'].values for sample in par_samples: @@ -376,6 +378,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = endf.get_cont_record(file_obj) + target_spin = items[0] lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form nls = items[4] # number of l-values @@ -384,6 +387,8 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): items = endf.get_cont_record(file_obj) # Number of short range type resonance covariances num_short_range = items[4] + # Number of long range type resonance covariances + num_long_range = items[5] # Read resonance widths, J values, etc records = [] @@ -416,6 +421,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # compact correlations elif lcomp == 2: items, values = endf.get_list_record(file_obj) + mean = items num_res = items[5] energy = values[0::12] spin = values[1::12] @@ -607,14 +613,20 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = endf.get_cont_record(file_obj) + target_spin = items[0] lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form + nls = items[4] # Number of l-values # Build covariance matrix for General Resolved Resonance Formats if lcomp == 1: items = endf.get_cont_record(file_obj) # Number of short range type resonance covariances num_short_range = items[4] + # Number of long range type resonance covariances + num_long_range = items[5] # Read resonance widths, J values, etc + channel_radius = {} + scattering_radius = {} records = [] for i in range(num_short_range): items, values = endf.get_list_record(file_obj) diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 3b910c535..3d5f2df64 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -5,6 +5,7 @@ from numbers import Real from io import StringIO import itertools import os +import re import tempfile from warnings import warn @@ -27,231 +28,69 @@ from .thermal_angle_energy import (CoherentElasticAE, IncoherentElasticAE, _THERMAL_NAMES = { - 'c_Ag': ('ag',), 'c_Al27': ('al', 'al27', 'al-27', '13-al- 27'), 'c_Al_in_Al2O3': ('asap00', 'asap', 'al(al2o3)'), - 'c_Al_in_Y3Al5O12': ('al(y3al5o1', 'alyag'), - 'c_Au': ('au',), - 'c_Be': ('be', 'be-metal', 'be-met', 'be00', 'be-metal', 'be metal', '4-be', '4-be-'), + 'c_Be': ('be', 'be-metal', 'be-met', 'be00', 'be-metal', 'be metal', '4-be'), 'c_BeO': ('beo',), - 'c_Be_distinct': ('besd', 'be+sd'), - 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o', 'bbeo00', 'be(beo)', 'be_beo'), - 'c_Be_in_Be2C': ('bebe2c', 'be(be2c)'), - 'c_Be_in_BeF2': ('bebef2', 'be in bef2'), + 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o', 'bbeo00', 'be(beo)'), + 'c_Be_in_Be2C': ('bebe2c',), 'c_Be_in_FLiBe': ('beflib', 'be(flibe)'), - 'c_Bi': ('83-bi-', 'bi'), - 'c_Bi_in_Ge3Bi4O12': ('bi(ge3bi4o', 'bigbo'), 'c_C6H6': ('benz', 'c6h6', 'benzine'), - 'c_C_in_Be2C': ('cbe2c', 'c(be2c)'), - 'c_C_in_C19H16_liquid': ('c(c19h16)l', 'c19liq'), - 'c_C_in_C19H16_solid': ('c(c19h16)s', 'c19sol'), - 'c_C_in_C2H6O_liquid': ('c(c2h6o)l', 'ethliq'), - 'c_C_in_C2H6O_solid': ('c(c2h6o)s', 'ethsol'), - 'c_C_in_C5O2H8': ('clucit', 'c(lucite)'), - 'c_C_in_C6H6_liquid': ('c(c6h6)l', 'benzlq'), - 'c_C_in_C6H6_solid': ('c(c6h6)s', 'benzsl'), - 'c_C_in_C7H8_liquid': ('c(c7h8)l', 'tolliq'), - 'c_C_in_C7H8_solid': ('c(c7h8)s', 'tolsol'), - 'c_C_in_C8H8': ('cc8h8', 'c(polystyr'), - 'c_C_in_C8H10_liquid': ('c(m-c8h10)l', 'xylliq'), - 'c_C_in_C8H10_solid': ('c(m-c8h10)s', 'xylsol'), - 'c_C_in_C9H12_liquid': ('c(c9h12)l', 'mesliq'), - 'c_C_in_C9H12_solid': ('c(c9h12)s', 'messol'), - 'c_C_in_CF2': ('ccf2', 'c(teflon)'), - 'c_C_in_CH2': ('c(c2h4)n r', 'cch2'), - 'c_C_in_CH4_liquid': ('c(ch4)l', 'cch4lq'), - 'c_C_in_CH4_solid': ('c(ch4)s', 'cch4sl'), - 'c_C_in_Diamond': ('c(c-diamon', 'cdiam'), - 'c_C_in_SiC': ('csic', 'c-sic', 'c(3c-sic)', 'c_sic'), - 'c_C_in_UC_100p': ('cuc100', 'cinuc_100p'), - 'c_C_in_UC_10p': ('cuc10', 'cinuc_10p'), - 'c_C_in_UC_5p': ('cuc5', 'cinuc_5p'), - 'c_C_in_UC': ('cinuc', 'cinuc_nat'), - 'c_C_in_UC_HALEU': ('cuchal', 'cinuc_haleu'), - 'c_C_in_UC_HEU': ('cucheu', 'cinuc_heu'), - 'c_C_in_ZrC': ('czrc', 'c(zrc)'), - 'c_Ca': ('ca',), - 'c_Ca_in_CaH2': ('cah', 'cah00', 'cacah2', 'ca(cah2)', 'ca_cah2'), - 'c_Ca_in_CaO2H2': ('ca(caoh2)', 'cacaoh'), - 'c_Cr': ('cr',), - 'c_Cu': ('cu',), - 'c_D_in_7LiD': ('dlid', 'd(7lid)'), + 'c_C_in_SiC': ('csic', 'c-sic', 'c(3c-sic)'), + 'c_Ca_in_CaH2': ('cah', 'cah00', 'cacah2', 'ca(cah2)'), 'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw', 'dhw00', 'd(d2o)'), - 'c_D_in_D2O_solid': ('dice',), - 'c_D_in_MgD2': ('d(mgd2)', 'dmgd2'), - 'c_F_in_Be2': ('fbef2', 'f in bef2'), - 'c_F_in_CF2': ('fcf2', 'f(teflon)'), + 'c_D_in_D2O_ice': ('dice',), 'c_F_in_FLiBe': ('fflibe', 'f(flibe)'), - 'c_F_in_HF': ('f_hf',), - 'c_F_in_LiF': ('f(lif)', 'flif'), - 'c_F_in_MgF2': ('fmgf2', 'f in mgf2'), 'c_Fe56': ('fe', 'fe56', 'fe-56', '26-fe- 56'), - 'c_Fe_in_Fe_alpha': ('fe(fe-alph', 'fealph'), - 'c_Fe_in_Fe_gamma': ('fe(fe-gamm', 'fegamm'), - 'c_Ga_in_GaN': ('ga(gan)', 'gagan'), - 'c_Ga_in_GaSe': ('ga(gase)', 'gagase'), - 'c_Ge': ('ge',), - 'c_Ge_in_Ge3Bi4O12': ('ge(ge3bi4o', 'gegbo'), - 'c_Ge_in_GeTe': ('ge(gete)', 'gegete'), 'c_Graphite': ('graph', 'grph', 'gr', 'gr00', 'graphite'), 'c_Graphite_10p': ('grph10', '10p graphit'), - 'c_Graphite_20p': ('grph20', '20 graphite'), 'c_Graphite_30p': ('grph30', '30p graphit'), - 'c_Graphite_distinct': ('grphsd', 'grph+sd'), - 'c_H_in_7LiH': ('hlih', 'h(7lih)'), 'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci', 'h(lucite)'), - 'c_H_in_C8H8': ('hc8h8', 'h(polystyr'), 'c_H_in_CaH2': ('hcah2', 'hca00', 'h(cah2)'), - 'c_H_in_CaO2H2': ('h(caoh2)', 'hcaoh'), - 'c_H1_in_CaH2': ('h1cah2', 'h1_cah2'), - 'c_H2_in_CaH2': ('h2cah2', 'h2_cah2'), - 'c_H_in_C19H16_liquid': ('h(c19h16)l', 'h19liq'), - 'c_H_in_C19H16_solid': ('h(c19h16)s', 'h19sol'), - 'c_H_in_C2H6O_liquid': ('h(c2h6o)l', 'hetliq'), - 'c_H_in_C2H6O_solid': ('h(c2h6o)s', 'hetsol'), - 'c_H_in_C6H6_liquid': ('h(c6h6)l', 'hbzliq'), - 'c_H_in_C6H6_solid': ('h(c6h6)s', 'hbzsol'), - 'c_H_in_C7H8_liquid': ('h(c7h8)l', 'htlliq'), - 'c_H_in_C7H8_solid': ('h(c7h8)s', 'htlsol'), - 'c_H_in_C8H10_liquid': ('h(m-c8h10)l', 'hxyliq'), - 'c_H_in_C8H10_solid': ('h(m-c8h10)s', 'hxysol'), - 'c_H_in_C9H12_liquid': ('h(c9h12)l', 'hmsliq'), - 'c_H_in_C9H12_solid': ('h(c9h12)s', 'hmssol'), - 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly', 'pol00', 'h(ch2)', 'h(c2h4)n r'), - 'c_H_in_CH4_liquid': ('lch4', 'lmeth', 'l-ch4', 'h(ch4)l'), - 'c_H_in_CH4_solid': ('sch4', 'smeth', 's-ch4', 'h(ch4)s'), + 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly', 'pol00', 'h(ch2)'), + 'c_H_in_CH4_liquid': ('lch4', 'lmeth', 'l-ch4'), + 'c_H_in_CH4_solid': ('sch4', 'smeth', 's-ch4'), 'c_H_in_CH4_solid_phase_II': ('sch4p2',), 'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw', 'lw00', 'h(h2o)'), 'c_H_in_H2O_solid': ('hice', 'h-ice', 'ice00', 'h(ice-ih)', 'h(ice)'), - 'c_H_in_HF': ('hhf', 'h(hf)', 'h_hf'), - 'c_H_in_KOH': ('h(koh)', 'hkoh'), - 'c_H_in_LiH': ('h(lih)', 'hlih2'), + 'c_H_in_HF': ('hhf', 'h(hf)'), 'c_H_in_Mesitylene': ('mesi00', 'mesi', 'mesi-phii'), - 'c_H_in_MgH2': ('h(mgh2)', 'hmgh2'), - 'c_H_in_MgOH2': ('h(mgoh2)', 'hmgoh'), - 'c_H_in_NaMgH3': ('h(namgh3)', 'hnamg'), - 'c_H_in_NaOH': ('h(naoh)', 'hnaoh'), - 'c_H_in_ParaffinicOil': ('hparaf', 'h(paraffin', 'h(paraffini'), - 'c_H_in_SrH2': ('h(srh2)', 'hsrh2'), + 'c_H_in_ParaffinicOil': ('hparaf', 'h(paraffin'), 'c_H_in_Toluene': ('tol00', 'tol', 'tolue-phii'), 'c_H_in_UH3': ('huh3', 'h(uh3)'), 'c_H_in_YH2': ('hyh2', 'h-yh2', 'h(yh2)'), 'c_H_in_ZrH': ('hzrh', 'h-zrh', 'h-zr', 'h/zr', 'hzr', 'hzr00', 'h(zrh)'), - 'c_H_in_ZrH2': ('hzrh2', 'h(zrh2)', 'h(zrh2) in'), - 'c_H_in_ZrHx': ('hzrhx', 'h(zrhx)', 'h(zrh15) i'), - 'c_I_in_NaI': ('i(nai)', 'inai'), - 'c_K': ('k',), - 'c_K_in_KOH': ('k(koh)', 'kkoh'), + 'c_H_in_ZrH2': ('hzrh2', 'h(zrh2)'), + 'c_H_in_ZrHx': ('hzrhx', 'h(zrhx)'), 'c_Li_in_FLiBe': ('liflib', 'li(flibe)'), - 'c_Li_in_7LiD': ('lilid', '7li(7lid)'), - 'c_Li_in_7LiH': ('lilih', '7li(7lih)'), - 'c_Li_in_LiF': ('li(lif)', 'lilif'), - 'c_Li_in_LiH': ('li(lih)', 'lilih2'), 'c_Mg24': ('mg', 'mg24', 'mg00', '24-mg'), - 'c_Mg_in_MgD2': ('mg(mgd2)', 'mgmgd2'), - 'c_Mg_in_MgF2': ('mgmgf2', 'mg in mgf2'), - 'c_Mg_in_MgH2': ('mg(mgh2)', 'mgmgh2'), - 'c_Mg_in_MgO': ('mgmgo', 'mg in mgo'), - 'c_Mg_in_MgOH2': ('mg(mgoh2)', 'mgoh2'), - 'c_Mg_in_NaMgH3': ('mg(namgh3)', 'mgnamg'), - 'c_Mo': ('mo',), - 'c_N_in_GaN': ('n(gan)', 'ngan'), - 'c_N_in_UN_100p': ('nun100', 'n-un-100p'), - 'c_N_in_UN_10p': ('nun10', 'n-un-10p'), - 'c_N_in_UN_5p': ('nun5', 'n-un-5p'), - 'c_N_in_UN': ('n-un', 'n(un)', 'n(un) l', 'ninun'), - 'c_N_in_UN_HALEU': ('nunhal', 'n-un-haleu'), - 'c_N_in_UN_HEU': ('nunheu', 'n-un-heu'), - 'c_Na': ('na',), - 'c_Na_in_NaI': ('na(nai)', 'nanai'), - 'c_Na_in_NaMgH3': ('na(namgh3)', 'nanamg'), - 'c_Na_in_NaOH': ('na(naoh)', 'nanaoh'), - 'c_Nb': ('nb',), - 'c_Ni': ('ni',), + 'c_N_in_UN': ('n-un', 'n(un)', 'n(un) l'), 'c_O_in_Al2O3': ('osap00', 'osap', 'o(al2o3)'), - 'c_O_in_BeO': ('obeo', 'o-beo', 'o-be', 'o/be', 'obeo00', 'o(beo)', 'o_beo'), - 'c_O_in_C2H6O_liquid': ('o(c2h6o)l', 'oetliq'), - 'c_O_in_C2H6O_solid': ('o(c2h6o)s', 'oetsol'), - 'c_O_in_C5O2H8': ('olucit', 'o(lucite)'), - 'c_O_in_CaO2H2': ('o(caoh2)', 'ocaoh'), + 'c_O_in_BeO': ('obeo', 'o-beo', 'o-be', 'o/be', 'obeo00', 'o(beo)'), 'c_O_in_D2O': ('od2o', 'o-d2o', 'ohw00', 'o(d2o)'), - 'c_O_in_H2O': ('o(h2o)', 'oh2o'), 'c_O_in_H2O_solid': ('oice', 'o-ice', 'o(ice-ih)'), - 'c_O_in_Ge3Bi4O12': ('o(ge3bi4o1', 'ogbo'), - 'c_O_in_KOH': ('o(koh)', 'okoh'), - 'c_O_in_MgO': ('omgo', 'o in mgo'), - 'c_O_in_MgOH2': ('o(mgoh2)', 'omgoh'), - 'c_O_in_NaOH': ('o(naoh)', 'onaoh'), - 'c_O_in_PuO2': ('opuo2', 'o in puo2'), - 'c_O_in_SiO2_alpha': ('osio2a', 'o_sio2a'), - 'c_O_in_UO2_100p': ('ouo200', 'o-uo2-100p'), - 'c_O_in_UO2_10p': ('ouo210', 'oinuo2-10p'), - 'c_O_in_UO2_5p': ('ouo25', 'oinuo2-5p'), 'c_O_in_UO2': ('ouo2', 'o-uo2', 'o2-u', 'o2/u', 'ouo200', 'o(uo2)'), - 'c_O_in_UO2_HALEU': ('ouo2hl', 'ouo2-haleu'), - 'c_O_in_UO2_HEU': ('ouo2he', 'o_uo2-heu'), - 'c_O_in_Y3Al5O12': ('o(y3al5o12', 'oyag'), 'c_ortho_D': ('orthod', 'orthoD', 'dortho', 'od200', 'ortod', 'ortho-d'), 'c_ortho_H': ('orthoh', 'orthoH', 'hortho', 'oh200', 'ortoh', 'ortho-h'), 'c_para_D': ('parad', 'paraD', 'dpara', 'pd200', 'para-d'), 'c_para_H': ('parah', 'paraH', 'hpara', 'ph200', 'para-h'), - 'c_Pb': ('pb',), - 'c_Pd': ('pd',), - 'c_Pt': ('pt',), - 'c_Pu_in_PuO2': ('puo2', 'pu in puo2'), 'c_Si28': ('si00', 'sili', 'si'), - 'c_Si_in_SiC': ('sisic', 'si-sic', 'si(3c-sic)', 'si_sic'), - 'c_Si_in_SiO2_alpha': ('si_o2a', 'si_sio2a'), - 'c_SiO2_alpha': ('sio2', 'sio2a', 'sio2alpha', 'sio2-a'), - 'c_SiO2_beta': ('sio2b', 'sio2beta', 'sio2-b'), - 'c_S_in_ZnS': ('s(zns-spha', 'szns'), - 'c_Se_in_GaSe': ('se(gase)', 'segase'), - 'c_Sn': ('sn',), - 'c_Sr_in_SrH2': ('sr(srh2)', 'srsrh2'), - 'c_Te_in_GeTe': ('te(gete)', 'tegete'), - 'c_Ti': ('ti',), - 'c_U_metal_100p': ('u-100p',), - 'c_U_metal_10p': ('u-10p',), - 'c_U_metal_5p': ('u-5p',), - 'c_U_metal': ('umetal', 'u-metal'), - 'c_U_metal_HALEU': ('uhaleu', 'u-haleu'), - 'c_U_metal_HEU': ('u-heu',), - 'c_U_in_UC_100p': ('uc-100', 'uinuc_100p'), - 'c_U_in_UC_10p': ('uc-10', 'uinuc_10p'), - 'c_U_in_UC_5p': ('uc-5', 'uinuc_5p'), - 'c_U_in_UC': ('uc-nat', 'uinuc_nat'), - 'c_U_in_UC_HALEU': ('uc-hal', 'uinuc_haleu'), - 'c_U_in_UC_HEU': ('uc-heu', 'uinuc_heu'), - 'c_U_in_UN_100p': ('un-100', 'u-un-100p'), - 'c_U_in_UN_10p': ('un-10', 'u-un-10p'), - 'c_U_in_UN_5p': ('un-5', 'u-un-5p'), - 'c_U_in_UN': ('u-un', 'u(un)', 'u(un) l', 'uinun'), - 'c_U_in_UN_HALEU': ('un-hal', 'u-un-haleu'), - 'c_U_in_UN_HEU': ('un-heu', 'u-un-heu'), - 'c_U_in_UO2_100p': ('uo2100', 'uuo2-100p'), - 'c_U_in_UO2_10p': ('uo2-10', 'uuo2-10p'), - 'c_U_in_UO2_5p': ('uo2-5', 'uuo2-5p'), + 'c_Si_in_SiC': ('sisic', 'si-sic', 'si(3c-sic)'), + 'c_SiO2_alpha': ('sio2', 'sio2a', 'sio2alpha'), + 'c_SiO2_beta': ('sio2b', 'sio2beta'), + 'c_U_in_UN': ('u-un', 'u(un)', 'u(un) l'), 'c_U_in_UO2': ('uuo2', 'u-uo2', 'u-o2', 'u/o2', 'uuo200', 'u(uo2)'), - 'c_U_in_UO2_HALEU': ('uo2hal', 'uuo2-haleu'), - 'c_U_in_UO2_HEU': ('uo2heu', 'u_uo2-heu'), - 'c_V': ('v',), - 'c_W': ('w',), - 'c_Y_in_Y3Al5O12': ('y(y3al5o12', 'yyag'), 'c_Y_in_YH2': ('yyh2', 'y-yh2', 'y(yh2)'), - 'c_Zn': ('zn',), - 'c_Zn_in_ZnS': ('zn(zns-sph', 'znzns'), - 'c_Zr': ('zr',), - 'c_Zr_in_ZrC': ('zrzrc', 'zr(zrc)'), 'c_Zr_in_ZrH': ('zrzrh', 'zr-zrh', 'zr-h', 'zr/h', 'zr(zrh)'), - 'c_Zr_in_ZrH2': ('zrzrh2', 'zr(zrh2)', 'zr(zrh2) i'), - 'c_Zr_in_ZrHx': ('zrzrhx', 'zr(zrhx)', 'zr(zrh15)'), + 'c_Zr_in_ZrH2': ('zrzrh2', 'zr(zrh2)'), + 'c_Zr_in_ZrHx': ('zrzrhx', 'zr(zrhx)'), } def _temperature_str(T): # round() normally returns an int when called with a single argument, but # numpy floats overload rounding to return another float - return f"{int(round(T))}K" + return "{}K".format(int(round(T))) def get_thermal_name(name): @@ -265,7 +104,7 @@ def get_thermal_name(name): Returns ------- str - GNDS-format thermal scattering name + GND-format thermal scattering name """ if name in _THERMAL_NAMES: @@ -354,15 +193,15 @@ class CoherentElastic(Function1D): def bragg_edges(self): return self._bragg_edges + @property + def factors(self): + return self._factors + @bragg_edges.setter def bragg_edges(self, bragg_edges): cv.check_type('Bragg edges', bragg_edges, Iterable, Real) self._bragg_edges = np.asarray(bragg_edges) - @property - def factors(self): - return self._factors - @factors.setter def factors(self, factors): cv.check_type('structure factor cumulative sums', factors, @@ -382,7 +221,7 @@ class CoherentElastic(Function1D): """ dataset = group.create_dataset(name, data=np.vstack( [self.bragg_edges, self.factors])) - dataset.attrs['type'] = np.bytes_(type(self).__name__) + dataset.attrs['type'] = np.string_(type(self).__name__) @classmethod def from_hdf5(cls, dataset): @@ -455,7 +294,7 @@ class IncoherentElastic(Function1D): """ data = np.array([self.bound_xs, self.debye_waller]) dataset = group.create_dataset(name, data=data) - dataset.attrs['type'] = np.bytes_(type(self).__name__) + dataset.attrs['type'] = np.string_(type(self).__name__) @classmethod def from_hdf5(cls, dataset): @@ -557,7 +396,7 @@ class ThermalScattering(EqualityMixin): Parameters ---------- name : str - Name of the material using GNDS convention, e.g. c_H_in_H2O + Name of the material using GND convention, e.g. c_H_in_H2O atomic_weight_ratio : float Atomic mass ratio of the target nuclide. kTs : Iterable of float @@ -576,7 +415,7 @@ class ThermalScattering(EqualityMixin): Inelastic scattering cross section derived in the incoherent approximation name : str - Name of the material using GNDS convention, e.g. c_H_in_H2O + Name of the material using GND convention, e.g. c_H_in_H2O temperatures : Iterable of str List of string representations the temperatures of the target nuclide in the data set. The temperatures are strings of the temperature, @@ -600,7 +439,7 @@ class ThermalScattering(EqualityMixin): def __repr__(self): if hasattr(self, 'name'): - return f"" + return "".format(self.name) else: return "" @@ -625,7 +464,7 @@ class ThermalScattering(EqualityMixin): """ # Open file and write version with h5py.File(str(path), mode, libver=libver) as f: - f.attrs['filetype'] = np.bytes_('data_thermal') + f.attrs['filetype'] = np.string_('data_thermal') f.attrs['version'] = np.array(HDF5_VERSION) # Write basic data @@ -652,7 +491,7 @@ class ThermalScattering(EqualityMixin): ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str - GNDS-conforming name of the material, e.g. c_H_in_H2O. If none is + GND-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. @@ -667,7 +506,7 @@ class ThermalScattering(EqualityMixin): # Check if temprature already exists strT = data.temperatures[0] if strT in self.temperatures: - warn(f'S(a,b) data at T={strT} already exists.') + warn('S(a,b) data at T={} already exists.'.format(strT)) return # Check that name matches @@ -757,7 +596,7 @@ class ThermalScattering(EqualityMixin): ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str - GNDS-conforming name of the material, e.g. c_H_in_H2O. If none is + GND-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. @@ -775,7 +614,7 @@ class ThermalScattering(EqualityMixin): # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') if not xs.endswith('t'): - raise TypeError(f"{ace} is not a thermal scattering ACE table.") + raise TypeError("{} is not a thermal scattering ACE table.".format(ace)) if name is None: name = get_thermal_name(ace_name) @@ -831,50 +670,12 @@ class ThermalScattering(EqualityMixin): mu_i = [] for j in range(n_energy_out[i]): mu = ace.xss[idx + 4:idx + 4 + n_mu] - # The equiprobable angles produced by NJOY are not always - # sorted. This is problematic when the smearing algorithm - # is applied when sampling the angles. We sort the angles - # here, because they are equiprobable, so the order - # doesn't matter. - mu.sort() - - # Older versions of NJOY had a bug, and the discrete - # scattering angles could sometimes be less than -1 or - # greater than 1. We check for this here, and warn users. - if mu[0] < -1. or mu[-1] > 1.: - warn('S(a,b) scattering angle for incident energy index ' - f'{i} and exit energy index {j} outside of the ' - 'interval [-1, 1].') - p_mu = 1. / n_mu * np.ones(n_mu) mu_ij = Discrete(mu, p_mu) mu_ij.c = np.cumsum(p_mu) mu_i.append(mu_ij) idx += 3 + n_mu - # Check if the CDF for the outgoing energy distribution starts - # at 0. For NJOY and FRENDY evaluations, this is never the case, - # and can very rarely lead to negative energies when sampling - # the outgoing energy. From Eq. 7.6 of the ENDF manual, we can - # add an outgoing energy 0 eV that has a PDF of 0 (and of - # course, a CDF of 0 as well). - if eout_i.c[0] > 0.: - eout_i._x = np.insert(eout_i.x, 0, 0.) - eout_i._p = np.insert(eout_i.p, 0, 0.) - eout_i.c = np.insert(eout_i.c, 0, 0.) - - # For this added outgoing energy (of 0 eV) we add a set of - # isotropic discrete angles. - dmu = 2. / n_mu - mu = np.linspace(-1. + 0.5*dmu, 1. - 0.5*dmu, n_mu) - p_mu = 1. / n_mu * np.ones(n_mu) - mu_0 = Discrete(mu, p_mu) - mu_0.c = np.cumsum(p_mu) - mu_i.insert(0, mu_0) - # We don't worry about renormalizing the outgoing energy PDF/CDF - # after this manipulation, because it never seems to be - # normalized to begin with (at least with NJOY). - energy_out.append(eout_i) mu_out.append(mu_i) @@ -929,10 +730,10 @@ class ThermalScattering(EqualityMixin): if ace.nxs[5] == 3: xs = incoherent_xs - distribution = incoherent_dist + dist = incoherent_dist elif ace.nxs[5] == 4: xs = coherent_xs - distribution = coherent_dist + dist = coherent_dist else: # Create mixed cross section -- note that coherent must come # first due to assumption on C++ side @@ -965,7 +766,7 @@ class ThermalScattering(EqualityMixin): @classmethod def from_njoy(cls, filename, filename_thermal, temperatures=None, evaluation=None, evaluation_thermal=None, - use_endf_data=True, divide_incoherent_elastic=False, **kwargs): + use_endf_data=True, **kwargs): """Generate thermal scattering data by running NJOY. Parameters @@ -988,13 +789,8 @@ class ThermalScattering(EqualityMixin): use_endf_data : bool If the material has incoherent elastic scattering, the ENDF data will be used rather than the ACE data. - divide_incoherent_elastic : bool - Divide incoherent elastic cross section by number of principal - atoms. This is not part of the ENDF-6 standard but it is how it is - processed by NJOY. **kwargs - Keyword arguments passed to - :func:`openmc.data.njoy.make_ace_thermal` + Keyword arguments passed to :func:`openmc.data.njoy.make_ace_thermal` Returns ------- @@ -1019,7 +815,7 @@ class ThermalScattering(EqualityMixin): # Load ENDF data to replace incoherent elastic if use_endf_data: - data_endf = cls.from_endf(filename_thermal, divide_incoherent_elastic) + data_endf = cls.from_endf(filename_thermal) if data_endf.elastic is not None: # Get appropriate temperatures if temperatures is None: @@ -1037,18 +833,14 @@ class ThermalScattering(EqualityMixin): return data @classmethod - def from_endf(cls, ev_or_filename, divide_incoherent_elastic=False): + def from_endf(cls, ev_or_filename): """Generate thermal scattering data from an ENDF file Parameters ---------- - ev_or_filename : openmc.data.endf.Evaluation, endf.Material, or str + ev_or_filename : openmc.data.endf.Evaluation or str ENDF evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. - divide_incoherent_elastic : bool - Divide incoherent elastic cross section by number of principal - atoms. This is not part of the ENDF-6 standard but it is how it is - processed by NJOY. Returns ------- @@ -1056,7 +848,60 @@ class ThermalScattering(EqualityMixin): Thermal scattering data """ - ev = endf.as_evaluation(ev_or_filename) + if isinstance(ev_or_filename, endf.Evaluation): + ev = ev_or_filename + else: + ev = endf.Evaluation(ev_or_filename) + + # Read coherent/incoherent elastic data + elastic = None + if (7, 2) in ev.section: + # Define helper functions to avoid duplication + def get_coherent_elastic(file_obj): + # Get structure factor at first temperature + params, S = endf.get_tab1_record(file_obj) + strT = _temperature_str(params[0]) + n_temps = params[2] + bragg_edges = S.x + xs = {strT: CoherentElastic(bragg_edges, S.y)} + distribution = {strT: CoherentElasticAE(xs[strT])} + + # Get structure factor for subsequent temperatures + for _ in range(n_temps): + params, S = endf.get_list_record(file_obj) + strT = _temperature_str(params[0]) + xs[strT] = CoherentElastic(bragg_edges, S) + distribution[strT] = CoherentElasticAE(xs[strT]) + return xs, distribution + + def get_incoherent_elastic(file_obj): + params, W = endf.get_tab1_record(file_obj) + bound_xs = params[0] + xs = {} + distribution = {} + for T, debye_waller in zip(W.x, W.y): + strT = _temperature_str(T) + xs[strT] = IncoherentElastic(bound_xs, debye_waller) + distribution[strT] = IncoherentElasticAE(debye_waller) + return xs, distribution + + file_obj = StringIO(ev.section[7, 2]) + lhtr = endf.get_head_record(file_obj)[2] + if lhtr == 1: + # coherent elastic + xs, distribution = get_coherent_elastic(file_obj) + elif lhtr == 2: + # incoherent elastic + xs, distribution = get_incoherent_elastic(file_obj) + elif lhtr == 3: + # mixed coherent / incoherent elastic + xs_c, dist_c = get_coherent_elastic(file_obj) + xs_i, dist_i = get_incoherent_elastic(file_obj) + assert sorted(xs_c) == sorted(xs_i) + xs = {T: Sum([xs_c[T], xs_i[T]]) for T in xs_c} + distribution = {T: MixedElasticAE(dist_c[T], dist_i[T]) for T in dist_c} + + elastic = ThermalScatteringReaction(xs, distribution) # Read incoherent inelastic data assert (7, 4) in ev.section, 'No MF=7, MT=4 found in thermal scattering' @@ -1072,7 +917,6 @@ class ThermalScattering(EqualityMixin): data['A0'] = awr = B[2] data['e_max'] = energy_max = B[3] data['M0'] = B[5] - free_xs = data['free_atom_xs'] / data['M0'] # Get information about non-principal atoms n_non_principal = params[5] @@ -1117,74 +961,6 @@ class ThermalScattering(EqualityMixin): _, Teff = endf.get_tab1_record(file_obj) data['effective_temperature'].append(Teff) - # Read coherent/incoherent elastic data - elastic = None - if (7, 2) in ev.section: - # Define helper functions to avoid duplication - def get_coherent_elastic(file_obj): - # Get structure factor at first temperature - params, S = endf.get_tab1_record(file_obj) - strT = _temperature_str(params[0]) - n_temps = params[2] - bragg_edges = S.x - xs = {strT: CoherentElastic(bragg_edges, S.y)} - distribution = {strT: CoherentElasticAE(xs[strT])} - - # Get structure factor for subsequent temperatures - for _ in range(n_temps): - params, S = endf.get_list_record(file_obj) - strT = _temperature_str(params[0]) - xs[strT] = CoherentElastic(bragg_edges, S) - distribution[strT] = CoherentElasticAE(xs[strT]) - return xs, distribution - - def get_incoherent_elastic(file_obj, natom): - params, W = endf.get_tab1_record(file_obj) - bound_xs = params[0]/natom - - # Check whether divide_incoherent_elastic was applied correctly - if abs(free_xs - bound_xs/(1 + 1/data['A0'])**2) > 0.5: - if divide_incoherent_elastic: - msg = ( - 'Thermal scattering evaluation follows ENDF-6 ' - 'definition of bound cross section but ' - 'divide_incoherent_elastic=True.' - ) - else: - msg = ( - 'Thermal scattering evaluation follows NJOY ' - 'definition of bound cross section but ' - 'divide_incoherent_elastic=False.' - ) - warn(msg) - - xs = {} - distribution = {} - for T, debye_waller in zip(W.x, W.y): - strT = _temperature_str(T) - xs[strT] = IncoherentElastic(bound_xs, debye_waller) - distribution[strT] = IncoherentElasticAE(debye_waller) - return xs, distribution - - file_obj = StringIO(ev.section[7, 2]) - lhtr = endf.get_head_record(file_obj)[2] - natom = data['M0'] if divide_incoherent_elastic else 1 - if lhtr == 1: - # coherent elastic - xs, distribution = get_coherent_elastic(file_obj) - elif lhtr == 2: - # incoherent elastic - xs, distribution = get_incoherent_elastic(file_obj, natom) - elif lhtr == 3: - # mixed coherent / incoherent elastic - xs_c, dist_c = get_coherent_elastic(file_obj) - xs_i, dist_i = get_incoherent_elastic(file_obj, natom) - assert sorted(xs_c) == sorted(xs_i) - xs = {T: Sum([xs_c[T], xs_i[T]]) for T in xs_c} - distribution = {T: MixedElasticAE(dist_c[T], dist_i[T]) for T in dist_c} - - elastic = ThermalScatteringReaction(xs, distribution) - name = ev.target['zsymam'].strip() instance = cls(name, awr, energy_max, kTs) if elastic is not None: diff --git a/openmc/data/thermal_angle_energy.py b/openmc/data/thermal_angle_energy.py index 4789ebcc6..17a560092 100644 --- a/openmc/data/thermal_angle_energy.py +++ b/openmc/data/thermal_angle_energy.py @@ -43,7 +43,7 @@ class CoherentElasticAE(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('coherent_elastic') + group.attrs['type'] = np.string_('coherent_elastic') self.coherent_xs.to_hdf5(group, 'coherent_xs') @classmethod @@ -104,7 +104,7 @@ class IncoherentElasticAE(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('incoherent_elastic') + group.attrs['type'] = np.string_('incoherent_elastic') group.create_dataset('debye_waller', data=self.debye_waller) @classmethod @@ -146,7 +146,7 @@ class IncoherentElasticAEDiscrete(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('incoherent_elastic_discrete') + group.attrs['type'] = np.string_('incoherent_elastic_discrete') group.create_dataset('mu_out', data=self.mu_out) @classmethod @@ -203,7 +203,7 @@ class IncoherentInelasticAEDiscrete(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('incoherent_inelastic_discrete') + group.attrs['type'] = np.string_('incoherent_inelastic_discrete') group.create_dataset('energy_out', data=self.energy_out) group.create_dataset('mu_out', data=self.mu_out) group.create_dataset('skewed', data=self.skewed) @@ -225,7 +225,7 @@ class IncoherentInelasticAEDiscrete(AngleEnergy): """ energy_out = group['energy_out'][()] mu_out = group['mu_out'][()] - skewed = bool(group['skewed'][()]) + skewed = bool(group['skewed']) return cls(energy_out, mu_out, skewed) @@ -266,7 +266,7 @@ class MixedElasticAE(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('mixed_elastic') + group.attrs['type'] = np.string_('mixed_elastic') coherent_group = group.create_group('coherent') self.coherent.to_hdf5(coherent_group) incoherent_group = group.create_group('incoherent') diff --git a/openmc/data/uncorrelated.py b/openmc/data/uncorrelated.py index 141007b70..0361c9b37 100644 --- a/openmc/data/uncorrelated.py +++ b/openmc/data/uncorrelated.py @@ -38,16 +38,16 @@ class UncorrelatedAngleEnergy(AngleEnergy): def angle(self): return self._angle + @property + def energy(self): + return self._energy + @angle.setter def angle(self, angle): cv.check_type('uncorrelated angle distribution', angle, AngleDistribution) self._angle = angle - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('uncorrelated energy distribution', energy, @@ -63,7 +63,7 @@ class UncorrelatedAngleEnergy(AngleEnergy): HDF5 group to write to """ - group.attrs['type'] = np.bytes_('uncorrelated') + group.attrs['type'] = np.string_('uncorrelated') if self.angle is not None: angle_group = group.create_group('angle') self.angle.to_hdf5(angle_group) diff --git a/openmc/data/urr.py b/openmc/data/urr.py index f129c98f8..53961a50a 100644 --- a/openmc/data/urr.py +++ b/openmc/data/urr.py @@ -79,51 +79,51 @@ class ProbabilityTables(EqualityMixin): def absorption_flag(self): return self._absorption_flag + @property + def energy(self): + return self._energy + + @property + def inelastic_flag(self): + return self._inelastic_flag + + @property + def interpolation(self): + return self._interpolation + + @property + def multiply_smooth(self): + return self._multiply_smooth + + @property + def table(self): + return self._table + @absorption_flag.setter def absorption_flag(self, absorption_flag): cv.check_type('absorption flag', absorption_flag, Integral) self._absorption_flag = absorption_flag - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('probability table energies', energy, Iterable, Real) self._energy = energy - @property - def inelastic_flag(self): - return self._inelastic_flag - @inelastic_flag.setter def inelastic_flag(self, inelastic_flag): cv.check_type('inelastic flag', inelastic_flag, Integral) self._inelastic_flag = inelastic_flag - @property - def interpolation(self): - return self._interpolation - @interpolation.setter def interpolation(self, interpolation): cv.check_value('interpolation', interpolation, [2, 5]) self._interpolation = interpolation - @property - def multiply_smooth(self): - return self._multiply_smooth - @multiply_smooth.setter def multiply_smooth(self, multiply_smooth): cv.check_type('multiply by smooth', multiply_smooth, bool) self._multiply_smooth = multiply_smooth - @property - def table(self): - return self._table - @table.setter def table(self, table): cv.check_type('probability tables', table, np.ndarray) diff --git a/openmc/data/vectfit.py b/openmc/data/vectfit.py deleted file mode 100644 index c5a783a3c..000000000 --- a/openmc/data/vectfit.py +++ /dev/null @@ -1,811 +0,0 @@ -""" -Fast Relaxed Vector Fitting function - -Approximate f(s) with a rational function: - f(s)=R*(s*I-A)^(-1) + Polynomials*s -where f(s) is a vector of elements. - -When f(s) is a vector, all elements become fitted with a common pole set. The -identification is done using the pole relocating method known as Vector Fitting -[1] with relaxed non-triviality constraint for faster convergence and smaller -fitting errors [2], and utilization of matrix structure for fast solution of the -pole identifion step [3]. - -[1] B. Gustavsen and A. Semlyen, "Rational approximation of frequency - domain responses by Vector Fitting", IEEE Trans. Power Delivery, vol. 14, - no. 3, pp. 1052-1061, July 1999. -[2] B. Gustavsen, "Improving the pole relocating properties of vector - fitting", IEEE Trans. Power Delivery, vol. 21, no. 3, pp. 1587-1592, July - 2006. -[3] D. Deschrijver, M. Mrozowski, T. Dhaene, and D. De Zutter, - "Macromodeling of Multiport Systems Using a Fast Implementation of the - Vector Fitting Method", IEEE Microwave and Wireless Components Letters, vol. - 18, no. 6, pp. 383-385, June 2008. - -All credit goes to: - - Bjorn Gustavsen for his MATLAB implementation. - (http://www.sintef.no/Projectweb/VECTFIT/) - - Jingang Liang for his C++ implementation. - (https://github.com/mit-crpg/vectfit.git) - -""" - -from typing import Tuple - -import numpy as np -from scipy.linalg import eigvals, lstsq, norm, qr - - -def wlstsq(a, b): - """Apply least-squares solve with column normalization. - - Notes - ----- - This routine rescales columns of `a` to improve conditioning. Columns with - zero norm are left unscaled to avoid divide-by-zero warnings. - """ - col_norm = np.linalg.norm(a, axis=0) - scale = np.ones_like(col_norm, dtype=float) - nonzero = col_norm > 0.0 - scale[nonzero] = 1.0 / col_norm[nonzero] - scale = np.nan_to_num(scale, nan=1.0, posinf=1.0, neginf=1.0) - - sol = lstsq(a * scale, b) - return (sol[0] * scale, sol[1:]) - - -def evaluate( - eval_points: np.ndarray, - pole_values: np.ndarray, - residue_matrix: np.ndarray, - poly_coefficients: np.ndarray | None = None, -) -> np.ndarray: - """Evaluate the rational function approximation: - f(s) ≈ sum(residue / (s - pole)) + sum(poly_coefficients * s^j) - - Parameters - ---------- - eval_points : np.ndarray - 1D array of real scalar frequency values (s). - pole_values : np.ndarray - 1D array of complex poles. - residue_matrix : np.ndarray - 2D or 1D array of complex residues (shape: [num_vectors, num_poles] or [num_poles]). - poly_coefficients : np.ndarray, optional - 2D or 1D array of real polynomial coefficients (shape: [num_vectors, num_polys]). - - Returns - ------- - np.ndarray - 2D array of evaluated real function values (shape: [num_vectors, num_samples]). - - Raises - ------ - ValueError - If input arrays have incompatible shapes. - """ - eval_points = np.asarray(eval_points) - pole_values = np.asarray(pole_values) - residue_matrix = np.asarray(residue_matrix) - - if eval_points.ndim != 1: - raise ValueError("eval_points must be a 1D array") - if pole_values.ndim != 1: - raise ValueError("pole_values must be a 1D array") - - if residue_matrix.ndim == 1: - residue_matrix = residue_matrix.reshape((1, -1)) - num_vectors, _ = residue_matrix.shape - num_samples = len(eval_points) - - if poly_coefficients is not None and isinstance(poly_coefficients, list): - poly_coefficients = np.array(poly_coefficients) - if poly_coefficients is None or poly_coefficients.size == 0: - poly_coefficients = np.zeros((num_vectors, 0)) - else: - poly_coefficients = np.asarray(poly_coefficients) - if poly_coefficients.ndim == 1: - poly_coefficients = poly_coefficients.reshape((1, -1)) - elif poly_coefficients.shape[0] != num_vectors: - raise ValueError("Mismatch in residues and poly_coefficients shapes") - - num_coeffs = poly_coefficients.shape[1] - result = np.zeros((num_vectors, num_samples)) - - # term: sum over poles of (residues / (eval_points - poles)) - denominator = ( - eval_points[np.newaxis, :] - pole_values[:, np.newaxis] - ) # shape: (num_poles, num_eval) - pole_terms = residue_matrix @ (1.0 / denominator) # shape: (num_vectors, num_eval) - result = np.real(pole_terms) - - # polynomial part: sum over poly_idx of (coeff * eval_points**poly_idx) - if num_coeffs > 0: - powers = ( - eval_points[np.newaxis, :] ** np.arange(num_coeffs)[:, np.newaxis] - ) # shape: (num_coeffs, num_eval) - result += poly_coefficients @ powers # shape: (num_vectors, num_eval) - - return result - - -def vectfit( - response_matrix: np.ndarray, - eval_points: np.ndarray, - initial_poles: np.ndarray, - weights: np.ndarray, - n_polys: int = 0, - skip_pole_update: bool = False, - skip_residue_update: bool = False, -) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, float]: - """Perform vector fitting using the Fast Relaxed Vector Fitting algorithm. - - Parameters - ---------- - response_matrix : np.ndarray - Complex matrix of frequency responses (shape: [num_vectors, num_samples]). - eval_points : np.ndarray - Real frequency samples (s), shape (num_samples,). - initial_poles : np.ndarray - Initial guess for poles (complex), shape (num_poles,). - weights : np.ndarray - Weighting matrix for fitting (same shape as response_matrix). - n_polys : int, optional - Number of real polynomial terms to include. - skip_pole_update : bool, optional - Whether to skip pole relocation step. - skip_residue_update : bool, optional - Whether to skip residue fitting step. - - Returns - ------- - Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, float] - - Updated poles (np.ndarray) - - Residues (np.ndarray) - - Polynomial coefficients (np.ndarray) - - Fitted response matrix (np.ndarray) - - Root-mean-square error (float) - """ - tol_low = 1e-18 - tol_high = 1e18 - response_matrix = np.asarray(response_matrix) - eval_points = np.asarray(eval_points) - initial_poles = np.asarray(initial_poles) - weights = np.asarray(weights) - - num_vectors, num_samples = response_matrix.shape - num_poles = len(initial_poles) - - if n_polys < 0 or n_polys > 11: - raise ValueError("n_polys must be in [0, 11]") - - residue_matrix = np.zeros((num_vectors, num_poles), dtype=np.complex128) - poly_coefficients = np.zeros((num_vectors, n_polys)) - fit_result = np.zeros_like(response_matrix) - rms_error = 0.0 - - if num_poles == 0 and n_polys == 0: - rms_error = norm(response_matrix) / np.sqrt(num_vectors * num_samples) - return initial_poles, residue_matrix, poly_coefficients, fit_result, rms_error - - if not skip_pole_update and num_poles > 0: - updated_poles = identify_poles( - num_poles, - num_samples, - n_polys, - initial_poles, - eval_points, - tol_high, - weights, - response_matrix, - num_vectors, - tol_low, - ) - else: - updated_poles = initial_poles - - if not skip_residue_update: - fit_result, rms_error = identify_residues( - num_poles, - updated_poles, - num_samples, - n_polys, - eval_points, - num_vectors, - weights, - response_matrix, - poly_coefficients, - residue_matrix, - ) - - return updated_poles, residue_matrix, poly_coefficients, fit_result, rms_error - - -def compute_dk_matrix( - dk_matrix: np.ndarray, - eval_points: np.ndarray, - poles: np.ndarray, - conj_index: np.ndarray, - num_poles: int, - num_polys: int, - tol_high: float = None, -): - """Compute the dk_matrix used in windowed multipole evaluations. - - Parameters - ---------- - dk_matrix : ndarray of shape (len(eval_points), M) - The full matrix used in least-squares fitting or evaluation. - eval_points : ndarray of shape (N,) - Energy points at which to evaluate. - poles : ndarray of shape (num_poles,) - Complex poles used in the resonance model. - conj_index : ndarray of shape (num_poles,) - Index array indicating pole conjugacy behavior: 0 (normal), 1 (add conjugate), 2 (imaginary part). - num_poles : int - Number of complex poles. - num_polys : int - Number of polynomial terms (including constant term). - tol_high : float - Replacement value for infinities. - """ - # Broadcast shapes - eval_points_col = eval_points[:, np.newaxis] - poles_row = poles[np.newaxis, :] - - # Compute base terms - term1 = 1.0 / (eval_points_col - poles_row) - term2 = 1.0 / (eval_points_col - np.conj(poles_row)) - term3 = 1j / (eval_points_col - np.conj(poles_row)) - 1j / ( - eval_points_col - poles_row - ) - - # Masks for different conjugacy types - mask0 = conj_index == 0 - mask1 = conj_index == 1 - mask2 = conj_index == 2 - - # Fill dk_matrix with pole terms - dk_matrix[:, :num_poles][:, mask0] = term1[:, mask0] - dk_matrix[:, :num_poles][:, mask1] = term1[:, mask1] + term2[:, mask1] - dk_matrix[:, :num_poles][:, mask2] = term3[:, mask2] - - # Replace infinities with high tolerance value - if tol_high is not None: - inf_mask = np.isinf(dk_matrix) - dk_matrix[inf_mask] = tol_high + 0j - - # Add polynomial basis (Chebyshev-like, just powers here) - powers = np.arange(num_polys) - dk_matrix[:, num_poles : num_poles + num_polys] = eval_points_col**powers + 0j - return dk_matrix - - -def row_block_matrix( - dk_matrix: np.ndarray, - weights: np.ndarray, - response_matrix: np.ndarray, - vec_idx: int, - num_poles: int, - num_polys: int, -) -> np.ndarray: - """ - Construct a single matrix row block for the given vector index. - - Parameters - ---------- - dk_matrix : ndarray of shape (num_samples, num_poles + num_polys) - Basis function evaluations at each sample point. - weights : ndarray of shape (num_vectors, num_samples) - Sample weights for each vector. - response_matrix : ndarray of shape (num_vectors, num_samples) - Response values at each sample point. - vec_idx : int - Index of the vector to construct the A1 block for. - num_poles : int - Number of poles used in the model. - num_polys : int - Number of polynomial basis terms. - - Returns - ------- - A : ndarray of shape (num_samples, num_poles + num_polys + num_poles + 1) - Weighted and assembled matrix block for the current vector. - """ - num_samples = dk_matrix.shape[0] - A = np.zeros( - (num_samples, num_poles + num_polys + num_poles + 1), dtype=np.complex128 - ) - - # Weighted basis terms - A[:, : num_poles + num_polys] = ( - weights[vec_idx][:, np.newaxis] * dk_matrix[:, : num_poles + num_polys] - ) - - # Weighted response terms (includes poles + 1) - A[:, num_poles + num_polys : num_poles + num_polys + num_poles + 1] = ( - -weights[vec_idx][:, np.newaxis] - * dk_matrix[:, : num_poles + 1] - * response_matrix[vec_idx][:, np.newaxis] - ) - - return A - - -def process_constrained_block( - vec_idx: int, - dk_matrix: np.ndarray, - weights: np.ndarray, - response_matrix: np.ndarray, - num_samples: int, - num_poles: int, - num_polys: int, - scale_factor: float, - num_vectors: int, -) -> Tuple[int, np.ndarray, np.ndarray]: - """ - Construct a constrained least-squares system block for the given vector index. - - This function computes the A matrix using weighted evaluations of the basis functions - and response terms. It appends a constraint row to enforce physical properties - (e.g., normalization) **only for the final vector index**. The full matrix A is - decomposed via QR, and the resulting triangular block is returned. - - This routine is intended for use in the main vector fitting loop when the denominator - is well-conditioned but requires an additional constraint row for physical consistency. - - Parameters - ---------- - vec_idx : int - Index of the vector to process. - dk_matrix : ndarray of shape (num_samples, num_poles + num_polys) - Evaluated basis functions at sample points. - weights : ndarray of shape (num_vectors, num_samples) - Weight matrix per vector. - response_matrix : ndarray of shape (num_vectors, num_samples) - Response function values for each vector. - num_samples : int - Number of sample points. - num_poles : int - Number of poles in the model. - num_polys : int - Number of polynomial terms in the model. - scale_factor : float - Scaling factor applied to the final constraint row. - num_vectors : int - Total number of vectors to process. - - Returns - ------- - vec_idx : int - Index of the processed vector. - lhs_block : ndarray of shape (num_poles + 1, num_poles + 1) - Triangular matrix block from QR decomposition. - rhs_block : ndarray of shape (num_poles + 1,) or None - Right-hand side vector block (only returned for final vec_idx), else None. - """ - A1 = row_block_matrix( - dk_matrix, weights, response_matrix, vec_idx, num_poles, num_polys - ) - A = np.zeros((2 * num_samples + 1, num_poles + num_polys + num_poles + 1)) - A[:num_samples] = A1.real - A[num_samples : 2 * num_samples] = A1.imag - # Handle final row only if vec_idx is last - if vec_idx == num_vectors - 1: - A[ - 2 * num_samples, - num_poles + num_polys : num_poles + num_polys + num_poles + 1, - ] = scale_factor * np.real(dk_matrix[:, : num_poles + 1].sum(axis=0)) - - Q, R = qr(A, mode="economic") - - lhs_block = R[ - num_poles + num_polys : num_poles + num_polys + num_poles + 1, - num_poles + num_polys : num_poles + num_polys + num_poles + 1, - ] - - if vec_idx == num_vectors - 1: - rhs_block = ( - num_samples - * scale_factor - * Q[-1, num_poles + num_polys : num_poles + num_polys + num_poles + 1] - ) - else: - rhs_block = np.zeros_like( - Q[-1, num_poles + num_polys : num_poles + num_polys + num_poles + 1] - ) - - return vec_idx, lhs_block, rhs_block - - -def process_unconstrained_block( - vec_idx: int, - dk_matrix: np.ndarray, - weights: np.ndarray, - response_matrix: np.ndarray, - denom: float, - num_poles: int, - num_polys: int, -) -> Tuple[int, np.ndarray, np.ndarray]: - """ - Construct an unconstrained least-squares system block for the given vector index. - - This function is used when the fitting denominator becomes ill-conditioned - (too small or too large), and the original constrained system is replaced by - an alternative regularized least-squares problem. The A matrix is built by stacking - the real and imaginary parts of the basis evaluations, and the RHS vector b is - scaled by `denom`. - - A standard QR decomposition is used to extract the square block of the system, - which can be solved independently from the constrained system. - - Parameters - ---------- - vec_idx : int - Index of the vector to process. - dk_matrix : ndarray of shape (num_samples, num_poles + num_polys) - Evaluated basis functions at sample points. - weights : ndarray of shape (num_vectors, num_samples) - Weight matrix per vector. - response_matrix : ndarray of shape (num_vectors, num_samples) - Response function values for each vector. - denom : float - Scaling factor applied to the right-hand side vector b. - num_poles : int - Number of poles in the model. - num_polys : int - Number of polynomial terms in the model. - - Returns - ------- - vec_idx : int - Index of the processed vector. - lhs_block : ndarray of shape (num_poles, num_poles) - Triangular matrix block from QR decomposition. - rhs_block : ndarray of shape (num_poles,) - Right-hand side vector block for this vector. - """ - A1 = row_block_matrix( - dk_matrix, weights, response_matrix, vec_idx, num_poles, num_polys - ) - A = np.vstack((A1.real, A1.imag)) - - b1 = denom * weights[vec_idx] * response_matrix[vec_idx] - b = np.concatenate((b1.real, b1.imag)) - - Q, R = qr(A, mode="economic") - - lhs_block = R[ - num_poles + num_polys : num_poles + num_polys + num_poles, - num_poles + num_polys : num_poles + num_polys + num_poles, - ] - rhs_block = Q[:, num_poles + num_polys : num_poles + num_polys + num_poles].T @ b - return vec_idx, lhs_block, rhs_block - - -def identify_poles( - num_poles: int, - num_samples: int, - num_polys: int, - poles: np.ndarray, - eval_points: np.ndarray, - tol_high: float, - weights: np.ndarray, - response_matrix: np.ndarray, - num_vectors: int, - tol_low: float, -) -> np.ndarray: - """ - Internal routine to update poles via relaxed vector fitting. - - Parameters - ---------- - num_poles : int - Number of poles. - num_samples : int - Number of frequency samples. - num_polys : int - Number of polynomial terms. - poles : np.ndarray - Initial poles (complex), shape (num_poles,). - eval_points : np.ndarray - Real frequency values, shape (num_samples,). - tol_high : float - Upper tolerance threshold for denominator. - weights : np.ndarray - Weighting matrix, shape (num_vectors, num_samples). - response_matrix : np.ndarray - Complex frequency responses, shape (num_vectors, num_samples). - num_vectors : int - Number of response vectors. - tol_low : float - Lower tolerance threshold for denominator. - - Returns - ------- - np.ndarray - Updated poles as eigenvalues (shape: [num_poles]). - """ - conj_index = label_conjugate_poles(poles) - dk_matrix = np.zeros( - (num_samples, num_poles + max(num_polys, 1)), dtype=np.complex128 - ) - compute_dk_matrix( - dk_matrix, eval_points, poles, conj_index, num_poles, num_polys, tol_high - ) - # For relaxed vector fitting, include the constant term in the sigma(s) - # function even when no polynomial terms are requested. This ensures the - # constrained system is well-posed when n_polys == 0. - if num_polys == 0: - dk_matrix[:, num_poles] = 1.0 + 0j - - scale_factor = ( - np.sqrt( - sum(norm(weights[m] * response_matrix[m]) ** 2 for m in range(num_vectors)) - ) - / num_samples - ) - lhs_matrix = np.zeros((num_vectors * (num_poles + 1), num_poles + 1)) - rhs_vector = np.zeros(num_vectors * (num_poles + 1)) - - for vec_idx in range(num_vectors): - vec_idx, lhs_block, rhs_block = process_constrained_block( - vec_idx, - dk_matrix, - weights, - response_matrix, - num_samples, - num_poles, - num_polys, - scale_factor, - num_vectors, - ) - i0 = vec_idx * (num_poles + 1) - i1 = (vec_idx + 1) * (num_poles + 1) - lhs_matrix[i0:i1] = lhs_block - rhs_vector[i0:i1] = rhs_block - - solution, *_ = wlstsq(lhs_matrix, rhs_vector) - coeffs = solution[:-1] - denom = solution[-1] - - if abs(denom) < tol_low or abs(denom) > tol_high: - lhs_matrix = np.zeros((num_vectors * num_poles, num_poles)) - rhs_vector = np.zeros(num_vectors * num_poles) - # Adjust denom - if denom == 0.0: - denom = 1.0 - elif abs(denom) < tol_low: - denom = np.sign(denom) * tol_low - elif abs(denom) > tol_high: - denom = np.sign(denom) * tol_high - - # Allocate output - lhs_matrix = np.zeros((num_vectors * num_poles, num_poles)) - rhs_vector = np.zeros(num_vectors * num_poles) - - for vec_idx in range(num_vectors): - vec_idx, lhs_block, rhs_block = process_unconstrained_block( - vec_idx, - dk_matrix, - weights, - response_matrix, - denom, - num_poles, - num_polys, - ) - i0 = vec_idx * num_poles - i1 = (vec_idx + 1) * num_poles - lhs_matrix[i0:i1] = lhs_block - rhs_vector[i0:i1] = rhs_block - - coeffs, *_ = wlstsq(lhs_matrix, rhs_vector) - - lambda_matrix = np.zeros((num_poles, num_poles)) - scale_vector = np.ones((num_poles, 1)) - - # Mask for real poles (conj_index == 0) - mask_real = conj_index == 0 - real_indices = np.where(mask_real)[0] - lambda_matrix[real_indices, real_indices] = np.real(poles[real_indices]) - - # Mask for start of complex conjugate pairs (conj_index == 1) - mask_cplx_start = conj_index == 1 - cplx_indices = np.where(mask_cplx_start)[0] - - # Extract real and imaginary parts of complex conjugate poles - real_parts = np.real(poles[cplx_indices]) - imag_parts = np.imag(poles[cplx_indices]) - - # Diagonal assignments - lambda_matrix[cplx_indices, cplx_indices] = real_parts - lambda_matrix[cplx_indices + 1, cplx_indices + 1] = real_parts - - # Off-diagonal assignments - lambda_matrix[cplx_indices, cplx_indices + 1] = imag_parts - lambda_matrix[cplx_indices + 1, cplx_indices] = -imag_parts - - # Scaling vector adjustments - scale_vector[cplx_indices, 0] = 2.0 - scale_vector[cplx_indices + 1, 0] = 0.0 - - residue_matrix = lambda_matrix - np.outer(scale_vector.squeeze(), coeffs) / denom - return eigvals(residue_matrix) - - -def solve_vector_block( - vec_idx: int, - dk_matrix: np.ndarray, - weights: np.ndarray, - response_matrix: np.ndarray, - num_poles: int, - num_polys: int, -) -> Tuple[int, np.ndarray, np.ndarray]: - """ - Solve the least-squares system for a single vector index. - - Parameters - ---------- - vec_idx : int - Index of the vector to solve. - dk_matrix : ndarray - Basis function evaluations of shape (num_samples, num_poles + num_polys). - weights : ndarray - Weight array of shape (num_vectors, num_samples). - response_matrix : ndarray - Response array of shape (num_vectors, num_samples). - num_poles : int - Number of poles. - num_polys : int - Number of polynomial coefficients. - - Returns - ------- - vec_idx : int - The index of the solved vector. - residues : ndarray - Solution vector for the residues (length = num_poles). - poly_coeffs : ndarray or None - Solution vector for polynomial coefficients (length = num_polys), or None if num_polys == 0. - """ - A = dk_matrix * weights[vec_idx][:, np.newaxis] - b = weights[vec_idx] * response_matrix[vec_idx] - - lhs_matrix = np.vstack((A.real, A.imag)) - rhs_vector = np.concatenate((b.real, b.imag)) - - x = wlstsq(lhs_matrix, rhs_vector)[0] - - residues = x[:num_poles] - poly_coeffs = x[num_poles : num_poles + num_polys] if num_polys > 0 else None - - return vec_idx, residues, poly_coeffs - - -def identify_residues( - num_poles: int, - poles: np.ndarray, - num_samples: int, - num_polys: int, - eval_points: np.ndarray, - num_vectors: int, - weights: np.ndarray, - response_matrix: np.ndarray, - poly_coefficients: np.ndarray, - residue_matrix: np.ndarray, -) -> Tuple[np.ndarray, float]: - """ - Internal routine to compute residues and polynomial coefficients. - - Parameters - ---------- - num_poles : int - Number of poles. - poles : np.ndarray - Current poles (complex), shape (num_poles,). - num_samples : int - Number of frequency samples. - num_polys : int - Number of polynomial terms. - eval_points : np.ndarray - Real frequency values, shape (num_samples,). - num_vectors : int - Number of response vectors. - weights : np.ndarray - Weighting matrix, shape (num_vectors, num_samples). - response_matrix : np.ndarray - Complex frequency responses, shape (num_vectors, num_samples). - poly_coefficients : np.ndarray - Array to store output polynomial coefficients (in-place). - residue_matrix : np.ndarray - Array to store output residues (in-place). - - Returns - ------- - Tuple[np.ndarray, float] - - Fitted response matrix (np.ndarray) - - Root-mean-square fitting error (float) - """ - conj_index = label_conjugate_poles(poles) - dk_matrix = np.zeros((num_samples, num_poles + num_polys), dtype=np.complex128) - - compute_dk_matrix(dk_matrix, eval_points, poles, conj_index, num_poles, num_polys) - - real_residues = np.zeros((num_vectors, num_poles), dtype=np.float64) - - for vec_idx in range(num_vectors): - vec_idx, residues, poly_coeffs = solve_vector_block( - vec_idx, - dk_matrix, - weights, - response_matrix, - num_poles, - num_polys, - ) - real_residues[vec_idx] = residues - if poly_coeffs is not None: - poly_coefficients[vec_idx] = poly_coeffs - - # Mask for real poles - mask_real = conj_index == 0 - real_indices = np.where(mask_real)[0] - residue_matrix[:, real_indices] = real_residues[:, real_indices] - - # Mask for first of complex conjugate pairs - mask_cplx_start = conj_index == 1 - cplx_indices = np.where(mask_cplx_start)[0] - - # Compute complex residues using vectorized operations - residue_matrix[:, cplx_indices] = ( - real_residues[:, cplx_indices] + 1j * real_residues[:, cplx_indices + 1] - ) - residue_matrix[:, cplx_indices + 1] = ( - real_residues[:, cplx_indices] - 1j * real_residues[:, cplx_indices + 1] - ) - - fit_result = evaluate(eval_points, poles, residue_matrix, poly_coefficients) - rms_error = norm(fit_result - response_matrix) / np.sqrt(num_vectors * num_samples) - return fit_result, rms_error - - -def label_conjugate_poles(poles: np.ndarray) -> np.ndarray: - """ - Ensure complex poles appear in conjugate pairs and label them accordingly. - - Parameters - ---------- - poles : np.ndarray - 1D array of complex poles. - - Returns - ------- - np.ndarray - Array of integers indicating pole type: - - 0: real pole - - 1: first in a complex-conjugate pair - - 2: second in a complex-conjugate pair - - Raises - ------ - ValueError - If any complex pole does not have a valid conjugate pair. - """ - num_poles = len(poles) - conj_index = np.zeros(num_poles, dtype=int) - - # Identify complex poles (nonzero imaginary part) - is_complex = np.imag(poles) != 0.0 - - # Find conjugate pairs: poles[i+1] ≈ conj(poles[i]) - is_pair_start = is_complex[:-1] & np.isclose(np.conj(poles[:-1]), poles[1:]) - - # Mark valid conjugate pair entries - conj_index[:-1][is_pair_start] = 1 # mark i with 1 - conj_index[1:][is_pair_start] = 2 # mark i+1 with 2 - - # Now validate: all complex poles must be part of valid conjugate pairs - unmatched_complex = is_complex & (conj_index == 0) - if np.any(unmatched_complex): - raise ValueError("Complex poles must appear in conjugate pairs") - - return conj_index diff --git a/openmc/deplete/__init__.py b/openmc/deplete/__init__.py index 052e22459..329ee8b52 100644 --- a/openmc/deplete/__init__.py +++ b/openmc/deplete/__init__.py @@ -16,8 +16,6 @@ from .atom_number import * from .stepresult import * from .results import * from .integrators import * -from .transfer_rates import * -from .r2s import * from . import abc from . import cram from . import helpers diff --git a/openmc/deplete/_matrix_funcs.py b/openmc/deplete/_matrix_funcs.py index c7f7df76f..a606d739f 100644 --- a/openmc/deplete/_matrix_funcs.py +++ b/openmc/deplete/_matrix_funcs.py @@ -77,4 +77,4 @@ def leqi_f4(chain, inputs, fission_yields=None): return (-dt ** 2 / (12 * dt_l * (dt + dt_l)) * f1 + (dt ** 2 + 2 * dt * dt_l + dt_l ** 2) / (12 * dt_l * (dt + dt_l)) * f2 - + (4 * dt + 5 * dt_l) / (12 * (dt + dt_l)) * f3) + + (4 * dt * dt_l + 5 * dt_l ** 2) / (12 * dt_l * (dt + dt_l)) * f3) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 66bd7148d..3e2c37ece 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -1,37 +1,30 @@ """abc module. -This module contains Abstract Base Classes for implementing operator, -integrator, depletion system solver, and operator helper classes +This module contains Abstract Base Classes for implementing operator, integrator, depletion system solver, and operator helper classes """ -from __future__ import annotations from abc import ABC, abstractmethod from collections import namedtuple, defaultdict from collections.abc import Iterable, Callable from copy import deepcopy from inspect import signature from numbers import Real, Integral +from contextlib import contextmanager +import os from pathlib import Path -from textwrap import dedent +import sys import time -from typing import Optional, Union, Sequence from warnings import warn -import numpy as np +from numpy import nonzero, empty, asarray from uncertainties import ufloat -from openmc.checkvalue import check_type, check_greater_than, PathLike +from openmc.checkvalue import check_type, check_greater_than from openmc.mpi import comm -from openmc.utility_funcs import change_directory -from openmc import Material from .stepresult import StepResult -from .chain import _get_chain -from .results import Results, _SECONDS_PER_MINUTE, _SECONDS_PER_HOUR, \ - _SECONDS_PER_DAY, _SECONDS_PER_JULIAN_YEAR +from .chain import Chain +from .results import Results from .pool import deplete -from .reaction_rates import ReactionRates -from .transfer_rates import TransferRates, ExternalSourceRates -from .keff_search_control import _KeffSearchControl __all__ = [ @@ -40,61 +33,9 @@ __all__ = [ "Integrator", "SIIntegrator", "DepSystemSolver", "add_params"] -def _normalize_timesteps( - timesteps: Sequence[float] | Sequence[tuple[float, str]], - source_rates: float | Sequence[float], - timestep_units: str = 's', - operator: TransportOperator | None = None, -): - if not isinstance(source_rates, Sequence): - # Ensure that rate is single value if that is the case - source_rates = [source_rates] * len(timesteps) - - if len(source_rates) != len(timesteps): - raise ValueError( - "Number of time steps ({}) != number of powers ({})".format( - len(timesteps), len(source_rates))) - - # Get list of times / units - if isinstance(timesteps[0], Sequence): - times, units = zip(*timesteps) - else: - times = timesteps - units = [timestep_units] * len(timesteps) - - # Determine number of seconds for each timestep - seconds = [] - for timestep, unit, rate in zip(times, units, source_rates): - # Make sure values passed make sense - check_type('timestep', timestep, Real) - check_greater_than('timestep', timestep, 0.0, False) - check_type('timestep units', unit, str) - check_type('source rate', rate, Real) - check_greater_than('source rate', rate, 0.0, True) - - if unit in ('s', 'sec'): - seconds.append(timestep) - elif unit in ('min', 'minute'): - seconds.append(timestep*_SECONDS_PER_MINUTE) - elif unit in ('h', 'hr', 'hour'): - seconds.append(timestep*_SECONDS_PER_HOUR) - elif unit in ('d', 'day'): - seconds.append(timestep*_SECONDS_PER_DAY) - elif unit in ('a', 'year'): - seconds.append(timestep*_SECONDS_PER_JULIAN_YEAR) - elif unit.lower() == 'mwd/kg': - watt_days_per_kg = 1e6*timestep - kilograms = 1e-3*operator.heavy_metal - if rate == 0.0: - raise ValueError("Cannot specify a timestep in [MWd/kg] when" - " the power is zero.") - days = watt_days_per_kg * kilograms / rate - seconds.append(days*_SECONDS_PER_DAY) - else: - raise ValueError(f"Invalid timestep unit '{unit}'") - - return (np.asarray(seconds), np.asarray(source_rates)) - +_SECONDS_PER_MINUTE = 60 +_SECONDS_PER_HOUR = 60*60 +_SECONDS_PER_DAY = 24*60*60 OperatorResult = namedtuple('OperatorResult', ['k', 'rates']) OperatorResult.__doc__ = """\ @@ -115,6 +56,24 @@ except AttributeError: # Can't set __doc__ on properties on Python 3.4 pass +@contextmanager +def change_directory(output_dir): + """ + Helper function for managing the current directory. + + Parameters + ---------- + output_dir : pathlib.Path + Directory to switch to. + """ + orig_dir = os.getcwd() + try: + output_dir.mkdir(exist_ok=True) + os.chdir(output_dir) + yield + finally: + os.chdir(orig_dir) + class TransportOperator(ABC): """Abstract class defining a transport operator @@ -128,16 +87,25 @@ class TransportOperator(ABC): Parameters ---------- - chain_file : PathLike or Chain - Path to the depletion chain XML file or instance of openmc.deplete.Chain. + chain_file : str + Path to the depletion chain XML file fission_q : dict, optional Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. + dilute_initial : float, optional + Initial atom density [atoms/cm^3] to add for nuclides that are zero + in initial condition to ensure they exist in the decay chain. + Only done for nuclides with reaction rates. + Defaults to 1.0e3. prev_results : Results, optional Results from a previous depletion calculation. Attributes ---------- + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that are zero + in initial condition to ensure they exist in the decay chain. + Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. prev_res : Results or None @@ -147,20 +115,32 @@ class TransportOperator(ABC): The depletion chain information necessary to form matrices and tallies. """ - def __init__(self, chain_file=None, fission_q=None, prev_results=None): + def __init__(self, chain_file, fission_q=None, dilute_initial=1.0e3, + prev_results=None): + self.dilute_initial = dilute_initial self.output_dir = '.' # Read depletion chain - self.chain = _get_chain(chain_file, fission_q) - + self.chain = Chain.from_xml(chain_file, fission_q) if prev_results is None: self.prev_res = None else: check_type("previous results", prev_results, Results) self.prev_res = prev_results + @property + def dilute_initial(self): + """Initial atom density for nuclides with zero initial concentration""" + return self._dilute_initial + + @dilute_initial.setter + def dilute_initial(self, value): + check_type("dilute_initial", value, Real) + check_greater_than("dilute_initial", value, 0.0, equality=True) + self._dilute_initial = value + @abstractmethod - def __call__(self, vec, source_rate) -> OperatorResult: + def __call__(self, vec, source_rate): """Runs a simulation. Parameters @@ -202,7 +182,7 @@ class TransportOperator(ABC): Returns ------- volume : dict of str to float - Volumes corresponding to materials in full_burn_list + Volumes corresponding to materials in burn_list nuc_list : list of str A list of all nuclide names. Used for sorting the simulation. burn_list : list of int @@ -210,15 +190,13 @@ class TransportOperator(ABC): simulation. full_burn_list : list of int All burnable materials in the geometry. - name_list : list of str - Material names corresponding to materials in full_burn_list """ def finalize(self): pass @abstractmethod - def write_bos_data(self, step: int): + def write_bos_data(self, step): """Document beginning of step data for a given step Called at the beginning of a depletion step and at @@ -257,7 +235,7 @@ class ReactionRateHelper(ABC): def __init__(self, n_nucs, n_react): self._nuclides = None - self._results_cache = np.empty((n_nucs, n_react)) + self._results_cache = empty((n_nucs, n_react)) @abstractmethod def generate_tallies(self, materials, scores): @@ -274,12 +252,7 @@ class ReactionRateHelper(ABC): self._nuclides = nuclides @abstractmethod - def get_material_rates( - self, - mat_id: int, - nuc_index: Sequence[str], - react_index: Sequence[str] - ): + def get_material_rates(self, mat_id, nuc_index, react_index): """Return 2D array of [nuclide, reaction] reaction rates Parameters @@ -292,15 +265,16 @@ class ReactionRateHelper(ABC): Ordering of reactions """ - def divide_by_atoms(self, number: Sequence[float]): - """Normalize reaction rates by number of atoms + def divide_by_adens(self, number): + """Normalize reaction rates by number of nuclides Acts on the current material examined by :meth:`get_material_rates` Parameters ---------- number : iterable of float - Number of each nuclide in [atom] tracked in the calculation. + Number density [atoms/b-cm] of each nuclide tracked in the + calculation. Returns ------- @@ -309,7 +283,7 @@ class ReactionRateHelper(ABC): normalized by the number of nuclides """ - mask = np.nonzero(number) + mask = nonzero(number) results = self._results_cache for col in range(results.shape[1]): results[mask, col] /= number[mask] @@ -341,7 +315,7 @@ class NormalizationHelper(ABC): """Reset state for normalization""" @abstractmethod - def prepare(self, chain_nucs: Sequence[str], rate_index: dict): + def prepare(self, chain_nucs, rate_index): """Perform work needed to obtain energy produced This method is called prior to calculating the reaction rates @@ -380,7 +354,7 @@ class NormalizationHelper(ABC): self._nuclides = nuclides @abstractmethod - def factor(self, source_rate: float): + def factor(self, source_rate): """Return normalization factor Parameters @@ -483,7 +457,7 @@ class FissionYieldHelper(ABC): in parallel mode. """ - def update_tally_nuclides(self, nuclides: Sequence[str]) -> list: + def update_tally_nuclides(self, nuclides): """Return nuclides with non-zero densities and yield data Parameters @@ -530,7 +504,7 @@ class Integrator(ABC): r"""Abstract class for solving the time-integration for depletion """ - _params = dedent(r""" + _params = r""" Parameters ---------- operator : openmc.deplete.abc.TransportOperator @@ -541,28 +515,30 @@ class Integrator(ABC): iterable of float. Alternatively, units can be specified for each step by passing an iterable of (value, unit) tuples. power : float or iterable of float, optional - Power of the reactor in [W]. A single value indicates that the power is - constant over all timesteps. An iterable indicates potentially different - power levels for each timestep. For a 2D problem, the power can be given - in [W/cm] as long as the "volume" assigned to a depletion material is - actually an area in [cm^2]. Either ``power``, ``power_density``, or + Power of the reactor in [W]. A single value indicates that + the power is constant over all timesteps. An iterable + indicates potentially different power levels for each timestep. + For a 2D problem, the power can be given in [W/cm] as long + as the "volume" assigned to a depletion material is actually + an area in [cm^2]. Either ``power``, ``power_density``, or ``source_rates`` must be specified. power_density : float or iterable of float, optional - Power density of the reactor in [W/gHM]. It is multiplied by initial - heavy metal inventory to get total power if ``power`` is not specified. + Power density of the reactor in [W/gHM]. It is multiplied by + initial heavy metal inventory to get total power if ``power`` + is not specified. source_rates : float or iterable of float, optional Source rate in [neutron/sec] or neutron flux in [neutron/s-cm^2] for each interval in :attr:`timesteps` .. versionadded:: 0.12.1 - timestep_units : {'s', 'min', 'h', 'd', 'a', 'MWd/kg'} + timestep_units : {'s', 'min', 'h', 'd', 'MWd/kg'} Units for values specified in the `timesteps` argument. 's' means - seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years - and 'MWd/kg' indicates that the values are given in burnup (MW-d of - energy deposited per kilogram of initial heavy metal). + seconds, 'min' means minutes, 'h' means hours, and 'MWd/kg' indicates + that the values are given in burnup (MW-d of energy deposited per + kilogram of initial heavy metal). solver : str or callable, optional - If a string, must be the name of the solver responsible for solving the - Bateman equations. Current options are: + If a string, must be the name of the solver responsible for + solving the Bateman equations. Current options are: * ``cram16`` - 16th order IPF CRAM * ``cram48`` - 48th order IPF CRAM [default] @@ -571,24 +547,6 @@ class Integrator(ABC): :attr:`solver`. .. versionadded:: 0.12 - substeps : int, optional - Number of substeps per depletion interval. When greater than 1, each - interval is subdivided into `substeps` identical sub-intervals and LU - factorizations may be reused across them, improving accuracy for - nuclides with large decay-constant × timestep products. - - .. versionadded:: 0.15.4 - continue_timesteps : bool, optional - Whether or not to treat the current solve as a continuation of a - previous simulation. Defaults to `False`. When `False`, the depletion - steps provided are appended to any previous steps. If `True`, the - timesteps provided to the `Integrator` must exacly match any that exist - in the `prev_results` passed to the `Operator`. The `power`, - `power_density`, or `source_rates` must match as well. The method of - specifying `power`, `power_density`, or `source_rates` should be the - same as the initial run. - - .. versionadded:: 0.15.1 Attributes ---------- @@ -606,46 +564,32 @@ class Integrator(ABC): :math:`\frac{\partial}{\partial t}\vec{n} = A_i\vec{n}_i` with a step size :math:`t_i`. Can be configured using the ``solver`` argument. User-supplied functions are expected to have the following signature: - ``solver(A, n0, t, substeps=1) -> n1``, where + ``solver(A, n0, t) -> n1`` where - * ``A`` is a :class:`scipy.sparse.csc_array` making up the depletion - matrix - * ``n0`` is a 1-D :class:`numpy.ndarray` of initial compositions for - a given material in atoms/cm3 - * ``t`` is a float of the time step size in seconds - * ``substeps`` is an optional integer number of substeps, and - * ``n1`` is a :class:`numpy.ndarray` of compositions at the next - time step. Expected to be of the same shape as ``n0`` + * ``A`` is a :class:`scipy.sparse.csr_matrix` making up the + depletion matrix + * ``n0`` is a 1-D :class:`numpy.ndarray` of initial compositions + for a given material in atoms/cm3 + * ``t`` is a float of the time step size in seconds, and + * ``n1`` is a :class:`numpy.ndarray` of compositions at the + next time step. Expected to be of the same shape as ``n0`` - Solvers that do not support multiple substeps should raise an exception - when ``substeps > 1``. + .. versionadded:: 0.12 - transfer_rates : openmc.deplete.TransferRates - Transfer rates for the depletion system used to model continuous - removal/feed between materials. + """ - .. versionadded:: 0.14.0 - external_source_rates : openmc.deplete.ExternalSourceRates - External source rates for the depletion system. - - .. versionadded:: 0.15.3 - - """) - - def __init__( - self, - operator: TransportOperator, - timesteps: Sequence[float] | Sequence[tuple[float, str]], - power: Optional[Union[float, Sequence[float]]] = None, - power_density: Optional[Union[float, Sequence[float]]] = None, - source_rates: Optional[Union[float, Sequence[float]]] = None, - timestep_units: str = 's', - solver: str = "cram48", - substeps: int = 1, - continue_timesteps: bool = False, - ): - if continue_timesteps and operator.prev_res is None: - raise ValueError("Continuation run requires passing prev_results.") + def __init__(self, operator, timesteps, power=None, power_density=None, + source_rates=None, timestep_units='s', solver="cram48"): + # Check number of stages previously used + if operator.prev_res is not None: + res = operator.prev_res[-1] + if res.data.shape[0] != self._num_stages: + raise ValueError( + "{} incompatible with previous restart calculation. " + "Previous scheme used {} intermediate solutions, while " + "this uses {}".format( + self.__class__.__name__, res.data.shape[0], + self._num_stages)) self.operator = operator self.chain = operator.chain @@ -660,47 +604,53 @@ class Integrator(ABC): elif source_rates is None: raise ValueError("Either power, power_density, or source_rates must be set") - # Normalize timesteps and source rates - seconds, source_rates = _normalize_timesteps( - timesteps, source_rates, timestep_units, operator) - check_type("substeps", substeps, Integral) - check_greater_than("substeps", substeps, 0) + if not isinstance(source_rates, Iterable): + # Ensure that rate is single value if that is the case + source_rates = [source_rates] * len(timesteps) - if continue_timesteps: - # Get timesteps and source rates from previous results - prev_times = operator.prev_res.get_times(timestep_units) - prev_source_rates = operator.prev_res.get_source_rates() - prev_timesteps = np.diff(prev_times) + if len(source_rates) != len(timesteps): + raise ValueError( + "Number of time steps ({}) != number of powers ({})".format( + len(timesteps), len(source_rates))) - # Make sure parameters from the previous results are consistent with - # those passed to operator - num_prev = len(prev_timesteps) - if not np.array_equal(prev_timesteps, timesteps[:num_prev]): - raise ValueError( - "You are attempting to continue a run in which the previous timesteps " - "do not have the same initial timesteps as those provided to the " - "Integrator. Please make sure you are using the correct timesteps." - ) - if not np.array_equal(prev_source_rates, source_rates[:num_prev]): - raise ValueError( - "You are attempting to continue a run in which the previous results " - "do not have the same initial source rates, powers, or power densities " - "as those provided to the Integrator. Please make sure you are using " - "the correct powers, power densities, or source rates and previous " - "results file." - ) + # Get list of times / units + if isinstance(timesteps[0], Iterable): + times, units = zip(*timesteps) + else: + times = timesteps + units = [timestep_units] * len(timesteps) - # Run with only the new time steps and source rates provided - seconds = seconds[num_prev:] - source_rates = source_rates[num_prev:] + # Determine number of seconds for each timestep + seconds = [] + for timestep, unit, rate in zip(times, units, source_rates): + # Make sure values passed make sense + check_type('timestep', timestep, Real) + check_greater_than('timestep', timestep, 0.0, False) + check_type('timestep units', unit, str) + check_type('source rate', rate, Real) + check_greater_than('source rate', rate, 0.0, True) - self.timesteps = np.asarray(seconds) - self.source_rates = np.asarray(source_rates) - self.substeps = substeps + if unit in ('s', 'sec'): + seconds.append(timestep) + elif unit in ('min', 'minute'): + seconds.append(timestep*_SECONDS_PER_MINUTE) + elif unit in ('h', 'hr', 'hour'): + seconds.append(timestep*_SECONDS_PER_HOUR) + elif unit in ('d', 'day'): + seconds.append(timestep*_SECONDS_PER_DAY) + elif unit.lower() == 'mwd/kg': + watt_days_per_kg = 1e6*timestep + kilograms = 1e-3*operator.heavy_metal + if rate == 0.0: + raise ValueError("Cannot specify a timestep in [MWd/kg] when" + " the power is zero.") + days = watt_days_per_kg * kilograms / rate + seconds.append(days*_SECONDS_PER_DAY) + else: + raise ValueError("Invalid timestep unit '{}'".format(unit)) - self.transfer_rates = None - self.external_source_rates = None - self._keff_search_control = None + self.timesteps = asarray(seconds) + self.source_rates = asarray(source_rates) if isinstance(solver, str): # Delay importing of cram module, which requires this file @@ -712,7 +662,8 @@ class Integrator(ABC): self._solver = CRAM16 else: raise ValueError( - f"Solver {solver} not understood. Expected 'cram48' or 'cram16'") + "Solver {} not understood. Expected 'cram48' or " + "'cram16'".format(solver)) else: self.solver = solver @@ -724,65 +675,44 @@ class Integrator(ABC): def solver(self, func): if not isinstance(func, Callable): raise TypeError( - f"Solver must be callable, not {type(func)}") + "Solver must be callable, not {}".format(type(func))) try: sig = signature(func) except ValueError: # Guard against callables that aren't introspectable, e.g. # fortran functions wrapped by F2PY - warn(f"Could not determine arguments to {func}. Proceeding anyways") + warn("Could not determine arguments to {}. Proceeding " + "anyways".format(func)) self._solver = func return - params = list(sig.parameters.values()) - # Inspect arguments - if len(params) != 4: - raise ValueError( - "Function {} must support four arguments " - "(A, n0, t, substeps=1): {!s}" - .format(func, sig)) + if len(sig.parameters) != 3: + raise ValueError("Function {} does not support three arguments: " + "{!s}".format(func, sig)) - for ix, param in enumerate(params): - if param.kind in {param.KEYWORD_ONLY, param.VAR_KEYWORD, - param.VAR_POSITIONAL}: + for ix, param in enumerate(sig.parameters.values()): + if param.kind in {param.KEYWORD_ONLY, param.VAR_KEYWORD}: raise ValueError( - f"Keyword arguments like {ix} at position {param} are not allowed") - - if len(params) == 4 and params[3].default != 1: - raise ValueError( - f"Fourth solver argument must default to 1, not {params[3].default}") + "Keyword arguments like {} at position {} are not " + "allowed".format(ix, param)) self._solver = func - def _timed_deplete(self, n, rates, dt, i=None, matrix_func=None): + def _timed_deplete(self, concs, rates, dt, matrix_func=None): start = time.time() results = deplete( - self._solver, self.chain, n, rates, dt, i, matrix_func, - self.transfer_rates, self.external_source_rates, self.substeps) - - # Clip unphysical negative number densities - for r in results: - r.clip(min=0.0, out=r) - + self._solver, self.chain, concs, rates, dt, matrix_func) return time.time() - start, results @abstractmethod - def __call__( - self, - n: Sequence[np.ndarray], - rates: ReactionRates, - dt: float, - source_rate: float, - i: int - ): + def __call__(self, conc, rates, dt, source_rate, i): """Perform the integration across one time step Parameters ---------- - n : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -796,8 +726,12 @@ class Integrator(ABC): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of timestep + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult + Eigenvalue and reaction rates from intermediate transport + simulations """ @property @@ -824,88 +758,25 @@ class Integrator(ABC): self.operator.write_bos_data(step_index + self._i_res) return x, res - def _get_bos_data_from_restart(self, source_rate, bos_conc): + def _get_bos_data_from_restart(self, step_index, source_rate, bos_conc): """Get beginning of step concentrations, reaction rates from restart""" res = self.operator.prev_res[-1] # Depletion methods expect list of arrays - bos_conc = list(res.data) - rates = res.rates - k = ufloat(res.k[0], res.k[1]) + bos_conc = list(res.data[0]) + rates = res.rates[0] + k = ufloat(res.k[0, 0], res.k[0, 1]) - if res.source_rate != 0.0: - # Scale reaction rates by ratio of source rates - rates *= source_rate / res.source_rate + # Scale reaction rates by ratio of source rates + rates *= source_rate / res.source_rate return bos_conc, OperatorResult(k, rates) - def _get_start_data(self) -> tuple[float, int]: - """ - This function fetches the starting state of a depletion simulation in - terms of the simulation physical time at which to start and the index at - which the depletion simulation should start. When no previous results - exist, the time and index are both zero. When previous results do exist, - it returns the time corresponding to beginning the previous results last - timestep and the index as N-1 where N is the number of previous - StepResults found in the previous Results (as expected from 0-based - indexing). - - Note that the openmc.deplete.Results.time object is a list of float with - [t,t+dt] where t is the beginning of timestep time and t+dt is the end - of timestep time. If the previous results correspond to a simulation - that finished to completeion, it will contain a results in the form of - [t,t], but if a simulation doesn't finish all the given timesteps, it is - the t that is the desired start time, not t+dt. Thus, it is always safe - to take time[0]. - - Returns - ------- - start_time : float - Time at which depletion simulation should start in [s] - index : int - Index at which depletion simulation should start - """ + def _get_start_data(self): if self.operator.prev_res is None: return 0.0, 0 - return (self.operator.prev_res[-1].time[0], + return (self.operator.prev_res[-1].time[-1], len(self.operator.prev_res) - 1) - def _restore_keff_search_control(self, res: StepResult): - """Restore keff search control from restart results.""" - keff_search_root = res.keff_search_root - if keff_search_root is None: - raise ValueError( - "Cannot restore keff search control from restart " - "results because no stored keff_search_root is " - "available." - ) - self._keff_search_control.function(keff_search_root) - return keff_search_root - - def _get_bos_data(self, step_index, source_rate, bos_conc): - """Get beginning-of-step concentrations, rates, and control state.""" - if step_index > 0 or self.operator.prev_res is None: - if self._keff_search_control is not None and source_rate != 0.0: - keff_search_root = self._keff_search_control.run(bos_conc) - else: - keff_search_root = None - bos_conc, res = self._get_bos_data_from_operator( - step_index, source_rate, bos_conc) - else: - bos_conc, res = self._get_bos_data_from_restart( - source_rate, bos_conc) - if self._keff_search_control is not None and source_rate != 0.0: - keff_search_root = self._restore_keff_search_control(self.operator.prev_res[-1]) - else: - keff_search_root = None - - return bos_conc, res, keff_search_root - - def integrate( - self, - final_step: bool = True, - output: bool = True, - path: PathLike = 'depletion_results.h5', - write_rates: bool = False - ): + def integrate(self, final_step=True, output=True): """Perform the entire depletion process across all steps Parameters @@ -919,294 +790,49 @@ class Integrator(ABC): Indicate whether to display information about progress .. versionadded:: 0.13.1 - path : PathLike - Path to file to write. Defaults to 'depletion_results.h5'. - - .. versionadded:: 0.15.0 - write_rates : bool, optional - Whether reaction rates should be written to the results file for - each step. Defaults to ``False`` to reduce file size. - - .. versionadded:: 0.15.3 """ with change_directory(self.operator.output_dir): - n = self.operator.initial_condition() + conc = self.operator.initial_condition() t, self._i_res = self._get_start_data() for i, (dt, source_rate) in enumerate(self): - if output and comm.rank == 0: + if output: print(f"[openmc.deplete] t={t} s, dt={dt} s, source={source_rate}") - # Get beginning-of-step data from operator or restart results - n, res, keff_search_root = self._get_bos_data(i, source_rate, n) + # Solve transport equation (or obtain result from restart) + if i > 0 or self.operator.prev_res is None: + conc, res = self._get_bos_data_from_operator(i, source_rate, conc) + else: + conc, res = self._get_bos_data_from_restart(i, source_rate, conc) # Solve Bateman equations over time interval - proc_time, n_end = self(n, res.rates, dt, source_rate, i) + proc_time, conc_list, res_list = self(conc, res.rates, dt, source_rate, i) - StepResult.save( - self.operator, - n, - res, - [t, t + dt], - source_rate, - self._i_res + i, - proc_time, - write_rates=write_rates, - keff_search_root=keff_search_root, - path=path - ) + # Insert BOS concentration, transport results + conc_list.insert(0, conc) + res_list.insert(0, res) + + # Remove actual EOS concentration for next step + conc = conc_list.pop() + + StepResult.save(self.operator, conc_list, res_list, [t, t + dt], + source_rate, self._i_res + i, proc_time) - # Update for next step - n = n_end t += dt # Final simulation -- in the case that final_step is False, a zero # source rate is passed to the transport operator (which knows to # just return zero reaction rates without actually doing a transport # solve) - if output and final_step and comm.rank == 0: + if output and final_step: print(f"[openmc.deplete] t={t} (final operator evaluation)") - if self._keff_search_control is not None and source_rate != 0.0: - keff_search_root = self._keff_search_control.run(n) - else: - keff_search_root = None - res_final = self.operator(n, source_rate if final_step else 0.0) - StepResult.save( - self.operator, - n, - res_final, - [t, t], - source_rate, - self._i_res + len(self), - proc_time, - write_rates=write_rates, - keff_search_root=keff_search_root, - path=path - ) + res_list = [self.operator(conc, source_rate if final_step else 0.0)] + StepResult.save(self.operator, [conc], res_list, [t, t], + source_rate, self._i_res + len(self), proc_time) self.operator.write_bos_data(len(self) + self._i_res) self.operator.finalize() - def add_transfer_rate( - self, - material: str | int | Material, - components: Sequence[str], - transfer_rate: float, - transfer_rate_units: str = '1/s', - timesteps: Sequence[int] | None = None, - destination_material: str | int | Material | None = None - ): - """Add transfer rates to depletable material. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - components : list of str - List of strings of elements and/or nuclides that share transfer rate. - A transfer rate for a nuclide cannot be added to a material - alongside a transfer rate for its element and vice versa. - transfer_rate : float - Rate at which elements are transferred. A positive or negative values - set removal of feed rates, respectively. - transfer_rate_units : {'1/s', '1/min', '1/h', '1/d', '1/a'} - Units for values specified in the transfer_rate argument. 's' means - seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years. - timesteps : list of int, optional - List of timestep indices where to set external source rates. - Defaults to None, which means the external source rate is set for - all timesteps. - destination_material : openmc.Material or str or int, Optional - Destination material to where nuclides get fed. - - """ - if self.transfer_rates is None: - if hasattr(self.operator, 'model'): - materials = self.operator.model.materials - elif hasattr(self.operator, 'materials'): - materials = self.operator.materials - self.transfer_rates = TransferRates( - self.operator, materials, len(self.timesteps)) - - if self.external_source_rates is not None and destination_material: - raise ValueError('Currently is not possible to set a transfer rate ' - 'with destination matrial in combination with ' - 'external source rates.') - - self.transfer_rates.set_transfer_rate( - material, components, transfer_rate, transfer_rate_units, - timesteps, destination_material) - - def add_external_source_rate( - self, - material: str | int | Material, - composition: dict[str, float], - rate: float, - rate_units: str = 'g/s', - timesteps: Sequence[int] | None = None - ): - """Add external source rates to depletable material. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - composition : dict of str to float - External source rate composition vector, where key can be an element - or a nuclide and value the corresponding weight percent. - rate : float - External source rate in units of mass per time. A positive or - negative value corresponds to a feed or removal rate, respectively. - units : {'g/s', 'g/min', 'g/h', 'g/d', 'g/a'} - Units for values specified in the `rate` argument. 's' for seconds, - 'min' for minutes, 'h' for hours, 'a' for Julian years. - timesteps : list of int, optional - List of timestep indices where to set external source rates. - Defaults to None, which means the external source rate is set for - all timesteps. - - """ - if self.external_source_rates is None: - if hasattr(self.operator, 'model'): - materials = self.operator.model.materials - elif hasattr(self.operator, 'materials'): - materials = self.operator.materials - self.external_source_rates = ExternalSourceRates( - self.operator, materials, len(self.timesteps)) - - if self.transfer_rates is not None and self.transfer_rates.index_transfer: - raise ValueError('Currently is not possible to set an external ' - 'source rate in combination with transfer rates ' - 'with destination matrial.') - - self.external_source_rates.set_external_source_rate( - material, composition, rate, rate_units, timesteps) - - - def add_redox(self, material, buffer, oxidation_states, timesteps=None): - """Add redox control to depletable material. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - buffer : dict - Dictionary of buffer nuclides used to maintain redox balance. Keys - are nuclide names (strings) and values are their respective - fractions (float) that collectively sum to 1. - oxidation_states : dict - User-defined oxidation states for elements. Keys are element symbols - (e.g., 'H', 'He'), and values are their corresponding oxidation - states as integers (e.g., +1, 0). - timesteps : list of int, optional - List of timestep indices where to set external source rates. - Defaults to None, which means the external source rate is set for - all timesteps. - """ - if self.transfer_rates is None: - if hasattr(self.operator, 'model'): - materials = self.operator.model.materials - elif hasattr(self.operator, 'materials'): - materials = self.operator.materials - self.transfer_rates = TransferRates( - self.operator, materials, len(self.timesteps)) - - self.transfer_rates.set_redox(material, buffer, oxidation_states, timesteps) - - def add_keff_search_control( - self, - function: Callable, - x0: float, - x1: float, - bracket: Sequence[float], - **search_kwargs - ): - """Add keff search to the integrator scheme. - - This method causes OpenMC to perform a keff search during depletion to - maintain a target keff by adjusting a model parameter through the - provided function. - - .. important:: - The function **must** modify the model through ``openmc.lib`` (e.g., - ``openmc.lib.cells``, ``openmc.lib.materials``) and **NOT** through - ``openmc.Model``. The function is called within a - :class:`openmc.lib.TemporarySession` context where only the C API - (``openmc.lib``) is available for modifications. - - Parameters - ---------- - function : Callable - Function that takes a single float argument and modifies the model - through :mod:`openmc.lib`. - x0 : float - Initial lower bound for the keff search. - x1 : float - Initial upper bound for the keff search. - bracket : sequence of float - Bracket interval [x_min, x_max] that constrains the allowed parameter - values during the keff search. This is a required parameter - that defines the absolute bounds for the search. The bracket must contain - exactly 2 elements with bracket[0] < bracket[1]. These values are passed - directly to the ``x_min`` and ``x_max`` optional arguments in - :meth:`openmc.Model.keff_search`, which enforce hard limits on the - parameter range. If the keff search converges to a value outside this - bracket, it will be clamped to the nearest bracket bound with a warning. - **search_kwargs - Additional keyword arguments passed to - :meth:`openmc.Model.keff_search`. Common options include: - - * ``target`` : float, optional - Target keff value to search for. Defaults to 1.0. - * ``k_tol`` : float, optional - Stopping criterion on the function value. Defaults to 1e-4. - * ``sigma_final`` : float, optional - Maximum accepted k-effective uncertainty. Defaults to 3e-4. - * ``maxiter`` : int, optional - Maximum number of iterations. Defaults to 50. - - See :meth:`openmc.Model.keff_search` for a complete list of - available options. - - Examples - -------- - Add keff search that adjusts a control rod position: - - >>> def adjust_rod_position(position): - ... openmc.lib.cells[rod_cell.id].translation = [0, 0, position] - >>> integrator.add_keff_search_control( - ... adjust_rod_position, - ... x0=0.0, - ... x1=5.0, - ... bracket=[-10,10], - ... target=1.0, - ... k_tol=1e-4 - ... ) - - Add keff search that adjusts the U235 density: - - >>> def set_u235_density(u235_density): - ... # Get the material from openmc.lib - ... lib_mat = openmc.lib.materials[material_id] - ... # Get current nuclides and densities - ... nuclides = lib_mat.nuclides - ... densities = lib_mat.densities - ... u235_idx = nuclides.index('U235') - ... densities[u235_idx] = u235_density - ... lib_mat.set_densities(nuclides, densities) - >>> integrator.add_keff_search_control( - ... set_u235_density, - ... x0=5.0e-4, - ... x1=1.0e-3, - ... bracket=[1.0e-4, 2.0e-3], - ... target=1.0 - ... ) - - .. versionadded:: 0.15.4 - - """ - self._keff_search_control = _KeffSearchControl( - self.operator, function, x0, x1, bracket, **search_kwargs) @add_params class SIIntegrator(Integrator): @@ -1216,7 +842,7 @@ class SIIntegrator(Integrator): the number of particles used in initial transport calculation """ - _params = dedent(r""" + _params = r""" Parameters ---------- operator : openmc.deplete.abc.TransportOperator @@ -1227,15 +853,17 @@ class SIIntegrator(Integrator): iterable of float. Alternatively, units can be specified for each step by passing an iterable of (value, unit) tuples. power : float or iterable of float, optional - Power of the reactor in [W]. A single value indicates that the power is - constant over all timesteps. An iterable indicates potentially different - power levels for each timestep. For a 2D problem, the power can be given - in [W/cm] as long as the "volume" assigned to a depletion material is - actually an area in [cm^2]. Either ``power``, ``power_density``, or + Power of the reactor in [W]. A single value indicates that + the power is constant over all timesteps. An iterable + indicates potentially different power levels for each timestep. + For a 2D problem, the power can be given in [W/cm] as long + as the "volume" assigned to a depletion material is actually + an area in [cm^2]. Either ``power``, ``power_density``, or ``source_rates`` must be specified. power_density : float or iterable of float, optional - Power density of the reactor in [W/gHM]. It is multiplied by initial - heavy metal inventory to get total power if ``power`` is not specified. + Power density of the reactor in [W/gHM]. It is multiplied by + initial heavy metal inventory to get total power if ``power`` + is not specified. source_rates : float or iterable of float, optional Source rate in [neutron/sec] or neutron flux in [neutron/s-cm^2] for each interval in :attr:`timesteps` @@ -1247,11 +875,11 @@ class SIIntegrator(Integrator): that the values are given in burnup (MW-d of energy deposited per kilogram of initial heavy metal). n_steps : int, optional - Number of stochastic iterations per depletion interval. Must be greater - than zero. Default : 10 + Number of stochastic iterations per depletion interval. + Must be greater than zero. Default : 10 solver : str or callable, optional - If a string, must be the name of the solver responsible for solving the - Bateman equations. Current options are: + If a string, must be the name of the solver responsible for + solving the Bateman equations. Current options are: * ``cram16`` - 16th order IPF CRAM * ``cram48`` - 48th order IPF CRAM [default] @@ -1260,25 +888,6 @@ class SIIntegrator(Integrator): :attr:`solver`. .. versionadded:: 0.12 - substeps : int, optional - Number of substeps per depletion interval. When greater than 1, each - interval is subdivided into `substeps` identical sub-intervals and LU - factorizations may be reused across them, improving accuracy for - nuclides with large decay-constant × timestep products. - - .. versionadded:: 0.15.4 - continue_timesteps : bool, optional - Whether or not to treat the current solve as a continuation of a - previous simulation. Defaults to `False`. If `False`, all time steps and - source rates will be run in an append fashion and will run after - whatever time steps exist, if any. If `True`, the timesteps provided to - the `Integrator` must match exactly those that exist in the - `prev_results` passed to the `Opereator`. The `power`, `power_density`, - or `source_rates` must match as well. The method of specifying `power`, - `power_density`, or `source_rates` should be the same as the initial - run. - - .. versionadded:: 0.15.1 Attributes ---------- @@ -1297,154 +906,86 @@ class SIIntegrator(Integrator): :math:`\frac{\partial}{\partial t}\vec{n} = A_i\vec{n}_i` with a step size :math:`t_i`. Can be configured using the ``solver`` argument. User-supplied functions are expected to have the following signature: - ``solver(A, n0, t, substeps=1) -> n1``, where + ``solver(A, n0, t) -> n1`` where - * ``A`` is a :class:`scipy.sparse.csc_array` making up the depletion - matrix - * ``n0`` is a 1-D :class:`numpy.ndarray` of initial compositions for - a given material in atoms/cm3 - * ``t`` is a float of the time step size in seconds - * ``substeps`` is an optional integer number of substeps, and - * ``n1`` is a :class:`numpy.ndarray` of compositions at the next - time step. Expected to be of the same shape as ``n0`` - - Solvers that do not support multiple substeps should raise an exception - when ``substeps > 1``. + * ``A`` is a :class:`scipy.sparse.csr_matrix` making up the + depletion matrix + * ``n0`` is a 1-D :class:`numpy.ndarray` of initial compositions + for a given material in atoms/cm3 + * ``t`` is a float of the time step size in seconds, and + * ``n1`` is a :class:`numpy.ndarray` of compositions at the + next time step. Expected to be of the same shape as ``n0`` .. versionadded:: 0.12 - """) + """ - def __init__( - self, - operator: TransportOperator, - timesteps: Sequence[float], - power: Optional[Union[float, Sequence[float]]] = None, - power_density: Optional[Union[float, Sequence[float]]] = None, - source_rates: Optional[Sequence[float]] = None, - timestep_units: str = 's', - n_steps: int = 10, - solver: str = "cram48", - substeps: int = 1, - continue_timesteps: bool = False, - ): + def __init__(self, operator, timesteps, power=None, power_density=None, + source_rates=None, timestep_units='s', n_steps=10, + solver="cram48"): check_type("n_steps", n_steps, Integral) check_greater_than("n_steps", n_steps, 0) super().__init__( operator, timesteps, power, power_density, source_rates, - timestep_units=timestep_units, solver=solver, - substeps=substeps, - continue_timesteps=continue_timesteps) + timestep_units=timestep_units, solver=solver) self.n_steps = n_steps - def _get_bos_data_from_operator(self, step_index, step_power, n_bos): + def _get_bos_data_from_operator(self, step_index, step_power, bos_conc): reset_particles = False if step_index == 0 and hasattr(self.operator, "settings"): reset_particles = True self.operator.settings.particles *= self.n_steps inherited = super()._get_bos_data_from_operator( - step_index, step_power, n_bos) + step_index, step_power, bos_conc) if reset_particles: self.operator.settings.particles //= self.n_steps return inherited - @abstractmethod - def __call__(self, n, rates, dt, source_rate, i): - """Perform the integration across one time step - - Parameters - ---------- - n : list of numpy.ndarray - List of atom number arrays for each material. Each array has - shape ``(n_nucs,)`` where ``n_nucs`` is the number of nuclides - rates : openmc.deplete.ReactionRates - Reaction rates (from transport operator) - dt : float - Time step in [s] - source_rate : float - Power in [W] or source rate in [neutron/sec] - i : int - Current time step index - - Returns - ------- - proc_time : float - Time spent in transport simulation - n_end : list of numpy.ndarray - Updated atom number densities for each material - op_result : OperatorResult - Eigenvalue and reaction rates resulting from transport simulation - - """ - - def integrate( - self, - output: bool = True, - path: PathLike = "depletion_results.h5", - write_rates: bool = False - ): + def integrate(self, output=True): """Perform the entire depletion process across all steps Parameters ---------- output : bool, optional Indicate whether to display information about progress - path : PathLike - Path to file to write. Defaults to 'depletion_results.h5'. - .. versionadded:: 0.15.0 - write_rates : bool, optional - Whether reaction rates should be written to the results file for - each step. Defaults to ``False`` to reduce file size. - - .. versionadded:: 0.15.3 + .. versionadded:: 0.13.1 """ with change_directory(self.operator.output_dir): - n = self.operator.initial_condition() + conc = self.operator.initial_condition() t, self._i_res = self._get_start_data() - res_end = None # Will be set in first iteration for i, (dt, p) in enumerate(self): if output: print(f"[openmc.deplete] t={t} s, dt={dt} s, source={p}") if i == 0: if self.operator.prev_res is None: - n, res = self._get_bos_data_from_operator(i, p, n) + conc, res = self._get_bos_data_from_operator(i, p, conc) else: - n, res = self._get_bos_data_from_restart(p, n) + conc, res = self._get_bos_data_from_restart(i, p, conc) + else: + # Pull rates, k from previous iteration w/o + # re-running transport + res = res_list[-1] # defined in previous i iteration - proc_time, n_end, res_end = self(n, res.rates, dt, p, i) + proc_time, conc_list, res_list = self(conc, res.rates, dt, p, i) - StepResult.save( - self.operator, - n, - res, - [t, t + dt], - p, - self._i_res + i, - proc_time, - write_rates=write_rates, - path=path - ) + # Insert BOS concentration, transport results + conc_list.insert(0, conc) + res_list.insert(0, res) + + # Remove actual EOS concentration for next step + conc = conc_list.pop() + + StepResult.save(self.operator, conc_list, res_list, [t, t + dt], + p, self._i_res + i, proc_time) - # Update for next step - n = n_end - res = res_end t += dt # No final simulation for SIE, use last iteration results - StepResult.save( - self.operator, - n, - res_end, - [t, t], - p, - self._i_res + len(self), - proc_time, - write_rates=write_rates, - path=path - ) + StepResult.save(self.operator, [conc], [res_list[-1]], [t, t], + p, self._i_res + len(self), proc_time) self.operator.write_bos_data(self._i_res + len(self)) self.operator.finalize() @@ -1464,12 +1005,12 @@ class DepSystemSolver(ABC): """ @abstractmethod - def __call__(self, A, n0, dt, substeps=1): + def __call__(self, A, n0, dt): """Solve the linear system of equations for depletion Parameters ---------- - A : scipy.sparse.csc_array + A : scipy.sparse.csr_matrix Sparse transmutation matrix ``A[j, i]`` describing rates at which isotope ``i`` transmutes to isotope ``j`` n0 : numpy.ndarray @@ -1477,8 +1018,6 @@ class DepSystemSolver(ABC): material or an atom density dt : float Time [s] of the specific interval to be solved - substeps : int, optional - Number of substeps to use when the solver supports substepping. Returns ------- diff --git a/openmc/deplete/atom_number.py b/openmc/deplete/atom_number.py index b24c048cc..78ceecca6 100644 --- a/openmc/deplete/atom_number.py +++ b/openmc/deplete/atom_number.py @@ -2,6 +2,8 @@ An ndarray to store atom densities with string, integer, or slice indexing. """ +from collections import OrderedDict + import numpy as np from openmc import Material @@ -45,8 +47,8 @@ class AtomNumber: """ def __init__(self, local_mats, nuclides, volume, n_nuc_burn): - self.index_mat = {mat: i for i, mat in enumerate(local_mats)} - self.index_nuc = {nuc: i for i, nuc in enumerate(nuclides)} + self.index_mat = OrderedDict((mat, i) for i, mat in enumerate(local_mats)) + self.index_nuc = OrderedDict((nuc, i) for i, nuc in enumerate(nuclides)) self.volume = np.ones(len(local_mats)) for mat, val in volume.items(): diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index a2ff6dea0..d63bc6bfb 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -7,114 +7,123 @@ loaded from an .xml file and all the nuclides are linked together. from io import StringIO from itertools import chain import math -import numpy as np +import os import re -from collections import defaultdict, namedtuple +from collections import OrderedDict, defaultdict, namedtuple from collections.abc import Mapping, Iterable from numbers import Real, Integral -from pathlib import Path from warnings import warn -from typing import List -import lxml.etree as ET - -from openmc.checkvalue import check_type, check_length, check_greater_than, PathLike -from openmc.data import gnds_name, zam +from openmc.checkvalue import check_type, check_greater_than +from openmc.data import gnd_name, zam, DataLibrary from openmc.exceptions import DataError -from .nuclide import FissionYieldDistribution, Nuclide -from .._xml import get_text -from .._sparse_compat import csc_array, dok_array +from .nuclide import FissionYieldDistribution + +# Try to use lxml if it is available. It preserves the order of attributes and +# provides a pretty-printer by default. If not available, +# use OpenMC function to pretty print. +try: + import lxml.etree as ET + _have_lxml = True +except ImportError: + import xml.etree.ElementTree as ET + _have_lxml = False +import scipy.sparse as sp + import openmc.data +from openmc._xml import clean_indentation +from .nuclide import Nuclide, DecayTuple, ReactionTuple -# tuple of (possible MT values, secondaries) -ReactionInfo = namedtuple('ReactionInfo', ('mts', 'secondaries')) +# tuple of (possible MT values, (dA, dZ), secondaries) where dA is the change in +# the mass number and dZ is the change in the atomic number +ReactionInfo = namedtuple('ReactionInfo', ('mts', 'dadz', 'secondaries')) REACTIONS = { - '(n,2nd)': ReactionInfo({11}, ('H2',)), - '(n,2n)': ReactionInfo(set(chain([16], range(875, 892))), ()), - '(n,3n)': ReactionInfo({17}, ()), - '(n,na)': ReactionInfo({22}, ('He4',)), - '(n,n3a)': ReactionInfo({23}, ('He4', 'He4', 'He4')), - '(n,2na)': ReactionInfo({24}, ('He4',)), - '(n,3na)': ReactionInfo({25}, ('He4',)), - '(n,np)': ReactionInfo({28}, ('H1',)), - '(n,n2a)': ReactionInfo({29}, ('He4', 'He4')), - '(n,2n2a)': ReactionInfo({30}, ('He4', 'He4')), - '(n,nd)': ReactionInfo({32}, ('H2',)), - '(n,nt)': ReactionInfo({33}, ('H3',)), - '(n,n3He)': ReactionInfo({34}, ('He3',)), - '(n,nd2a)': ReactionInfo({35}, ('H2', 'He4', 'He4')), - '(n,nt2a)': ReactionInfo({36}, ('H3', 'He4', 'He4')), - '(n,4n)': ReactionInfo({37}, ()), - '(n,2np)': ReactionInfo({41}, ('H1',)), - '(n,3np)': ReactionInfo({42}, ('H1',)), - '(n,n2p)': ReactionInfo({44}, ('H1', 'H1')), - '(n,npa)': ReactionInfo({45}, ('H1', 'He4')), - '(n,gamma)': ReactionInfo({102}, ()), - '(n,p)': ReactionInfo(set(chain([103], range(600, 650))), ('H1',)), - '(n,d)': ReactionInfo(set(chain([104], range(650, 700))), ('H2',)), - '(n,t)': ReactionInfo(set(chain([105], range(700, 750))), ('H3',)), - '(n,3He)': ReactionInfo(set(chain([106], range(750, 800))), ('He3',)), - '(n,a)': ReactionInfo(set(chain([107], range(800, 850))), ('He4',)), - '(n,2a)': ReactionInfo({108}, ('He4', 'He4')), - '(n,3a)': ReactionInfo({109}, ('He4', 'He4', 'He4')), - '(n,2p)': ReactionInfo({111}, ('H1', 'H1')), - '(n,pa)': ReactionInfo({112}, ('H1', 'He4')), - '(n,t2a)': ReactionInfo({113}, ('H3', 'He4', 'He4')), - '(n,d2a)': ReactionInfo({114}, ('H2', 'He4', 'He4')), - '(n,pd)': ReactionInfo({115}, ('H1', 'H2')), - '(n,pt)': ReactionInfo({116}, ('H1', 'H3')), - '(n,da)': ReactionInfo({117}, ('H2', 'He4')), - '(n,5n)': ReactionInfo({152}, ()), - '(n,6n)': ReactionInfo({153}, ()), - '(n,2nt)': ReactionInfo({154}, ('H3',)), - '(n,ta)': ReactionInfo({155}, ('H3', 'He4')), - '(n,4np)': ReactionInfo({156}, ('H1',)), - '(n,3nd)': ReactionInfo({157}, ('H2',)), - '(n,nda)': ReactionInfo({158}, ('H2', 'He4')), - '(n,2npa)': ReactionInfo({159}, ('H1', 'He4')), - '(n,7n)': ReactionInfo({160}, ()), - '(n,8n)': ReactionInfo({161}, ()), - '(n,5np)': ReactionInfo({162}, ('H1',)), - '(n,6np)': ReactionInfo({163}, ('H1',)), - '(n,7np)': ReactionInfo({164}, ('H1',)), - '(n,4na)': ReactionInfo({165}, ('He4',)), - '(n,5na)': ReactionInfo({166}, ('He4',)), - '(n,6na)': ReactionInfo({167}, ('He4',)), - '(n,7na)': ReactionInfo({168}, ('He4',)), - '(n,4nd)': ReactionInfo({169}, ('H2',)), - '(n,5nd)': ReactionInfo({170}, ('H2',)), - '(n,6nd)': ReactionInfo({171}, ('H2',)), - '(n,3nt)': ReactionInfo({172}, ('H3',)), - '(n,4nt)': ReactionInfo({173}, ('H3',)), - '(n,5nt)': ReactionInfo({174}, ('H3',)), - '(n,6nt)': ReactionInfo({175}, ('H3',)), - '(n,2n3He)': ReactionInfo({176}, ('He3',)), - '(n,3n3He)': ReactionInfo({177}, ('He3',)), - '(n,4n3He)': ReactionInfo({178}, ('He3',)), - '(n,3n2p)': ReactionInfo({179}, ('H1', 'H1')), - '(n,3n2a)': ReactionInfo({180}, ('He4', 'He4')), - '(n,3npa)': ReactionInfo({181}, ('H1', 'He4')), - '(n,dt)': ReactionInfo({182}, ('H2', 'H3')), - '(n,npd)': ReactionInfo({183}, ('H1', 'H2')), - '(n,npt)': ReactionInfo({184}, ('H1', 'H3')), - '(n,ndt)': ReactionInfo({185}, ('H2', 'H3')), - '(n,np3He)': ReactionInfo({186}, ('H1', 'He3')), - '(n,nd3He)': ReactionInfo({187}, ('H2', 'He3')), - '(n,nt3He)': ReactionInfo({188}, ('H3', 'He3')), - '(n,nta)': ReactionInfo({189}, ('H3', 'He4')), - '(n,2n2p)': ReactionInfo({190}, ('H1', 'H1')), - '(n,p3He)': ReactionInfo({191}, ('H1', 'He3')), - '(n,d3He)': ReactionInfo({192}, ('H2', 'He3')), - '(n,3Hea)': ReactionInfo({193}, ('He3', 'He4')), - '(n,4n2p)': ReactionInfo({194}, ('H1', 'H1')), - '(n,4n2a)': ReactionInfo({195}, ('He4', 'He4')), - '(n,4npa)': ReactionInfo({196}, ('H1', 'He4')), - '(n,3p)': ReactionInfo({197}, ('H1', 'H1', 'H1')), - '(n,n3p)': ReactionInfo({198}, ('H1', 'H1', 'H1')), - '(n,3n2pa)': ReactionInfo({199}, ('H1', 'H1', 'He4')), - '(n,5n2p)': ReactionInfo({200}, ('H1', 'H1')), + '(n,2nd)': ReactionInfo({11}, (-3, -1), ('H2',)), + '(n,2n)': ReactionInfo(set(chain([16], range(875, 892))), (-1, 0), ()), + '(n,3n)': ReactionInfo({17}, (-2, 0), ()), + '(n,na)': ReactionInfo({22}, (-4, -2), ('He4',)), + '(n,n3a)': ReactionInfo({23}, (-12, -6), ('He4', 'He4', 'He4')), + '(n,2na)': ReactionInfo({24}, (-5, -2), ('He4',)), + '(n,3na)': ReactionInfo({25}, (-6, -2), ('He4',)), + '(n,np)': ReactionInfo({28}, (-1, -1), ('H1',)), + '(n,n2a)': ReactionInfo({29}, (-8, -4), ('He4', 'He4')), + '(n,2n2a)': ReactionInfo({30}, (-9, -4), ('He4', 'He4')), + '(n,nd)': ReactionInfo({32}, (-2, -1), ('H2',)), + '(n,nt)': ReactionInfo({33}, (-3, -1), ('H3',)), + '(n,n3He)': ReactionInfo({34}, (-3, -2), ('He3',)), + '(n,nd2a)': ReactionInfo({35}, (-10, -5), ('H2', 'He4', 'He4')), + '(n,nt2a)': ReactionInfo({36}, (-11, -5), ('H3', 'He4', 'He4')), + '(n,4n)': ReactionInfo({37}, (-3, 0), ()), + '(n,2np)': ReactionInfo({41}, (-2, -1), ('H1',)), + '(n,3np)': ReactionInfo({42}, (-3, -1), ('H1',)), + '(n,n2p)': ReactionInfo({44}, (-2, -2), ('H1', 'H1')), + '(n,npa)': ReactionInfo({45}, (-5, -3), ('H1', 'He4')), + '(n,gamma)': ReactionInfo({102}, (1, 0), ()), + '(n,p)': ReactionInfo(set(chain([103], range(600, 650))), (0, -1), ('H1',)), + '(n,d)': ReactionInfo(set(chain([104], range(650, 700))), (-1, -1), ('H2',)), + '(n,t)': ReactionInfo(set(chain([105], range(700, 750))), (-2, -1), ('H3',)), + '(n,3He)': ReactionInfo(set(chain([106], range(750, 800))), (-2, -2), ('He3',)), + '(n,a)': ReactionInfo(set(chain([107], range(800, 850))), (-3, -2), ('He4',)), + '(n,2a)': ReactionInfo({108}, (-7, -4), ('He4', 'He4')), + '(n,3a)': ReactionInfo({109}, (-11, -6), ('He4', 'He4', 'He4')), + '(n,2p)': ReactionInfo({111}, (-1, -2), ('H1', 'H1')), + '(n,pa)': ReactionInfo({112}, (-4, -3), ('H1', 'He4')), + '(n,t2a)': ReactionInfo({113}, (-10, -5), ('H3', 'He4', 'He4')), + '(n,d2a)': ReactionInfo({114}, (-9, -5), ('H2', 'He4', 'He4')), + '(n,pd)': ReactionInfo({115}, (-2, -2), ('H1', 'H2')), + '(n,pt)': ReactionInfo({116}, (-3, -2), ('H1', 'H3')), + '(n,da)': ReactionInfo({117}, (-5, -3), ('H2', 'He4')), + '(n,5n)': ReactionInfo({152}, (-4, 0), ()), + '(n,6n)': ReactionInfo({153}, (-5, 0), ()), + '(n,2nt)': ReactionInfo({154}, (-4, -1), ('H3',)), + '(n,ta)': ReactionInfo({155}, (-6, -3), ('H3', 'He4')), + '(n,4np)': ReactionInfo({156}, (-4, -1), ('H1',)), + '(n,3nd)': ReactionInfo({157}, (-4, -1), ('H2',)), + '(n,nda)': ReactionInfo({158}, (-6, -3), ('H2', 'He4')), + '(n,2npa)': ReactionInfo({159}, (-6, -3), ('H1', 'He4')), + '(n,7n)': ReactionInfo({160}, (-6, 0), ()), + '(n,8n)': ReactionInfo({161}, (-7, 0), ()), + '(n,5np)': ReactionInfo({162}, (-5, -1), ('H1',)), + '(n,6np)': ReactionInfo({163}, (-6, -1), ('H1',)), + '(n,7np)': ReactionInfo({164}, (-7, -1), ('H1',)), + '(n,4na)': ReactionInfo({165}, (-7, -2), ('He4',)), + '(n,5na)': ReactionInfo({166}, (-8, -2), ('He4',)), + '(n,6na)': ReactionInfo({167}, (-9, -2), ('He4',)), + '(n,7na)': ReactionInfo({168}, (-10, -2), ('He4',)), + '(n,4nd)': ReactionInfo({169}, (-5, -1), ('H2',)), + '(n,5nd)': ReactionInfo({170}, (-6, -1), ('H2',)), + '(n,6nd)': ReactionInfo({171}, (-7, -1), ('H2',)), + '(n,3nt)': ReactionInfo({172}, (-5, -1), ('H3',)), + '(n,4nt)': ReactionInfo({173}, (-6, -1), ('H3',)), + '(n,5nt)': ReactionInfo({174}, (-7, -1), ('H3',)), + '(n,6nt)': ReactionInfo({175}, (-8, -1), ('H3',)), + '(n,2n3He)': ReactionInfo({176}, (-4, -2), ('He3',)), + '(n,3n3He)': ReactionInfo({177}, (-5, -2), ('He3',)), + '(n,4n3He)': ReactionInfo({178}, (-6, -2), ('He3',)), + '(n,3n2p)': ReactionInfo({179}, (-4, -2), ('H1', 'H1')), + '(n,3n2a)': ReactionInfo({180}, (-10, -4), ('He4', 'He4')), + '(n,3npa)': ReactionInfo({181}, (-7, -3), ('H1', 'He4')), + '(n,dt)': ReactionInfo({182}, (-4, -2), ('H2', 'H3')), + '(n,npd)': ReactionInfo({183}, (-3, -2), ('H1', 'H2')), + '(n,npt)': ReactionInfo({184}, (-4, -2), ('H1', 'H3')), + '(n,ndt)': ReactionInfo({185}, (-5, -2), ('H2', 'H3')), + '(n,np3He)': ReactionInfo({186}, (-4, -3), ('H1', 'He3')), + '(n,nd3He)': ReactionInfo({187}, (-5, -3), ('H2', 'He3')), + '(n,nt3He)': ReactionInfo({188}, (-6, -3), ('H3', 'He3')), + '(n,nta)': ReactionInfo({189}, (-7, -3), ('H3', 'He4')), + '(n,2n2p)': ReactionInfo({190}, (-3, -2), ('H1', 'H1')), + '(n,p3He)': ReactionInfo({191}, (-4, -3), ('H1', 'He3')), + '(n,d3He)': ReactionInfo({192}, (-5, -3), ('H2', 'He3')), + '(n,3Hea)': ReactionInfo({193}, (-6, -4), ('He3', 'He4')), + '(n,4n2p)': ReactionInfo({194}, (-5, -2), ('H1', 'H1')), + '(n,4n2a)': ReactionInfo({195}, (-11, -4), ('He4', 'He4')), + '(n,4npa)': ReactionInfo({196}, (-8, -3), ('H1', 'He4')), + '(n,3p)': ReactionInfo({197}, (-2, -3), ('H1', 'H1', 'H1')), + '(n,n3p)': ReactionInfo({198}, (-3, -3), ('H1', 'H1', 'H1')), + '(n,3n2pa)': ReactionInfo({199}, (-8, -4), ('H1', 'H1', 'He4')), + '(n,5n2p)': ReactionInfo({200}, (-6, -2), ('H1', 'H1')), } __all__ = ["Chain", "REACTIONS"] @@ -126,14 +135,14 @@ def replace_missing(product, decay_data): Parameters ---------- product : str - Name of product in GNDS format, e.g. 'Y86_m1'. + Name of product in GND format, e.g. 'Y86_m1'. decay_data : dict Dictionary of decay data Returns ------- product : str - Replacement for missing product in GNDS format. + Replacement for missing product in GND format. """ # Determine atomic number, mass number, and metastable state @@ -146,7 +155,7 @@ def replace_missing(product, decay_data): # First check if ground state is available if state: - product = f'{symbol}{A}' + product = '{}{}'.format(symbol, A) # Find isotope with longest half-life half_life = 0.0 @@ -177,7 +186,7 @@ def replace_missing(product, decay_data): Z += 1 else: Z -= 1 - product = f'{openmc.data.ATOMIC_SYMBOL[Z]}{A}' + product = '{}{}'.format(openmc.data.ATOMIC_SYMBOL[Z], A) return product @@ -204,7 +213,7 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): # Check if metastable state has data (e.g., Am242m) Z, A, m = zam(actinide) if m == 0: - metastable = gnds_name(Z, A, 1) + metastable = gnd_name(Z, A, 1) if metastable in fpy_data: return metastable @@ -213,7 +222,7 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): while isotone in decay_data: Z += 1 A += 1 - isotone = gnds_name(Z, A, 0) + isotone = gnd_name(Z, A, 0) if isotone in fpy_data: return isotone @@ -222,7 +231,7 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): while isotone in decay_data: Z -= 1 A -= 1 - isotone = gnds_name(Z, A, 0) + isotone = gnd_name(Z, A, 0) if isotone in fpy_data: return isotone @@ -230,6 +239,24 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): return 'U235' +def _find_chain_file(cross_sections=None): + # First check deprecated OPENMC_DEPLETE_CHAIN environment variable + chain_file = os.environ.get("OPENMC_DEPLETE_CHAIN") + if chain_file is not None: + warn("Use of OPENMC_DEPLETE_CHAIN is deprecated in favor of adding " + "depletion_chain to OPENMC_CROSS_SECTIONS", FutureWarning) + return chain_file + + # Check for depletion chain in cross_sections.xml + data = DataLibrary.from_xml(cross_sections) + for lib in reversed(data.libraries): + if lib['type'] == 'depletion_chain': + return lib['path'] + + raise DataError("No depletion chain specified and could not find depletion " + f"chain in {cross_sections}") + + class Chain: """Full representation of a depletion chain. @@ -238,8 +265,9 @@ class Chain: yield sublibrary files. The depletion chain used during a depletion simulation is indicated by either an argument to :class:`openmc.deplete.CoupledOperator` or - :class:`openmc.deplete.IndependentOperator`, or through - openmc.config['chain_file']. + :class:`openmc.deplete.IndependentOperator`, or through the + ``depletion_chain`` item in the :envvar:`OPENMC_CROSS_SECTIONS` + environment variable. Attributes ---------- @@ -247,12 +275,8 @@ class Chain: Nuclides present in the chain. reactions : list of str Reactions that are tracked in the depletion chain - nuclide_dict : dict of str to int + nuclide_dict : OrderedDict of str to int Maps a nuclide name to an index in nuclides. - stable_nuclides : list of openmc.deplete.Nuclide - List of stable nuclides available in the chain. - unstable_nuclides : list of openmc.deplete.Nuclide - List of unstable nuclides available in the chain. fission_yields : None or iterable of dict List of effective fission yields for materials. Each dictionary should be of the form ``{parent: {product: yield}}`` with @@ -265,11 +289,10 @@ class Chain: """ def __init__(self): - self.nuclides: List[Nuclide] = [] + self.nuclides = [] self.reactions = [] - self.nuclide_dict = {} + self.nuclide_dict = OrderedDict() self._fission_yields = None - self._decay_matrix = None def __contains__(self, nuclide): return nuclide in self.nuclide_dict @@ -282,17 +305,7 @@ class Chain: """Number of nuclides in chain.""" return len(self.nuclides) - @property - def stable_nuclides(self) -> List[Nuclide]: - """List of stable nuclides available in the chain""" - return [nuc for nuc in self.nuclides if nuc.half_life is None] - - @property - def unstable_nuclides(self) -> List[Nuclide]: - """List of unstable nuclides available in the chain""" - return [nuc for nuc in self.nuclides if nuc.half_life is not None] - - def add_nuclide(self, nuclide: Nuclide): + def add_nuclide(self, nuclide): """Add a nuclide to the depletion chain Parameters @@ -301,7 +314,6 @@ class Chain: Nuclide to add """ - _invalidate_chain_cache(self) self.nuclide_dict[nuclide.name] = len(self.nuclides) self.nuclides.append(nuclide) @@ -319,16 +331,16 @@ class Chain: String arguments in ``decay_files``, ``fpy_files``, and ``neutron_files`` will be treated as file names to be read. - Alternatively, :class:`openmc.data.endf.Evaluation` or - ``endf.Material`` instances can be included in these arguments. + Alternatively, :class:`openmc.data.endf.Evaluation` instances + can be included in these arguments. Parameters ---------- - decay_files : list of str, openmc.data.endf.Evaluation, or endf.Material + decay_files : list of str or openmc.data.endf.Evaluation List of ENDF decay sub-library files - fpy_files : list of str, openmc.data.endf.Evaluation, or endf.Material + fpy_files : list of str or openmc.data.endf.Evaluation List of ENDF neutron-induced fission product yield sub-library files - neutron_files : list of str, openmc.data.endf.Evaluation, or endf.Material + neutron_files : list of str or openmc.data.endf.Evaluation List of ENDF neutron reaction sub-library files reactions : iterable of str, optional Transmutation reactions to include in the depletion chain, e.g., @@ -363,8 +375,8 @@ class Chain: print('Processing neutron sub-library files...') reactions = {} for f in neutron_files: - evaluation = openmc.data.endf.as_evaluation(f) - name = evaluation.gnds_name + evaluation = openmc.data.endf.Evaluation(f) + name = evaluation.gnd_name reactions[name] = {} for mf, mt, nc, mod in evaluation.reaction_list: if mf == 3: @@ -407,47 +419,36 @@ class Chain: if not data.nuclide['stable'] and data.half_life.nominal_value != 0.0: nuclide.half_life = data.half_life.nominal_value nuclide.decay_energy = data.decay_energy.nominal_value - branch_ratios = [] - branch_ids = [] - for mode in data.modes: + sum_br = 0.0 + for i, mode in enumerate(data.modes): type_ = ','.join(mode.modes) if mode.daughter in decay_data: target = mode.daughter - elif 'sf' in type_: - target = None else: print('missing {} {} {}'.format( - parent, type_, mode.daughter)) + parent, ','.join(mode.modes), mode.daughter)) target = replace_missing(mode.daughter, decay_data) + + # Write branching ratio, taking care to ensure sum is unity br = mode.branching_ratio.nominal_value - branch_ratios.append(br) - branch_ids.append((type_, target)) + sum_br += br + if i == len(data.modes) - 1 and sum_br != 1.0: + br = 1.0 - sum(m.branching_ratio.nominal_value + for m in data.modes[:-1]) - if not math.isclose(sum(branch_ratios), 1.0): - max_br = max(branch_ratios) - max_index = branch_ratios.index(max_br) - - # Adjust maximum branching ratio so they sum to unity - new_br = max_br - sum(branch_ratios) + 1.0 - branch_ratios[max_index] = new_br - assert math.isclose(sum(branch_ratios), 1.0) - - # Append decay modes - for br, (type_, target) in zip(branch_ratios, branch_ids): + # Append decay mode nuclide.add_decay_mode(type_, target, br) - nuclide.sources = data.sources - fissionable = False if parent in reactions: reactions_available = set(reactions[parent].keys()) for name in transmutation_reactions: - mts = REACTIONS[name].mts - delta_A, delta_Z = openmc.data.DADZ[name] + mts, changes, _ = REACTIONS[name] if mts & reactions_available: + delta_A, delta_Z = changes A = data.nuclide['mass_number'] + delta_A Z = data.nuclide['atomic_number'] + delta_Z - daughter = f'{openmc.data.ATOMIC_SYMBOL[Z]}{A}' + daughter = '{}{}'.format(openmc.data.ATOMIC_SYMBOL[Z], A) if daughter not in decay_data: daughter = replace_missing(daughter, decay_data) @@ -469,6 +470,7 @@ class Chain: nuclide.add_reaction('fission', None, q_value, 1.0) fissionable = True + if fissionable: if parent in fpy_data: fpy = fpy_data[parent] @@ -512,7 +514,7 @@ class Chain: if missing_daughter: print('The following decay modes have daughters with no decay data:') for mode in missing_daughter: - print(f' {mode}') + print(' {}'.format(mode)) print('') if missing_rx_product: @@ -524,7 +526,7 @@ class Chain: if missing_fpy: print('The following fissionable nuclides have no fission product yields:') for parent, replacement in missing_fpy: - print(f' {parent}, replaced with {replacement}') + print(' {}, replaced with {}'.format(parent, replacement)) print('') if missing_fp: @@ -558,14 +560,11 @@ class Chain: root = ET.parse(str(filename)) for i, nuclide_elem in enumerate(root.findall('nuclide')): - this_q = fission_q.get(get_text(nuclide_elem, "name")) + this_q = fission_q.get(nuclide_elem.get("name")) nuc = Nuclide.from_xml(nuclide_elem, root, this_q) chain.add_nuclide(nuc) - # Store path of XML file (used for handling cache invalidation) - chain._xml_path = str(Path(filename).resolve()) - return chain def export_to_xml(self, filename): @@ -583,7 +582,11 @@ class Chain: root_elem.append(nuclide.to_xml_element()) tree = ET.ElementTree(root_elem) - tree.write(str(filename), encoding='utf-8', pretty_print=True) + if _have_lxml: + tree.write(str(filename), encoding='utf-8', pretty_print=True) + else: + clean_indentation(root_elem) + tree.write(str(filename), encoding='utf-8') def get_default_fission_yields(self): """Return fission yields at lowest incident neutron energy @@ -607,152 +610,8 @@ class Chain: out[nuc.name] = dict(yield_obj) return out - @property - def decay_matrix(self): - """Sparse CSC decay transmutation matrix. - - Contains only terms from radioactive decay: diagonal loss terms - and off-diagonal gain terms (branching ratios, alpha/proton - production). Independent of reaction rates, so computed once and - cached. - - See Also - -------- - :meth:`form_rxn_matrix`, :meth:`form_matrix` - """ - if self._decay_matrix is None: - n = len(self) - rows, cols, vals = [], [], [] - - def setval(i, j, val): - rows.append(i) - cols.append(j) - vals.append(val) - - for i, nuc in enumerate(self.nuclides): - # Loss from radioactive decay - if nuc.half_life is not None: - decay_constant = math.log(2) / nuc.half_life - if decay_constant != 0.0: - setval(i, i, -decay_constant) - - # Gain from radioactive decay - if nuc.n_decay_modes != 0: - for decay_type, target, branching_ratio in nuc.decay_modes: - branch_val = branching_ratio * decay_constant - - # Allow for total annihilation for debug purposes - if branch_val != 0.0: - if target is not None and 'sf' not in decay_type: - k = self.nuclide_dict[target] - setval(k, i, branch_val) - - # Produce alphas and protons from decay - if 'alpha' in decay_type: - k = self.nuclide_dict.get('He4') - if k is not None: - count = decay_type.count('alpha') - setval(k, i, count * branch_val) - elif 'p' in decay_type: - k = self.nuclide_dict.get('H1') - if k is not None: - count = decay_type.count('p') - setval(k, i, count * branch_val) - - self._decay_matrix = csc_array((vals, (rows, cols)), shape=(n, n)) - return self._decay_matrix - - def form_rxn_matrix(self, rates, fission_yields=None): - """Form the reaction-rate portion of the transmutation matrix. - - Builds only the terms that depend on reaction rates: transmutation - reactions and fission product yields. Does not include radioactive - decay terms (see :attr:`decay_matrix`). - - Parameters - ---------- - rates : numpy.ndarray - 2D array indexed by (nuclide, reaction) - fission_yields : dict, optional - Option to use a custom set of fission yields. Expected - to be of the form ``{parent : {product : f_yield}}`` - with string nuclide names for ``parent`` and ``product``, - and ``f_yield`` as the respective fission yield - - Returns - ------- - scipy.sparse.csc_array - Sparse matrix representing reaction-rate terms. - - See Also - -------- - :attr:`decay_matrix`, :meth:`form_matrix` - """ - reactions = set() - n = len(self) - - # Accumulate indices/values and then create the matrix at the end to - # avoid expensive index checks scipy otherwise does. - rows, cols, vals = [], [], [] - - def setval(i, j, val): - rows.append(i) - cols.append(j) - vals.append(val) - - if fission_yields is None: - fission_yields = self.get_default_fission_yields() - - # Save local variables to avoid attribute lookups in loop - index_nuc = rates.index_nuc - index_rx = rates.index_rx - - for i, nuc in enumerate(self.nuclides): - if nuc.name not in index_nuc: - continue - - nuc_ind = index_nuc[nuc.name] - nuc_rates = rates[nuc_ind, :] - - for r_type, target, _, br in nuc.reactions: - r_id = index_rx[r_type] - path_rate = nuc_rates[r_id] - - # Loss term -- make sure we only count loss once for - # reactions with branching ratios - if r_type not in reactions: - reactions.add(r_type) - if path_rate != 0.0: - setval(i, i, -path_rate) - - # Gain term; allow for total annihilation for debug purposes - if r_type != 'fission': - if target is not None and path_rate != 0.0: - k = self.nuclide_dict[target] - setval(k, i, path_rate * br) - - # Determine light nuclide production, e.g., (n,d) should - # produce H2 - if path_rate != 0.0: - light_nucs = REACTIONS[r_type].secondaries - for light_nuc in light_nucs: - k = self.nuclide_dict.get(light_nuc) - if k is not None: - setval(k, i, path_rate * br) - - else: - for product, y in fission_yields[nuc.name].items(): - yield_val = y * path_rate - if yield_val != 0.0: - k = self.nuclide_dict[product] - setval(k, i, yield_val) - - reactions.clear() - - return csc_array((vals, (rows, cols)), shape=(n, n)) - def form_matrix(self, rates, fission_yields=None): - """Form the full transmutation matrix (decay + reactions). + """Forms depletion matrix. Parameters ---------- @@ -766,169 +625,83 @@ class Chain: Returns ------- - scipy.sparse.csc_array + scipy.sparse.csr_matrix Sparse matrix representing depletion. See Also -------- - :attr:`decay_matrix`, :meth:`form_rxn_matrix`, :meth:`get_default_fission_yields` """ - return self.decay_matrix + self.form_rxn_matrix(rates, fission_yields) + matrix = defaultdict(float) + reactions = set() - def add_redox_term(self, matrix, buffer, oxidation_states): - r"""Adds a redox term to the depletion matrix from data contained in - the matrix itself and a few user-inputs. - - The redox term to add to the buffer nuclide :math:`N_j` can be written - as: - - .. math:: - \frac{dN_j(t)}{dt} = \cdots - \frac{1}{OS_j}\sum_i N_i a_{ij} - \cdot OS_i - - where :math:`OS` is the oxidation states vector and :math:`a_{ij}` the - corresponding term in the Bateman matrix. - - Parameters - ---------- - matrix : scipy.sparse.csc_array - Sparse matrix representing depletion - buffer : dict - Dictionary of buffer nuclides used to maintain anoins net balance. - Keys are nuclide names (strings) and values are their respective - fractions (float) that collectively sum to 1. - oxidation_states : dict - User-defined oxidation states for elements. Keys are element symbols - (e.g., 'H', 'He'), and values are their corresponding oxidation - states as integers (e.g., +1, 0). - Returns - ------- - matrix : scipy.sparse.csc_array - Sparse matrix with redox term added - """ - # Elements list with the same size as self.nuclides - elements = [re.split(r'\d+', nuc.name)[0] for nuc in self.nuclides] - - # Match oxidation states with all elements and add 0 if not data - os = np.array([oxidation_states[elm] if elm in oxidation_states else 0 - for elm in elements]) - - # Buffer idx with nuclide index as value - buffer_idx = {nuc: self.nuclide_dict[nuc] for nuc in buffer} - array = matrix.toarray() - redox_change = np.array([]) - - # calculate the redox array - for i in range(len(self)): - # Net redox impact of reaction: multiply the i-th column of the - # depletion matrix by the oxidation states - redox_change = np.append(redox_change, sum(array[:, i]*os)) - - # Subtract redox vector to the buffer nuclides in the matrix scaling by - # their respective oxidation states - for nuc, idx in buffer_idx.items(): - array[idx] -= redox_change * buffer[nuc] / os[idx] - - return csc_array(array) - - def form_rr_term(self, tr_rates, current_timestep, mats): - """Function to form the transfer rate term matrices. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - tr_rates : openmc.deplete.TransferRates - Instance of openmc.deplete.TransferRates - current_timestep : int - Current timestep index - mats : string or two-tuple of strings - Two cases are possible: - - 1) Material ID as string: - Nuclide transfer only. In this case the transfer rate terms will be - subtracted from the respective depletion matrix - - 2) Two-tuple of material IDs as strings: - Nuclide transfer from one material into another. - The pair is assumed to be - ``(destination_material, source_material)``, where - ``destination_material`` and ``source_material`` are the nuclide - receiving and losing materials, respectively. - The transfer rate terms get placed in the final matrix with indexing - position corresponding to the ID of the materials set. - - Returns - ------- - scipy.sparse.csc_array - Sparse matrix representing transfer term. - - """ - # Use DOK as intermediate representation - n = len(self) - matrix = dok_array((n, n)) - - check_type("mats", mats, (tuple, str)) - if not isinstance(mats, str): - check_type("mats", mats, tuple, str) - check_length("mats", mats, 2, 2) - dest_mat, mat = mats - else: - mat = mats - dest_mat = None - - # Build transfer term - components = tr_rates.get_components(mat, current_timestep, dest_mat) + if fission_yields is None: + fission_yields = self.get_default_fission_yields() for i, nuc in enumerate(self.nuclides): - elm = re.split(r'\d+', nuc.name)[0] - if elm in components: - key = elm - elif nuc.name in components: - key = nuc.name - else: - continue - matrix[i, i] = sum(tr_rates.get_external_rate(mat, key, current_timestep, dest_mat)) + # Loss from radioactive decay + if nuc.half_life is not None: + decay_constant = math.log(2) / nuc.half_life + if decay_constant != 0.0: + matrix[i, i] -= decay_constant - # Return CSC instead of DOK - return matrix.tocsc() + # Gain from radioactive decay + if nuc.n_decay_modes != 0: + for _, target, branching_ratio in nuc.decay_modes: + # Allow for total annihilation for debug purposes + if target is not None: + branch_val = branching_ratio * decay_constant - def form_ext_source_term(self, ext_source_rates, current_timestep, mat): - """Function to form the external source rate term vectors. + if branch_val != 0.0: + k = self.nuclide_dict[target] + matrix[k, i] += branch_val - .. versionadded:: 0.15.3 + if nuc.name in rates.index_nuc: + # Extract all reactions for this nuclide in this cell + nuc_ind = rates.index_nuc[nuc.name] + nuc_rates = rates[nuc_ind, :] - Parameters - ---------- - ext_source_rates : openmc.deplete.ExternalSourceRates - Instance of openmc.deplete.ExternalSourceRates - current_timestep : int - Current timestep index - mat : string - Material id + for r_type, target, _, br in nuc.reactions: + # Extract reaction index, and then final reaction rate + r_id = rates.index_rx[r_type] + path_rate = nuc_rates[r_id] - Returns - ------- - scipy.sparse.csc_array - Sparse vector representing external source term. + # Loss term -- make sure we only count loss once for + # reactions with branching ratios + if r_type not in reactions: + reactions.add(r_type) + if path_rate != 0.0: + matrix[i, i] -= path_rate - """ - if not ext_source_rates.get_components(mat, current_timestep): - return - # Use DOK as intermediate representation + # Gain term; allow for total annihilation for debug purposes + if r_type != 'fission': + if target is not None and path_rate != 0.0: + k = self.nuclide_dict[target] + matrix[k, i] += path_rate * br + + # Determine light nuclide production, e.g., (n,d) should + # produce H2 + light_nucs = REACTIONS[r_type].secondaries + for light_nuc in light_nucs: + k = self.nuclide_dict.get(light_nuc) + if k is not None: + matrix[k, i] += path_rate * br + + else: + for product, y in fission_yields[nuc.name].items(): + yield_val = y * path_rate + if yield_val != 0.0: + k = self.nuclide_dict[product] + matrix[k, i] += yield_val + + # Clear set of reactions + reactions.clear() + + # Use DOK matrix as intermediate representation, then convert to CSR and return n = len(self) - vector = dok_array((n, 1)) - components = ext_source_rates.get_components(mat, current_timestep) - - for i, nuc in enumerate(self.nuclides): - # Build source term vector - if nuc.name in components: - vector[i] = sum(ext_source_rates.get_external_rate( - mat, nuc.name, current_timestep)) - - # Return CSC instead of DOK - return vector.tocsc() + matrix_dok = sp.dok_matrix((n, n)) + dict.update(matrix_dok, matrix) + return matrix_dok.tocsr() def get_branch_ratios(self, reaction="(n,gamma)"): """Return a dictionary with reaction branching ratios @@ -1007,7 +780,7 @@ class Chain: -------- :meth:`get_branch_ratios` """ - _invalidate_chain_cache(self) + # Store some useful information through the validation stage sums = {} @@ -1060,7 +833,8 @@ class Chain: if len(indexes) == 0: if strict: raise AttributeError( - f"Nuclide {parent} does not have {reaction} reactions") + "Nuclide {} does not have {} reactions".format( + parent, reaction)) missing_reaction.add(parent) continue @@ -1082,7 +856,8 @@ class Chain: if len(rxn_ix_map) == 0: raise IndexError( - f"No {reaction} reactions found in this {self.__class__.__name__}") + "No {} reactions found in this {}".format( + reaction, self.__class__.__name__)) if len(missing_parents) > 0: warn("The following nuclides were not found in {}: {}".format( @@ -1093,14 +868,14 @@ class Chain: "{}".format(reaction, ", ".join(sorted(missing_reaction)))) if len(missing_products) > 0: - tail = (f"{k} -> {v}" + tail = ("{} -> {}".format(k, v) for k, v in sorted(missing_products.items())) warn("The following products were not found in the {} and " "parents were unmodified: \n{}".format( self.__class__.__name__, ", ".join(tail))) if len(bad_sums) > 0: - tail = (f"{k}: {s:5.3f}" + tail = ("{}: {:5.3f}".format(k, s) for k, s in sorted(bad_sums.items())) warn("The following parent nuclides were given {} branch ratios " "with a sum outside tolerance of 1 +/- {:5.3e}:\n{}".format( @@ -1134,7 +909,7 @@ class Chain: ground_target = grounds.get(parent_name) if ground_target is None: pz, pa, pm = zam(parent_name) - ground_target = gnds_name(pz, pa + 1, 0) + ground_target = gnd_name(pz, pa + 1, 0) new_ratios[ground_target] = ground_br parent.add_reaction(reaction, ground_target, rxn_Q, ground_br) @@ -1146,7 +921,6 @@ class Chain: @fission_yields.setter def fission_yields(self, yields): - _invalidate_chain_cache(self) if yields is not None: if isinstance(yields, Mapping): yields = [yields] @@ -1268,7 +1042,6 @@ class Chain: new_nuclide = Nuclide(previous.name) new_nuclide.half_life = previous.half_life new_nuclide.decay_energy = previous.decay_energy - new_nuclide.sources = previous.sources.copy() if hasattr(previous, '_fpy'): new_nuclide._fpy = previous._fpy @@ -1367,66 +1140,3 @@ class Chain: found.update(isotopes) return found - - -# A global cache for Chain objects -_CHAIN_CACHE = {} - - -def _get_chain( - chain_file: PathLike | Chain | None = None, - fission_q: dict | None = None -) -> Chain: - """Get a depletion chain from a file or the runtime configuration. - - Parameters - ---------- - chain_file : PathLike or Chain, optional - Path to depletion chain XML file, a Chain instance, or None to use - the file specified in ``openmc.config['chain_file']``. - fission_q : dict, optional - Dictionary of nuclides and their fission Q values [eV]. If not given, - values will be pulled from the ``chain_file``. - - Returns - ------- - Chain - Depletion chain instance. - """ - # If chain_file is already a Chain, return it directly - if isinstance(chain_file, Chain): - return chain_file - - # Resolve chain_file based on config if None - if chain_file is None: - chain_file = openmc.config.get('chain_file') - if 'chain_file' not in openmc.config: - raise DataError( - "No depletion chain specified and could not find depletion " - "chain in openmc.config['chain_file']" - ) - elif not isinstance(chain_file, PathLike): - raise TypeError("chain_file must be path-like, a Chain, or None") - - # Determine the key for the cache, which consists of the absolute path, the - # file modification time, the file size, and the fission Q values. - chain_path = Path(chain_file).resolve() - stat_result = chain_path.stat() - fq_tuple = tuple(sorted(fission_q.items())) if fission_q else () - key = (chain_path, stat_result.st_mtime, stat_result.st_size, fq_tuple) - - # Check the global cache. If not cached, load the chain from XML and store - global _CHAIN_CACHE - if key not in _CHAIN_CACHE: - _CHAIN_CACHE[key] = Chain.from_xml(chain_path, fission_q) - return _CHAIN_CACHE[key] - - -def _invalidate_chain_cache(chain): - """Invalidate the cache for a specific Chain (when it is modifed).""" - chain._decay_matrix = None - if hasattr(chain, '_xml_path'): - # Remove all entries with the same path as self._xml_path - for key in list(_CHAIN_CACHE.keys()): - if str(key[0]) == chain._xml_path: - del _CHAIN_CACHE[key] diff --git a/openmc/deplete/coupled_operator.py b/openmc/deplete/coupled_operator.py index a21d57d46..dd14f282f 100644 --- a/openmc/deplete/coupled_operator.py +++ b/openmc/deplete/coupled_operator.py @@ -9,6 +9,7 @@ filesystem. """ import copy +import os from warnings import warn import numpy as np @@ -21,8 +22,8 @@ from openmc.exceptions import DataError import openmc.lib from openmc.mpi import comm from .abc import OperatorResult -from .openmc_operator import OpenMCOperator -from .pool import _distribute +from .chain import _find_chain_file +from .openmc_operator import OpenMCOperator, _distribute from .results import Results from .helpers import ( DirectReactionRateHelper, ChainFissionHelper, ConstantFissionYieldHelper, @@ -33,26 +34,25 @@ from .helpers import ( __all__ = ["CoupledOperator", "Operator", "OperatorResult"] -def _find_cross_sections(model: str | None = None): +def _find_cross_sections(model): """Determine cross sections to use for depletion Parameters ---------- - model : openmc.model.Model, optional + model : openmc.model.Model Reactor model """ - if model: - if model.materials and model.materials.cross_sections is not None: - # Prefer info from Model class if available - return model.materials.cross_sections + if model.materials and model.materials.cross_sections is not None: + # Prefer info from Model class if available + return model.materials.cross_sections # otherwise fallback to environment variable - cross_sections = openmc.config.get("cross_sections") + cross_sections = os.environ.get("OPENMC_CROSS_SECTIONS") if cross_sections is None: raise DataError( "Cross sections were not specified in Model.materials and " - "openmc.config['cross_sections'] is not set." + "the OPENMC_CROSS_SECTIONS environment variable is not set." ) return cross_sections @@ -68,7 +68,7 @@ def _get_nuclides_with_data(cross_sections): Returns ------- nuclides : set of str - Set of nuclide names that have cross section data + Set of nuclide names that have cross secton data """ nuclides = set() @@ -102,9 +102,10 @@ class CoupledOperator(OpenMCOperator): ---------- model : openmc.model.Model OpenMC model object - chain_file : PathLike or Chain, optional - Path to the depletion chain XML file or instance of openmc.deplete.Chain. - Defaults to ``openmc.config['chain_file']``. + chain_file : str, optional + Path to the depletion chain XML file. Defaults to the file + listed under ``depletion_chain`` in + :envvar:`OPENMC_CROSS_SECTIONS` environment variable. prev_results : Results, optional Results from a previous depletion calculation. If this argument is specified, the depletion calculation will start from the latest state @@ -123,6 +124,10 @@ class CoupledOperator(OpenMCOperator): Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Only applicable if ``"normalization_mode" == "fission-q"`` + dilute_initial : float, optional + Initial atom density [atoms/cm^3] to add for nuclides that are zero + in initial condition to ensure they exist in the decay chain. + Only done for nuclides with reaction rates. fission_yield_mode : {"constant", "cutoff", "average"} Key indicating what fission product yield scheme to use. The key determines what fission energy helper is used: @@ -154,23 +159,30 @@ class CoupledOperator(OpenMCOperator): options. .. versionadded:: 0.12.1 - reduce_chain_level : int, optional - Depth of the search when reducing the depletion chain. The default - value of ``None`` implies no limit on the depth. + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the + depletion chain up to ``reduce_chain_level``. .. versionadded:: 0.12 - diff_volume_method : str - Specifies how the volumes of the new materials should be found. Default - is to 'divide equally' which divides the original material volume - equally between the new materials, 'match cell' sets the volume of the - material to volume of the cell they fill. + reduce_chain_level : int, optional + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. - .. versionadded:: 0.14.0 + .. versionadded:: 0.12 Attributes ---------- model : openmc.model.Model OpenMC model object + geometry : openmc.Geometry + OpenMC geometry object + settings : openmc.Settings + OpenMC settings object + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that + are zero in initial condition to ensure they exist in the decay + chain. Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. round_number : bool @@ -204,11 +216,11 @@ class CoupledOperator(OpenMCOperator): } def __init__(self, model, chain_file=None, prev_results=None, - diff_burnable_mats=False, diff_volume_method="divide equally", - normalization_mode="fission-q", fission_q=None, + diff_burnable_mats=False, normalization_mode="fission-q", + fission_q=None, dilute_initial=1.0e3, fission_yield_mode="constant", fission_yield_opts=None, reaction_rate_mode="direct", reaction_rate_opts=None, - reduce_chain_level=None): + reduce_chain=False, reduce_chain_level=None): # check for old call to constructor if isinstance(model, openmc.Geometry): @@ -219,8 +231,10 @@ class CoupledOperator(OpenMCOperator): " model with which to generate the transport Operator." raise TypeError(msg) - # Determine cross sections + # Determine cross sections / depletion chain cross_sections = _find_cross_sections(model) + if chain_file is None: + chain_file = _find_chain_file(cross_sections) check_value('fission yield mode', fission_yield_mode, self._fission_helpers.keys()) @@ -231,6 +245,8 @@ class CoupledOperator(OpenMCOperator): warn("Fission Q dictionary will not be used") fission_q = None self.model = model + self.settings = model.settings + self.geometry = model.geometry # determine set of materials in the model if not model.materials: @@ -252,25 +268,45 @@ class CoupledOperator(OpenMCOperator): 'fission_yield_opts': fission_yield_opts } - # Records how many times the operator has been called - self._n_calls = 0 - super().__init__( - materials=model.materials, - cross_sections=cross_sections, - chain_file=chain_file, - prev_results=prev_results, - diff_burnable_mats=diff_burnable_mats, - diff_volume_method=diff_volume_method, - fission_q=fission_q, - helper_kwargs=helper_kwargs, - reduce_chain_level=reduce_chain_level) + model.materials, + cross_sections, + chain_file, + prev_results, + diff_burnable_mats, + fission_q, + dilute_initial, + helper_kwargs, + reduce_chain, + reduce_chain_level) def _differentiate_burnable_mats(self): """Assign distribmats for each burnable material""" - self.model.differentiate_depletable_mats( - diff_volume_method=self.diff_volume_method + # Count the number of instances for each cell and material + self.geometry.determine_paths(instances_only=True) + + # Extract all burnable materials which have multiple instances + distribmats = set( + [mat for mat in self.materials + if mat.depletable and mat.num_instances > 1]) + + for mat in distribmats: + if mat.volume is None: + raise RuntimeError("Volume not specified for depletable " + "material with ID={}.".format(mat.id)) + mat.volume /= mat.num_instances + + if distribmats: + # Assign distribmats to cells + for cell in self.geometry.get_all_material_cells().values(): + if cell.fill in distribmats: + mat = cell.fill + cell.fill = [mat.clone() + for i in range(cell.num_instances)] + + self.materials = openmc.Materials( + self.model.geometry.get_all_materials().values() ) def _load_previous_results(self): @@ -283,7 +319,7 @@ class CoupledOperator(OpenMCOperator): # on this process if comm.size != 1: prev_results = self.prev_res - self.prev_res = Results(filename=None) + self.prev_res = Results() mat_indexes = _distribute(range(len(self.burnable_mats))) for res_obj in prev_results: new_res = res_obj.distribute(self.local_mats, mat_indexes) @@ -344,7 +380,7 @@ class CoupledOperator(OpenMCOperator): if normalization_mode == "fission-q": self._normalization_helper = ChainFissionHelper() elif normalization_mode == "energy-deposition": - score = "heating" if self.model.settings.photon_transport else "heating-local" + score = "heating" if self.settings.photon_transport else "heating-local" self._normalization_helper = EnergyScoreHelper(score) else: self._normalization_helper = SourceRateHelper() @@ -366,12 +402,8 @@ class CoupledOperator(OpenMCOperator): # Create XML files if comm.rank == 0: - self.model.geometry.export_to_xml() - self.model.settings.export_to_xml() - if self.model.plots: - self.model.plots.export_to_xml() - if self.model.tallies: - self.model.tallies.export_to_xml() + self.geometry.export_to_xml() + self.settings.export_to_xml() self._generate_materials_xml() # Initialize OpenMC library @@ -397,9 +429,9 @@ class CoupledOperator(OpenMCOperator): for mat in self.materials: mat._nuclides.sort(key=lambda x: nuclides.index(x[0])) - self.materials.export_to_xml(nuclides_to_ignore=self._decay_nucs) + self.materials.export_to_xml() - def __call__(self, vec, source_rate) -> OperatorResult: + def __call__(self, vec, source_rate): """Runs a simulation. Simulation will abort under the following circumstances: @@ -422,16 +454,6 @@ class CoupledOperator(OpenMCOperator): # Reset results in OpenMC openmc.lib.reset() - # The timers are reset only if the operator has been called before. - # This is because we call this method after loading cross sections, and - # no transport has taken place yet. As a result, we only reset the - # timers after the first step so as to correctly report the time spent - # reading cross sections in the first depletion step, and from there - # correctly report all particle tracking rates in multistep depletion - # solvers. - if self._n_calls > 0: - openmc.lib.reset_timers() - self._update_materials_and_nuclides(vec) # If the source rate is zero, return zero reaction rates without running @@ -443,6 +465,7 @@ class CoupledOperator(OpenMCOperator): # Run OpenMC openmc.lib.run() + openmc.lib.reset_timers() # Extract results rates = self._calculate_reaction_rates(source_rate) @@ -452,8 +475,6 @@ class CoupledOperator(OpenMCOperator): op_result = OperatorResult(keff, rates) - self._n_calls += 1 - return copy.deepcopy(op_result) def _update_materials(self): @@ -510,7 +531,7 @@ class CoupledOperator(OpenMCOperator): """ openmc.lib.statepoint_write( - f"openmc_simulation_n{step}.h5", + "openmc_simulation_n{}.h5".format(step), write_source=False) def finalize(self): @@ -518,36 +539,6 @@ class CoupledOperator(OpenMCOperator): if self.cleanup_when_done: openmc.lib.finalize() - # The next few class variables and methods should be removed after one - # release cycle or so. For now, we will provide compatibility to - # accessing CoupledOperator.settings and CoupledOperator.geometry. In - # the future these should stay on the Model class. - - var_warning_msg = "The CoupledOperator.{0} variable should be \ -accessed through CoupledOperator.model.{0}." - geometry_warning_msg = var_warning_msg.format("geometry") - settings_warning_msg = var_warning_msg.format("settings") - - @property - def settings(self): - warn(self.settings_warning_msg, FutureWarning) - return self.model.settings - - @settings.setter - def settings(self, new_settings): - warn(self.settings_warning_msg, FutureWarning) - self.model.settings = new_settings - - @property - def geometry(self): - warn(self.geometry_warning_msg, FutureWarning) - return self.model.geometry - - @geometry.setter - def geometry(self, new_geometry): - warn(self.geometry_warning_msg, FutureWarning) - self.model.geometry = new_geometry - # Retain deprecated name for the time being def Operator(*args, **kwargs): diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index 3594ffbe8..f5f80dfdc 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -3,15 +3,14 @@ Implements two different forms of CRAM for use in openmc.deplete. """ -from functools import partial import numbers import numpy as np -from scipy.sparse.linalg import spsolve, splu +import scipy.sparse as sp +import scipy.sparse.linalg as sla -from openmc.checkvalue import check_type, check_length, check_greater_than +from openmc.checkvalue import check_type, check_length from .abc import DepSystemSolver -from .._sparse_compat import csc_array, eye_array __all__ = ["CRAM16", "CRAM48", "Cram16Solver", "Cram48Solver", "IPFCramSolver"] @@ -25,12 +24,6 @@ class IPFCramSolver(DepSystemSolver): Chebyshev Rational Approximation Method and Application to Burnup Equations `_," Nucl. Sci. Eng., 182:3, 297-318. - When `substeps` > 1, the time interval is split into `substeps` identical - sub-intervals and LU factorizations are reused across them, as described - in: A. Isotalo and M. Pusa, "`Improving the Accuracy of the Chebyshev - Rational Approximation Method Using Substeps - `_," Nucl. Sci. Eng., 183:1, 65-77. - Parameters ---------- alpha : numpy.ndarray @@ -62,12 +55,12 @@ class IPFCramSolver(DepSystemSolver): self.theta = theta self.alpha0 = alpha0 - def __call__(self, A, n0, dt, substeps=1): + def __call__(self, A, n0, dt): """Solve depletion equations using IPF CRAM Parameters ---------- - A : scipy.sparse.csc_array + A : scipy.sparse.csr_matrix Sparse transmutation matrix ``A[j, i]`` desribing rates at which isotope ``i`` transmutes to isotope ``j`` n0 : numpy.ndarray @@ -75,8 +68,6 @@ class IPFCramSolver(DepSystemSolver): material or an atom density dt : float Time [s] of the specific interval to be solved - substeps : int, optional - Number of substeps per depletion interval. Returns ------- @@ -84,25 +75,12 @@ class IPFCramSolver(DepSystemSolver): Final compositions after ``dt`` """ - check_type("substeps", substeps, numbers.Integral) - check_greater_than("substeps", substeps, 0) - - step_dt = dt if substeps == 1 else dt / substeps - A = step_dt * csc_array(A, dtype=np.float64) - ident = eye_array(A.shape[0], format='csc') - - if substeps == 1: - solvers = [partial(spsolve, A - theta * ident) for theta in self.theta] - else: - # Pre-compute LU factorizations and reuse them across substeps. - solvers = [splu(A - theta * ident).solve for theta in self.theta] - + A = sp.csr_matrix(A * dt, dtype=np.float64) y = n0.copy() - for _ in range(substeps): - for alpha, solve in zip(self.alpha, solvers): - y += 2 * np.real(alpha * solve(y)) - y *= self.alpha0 - return y + ident = sp.eye(A.shape[0]) + for alpha, theta in zip(self.alpha, self.theta): + y += 2*np.real(alpha*sla.spsolve(A - theta*ident, y)) + return y * self.alpha0 # Coefficients for IPF Cram 16 diff --git a/openmc/deplete/d1s.py b/openmc/deplete/d1s.py deleted file mode 100644 index d85d2e8a7..000000000 --- a/openmc/deplete/d1s.py +++ /dev/null @@ -1,256 +0,0 @@ -"""D1S module - -This module contains functionality to support the direct 1-step (D1S) method for -shutdown dose rate calculations. - -""" - -from copy import copy -from typing import Sequence -from math import log, prod - -import numpy as np - -import openmc -from openmc.data import half_life -from .abc import _normalize_timesteps -from .chain import Chain, _get_chain -from ..checkvalue import PathLike - - -def get_radionuclides(model: openmc.Model, chain_file: PathLike | Chain | None = None) -> list[str]: - """Determine all radionuclides that can be produced during D1S. - - Parameters - ---------- - model : openmc.Model - Model that should be used for determining what nuclides are present - chain_file : PathLike | Chain - Path to the depletion chain XML file or instance of openmc.deplete.Chain. - Used for inspecting decay data. Defaults to ``openmc.config['chain_file']`` - - Returns - ------- - List of nuclide names - - """ - - # Determine what nuclides appear in the model - model_nuclides = {nuc for mat in model._materials_by_id.values() - for nuc in mat.get_nuclides()} - - # Load chain file - chain = _get_chain(chain_file) - - radionuclides = set() - for nuclide in chain.nuclides: - # Restrict to set of nuclides present in model - if nuclide.name not in model_nuclides: - continue - - # Loop over reactions and add any targets that are unstable - for rx_tuple in nuclide.reactions: - target = rx_tuple.target - if target is None: - continue - target_nuclide = chain[target] - if target_nuclide.half_life is not None: - radionuclides.add(target_nuclide.name) - - return list(radionuclides) - - -def time_correction_factors( - nuclides: list[str], - timesteps: Sequence[float] | Sequence[tuple[float, str]], - source_rates: float | Sequence[float], - timestep_units: str = 's' -) -> dict[str, np.ndarray]: - """Calculate time correction factors for the D1S method. - - This function determines the time correction factor that should be applied - to photon tallies as part of the D1S method. - - Parameters - ---------- - nuclides : list of str - The name of the nuclide to find the time correction for, e.g., 'Ni65' - timesteps : iterable of float or iterable of tuple - Array of timesteps. Note that values are not cumulative. The units are - specified by the `timestep_units` argument when `timesteps` is an - iterable of float. Alternatively, units can be specified for each step - by passing a sequence of (value, unit) tuples. - source_rates : float or iterable of float - Source rate in [neutron/sec] for each interval in `timesteps` - timestep_units : {'s', 'min', 'h', 'd', 'a'}, optional - Units for values specified in the `timesteps` argument. 's' means - seconds, 'min' means minutes, 'h' means hours, and 'a' means Julian - years. - - Returns - ------- - dict - Dictionary mapping nuclide to an array of time correction factors for - each time. - - """ - - # Determine normalized timesteps and source rates - timesteps, source_rates = _normalize_timesteps( - timesteps, source_rates, timestep_units) - - # Calculate decay rate for each nuclide - decay_rate = np.array([log(2.0) / half_life(x) for x in nuclides]) - - n_timesteps = len(timesteps) + 1 - n_nuclides = len(nuclides) - - # Create a 2D array for the time correction factors - h = np.zeros((n_timesteps, n_nuclides)) - - # Precompute all exponential terms with same shape as h - decay_dt = decay_rate[np.newaxis, :] * timesteps[:, np.newaxis] - g = np.exp(-decay_dt) - one_minus_g = -np.expm1(-decay_dt) - - # Apply recurrence relation step by step - for i in range(len(timesteps)): - # Eq. (4) in doi:10.1016/j.fusengdes.2019.111399 - h[i + 1] = source_rates[i] * one_minus_g[i] + h[i] * g[i] - - return {nuclides[i]: h[:, i] for i in range(n_nuclides)} - - -def apply_time_correction( - tally: openmc.Tally, - time_correction_factors: dict[str, np.ndarray], - index: int = -1, - sum_nuclides: bool = True -) -> openmc.Tally: - """Apply time correction factors to a tally. - - This function applies the time correction factors at the given index to a - tally that contains a :class:`~openmc.ParentNuclideFilter`. When - `sum_nuclides` is True, values over all parent nuclides will be summed, - leaving a single value for each filter combination. - - Parameters - ---------- - tally : openmc.Tally - Tally to apply the time correction factors to - time_correction_factors : dict - Time correction factors as returned by :func:`time_correction_factors` - index : int, optional - Index of the time of interest. If N timesteps are provided in - :func:`time_correction_factors`, there are N + 1 times to select from. - The default is -1 which corresponds to the final time. - sum_nuclides : bool - Whether to sum over the parent nuclides - - Returns - ------- - openmc.Tally - Derived tally with time correction factors applied - - """ - # Make sure the tally contains a ParentNuclideFilter - for i_filter, filter in enumerate(tally.filters): - if isinstance(filter, openmc.ParentNuclideFilter): - break - else: - raise ValueError('Tally must contain a ParentNuclideFilter') - - # Get list of radionuclides based on tally filter - radionuclides = [str(x) for x in tally.filters[i_filter].bins] - tcf = np.array([time_correction_factors[x][index] for x in radionuclides]) - - # Force tally results to be read and std_dev to be computed - tally.std_dev - - # Create shallow copy of tally - new_tally = copy(tally) - new_tally._filters = copy(tally._filters) - - # Determine number of bins in other filters - n_bins_before = prod([f.num_bins for f in tally.filters[:i_filter]]) - n_bins_after = prod([f.num_bins for f in tally.filters[i_filter + 1:]]) - - # Reshape sum and sum_sq, apply TCF, and sum along that axis - _, n_nuclides, n_scores = new_tally.shape - n_radionuclides = len(radionuclides) - shape = (n_bins_before, n_radionuclides, n_bins_after, n_nuclides, n_scores) - tally_sum = new_tally.sum.reshape(shape) - tally_sum_sq = new_tally.sum_sq.reshape(shape) - tally_mean = new_tally.mean.reshape(shape) - tally_std_dev = new_tally.std_dev.reshape(shape) - - # Apply TCF, broadcasting to the correct dimensions - tcf.shape = (1, -1, 1, 1, 1) - new_tally._mean = tally_mean * tcf - new_tally._std_dev = tally_std_dev * tcf - - shape = (-1, n_nuclides, n_scores) - - if sum_nuclides: - # Sum over parent nuclides (note that when combining different bins for - # parent nuclide, we can't work directly on sum_sq) - new_tally._sum = None - new_tally._sum_sq = None - new_tally._mean = new_tally.mean.sum(axis=1).reshape(shape) - new_tally._std_dev = np.linalg.norm(new_tally.std_dev, axis=1).reshape(shape) - new_tally._derived = True - - # Remove ParentNuclideFilter - new_tally.filters.pop(i_filter) - else: - # Apply TCF and change shape back to (filter combinations, nuclides, - # scores) - new_tally._sum = (tally_sum * tcf).reshape(shape) - new_tally._sum_sq = (tally_sum_sq * (tcf*tcf)).reshape(shape) - new_tally._mean.shape = shape - new_tally._std_dev.shape = shape - - return new_tally - - -def prepare_tallies( - model: openmc.Model, - nuclides: list[str] | None = None, - chain_file: str | None = None -) -> list[str]: - """Prepare tallies for the D1S method. - - This function adds a :class:`~openmc.ParentNuclideFilter` to any tally that - has a particle filter with a single 'photon' bin. - - Parameters - ---------- - model : openmc.Model - Model to prepare tallies for - nuclides : list of str, optional - Nuclides to use for the parent nuclide filter. If None, radionuclides - are determined from :func:`get_radionuclides`. - chain_file : str, optional - Chain file to use for inspecting decay data. If None, defaults to - ``openmc.config['chain_file']`` - - Returns - ------- - list of str - List of parent nuclides being filtered on - - """ - if nuclides is None: - nuclides = get_radionuclides(model, chain_file) - filter = openmc.ParentNuclideFilter(nuclides) - - # Apply parent nuclide filter to any tally that has a particle filter with a - # single 'photon' bin - for tally in model.tallies: - for f in tally.filters: - if isinstance(f, openmc.ParticleFilter): - if list(f.bins) == ['photon']: - if not tally.contains_filter(openmc.ParentNuclideFilter): - tally.filters.append(filter) - break - return nuclides diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index 14780d61a..3a7928a52 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -15,7 +15,7 @@ from openmc.mpi import comm from openmc.checkvalue import check_type, check_greater_than from openmc.data import JOULE_PER_EV, REACTION_MT from openmc.lib import ( - Tally, MaterialFilter, EnergyFilter, EnergyFunctionFilter, load_nuclide) + Tally, MaterialFilter, EnergyFilter, EnergyFunctionFilter) import openmc.lib from .abc import ( ReactionRateHelper, NormalizationHelper, FissionYieldHelper) @@ -26,7 +26,6 @@ __all__ = ( "ConstantFissionYieldHelper", "FissionYieldCutoffHelper", "AveragedFissionYieldHelper", "FluxCollapseHelper") - class TalliedFissionYieldHelper(FissionYieldHelper): """Abstract class for computing fission yields with tallies @@ -160,53 +159,34 @@ class DirectReactionRateHelper(ReactionRateHelper): def generate_tallies(self, materials, scores): """Produce one-group reaction rate tally - Uses the :mod:`openmc.lib` to generate a tally of relevant reactions - across all burnable materials. + Uses the :mod:`openmc.lib` to generate a tally + of relevant reactions across all burnable materials. Parameters ---------- - materials : iterable of :class:`openmc.lib.Material` - Burnable materials in the problem. Used to construct a - :class:`openmc.lib.MaterialFilter` + materials : iterable of :class:`openmc.Material` + Burnable materials in the problem. Used to + construct a :class:`openmc.MaterialFilter` scores : iterable of str - Reaction identifiers, e.g. ``"(n, fission)"``, ``"(n, gamma)"``, - needed for the reaction rate tally. + Reaction identifiers, e.g. ``"(n, fission)"``, + ``"(n, gamma)"``, needed for the reaction rate tally. """ self._rate_tally = Tally() self._rate_tally.writable = False self._rate_tally.scores = scores self._rate_tally.filters = [MaterialFilter(materials)] - self._rate_tally.multiply_density = False - self._rate_tally_means_cache = None - @property - def rate_tally_means(self): - """The mean results of the tally of every material's reaction rates for this cycle - """ - # If the mean cache is empty, fill it once with this transport cycle's results - if self._rate_tally_means_cache is None: - self._rate_tally_means_cache = self._rate_tally.mean - return self._rate_tally_means_cache - - def reset_tally_means(self): - """Reset the cached mean rate tallies. - .. note:: - - This step must be performed after each transport cycle - """ - self._rate_tally_means_cache = None - - def get_material_rates(self, mat_index, nuc_index, rx_index): + def get_material_rates(self, mat_id, nuc_index, react_index): """Return an array of reaction rates for a material Parameters ---------- - mat_index : int - Index for the material + mat_id : int + Unique ID for the requested material nuc_index : iterable of int Index for each nuclide in :attr:`nuclides` in the desired reaction rate matrix - rx_index : iterable of int + react_index : iterable of int Index for each reaction scored in the tally Returns @@ -216,9 +196,10 @@ class DirectReactionRateHelper(ReactionRateHelper): reaction rates in this material """ self._results_cache.fill(0.0) - full_tally_res = self.rate_tally_means[mat_index] - for i_tally, (i_nuc, i_rx) in enumerate(product(nuc_index, rx_index)): - self._results_cache[i_nuc, i_rx] = full_tally_res[i_tally] + full_tally_res = self._rate_tally.mean[mat_id] + for i_tally, (i_nuc, i_react) in enumerate( + product(nuc_index, react_index)): + self._results_cache[i_nuc, i_react] = full_tally_res[i_tally] return self._results_cache @@ -268,11 +249,6 @@ class FluxCollapseHelper(ReactionRateHelper): if self._reactions_direct and self._nuclides_direct is None: self._rate_tally.nuclides = nuclides - # Make sure nuclide data is loaded - for nuclide in self.nuclides: - if nuclide not in openmc.lib.nuclides: - openmc.lib.load_nuclide(nuclide) - def generate_tallies(self, materials, scores): """Produce multigroup flux spectrum tally @@ -302,7 +278,6 @@ class FluxCollapseHelper(ReactionRateHelper): EnergyFilter(self._energies) ] self._flux_tally.scores = ['flux'] - self._flux_tally_means_cache = None # Create reaction rate tally if self._reactions_direct: @@ -310,43 +285,9 @@ class FluxCollapseHelper(ReactionRateHelper): self._rate_tally.writable = False self._rate_tally.scores = self._reactions_direct self._rate_tally.filters = [MaterialFilter(materials)] - self._rate_tally.multiply_density = False - self._rate_tally_means_cache = None if self._nuclides_direct is not None: - # check if any direct tally nuclides are requested that are not - # already loaded with the materials. Load separately if so. - mat_nuclides = {n for mat in materials for n in mat.nuclides} - extra_nuclides = set(self._nuclides_direct) - mat_nuclides - for nuc in extra_nuclides: - load_nuclide(nuc) self._rate_tally.nuclides = self._nuclides_direct - @property - def rate_tally_means(self): - """The mean results of the tally of every material's reaction rates for this cycle - """ - # If the mean cache is empty, fill it once with this transport cycle's results - if self._rate_tally_means_cache is None: - self._rate_tally_means_cache = self._rate_tally.mean - return self._rate_tally_means_cache - - @property - def flux_tally_means(self): - # If the mean cache is empty, fill it once for this transport cycle's results - if self._flux_tally_means_cache is None: - self._flux_tally_means_cache = self._flux_tally.mean - return self._flux_tally_means_cache - - def reset_tally_means(self): - """Reset the cached mean rate and flux tallies. - .. note:: - - This step must be performed after each transport cycle - """ - self._flux_tally_means_cache = None - if self._reactions_direct: - self._rate_tally_means_cache = None - def get_material_rates(self, mat_index, nuc_index, react_index): """Return an array of reaction rates for a material @@ -371,25 +312,31 @@ class FluxCollapseHelper(ReactionRateHelper): # Get flux for specified material shape = (len(self._materials), len(self._energies) - 1) - mean_value = self.flux_tally_means.reshape(shape) + mean_value = self._flux_tally.mean.reshape(shape) flux = mean_value[mat_index] # Get direct reaction rates if self._reactions_direct: nuclides_direct = self._rate_tally.nuclides shape = (len(nuclides_direct), len(self._reactions_direct)) - rx_rates = self.rate_tally_means[mat_index].reshape(shape) - direct_rx_index = {score: i for i, score in enumerate(self._reactions_direct)} - direct_nuc_index = {nuc: i for i, nuc in enumerate(nuclides_direct)} + rx_rates = self._rate_tally.mean[mat_index].reshape(shape) mat = self._materials[mat_index] + # Build nucname: density mapping to enable O(1) lookup in loop below + densities = dict(zip(mat.nuclides, mat.densities)) + for name, i_nuc in zip(self.nuclides, nuc_index): + # Determine density of nuclide + density = densities[name] + for mt, score, i_rx in zip(self._mts, self._scores, react_index): if score in self._reactions_direct and name in nuclides_direct: + # Determine index in rx_rates + i_rx_direct = self._reactions_direct.index(score) + i_nuc_direct = nuclides_direct.index(name) + # Get reaction rate from tally - i_rx_direct = direct_rx_index[score] - i_nuc_direct = direct_nuc_index[name] self._results_cache[i_nuc, i_rx] = rx_rates[i_nuc_direct, i_rx_direct] else: # Use flux to collapse reaction rate (per N) @@ -397,7 +344,8 @@ class FluxCollapseHelper(ReactionRateHelper): rate_per_nuc = nuc.collapse_rate( mt, mat.temperature, self._energies, flux) - self._results_cache[i_nuc, i_rx] = rate_per_nuc + # Multiply by density to get absolute reaction rate + self._results_cache[i_nuc, i_rx] = rate_per_nuc * density return self._results_cache @@ -594,6 +542,7 @@ class ConstantFissionYieldHelper(FissionYieldHelper): self._constant_yields[name] = yield_data continue # Specific energy not found, use closest energy + distances = [abs(energy - ene) for ene in nuc.yield_energies] min_E = min(nuc.yield_energies, key=lambda e: abs(e - energy)) self._constant_yields[name] = nuc.yield_data[min_E] diff --git a/openmc/deplete/independent_operator.py b/openmc/deplete/independent_operator.py index bdfc32763..200bc195e 100644 --- a/openmc/deplete/independent_operator.py +++ b/openmc/deplete/independent_operator.py @@ -1,13 +1,12 @@ """Transport-independent transport operator for depletion. This module implements a transport operator that runs independently of any -transport solver by using user-provided multigroup fluxes and cross sections. +transport solver by using user-provided one-group cross sections. """ -from __future__ import annotations -from collections.abc import Iterable import copy +from itertools import product import numpy as np from uncertainties import ufloat @@ -16,76 +15,79 @@ import openmc from openmc.checkvalue import check_type from openmc.mpi import comm from .abc import ReactionRateHelper, OperatorResult -from .openmc_operator import OpenMCOperator -from .pool import _distribute +from .openmc_operator import OpenMCOperator, _distribute from .microxs import MicroXS from .results import Results from .helpers import ChainFissionHelper, ConstantFissionYieldHelper, SourceRateHelper class IndependentOperator(OpenMCOperator): - """Transport-independent transport operator based on multigroup data. + """Transport-independent transport operator that uses one-group cross + sections to calculate reaction rates. - Instances of this class can be used to perform depletion using multigroup - cross sections and multigroup fluxes. Normally, a user needn't call methods - of this class directly. Instead, an instance of this class is passed to an - integrator class, such as :class:`openmc.deplete.CECMIntegrator`. - - Note that passing an empty :class:`~openmc.deplete.MicroXS` instance to the - ``micro_xs`` argument allows a decay-only calculation to be run. + Instances of this class can be used to perform depletion using one-group + cross sections and constant flux or constant power. Normally, a user needn't + call methods of this class directly. Instead, an instance of this class is + passed to an integrator class, such as + :class:`openmc.deplete.CECMIntegrator`. .. versionadded:: 0.13.1 - .. versionchanged:: 0.14.0 - Arguments updated to include list of fluxes and microscopic cross - sections. - Parameters ---------- - materials : iterable of openmc.Material + materials : openmc.Materials Materials to deplete. - fluxes : list of numpy.ndarray - Flux in each group in [n-cm/src] for each domain - micros : list of MicroXS - Cross sections in [b] for each domain. If the - :class:`~openmc.deplete.MicroXS` object is empty, a decay-only - calculation will be run. - chain_file : PathLike or Chain, optional - Path to the depletion chain XML file or instance of openmc.deplete.Chain. - Defaults to ``openmc.config['chain_file']``. + micro_xs : MicroXS + One-group microscopic cross sections in [b] . + chain_file : str + Path to the depletion chain XML file. keff : 2-tuple of float, optional keff eigenvalue and uncertainty from transport calculation. + Default is None. prev_results : Results, optional Results from a previous depletion calculation. normalization_mode : {"fission-q", "source-rate"} - Indicate how reaction rates should be calculated. ``"fission-q"`` uses - the fission Q values from the depletion chain to compute the flux based - on the power. ``"source-rate"`` uses a the source rate (assumed to be - neutron flux) to calculate the reaction rates. + Indicate how reaction rates should be calculated. + ``"fission-q"`` uses the fission Q values from the depletion chain to + compute the flux based on the power. ``"source-rate"`` uses a the + source rate (assumed to be neutron flux) to calculate the + reaction rates. fission_q : dict, optional Dictionary of nuclides and their fission Q values [eV]. If not given, - values will be pulled from the ``chain_file``. Only applicable if - ``"normalization_mode" == "fission-q"``. + values will be pulled from the ``chain_file``. Only applicable + if ``"normalization_mode" == "fission-q"``. + dilute_initial : float, optional + Initial atom density [atoms/cm^3] to add for nuclides that are zero + in initial condition to ensure they exist in the decay chain. + Only done for nuclides with reaction rates. + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the + depletion chain up to ``reduce_chain_level``. reduce_chain_level : int, optional - Depth of the search when reducing the depletion chain. The default - value of ``None`` implies no limit on the depth. + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. fission_yield_opts : dict of str to option, optional Optional arguments to pass to the :class:`openmc.deplete.helpers.FissionYieldHelper` object. Will be - passed directly on to the helper. Passing a value of None will use the - defaults for the associated helper. + passed directly on to the helper. Passing a value of None will use + the defaults for the associated helper. Attributes ---------- materials : openmc.Materials All materials present in the model - cross_sections : list of MicroXS - Object containing multigroup cross-sections in [b] for each material. + cross_sections : MicroXS + Object containing one-group cross-sections in [cm^2]. + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that + are zero in initial condition to ensure they exist in the decay + chain. Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. round_number : bool - Whether or not to round output to OpenMC to 8 digits. Useful in testing, - as OpenMC is incredibly sensitive to exact values. + Whether or not to round output to OpenMC to 8 digits. + Useful in testing, as OpenMC is incredibly sensitive to exact values. number : openmc.deplete.AtomNumber Total number of atoms in simulation. nuclides_with_data : set of str @@ -101,33 +103,26 @@ class IndependentOperator(OpenMCOperator): local_mats : list of str All burnable material IDs being managed by a single process prev_res : Results or None - Results from a previous depletion calculation. ``None`` if no results - are to be used. + Results from a previous depletion calculation. ``None`` if no + results are to be used. """ def __init__(self, materials, - fluxes, - micros, - chain_file=None, + micro_xs, + chain_file, keff=None, normalization_mode='fission-q', fission_q=None, + dilute_initial=1.0e3, prev_results=None, + reduce_chain=False, reduce_chain_level=None, fission_yield_opts=None): # Validate micro-xs parameters - check_type('materials', materials, Iterable, openmc.Material) - check_type('micros', micros, Iterable, MicroXS) - materials = openmc.Materials(materials) - - if not (len(fluxes) == len(micros) == len(materials)): - msg = (f'The length of fluxes ({len(fluxes)}) should be equal to ' - f'the length of micros ({len(micros)}) and the length of ' - f'materials ({len(materials)}).') - raise ValueError(msg) - + check_type('materials', materials, openmc.Materials) + check_type('micro_xs', micro_xs, MicroXS) if keff is not None: check_type('keff', keff, tuple, float) keff = ufloat(*keff) @@ -139,31 +134,29 @@ class IndependentOperator(OpenMCOperator): helper_kwargs = {'normalization_mode': normalization_mode, 'fission_yield_opts': fission_yield_opts} - # Sort fluxes and micros in same order that materials get sorted - index_sort = np.argsort([mat.id for mat in materials]) - fluxes = [fluxes[i] for i in index_sort] - micros = [micros[i] for i in index_sort] - - self.fluxes = fluxes + cross_sections = micro_xs * 1e-24 super().__init__( - materials=materials, - cross_sections=micros, - chain_file=chain_file, - prev_results=prev_results, + materials, + cross_sections, + chain_file, + prev_results, fission_q=fission_q, + dilute_initial=dilute_initial, helper_kwargs=helper_kwargs, + reduce_chain=reduce_chain, reduce_chain_level=reduce_chain_level) @classmethod def from_nuclides(cls, volume, nuclides, - flux, micro_xs, - chain_file=None, + chain_file, nuc_units='atom/b-cm', keff=None, normalization_mode='fission-q', fission_q=None, + dilute_initial=1.0e3, prev_results=None, + reduce_chain=False, reduce_chain_level=None, fission_yield_opts=None): """ @@ -174,15 +167,11 @@ class IndependentOperator(OpenMCOperator): nuclides : dict of str to float Dictionary with nuclide names as keys and nuclide concentrations as values. - flux : numpy.ndarray - Flux in each group in [n-cm/src] micro_xs : MicroXS - Cross sections in [b]. If the :class:`~openmc.deplete.MicroXS` - object is empty, a decay-only calculation will be run. - chain_file : PathLike or Chain, optional - Path to the depletion chain XML file or instance of - openmc.deplete.Chain. Defaults to ``openmc.config['chain_file']``. - nuc_units : {'atom/cm3', 'atom/b-cm'}, optional + One-group microscopic cross sections. + chain_file : str + Path to the depletion chain XML file. + nuc_units : {'atom/cm3', 'atom/b-cm'} Units for nuclide concentration. keff : 2-tuple of float, optional keff eigenvalue and uncertainty from transport calculation. @@ -197,11 +186,19 @@ class IndependentOperator(OpenMCOperator): Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Only applicable if ``"normalization_mode" == "fission-q"``. + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that + are zero in initial condition to ensure they exist in the decay + chain. Only done for nuclides with reaction rates. prev_results : Results, optional Results from a previous depletion calculation. + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the + depletion chain up to ``reduce_chain_level``. Default is False. reduce_chain_level : int, optional - Depth of the search when reducing the depletion chain. The default - value of ``None`` implies no limit on the depth. + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. fission_yield_opts : dict of str to option, optional Optional arguments to pass to the :class:`openmc.deplete.helpers.FissionYieldHelper` class. Will be @@ -211,24 +208,25 @@ class IndependentOperator(OpenMCOperator): """ check_type('nuclides', nuclides, dict, str) materials = cls._consolidate_nuclides_to_material(nuclides, nuc_units, volume) - fluxes = [flux] - micros = [micro_xs] return cls(materials, - fluxes, - micros, + micro_xs, chain_file, keff=keff, normalization_mode=normalization_mode, fission_q=fission_q, + dilute_initial=dilute_initial, prev_results=prev_results, + reduce_chain=reduce_chain, reduce_chain_level=reduce_chain_level, fission_yield_opts=fission_yield_opts) + @staticmethod def _consolidate_nuclides_to_material(nuclides, nuc_units, volume): """Puts nuclide list into an openmc.Materials object. """ + openmc.reset_auto_ids() mat = openmc.Material() if nuc_units == 'atom/b-cm': for nuc, conc in nuclides.items(): @@ -251,6 +249,7 @@ class IndependentOperator(OpenMCOperator): self.prev_res[-1].transfer_volumes(model) self.materials = model.materials + # Store previous results in operator # Distribute reaction rates according to those tracked # on this process @@ -262,27 +261,16 @@ class IndependentOperator(OpenMCOperator): new_res = res_obj.distribute(self.local_mats, mat_indexes) self.prev_res.append(new_res) - def _get_nuclides_with_data(self, cross_sections: list[MicroXS]) -> set[str]: - """Finds nuclides with cross section data - Parameters - ---------- - cross_sections : iterable of :class`~openmc.deplete.MicroXS` - List of multigroup cross-section data. - - Returns - ------- - nuclides : set of str - Set of nuclide names that have cross section data - - """ - return set(cross_sections[0].nuclides) + def _get_nuclides_with_data(self, cross_sections): + """Finds nuclides with cross section data""" + return set(cross_sections.index) class _IndependentRateHelper(ReactionRateHelper): - """Class for generating reaction rates with multigroup fluxes and - multigroup cross sections. + """Class for generating one-group reaction rates with flux and + one-group cross sections. - This class does not generate tallies and instead stores cross sections + This class does not generate tallies, and instead stores cross sections for each nuclide and transmutation reaction relevant for a depletion calculation. The reaction rate is calculated by multiplying the flux by the cross sections. @@ -298,34 +286,30 @@ class IndependentOperator(OpenMCOperator): ---------- nuc_ind_map : dict of int to str Dictionary mapping the nuclide index to nuclide name - rx_ind_map : dict of int to str + rxn_ind_map : dict of int to str Dictionary mapping reaction index to reaction name """ - def __init__(self, op: IndependentOperator): + def __init__(self, op): rates = op.reaction_rates super().__init__(rates.n_nuc, rates.n_react) self.nuc_ind_map = {ind: nuc for nuc, ind in rates.index_nuc.items()} - self.rx_ind_map = {ind: rxn for rxn, ind in rates.index_rx.items()} + self.rxn_ind_map = {ind: rxn for rxn, ind in rates.index_rx.items()} self._op = op def generate_tallies(self, materials, scores): """Unused in this case""" pass - def reset_tally_means(self): - """Unused in this case""" - pass - - def get_material_rates(self, mat_index, nuc_index, react_index): + def get_material_rates(self, mat_id, nuc_index, react_index): """Return 2D array of [nuclide, reaction] reaction rates Parameters ---------- - mat_index : int - Index for the material + mat_id : int + Unique ID for the requested material nuc_index : list of str Ordering of desired nuclides react_index : list of str @@ -333,22 +317,14 @@ class IndependentOperator(OpenMCOperator): """ self._results_cache.fill(0.0) - # Get flux and microscopic cross sections from operator - flux = self._op.fluxes[mat_index] - xs = self._op.cross_sections[mat_index] - - for i_nuc in nuc_index: + for i_nuc, i_react in product(nuc_index, react_index): nuc = self.nuc_ind_map[i_nuc] - if nuc not in xs._index_nuc: - continue - for i_rx in react_index: - rx = self.rx_ind_map[i_rx] - if rx not in xs._index_rx: - continue + rxn = self.rxn_ind_map[i_react] - # Determine reaction rate by multiplying xs in [b] by flux - # in [n-cm/src] to give [(reactions/src)*b-cm/atom] - self._results_cache[i_nuc, i_rx] = (xs[nuc, rx] * flux).sum() + # Sigma^j_i * V = sigma^j_i * n_i * V = sigma^j_i * N_i + self._results_cache[i_nuc,i_react] = \ + self._op.cross_sections[rxn][nuc] * \ + self._op.number[mat_id, nuc] return self._results_cache @@ -388,7 +364,7 @@ class IndependentOperator(OpenMCOperator): # Return number density vector return super().initial_condition(self.materials) - def __call__(self, vec, source_rate) -> OperatorResult: + def __call__(self, vec, source_rate): """Obtain the reaction rates Parameters @@ -407,12 +383,6 @@ class IndependentOperator(OpenMCOperator): self._update_materials_and_nuclides(vec) - # If the source rate is zero, return zero reaction rates - if source_rate == 0.0: - rates = self.reaction_rates.copy() - rates.fill(0.0) - return OperatorResult(ufloat(0.0, 0.0), rates) - rates = self._calculate_reaction_rates(source_rate) keff = self._keff diff --git a/openmc/deplete/integrators.py b/openmc/deplete/integrators.py index 25e64cb2e..74a3cebdb 100644 --- a/openmc/deplete/integrators.py +++ b/openmc/deplete/integrators.py @@ -22,36 +22,39 @@ class PredictorIntegrator(Integrator): .. math:: \mathbf{n}_{i+1} = \exp\left(h\mathbf{A}(\mathbf{n}_i) \right) \mathbf{n}_i + """ _num_stages = 1 - def __call__(self, n, rates, dt, source_rate, _i=None): + def __call__(self, conc, rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - n : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float Time in [s] for the entire depletion interval source_rate : float Power in [W] or source rate in [neutron/sec] - _i : int, optional - Current iteration count. Not used + _i : int or None + Iteration index. Not used Returns ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray + conc_list : list of numpy.ndarray Concentrations at end of interval + op_results : empty list + Kept for consistency with API. No intermediate calls to + operator with predictor """ - proc_time, n_end = self._timed_deplete(n, rates, dt, _i) - return proc_time, n_end + proc_time, conc_end = self._timed_deplete(conc, rates, dt) + return proc_time, [conc_end], [] @add_params @@ -74,14 +77,13 @@ class CECMIntegrator(Integrator): """ _num_stages = 2 - def __call__(self, n, rates, dt, source_rate, _i=None): + def __call__(self, conc, rates, dt, source_rate, _i=None): """Integrate using CE/CM Parameters ---------- - n : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -95,18 +97,21 @@ class CECMIntegrator(Integrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult + Eigenvalue and reaction rates from transport simulations """ # deplete across first half of interval - time0, n_middle = self._timed_deplete(n, rates, dt / 2, _i) - res_middle = self.operator(n_middle, source_rate) + time0, x_middle = self._timed_deplete(conc, rates, dt / 2) + res_middle = self.operator(x_middle, source_rate) # deplete across entire interval with BOS concentrations, # MOS reaction rates - time1, n_end = self._timed_deplete(n, res_middle.rates, dt, _i) + time1, x_end = self._timed_deplete(conc, res_middle.rates, dt) - return time0 + time1, n_end + return time0 + time1, [x_middle, x_end], [res_middle] @add_params @@ -130,19 +135,18 @@ class CF4Integrator(Integrator): \mathbf{n}_{i+1} &= \exp \left ( \frac{\mathbf{A}_1}{4} + \frac{\mathbf{A}_2}{6} + \frac{\mathbf{A}_3}{6} - \frac{\mathbf{A}_4}{12} \right ) \exp \left ( -\frac{\mathbf{A}_1}{12} + \frac{\mathbf{A}_2}{6} + - \frac{\mathbf{A}_3}{6} + \frac{\mathbf{A}_4}{4} \right ) \mathbf{n}_i. + \frac{\mathbf{A}_3}{6} - \frac{\mathbf{A}_4}{4} \right ) \mathbf{n}_i. \end{aligned} """ _num_stages = 4 - def __call__(self, n_bos, bos_rates, dt, source_rate, _i=None): + def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - n_bos : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + bos_conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] bos_rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -156,33 +160,39 @@ class CF4Integrator(Integrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult + Eigenvalue and reaction rates from intermediate transport + simulations """ # Step 1: deplete with matrix 1/2*A(y0) - time1, n_eos1 = self._timed_deplete( - n_bos, bos_rates, dt, _i, matrix_func=cf4_f1) - res1 = self.operator(n_eos1, source_rate) + time1, conc_eos1 = self._timed_deplete( + bos_conc, bos_rates, dt, matrix_func=cf4_f1) + res1 = self.operator(conc_eos1, source_rate) # Step 2: deplete with matrix 1/2*A(y1) - time2, n_eos2 = self._timed_deplete( - n_bos, res1.rates, dt, _i, matrix_func=cf4_f1) - res2 = self.operator(n_eos2, source_rate) + time2, conc_eos2 = self._timed_deplete( + bos_conc, res1.rates, dt, matrix_func=cf4_f1) + res2 = self.operator(conc_eos2, source_rate) # Step 3: deplete with matrix -1/2*A(y0)+A(y2) list_rates = list(zip(bos_rates, res2.rates)) - time3, n_eos3 = self._timed_deplete( - n_eos1, list_rates, dt, _i, matrix_func=cf4_f2) - res3 = self.operator(n_eos3, source_rate) + time3, conc_eos3 = self._timed_deplete( + conc_eos1, list_rates, dt, matrix_func=cf4_f2) + res3 = self.operator(conc_eos3, source_rate) # Step 4: deplete with two matrix exponentials list_rates = list(zip(bos_rates, res1.rates, res2.rates, res3.rates)) - time4, n_inter = self._timed_deplete( - n_bos, list_rates, dt, _i, matrix_func=cf4_f3) - time5, n_eos5 = self._timed_deplete( - n_inter, list_rates, dt, _i, matrix_func=cf4_f4) + time4, conc_inter = self._timed_deplete( + bos_conc, list_rates, dt, matrix_func=cf4_f3) + time5, conc_eos5 = self._timed_deplete( + conc_inter, list_rates, dt, matrix_func=cf4_f4) - return time1 + time2 + time3 + time4 + time5, n_eos5 + return (time1 + time2 + time3 + time4 + time5, + [conc_eos1, conc_eos2, conc_eos3, conc_eos5], + [res1, res2, res3]) @add_params @@ -207,14 +217,13 @@ class CELIIntegrator(Integrator): """ _num_stages = 2 - def __call__(self, n_bos, rates, dt, source_rate, _i=None): + def __call__(self, bos_conc, rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - n_bos : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + bos_conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -228,23 +237,27 @@ class CELIIntegrator(Integrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult + Eigenvalue and reaction rates from intermediate transport + simulation """ # deplete to end using BOS rates - proc_time, n_ce = self._timed_deplete(n_bos, rates, dt, _i) - res_ce = self.operator(n_ce, source_rate) + proc_time, conc_ce = self._timed_deplete(bos_conc, rates, dt) + res_ce = self.operator(conc_ce, source_rate) # deplete using two matrix exponentials list_rates = list(zip(rates, res_ce.rates)) - time_le1, n_inter = self._timed_deplete( - n_bos, list_rates, dt, _i, matrix_func=celi_f1) + time_le1, conc_inter = self._timed_deplete( + bos_conc, list_rates, dt, matrix_func=celi_f1) - time_le2, n_end = self._timed_deplete( - n_inter, list_rates, dt, _i, matrix_func=celi_f2) + time_le2, conc_end = self._timed_deplete( + conc_inter, list_rates, dt, matrix_func=celi_f2) - return proc_time + time_le1 + time_le2, n_end + return proc_time + time_le1 + time_le1, [conc_ce, conc_end], [res_ce] @add_params @@ -269,14 +282,13 @@ class EPCRK4Integrator(Integrator): """ _num_stages = 4 - def __call__(self, n, rates, dt, source_rate, _i=None): + def __call__(self, conc, rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - n : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -290,27 +302,35 @@ class EPCRK4Integrator(Integrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult + Eigenvalue and reaction rates from intermediate transport + simulations """ # Step 1: deplete with matrix A(y0) / 2 - time1, n1 = self._timed_deplete(n, rates, dt, _i, matrix_func=rk4_f1) - res1 = self.operator(n1, source_rate) + time1, conc1 = self._timed_deplete( + conc, rates, dt, matrix_func=rk4_f1) + res1 = self.operator(conc1, source_rate) # Step 2: deplete with matrix A(y1) / 2 - time2, n2 = self._timed_deplete(n, res1.rates, dt, _i, matrix_func=rk4_f1) - res2 = self.operator(n2, source_rate) + time2, conc2 = self._timed_deplete( + conc, res1.rates, dt, matrix_func=rk4_f1) + res2 = self.operator(conc2, source_rate) # Step 3: deplete with matrix A(y2) - time3, n3 = self._timed_deplete(n, res2.rates, dt, _i) - res3 = self.operator(n3, source_rate) + time3, conc3 = self._timed_deplete(conc, res2.rates, dt) + res3 = self.operator(conc3, source_rate) # Step 4: deplete with matrix built from weighted rates list_rates = list(zip(rates, res1.rates, res2.rates, res3.rates)) - time4, n4 = self._timed_deplete(n, list_rates, dt, _i, matrix_func=rk4_f4) + time4, conc4 = self._timed_deplete( + conc, list_rates, dt, matrix_func=rk4_f4) - return time1 + time2 + time3 + time4, n4 + return (time1 + time2 + time3 + time4, [conc1, conc2, conc3, conc4], + [res1, res2, res3]) @add_params @@ -339,7 +359,8 @@ class LEQIIntegrator(Integrator): h_i)} \mathbf{A}_0 + \frac{h_{i-1}}{12 (h_{i-1} + h_i)} \mathbf{A}_1 \\ \mathbf{F}_4 &= \frac{-h_i^2}{12 h_{i-1} (h_{i-1} + h_i)} \mathbf{A}_{-1} + \frac{h_{i-1}^2 + 2 h_i h_{i-1} + h_i^2}{12 h_{i-1} (h_{i-1} + h_i)} - \mathbf{A}_0 + \frac{5 h_{i-1} + 4 h_i}{12 (h_{i-1} + h_i)} \mathbf{A}_1 \\ + \mathbf{A}_0 + \frac{5 h_{i-1}^2 + 4 h_i h_{i-1}}{12 h_{i-1} + (h_{i-1} + h_i)} \mathbf{A}_1 \\ \mathbf{n}_{i+1} &= \exp(h_i \mathbf{F}_4) \exp(h_i \mathbf{F}_3) \mathbf{n}_i \end{aligned} @@ -347,15 +368,14 @@ class LEQIIntegrator(Integrator): """ _num_stages = 2 - def __call__(self, n_bos, bos_rates, dt, source_rate, i): + def __call__(self, bos_conc, bos_rates, dt, source_rate, i): """Perform the integration across one time step Parameters ---------- - n_bos : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. - bos_rates : openmc.deplete.ReactionRates + conc : numpy.ndarray + Initial concentrations for all nuclides in [atom] + rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float Time in [s] for the entire depletion interval @@ -368,46 +388,52 @@ class LEQIIntegrator(Integrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult + Eigenvalue and reaction rates from intermediate transport + simulation """ if i == 0: if self._i_res < 1: # need at least previous transport solution self._prev_rates = bos_rates return CELIIntegrator.__call__( - self, n_bos, bos_rates, dt, source_rate, i) + self, bos_conc, bos_rates, dt, source_rate, i) prev_res = self.operator.prev_res[-2] prev_dt = self.timesteps[i] - prev_res.time[0] - self._prev_rates = prev_res.rates + self._prev_rates = prev_res.rates[0] else: prev_dt = self.timesteps[i - 1] # Remaining LE/QI - bos_res = self.operator(n_bos, source_rate) + bos_res = self.operator(bos_conc, source_rate) le_inputs = list(zip( self._prev_rates, bos_res.rates, repeat(prev_dt), repeat(dt))) - time1, n_inter = self._timed_deplete( - n_bos, le_inputs, dt, i, matrix_func=leqi_f1) - time2, n_eos0 = self._timed_deplete( - n_inter, le_inputs, dt, i, matrix_func=leqi_f2) + time1, conc_inter = self._timed_deplete( + bos_conc, le_inputs, dt, matrix_func=leqi_f1) + time2, conc_eos0 = self._timed_deplete( + conc_inter, le_inputs, dt, matrix_func=leqi_f2) - res_inter = self.operator(n_eos0, source_rate) + res_inter = self.operator(conc_eos0, source_rate) qi_inputs = list(zip( self._prev_rates, bos_res.rates, res_inter.rates, repeat(prev_dt), repeat(dt))) - time3, n_inter = self._timed_deplete( - n_bos, qi_inputs, dt, i, matrix_func=leqi_f3) - time4, n_eos1 = self._timed_deplete( - n_inter, qi_inputs, dt, i, matrix_func=leqi_f4) + time3, conc_inter = self._timed_deplete( + bos_conc, qi_inputs, dt, matrix_func=leqi_f3) + time4, conc_eos1 = self._timed_deplete( + conc_inter, qi_inputs, dt, matrix_func=leqi_f4) # store updated rates self._prev_rates = copy.deepcopy(bos_res.rates) - return time1 + time2 + time3 + time4, n_eos1 + return ( + time1 + time2 + time3 + time4, [conc_eos0, conc_eos1], + [bos_res, res_inter]) @add_params @@ -419,18 +445,17 @@ class SICELIIntegrator(SIIntegrator): `_. Detailed algorithm can be found in section 3.2 in `Colin Josey's thesis - `_. + `_. """ _num_stages = 2 - def __call__(self, n_bos, bos_rates, dt, source_rate, _i=None): + def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - n_bos : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + bos_conc : numpy.ndarray + Initial bos_concentrations for all nuclides in [atom] bos_rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -444,18 +469,19 @@ class SICELIIntegrator(SIIntegrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval - op_result : openmc.deplete.OperatorResult + bos_conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final bos_concentration as the last element + op_results : list of openmc.deplete.OperatorResult Eigenvalue and reaction rates from intermediate transport simulations """ - proc_time, n_eos = self._timed_deplete(n_bos, bos_rates, dt, _i) - n_inter = copy.deepcopy(n_eos) + proc_time, eos_conc = self._timed_deplete(bos_conc, bos_rates, dt) + inter_conc = copy.deepcopy(eos_conc) # Begin iteration for j in range(self.n_steps + 1): - inter_res = self.operator(n_inter, source_rate) + inter_res = self.operator(inter_conc, source_rate) if j <= 1: res_bar = copy.deepcopy(inter_res) @@ -465,14 +491,14 @@ class SICELIIntegrator(SIIntegrator): res_bar = OperatorResult(k, rates) list_rates = list(zip(bos_rates, res_bar.rates)) - time1, n_inter = self._timed_deplete( - n_bos, list_rates, dt, _i, matrix_func=celi_f1) - time2, n_inter = self._timed_deplete( - n_inter, list_rates, dt, _i, matrix_func=celi_f2) + time1, inter_conc = self._timed_deplete( + bos_conc, list_rates, dt, matrix_func=celi_f1) + time2, inter_conc = self._timed_deplete( + inter_conc, list_rates, dt, matrix_func=celi_f2) proc_time += time1 + time2 # end iteration - return proc_time, n_inter, res_bar + return proc_time, [eos_conc, inter_conc], [res_bar] @add_params @@ -484,18 +510,18 @@ class SILEQIIntegrator(SIIntegrator): `_. Detailed algorithm can be found in Section 3.2 in `Colin Josey's thesis - `_. + `_. """ _num_stages = 2 - def __call__(self, n_bos, bos_rates, dt, source_rate, i): + def __call__(self, bos_conc, bos_rates, dt, source_rate, i): """Perform the integration across one time step Parameters ---------- - n_bos : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + bos_conc : list of numpy.ndarray + Initial concentrations for all nuclides in [atom] for + all depletable materials bos_rates : list of openmc.deplete.ReactionRates Reaction rates from operator for all depletable materials dt : float @@ -509,9 +535,10 @@ class SILEQIIntegrator(SIIntegrator): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - n_end : list of numpy.ndarray - Concentrations at end of interval - op_result : openmc.deplete.OperatorResult + conc_list : list of numpy.ndarray + Concentrations at each of the intermediate points with + the final concentration as the last element + op_results : list of openmc.deplete.OperatorResult Eigenvalue and reaction rates from intermediate transport simulation """ @@ -520,26 +547,26 @@ class SILEQIIntegrator(SIIntegrator): self._prev_rates = bos_rates # Perform CELI for initial steps return SICELIIntegrator.__call__( - self, n_bos, bos_rates, dt, source_rate, i) + self, bos_conc, bos_rates, dt, source_rate, i) prev_res = self.operator.prev_res[-2] prev_dt = self.timesteps[i] - prev_res.time[0] - self._prev_rates = prev_res.rates + self._prev_rates = prev_res.rates[0] else: prev_dt = self.timesteps[i - 1] # Perform remaining LE/QI inputs = list(zip(self._prev_rates, bos_rates, repeat(prev_dt), repeat(dt))) - proc_time, n_inter = self._timed_deplete( - n_bos, inputs, dt, i, matrix_func=leqi_f1) - time1, n_eos = self._timed_deplete( - n_inter, inputs, dt, i, matrix_func=leqi_f2) + proc_time, inter_conc = self._timed_deplete( + bos_conc, inputs, dt, matrix_func=leqi_f1) + time1, eos_conc = self._timed_deplete( + inter_conc, inputs, dt, matrix_func=leqi_f2) proc_time += time1 - n_inter = copy.deepcopy(n_eos) + inter_conc = copy.deepcopy(eos_conc) for j in range(self.n_steps + 1): - inter_res = self.operator(n_inter, source_rate) + inter_res = self.operator(inter_conc, source_rate) if j <= 1: res_bar = copy.deepcopy(inter_res) @@ -550,16 +577,13 @@ class SILEQIIntegrator(SIIntegrator): inputs = list(zip(self._prev_rates, bos_rates, res_bar.rates, repeat(prev_dt), repeat(dt))) - time1, n_inter = self._timed_deplete( - n_bos, inputs, dt, i, matrix_func=leqi_f3) - time2, n_inter = self._timed_deplete( - n_inter, inputs, dt, i, matrix_func=leqi_f4) + time1, inter_conc = self._timed_deplete( + bos_conc, inputs, dt, matrix_func=leqi_f3) + time2, inter_conc = self._timed_deplete( + inter_conc, inputs, dt, matrix_func=leqi_f4) proc_time += time1 + time2 - # Store updated rates for next step - self._prev_rates = copy.deepcopy(bos_rates) - - return proc_time, n_inter, res_bar + return proc_time, [eos_conc, inter_conc], [res_bar] integrator_by_name = { diff --git a/openmc/deplete/keff_search_control.py b/openmc/deplete/keff_search_control.py deleted file mode 100644 index 49f7cc4df..000000000 --- a/openmc/deplete/keff_search_control.py +++ /dev/null @@ -1,128 +0,0 @@ -from typing import Callable -from warnings import warn - -import openmc.lib - - -class _KeffSearchControl: - """Controller for keff search during depletion calculations. - - This class performs keff searches to maintain a target keff by adjusting a - model parameter through a provided function. - - Parameters - ---------- - operator : openmc.deplete.Operator - Depletion operator instance - function : Callable - Function that modifies the model based on a parameter value - x0 : float - Initial lower bound for the keff search - x1 : float - Initial upper bound for the keff search - bracket : list[float] - Absolute bracketing interval lower and upper. If the keff search - solution lies off these limits the closest limit will be set as new - result. - **search_kwargs : dict, optional - Additional keyword arguments to pass to :meth:`openmc.Model.keff_search` - - """ - def __init__(self, operator, function: Callable, x0: float, x1: float, bracket: list[float], **search_kwargs): - if len(bracket) != 2: - raise ValueError(f"bracket must have exactly 2 elements, got {len(bracket)}") - if bracket[0] >= bracket[1]: - raise ValueError(f"bracket[0] must be < bracket[1], got {bracket}") - self.x0 = x0 - self.x1 = x1 - self.operator = operator - self.function = function - self.search_kwargs = search_kwargs - self.search_kwargs['x_min'] = bracket[0] - self.search_kwargs['x_max'] = bracket[1] - - def run(self, x): - """Perform keff search and update the atom density vector. - - Parameters - ---------- - x : list of numpy.ndarray - Current atom density vector (atoms per material) - - Returns - ------- - root : float - Parameter value that achieves target keff - """ - root = self._search_for_keff() - self._update_vec(x) - return root - - def _search_for_keff(self) -> float: - """Perform the keff search using the model's keff_search method. - - Returns - ------- - float - Parameter value that achieves target keff - - Raises - ------ - ValueError - If the keff search fails to converge - """ - with openmc.lib.TemporarySession(self.operator.model): - # Only pass the first 3 required args plus explicitly provided kwargs - result = self.operator.model.keff_search( - self.function, self.x0, self.x1, **self.search_kwargs - ) - if not result.converged: - raise ValueError( - f"Search for keff failed to converge. " - f"Termination reason: {result.flag}" - ) - - root = result.root - - # Check if root is outside the bracket bounds and give a warning - if root < self.search_kwargs['x_min']: - warn(f"keff search result ({root:.6f}) is below the lower bracket " - f"bound ({self.search_kwargs['x_min']:.6f}).", UserWarning) - elif root > self.search_kwargs['x_max']: - warn(f"keff search result ({root:.6f}) is above the upper bracket " - f"bound ({self.search_kwargs['x_max']:.6f}).", UserWarning) - - # Restore the number of initial batches - openmc.lib.settings.set_batches(self.operator.model.settings.batches) - - return root - - def _update_vec(self, x): - """Update the atom density vector from openmc.lib.materials and AtomNumber object. - - The depletion vector ``x`` is rank-local, matching the materials owned - by ``self.operator.number`` on the current MPI rank. We therefore only - update entries for locally owned materials using the compositions - currently stored in ``openmc.lib.materials``. - - Parameters - ---------- - x : list of numpy.ndarray - Atom density vector to update (atoms per material) - - """ - number = self.operator.number - - for mat_idx, mat in enumerate(number.materials): - lib_material = openmc.lib.materials[int(mat)] - nuclides = lib_material.nuclides - densities = 1e24 * lib_material.densities - volume = number.get_mat_volume(mat) - - for nuc_idx, nuc in enumerate(number.burnable_nuclides): - if nuc in nuclides: - lib_nuc_idx = nuclides.index(nuc) - atom_density = densities[lib_nuc_idx] - else: - atom_density = number.get_atom_density(mat, nuc) - x[mat_idx][nuc_idx] = atom_density * volume diff --git a/openmc/deplete/microxs.py b/openmc/deplete/microxs.py index 7049f7d31..72d87d3b7 100644 --- a/openmc/deplete/microxs.py +++ b/openmc/deplete/microxs.py @@ -1,490 +1,212 @@ """MicroXS module -A class for storing microscopic cross section data that can be used with the -IndependentOperator class for depletion. +A pandas.DataFrame storing microscopic cross section data with +nuclide names as row indices and reaction names as column indices. """ -from __future__ import annotations -from collections.abc import Sequence -import shutil -from tempfile import TemporaryDirectory -from typing import Union, TypeAlias, Self +import tempfile +from pathlib import Path +from copy import deepcopy -import h5py -import pandas as pd +from pandas import DataFrame, read_csv, concat import numpy as np -from openmc.checkvalue import check_type, check_value, check_iterable_type, PathLike -from openmc import StatePoint -from openmc.mgxs import GROUP_STRUCTURES -from openmc.data import REACTION_MT -import openmc -from .chain import Chain, REACTIONS, _get_chain +from openmc.checkvalue import check_type, check_value, check_iterable_type +from openmc.mgxs import EnergyGroups, ArbitraryXS, FissionXS +from openmc.data import DataLibrary +from openmc import Tallies, StatePoint, Materials, Material + + +from .chain import Chain, REACTIONS from .coupled_operator import _find_cross_sections, _get_nuclides_with_data -from ..utility_funcs import h5py_file_or_group -import openmc.lib -from openmc.mpi import comm _valid_rxns = list(REACTIONS) _valid_rxns.append('fission') -_valid_rxns.append('damage-energy') -# TODO: Replace with type statement when support is Python 3.12+ -DomainTypes: TypeAlias = Union[ - Sequence[openmc.Material], - Sequence[openmc.Cell], - Sequence[openmc.Universe], - openmc.MeshBase, - openmc.Filter, - Sequence[openmc.Filter] -] - - -def get_microxs_and_flux( - model: openmc.Model, - domains: DomainTypes, - nuclides: Sequence[str] | None = None, - reactions: Sequence[str] | None = None, - energies: Sequence[float] | str | None = None, - reaction_rate_mode: str = 'direct', - chain_file: PathLike | Chain | None = None, - path_statepoint: PathLike | None = None, - path_input: PathLike | None = None, - run_kwargs=None, - reaction_rate_opts: dict | None = None, -) -> tuple[list[np.ndarray], list[MicroXS]]: - """Generate microscopic cross sections and fluxes for multiple domains. - - This function runs a neutron transport solve to obtain the flux and reaction - rates in the specified domains and computes multigroup microscopic cross - sections that can be used in depletion calculations with the - :class:`~openmc.deplete.IndependentOperator` class. - - .. versionadded:: 0.14.0 - - .. versionchanged:: 0.15.3 - Added `reaction_rate_mode`, `path_statepoint`, `path_input` arguments. - - Parameters - ---------- - model : openmc.Model - OpenMC model object. Must contain geometry, materials, and settings. - domains : list of openmc.Material or openmc.Cell or openmc.Universe, or openmc.MeshBase, or openmc.Filter, or list of openmc.Filter - Domains in which to tally reaction rates, or a spatial tally filter. - A list of filters can be provided to create one set of tallies per - filter (e.g., one :class:`~openmc.MeshMaterialFilter` per mesh) that - are all evaluated in a single transport solve. Results are - concatenated across all filters in order. - nuclides : list of str - Nuclides to get cross sections for. If not specified, all burnable - nuclides from the depletion chain file are used. - reactions : list of str - Reactions to get cross sections for. If not specified, all neutron - reactions listed in the depletion chain file are used. - energies : iterable of float or str - Energy group boundaries in [eV] or the name of the group structure. - If left as None, no energy filter is applied to the flux tally. When - `reaction_rate_mode` is "direct", these boundaries define the output - flux and microscopic cross section energy group structure. When - `reaction_rate_mode` is "flux", these boundaries define the multigroup - flux tally used to collapse continuous-energy cross sections; returned - fluxes and microscopic cross sections are one-group. - reaction_rate_mode : {"direct", "flux"}, optional - The "direct" method tallies reaction rates directly (per energy - group). The "flux" method tallies a multigroup flux spectrum and then - collapses reaction rates after a transport solve. When - `reaction_rate_opts` is provided with `reaction_rate_mode='flux'`, the - specified nuclide/reaction pairs are tallied directly and those values - override the flux-collapsed values. - chain_file : PathLike or Chain, optional - Path to the depletion chain XML file or an instance of - openmc.deplete.Chain. Used to determine cross sections for materials not - present in the inital composition. Defaults to - ``openmc.config['chain_file']``. - path_statepoint : path-like, optional - Path to write the statepoint file from the neutron transport solve to. - By default, The statepoint file is written to a temporary directory and - is not kept. - path_input : path-like, optional - Path to write the model XML file from the neutron transport solve to. - By default, the model XML file is written to a temporary directory and - not kept. - run_kwargs : dict, optional - Keyword arguments passed to :meth:`openmc.Model.run` - reaction_rate_opts : dict, optional - When `reaction_rate_mode="flux"`, allows selecting a subset of - nuclide/reaction pairs to be computed via direct reaction-rate tallies - over one energy bin spanning the full `energies` range. Supported keys: - "nuclides", "reactions". If "reactions" are specified without - "nuclides", all selected nuclides are used. - - Returns - ------- - list of numpy.ndarray - Flux in each group in [n-cm/src] for each domain - list of MicroXS - Cross section data in [b] for each domain - - See Also - -------- - openmc.deplete.IndependentOperator - - """ - check_value('reaction_rate_mode', reaction_rate_mode, {'direct', 'flux'}) - - # Save any original tallies on the model - original_tallies = list(model.tallies) - - # Determine what reactions and nuclides are available in chain - chain = _get_chain(chain_file) - if reactions is None: - reactions = chain.reactions - if not nuclides: - cross_sections = _find_cross_sections(model) - nuclides_with_data = _get_nuclides_with_data(cross_sections) - nuclides = [nuc.name for nuc in chain.nuclides - if nuc.name in nuclides_with_data] - - # Set up the reaction rate and flux tallies. When energies are omitted, no - # energy filter is needed for the transport calculation. A one-group energy - # range is still needed later if flux collapse is requested. - collapse_energies = energies - if energies is None: - energy_filter = None - collapse_energies = [0.0, 100.0e6] - elif isinstance(energies, str): - energy_filter = openmc.EnergyFilter.from_group_structure(energies) - else: - energy_filter = openmc.EnergyFilter(energies) - - # Build list of domain filters - if isinstance(domains, openmc.Filter): - domain_filters = [domains] - elif isinstance(domains, openmc.MeshBase): - domain_filters = [openmc.MeshFilter(domains)] - elif isinstance(domains, Sequence) and len(domains) > 0 and \ - isinstance(domains[0], openmc.Filter): - domain_filters = list(domains) - elif isinstance(domains[0], openmc.Material): - domain_filters = [openmc.MaterialFilter(domains)] - elif isinstance(domains[0], openmc.Cell): - domain_filters = [openmc.CellFilter(domains)] - elif isinstance(domains[0], openmc.Universe): - domain_filters = [openmc.UniverseFilter(domains)] - else: - raise ValueError(f"Unsupported domain type: {type(domains[0])}") - - # Prepare reaction-rate nuclides/reactions - rr_nuclides: list[str] = [] - rr_reactions: list[str] = [] - if reaction_rate_mode == 'direct': - rr_nuclides = list(nuclides) - rr_reactions = list(reactions) - elif reaction_rate_mode == 'flux' and reaction_rate_opts: - opts = reaction_rate_opts or {} - rr_reactions = list(opts.get('reactions', [])) - if rr_reactions: - rr_nuclides = list(opts.get('nuclides', nuclides)) - else: - rr_nuclides = list(opts.get('nuclides', [])) - # Keep only requested pairs within overall sets - if rr_nuclides: - rr_nuclides = [n for n in rr_nuclides if n in set(nuclides)] - if rr_reactions: - rr_reactions = [r for r in rr_reactions if r in set(reactions)] - - # Use 1-group energy filter for RR in flux mode - has_rr = bool(rr_nuclides and rr_reactions) - if has_rr and reaction_rate_mode == 'flux' and energy_filter is not None: - rr_energy_filter = openmc.EnergyFilter( - [energy_filter.values[0], energy_filter.values[-1]]) - else: - rr_energy_filter = energy_filter - - # Create one flux tally (and optionally one RR tally) per domain filter. - flux_tallies = [] - rr_tallies = [] - model.tallies = [] - for i, domain_filter in enumerate(domain_filters): - flux_tally = openmc.Tally(name=f'MicroXS flux {i}') - flux_tally.filters = [domain_filter] - if energy_filter is not None: - flux_tally.filters.append(energy_filter) - flux_tally.scores = ['flux'] - model.tallies.append(flux_tally) - flux_tallies.append(flux_tally) - - if has_rr: - rr_tally = openmc.Tally(name=f'MicroXS RR {i}') - rr_tally.filters = [domain_filter] - if rr_energy_filter is not None: - rr_tally.filters.append(rr_energy_filter) - rr_tally.nuclides = rr_nuclides - rr_tally.multiply_density = False - rr_tally.scores = rr_reactions - model.tallies.append(rr_tally) - rr_tallies.append(rr_tally) - - if openmc.lib.is_initialized: - openmc.lib.finalize() - - if comm.rank == 0: - model.export_to_model_xml() - comm.barrier() - # Reinitialize with tallies - output = run_kwargs.get('output', True) if run_kwargs else True - openmc.lib.init(intracomm=comm, output=output) - - with TemporaryDirectory() as temp_dir: - # Indicate to run in temporary directory unless being executed through - # openmc.lib, in which case we don't need to specify the cwd - run_kwargs = dict(run_kwargs) if run_kwargs else {} - if not openmc.lib.is_initialized: - run_kwargs.setdefault('cwd', temp_dir) - - # Run transport simulation and synchronize - statepoint_path = model.run(**run_kwargs) - comm.barrier() - - if comm.rank == 0: - # Move the statepoint file if it is being saved to a specific path - if path_statepoint is not None: - shutil.move(statepoint_path, path_statepoint) - statepoint_path = path_statepoint - - # Export the model to path_input if provided - if path_input is not None: - model.export_to_model_xml(path_input) - - # Broadcast updated statepoint path to all ranks - statepoint_path = comm.bcast(statepoint_path) - - # Read in tally results (on all ranks) - with StatePoint(statepoint_path) as sp: - for i in range(len(flux_tallies)): - flux_tallies[i] = sp.tallies[flux_tallies[i].id] - flux_tallies[i]._read_results() - if rr_tallies: - rr_tallies[i] = sp.tallies[rr_tallies[i].id] - rr_tallies[i]._read_results() - - # Concatenate results across all domain filters - fluxes = [] - all_flux_arrays = [] - for flux_tally in flux_tallies: - # Get flux values and make energy groups last dimension - flux = flux_tally.get_reshaped_data() - if energy_filter is None: - flux = flux[..., np.newaxis] # (domains, 1, 1, groups) - else: - # (domains, groups, 1, 1) -> (domains, 1, 1, groups) - flux = np.moveaxis(flux, 1, -1) - all_flux_arrays.append(flux) - fluxes.extend(flux.squeeze((1, 2))) - - # If we built reaction-rate tallies, compute microscopic cross sections - if rr_tallies: - direct_micros = [] - for flux_arr, rr_tally in zip(all_flux_arrays, rr_tallies): - flux = flux_arr - # Get reaction rates and make energy groups last dimension - reaction_rates = rr_tally.get_reshaped_data() - if rr_energy_filter is None: - # (domains, nuclides, reactions) -> - # (domains, nuclides, reactions, groups) - reaction_rates = reaction_rates[..., np.newaxis] - else: - # (domains, groups, nuclides, reactions) -> - # (domains, nuclides, reactions, groups) - reaction_rates = np.moveaxis(reaction_rates, 1, -1) - - # If RR is 1-group, sum flux over groups - if reaction_rate_mode == "flux": - flux = flux.sum(axis=-1, keepdims=True) - - xs = np.zeros_like(reaction_rates) - d, _, _, g = np.nonzero(flux) - xs[d, ..., g] = reaction_rates[d, ..., g] / flux[d, :, :, g] - direct_micros.extend( - MicroXS(xs_i, rr_nuclides, rr_reactions) for xs_i in xs) - - if reaction_rate_mode == 'flux': - # Compute flux-collapsed microscopic XS - flux_micros = [MicroXS.from_multigroup_flux( - energies=collapse_energies, - multigroup_flux=flux_i, - chain_file=chain_file, - nuclides=nuclides, - reactions=reactions - ) for flux_i in fluxes] - - # We need to return one-group fluxes to match the microscopic cross - # sections, which are always one-group by virtue of the collapse - fluxes = [flux.sum(keepdims=True) for flux in fluxes] - - # Decide which micros to use and merge if needed - if reaction_rate_mode == 'flux' and rr_tallies: - micros = [m1.merge(m2) for m1, m2 in zip(flux_micros, direct_micros)] - elif rr_tallies: - micros = direct_micros - else: - micros = flux_micros - - # Reset tallies - model.tallies = original_tallies - - return fluxes, micros - - -class MicroXS: +class MicroXS(DataFrame): """Microscopic cross section data for use in transport-independent depletion. .. versionadded:: 0.13.1 - .. versionchanged:: 0.14.0 - Class was heavily refactored and no longer subclasses pandas.DataFrame. - - Parameters - ---------- - data : numpy.ndarray of floats - 3D array containing microscopic cross section values for each - nuclide, reaction, and energy group. Cross section values are assumed to - be in [b], and indexed by [nuclide, reaction, energy group] - nuclides : list of str - List of nuclide symbols for that have data for at least one - reaction. - reactions : list of str - List of reactions. All reactions must match those in - :data:`openmc.deplete.chain.REACTIONS` - """ - def __init__(self, data: np.ndarray, nuclides: list[str], reactions: list[str]): - # Validate inputs - if len(data.shape) != 3: - raise ValueError('Data array must be 3D.') - if data.shape[:2] != (len(nuclides), len(reactions)): - raise ValueError( - f'Nuclides list of length {len(nuclides)} and ' - f'reactions array of length {len(reactions)} do not ' - f'match dimensions of data array of shape {data.shape}') - check_iterable_type('nuclides', nuclides, str) - check_iterable_type('reactions', reactions, str) - check_type('data', data, np.ndarray, expected_iter_type=float) - for reaction in reactions: - check_value('reactions', reaction, _valid_rxns) - - self.data = data - self.nuclides = nuclides - self.reactions = reactions - self._index_nuc = {nuc: i for i, nuc in enumerate(nuclides)} - self._index_rx = {rx: i for i, rx in enumerate(reactions)} @classmethod - def from_multigroup_flux( - cls, - energies: Sequence[float] | str, - multigroup_flux: Sequence[float], - chain_file: PathLike | None = None, - temperature: float = 293.6, - nuclides: Sequence[str] | None = None, - reactions: Sequence[str] | None = None, - **init_kwargs: dict, - ) -> MicroXS: - """Generated microscopic cross sections from a known flux. - - The size of the MicroXS matrix depends on the chain file and cross - sections available. MicroXS entry will be 0 if the nuclide cross section - is not found. - - It is recommended to make repeated calls to this method within a context - manager using the :class:`openmc.lib.TemporarySession` class to avoid - re-initializing OpenMC and loading cross sections each time. - - .. versionadded:: 0.15.0 + def from_model(cls, + model, + reaction_domain, + chain_file, + dilute_initial=1.0e3, + energy_bounds=(0, 20e6), + run_kwargs=None): + """Generate a one-group cross-section dataframe using + OpenMC. Note that the ``openmc`` executable must be compiled. Parameters ---------- - energies : iterable of float or str - Energy group boundaries in [eV] or the name of the group structure - multigroup_flux : iterable of float - Energy-dependent multigroup flux values - chain_file : PathLike or Chain, optional - Path to the depletion chain XML file or an instance of - openmc.deplete.Chain. Defaults to ``openmc.config['chain_file']``. - temperature : int, optional - Temperature for cross section evaluation in [K]. - nuclides : list of str, optional - Nuclides to get cross sections for. If not specified, all burnable - nuclides from the depletion chain file are used. + model : openmc.Model + OpenMC model object. Must contain geometry, materials, and settings. + reaction_domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh + Domain in which to tally reaction rates. + chain_file : str + Path to the depletion chain XML file that will be used in depletion + simulation. Used to determine cross sections for materials not + present in the inital composition. + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that + are zero in initial condition to ensure they exist in the cross + section data. Only done for nuclides with reaction rates. reactions : list of str, optional - Reactions to get cross sections for. If not specified, all neutron - reactions listed in the depletion chain file are used. - **init_kwargs : dict - Keyword arguments passed to :func:`openmc.lib.init` + Reaction names to tally + energy_bound : 2-tuple of float, optional + Bounds for the energy group. + run_kwargs : dict, optional + Keyword arguments passed to :meth:`openmc.model.Model.run` + + Returns + ------- + MicroXS + Cross section data in [b] + + """ + groups = EnergyGroups(energy_bounds) + + # Set up the reaction tallies + original_tallies = model.tallies + original_materials = deepcopy(model.materials) + tallies = Tallies() + xs = {} + reactions, diluted_materials = cls._add_dilute_nuclides(chain_file, + model, + dilute_initial) + model.materials = diluted_materials + + for rx in reactions: + if rx == 'fission': + xs[rx] = FissionXS(domain=reaction_domain, + energy_groups=groups, by_nuclide=True) + else: + xs[rx] = ArbitraryXS(rx, domain=reaction_domain, + energy_groups=groups, by_nuclide=True) + tallies += xs[rx].tallies.values() + + model.tallies = tallies + + # create temporary run + with tempfile.TemporaryDirectory() as temp_dir: + if run_kwargs is None: + run_kwargs = {} + run_kwargs.setdefault('cwd', temp_dir) + statepoint_path = model.run(**run_kwargs) + + with StatePoint(statepoint_path) as sp: + for rx in xs: + xs[rx].load_from_statepoint(sp) + + # Build the DataFrame + series = {} + for rx in xs: + df = xs[rx].get_pandas_dataframe(xs_type='micro') + series[rx] = df.set_index('nuclide')['mean'] + + # Revert to the original tallies and materials + model.tallies = original_tallies + model.materials = original_materials + + return cls(series) + + @classmethod + def _add_dilute_nuclides(cls, chain_file, model, dilute_initial): + """ + Add nuclides not present in burnable materials that have neutron data + and are present in the depletion chain to those materials. This allows + us to tally those specific nuclides for reactions to create one-group + cross sections. + + Parameters + ---------- + chain_file : str + Path to the depletion chain XML file that will be used in depletion + simulation. Used to determine cross sections for materials not + present in the inital composition. + model : openmc.Model + Model object + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that + are zero in initial condition to ensure they exist in the cross + section data. Only done for nuclides with reaction rates. + + Returns + ------- + reactions : list of str + List of reaction names + diluted_materials : openmc.Materials + :class:`openmc.Materials` object with nuclides added to burnable + materials. + """ + chain = Chain.from_xml(chain_file) + reactions = chain.reactions + cross_sections = _find_cross_sections(model) + nuclides_with_data = _get_nuclides_with_data(cross_sections) + burnable_nucs = [nuc.name for nuc in chain.nuclides + if nuc.name in nuclides_with_data] + diluted_materials = Materials() + for material in model.materials: + if material.depletable: + nuc_densities = material.get_nuclide_atom_densities() + dilute_density = 1.0e-24 * dilute_initial + material.set_density('sum') + for nuc, density in nuc_densities.items(): + material.remove_nuclide(nuc) + material.add_nuclide(nuc, density) + for burn_nuc in burnable_nucs: + if burn_nuc not in nuc_densities: + material.add_nuclide(burn_nuc, + dilute_density) + diluted_materials.append(material) + + return reactions, diluted_materials + + @classmethod + def from_array(cls, nuclides, reactions, data): + """ + Creates a ``MicroXS`` object from arrays. + + Parameters + ---------- + nuclides : list of str + List of nuclide symbols for that have data for at least one + reaction. + reactions : list of str + List of reactions. All reactions must match those in + :data:`openmc.deplete.chain.REACTIONS` + data : ndarray of floats + Array containing one-group microscopic cross section values for + each nuclide and reaction. Cross section values are assumed to be + in [b]. Returns ------- MicroXS """ - check_type("temperature", temperature, (int, float)) - # if energy is string then use group structure of that name - if isinstance(energies, str): - energies = GROUP_STRUCTURES[energies] - else: - # if user inputs energies check they are ascending (low to high) as - # some depletion codes use high energy to low energy. - if not np.all(np.diff(energies) > 0): - raise ValueError('Energy group boundaries must be in ascending order') + # Validate inputs + if data.shape != (len(nuclides), len(reactions)): + raise ValueError( + f'Nuclides list of length {len(nuclides)} and ' + f'reactions array of length {len(reactions)} do not ' + f'match dimensions of data array of shape {data.shape}') - # check dimension consistency - if len(multigroup_flux) != len(energies) - 1: - raise ValueError('Length of flux array should be len(energies)-1') + cls._validate_micro_xs_inputs( + nuclides, reactions, data) + micro_xs = cls(index=nuclides, columns=reactions, data=data) - chain = _get_chain(chain_file) - cross_sections = _find_cross_sections(model=None) - nuclides_with_data = _get_nuclides_with_data(cross_sections) - - # If no nuclides were specified, default to all nuclides from the chain - if not nuclides: - nuclides = chain.nuclides - nuclides = [nuc.name for nuc in nuclides] - - # Get reaction MT values. If no reactions specified, default to the - # reactions available in the chain file - if reactions is None: - reactions = chain.reactions - mts = [REACTION_MT[name] for name in reactions] - - # Create 3D array for microscopic cross sections - microxs_arr = np.zeros((len(nuclides), len(mts), 1)) - - # If flux is zero, safely return zero cross sections - multigroup_flux = np.array(multigroup_flux) - if (flux_sum := multigroup_flux.sum()) == 0.0: - return cls(microxs_arr, nuclides, reactions) - - # Normalize multigroup flux - multigroup_flux /= flux_sum - - # Compute microscopic cross sections within a temporary session - with openmc.lib.TemporarySession(**init_kwargs): - # For each nuclide and reaction, compute the flux-averaged xs - for nuc_index, nuc in enumerate(nuclides): - if nuc not in nuclides_with_data: - continue - lib_nuc = openmc.lib.load_nuclide(nuc) - for mt_index, mt in enumerate(mts): - microxs_arr[nuc_index, mt_index, 0] = lib_nuc.collapse_rate( - mt, temperature, energies, multigroup_flux - ) - - return cls(microxs_arr, nuclides, reactions) + return micro_xs @classmethod def from_csv(cls, csv_file, **kwargs): - """Load data from a comma-separated values (csv) file. + """ + Load a ``MicroXS`` object from a ``.csv`` file. Parameters ---------- @@ -499,204 +221,20 @@ class MicroXS: MicroXS """ - kwargs.setdefault('float_precision', 'round_trip') + if 'float_precision' not in kwargs: + kwargs['float_precision'] = 'round_trip' - df = pd.read_csv(csv_file, **kwargs) - df.set_index(['nuclides', 'reactions', 'groups'], inplace=True) - nuclides = list(df.index.unique(level='nuclides')) - reactions = list(df.index.unique(level='reactions')) - groups = list(df.index.unique(level='groups')) - shape = (len(nuclides), len(reactions), len(groups)) - data = df.values.reshape(shape) - return cls(data, nuclides, reactions) + micro_xs = cls(read_csv(csv_file, index_col=0, **kwargs)) - def __getitem__(self, index): - nuc, rx = index - i_nuc = self._index_nuc[nuc] - i_rx = self._index_rx[rx] - return self.data[i_nuc, i_rx] + cls._validate_micro_xs_inputs(list(micro_xs.index), + list(micro_xs.columns), + micro_xs.to_numpy()) + return micro_xs - def to_csv(self, *args, **kwargs): - """Write data to a comma-separated values (csv) file - - Parameters - ---------- - *args - Positional arguments passed to :meth:`pandas.DataFrame.to_csv` - **kwargs - Keyword arguments passed to :meth:`pandas.DataFrame.to_csv` - - """ - groups = self.data.shape[2] - multi_index = pd.MultiIndex.from_product( - [self.nuclides, self.reactions, range(1, groups + 1)], - names=['nuclides', 'reactions', 'groups'] - ) - df = pd.DataFrame({'xs': self.data.flatten()}, index=multi_index) - df.to_csv(*args, **kwargs) - - def to_hdf5(self, group_or_filename: h5py.Group | PathLike, **kwargs): - """Export microscopic cross section data to HDF5 format - - Parameters - ---------- - group_or_filename : h5py.Group or path-like - HDF5 group or filename to write to - kwargs : dict, optional - Keyword arguments to pass to :meth:`h5py.Group.create_dataset`. - Defaults to {'compression': 'lzf'}. - - """ - kwargs.setdefault('compression', 'lzf') - - with h5py_file_or_group(group_or_filename, 'w') as group: - # Store cross section data as 3D dataset - group.create_dataset('data', data=self.data, **kwargs) - - # Store metadata as datasets using string encoding - group.create_dataset('nuclides', data=np.array(self.nuclides, dtype='S')) - group.create_dataset('reactions', data=np.array(self.reactions, dtype='S')) - - @classmethod - def from_hdf5(cls, group_or_filename: h5py.Group | PathLike) -> Self: - """Load data from an HDF5 file - - Parameters - ---------- - group_or_filename : h5py.Group or str or PathLike - HDF5 group or path to HDF5 file. If given as an h5py.Group, the - data is read from that group. If given as a string, it is assumed - to be the filename for the HDF5 file. - - Returns - ------- - MicroXS - """ - - with h5py_file_or_group(group_or_filename, 'r') as group: - # Read data from HDF5 group - data = group['data'][:] - nuclides = [nuc.decode('utf-8') for nuc in group['nuclides'][:]] - reactions = [rxn.decode('utf-8') for rxn in group['reactions'][:]] - - return cls(data, nuclides, reactions) - - def merge(self, other: Self, prefer: str = 'other') -> Self: - """Merge two MicroXS objects by taking the union of nuclides/reactions. - - If the two objects contain overlapping nuclide/reaction entries, values - from `other` will overwrite values from `self` when `prefer='other'`. - When `prefer='self'`, values from `self` are retained for overlapping - entries, and values from `other` are used only for non-overlapping - entries. - - Parameters - ---------- - other : MicroXS - Other MicroXS instance to merge with this one. - prefer : {"other", "self"} - Which instance's data should take precedence on overlap. - - Returns - ------- - MicroXS - New instance containing the merged data. - """ - check_value('prefer', prefer, {'other', 'self'}) - - # Require same number of energy groups - if self.data.shape[2] != other.data.shape[2]: - raise ValueError( - 'Cannot merge MicroXS with different number of energy groups: ' - f"{self.data.shape[2]} vs {other.data.shape[2]}. Ensure that " - 'both were generated with consistent group structures and ' - 'treatments (e.g., both multigroup or both collapsed).' - ) - - # Build unified axes preserving order (self first, then other's new) - new_nuclides = list(self.nuclides) - for nuc in other.nuclides: - if nuc not in self._index_nuc: - new_nuclides.append(nuc) - new_reactions = list(self.reactions) - for rx in other.reactions: - if rx not in self._index_rx: - new_reactions.append(rx) - - # Allocate and fill from self (self's nuclides/reactions map to the - # first indices of new_nuclides/new_reactions by construction) - groups = self.data.shape[2] - data = np.zeros((len(new_nuclides), len(new_reactions), groups)) - idx_n = {nuc: i for i, nuc in enumerate(new_nuclides)} - idx_r = {rx: i for i, rx in enumerate(new_reactions)} - - n_self = len(self.nuclides) - r_self = len(self.reactions) - data[:n_self, :r_self] = self.data - - # Build destination index arrays for other's nuclides/reactions - dst_n = np.array([idx_n[nuc] for nuc in other.nuclides]) - dst_r = np.array([idx_r[rx] for rx in other.reactions]) - - # Copy from other, respecting precedence - if prefer == 'other': - data[np.ix_(dst_n, dst_r)] = other.data - else: - # Copy only entries where nuc or rx is absent from self - nuc_is_new = np.array( - [nuc not in self._index_nuc for nuc in other.nuclides]) - rx_is_new = np.array( - [rx not in self._index_rx for rx in other.reactions]) - mask = nuc_is_new[:, np.newaxis] | rx_is_new[np.newaxis, :] - src_i, src_j = np.where(mask) - if src_i.size: - data[dst_n[src_i], dst_r[src_j]] = other.data[src_i, src_j] - - return MicroXS(data, new_nuclides, new_reactions) - - -def write_microxs_hdf5( - micros: Sequence[MicroXS], - filename: PathLike, - names: Sequence[str] | None = None, - **kwargs -): - """Write multiple MicroXS objects to an HDF5 file - - Parameters - ---------- - micros : list of MicroXS - List of MicroXS objects - filename : PathLike - Output HDF5 filename - names : list of str, optional - Names for each MicroXS object. If None, uses 'domain_0', 'domain_1', - etc. - **kwargs - Additional keyword arguments passed to :meth:`h5py.Group.create_dataset` - """ - if names is None: - names = [f'domain_{i}' for i in range(len(micros))] - - # Open file once and write all domains using group interface - with h5py.File(filename, 'w') as f: - for microxs, name in zip(micros, names): - group = f.create_group(name) - microxs.to_hdf5(group, **kwargs) - - -def read_microxs_hdf5(filename: PathLike) -> dict[str, MicroXS]: - """Read multiple MicroXS objects from an HDF5 file - - Parameters - ---------- - filename : path-like - HDF5 filename - - Returns - ------- - dict - Dictionary mapping domain names to MicroXS objects - """ - with h5py.File(filename, 'r') as f: - return {name: MicroXS.from_hdf5(group) for name, group in f.items()} + @staticmethod + def _validate_micro_xs_inputs(nuclides, reactions, data): + check_iterable_type('nuclides', nuclides, str) + check_iterable_type('reactions', reactions, str) + check_type('data', data, np.ndarray, expected_iter_type=float) + for reaction in reactions: + check_value('reactions', reaction, _valid_rxns) diff --git a/openmc/deplete/nuclide.py b/openmc/deplete/nuclide.py index 958814834..7b6ddd788 100644 --- a/openmc/deplete/nuclide.py +++ b/openmc/deplete/nuclide.py @@ -1,4 +1,4 @@ -"""Nuclide module.xml.etree.Ele +"""Nuclide module. Contains the per-nuclide components of a depletion chain. """ @@ -8,13 +8,14 @@ from collections.abc import Mapping from collections import namedtuple, defaultdict from warnings import warn from numbers import Real +try: + import lxml.etree as ET +except ImportError: + import xml.etree.ElementTree as ET -import lxml.etree as ET -import numpy as np +from numpy import empty, searchsorted from openmc.checkvalue import check_type -from openmc.stats import Univariate -from .._xml import get_elem_list, get_text __all__ = [ "DecayTuple", "ReactionTuple", "Nuclide", "FissionYield", @@ -80,7 +81,7 @@ class Nuclide: Parameters ---------- name : str, optional - GNDS name of this nuclide, e.g. ``"He4"``, ``"Am242_m1"`` + GND name of this nuclide, e.g. ``"He4"``, ``"Am242_m1"`` Attributes ---------- @@ -100,9 +101,6 @@ class Nuclide: reactions : list of openmc.deplete.ReactionTuple Reaction information. Each element of the list is a named tuple with attribute 'type', 'target', 'Q', and 'branching_ratio'. - sources : dict - Dictionary mapping particle type as string to energy distribution of - decay source represented as :class:`openmc.stats.Univariate` yield_data : FissionYieldDistribution or None Fission product yields at tabulated energies for this nuclide. Can be treated as a nested dictionary ``{energy: {product: yield}}`` @@ -122,9 +120,6 @@ class Nuclide: # Reaction paths self.reactions = [] - # Decay sources - self.sources = {} - # Neutron fission yields, if present self._yield_data = None @@ -210,9 +205,9 @@ class Nuclide: Parameters ---------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element to read nuclide data from - root : lxml.etree._Element, optional + root : xml.etree.ElementTree.Element, optional Root XML element for chain file (only used when fission product yields are borrowed from another parent) fission_q : None or float @@ -226,39 +221,32 @@ class Nuclide: """ nuc = cls() - nuc.name = get_text(element, "name") + nuc.name = element.get('name') # Check for half-life - half_life = get_text(element, "half_life") - if half_life is not None: - nuc.half_life = float(half_life) - nuc.decay_energy = float(get_text(element, "decay_energy", 0.0)) + if 'half_life' in element.attrib: + nuc.half_life = float(element.get('half_life')) + nuc.decay_energy = float(element.get('decay_energy', '0')) # Check for decay paths for decay_elem in element.iter('decay'): - d_type = get_text(decay_elem, "type") - target = get_text(decay_elem, "target") + d_type = decay_elem.get('type') + target = decay_elem.get('target') if target is not None and target.lower() == "nothing": target = None - branching_ratio = float(get_text(decay_elem, "branching_ratio")) + branching_ratio = float(decay_elem.get('branching_ratio')) nuc.decay_modes.append(DecayTuple(d_type, target, branching_ratio)) - # Check for sources - for src_elem in element.iter('source'): - particle = get_text(src_elem, "particle") - distribution = Univariate.from_xml_element(src_elem) - nuc.sources[particle] = distribution - # Check for reaction paths for reaction_elem in element.iter('reaction'): - r_type = get_text(reaction_elem, "type") - Q = float(get_text(reaction_elem, "Q", 0.0)) - branching_ratio = float(get_text(reaction_elem, "branching_ratio", 1.0)) + r_type = reaction_elem.get('type') + Q = float(reaction_elem.get('Q', '0')) + branching_ratio = float(reaction_elem.get('branching_ratio', '1')) # If the type is not fission, get target and Q value, otherwise # just set null values if r_type != 'fission': - target = get_text(reaction_elem, "target") + target = reaction_elem.get('target') if target is not None and target.lower() == "nothing": target = None else: @@ -273,11 +261,11 @@ class Nuclide: fpy_elem = element.find('neutron_fission_yields') if fpy_elem is not None: # Check for use of FPY from other nuclide - parent = get_text(fpy_elem, "parent") + parent = fpy_elem.get('parent') if parent is not None: assert root is not None fpy_elem = root.find( - f'.//nuclide[@name="{parent}"]/neutron_fission_yields' + './/nuclide[@name="{}"]/neutron_fission_yields'.format(parent) ) if fpy_elem is None: raise ValueError( @@ -296,7 +284,7 @@ class Nuclide: Returns ------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element to write nuclide data to """ @@ -314,13 +302,6 @@ class Nuclide: mode_elem.set('target', daughter) mode_elem.set('branching_ratio', str(br)) - # Write decay sources - if self.sources: - for particle, source in self.sources.items(): - src_elem = source.to_xml_element('source') - src_elem.set('particle', particle) - elem.append(src_elem) - elem.set('reactions', str(len(self.reactions))) for rx, daughter, Q, br in self.reactions: rx_elem = ET.SubElement(elem, 'reaction') @@ -415,7 +396,7 @@ class Nuclide: continue msg = msg_func( name=self.name, actual=sum_br, expected=1.0, tol=tolerance, - prop=f"{rxn_type} reaction branch ratios") + prop="{} reaction branch ratios".format(rxn_type)) if strict: raise ValueError(msg) elif quiet: @@ -432,7 +413,7 @@ class Nuclide: msg = msg_func( name=self.name, actual=sum_yield, expected=2.0, tol=tolerance, - prop=f"fission yields (E = {energy:7.4e} eV)") + prop="fission yields (E = {:7.4e} eV)".format(energy)) if strict: raise ValueError(msg) elif quiet: @@ -489,7 +470,7 @@ class FissionYieldDistribution(Mapping): shared_prod = set.union(*(set(x) for x in fission_yields.values())) ordered_prod = sorted(shared_prod) - yield_matrix = np.empty((len(energies), len(shared_prod))) + yield_matrix = empty((len(energies), len(shared_prod))) for g_index, energy in enumerate(energies): prod_map = fission_yields[energy] @@ -522,7 +503,7 @@ class FissionYieldDistribution(Mapping): Parameters ---------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element to pull fission yield data from Returns @@ -531,9 +512,9 @@ class FissionYieldDistribution(Mapping): """ all_yields = {} for yield_elem in element.iter("fission_yields"): - energy = float(get_text(yield_elem, "energy")) - products = get_elem_list(yield_elem, "products", str) or [] - yields = get_elem_list(yield_elem, "data", float) or [] + energy = float(yield_elem.get("energy")) + products = yield_elem.find("products").text.split() + yields = map(float, yield_elem.find("data").text.split()) # Get a map of products to their corresponding yield all_yields[energy] = dict(zip(products, yields)) @@ -544,7 +525,7 @@ class FissionYieldDistribution(Mapping): Parameters ---------- - root : lxml.etree._Element + root : xml.etree.ElementTree.Element Element to write distribution data to """ for energy, yield_obj in self.items(): @@ -579,7 +560,7 @@ class FissionYieldDistribution(Mapping): return None products = sorted(overlap) - indices = np.searchsorted(self.products, products) + indices = searchsorted(self.products, products) # coerce back to dictionary to pass back to __init__ new_yields = {} @@ -697,12 +678,8 @@ class FissionYield(Mapping): return self * scalar def __repr__(self): - return f"<{self.__class__.__name__} containing {len(self)} products and yields>" - - def __deepcopy__(self, memo): - result = FissionYield(self.products, self.yields.copy()) - memo[id(self)] = result - return result + return "<{} containing {} products and yields>".format( + self.__class__.__name__, len(self)) # Avoid greedy numpy operations like np.float64 * fission_yield # converting this to an array on the fly. Force __rmul__ and diff --git a/openmc/deplete/openmc_operator.py b/openmc/deplete/openmc_operator.py index 7928e89ee..ee569bf71 100644 --- a/openmc/deplete/openmc_operator.py +++ b/openmc/deplete/openmc_operator.py @@ -6,22 +6,42 @@ transport-independent transport operators. """ from abc import abstractmethod -from warnings import warn +from collections import OrderedDict import numpy as np import openmc -from openmc.checkvalue import check_value, check_type, check_greater_than -from openmc.exceptions import DataError from openmc.mpi import comm from .abc import TransportOperator, OperatorResult from .atom_number import AtomNumber from .reaction_rates import ReactionRates -from .pool import _distribute __all__ = ["OpenMCOperator", "OperatorResult"] +def _distribute(items): + """Distribute items across MPI communicator + + Parameters + ---------- + items : list + List of items of distribute + + Returns + ------- + list + Items assigned to process that called + + """ + min_size, extra = divmod(len(items), comm.size) + j = 0 + for i in range(comm.size): + chunk_size = min_size + int(i < extra) + if comm.rank == i: + return items[j:j + chunk_size] + j += chunk_size + + class OpenMCOperator(TransportOperator): """Abstract class holding OpenMC-specific functions for running depletion calculations. @@ -33,41 +53,48 @@ class OpenMCOperator(TransportOperator): ---------- materials : openmc.Materials List of all materials in the model - cross_sections : str or list of MicroXS - Path to continuous energy cross section library, or list of objects - containing cross sections. - chain_file : PathLike or Chain, optional - Path to the depletion chain XML file or instance of openmc.deplete.Chain. - Defaults to ``openmc.config['chain_file']``. + cross_sections : str or pandas.DataFrame + Path to continuous energy cross section library, or object containing + one-group cross-sections. + chain_file : str, optional + Path to the depletion chain XML file. Defaults to the file + listed under ``depletion_chain`` in + :envvar:`OPENMC_CROSS_SECTIONS` environment variable. prev_results : Results, optional Results from a previous depletion calculation. If this argument is specified, the depletion calculation will start from the latest state in the previous results. diff_burnable_mats : bool, optional Whether to differentiate burnable materials with multiple instances. + Volumes are divided equally from the original material volume. fission_q : dict, optional Dictionary of nuclides and their fission Q values [eV]. + dilute_initial : float, optional + Initial atom density [atoms/cm^3] to add for nuclides that are zero + in initial condition to ensure they exist in the decay chain. + Only done for nuclides with reaction rates. helper_kwargs : dict Keyword arguments for helper classes + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce()` to reduce the + depletion chain up to ``reduce_chain_level``. reduce_chain_level : int, optional - Depth of the search when reducing the depletion chain. The default - value of ``None`` implies no limit on the depth. + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. - diff_volume_method : str - Specifies how the volumes of the new materials should be found. Default - is to 'divide equally' which divides the original material volume - equally between the new materials, 'match cell' sets the volume of the - material to volume of the cell they fill. - - .. versionadded:: 0.14.0 Attributes ---------- materials : openmc.Materials All materials present in the model - cross_sections : str or list of MicroXS - Path to continuous energy cross section library, or list of objects - containing cross sections. + cross_sections : str or MicroXS + Path to continuous energy cross section library, or object + containing one-group cross-sections. + dilute_initial : float + Initial atom density [atoms/cm^3] to add for nuclides that + are zero in initial condition to ensure they exist in the decay + chain. Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. round_number : bool @@ -100,34 +127,19 @@ class OpenMCOperator(TransportOperator): chain_file=None, prev_results=None, diff_burnable_mats=False, - diff_volume_method='divide equally', fission_q=None, + dilute_initial=0.0, helper_kwargs=None, + reduce_chain=False, reduce_chain_level=None): - # If chain file was not specified, try to get it from global config - if chain_file is None: - chain_file = openmc.config.get('chain_file') - if chain_file is None: - raise DataError( - "No depletion chain specified and could not find depletion " - "chain in openmc.config['chain_file']" - ) - - super().__init__(chain_file, fission_q, prev_results) + super().__init__(chain_file, fission_q, dilute_initial, prev_results) self.round_number = False self.materials = materials self.cross_sections = cross_sections - check_value('diff volume method', diff_volume_method, - {'divide equally', 'match cell'}) - if reduce_chain_level: - check_type('reduce_chain_level', reduce_chain_level, int) - check_greater_than('reduce_chain_level', reduce_chain_level, 0) - self.diff_volume_method = diff_volume_method - # Reduce the chain to only those nuclides present - if reduce_chain_level is not None: + if reduce_chain: init_nuclides = set() for material in self.materials: if not material.depletable: @@ -139,22 +151,11 @@ class OpenMCOperator(TransportOperator): if diff_burnable_mats: self._differentiate_burnable_mats() - self.materials = self.model.materials # Determine which nuclides have cross section data # This nuclides variables contains every nuclides # for which there is an entry in the micro_xs parameter - self.nuclides_with_data = self._get_nuclides_with_data( - self.cross_sections) - - # Select nuclides with data that are also in the chain - self._burnable_nucs = [nuc.name for nuc in self.chain.nuclides - if nuc.name in self.nuclides_with_data] - - # Select nuclides without data that are also in the chain - self._decay_nucs = [nuc.name for nuc in self.chain.nuclides - if nuc.name not in self.nuclides_with_data] - + openmc.reset_auto_ids() self.burnable_mats, volumes, all_nuclides = self._get_burnable_mats() self.local_mats = _distribute(self.burnable_mats) @@ -164,6 +165,13 @@ class OpenMCOperator(TransportOperator): if self.prev_res is not None: self._load_previous_results() + self.nuclides_with_data = self._get_nuclides_with_data( + self.cross_sections) + + # Select nuclides with data that are also in the chain + self._burnable_nucs = [nuc.name for nuc in self.chain.nuclides + if nuc.name in self.nuclides_with_data] + # Extract number densities from the geometry / previous depletion run self._extract_number(self.local_mats, volumes, @@ -180,14 +188,14 @@ class OpenMCOperator(TransportOperator): """Assign distribmats for each burnable material""" pass - def _get_burnable_mats(self) -> tuple[list[str], dict[str, float], list[str]]: + def _get_burnable_mats(self): """Determine depletable materials, volumes, and nuclides Returns ------- burnable_mats : list of str - list of burnable material IDs - volume : dict of str to float + List of burnable material IDs + volume : OrderedDict of str to float Volume of each material in [cm^3] nuclides : list of str Nuclides in order of how they'll appear in the simulation. @@ -196,30 +204,19 @@ class OpenMCOperator(TransportOperator): burnable_mats = set() model_nuclides = set() - volume = {} + volume = OrderedDict() self.heavy_metal = 0.0 # Iterate once through the geometry to get dictionaries for mat in self.materials: for nuclide in mat.get_nuclides(): - if nuclide in self.nuclides_with_data or self._decay_nucs: - model_nuclides.add(nuclide) - else: - msg = (f"Nuclide {nuclide} in material {mat.id} is not " - "present in the depletion chain and has no cross " - "section data.") - warn(msg) + model_nuclides.add(nuclide) if mat.depletable: - burnable_mats.add((str(mat.id), mat.name)) + burnable_mats.add(str(mat.id)) if mat.volume is None: - if mat.name is None: - msg = ("Volume not specified for depletable material " - f"with ID={mat.id}.") - else: - msg = ("Volume not specified for depletable material " - f"with ID={mat.id} Name={mat.name}.") - raise RuntimeError(msg) + raise RuntimeError("Volume not specified for depletable " + "material with ID={}.".format(mat.id)) volume[str(mat.id)] = mat.volume self.heavy_metal += mat.fissionable_mass @@ -229,17 +226,15 @@ class OpenMCOperator(TransportOperator): "No depletable materials were found in the model.") # Sort the sets - burnable_mats = sorted(burnable_mats, key=lambda x: int(x[0])) + burnable_mats = sorted(burnable_mats, key=int) model_nuclides = sorted(model_nuclides) - # Store material names for later use - burnable_mats, self.name_list = zip(*burnable_mats) - # Construct a global nuclide dictionary, burned first nuclides = list(self.chain.nuclide_dict) for nuc in model_nuclides: if nuc not in nuclides: nuclides.append(nuc) + return burnable_mats, volume, nuclides def _load_previous_results(self): @@ -248,7 +243,20 @@ class OpenMCOperator(TransportOperator): @abstractmethod def _get_nuclides_with_data(self, cross_sections): - """Find nuclides with cross section data.""" + """Find nuclides with cross section data + + Parameters + ---------- + cross_sections : str or pandas.DataFrame + Path to continuous energy cross section library, or object + containing one-group cross-sections. + + Returns + ------- + nuclides : set of str + Set of nuclide names that have cross secton data + + """ def _extract_number(self, local_mats, volume, all_nuclides, prev_res=None): """Construct AtomNumber using geometry @@ -257,7 +265,7 @@ class OpenMCOperator(TransportOperator): ---------- local_mats : list of str Material IDs to be managed by this process - volume : dict of str to float + volume : OrderedDict of str to float Volumes for the above materials in [cm^3] all_nuclides : list of str Nuclides to be used in the simulation. @@ -267,6 +275,11 @@ class OpenMCOperator(TransportOperator): """ self.number = AtomNumber(local_mats, all_nuclides, volume, len(self.chain)) + if self.dilute_initial != 0.0: + for nuc in self._burnable_nucs: + self.number.set_atom_density( + np.s_[:], nuc, self.dilute_initial) + # Now extract and store the number densities # From the geometry if no previous depletion results if prev_res is None: @@ -313,7 +326,7 @@ class OpenMCOperator(TransportOperator): mat_id = str(mat.id) # Get nuclide lists from geometry and depletion results - depl_nuc = prev_res[-1].index_nuc + depl_nuc = prev_res[-1].nuc_to_ind geom_nuc_densities = mat.get_nuclide_atom_densities() # Merge lists of nuclides, with the same order for every calculation @@ -346,8 +359,8 @@ class OpenMCOperator(TransportOperator): Parameters ---------- - materials : list of openmc.lib.Material - list of materials + materials : list of str + list of material IDs Returns ------- @@ -382,6 +395,9 @@ class OpenMCOperator(TransportOperator): self.number.set_density(vec) self._update_materials() + # Prevent OpenMC from complaining about re-creating tallies + openmc.reset_auto_ids() + # Update tally nuclides data in preparation for transport solve nuclides = self._get_reaction_nuclides() self._rate_helper.nuclides = nuclides @@ -427,7 +443,8 @@ class OpenMCOperator(TransportOperator): # for burning in which the number density is greater than zero. for nuc in self.number.nuclides: if nuc in self.nuclides_with_data: - nuc_set.add(nuc) + if np.sum(self.number[:, nuc]) > 0.0: + nuc_set.add(nuc) # Communicate which nuclides have nonzeros to rank 0 if comm.rank == 0: @@ -474,7 +491,7 @@ class OpenMCOperator(TransportOperator): # Form fast map nuc_ind = [rates.index_nuc[nuc] for nuc in rxn_nuclides] - rx_ind = [rates.index_rx[react] for react in self.chain.reactions] + react_ind = [rates.index_rx[react] for react in self.chain.reactions] # Keep track of energy produced from all reactions in eV per source # particle @@ -490,9 +507,6 @@ class OpenMCOperator(TransportOperator): fission_ind = rates.index_rx.get("fission") - # Reset the cached material reaction rates tallies - self._rate_helper.reset_tally_means() - # Extract results for i, mat in enumerate(self.local_mats): # Get tally index @@ -505,25 +519,21 @@ class OpenMCOperator(TransportOperator): for nuc, i_nuc_results in zip(rxn_nuclides, nuc_ind): number[i_nuc_results] = self.number[mat, nuc] - # Get microscopic reaction rates in [(reactions/src)*b-cm/atom]. 2D - # array with shape (nuclides, reactions). tally_rates = self._rate_helper.get_material_rates( - mat_index, nuc_ind, rx_ind) + mat_index, nuc_ind, react_ind) # Compute fission yields for this material fission_yields.append(self._yield_helper.weighted_yields(i)) # Accumulate energy from fission - volume_b_cm = 1e24 * self.number.get_mat_volume(mat) if fission_ind is not None: - atom_per_bcm = number / volume_b_cm - fission_rates = tally_rates[:, fission_ind] * atom_per_bcm - self._normalization_helper.update(fission_rates) + self._normalization_helper.update( + tally_rates[:, fission_ind]) - # Divide by [b-cm] to get [(reactions/src)/atom] - rates[i] = tally_rates / volume_b_cm + # Divide by total number and store + rates[i] = self._rate_helper.divide_by_adens(number) - # Scale reaction rates to obtain units of [(reactions/sec)/atom] + # Scale reaction rates to obtain units of reactions/sec rates *= self._normalization_helper.factor(source_rate) # Store new fission yields on the chain @@ -544,8 +554,6 @@ class OpenMCOperator(TransportOperator): A list of all material IDs to be burned. Used for sorting the simulation. full_burn_list : list List of all burnable material IDs - name_list : list of str - Material names corresponding to materials in burn_list """ nuc_list = self.number.burnable_nuclides @@ -559,4 +567,4 @@ class OpenMCOperator(TransportOperator): volume_list = comm.allgather(volume) volume = {k: v for d in volume_list for k, v in d.items()} - return volume, nuc_list, burn_list, self.burnable_mats, self.name_list + return volume, nuc_list, burn_list, self.burnable_mats diff --git a/openmc/deplete/pool.py b/openmc/deplete/pool.py index 19ad0ada5..a3d37f79f 100644 --- a/openmc/deplete/pool.py +++ b/openmc/deplete/pool.py @@ -5,11 +5,6 @@ Provided to avoid some circular imports from itertools import repeat, starmap from multiprocessing import Pool -import numpy as np -from scipy.sparse import hstack - -from openmc.mpi import comm -from .._sparse_compat import block_array # Configurable switch that enables / disables the use of # multiprocessing routines during depletion @@ -19,200 +14,57 @@ USE_MULTIPROCESSING = True # calculations NUM_PROCESSES = None -def _distribute(items): - """Distribute items across MPI communicator - Parameters - ---------- - items : list - List of items of distribute - - Returns - ------- - list - Items assigned to process that called - - """ - min_size, extra = divmod(len(items), comm.size) - j = 0 - for i in range(comm.size): - chunk_size = min_size + int(i < extra) - if comm.rank == i: - return items[j:j + chunk_size] - j += chunk_size - -def deplete(func, chain, n, rates, dt, current_timestep=None, matrix_func=None, - transfer_rates=None, external_source_rates=None, substeps=1, - *matrix_args): +def deplete(func, chain, x, rates, dt, matrix_func=None): """Deplete materials using given reaction rates for a specified time Parameters ---------- func : callable - Function to use to get new compositions. Expected to have the signature - ``func(A, n0, t, substeps=1) -> n1``. + Function to use to get new compositions. Expected to have the + signature ``func(A, n0, t) -> n1`` chain : openmc.deplete.Chain Depletion chain - n : list of numpy.ndarray - List of atom number arrays for each material. Each array in the list - contains the number of [atom] of each nuclide. + x : list of numpy.ndarray + Atom number vectors for each material rates : openmc.deplete.ReactionRates Reaction rates (from transport operator) dt : float Time in [s] to deplete for - current_timestep : int - Current timestep index maxtrix_func : callable, optional - Function to form the depletion matrix after calling ``matrix_func(chain, - rates, fission_yields)``, where ``fission_yields = {parent: {product: - yield_frac}}`` Expected to return the depletion matrix required by + Function to form the depletion matrix after calling + ``matrix_func(chain, rates, fission_yields)``, where + ``fission_yields = {parent: {product: yield_frac}}`` + Expected to return the depletion matrix required by ``func`` - transfer_rates : openmc.deplete.TransferRates, Optional - Transfer rates for continuous removal/feed. - - .. versionadded:: 0.14.0 - external_source_rates : openmc.deplete.ExternalSourceRates, Optional - External source rates for continuous removal/feed. - - .. versionadded:: 0.15.3 - substeps : int, optional - Number of substeps to pass to solvers that support substepping. - matrix_args: Any, optional - Additional arguments passed to matrix_func Returns ------- - n_result : list of numpy.ndarray - Updated list of atom number arrays for each material. Each array in the - list contains the number of [atom] of each nuclide. + x_result : list of numpy.ndarray + Updated atom number vectors for each material """ fission_yields = chain.fission_yields if len(fission_yields) == 1: fission_yields = repeat(fission_yields[0]) - elif len(fission_yields) != len(n): + elif len(fission_yields) != len(x): raise ValueError( "Number of material fission yield distributions {} is not " "equal to the number of compositions {}".format( - len(fission_yields), len(n))) + len(fission_yields), len(x))) if matrix_func is None: matrices = map(chain.form_matrix, rates, fission_yields) else: - matrices = map(matrix_func, repeat(chain), rates, fission_yields, - *matrix_args) + matrices = map(matrix_func, repeat(chain), rates, fission_yields) - if (transfer_rates is not None and - current_timestep in transfer_rates.external_timesteps): - # Calculate transfer rate terms as diagonal matrices - transfers = map(chain.form_rr_term, repeat(transfer_rates), - repeat(current_timestep), transfer_rates.local_mats) - - # Subtract transfer rate terms from Bateman matrices - matrices = [matrix - transfer for (matrix, transfer) in zip(matrices, - transfers)] - - if transfer_rates.redox: - for mat_idx, mat_id in enumerate(transfer_rates.local_mats): - if mat_id in transfer_rates.redox: - matrices[mat_idx] = chain.add_redox_term(matrices[mat_idx], - transfer_rates.redox[mat_id][0], - transfer_rates.redox[mat_id][1]) - - if current_timestep in transfer_rates.index_transfer: - # Gather all on comm.rank 0 - matrices = comm.gather(matrices) - n = comm.gather(n) - - if comm.rank == 0: - # Expand lists - matrices = [elm for matrix in matrices for elm in matrix] - n = [n_elm for n_mat in n for n_elm in n_mat] - - # Calculate transfer rate terms as diagonal matrices - transfer_pair = {} - for mat_pair in transfer_rates.index_transfer[current_timestep]: - transfer_matrix = chain.form_rr_term(transfer_rates, - current_timestep, - mat_pair) - - # check if destination material has a redox control - if mat_pair[0] in transfer_rates.redox: - transfer_matrix = chain.add_redox_term(transfer_matrix, - transfer_rates.redox[mat_pair[0]][0], - transfer_rates.redox[mat_pair[0]][1]) - transfer_pair[mat_pair] = transfer_matrix - - # Combine all matrices together in a single matrix of matrices - # to be solved in one go - n_rows = n_cols = len(transfer_rates.burnable_mats) - rows = [] - for row in range(n_rows): - cols = [] - for col in range(n_cols): - mat_pair = (transfer_rates.burnable_mats[row], - transfer_rates.burnable_mats[col]) - if row == col: - # Fill the diagonals with the Bateman matrices - cols.append(matrices[row]) - elif mat_pair in transfer_rates.index_transfer[current_timestep]: - # Fill the off-diagonals with the transfer pair matrices - cols.append(transfer_pair[mat_pair]) - else: - cols.append(None) - - rows.append(cols) - matrix = block_array(rows) - - # Concatenate vectors of nuclides in one - n_multi = np.concatenate(n) - n_result = func(matrix, n_multi, dt, substeps) - - # Split back the nuclide vector result into the original form - n_result = np.split(n_result, np.cumsum([len(i) for i in n])[:-1]) - - else: - n_result = None - - # Braodcast result to other ranks - n_result = comm.bcast(n_result) - # Distribute results across MPI - n_result = _distribute(n_result) - - return n_result - - if (external_source_rates is not None and - current_timestep in external_source_rates.external_timesteps): - # Calculate external source term vectors - sources = map(chain.form_ext_source_term, repeat(external_source_rates), - repeat(current_timestep), external_source_rates.local_mats) - - # stack vector column at the end of the matrix - matrices = [ - hstack([matrix, source]) - for matrix, source in zip(matrices, sources) - ] - - # Add a last row of zeroes to the matrices and append 1 to the last row - # of the nuclide vectors - for i, matrix in enumerate(matrices): - if not np.equal(*matrix.shape): - matrix.resize(matrix.shape[1], matrix.shape[1]) - n[i] = np.append(n[i], 1.0) - - inputs = zip(matrices, n, repeat(dt), repeat(substeps)) + inputs = zip(matrices, x, repeat(dt)) if USE_MULTIPROCESSING: with Pool(NUM_PROCESSES) as pool: - n_result = list(pool.starmap(func, inputs)) + x_result = list(pool.starmap(func, inputs)) else: - n_result = list(starmap(func, inputs)) + x_result = list(starmap(func, inputs)) - # Remove extra value at the end of the nuclide vectors - if (external_source_rates is not None and - current_timestep in external_source_rates.external_timesteps): - external_source_rates.reformat_nuclide_vectors(n) - external_source_rates.reformat_nuclide_vectors(n_result) - - return n_result + return x_result diff --git a/openmc/deplete/r2s.py b/openmc/deplete/r2s.py deleted file mode 100644 index 6c19531e7..000000000 --- a/openmc/deplete/r2s.py +++ /dev/null @@ -1,845 +0,0 @@ -from __future__ import annotations -from collections.abc import Sequence -from contextlib import nullcontext -import copy -from datetime import datetime -import json -from numbers import Integral -from pathlib import Path - -import numpy as np -import openmc -from . import IndependentOperator, PredictorIntegrator -from .chain import Chain -from .microxs import get_microxs_and_flux, write_microxs_hdf5, read_microxs_hdf5 -from .results import Results -from ..checkvalue import PathLike -from ..mpi import comm -from openmc.lib import TemporarySession - - -def get_activation_materials( - model: openmc.Model, - mmv_list: list[openmc.MeshMaterialVolumes] -) -> openmc.Materials: - """Get a list of activation materials for each mesh element/material. - - When performing a mesh-based R2S calculation, a unique material is needed - for each activation region, which is a combination of a mesh element and a - material within that mesh element. This function generates a list of such - materials, each with a unique name and volume corresponding to the mesh - element and material. - - Parameters - ---------- - model : openmc.Model - The full model containing the geometry and materials. - mmv_list : list of openmc.MeshMaterialVolumes - List of mesh material volumes objects, one per mesh, containing the - materials and their volumes for each mesh element. - - Returns - ------- - openmc.Materials - A list of materials, each corresponding to a unique mesh element and - material combination across all meshes. - - """ - # Get all materials in the model - material_dict = model._get_all_materials() - - # Create a new activation material for each element-material combination - # across all meshes - materials = openmc.Materials() - for mesh_idx, mmv in enumerate(mmv_list): - mat_ids = mmv._materials[mmv._materials > -1] - volumes = mmv._volumes[mmv._materials > -1] - elems, _ = np.where(mmv._materials > -1) - - for elem, mat_id, vol in zip(elems, mat_ids, volumes): - mat = material_dict[mat_id] - new_mat = mat.clone() - new_mat.depletable = True - new_mat.name = f'Mesh {mesh_idx}, Element {elem}, Material {mat_id}' - new_mat.volume = vol - materials.append(new_mat) - - return materials - - -class R2SManager: - """Manager for Rigorous 2-Step (R2S) method calculations. - - This class is responsible for managing the materials and sources needed for - mesh-based or cell-based R2S calculations. It provides methods to get - activation materials and decay photon sources based on the mesh/cells and - materials in the OpenMC model. Multiple meshes can be specified as domains, - in which case each element--material combination of each mesh is treated as - an activation region (meshes are assumed to be non-overlapping). - - This class supports the use of a different models for the neutron and photon - transport calculation. However, for cell-based calculations, it assumes that - the only changes in the model are material assignments. For mesh-based - calculations, it checks material assignments in the photon model and any - element--material combinations that don't appear in the photon model are - skipped. - - Parameters - ---------- - neutron_model : openmc.Model - The OpenMC model to use for neutron transport. - domains : openmc.MeshBase or Sequence[openmc.MeshBase] or Sequence[openmc.Cell] - The mesh(es) or a sequence of cells that represent the spatial units - over which the R2S calculation will be performed. When a single - :class:`~openmc.MeshBase` or a sequence of meshes is given, each - element--material combination across all meshes is treated as an - activation region. - photon_model : openmc.Model, optional - The OpenMC model to use for photon transport calculations. If None, a - shallow copy of the neutron_model will be created and used. - - Attributes - ---------- - domains : list of openmc.MeshBase or Sequence[openmc.Cell] - The meshes or a sequence of cells that represent the spatial units over - which the R2S calculation will be performed. - neutron_model : openmc.Model - The OpenMC model used for neutron transport. - photon_model : openmc.Model - The OpenMC model used for photon transport calculations. - method : {'mesh-based', 'cell-based'} - Indicates whether the R2S calculation uses mesh elements ('mesh-based') - as the spatial discretization or a list of cells ('cell-based'). - results : dict - A dictionary that stores results from the R2S calculation. - - """ - def __init__( - self, - neutron_model: openmc.Model, - domains: openmc.MeshBase | Sequence[openmc.MeshBase] | Sequence[openmc.Cell], - photon_model: openmc.Model | None = None, - ): - self.neutron_model = neutron_model - if photon_model is None: - # Create a shallow copy of the neutron model for photon transport - self.photon_model = openmc.Model( - geometry=copy.copy(neutron_model.geometry), - materials=copy.copy(neutron_model.materials), - settings=copy.copy(neutron_model.settings), - tallies=copy.copy(neutron_model.tallies), - plots=copy.copy(neutron_model.plots), - ) - else: - self.photon_model = photon_model - if isinstance(domains, openmc.MeshBase): - self.method = 'mesh-based' - self.domains = [domains] - elif isinstance(domains, Sequence) and len(domains) > 0 and \ - isinstance(domains[0], openmc.MeshBase): - self.method = 'mesh-based' - self.domains = list(domains) - else: - self.method = 'cell-based' - self.domains = list(domains) - self.results = {} - - def run( - self, - timesteps: Sequence[float] | Sequence[tuple[float, str]], - source_rates: float | Sequence[float], - timestep_units: str = 's', - photon_time_indices: Sequence[int] | None = None, - output_dir: PathLike | None = None, - bounding_boxes: dict[int, openmc.BoundingBox] | None = None, - chain_file: PathLike | Chain | None = None, - micro_kwargs: dict | None = None, - mat_vol_kwargs: dict | None = None, - run_kwargs: dict | None = None, - operator_kwargs: dict | None = None, - by_parent_nuclide: bool = False, - ): - """Run the R2S calculation. - - Parameters - ---------- - timesteps : Sequence[float] or Sequence[tuple[float, str]] - Sequence of timesteps. Note that values are not cumulative. The - units are specified by the `timestep_units` argument when - `timesteps` is an iterable of float. Alternatively, units can be - specified for each step by passing an iterable of (value, unit) - tuples. - source_rates : float or Sequence[float] - Source rate in [neutron/sec] for each interval in `timesteps`. - timestep_units : {'s', 'min', 'h', 'd', 'a'}, optional - Units for values specified in the `timesteps` argument when passing - float values. 's' means seconds, 'min' means minutes, 'h' means - hours, 'd' means days, and 'a' means years (Julian). - photon_time_indices : Sequence[int], optional - Sequence of time indices at which photon transport should be run; - represented as indices into the array of times formed by the - timesteps. For example, if two timesteps are specified, the array of - times would contain three entries, and [2] would indicate computing - photon results at the last time. A value of None indicates to run - photon transport at each time that has a decay photon source. - output_dir : PathLike, optional - Path to directory where R2S calculation outputs will be saved. If - not provided, a timestamped directory 'r2s_YYYY-MM-DDTHH-MM-SS' is - created. Subdirectories will be created for the neutron transport, - activation, and photon transport steps. - bounding_boxes : dict[int, openmc.BoundingBox], optional - Dictionary mapping cell IDs to bounding boxes used for spatial - source sampling in cell-based R2S calculations. Required if method - is 'cell-based'. - chain_file : PathLike or openmc.deplete.Chain, optional - Path to the depletion chain XML file or depletion chain object to - use during activation. If not provided, the default configured - chain file will be used. - micro_kwargs : dict, optional - Additional keyword arguments passed to - :func:`openmc.deplete.get_microxs_and_flux` during the neutron - transport step. - mat_vol_kwargs : dict, optional - Additional keyword arguments passed to - :meth:`openmc.MeshBase.material_volumes`. - run_kwargs : dict, optional - Additional keyword arguments passed to :meth:`openmc.Model.run` - during the neutron and photon transport step. By default, output is - disabled. - operator_kwargs : dict, optional - Additional keyword arguments passed to - :class:`openmc.deplete.IndependentOperator`. - by_parent_nuclide : bool, optional - Whether to score photon tallies separately for each parent - radionuclide. A :class:`~openmc.ParentNuclideFilter` is added to - tallies that do not already contain one, with bins determined from - the prepared decay photon sources. - - Returns - ------- - Path - Path to the output directory containing all calculation results - """ - - if output_dir is None: - # Create timestamped output directory and broadcast to all ranks for - # consistency (different ranks may have slightly different times) - stamp = datetime.now().strftime('%Y-%m-%dT%H-%M-%S') - output_dir = Path(comm.bcast(f'r2s_{stamp}')) - else: - output_dir = Path(output_dir) - - # Set run_kwargs for the neutron transport step - if micro_kwargs is None: - micro_kwargs = {} - if run_kwargs is None: - run_kwargs = {} - if operator_kwargs is None: - operator_kwargs = {} - run_kwargs.setdefault('output', False) - micro_kwargs.setdefault('run_kwargs', run_kwargs) - - # DecaySpectrum distributions are resolved in the C++ solver using - # OPENMC_CHAIN_FILE. If a Chain object was passed, write an XML - # representation alongside the R2S outputs. - if isinstance(chain_file, Chain): - output_dir.mkdir(parents=True, exist_ok=True) - chain_path = output_dir / 'chain.xml' - if comm.rank == 0: - chain_file.export_to_xml(chain_path) - comm.barrier() - else: - chain_path = chain_file - - chain_context = ( - openmc.config.patch('chain_file', chain_path) - if chain_path is not None else nullcontext() - ) - with chain_context: - self.step1_neutron_transport( - output_dir / 'neutron_transport', mat_vol_kwargs, micro_kwargs - ) - self.step2_activation( - timesteps, source_rates, timestep_units, - output_dir / 'activation', operator_kwargs=operator_kwargs - ) - self.step3_photon_source( - photon_time_indices, bounding_boxes, output_dir / 'photon_transport', - mat_vol_kwargs=mat_vol_kwargs, - ) - self.step4_photon_transport( - output_dir / 'photon_transport', run_kwargs=run_kwargs, - by_parent_nuclide=by_parent_nuclide, - ) - - return output_dir - - def step1_neutron_transport( - self, - output_dir: PathLike = "neutron_transport", - mat_vol_kwargs: dict | None = None, - micro_kwargs: dict | None = None - ): - """Run the neutron transport step. - - This step computes the material volume fractions on each mesh, creates - mesh-material filters, and retrieves the fluxes and microscopic cross - sections for each mesh/material combination via a single transport - solve. This step will populate the 'fluxes' and 'micros' keys in the - results dictionary. For a mesh-based calculation, it will also populate - the 'mesh_material_volumes' key (a list of - :class:`~openmc.MeshMaterialVolumes`, one per mesh). - - Parameters - ---------- - output_dir : PathLike, optional - The directory where the results will be saved. - mat_vol_kwargs : dict, optional - Additional keyword arguments based to - :meth:`openmc.MeshBase.material_volumes`. - micro_kwargs : dict, optional - Additional keyword arguments passed to - :func:`openmc.deplete.get_microxs_and_flux`. - - """ - - output_dir = Path(output_dir).resolve() - output_dir.mkdir(parents=True, exist_ok=True) - - if self.method == 'mesh-based': - # Compute material volume fractions on each mesh - if mat_vol_kwargs is None: - mat_vol_kwargs = {} - mat_vol_kwargs.setdefault('bounding_boxes', True) - - mmv_list = [] - domain_filters = [] - for i, mesh in enumerate(self.domains): - mmv = comm.bcast( - mesh.material_volumes(self.neutron_model, **mat_vol_kwargs)) - mmv_list.append(mmv) - - # Save results to file - if comm.rank == 0: - mmv.save(output_dir / f'mesh_material_volumes_{i}.npz') - - # Create mesh-material filter for this mesh - domain_filters.append( - openmc.MeshMaterialFilter.from_volumes(mesh, mmv)) - - self.results['mesh_material_volumes'] = mmv_list - domains = domain_filters - else: - domains: Sequence[openmc.Cell] = self.domains - - # Check to make sure that each cell is filled with a material and - # that the volume has been set - - # TODO: If volumes are not set, run volume calculation for cells - for cell in domains: - if cell.fill is None: - raise ValueError( - f"Cell {cell.id} is not filled with a materials. " - "Please set the fill material for each cell before " - "running the R2S calculation." - ) - if cell.volume is None: - raise ValueError( - f"Cell {cell.id} does not have a volume set. " - "Please set the volume for each cell before running " - "the R2S calculation." - ) - - # Set default keyword arguments for microxs and flux calculation - if micro_kwargs is None: - micro_kwargs = {} - micro_kwargs.setdefault('path_statepoint', output_dir / 'statepoint.h5') - micro_kwargs.setdefault('path_input', output_dir / 'model.xml') - - # Run neutron transport and get fluxes and micros. Run via openmc.lib to - # maintain a consistent parallelism strategy with the activation step. - with TemporarySession(output=False): - self.results['fluxes'], self.results['micros'] = get_microxs_and_flux( - self.neutron_model, domains, **micro_kwargs) - - # Save flux and micros to file - if comm.rank == 0: - np.save(output_dir / 'fluxes.npy', self.results['fluxes']) - write_microxs_hdf5(self.results['micros'], output_dir / 'micros.h5') - - def step2_activation( - self, - timesteps: Sequence[float] | Sequence[tuple[float, str]], - source_rates: float | Sequence[float], - timestep_units: str = 's', - output_dir: PathLike = 'activation', - operator_kwargs: dict | None = None, - ): - """Run the activation step. - - This step creates a unique copy of each activation material based on the - mesh elements or cells, then solves the depletion equations for each - material using the fluxes and microscopic cross sections obtained in the - neutron transport step. This step will populate the 'depletion_results' - and 'activation_materials' keys in the results dictionary. - - Parameters - ---------- - timesteps : Sequence[float] or Sequence[tuple[float, str]] - Sequence of timesteps. Note that values are not cumulative. The - units are specified by the `timestep_units` argument when - `timesteps` is an iterable of float. Alternatively, units can be - specified for each step by passing an iterable of (value, unit) - tuples. - source_rates : float | Sequence[float] - Source rate in [neutron/sec] for each interval in `timesteps`. - timestep_units : {'s', 'min', 'h', 'd', 'a'}, optional - Units for values specified in the `timesteps` argument when passing - float values. 's' means seconds, 'min' means minutes, 'h' means - hours, 'd' means days, and 'a' means years (Julian). - output_dir : PathLike, optional - Path to directory where activation calculation outputs will be - saved. - operator_kwargs : dict, optional - Additional keyword arguments passed to - :class:`openmc.deplete.IndependentOperator`. - """ - - if self.method == 'mesh-based': - # Get unique material for each (mesh, material) combination - mmv_list = self.results['mesh_material_volumes'] - self.results['activation_materials'] = get_activation_materials( - self.neutron_model, mmv_list) - else: - # Create unique material for each cell - activation_mats = openmc.Materials() - for cell in self.domains: - mat = cell.fill.clone() - mat.name = f'Cell {cell.id}' - mat.depletable = True - mat.volume = cell.volume - activation_mats.append(mat) - self.results['activation_materials'] = activation_mats - - # Save activation materials to file - output_dir = Path(output_dir) - output_dir.mkdir(parents=True, exist_ok=True) - self.results['activation_materials'].export_to_xml( - output_dir / 'materials.xml') - - # Create depletion operator for the activation materials - if operator_kwargs is None: - operator_kwargs = {} - operator_kwargs.setdefault('normalization_mode', 'source-rate') - op = IndependentOperator( - self.results['activation_materials'], - self.results['fluxes'], - self.results['micros'], - **operator_kwargs - ) - - # Create time integrator and solve depletion equations - integrator = PredictorIntegrator( - op, timesteps, source_rates=source_rates, timestep_units=timestep_units - ) - output_path = output_dir / 'depletion_results.h5' - integrator.integrate(final_step=False, path=output_path) - comm.barrier() - - # Get depletion results - self.results['depletion_results'] = Results(output_path) - - def step3_photon_source( - self, - time_indices: Sequence[int] | None = None, - bounding_boxes: dict[int, openmc.BoundingBox] | None = None, - output_dir: PathLike = 'photon_transport', - mat_vol_kwargs: dict | None = None, - ): - """Create decay photon sources. - - This step creates decay photon sources from the activated materials for - each specified time. In mesh-based mode, the sources are created using - mesh material volumes, while in cell-based mode, they are created using - bounding boxes for each cell. This step will populate the - 'photon_sources' key in the results dictionary. - - Parameters - ---------- - time_indices : Sequence[int], optional - Sequence of time indices at which photon transport should be run; - represented as indices into the array of times formed by the - timesteps. For example, if two timesteps are specified, the array of - times would contain three entries, and [2] would indicate computing - photon results at the last time. A value of None indicates to run - photon transport at each time that has a decay photon source. - bounding_boxes : dict[int, openmc.BoundingBox], optional - Dictionary mapping cell IDs to bounding boxes used for spatial - source sampling in cell-based R2S calculations. Required if method - is 'cell-based'. - output_dir : PathLike, optional - Path to directory where photon source outputs will be saved. - mat_vol_kwargs : dict, optional - Additional keyword arguments passed to - :meth:`openmc.MeshBase.material_volumes`. - """ - - # Do not retain sources from an earlier successful call if this source - # preparation attempt fails. - self.results.pop('photon_sources', None) - - # TODO: Automatically determine bounding box for each cell - if bounding_boxes is None and self.method == 'cell-based': - raise ValueError("bounding_boxes must be provided for cell-based " - "R2S calculations.") - - output_dir = Path(output_dir) - output_dir.mkdir(parents=True, exist_ok=True) - - # Determine and validate time indices before preparing source data. - n_steps = len(self.results['depletion_results']) - implicit_time_indices = time_indices is None - if time_indices is None: - time_indices = list(range(n_steps)) - else: - time_indices = list(time_indices) - if not time_indices: - raise ValueError('time_indices must contain at least one index') - - normalized_indices = [] - for index in time_indices: - if isinstance(index, bool) or not isinstance(index, Integral): - raise TypeError('time_indices must contain only integers') - index = int(index) - if index < -n_steps or index >= n_steps: - raise IndexError( - f'Photon time index {index} is out of range for ' - f'{n_steps} depletion results') - normalized_index = index % n_steps - normalized_indices.append(normalized_index) - - # Remove duplicates while preserving order - time_indices = list(dict.fromkeys(normalized_indices)) - - # Check whether the photon model is different - neutron_univ = self.neutron_model.geometry.root_universe - photon_univ = self.photon_model.geometry.root_universe - different_photon_model = (neutron_univ != photon_univ) - - # For mesh-based calculations, compute material volume fractions for the - # photon model if it is different from the neutron model to account for - # potential material changes - if self.method == 'mesh-based' and different_photon_model: - if mat_vol_kwargs is None: - mat_vol_kwargs = {} - photon_mmv_list = [] - for i, mesh in enumerate(self.domains): - photon_mmv = comm.bcast( - mesh.material_volumes(self.photon_model, **mat_vol_kwargs)) - photon_mmv_list.append(photon_mmv) - - # Save photon MMV results to file - if comm.rank == 0: - photon_mmv.save( - output_dir / f'mesh_material_volumes_{i}.npz') - - self.results['mesh_material_volumes_photon'] = photon_mmv_list - - # Get dictionary of cells in the photon model - if different_photon_model: - photon_cells = self.photon_model.geometry.get_all_cells() - - # Determine eligible work items upfront (independent of time index). - if self.method == 'mesh-based': - work_items = self._get_mesh_work_items() - else: - work_items = [] - for cell, original_mat in zip( - self.domains, self.results['activation_materials']): - if different_photon_model: - if cell.id not in photon_cells or \ - cell.fill.id != photon_cells[cell.id].fill.id: - continue - work_items.append((cell, original_mat, bounding_boxes[cell.id])) - - # Create decay photon sources for each time index - photon_sources = { - time_index: self._create_photon_sources(time_index, work_items) - for time_index in time_indices - } - - # Determine if any times have no decay photon sources. If the user - # didn't specify any specific time indices, remove those times from the - # photon_sources dictionary. If the user did specify time indices, raise - # an error if any of those times have no decay photon sources. - empty_indices = [ - time_index for time_index, sources in photon_sources.items() - if not sources - ] - if implicit_time_indices: - for time_index in empty_indices: - del photon_sources[time_index] - if not photon_sources: - raise RuntimeError( - 'No decay photon sources were found at any depletion time') - elif empty_indices: - indices = ', '.join(str(index) for index in empty_indices) - raise RuntimeError( - f'No decay photon source was found for requested time ' - f'indices: {indices}') - - self.results['photon_sources'] = photon_sources - - def step4_photon_transport( - self, - output_dir: PathLike = 'photon_transport', - run_kwargs: dict | None = None, - by_parent_nuclide: bool = False, - ): - """Run photon transport using prepared decay photon sources. - - This step runs a photon transport calculation for each source list - created by :meth:`step3_photon_source`. It will populate the - 'photon_tallies' key in the results dictionary. - - Parameters - ---------- - output_dir : PathLike, optional - Path to directory where photon transport outputs will be saved. - run_kwargs : dict, optional - Additional keyword arguments passed to :meth:`openmc.Model.run`. - By default, output is disabled. - by_parent_nuclide : bool, optional - Whether to score photon tallies separately for each parent - radionuclide. A :class:`~openmc.ParentNuclideFilter` is added to - tallies that do not already contain one, with bins determined from - the prepared decay photon sources. - """ - if 'photon_sources' not in self.results: - raise RuntimeError( - 'Photon sources must be created with step3_photon_source ' - 'before running photon transport.') - photon_sources = self.results['photon_sources'] - if not photon_sources: - raise RuntimeError( - 'No decay photon sources are available for transport') - - if by_parent_nuclide: - radionuclides = sorted({ - nuclide - for sources in photon_sources.values() - for source in sources - for nuclide in source.energy.nuclides - }) - - if radionuclides: - parent_filter = openmc.ParentNuclideFilter(radionuclides) - for tally in self.photon_model.tallies: - if not tally.contains_filter(openmc.ParentNuclideFilter): - tally.filters.append(parent_filter) - - if run_kwargs is None: - run_kwargs = {} - run_kwargs.setdefault('output', False) - - output_dir = Path(output_dir) - output_dir.mkdir(parents=True, exist_ok=True) - - if comm.rank == 0: - tally_ids = [tally.id for tally in self.photon_model.tallies] - with open(output_dir / 'tally_ids.json', 'w') as f: - json.dump(tally_ids, f) - - self.results['photon_tallies'] = {} - - # Ensure photon transport is enabled in settings. - self.photon_model.settings.photon_transport = True - - for time_index, sources in photon_sources.items(): - self.photon_model.settings.source = sources - - # Run photon transport calculation - photon_dir = Path(output_dir) / f'time_{time_index}' - with TemporarySession(self.photon_model, cwd=photon_dir): - statepoint_path = self.photon_model.run(**run_kwargs) - - # Store tally results - with openmc.StatePoint(statepoint_path) as sp: - self.results['photon_tallies'][time_index] = [ - sp.tallies[tally.id] for tally in self.photon_model.tallies - ] - - def _get_mesh_work_items(self): - """Enumerate mesh-based work items across all meshes. - - Returns a list of (index_mat, mat_id, bbox) tuples for each eligible - mesh element--material combination, where index_mat is the index into - the activation materials list, mat_id is the material ID, and bbox is - the bounding box for that mesh element--material combination. - - Returns - ------- - list of tuple - Each tuple is (index_mat, mat_id, bbox). - """ - mmv_list = self.results['mesh_material_volumes'] - photon_mmv_list = self.results.get('mesh_material_volumes_photon') - - work_items = [] - index_mat = 0 - for mesh_idx, mat_vols in enumerate(mmv_list): - photon_mat_vols = photon_mmv_list[mesh_idx] \ - if photon_mmv_list is not None else None - - n_elements = mat_vols.num_elements - for index_elem in range(n_elements): - if photon_mat_vols is not None: - photon_materials = { - mat_id - for mat_id, _ in photon_mat_vols.by_element(index_elem) - if mat_id is not None - } - - for mat_id, _, bbox in mat_vols.by_element( - index_elem, include_bboxes=True): - if mat_id is None: - continue - if photon_mat_vols is not None \ - and mat_id not in photon_materials: - index_mat += 1 - continue - work_items.append((index_mat, mat_id, bbox)) - index_mat += 1 - - return work_items - - def _create_photon_sources(self, time_index, work_items): - """Create decay photon sources for a set of regions. - - Builds :class:`openmc.IndependentSource` objects with - :class:`openmc.stats.DecaySpectrum` energy distributions that will be - serialized to XML and resolved against the depletion chain by the C++ - solver. - - Parameters - ---------- - time_index : int - Index into depletion results. - work_items : list of tuple - For mesh-based: list of (index_mat, mat_id, bbox). - For cell-based: list of (cell, original_mat, bbox). - - Returns - ------- - list of openmc.IndependentSource - Photon sources for each activated region. - """ - step_result = self.results['depletion_results'][time_index] - materials = self.results['activation_materials'] - mesh_based = self.method == 'mesh-based' - if mesh_based: - mat_dict = self.neutron_model._get_all_materials() - - sources = [] - for item in work_items: - if mesh_based: - index_mat, domain_id, bbox = item - original_mat = materials[index_mat] - domain = mat_dict[domain_id] - else: - cell, original_mat, bbox = item - domain = cell - - activated_mat = step_result.get_material(str(original_mat.id)) - nuclides = activated_mat.get_nuclide_atom_densities() - if not nuclides: - continue - - # Eliminate nuclides with zero density - nuclides = {nuclide: density for nuclide, density in nuclides.items() - if density > 0} - - energy = openmc.stats.DecaySpectrum(nuclides, activated_mat.volume) - energy.clip(inplace=True) - if not energy.nuclides: - continue - - sources.append(openmc.IndependentSource( - space=openmc.stats.Box(bbox.lower_left, bbox.upper_right), - energy=energy, - particle='photon', - constraints={'domains': [domain]}, - )) - - return sources - - def load_results(self, path: PathLike): - """Load results from a previous R2S calculation. - - Parameters - ---------- - path : PathLike - Path to the directory containing the R2S calculation results. - - """ - path = Path(path) - - # Load neutron transport results - neutron_dir = path / 'neutron_transport' - if self.method == 'mesh-based': - mmv_files = sorted(neutron_dir.glob('mesh_material_volumes*.npz'), - key=lambda p: int(p.stem.split('_')[-1]) - if p.stem[-1].isdigit() else 0) - if mmv_files: - self.results['mesh_material_volumes'] = [ - openmc.MeshMaterialVolumes.from_npz(f) for f in mmv_files - ] - fluxes_file = neutron_dir / 'fluxes.npy' - if fluxes_file.exists(): - self.results['fluxes'] = list(np.load(fluxes_file, allow_pickle=True)) - micros_dict = read_microxs_hdf5(neutron_dir / 'micros.h5') - self.results['micros'] = [ - micros_dict[f'domain_{i}'] for i in range(len(micros_dict)) - ] - - # Load activation results - activation_dir = path / 'activation' - activation_results = activation_dir / 'depletion_results.h5' - if activation_results.exists(): - self.results['depletion_results'] = Results(activation_results) - activation_mats_file = activation_dir / 'materials.xml' - if activation_mats_file.exists(): - self.results['activation_materials'] = \ - openmc.Materials.from_xml(activation_mats_file) - - # Load photon transport results - photon_dir = path / 'photon_transport' - - # Load photon mesh material volumes if they exist (for mesh-based calculations) - if self.method == 'mesh-based': - photon_mmv_files = sorted( - photon_dir.glob('mesh_material_volumes*.npz'), - key=lambda p: int(p.stem.split('_')[-1]) - if p.stem[-1].isdigit() else 0) - if photon_mmv_files: - self.results['mesh_material_volumes_photon'] = [ - openmc.MeshMaterialVolumes.from_npz(f) - for f in photon_mmv_files - ] - - # Load tally IDs from JSON file - tally_ids_path = photon_dir / 'tally_ids.json' - if tally_ids_path.exists(): - with tally_ids_path.open('r') as f: - tally_ids = json.load(f) - self.results['photon_tallies'] = {} - - # For each photon transport calc, load the statepoint and get the - # tally results based on tally_ids - for time_dir in photon_dir.glob('time_*'): - time_index = int(time_dir.name.split('_')[1]) - for sp_path in time_dir.glob('statepoint.*.h5'): - with openmc.StatePoint(sp_path) as sp: - self.results['photon_tallies'][time_index] = [ - sp.tallies[tally_id] for tally_id in tally_ids - ] diff --git a/openmc/deplete/reaction_rates.py b/openmc/deplete/reaction_rates.py index 714d9048b..299f1133f 100644 --- a/openmc/deplete/reaction_rates.py +++ b/openmc/deplete/reaction_rates.py @@ -2,7 +2,6 @@ An ndarray to store reaction rates with string, integer, or slice indexing. """ - import numpy as np @@ -30,11 +29,11 @@ class ReactionRates(np.ndarray): Attributes ---------- - index_mat : dict of str to int + index_mat : OrderedDict of str to int A dictionary mapping material ID as string to index. - index_nuc : dict of str to int + index_nuc : OrderedDict of str to int A dictionary mapping nuclide name as string to index. - index_rx : dict of str to int + index_rx : OrderedDict of str to int A dictionary mapping reaction name as string to index. n_mat : int Number of materials. @@ -52,10 +51,6 @@ class ReactionRates(np.ndarray): # the __array_finalize__ method (discussed here: # https://docs.scipy.org/doc/numpy/user/basics.subclassing.html) - index_mat: dict[str, int] - index_nuc: dict[str, int] - index_rx: dict[str, int] - def __new__(cls, local_mats, nuclides, reactions, from_results=False): # Create appropriately-sized zeroed-out ndarray shape = (len(local_mats), len(nuclides), len(reactions)) diff --git a/openmc/deplete/results.py b/openmc/deplete/results.py index 0cf0141d2..b38dcf058 100644 --- a/openmc/deplete/results.py +++ b/openmc/deplete/results.py @@ -1,34 +1,21 @@ -from __future__ import annotations - import numbers import bisect import math -from collections.abc import Iterable -from typing import Literal from warnings import warn import h5py import numpy as np -import openmc -from .chain import Chain, _get_chain from .stepresult import StepResult, VERSION_RESULTS import openmc.checkvalue as cv -from openmc.data import atomic_mass, AVOGADRO from openmc.data.library import DataLibrary from openmc.material import Material, Materials from openmc.exceptions import DataError -from openmc.checkvalue import PathLike __all__ = ["Results", "ResultsList"] -_SECONDS_PER_MINUTE = 60 -_SECONDS_PER_HOUR = 60*60 -_SECONDS_PER_DAY = 24*60*60 -_SECONDS_PER_JULIAN_YEAR = 365.25*24*60*60 # 365.25 due to the leap year - -def _get_time_as(seconds: float, units: str) -> float: +def _get_time_as(seconds, units): """Converts the time in seconds to time in different units Parameters @@ -41,13 +28,13 @@ def _get_time_as(seconds: float, units: str) -> float: """ if units == "a": - return seconds / _SECONDS_PER_JULIAN_YEAR + return seconds / (60 * 60 * 24 * 365.25) # 365.25 due to the leap year if units == "d": - return seconds / _SECONDS_PER_DAY + return seconds / (60 * 60 * 24) elif units == "h": - return seconds / _SECONDS_PER_HOUR + return seconds / (60 * 60) elif units == "min": - return seconds / _SECONDS_PER_MINUTE + return seconds / 60 else: return seconds @@ -64,11 +51,11 @@ class Results(list): Parameters ---------- - filename : str, optional + filename : str Path to depletion result file """ - def __init__(self, filename='depletion_results.h5'): + def __init__(self, filename=None): data = [] if filename is not None: with h5py.File(str(filename), "r") as fh: @@ -81,8 +68,9 @@ class Results(list): data.append(StepResult.from_hdf5(fh, i)) super().__init__(data) + @classmethod - def from_hdf5(cls, filename: PathLike): + def from_hdf5(cls, filename): """Load in depletion results from a previous file Parameters @@ -103,88 +91,16 @@ class Results(list): ) return cls(filename) - def get_activity( - self, - mat: Material | str, - units: str = "Bq/cm3", - by_nuclide: bool = False, - volume: float | None = None, - chain_file: Literal[False] | None | PathLike | Chain = None - ) -> tuple[np.ndarray, np.ndarray | list[dict]]: - """Get activity of material over time. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - mat : openmc.Material, str - Material object or material id to evaluate - units : {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Bq/m3'} - Specifies the type of activity to return, options include total - activity [Bq], specific [Bq/g, Bq/kg] or volumetric activity - [Bq/cm3]. - by_nuclide : bool - Specifies if the activity should be returned for the material as a - whole or per nuclide. Default is False. - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - chain_file : False, None, PathLike, or openmc.deplete.Chain, optional - Source of half-life values. If ``False``, only ENDF/B-VIII.0 data is - used. If ``None``, the chain specified by - ``openmc.config['chain_file']`` is used when available. If a path or - :class:`openmc.deplete.Chain` is given, that chain is used. For - ``None`` or an explicit chain, nuclides absent from the chain fall - back to ENDF/B-VIII.0 data. - - .. versionadded:: 0.15.4 - - Returns - ------- - times : numpy.ndarray - Array of times in [s] - activities : numpy.ndarray or List[dict] - Array of total activities if by_nuclide = False (default) or list of - dictionaries of activities by nuclide if by_nuclide = True. - - """ - if isinstance(mat, Material): - mat_id = str(mat.id) - elif isinstance(mat, str): - mat_id = mat - else: - raise TypeError('mat should be of type openmc.Material or str') - - if chain_file is not False: - if chain_file is None: - if openmc.config.get('chain_file') is not None: - chain_file = _get_chain(None) - else: - chain_file = _get_chain(chain_file) - - times = np.empty_like(self, dtype=float) - if by_nuclide: - activities = [None] * len(self) - else: - activities = np.empty_like(self, dtype=float) - - # Evaluate activity for each depletion time - for i, result in enumerate(self): - times[i] = result.time[0] - activities[i] = result.get_material(mat_id).get_activity( - units, by_nuclide, volume, chain_file=chain_file) - - return times, activities - - def get_atoms( - self, - mat: Material | str, - nuc: str, - nuc_units: str = "atoms", - time_units: str = "s" - ) -> tuple[np.ndarray, np.ndarray]: + def get_atoms(self, mat, nuc, nuc_units="atoms", time_units="s"): """Get number of nuclides over time from a single material + .. note:: + Initial values for some isotopes that do not appear in + initial concentrations may be non-zero, depending on the + value of the :attr:`openmc.deplete.CoupledOperator.dilute_initial` + attribute. The :class:`openmc.deplete.CoupledOperator` class adds + isotopes according to this setting, which can be set to zero. + Parameters ---------- mat : openmc.Material, str @@ -226,7 +142,7 @@ class Results(list): # Evaluate value in each region for i, result in enumerate(self): times[i] = result.time[0] - concentrations[i] = result[mat_id, nuc] + concentrations[i] = result[0, mat_id, nuc] # Unit conversions times = _get_time_as(times, time_units) @@ -239,123 +155,17 @@ class Results(list): return times, concentrations - def get_decay_heat( - self, - mat: Material | str, - units: str = "W", - by_nuclide: bool = False, - volume: float | None = None - ) -> tuple[np.ndarray, np.ndarray | list[dict]]: - """Get decay heat of material over time. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - mat : openmc.Material, str - Material object or material id to evaluate. - units : {'W', 'W/g', 'W/kg', 'W/cm3', 'W/m3'} - Specifies the units of decay heat to return. Options include total - heat [W], specific [W/g, W/kg] or volumetric heat [W/cm3]. - by_nuclide : bool - Specifies if the decay heat should be returned for the material as a - whole or per nuclide. Default is False. - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - - Returns - ------- - times : numpy.ndarray - Array of times in [s] - decay_heat : numpy.ndarray or list[dict] - Array of total decay heat values if by_nuclide = False (default) - or list of dictionaries of decay heat values by nuclide if - by_nuclide = True. - """ - - if isinstance(mat, Material): - mat_id = str(mat.id) - elif isinstance(mat, str): - mat_id = mat - else: - raise TypeError('mat should be of type openmc.Material or str') - - times = np.empty_like(self, dtype=float) - if by_nuclide: - decay_heat = [None] * len(self) - else: - decay_heat = np.empty_like(self, dtype=float) - - # Evaluate decay heat for each depletion time - for i, result in enumerate(self): - times[i] = result.time[0] - decay_heat[i] = result.get_material(mat_id).get_decay_heat( - units, by_nuclide, volume) - - return times, decay_heat - - def get_mass(self, - mat: Material | str, - nuc: str, - mass_units: str = "g", - time_units: str = "s" - ) -> tuple[np.ndarray, np.ndarray]: - """Get mass of nuclides over time from a single material - - .. versionadded:: 0.14.0 - - Parameters - ---------- - mat : openmc.Material, str - Material object or material id to evaluate - nuc : str - Nuclide name to evaluate - mass_units : {"g", "g/cm3", "kg"}, optional - Units for the returned mass. - time_units : {"s", "min", "h", "d", "a"}, optional - Units for the returned time array. Default is ``"s"`` to - return the value in seconds. Other options are minutes ``"min"``, - hours ``"h"``, days ``"d"``, and Julian years ``"a"``. - - Returns - ------- - times : numpy.ndarray - Array of times in units of ``time_units`` - mass : numpy.ndarray - Mass of specified nuclide in units of ``mass_units`` - - """ - cv.check_value("mass_units", mass_units, {"g", "g/cm3", "kg"}) - - if isinstance(mat, Material): - mat_id = str(mat.id) - elif isinstance(mat, str): - mat_id = mat - else: - raise TypeError('mat should be of type openmc.Material or str') - - times, atoms = self.get_atoms(mat, nuc, time_units=time_units) - - mass = atoms * atomic_mass(nuc) / AVOGADRO - - # Unit conversions - if mass_units == "g/cm3": - # Divide by volume to get density - mass /= self[0].volume[mat_id] - elif mass_units == "kg": - mass /= 1e3 - - return times, mass - - def get_reaction_rate( - self, - mat: Material | str, - nuc: str, - rx: str - ) -> tuple[np.ndarray, np.ndarray]: + def get_reaction_rate(self, mat, nuc, rx): """Get reaction rate in a single material/nuclide over time + .. note:: + + Initial values for some isotopes that do not appear in + initial concentrations may be non-zero, depending on the + value of :class:`openmc.deplete.CoupledOperator` ``dilute_initial`` + The :class:`openmc.deplete.CoupledOperator` adds isotopes according + to this setting, which can be set to zero. + Parameters ---------- mat : openmc.Material, str @@ -386,11 +196,11 @@ class Results(list): # Evaluate value in each region for i, result in enumerate(self): times[i] = result.time[0] - rates[i] = result.rates.get(mat_id, nuc, rx) * result[mat, nuc] + rates[i] = result.rates[0].get(mat_id, nuc, rx) * result[0, mat, nuc] return times, rates - def get_keff(self, time_units: str = 's') -> tuple[np.ndarray, np.ndarray]: + def get_keff(self, time_units='s'): """Evaluates the eigenvalue from a results list. .. versionadded:: 0.13.1 @@ -420,18 +230,18 @@ class Results(list): # Get time/eigenvalue at each point for i, result in enumerate(self): times[i] = result.time[0] - eigenvalues[i] = result.k + eigenvalues[i] = result.k[0] # Convert time units if necessary times = _get_time_as(times, time_units) return times, eigenvalues - def get_eigenvalue(self, time_units: str = 's') -> tuple[np.ndarray, np.ndarray]: + def get_eigenvalue(self, time_units='s'): warn("The get_eigenvalue(...) function has been renamed get_keff and " "will be removed in a future version of OpenMC.", FutureWarning) return self.get_keff(time_units) - def get_depletion_time(self) -> np.ndarray: + def get_depletion_time(self): """Return an array of the average time to deplete a material .. note:: @@ -459,7 +269,7 @@ class Results(list): times[ix] = res.proc_time return times - def get_times(self, time_units: str = "d") -> np.ndarray: + def get_times(self, time_units="d") -> np.ndarray: """Return the points in time that define the depletion schedule .. versionadded:: 0.12.1 @@ -487,28 +297,8 @@ class Results(list): return _get_time_as(times, time_units) - def get_source_rates(self) -> np.ndarray: - """ - .. versionadded:: 0.15.1 - - Returns - ------- - numpy.ndarray - 1-D vector of source rates at each point in the depletion simulation - with the units originally defined by the user. - - """ - # Results duplicate the final source rate at the final simulation time - source_rates = np.fromiter( - (r.source_rate for r in self), - dtype=self[0].source_rate.dtype, - count=len(self)-1, - ) - - return source_rates - def get_step_where( - self, time, time_units: str = "d", atol: float = 1e-6, rtol: float = 1e-3 + self, time, time_units="d", atol=1e-6, rtol=1e-3 ) -> int: """Return the index closest to a given point in time @@ -562,19 +352,13 @@ class Results(list): if math.isclose(time, times[ix], rel_tol=rtol, abs_tol=atol): return ix - closest = min(times, key=lambda t: abs(time - t)) raise ValueError( - f"A value of {time} {time_units} was not found given absolute and " - f"relative tolerances {atol} and {rtol}. Closest time is {closest} " - f"{time_units}." + "A value of {} {} was not found given absolute and " + "relative tolerances {} and {}.".format( + time, time_units, atol, rtol) ) - def export_to_materials( - self, - burnup_index: int, - nuc_with_data: Iterable[str] | None = None, - path: PathLike = 'materials.xml' - ) -> Materials: + def export_to_materials(self, burnup_index, nuc_with_data=None) -> Materials: """Return openmc.Materials object based on results at a given step .. versionadded:: 0.12.1 @@ -591,11 +375,7 @@ class Results(list): as such cannot be used in subsequent transport calculations. If not provided, nuclides from the cross_sections element of materials.xml will be used. If that element is not present, - nuclides from openmc.config['cross_sections'] will be used. - path : PathLike - Path to materials XML file to read. Defaults to 'materials.xml'. - - .. versionadded:: 0.13.3 + nuclides from OPENMC_CROSS_SECTIONS will be used. Returns ------- @@ -609,13 +389,13 @@ class Results(list): # updated. If for some reason you have modified OpenMC to produce # new materials as depletion takes place, this method will not # work as expected and leave out that material. - mat_file = Materials.from_xml(path) + mat_file = Materials.from_xml("materials.xml") # Only nuclides with valid transport data will be written to # the new materials XML file. The precedence of nuclides to select # is first ones provided as a kwarg here, then ones specified # in the materials.xml file if provided, then finally from - # openmc.config['cross_sections']. + # the environment variable OPENMC_CROSS_SECTIONS. if nuc_with_data: cv.check_iterable_type('nuclide names', nuc_with_data, str) available_cross_sections = nuc_with_data @@ -638,7 +418,7 @@ class Results(list): # results, and save them to the new depleted xml file. for mat in mat_file: mat_id = str(mat.id) - if mat_id in result.index_mat: + if mat_id in result.mat_to_ind: mat.volume = result.volume[mat_id] # Change density of all nuclides in material to atom/b-cm @@ -650,10 +430,10 @@ class Results(list): # For nuclides in chain that have cross sections, replace # density in original material with new density from results - for nuc in result.index_nuc: + for nuc in result.nuc_to_ind: if nuc not in available_cross_sections: continue - atoms = result[mat_id, nuc] + atoms = result[0, mat_id, nuc] if atoms > 0.0: atoms_per_barn_cm = 1e-24 * atoms / mat.volume mat.remove_nuclide(nuc) # Replace if it's there diff --git a/openmc/deplete/stepresult.py b/openmc/deplete/stepresult.py index 9f638a058..db5260c80 100644 --- a/openmc/deplete/stepresult.py +++ b/openmc/deplete/stepresult.py @@ -4,20 +4,17 @@ Contains capabilities for generating and saving results of a single depletion timestep. """ +from collections import OrderedDict import copy -import warnings -from pathlib import Path import h5py import numpy as np import openmc -from openmc.checkvalue import PathLike -from openmc.mpi import MPI, comm - +from openmc.mpi import comm, MPI from .reaction_rates import ReactionRates -VERSION_RESULTS = (1, 3) +VERSION_RESULTS = (1, 1) __all__ = ["StepResult"] @@ -31,8 +28,8 @@ class StepResult: Attributes ---------- - k : tuple of (float, float) - Eigenvalue and uncertainty at end of step. + k : list of (float, float) + Eigenvalue and uncertainty for each substep. time : list of float Time at beginning, end of step, in seconds. source_rate : float @@ -41,25 +38,25 @@ class StepResult: Number of mats. n_nuc : int Number of nuclides. - rates : ReactionRates - The reaction rates at end of step. - volume : dict of str to float + rates : list of ReactionRates + The reaction rates for each substep. + volume : OrderedDict of str to float Dictionary mapping mat id to volume. - index_mat : dict of str to int + mat_to_ind : OrderedDict of str to int A dictionary mapping mat ID as string to index. - index_nuc : dict of str to int + nuc_to_ind : OrderedDict of str to int A dictionary mapping nuclide name as string to index. - mat_to_hdf5_ind : dict of str to int + mat_to_hdf5_ind : OrderedDict of str to int A dictionary mapping mat ID as string to global index. n_hdf5_mats : int Number of materials in entire geometry. + n_stages : int + Number of stages in simulation. data : numpy.ndarray - Atom quantity, stored by mat, then by nuclide. + Atom quantity, stored by stage, mat, then by nuclide. proc_time : int Average time spent depleting a material across all materials and processes - keff_search_root : float - The root returned by the keff search control. """ def __init__(self): @@ -70,13 +67,11 @@ class StepResult: self.volume = None self.proc_time = None - self.index_mat = None - self.index_nuc = None + self.mat_to_ind = None + self.nuc_to_ind = None self.mat_to_hdf5_ind = None - self.name_list = None self.data = None - self.keff_search_root = None def __repr__(self): t = self.time[0] @@ -89,25 +84,25 @@ class StepResult: Parameters ---------- pos : tuple - A two-length tuple containing a mat index and a nuc - index. Both can be integers or slices, or can be + A three-length tuple containing a stage index, mat index and a nuc + index. All can be integers or slices. The second two can be strings corresponding to their respective dictionary. Returns ------- float - The atoms for mat, nuc + The atoms for stage, mat, nuc """ - mat, nuc = pos + stage, mat, nuc = pos if isinstance(mat, openmc.Material): mat = str(mat.id) if isinstance(mat, str): - mat = self.index_mat[mat] + mat = self.mat_to_ind[mat] if isinstance(nuc, str): - nuc = self.index_nuc[nuc] + nuc = self.nuc_to_ind[nuc] - return self.data[mat, nuc] + return self.data[stage, mat, nuc] def __setitem__(self, pos, val): """Sets an item from results. @@ -115,35 +110,39 @@ class StepResult: Parameters ---------- pos : tuple - A two-length tuple containing a mat index and a nuc - index. Both can be integers or slices, or can be + A three-length tuple containing a stage index, mat index and a nuc + index. All can be integers or slices. The second two can be strings corresponding to their respective dictionary. val : float The value to set data to. """ - mat, nuc = pos + stage, mat, nuc = pos if isinstance(mat, str): - mat = self.index_mat[mat] + mat = self.mat_to_ind[mat] if isinstance(nuc, str): - nuc = self.index_nuc[nuc] + nuc = self.nuc_to_ind[nuc] - self.data[mat, nuc] = val + self.data[stage, mat, nuc] = val @property def n_mat(self): - return len(self.index_mat) + return len(self.mat_to_ind) @property def n_nuc(self): - return len(self.index_nuc) + return len(self.nuc_to_ind) @property def n_hdf5_mats(self): return len(self.mat_to_hdf5_ind) - def allocate(self, volume, nuc_list, burn_list, full_burn_list, name_list=None): + @property + def n_stages(self): + return self.data.shape[0] + + def allocate(self, volume, nuc_list, burn_list, full_burn_list, stages): """Allocate memory for depletion step data Parameters @@ -156,18 +155,17 @@ class StepResult: A list of all mat IDs to be burned. Used for sorting the simulation. full_burn_list : list of str List of all burnable material IDs - name_list : list of str, optional - Material names corresponding to materials in full_burn_list + stages : int + Number of stages in simulation. """ self.volume = copy.deepcopy(volume) - self.index_nuc = {nuc: i for i, nuc in enumerate(nuc_list)} - self.index_mat = {mat: i for i, mat in enumerate(burn_list)} + self.nuc_to_ind = {nuc: i for i, nuc in enumerate(nuc_list)} + self.mat_to_ind = {mat: i for i, mat in enumerate(burn_list)} self.mat_to_hdf5_ind = {mat: i for i, mat in enumerate(full_burn_list)} - self.mat_to_name = dict(zip(full_burn_list, name_list)) if name_list is not None else {} # Create storage array - self.data = np.zeros((self.n_mat, self.n_nuc)) + self.data = np.zeros((stages, self.n_mat, self.n_nuc)) def distribute(self, local_materials, ranges): """Create a new object containing data for distributed materials @@ -188,64 +186,19 @@ class StepResult: """ new = StepResult() new.volume = {lm: self.volume[lm] for lm in local_materials} - new.index_mat = {mat: idx for (idx, mat) in enumerate(local_materials)} + new.mat_to_ind = {mat: idx for (idx, mat) in enumerate(local_materials)} # Direct transfer - direct_attrs = ("time", "k", "source_rate", "index_nuc", - "mat_to_hdf5_ind", "mat_to_name", "proc_time") + direct_attrs = ("time", "k", "source_rate", "nuc_to_ind", + "mat_to_hdf5_ind", "proc_time") for attr in direct_attrs: setattr(new, attr, getattr(self, attr)) # Get applicable slice of data - new.data = self.data[ranges] - new.rates = self.rates[ranges] + new.data = self.data[:, ranges] + new.rates = [r[ranges] for r in self.rates] return new - def get_material(self, mat_id: str | int) -> openmc.Material: - """Return material object for given depleted composition - - .. versionadded:: 0.13.2 - - Parameters - ---------- - mat_id : str or int - Material ID as a string or integer - - Returns - ------- - openmc.Material - Equivalent material - - Raises - ------ - KeyError - If specified material ID is not found in the StepResult - - """ - # Coerce to str since internal dictionaries use str keys - mat_id = str(mat_id) - - with warnings.catch_warnings(): - warnings.simplefilter('ignore', openmc.IDWarning) - material = openmc.Material(material_id=int(mat_id)) - try: - vol = self.volume[mat_id] - except KeyError as e: - raise KeyError( - f'mat_id {mat_id} not found in StepResult. Available mat_id ' - f'values are {list(self.volume.keys())}' - ) from e - if mat_id in self.mat_to_name: - material.name = self.mat_to_name[mat_id] - for nuc, _ in sorted(self.index_nuc.items(), key=lambda x: x[1]): - atoms = self[mat_id, nuc] - if atoms <= 0.0: - continue - atom_per_bcm = atoms / vol * 1e-24 - material.add_nuclide(nuc, atom_per_bcm) - material.volume = vol - return material - - def export_to_hdf5(self, filename, step, write_rates: bool = False): + def export_to_hdf5(self, filename, step): """Export results to an HDF5 file Parameters @@ -254,8 +207,6 @@ class StepResult: The filename to write to step : int What step is this? - write_rates : bool, optional - Whether to include reaction rate datasets in the results file. """ # Write new file if first time step, else add to existing file @@ -266,8 +217,7 @@ class StepResult: kwargs['driver'] = 'mpio' kwargs['comm'] = comm with h5py.File(filename, **kwargs) as handle: - self._to_hdf5(handle, step, parallel=True, - write_rates=write_rates) + self._to_hdf5(handle, step, parallel=True) else: # Gather results at root process all_results = comm.gather(self) @@ -276,49 +226,40 @@ class StepResult: if comm.rank == 0: with h5py.File(filename, **kwargs) as handle: for res in all_results: - res._to_hdf5(handle, step, parallel=False, - write_rates=write_rates) + res._to_hdf5(handle, step, parallel=False) - def _write_hdf5_metadata(self, handle, write_rates): + def _write_hdf5_metadata(self, handle): """Writes result metadata in HDF5 file Parameters ---------- handle : h5py.File or h5py.Group An hdf5 file or group type to store this in. - write_rates : bool - Whether reaction rate datasets are being written. """ # Create and save the 5 dictionaries: # quantities - # self.index_mat -> self.volume (TODO: support for changing volumes) - # self.index_nuc + # self.mat_to_ind -> self.volume (TODO: support for changing volumes) + # self.nuc_to_ind # reactions - # self.rates.index_nuc (can be different from above, above is superset) - # self.rates.index_rx + # self.rates[0].nuc_to_ind (can be different from above, above is superset) + # self.rates[0].react_to_ind # these are shared by every step of the simulation, and should be deduplicated. # Store concentration mat and nuclide dictionaries (along with volumes) handle.attrs['version'] = np.array(VERSION_RESULTS) - handle.attrs['filetype'] = np.bytes_('depletion results') + handle.attrs['filetype'] = np.string_('depletion results') mat_list = sorted(self.mat_to_hdf5_ind, key=int) - nuc_list = sorted(self.index_nuc) - - include_rates = ( - write_rates - and self.rates is not None - and bool(self.rates.index_nuc) - and bool(self.rates.index_rx) - ) - rxn_list = sorted(self.rates.index_rx) if include_rates else [] + nuc_list = sorted(self.nuc_to_ind) + rxn_list = sorted(self.rates[0].index_rx) n_mats = self.n_hdf5_mats n_nuc_number = len(nuc_list) - n_nuc_rxn = len(self.rates.index_nuc) if include_rates else 0 + n_nuc_rxn = len(self.rates[0].index_nuc) n_rxn = len(rxn_list) + n_stages = self.n_stages mat_group = handle.create_group("materials") @@ -326,56 +267,46 @@ class StepResult: mat_single_group = mat_group.create_group(mat) mat_single_group.attrs["index"] = self.mat_to_hdf5_ind[mat] mat_single_group.attrs["volume"] = self.volume[mat] - if mat in self.mat_to_name: - mat_single_group.attrs["name"] = self.mat_to_name[mat] nuc_group = handle.create_group("nuclides") for nuc in nuc_list: nuc_single_group = nuc_group.create_group(nuc) - nuc_single_group.attrs["atom number index"] = self.index_nuc[nuc] - if include_rates and nuc in self.rates.index_nuc: - nuc_single_group.attrs["reaction rate index"] = ( - self.rates.index_nuc[nuc]) + nuc_single_group.attrs["atom number index"] = self.nuc_to_ind[nuc] + if nuc in self.rates[0].index_nuc: + nuc_single_group.attrs["reaction rate index"] = self.rates[0].index_nuc[nuc] - if include_rates: - rxn_group = handle.create_group("reactions") + rxn_group = handle.create_group("reactions") - for rxn in rxn_list: - rxn_single_group = rxn_group.create_group(rxn) - rxn_single_group.attrs["index"] = ( - self.rates.index_rx[rxn]) + for rxn in rxn_list: + rxn_single_group = rxn_group.create_group(rxn) + rxn_single_group.attrs["index"] = self.rates[0].index_rx[rxn] # Construct array storage - handle.create_dataset("number", (1, n_mats, n_nuc_number), - maxshape=(None, n_mats, n_nuc_number), - chunks=True, + handle.create_dataset("number", (1, n_stages, n_mats, n_nuc_number), + maxshape=(None, n_stages, n_mats, n_nuc_number), + chunks=(1, 1, n_mats, n_nuc_number), dtype='float64') - if include_rates and n_nuc_rxn > 0 and n_rxn > 0: - handle.create_dataset( - "reaction rates", (1, n_mats, n_nuc_rxn, n_rxn), - maxshape=(None, n_mats, n_nuc_rxn, n_rxn), - chunks=True, dtype='float64') + handle.create_dataset("reaction rates", (1, n_stages, n_mats, n_nuc_rxn, n_rxn), + maxshape=(None, n_stages, n_mats, n_nuc_rxn, n_rxn), + chunks=(1, 1, n_mats, n_nuc_rxn, n_rxn), + dtype='float64') - handle.create_dataset("eigenvalues", (1, 2), - maxshape=(None, 2), dtype='float64') + handle.create_dataset("eigenvalues", (1, n_stages, 2), + maxshape=(None, n_stages, 2), dtype='float64') handle.create_dataset("time", (1, 2), maxshape=(None, 2), dtype='float64') - handle.create_dataset("source_rate", (1,), maxshape=(None,), + handle.create_dataset("source_rate", (1, n_stages), maxshape=(None, n_stages), dtype='float64') handle.create_dataset( "depletion time", (1,), maxshape=(None,), dtype="float64") - handle.create_dataset( - "keff_search_root", (1,), maxshape=(None,), - dtype="float64") - - def _to_hdf5(self, handle, index, parallel=False, write_rates: bool = False): + def _to_hdf5(self, handle, index, parallel=False): """Converts results object into an hdf5 object. Parameters @@ -386,28 +317,23 @@ class StepResult: What step is this? parallel : bool Being called with parallel HDF5? - write_rates : bool, optional - Whether reaction rate datasets are being written. """ if "/number" not in handle: if parallel: comm.barrier() - self._write_hdf5_metadata(handle, write_rates) + self._write_hdf5_metadata(handle) if parallel: comm.barrier() # Grab handles number_dset = handle["/number"] - has_reactions = ("reaction rates" in handle) - if has_reactions: - rxn_dset = handle["/reaction rates"] + rxn_dset = handle["/reaction rates"] eigenvalues_dset = handle["/eigenvalues"] time_dset = handle["/time"] source_rate_dset = handle["/source_rate"] proc_time_dset = handle["/depletion time"] - keff_search_root_dset = handle["/keff_search_root"] # Get number of results stored number_shape = list(number_dset.shape) @@ -420,10 +346,9 @@ class StepResult: number_shape[0] = new_shape number_dset.resize(number_shape) - if has_reactions: - rxn_shape = list(rxn_dset.shape) - rxn_shape[0] = new_shape - rxn_dset.resize(rxn_shape) + rxn_shape = list(rxn_dset.shape) + rxn_shape[0] = new_shape + rxn_dset.resize(rxn_shape) eigenvalues_shape = list(eigenvalues_dset.shape) eigenvalues_shape[0] = new_shape @@ -441,30 +366,28 @@ class StepResult: proc_shape[0] = new_shape proc_time_dset.resize(proc_shape) - keff_search_root_shape = list(keff_search_root_dset.shape) - keff_search_root_shape[0] = new_shape - keff_search_root_dset.resize(keff_search_root_shape) - # If nothing to write, just return - if len(self.index_mat) == 0: + if len(self.mat_to_ind) == 0: return # Add data - inds = [self.mat_to_hdf5_ind[mat] for mat in self.index_mat] + # Note, for the last step, self.n_stages = 1, even if n_stages != 1. + n_stages = self.n_stages + inds = [self.mat_to_hdf5_ind[mat] for mat in self.mat_to_ind] low = min(inds) high = max(inds) - number_dset[index, low:high+1] = self.data - if has_reactions: - rxn_dset[index, low:high+1] = self.rates + for i in range(n_stages): + number_dset[index, i, low:high+1] = self.data[i] + rxn_dset[index, i, low:high+1] = self.rates[i] + if comm.rank == 0: + eigenvalues_dset[index, i] = self.k[i] if comm.rank == 0: - eigenvalues_dset[index] = self.k time_dset[index] = self.time source_rate_dset[index] = self.source_rate if self.proc_time is not None: proc_time_dset[index] = ( self.proc_time / (comm.size * self.n_hdf5_mats) ) - keff_search_root_dset[index] = self.keff_search_root @classmethod def from_hdf5(cls, handle, step): @@ -489,101 +412,65 @@ class StepResult: # Older versions used "power" instead of "source_rate" source_rate_dset = handle["/power"] - # Check if this is an old format file (with stages dimension) or new format - # Old format: number has shape (n_steps, n_stages, n_mats, n_nucs) - # New format: number has shape (n_steps, n_mats, n_nucs) - has_stages = len(number_dset.shape) == 4 - - if has_stages: - # Old format - extract data from first stage (index 0) - results.data = number_dset[step, 0, :, :] - results.k = eigenvalues_dset[step, 0, :] - # source_rate had shape (n_steps, n_stages) in old format - results.source_rate = source_rate_dset[step, 0] - else: - # New format - no stages dimension - results.data = number_dset[step, :, :] - results.k = eigenvalues_dset[step, :] - results.source_rate = source_rate_dset[step] - + results.data = number_dset[step, :, :, :] + results.k = eigenvalues_dset[step, :] results.time = time_dset[step, :] + results.source_rate = source_rate_dset[step, 0] if "depletion time" in handle: proc_time_dset = handle["/depletion time"] if step < proc_time_dset.shape[0]: results.proc_time = proc_time_dset[step] - if "keff_search_root" in handle: - keff_search_root_dset = handle["/keff_search_root"] - results.keff_search_root = keff_search_root_dset[step] - if results.proc_time is None: results.proc_time = np.array([np.nan]) # Reconstruct dictionaries - results.volume = {} - results.index_mat = {} - results.index_nuc = {} - results.mat_to_name = {} - rxn_nuc_to_ind = {} - rxn_to_ind = {} + results.volume = OrderedDict() + results.mat_to_ind = OrderedDict() + results.nuc_to_ind = OrderedDict() + rxn_nuc_to_ind = OrderedDict() + rxn_to_ind = OrderedDict() for mat, mat_handle in handle["/materials"].items(): vol = mat_handle.attrs["volume"] ind = mat_handle.attrs["index"] results.volume[mat] = vol - results.index_mat[mat] = ind - if "name" in mat_handle.attrs: - results.mat_to_name[mat] = mat_handle.attrs["name"] + results.mat_to_ind[mat] = ind for nuc, nuc_handle in handle["/nuclides"].items(): ind_atom = nuc_handle.attrs["atom number index"] - results.index_nuc[nuc] = ind_atom + results.nuc_to_ind[nuc] = ind_atom if "reaction rate index" in nuc_handle.attrs: rxn_nuc_to_ind[nuc] = nuc_handle.attrs["reaction rate index"] - if "reactions" in handle: - for rxn, rxn_handle in handle["/reactions"].items(): - rxn_to_ind[rxn] = rxn_handle.attrs["index"] + for rxn, rxn_handle in handle["/reactions"].items(): + rxn_to_ind[rxn] = rxn_handle.attrs["index"] - # Reconstruct reaction rates - rate = ReactionRates(results.index_mat, rxn_nuc_to_ind, rxn_to_ind, True) - if "reaction rates" in handle: - if has_stages: - # Old format: (n_steps, n_stages, n_mats, n_nucs, n_rxns) - rate[:] = handle["/reaction rates"][step, 0, :, :, :] - else: - # New format: (n_steps, n_mats, n_nucs, n_rxns) - rate[:] = handle["/reaction rates"][step, :, :, :] - results.rates = rate + results.rates = [] + # Reconstruct reactions + for i in range(results.n_stages): + rate = ReactionRates(results.mat_to_ind, rxn_nuc_to_ind, rxn_to_ind, True) + + rate[:] = handle["/reaction rates"][step, i, :, :, :] + results.rates.append(rate) return results @staticmethod - def save( - op, - x, - op_results, - t, - source_rate, - step_ind, - proc_time=None, - write_rates: bool = False, - keff_search_root=None, - path: PathLike = "depletion_results.h5" - ): + def save(op, x, op_results, t, source_rate, step_ind, proc_time=None): """Creates and writes depletion results to disk Parameters ---------- op : openmc.deplete.abc.TransportOperator The operator used to generate these results. - x : numpy.array - End-of-step concentrations for each material - op_results : openmc.deplete.OperatorResult - Result of applying transport operator at end of step + x : list of list of numpy.array + The prior x vectors. Indexed [i][cell] using the above equation. + op_results : list of openmc.deplete.OperatorResult + Results of applying transport operator t : list of float Time indices. source_rate : float @@ -594,42 +481,38 @@ class StepResult: Total process time spent depleting materials. This may be process-dependent and will be reduced across MPI processes. - write_rates : bool, optional - Whether reaction rates should be written to the results file. - keff_search_root : float - The root returned by the keff search control. - path : PathLike - Path to file to write. Defaults to 'depletion_results.h5'. - .. versionadded:: 0.14.0 """ # Get indexing terms - vol_dict, nuc_list, burn_list, full_burn_list, name_list = op.get_results_info() + vol_dict, nuc_list, burn_list, full_burn_list = op.get_results_info() + + stages = len(x) # Create results results = StepResult() - results.allocate(vol_dict, nuc_list, burn_list, full_burn_list, name_list) + results.allocate(vol_dict, nuc_list, burn_list, full_burn_list, stages) n_mat = len(burn_list) - for mat_i in range(n_mat): - results[mat_i, :] = x[mat_i] + for i in range(stages): + for mat_i in range(n_mat): + results[i, mat_i, :] = x[i][mat_i] - if isinstance(op_results.k, type(None)): - results.k = (None, None) - else: - results.k = (op_results.k.nominal_value, op_results.k.std_dev) - results.rates = op_results.rates + ks = [] + for r in op_results: + if isinstance(r.k, type(None)): + ks += [(None, None)] + else: + ks += [(r.k.nominal_value, r.k.std_dev)] + results.k = ks + results.rates = [r.rates for r in op_results] results.time = t results.source_rate = source_rate results.proc_time = proc_time if results.proc_time is not None: results.proc_time = comm.reduce(proc_time, op=MPI.SUM) - results.keff_search_root = keff_search_root - if not Path(path).is_file(): - Path(path).parent.mkdir(parents=True, exist_ok=True) - results.export_to_hdf5(path, step_ind, write_rates) + results.export_to_hdf5("depletion_results.h5", step_ind) def transfer_volumes(self, model): """Transfers volumes from depletion results to geometry diff --git a/openmc/deplete/transfer_rates.py b/openmc/deplete/transfer_rates.py deleted file mode 100644 index ea9fc9185..000000000 --- a/openmc/deplete/transfer_rates.py +++ /dev/null @@ -1,473 +0,0 @@ -from collections import defaultdict -from numbers import Real -import re -from typing import Sequence - -import numpy as np - -from openmc.checkvalue import check_type, check_value -from openmc import Material -from openmc.data import ELEMENT_SYMBOL, isotopes, AVOGADRO, atomic_mass -from .results import _SECONDS_PER_MINUTE, _SECONDS_PER_HOUR, \ - _SECONDS_PER_DAY, _SECONDS_PER_JULIAN_YEAR - - - -class ExternalRates: - """External rates class for defining addition terms of depletion equation. - - .. versionadded:: 0.15.3 - - Parameters - ---------- - operator : openmc.TransportOperator - Depletion operator - materials : openmc.Materials - OpenMC materials. - number_of_timesteps : int - Total number of depletion timesteps - - Attributes - ---------- - burnable_mats : list of str - All burnable material IDs. - local_mats : list of str - All burnable material IDs being managed by a single process - number_of_timesteps : int - Total number of depletion timesteps - external_rates : dict of str to dict - Container of timesteps, external rates, components (elements and/or - nuclides) and optionally destination material - external_timesteps : list of int - Container of all timesteps indeces with an external rate defined. - """ - - def __init__(self, operator, materials, number_of_timesteps): - - self.materials = materials - self.burnable_mats = operator.burnable_mats - self.local_mats = operator.local_mats - self.number_of_timesteps = number_of_timesteps - - #initialize transfer rates container dict - self.external_rates = {mat: defaultdict(list) for mat in self.burnable_mats} - self.external_timesteps = [] - self.redox = {} - - def _get_material_id(self, val): - """Helper method for getting material id from Material obj or name. - - Parameters - ---------- - val : openmc.Material or str or int representing material name/id - - Returns - ------- - material_id : str - - """ - if isinstance(val, Material): - check_value('Depeletable Material', str(val.id), self.burnable_mats) - val = val.id - - elif isinstance(val, str): - if val.isnumeric(): - check_value('Material ID', str(val), self.burnable_mats) - else: - check_value('Material name', val, - [mat.name for mat in self.materials if mat.depletable]) - val = [mat.id for mat in self.materials if mat.name == val][0] - - elif isinstance(val, int): - check_value('Material ID', str(val), self.burnable_mats) - - return str(val) - - def get_external_rate( - self, - material: str | int | Material, - component: str, - timestep: int, - destination_material: str | int | Material | None = None - ): - """Return transfer rate for given material and element. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - component : str - Element or nuclide to get transfer rate value - timestep : int - Current timestep index - destination_material : openmc.Material or str or int, Optional - Destination material to where nuclides get fed - - Returns - ------- - external_rate : list of floats - External rate values - - """ - material_id = self._get_material_id(material) - check_type('component', component, str) - if destination_material is not None: - dest_mat_id = self._get_material_id(destination_material) - return [i[1] for i in self.external_rates[material_id][component] - if timestep in i[0] and dest_mat_id == i[2]] - else: - return [i[1] for i in self.external_rates[material_id][component] - if timestep in i[0]] - - def get_components(self, material, timestep, destination_material=None): - """Extract removing elements and/or nuclides for a given material at a - given timestep - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - timestep : int - Current timestep index - destination_material : openmc.Material or str or int, Optional - Destination material to where nuclides get fed - - Returns - ------- - components : list - List of elements or nuclides with external rates set at a given - timestep - - """ - material_id = self._get_material_id(material) - if destination_material is not None: - dest_mat_id = self._get_material_id(destination_material) - else: - dest_mat_id = None - - all_components = [] - if material_id in self.external_rates: - mat_components = self.external_rates[material_id] - - for component in mat_components: - if dest_mat_id: - # check for both timestep and destination material ids - if np.isin(timestep, [val[0] for val in mat_components[component]]) and \ - np.isin(dest_mat_id, [val[2] for val in mat_components[component]]): - all_components.append(component) - else: - # check only for timesteps - if np.isin(timestep, [val[0] for val in mat_components[component]]): - all_components.append(component) - return all_components - - -class TransferRates(ExternalRates): - """Class for defining continuous removals and feeds. - - Molten Salt Reactors (MSRs) benefit from continuous reprocessing, - which removes fission products and feeds fresh fuel into the system. MSRs - inspired the development of this class. - - An instance of this class can be passed directly to an instance of one of - the :class:`openmc.deplete.Integrator` classes. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - operator : openmc.TransportOperator - Depletion operator - materials : openmc.Materials - OpenMC materials. - number_of_timesteps : int - Total number of depletion timesteps - - Attributes - ---------- - burnable_mats : list of str - All burnable material IDs. - local_mats : list of str - All burnable material IDs being managed by a single process - external_rates : dict of str to dict - Container of timesteps, transfer rates, components (elements and/or - nuclides) and destination material - external_timesteps : list of int - Container of all timesteps indeces with an external rate defined. - index_transfer : Set of pair of str - Pair of strings needed to build final matrix (destination_material, mat) - """ - - def __init__(self, operator, materials, number_of_timesteps): - super().__init__(operator, materials, number_of_timesteps) - self.index_transfer = defaultdict(list) - self.chain_nuclides = [nuc.name for nuc in operator.chain.nuclides] - - def set_transfer_rate(self, material, components, transfer_rate, - transfer_rate_units='1/s', timesteps=None, - destination_material=None): - """Set element and/or nuclide transfer rates in a depletable material. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - components : list of str - List of strings of elements and/or nuclides that share transfer rate. - Cannot add transfer rates for nuclides to a material where a - transfer rate for its element is specified and vice versa. - transfer_rate : float - Rate at which elements and/or nuclides are transferred. A positive or - negative value corresponds to a removal or feed rate, respectively. - transfer_rate_units : {'1/s', '1/min', '1/h', '1/d', '1/a'} - Units for values specified in the transfer_rate argument. 's' for - seconds, 'min' for minutes, 'h' for hours, 'a' for Julian years. - timesteps : list of int, Optional - List of timestep indeces where to set transfer rates. - Default to None means the transfer rate is set for all timesteps. - destination_material : openmc.Material or str or int, Optional - Destination material to where nuclides get fed. - - """ - material_id = self._get_material_id(material) - check_type('transfer_rate', transfer_rate, Real) - check_type('components', components, list, expected_iter_type=str) - - if destination_material is not None: - destination_material_id = self._get_material_id(destination_material) - if len(self.burnable_mats) > 1: - check_value('destination_material', str(destination_material_id), - self.burnable_mats) - else: - raise ValueError('Transfer to material ' - f'{destination_material_id} is set, but there ' - 'is only one depletable material') - else: - destination_material_id = None - - if transfer_rate_units in ('1/s', '1/sec'): - unit_conv = 1 - elif transfer_rate_units in ('1/min', '1/minute'): - unit_conv = _SECONDS_PER_MINUTE - elif transfer_rate_units in ('1/h', '1/hr', '1/hour'): - unit_conv = _SECONDS_PER_HOUR - elif transfer_rate_units in ('1/d', '1/day'): - unit_conv = _SECONDS_PER_DAY - elif transfer_rate_units in ('1/a', '1/year'): - unit_conv = _SECONDS_PER_JULIAN_YEAR - else: - raise ValueError(f'Invalid transfer rate unit "{transfer_rate_units}"') - - if timesteps is not None: - for timestep in timesteps: - check_value('timestep', timestep, range(self.number_of_timesteps)) - timesteps = np.array(timesteps) - else: - timesteps = np.arange(self.number_of_timesteps) - - for component in components: - current_components = self.external_rates[material_id].keys() - split_component = re.split(r'\d+', component) - element = split_component[0] - if element not in ELEMENT_SYMBOL.values(): - raise ValueError(f'{component} is not a valid nuclide or ' - 'element.') - else: - if len(split_component) == 1: - element_nucs = [c for c in current_components - if re.match(component + r'\d', c)] - if len(element_nucs) > 0: - nuc_str = ", ".join(element_nucs) - raise ValueError('Cannot add transfer rate for element ' - f'{component} to material {material_id} ' - f'with transfer rate(s) for nuclide(s) ' - f'{nuc_str}.') - - else: - if element in current_components: - raise ValueError('Cannot add transfer rate for nuclide ' - f'{component} to material {material_id} ' - f'where element {element} already has ' - 'a transfer rate.') - - self.external_rates[material_id][component].append( - (timesteps, transfer_rate/unit_conv, destination_material_id)) - - if destination_material_id is not None: - for timestep in timesteps: - self.index_transfer[timestep].append( - (destination_material_id, material_id)) - - self.external_timesteps = np.unique(np.concatenate( - [self.external_timesteps, timesteps])) - - def set_redox(self, material, buffer, oxidation_states, timesteps=None): - """Add redox control to depletable material. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - buffer : dict - Dictionary of buffer nuclides used to maintain redox balance. - Keys are nuclide names (strings) and values are their respective - fractions (float) that collectively sum to 1. - oxidation_states : dict - User-defined oxidation states for elements. - Keys are element symbols (e.g., 'H', 'He'), and values are their - corresponding oxidation states as integers (e.g., +1, 0). - timesteps : list of int, optional - List of timestep indices where to set external source rates. - Defaults to None, which means the external source rate is set for - all timesteps. - - """ - material_id = self._get_material_id(material) - if timesteps is not None: - for timestep in timesteps: - check_value('timestep', timestep, range(self.number_of_timesteps)) - timesteps = np.array(timesteps) - else: - timesteps = np.arange(self.number_of_timesteps) - #Check nuclides in buffer exist - for nuc in buffer: - if nuc not in self.chain_nuclides: - raise ValueError(f'{nuc} is not a valid nuclide.') - # Checks element in oxidation states exist - for elm in oxidation_states: - if elm not in ELEMENT_SYMBOL.values(): - raise ValueError(f'{elm} is not a valid element.') - - self.redox[material_id] = (buffer, oxidation_states) - self.external_timesteps = np.unique(np.concatenate( - [self.external_timesteps, timesteps])) - -class ExternalSourceRates(ExternalRates): - """Class for defining external source rates. - - An instance of this class can be passed directly to an instance of one of - the :class:`openmc.deplete.Integrator` classes. - - .. versionadded:: 0.15.3 - - Parameters - ---------- - operator : openmc.TransportOperator - Depletion operator - materials : openmc.Materials - OpenMC materials. - number_of_timesteps : int - Total number of depletion timesteps - - Attributes - ---------- - burnable_mats : list of str - All burnable material IDs. - local_mats : list of str - All burnable material IDs being managed by a single process - external_timesteps : list of int - Container of all timesteps indeces with an external rate defined. - external_rates : dict of str to dict - Container of timesteps external source rates, and components - (elements and/or nuclides) - """ - - def reformat_nuclide_vectors(self, vectors): - """Remove last element of nuclide vector that was added for handling - external source rates by the depletion solver. - - Parameters - ---------- - vectors : list of array - List of nuclides vector to reformat - - """ - for mat_index, i in enumerate(self.local_mats): - if self.external_rates[i]: - vectors[mat_index] = vectors[mat_index][:-1] - - def set_external_source_rate( - self, - material: str | int | Material, - composition: dict[str, float], - rate: float, - rate_units: str = 'g/s', - timesteps: Sequence[int] | None = None - ): - """Set element and/or nuclide composition vector external source rates - to a depletable material. - - Parameters - ---------- - material : openmc.Material or str or int - Depletable material - composition : dict of str to float - External source rate composition vector, where key can be an element - or a nuclide and value the corresponding weight percent. - rate : float - External source rate in units of mass per time. A positive or - negative value corresponds to a feed or removal rate, respectively. - rate_units : {'g/s', 'g/min', 'g/h', 'g/d', 'g/a'} - Units for values specified in the `rate` argument. 's' for seconds, - 'min' for minutes, 'h' for hours, 'a' for Julian years. - timesteps : list of int, optional - List of timestep indices where to set external source rates. Default - to None, which means the external source rate is set for all - timesteps. - - """ - - material_id = self._get_material_id(material) - check_type('rate', rate, Real) - check_type('composition', composition, dict, str) - - if rate_units in ('g/s', 'g/sec'): - unit_conv = 1 - elif rate_units in ('g/min', 'g/minute'): - unit_conv = _SECONDS_PER_MINUTE - elif rate_units in ('g/h', 'g/hr', 'g/hour'): - unit_conv = _SECONDS_PER_HOUR - elif rate_units in ('g/d', 'g/day'): - unit_conv = _SECONDS_PER_DAY - elif rate_units in ('g/a', 'g/year'): - unit_conv = _SECONDS_PER_JULIAN_YEAR - else: - raise ValueError(f'Invalid external source rate unit "{rate_units}"') - - if timesteps is not None: - for timestep in timesteps: - check_value('timestep', timestep, range(self.number_of_timesteps)) - timesteps = np.asarray(timesteps) - else: - timesteps = np.arange(self.number_of_timesteps) - - components = composition.keys() - percents = composition.values() - norm_percents = [float(i) / sum(percents) for i in percents] - - atoms_per_nuc = {} - for component, percent in zip(components, norm_percents): - split_component = re.split(r'\d+', component) - element = split_component[0] - if element not in ELEMENT_SYMBOL.values(): - raise ValueError(f'{component} is not a valid nuclide or element.') - - if len(split_component) == 1: - if not isotopes(component): - raise ValueError(f'Cannot add element {component} ' - 'as it is not naturally abundant. ' - 'Specify a nuclide vector instead.') - for nuc, frac in isotopes(component): - atoms_per_nuc[nuc] = (rate / atomic_mass(nuc) * AVOGADRO * - frac * percent / unit_conv) - - else: - atoms_per_nuc[component] = (rate / atomic_mass(component) * - AVOGADRO * percent / unit_conv) - - for nuc, val in atoms_per_nuc.items(): - self.external_rates[material_id][nuc].append((timesteps, val, None)) - - self.external_timesteps = np.unique(np.concatenate( - [self.external_timesteps, timesteps] - )) diff --git a/openmc/element.py b/openmc/element.py index 5deede971..1473bd63e 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -1,11 +1,10 @@ +from collections import OrderedDict +import os import re -import warnings - -import lxml.etree as ET +from xml.etree import ElementTree as ET import openmc.checkvalue as cv -import openmc -from openmc.data import NATURAL_ABUNDANCE, atomic_mass, zam, \ +from openmc.data import NATURAL_ABUNDANCE, atomic_mass, \ isotopes as natural_isotopes @@ -41,10 +40,10 @@ class Element(str): cross_sections=None): """Expand natural element into its naturally-occurring isotopes. - An optional cross_sections argument or the ``cross_sections`` - configuration value is used to specify a cross_sections.xml file. If the - cross_sections.xml file is found, the element is expanded only into the - isotopes/nuclides present in cross_sections.xml. If no + An optional cross_sections argument or the :envvar:`OPENMC_CROSS_SECTIONS` + environment variable is used to specify a cross_sections.xml file. + If the cross_sections.xml file is found, the element is expanded only + into the isotopes/nuclides present in cross_sections.xml. If no cross_sections.xml file is found, the element is expanded based on its naturally occurring isotopes. @@ -55,13 +54,12 @@ class Element(str): percent_type : {'ao', 'wo'} 'ao' for atom percent and 'wo' for weight percent enrichment : float, optional - Enrichment of an enrichment_target nuclide in percent (ao or wo). If - enrichment_target is not supplied then it is enrichment for U235 in - weight percent. For example, input 4.95 for 4.95 weight percent + Enrichment of an enrichment_target nuclide in percent (ao or wo). + If enrichment_target is not supplied then it is enrichment for U235 + in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). enrichment_target: str, optional - Single nuclide name to enrich from a natural composition (e.g., - 'O16') + Single nuclide name to enrich from a natural composition (e.g., 'O16') .. versionadded:: 0.12 enrichment_type: {'ao', 'wo'}, optional @@ -84,8 +82,8 @@ class Element(str): ValueError No data is available for any of natural isotopes of the element ValueError - If only some natural isotopes are available in the cross-section - data library and the element is not O, W, or Ta + If only some natural isotopes are available in the cross-section data + library and the element is not O, W, or Ta ValueError If a non-naturally-occurring isotope is requested ValueError @@ -103,8 +101,8 @@ class Element(str): `ORNL/CSD/TM-244 `_ is used to calculate the weight fractions of U234, U235, U236, and U238. Namely, the weight fraction of U234 and U236 are taken to be 0.89% and 0.46%, - respectively, of the U235 weight fraction. The remainder of the isotopic - weight is assigned to U238. + respectively, of the U235 weight fraction. The remainder of the + isotopic weight is assigned to U238. When the `enrichment` argument is specified with `enrichment_target`, a general enrichment procedure is used for elements composed of exactly @@ -124,17 +122,13 @@ class Element(str): # Get the nuclides present in nature natural_nuclides = {name for name, abundance in natural_isotopes(self)} - # Issue warning if no existing nuclides - if len(natural_nuclides) == 0: - warnings.warn(f"No naturally occurring isotopes found for {self}.") - # Create dict to store the expanded nuclides and abundances - abundances = {} + abundances = OrderedDict() - # If cross_sections is None, get the cross sections from the global - # configuration + # If cross_sections is None, get the cross sections from the + # OPENMC_CROSS_SECTIONS environment variable if cross_sections is None: - cross_sections = openmc.config.get('cross_sections') + cross_sections = os.environ.get('OPENMC_CROSS_SECTIONS') # If a cross_sections library is present, check natural nuclides # against the nuclides in the library @@ -144,15 +138,16 @@ class Element(str): root = tree.getroot() for child in root.findall('library'): nuclide = child.attrib['materials'] - if re.match(r'{}\d+'.format(self), nuclide): + if re.match(r'{}\d+'.format(self), nuclide) and \ + '_m' not in nuclide: library_nuclides.add(nuclide) # Get a set of the mutual and absent nuclides. Convert to lists # and sort to avoid different ordering between Python 2 and 3. mutual_nuclides = natural_nuclides.intersection(library_nuclides) absent_nuclides = natural_nuclides.difference(mutual_nuclides) - mutual_nuclides = sorted(mutual_nuclides, key=zam) - absent_nuclides = sorted(absent_nuclides, key=zam) + mutual_nuclides = sorted(list(mutual_nuclides)) + absent_nuclides = sorted(list(absent_nuclides)) # If all naturally occurring isotopes are present in the library, # add them based on their abundance @@ -184,8 +179,8 @@ class Element(str): for nuclide in absent_nuclides: if nuclide in ['O17', 'O18'] and 'O16' in mutual_nuclides: abundances['O16'] += NATURAL_ABUNDANCE[nuclide] - elif nuclide == 'Ta180_m1' and 'Ta181' in mutual_nuclides: - abundances['Ta181'] += NATURAL_ABUNDANCE[nuclide] + elif nuclide == 'Ta180' and 'Ta181' in mutual_nuclides: + abundances['Ta181'] += NATURAL_ABUNDANCE[nuclide] elif nuclide == 'W180' and 'W182' in mutual_nuclides: abundances['W182'] += NATURAL_ABUNDANCE[nuclide] else: @@ -199,7 +194,7 @@ class Element(str): # If a cross_section library is not present, expand the element into # its natural nuclides else: - for nuclide in sorted(natural_nuclides, key=zam): + for nuclide in natural_nuclides: abundances[nuclide] = NATURAL_ABUNDANCE[nuclide] # Modify mole fractions if enrichment provided diff --git a/openmc/examples.py b/openmc/examples.py index 6895bd94b..3b73d043f 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -3,25 +3,24 @@ from numbers import Integral import numpy as np import openmc +import openmc.model -PINCELL_PITCH = 1.26 # cm -def pwr_pin_cell() -> openmc.Model: +def pwr_pin_cell(): """Create a PWR pin-cell model. This model is a single fuel pin with 2.4 w/o enriched UO2 corresponding to a beginning-of-cycle condition and borated water. The specifications are from - the `BEAVRS `_ benchmark. Note that - the number of particles/batches is initially set very low for testing - purposes. + the `BEAVRS `_ benchmark. Note that the + number of particles/batches is initially set very low for testing purposes. Returns ------- - model : openmc.Model + model : openmc.model.Model A PWR pin-cell model """ - model = openmc.Model() + model = openmc.model.Model() # Define materials. fuel = openmc.Material(name='UO2 (2.4%)') @@ -51,7 +50,7 @@ def pwr_pin_cell() -> openmc.Model: model.materials = (fuel, clad, hot_water) # Instantiate ZCylinder surfaces - pitch = PINCELL_PITCH + pitch = 1.26 fuel_or = openmc.ZCylinder(x0=0, y0=0, r=0.39218, name='Fuel OR') clad_or = openmc.ZCylinder(x0=0, y0=0, r=0.45720, name='Clad OR') left = openmc.XPlane(x0=-pitch/2, name='left', boundary_type='reflective') @@ -77,13 +76,10 @@ def pwr_pin_cell() -> openmc.Model: model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box([-pitch/2, -pitch/2, -1], - [pitch/2, pitch/2, 1]), - constraints={'fissionable': True} - ) + model.settings.source = openmc.Source(space=openmc.stats.Box( + [-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1], only_fissionable=True)) - plot = openmc.SlicePlot.from_geometry(model.geometry) + plot = openmc.Plot.from_geometry(model.geometry) plot.pixels = (300, 300) plot.color_by = 'material' model.plots.append(plot) @@ -91,7 +87,7 @@ def pwr_pin_cell() -> openmc.Model: return model -def pwr_core() -> openmc.Model: +def pwr_core(): """Create a PWR full-core model. This model is the OECD/NEA Monte Carlo Performance benchmark which is a @@ -101,11 +97,11 @@ def pwr_core() -> openmc.Model: Returns ------- - model : openmc.Model + model : openmc.model.Model Full-core PWR model """ - model = openmc.Model() + model = openmc.model.Model() # Define materials. fuel = openmc.Material(1, name='UOX fuel') @@ -150,7 +146,7 @@ def pwr_core() -> openmc.Model: rpv_steel.add_nuclide('Ni60', 0.0026776, 'wo') rpv_steel.add_nuclide('Mn55', 0.01, 'wo') rpv_steel.add_nuclide('Cr52', 0.002092475, 'wo') - rpv_steel.add_element('C', 0.0025, 'wo') + rpv_steel.add_nuclide('C0', 0.0025, 'wo') rpv_steel.add_nuclide('Cu63', 0.0013696, 'wo') lower_rad_ref = openmc.Material(6, name='Lower radial reflector') @@ -168,8 +164,7 @@ def pwr_core() -> openmc.Model: lower_rad_ref.add_nuclide('Cr52', 0.145407678031, 'wo') lower_rad_ref.add_s_alpha_beta('c_H_in_H2O') - upper_rad_ref = openmc.Material( - 7, name='Upper radial reflector / Top plate region') + upper_rad_ref = openmc.Material(7, name='Upper radial reflector / Top plate region') upper_rad_ref.set_density('g/cm3', 4.28) upper_rad_ref.add_nuclide('H1', 0.0086117, 'wo') upper_rad_ref.add_nuclide('O16', 0.0683369, 'wo') @@ -316,17 +311,15 @@ def pwr_core() -> openmc.Model: 11, 11, 11, 11, 11, 13, 13, 14, 14, 14]) # Define fuel lattices. - l100 = openmc.RectLattice( - name='Fuel assembly (lower half)', lattice_id=100) + l100 = openmc.RectLattice(name='Fuel assembly (lower half)', lattice_id=100) l100.lower_left = (-10.71, -10.71) - l100.pitch = (PINCELL_PITCH, PINCELL_PITCH) + l100.pitch = (1.26, 1.26) l100.universes = np.tile(fuel_cold, (17, 17)) l100.universes[tube_x, tube_y] = tube_cold - l101 = openmc.RectLattice( - name='Fuel assembly (upper half)', lattice_id=101) + l101 = openmc.RectLattice(name='Fuel assembly (upper half)', lattice_id=101) l101.lower_left = (-10.71, -10.71) - l101.pitch = (PINCELL_PITCH, PINCELL_PITCH) + l101.pitch = (1.26, 1.26) l101.universes = np.tile(fuel_hot, (17, 17)) l101.universes[tube_x, tube_y] = tube_hot @@ -350,7 +343,7 @@ def pwr_core() -> openmc.Model: # Define core lattices l200 = openmc.RectLattice(name='Core lattice (lower half)', lattice_id=200) l200.lower_left = (-224.91, -224.91) - l200.pitch = (17 * PINCELL_PITCH, 17 * PINCELL_PITCH) + l200.pitch = (21.42, 21.42) l200.universes = [ [fa_cw]*21, [fa_cw]*21, @@ -376,7 +369,7 @@ def pwr_core() -> openmc.Model: l201 = openmc.RectLattice(name='Core lattice (lower half)', lattice_id=201) l201.lower_left = (-224.91, -224.91) - l201.pitch = (17 * PINCELL_PITCH, 17 * PINCELL_PITCH) + l201.pitch = (21.42, 21.42) l201.universes = [ [fa_hw]*21, [fa_hw]*21, @@ -410,14 +403,10 @@ def pwr_core() -> openmc.Model: c6 = openmc.Cell(cell_id=6, fill=top_fa, region=-s5 & +s36 & -s37) c7 = openmc.Cell(cell_id=7, fill=top_nozzle, region=-s5 & +s37 & -s38) c8 = openmc.Cell(cell_id=8, fill=upper_rad_ref, region=-s7 & +s38 & -s39) - c9 = openmc.Cell(cell_id=9, fill=bot_nozzle, - region=+s6 & -s7 & +s32 & -s38) - c10 = openmc.Cell(cell_id=10, fill=rpv_steel, - region=+s7 & -s8 & +s31 & -s39) - c11 = openmc.Cell(cell_id=11, fill=lower_rad_ref, - region=+s5 & -s6 & +s32 & -s34) - c12 = openmc.Cell(cell_id=12, fill=upper_rad_ref, - region=+s5 & -s6 & +s36 & -s38) + c9 = openmc.Cell(cell_id=9, fill=bot_nozzle, region=+s6 & -s7 & +s32 & -s38) + c10 = openmc.Cell(cell_id=10, fill=rpv_steel, region=+s7 & -s8 & +s31 & -s39) + c11 = openmc.Cell(cell_id=11, fill=lower_rad_ref, region=+s5 & -s6 & +s32 & -s34) + c12 = openmc.Cell(cell_id=12, fill=upper_rad_ref, region=+s5 & -s6 & +s36 & -s38) root.add_cells((c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)) # Assign root universe to geometry @@ -426,10 +415,10 @@ def pwr_core() -> openmc.Model: model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + model.settings.source = openmc.Source(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) - plot = openmc.SlicePlot() + plot = openmc.Plot() plot.origin = (125, 125, 0) plot.width = (250, 250) plot.pixels = (3000, 3000) @@ -439,22 +428,22 @@ def pwr_core() -> openmc.Model: return model -def pwr_assembly() -> openmc.Model: +def pwr_assembly(): """Create a PWR assembly model. This model is a reflected 17x17 fuel assembly from the the `BEAVRS - `_ benchmark. The fuel is 2.4 w/o + `_ benchmark. The fuel is 2.4 w/o enriched UO2 corresponding to a beginning-of-cycle condition. Note that the number of particles/batches is initially set very low for testing purposes. Returns ------- - model : openmc.Model + model : openmc.model.Model A PWR assembly model """ - model = openmc.Model() + model = openmc.model.Model() # Define materials. fuel = openmc.Material(name='Fuel') @@ -488,7 +477,7 @@ def pwr_assembly() -> openmc.Model: clad_or = openmc.ZCylinder(x0=0, y0=0, r=0.45720, name='Clad OR') # Create boundary planes to surround the geometry - pitch = 17 * PINCELL_PITCH + pitch = 21.42 min_x = openmc.XPlane(x0=-pitch/2, boundary_type='reflective') max_x = openmc.XPlane(x0=+pitch/2, boundary_type='reflective') min_y = openmc.YPlane(y0=-pitch/2, boundary_type='reflective') @@ -498,10 +487,10 @@ def pwr_assembly() -> openmc.Model: fuel_pin_universe = openmc.Universe(name='Fuel Pin') fuel_cell = openmc.Cell(name='fuel', fill=fuel, region=-fuel_or) clad_cell = openmc.Cell(name='clad', fill=clad, region=+fuel_or & -clad_or) - hot_water_cell = openmc.Cell( - name='hot water', fill=hot_water, region=+clad_or) + hot_water_cell = openmc.Cell(name='hot water', fill=hot_water, region=+clad_or) fuel_pin_universe.add_cells([fuel_cell, clad_cell, hot_water_cell]) + # Create a control rod guide tube universe guide_tube_universe = openmc.Universe(name='Guide Tube') gt_inner_cell = openmc.Cell(name='guide tube inner water', fill=hot_water, @@ -514,7 +503,7 @@ def pwr_assembly() -> openmc.Model: # Create fuel assembly Lattice assembly = openmc.RectLattice(name='Fuel Assembly') - assembly.pitch = (PINCELL_PITCH, PINCELL_PITCH) + assembly.pitch = (pitch/17, pitch/17) assembly.lower_left = (-pitch/2, -pitch/2) # Create array indices for guide tube locations in lattice @@ -538,13 +527,10 @@ def pwr_assembly() -> openmc.Model: model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box([-pitch/2, -pitch/2, -1], - [pitch/2, pitch/2, 1]), - constraints={'fissionable': True} - ) + model.settings.source = openmc.Source(space=openmc.stats.Box( + [-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1], only_fissionable=True)) - plot = openmc.SlicePlot() + plot = openmc.Plot() plot.origin = (0.0, 0.0, 0) plot.width = (21.42, 21.42) plot.pixels = (300, 300) @@ -554,7 +540,7 @@ def pwr_assembly() -> openmc.Model: return model -def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5') -> openmc.Model: +def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5'): """Create a 1D slab model. Parameters @@ -571,7 +557,7 @@ def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5') -> openmc.Model Returns ------- - model : openmc.Model + model : openmc.model.Model One-group, 1D slab model """ @@ -643,979 +629,14 @@ def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5') -> openmc.Model INF = 1000. bounds = [0., -INF, -INF, rads[0], INF, INF] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.IndependentSource(space=uniform_dist) + settings_file.source = openmc.source.Source(space=uniform_dist) settings_file.output = {'summary': False} - model = openmc.Model() + model = openmc.model.Model() model.geometry = geometry_file model.materials = materials_file model.settings = settings_file model.xs_data = macros return model - - -def _generate_c5g7_materials(second_temp = False) -> openmc.Materials: - """Generate materials utilizing multi-group cross sections based on the - the C5G7 Benchmark. - - Parameters - ---------- - second_temp : bool, optional - Whether or not the cross sections should contain two temperature datapoints. - The first data point is the C5G7 cross sections, which corresponds to a temperature - of 294 K. The second data point is the C5G7 cross sections multiplied by 1/2, - which corresponds to a temperature of 394 K. This temperature dependence is - fictitious; it is used for testing temperature feedback in the random ray solver. - - Returns - ------- - materials : openmc.Materials - Materials object containing UO2 and water materials. - - Data Sources - ------------ - All cross section data are from: - Lewis et al., "Benchmark specification for determinisitc 2D/3D MOX fuel - assembly transport calculations without spatial homogenization" - """ - # Instantiate the energy group data - # MGXS for the UO2 pins. - group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] - groups = openmc.mgxs.EnergyGroups(group_edges) - - uo2_total = np.array([0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, - 0.5644058]) - uo2_abs = np.array([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02, 3.0020e-02, - 1.1126e-01, 2.8278e-01]) - uo2_scatter_matrix = np.array( - [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) - uo2_scatter_matrix = np.rollaxis(uo2_scatter_matrix, 0, 3) - uo2_fission = np.array([7.21206e-03, 8.19301e-04, 6.45320e-03, 1.85648e-02, 1.78084e-02, - 8.30348e-02, 2.16004e-01]) - uo2_nu_fission = np.array([2.005998e-02, 2.027303e-03, 1.570599e-02, 4.518301e-02, - 4.334208e-02, 2.020901e-01, 5.257105e-01]) - uo2_chi = np.array([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, - 0.0000e+00, 0.0000e+00]) - - # MGXS for the H2O moderator. - h2o_total = np.array([0.15920605, 0.412969593, 0.59030986, 0.58435, 0.718, 1.2544497, - 2.650379]) - h2o_abs = np.array([6.0105e-04, 1.5793e-05, 3.3716e-04, 1.9406e-03, 5.7416e-03, - 1.5001e-02, 3.7239e-02]) - h2o_scatter_matrix = np.array( - [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], - [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], - [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], - [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], - [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]) - h2o_scatter_matrix = np.rollaxis(h2o_scatter_matrix, 0, 3) - - # Instantiate the 7-group (C5G7) cross section data - uo2_xsdata = openmc.XSdata('UO2', groups) - uo2_xsdata.order = 0 - uo2_xsdata.set_total( - [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, - 0.5644058]) - uo2_xsdata.set_absorption([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02, - 3.0020e-02, 1.1126e-01, 2.8278e-01]) - scatter_matrix = np.array( - [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.3244560, 0.0016314, 0.0000000, - 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.4509400, 0.0026792, - 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.4525650, - 0.0055664, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0001253, - 0.2714010, 0.0102550, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, - 0.0012968, 0.2658020, 0.0168090], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) - scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) - uo2_xsdata.set_scatter_matrix(scatter_matrix) - uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03, - 1.85648e-02, 1.78084e-02, 8.30348e-02, - 2.16004e-01]) - nu_fission = np.array([2.005998e-02, 2.027303e-03, 1.570599e-02, - 4.518301e-02, 4.334208e-02, 2.020901e-01, - 5.257105e-01]) - uo2_xsdata.set_nu_fission(nu_fission) - uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, - 0.0000e+00, 0.0000e+00]) - uo2_xsdata.set_total(uo2_total, temperature=294.0) - uo2_xsdata.set_absorption(uo2_abs, temperature=294.0) - uo2_xsdata.set_scatter_matrix(uo2_scatter_matrix, temperature=294.0) - uo2_xsdata.set_fission(uo2_fission, temperature=294.0) - uo2_xsdata.set_nu_fission(uo2_nu_fission, temperature=294.0) - uo2_xsdata.set_chi(uo2_chi, temperature=294.0) - - h2o_xsdata = openmc.XSdata('LWTR', groups) - h2o_xsdata.order = 0 - h2o_xsdata.set_total(h2o_total, temperature=294.0) - h2o_xsdata.set_absorption(h2o_abs, temperature=294.0) - h2o_xsdata.set_scatter_matrix(h2o_scatter_matrix, temperature=294.0) - - # Add the second temperature data point if requested. - if second_temp: - uo2_xsdata.add_temperature(394.0) - uo2_xsdata.set_total(0.5 * uo2_total, temperature=394.0) - uo2_xsdata.set_absorption(0.5 * uo2_abs, temperature=394.0) - uo2_xsdata.set_scatter_matrix(0.5 * uo2_scatter_matrix, temperature=394.0) - uo2_xsdata.set_fission(0.5 * uo2_fission, temperature=394.0) - uo2_xsdata.set_nu_fission(0.5 * uo2_nu_fission, temperature=394.0) - uo2_xsdata.set_chi(uo2_chi, temperature=394.0) - - h2o_xsdata.add_temperature(394.0) - h2o_xsdata.set_total(0.5 * h2o_total, temperature=394.0) - h2o_xsdata.set_absorption(0.5 * h2o_abs, temperature=394.0) - h2o_xsdata.set_scatter_matrix(0.5 * h2o_scatter_matrix, temperature=394.0) - - mg_cross_sections = openmc.MGXSLibrary(groups) - mg_cross_sections.add_xsdatas([uo2_xsdata, h2o_xsdata]) - mg_cross_sections.export_to_hdf5('mgxs.h5') - - ########################################################################### - # Create materials for the problem - - # Instantiate some Materials and register the appropriate macroscopic data - uo2 = openmc.Material(name='UO2 fuel') - uo2.set_density('macro', 1.0) - uo2.add_macroscopic('UO2') - - water = openmc.Material(name='Water') - water.set_density('macro', 1.0) - water.add_macroscopic('LWTR') - - # Instantiate a Materials collection and export to XML - materials = openmc.Materials([uo2, water]) - materials.cross_sections = "mgxs.h5" - return materials - - -def _generate_subdivided_pin_cell(uo2, water) -> openmc.Universe: - """Create a radially and azimuthally subdivided pin cell universe. Helper - function for random_ray_pin_cell() and random_ray_lattice() - - Parameters - ---------- - uo2 : openmc.Material - UO2 material - water : openmc.Material - Water material - - Returns - ------- - pincell : openmc.Universe - Universe containing an unbounded pin cell - - """ - ######################################## - # Define an unbounded pin cell universe - - # Create a surface for the fuel outer radius - fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') - inner_ring_a = openmc.ZCylinder(r=0.33, name='inner ring a') - inner_ring_b = openmc.ZCylinder(r=0.45, name='inner ring b') - outer_ring_a = openmc.ZCylinder(r=0.60, name='outer ring a') - outer_ring_b = openmc.ZCylinder(r=0.69, name='outer ring b') - - # Instantiate Cells - fuel_a = openmc.Cell(fill=uo2, region=-inner_ring_a, name='fuel inner a') - fuel_b = openmc.Cell(fill=uo2, region=+inner_ring_a & - - inner_ring_b, name='fuel inner b') - fuel_c = openmc.Cell(fill=uo2, region=+inner_ring_b & - - fuel_or, name='fuel inner c') - moderator_a = openmc.Cell( - fill=water, region=+fuel_or & -outer_ring_a, name='moderator inner a') - moderator_b = openmc.Cell( - fill=water, region=+outer_ring_a & -outer_ring_b, name='moderator outer b') - moderator_c = openmc.Cell( - fill=water, region=+outer_ring_b, name='moderator outer c') - - # Create pin cell universe - pincell_base = openmc.Universe() - - # Register Cells with Universe - pincell_base.add_cells( - [fuel_a, fuel_b, fuel_c, moderator_a, moderator_b, moderator_c]) - - # Create planes for azimuthal sectors - azimuthal_planes = [] - for i in range(8): - angle = 2 * i * openmc.pi / 8 - normal_vector = (-openmc.sin(angle), openmc.cos(angle), 0) - azimuthal_planes.append(openmc.Plane( - a=normal_vector[0], b=normal_vector[1], c=normal_vector[2], d=0)) - - # Create a cell for each azimuthal sector - azimuthal_cells = [] - for i in range(8): - azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}') - azimuthal_cell.fill = pincell_base - azimuthal_cell.region = + \ - azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] - azimuthal_cells.append(azimuthal_cell) - - # Create a geometry with the azimuthal universes - pincell = openmc.Universe(cells=azimuthal_cells, name='pincell') - - return pincell - - -def random_ray_pin_cell(second_temp = False) -> openmc.Model: - """Create a PWR pin cell example using C5G7 cross section data. - cross section data. - - Parameters - ---------- - second_temp : bool, optional - Whether or not the cross sections should contain two temperature datapoints. - The first data point is the C5G7 cross sections, which corresponds to a temperature - of 294 K. The second data point is the C5G7 cross sections multiplied by 1/2, - which corresponds to a temperature of 3934 K. This temperature dependence is - fictitious; it is used for testing temperature feedback in the random ray solver. - - Returns - ------- - model : openmc.Model - A PWR pin cell model - - """ - model = openmc.Model() - - ########################################################################### - # Create Materials for the problem - materials = _generate_c5g7_materials(second_temp) - uo2 = materials[0] - water = materials[1] - - ########################################################################### - # Define problem geometry - pincell = _generate_subdivided_pin_cell(uo2, water) - - ######################################## - # Define cell containing lattice and other stuff - pitch = PINCELL_PITCH - box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') - - pincell = openmc.Cell(fill=pincell, region=-box, name='pincell') - - # Create a geometry with the top-level cell - geometry = openmc.Geometry([pincell]) - - ########################################################################### - # Define problem settings - - # Instantiate a Settings object, set all runtime parameters, and export to XML - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.batches = 400 - settings.inactive = 200 - settings.particles = 100 - - # Create an initial uniform spatial source distribution over fissionable zones - lower_left = (-pitch / 2, -pitch / 2, -1) - upper_right = (pitch / 2, pitch / 2, 1) - uniform_dist = openmc.stats.Box(lower_left, upper_right) - rr_source = openmc.IndependentSource(space=uniform_dist) - - settings.random_ray['distance_active'] = 100.0 - settings.random_ray['distance_inactive'] = 20.0 - settings.random_ray['ray_source'] = rr_source - settings.random_ray['volume_normalized_flux_tallies'] = True - - ########################################################################### - # Define tallies - # Now use the mesh filter in a tally and indicate what scores are desired - tally = openmc.Tally(name="Pin tally") - tally.scores = ['flux', 'fission', 'nu-fission'] - tally.estimator = 'analog' - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([tally]) - - ########################################################################### - # Exporting to OpenMC model - ########################################################################### - - model.geometry = geometry - model.materials = materials - model.settings = settings - model.tallies = tallies - return model - - -def random_ray_lattice(second_temp = False) -> openmc.Model: - """Create a 2x2 PWR pin cell asymmetrical lattice example. - - This model is a 2x2 reflective lattice of fuel pins with one of the lattice - locations having just moderator instead of a fuel pin. It uses C5G7 - cross section data. - - Parameters - ---------- - second_temp : bool, optional - Whether or not the cross sections should contain two temperature datapoints. - The first data point is the C5G7 cross sections, which corresponds to a temperature - of 294 K. The second data point is the C5G7 cross sections multiplied by 1/2, - which corresponds to a temperature of 3934 K. This temperature dependence is - fictitious; it is used for testing temperature feedback in the random ray solver. - - Returns - ------- - model : openmc.Model - A PWR 2x2 lattice model - - """ - model = openmc.Model() - - ########################################################################### - # Create Materials for the problem - materials = _generate_c5g7_materials(second_temp) - uo2 = materials[0] - water = materials[1] - - ########################################################################### - # Define problem geometry - pincell = _generate_subdivided_pin_cell(uo2, water) - - ######################################## - # Define a moderator lattice universe - - moderator_infinite = openmc.Cell(name='moderator infinite') - moderator_infinite.fill = water - - mu = openmc.Universe() - mu.add_cells([moderator_infinite]) - - pitch = PINCELL_PITCH - lattice = openmc.RectLattice() - lattice.lower_left = [-pitch/2.0, -pitch/2.0] - lattice.pitch = [pitch/10.0, pitch/10.0] - lattice.universes = np.full((10, 10), mu) - - mod_lattice_cell = openmc.Cell(fill=lattice) - - mod_lattice_uni = openmc.Universe() - - mod_lattice_uni.add_cells([mod_lattice_cell]) - - ######################################## - # Define 2x2 outer lattice - lattice2x2 = openmc.RectLattice() - lattice2x2.lower_left = (-pitch, -pitch) - lattice2x2.pitch = (pitch, pitch) - lattice2x2.universes = [ - [pincell, pincell], - [pincell, mod_lattice_uni] - ] - - ######################################## - # Define cell containing lattice and other stuff - box = openmc.model.RectangularPrism(pitch*2, pitch*2, boundary_type='reflective') - - assembly = openmc.Cell(fill=lattice2x2, region=-box, name='assembly') - - # Create a geometry with the top-level cell - geometry = openmc.Geometry([assembly]) - - ########################################################################### - # Define problem settings - - # Instantiate a Settings object, set all runtime parameters, and export to XML - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.batches = 10 - settings.inactive = 5 - settings.particles = 100 - - # Create an initial uniform spatial source distribution over fissionable zones - lower_left = (-pitch, -pitch, -1) - upper_right = (pitch, pitch, 1) - uniform_dist = openmc.stats.Box(lower_left, upper_right) - rr_source = openmc.IndependentSource(space=uniform_dist) - - settings.random_ray['distance_active'] = 100.0 - settings.random_ray['distance_inactive'] = 20.0 - settings.random_ray['ray_source'] = rr_source - settings.random_ray['volume_normalized_flux_tallies'] = True - - ########################################################################### - # Define tallies - - # Create a mesh that will be used for tallying - mesh = openmc.RegularMesh() - mesh.dimension = (2, 2) - mesh.lower_left = (-pitch, -pitch) - mesh.upper_right = (pitch, pitch) - - # Create a mesh filter that can be used in a tally - mesh_filter = openmc.MeshFilter(mesh) - - # Create an energy group filter as well - group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] - energy_filter = openmc.EnergyFilter(group_edges) - - # Now use the mesh filter in a tally and indicate what scores are desired - tally = openmc.Tally(name="Mesh tally") - tally.filters = [mesh_filter, energy_filter] - tally.scores = ['flux', 'fission', 'nu-fission'] - tally.estimator = 'analog' - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([tally]) - - ########################################################################### - # Exporting to OpenMC model - ########################################################################### - - model.geometry = geometry - model.materials = materials - model.settings = settings - model.tallies = tallies - return model - - -def random_ray_three_region_cube() -> openmc.Model: - """Create a three region cube model. - - This is a simple monoenergetic problem of a cube with three concentric cubic - regions. The innermost region is near void (with Sigma_t around 10^-5) and - contains an external isotropic source term, the middle region is void (with - Sigma_t around 10^-4), and the outer region of the cube is an absorber - (with Sigma_t around 1). - - Returns - ------- - model : openmc.Model - A three region cube model - - """ - - model = openmc.Model() - - ########################################################################### - # Helper function creates a 3 region cube with different fills in each region - def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): - cube = [[[0 for _ in range(N)] for _ in range(N)] for _ in range(N)] - for i in range(N): - for j in range(N): - for k in range(N): - if i < n_1 and j >= (N-n_1) and k < n_1: - cube[i][j][k] = fill_1 - elif i < n_2 and j >= (N-n_2) and k < n_2: - cube[i][j][k] = fill_2 - else: - cube[i][j][k] = fill_3 - return cube - - ########################################################################### - # Create multigroup data - - # Instantiate the energy group data - ebins = [1e-5, 20.0e6] - groups = openmc.mgxs.EnergyGroups(group_edges=ebins) - - void_sigma_a = 4.0e-6 - void_sigma_s = 3.0e-4 - void_mat_data = openmc.XSdata('void', groups) - void_mat_data.order = 0 - void_mat_data.set_total([void_sigma_a + void_sigma_s]) - void_mat_data.set_absorption([void_sigma_a]) - void_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[void_sigma_s]]]), 0, 3)) - - absorber_sigma_a = 0.75 - absorber_sigma_s = 0.25 - absorber_mat_data = openmc.XSdata('absorber', groups) - absorber_mat_data.order = 0 - absorber_mat_data.set_total([absorber_sigma_a + absorber_sigma_s]) - absorber_mat_data.set_absorption([absorber_sigma_a]) - absorber_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[absorber_sigma_s]]]), 0, 3)) - - multiplier = 0.1 - source_sigma_a = void_sigma_a * multiplier - source_sigma_s = void_sigma_s * multiplier - source_mat_data = openmc.XSdata('source', groups) - source_mat_data.order = 0 - source_mat_data.set_total([source_sigma_a + source_sigma_s]) - source_mat_data.set_absorption([source_sigma_a]) - source_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[source_sigma_s]]]), 0, 3)) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - mg_cross_sections_file.add_xsdatas( - [source_mat_data, void_mat_data, absorber_mat_data]) - mg_cross_sections_file.export_to_hdf5() - - ########################################################################### - # Create materials for the problem - - # Instantiate some Macroscopic Data - source_data = openmc.Macroscopic('source') - void_data = openmc.Macroscopic('void') - absorber_data = openmc.Macroscopic('absorber') - - # Instantiate some Materials and register the appropriate Macroscopic objects - source_mat = openmc.Material(name='source') - source_mat.set_density('macro', 1.0) - source_mat.add_macroscopic(source_data) - - void_mat = openmc.Material(name='void') - void_mat.set_density('macro', 1.0) - void_mat.add_macroscopic(void_data) - - absorber_mat = openmc.Material(name='absorber') - absorber_mat.set_density('macro', 1.0) - absorber_mat.add_macroscopic(absorber_data) - - # Instantiate a Materials collection and export to XML - materials_file = openmc.Materials([source_mat, void_mat, absorber_mat]) - materials_file.cross_sections = "mgxs.h5" - - ########################################################################### - # Define problem geometry - - source_cell = openmc.Cell(fill=source_mat, name='infinite source region') - void_cell = openmc.Cell(fill=void_mat, name='infinite void region') - absorber_cell = openmc.Cell( - fill=absorber_mat, name='infinite absorber region') - - source_universe = openmc.Universe(name='source universe') - source_universe.add_cells([source_cell]) - - void_universe = openmc.Universe() - void_universe.add_cells([void_cell]) - - absorber_universe = openmc.Universe() - absorber_universe.add_cells([absorber_cell]) - - absorber_width = 30.0 - n_base = 6 - - # This variable can be increased above 1 to refine the FSR mesh resolution further - refinement_level = 2 - - n = n_base * refinement_level - pitch = absorber_width / n - - pattern = fill_cube(n, 1*refinement_level, 5*refinement_level, - source_universe, void_universe, absorber_universe) - - lattice = openmc.RectLattice() - lattice.lower_left = [0.0, 0.0, 0.0] - lattice.pitch = [pitch, pitch, pitch] - lattice.universes = pattern - - lattice_cell = openmc.Cell(fill=lattice) - - lattice_uni = openmc.Universe() - lattice_uni.add_cells([lattice_cell]) - - x_low = openmc.XPlane(x0=0.0, boundary_type='reflective') - x_high = openmc.XPlane(x0=absorber_width, boundary_type='vacuum') - - y_low = openmc.YPlane(y0=0.0, boundary_type='reflective') - y_high = openmc.YPlane(y0=absorber_width, boundary_type='vacuum') - - z_low = openmc.ZPlane(z0=0.0, boundary_type='reflective') - z_high = openmc.ZPlane(z0=absorber_width, boundary_type='vacuum') - - full_domain = openmc.Cell(fill=lattice_uni, region=+x_low & - - x_high & +y_low & -y_high & +z_low & -z_high, name='full domain') - - root = openmc.Universe(name='root universe') - root.add_cell(full_domain) - - # Create a geometry with the two cells and export to XML - geometry = openmc.Geometry(root) - - ########################################################################### - # Define problem settings - - # Instantiate a Settings object, set all runtime parameters, and export to XML - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.inactive = 5 - settings.batches = 10 - settings.particles = 90 - settings.run_mode = 'fixed source' - - # Create an initial uniform spatial source for ray integration - lower_left_ray = [0.0, 0.0, 0.0] - upper_right_ray = [absorber_width, absorber_width, absorber_width] - uniform_dist_ray = openmc.stats.Box( - lower_left_ray, upper_right_ray, only_fissionable=False) - rr_source = openmc.IndependentSource(space=uniform_dist_ray) - - settings.random_ray['distance_active'] = 500.0 - settings.random_ray['distance_inactive'] = 100.0 - settings.random_ray['ray_source'] = rr_source - settings.random_ray['volume_normalized_flux_tallies'] = True - - # Create the neutron source in the bottom right of the moderator - # Good - fast group appears largest (besides most thermal) - strengths = [1.0] - midpoints = [100.0] - energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths) - - source = openmc.IndependentSource(energy=energy_distribution, constraints={ - 'domains': [source_universe]}, strength=3.14) - - settings.source = [source] - - ########################################################################### - # Define tallies - - estimator = 'tracklength' - - absorber_filter = openmc.MaterialFilter(absorber_mat) - absorber_tally = openmc.Tally(name="Absorber Tally") - absorber_tally.filters = [absorber_filter] - absorber_tally.scores = ['flux'] - absorber_tally.estimator = estimator - - void_filter = openmc.MaterialFilter(void_mat) - void_tally = openmc.Tally(name="Void Tally") - void_tally.filters = [void_filter] - void_tally.scores = ['flux'] - void_tally.estimator = estimator - - source_filter = openmc.MaterialFilter(source_mat) - source_tally = openmc.Tally(name="Source Tally") - source_tally.filters = [source_filter] - source_tally.scores = ['flux'] - source_tally.estimator = estimator - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([source_tally, void_tally, absorber_tally]) - - ########################################################################### - # Assmble Model - - model.geometry = geometry - model.materials = materials_file - model.settings = settings - model.tallies = tallies - - return model - -def random_ray_three_region_cube_with_detectors() -> openmc.Model: - """Create a three region cube model with two external tally regions. - - This is an adaptation of the simple monoenergetic problem of a cube with - three concentric cubic regions. The innermost region is near void (with - Sigma_t around 10^-5) and contains an external isotropic source term, the - middle region is a mild scatterer (with Sigma_t around 10^-3), and the - outer region of the cube is a scatterer and absorber (with Sigma_t around - 1). - - Two cubic "detector" regions are found outside this geometry, one along the - y-axis near z=0, and the other in the upper right corner of the system. - The size of each detector is scaled to be equal to that of the source - region. The model returned by this function contains cell tallies on each - detector. - - Returns - ------- - model : openmc.Model - A three region cube model - - """ - - model = openmc.Model() - - ########################################################################### - # Helper function creates a 3 region cube with different fills in each region - def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): - cube = [[[0 for _ in range(N)] for _ in range(N)] for _ in range(N)] - for i in range(N): - for j in range(N): - for k in range(N): - if i < n_1 and j >= (N-n_1) and k < n_1: - cube[i][j][k] = fill_1 - elif i < n_2 and j >= (N-n_2) and k < n_2: - cube[i][j][k] = fill_2 - else: - cube[i][j][k] = fill_3 - return cube - - ########################################################################### - # Create multigroup data - - # Instantiate the energy group data - ebins = [1e-5, 20.0e6] - groups = openmc.mgxs.EnergyGroups(group_edges=ebins) - - cavity_sigma_a = 4.0e-5 - cavity_sigma_s = 3.0e-3 - cavity_mat_data = openmc.XSdata('cavity', groups) - cavity_mat_data.order = 0 - cavity_mat_data.set_total([cavity_sigma_a + cavity_sigma_s]) - cavity_mat_data.set_absorption([cavity_sigma_a]) - cavity_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[cavity_sigma_s]]]), 0, 3)) - - absorber_sigma_a = 0.50 - absorber_sigma_s = 0.50 - absorber_mat_data = openmc.XSdata('absorber', groups) - absorber_mat_data.order = 0 - absorber_mat_data.set_total([absorber_sigma_a + absorber_sigma_s]) - absorber_mat_data.set_absorption([absorber_sigma_a]) - absorber_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[absorber_sigma_s]]]), 0, 3)) - - multiplier = 0.01 - source_sigma_a = cavity_sigma_a * multiplier - source_sigma_s = cavity_sigma_s * multiplier - source_mat_data = openmc.XSdata('source', groups) - source_mat_data.order = 0 - source_mat_data.set_total([source_sigma_a + source_sigma_s]) - source_mat_data.set_absorption([source_sigma_a]) - source_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[source_sigma_s]]]), 0, 3)) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - mg_cross_sections_file.add_xsdatas( - [source_mat_data, cavity_mat_data, absorber_mat_data]) - mg_cross_sections_file.export_to_hdf5() - - ########################################################################### - # Create materials for the problem - - # Instantiate some Macroscopic Data - source_data = openmc.Macroscopic('source') - cavity_data = openmc.Macroscopic('cavity') - absorber_data = openmc.Macroscopic('absorber') - - # Instantiate some Materials and register the appropriate Macroscopic objects - source_mat = openmc.Material(name='source') - source_mat.set_density('macro', 1.0) - source_mat.add_macroscopic(source_data) - - cavity_mat = openmc.Material(name='cavity') - cavity_mat.set_density('macro', 1.0) - cavity_mat.add_macroscopic(cavity_data) - - absorber_mat = openmc.Material(name='absorber') - absorber_mat.set_density('macro', 1.0) - absorber_mat.add_macroscopic(absorber_data) - - # Instantiate a Materials collection - materials_file = openmc.Materials([source_mat, cavity_mat, absorber_mat]) - materials_file.cross_sections = "mgxs.h5" - - ########################################################################### - # Define problem geometry - - source_cell = openmc.Cell(fill=source_mat, name='infinite source region') - cavity_cell = openmc.Cell(fill=cavity_mat, name='cube cavity region') - absorber_cell = openmc.Cell( - fill=absorber_mat, name='absorber region') - - source_universe = openmc.Universe(name='source universe') - source_universe.add_cells([source_cell]) - - cavity_universe = openmc.Universe() - cavity_universe.add_cells([cavity_cell]) - - absorber_universe = openmc.Universe() - absorber_universe.add_cells([absorber_cell]) - - absorber_width = 30.0 - n_base = 6 - - # This variable can be increased above 1 to refine the FSR mesh resolution further - refinement_level = 2 - - n = n_base * refinement_level - pitch = absorber_width / n - - pattern = fill_cube(n, 1*refinement_level, 5*refinement_level, - source_universe, cavity_universe, absorber_universe) - - lattice = openmc.RectLattice() - lattice.lower_left = [0.0, 0.0, 0.0] - lattice.pitch = [pitch, pitch, pitch] - lattice.universes = pattern - - lattice_cell = openmc.Cell(fill=lattice) - - lattice_uni = openmc.Universe() - lattice_uni.add_cells([lattice_cell]) - - x_low = openmc.XPlane(x0=0.0, boundary_type='reflective') - x_high = openmc.XPlane(x0=absorber_width) - - y_low = openmc.YPlane(y0=0.0, boundary_type='reflective') - y_high = openmc.YPlane(y0=absorber_width) - - z_low = openmc.ZPlane(z0=0.0, boundary_type='reflective') - z_high = openmc.ZPlane(z0=absorber_width) - - cube_domain = openmc.Cell(fill=lattice_uni, region=+x_low & - - x_high & +y_low & -y_high & +z_low & -z_high, name='full domain') - - detect_width = absorber_width / n_base - outer_width = absorber_width + detect_width - - x_outer = openmc.XPlane(x0=outer_width, boundary_type='vacuum') - y_outer = openmc.YPlane(y0=outer_width, boundary_type='vacuum') - z_outer = openmc.ZPlane(z0=outer_width, boundary_type='vacuum') - - detector1_right = openmc.XPlane(x0=detect_width) - detector1_top = openmc.ZPlane(z0=detect_width) - - detector1_region = ( - +x_low & -detector1_right & - +y_high & -y_outer & - +z_low & -detector1_top - ) - detector1 = openmc.Cell( - name='detector 1', - fill=absorber_mat, - region=detector1_region - ) - - detector2_region = ( - +x_high & -x_outer & - +y_high & -y_outer & - +z_high & -z_outer - ) - detector2 = openmc.Cell( - name='detector 2', - fill=absorber_mat, - region=detector2_region - ) - - external_x = ( - +x_high & +y_low & +z_low & -x_outer & - ((-y_outer & -z_high) | (-y_high & +z_high & -z_outer)) - ) - external_y = ( - +y_high & -y_outer & - ( - (+detector1_right & -x_high & +z_low & -z_outer) | - (-detector1_right & +x_low & +detector1_top & -z_outer) | - (+x_high & -x_outer & +z_low & -z_high) - ) - ) - external_z = ( - +x_low & +y_low & +z_high & -z_outer & - ((-y_outer & -x_high) | (-y_high & +x_high & -x_outer)) - ) - external_cell = openmc.Cell(fill=cavity_mat, - region=(external_x | external_y | external_z), - name='outside cube') - - root = openmc.Universe( - name='root universe', - cells=[cube_domain, detector1, detector2, external_cell] - ) - - # Create a geometry with the two cells and export to XML - geometry = openmc.Geometry(root) - - ########################################################################### - # Define problem settings - - # Instantiate a Settings object, set all runtime parameters, and export to XML - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.inactive = 5 - settings.batches = 10 - settings.particles = 500 - settings.run_mode = 'fixed source' - - # Create an initial uniform spatial source for ray integration - lower_left_ray = [0.0, 0.0, 0.0] - upper_right_ray = [outer_width, outer_width, outer_width] - uniform_dist_ray = openmc.stats.Box( - lower_left_ray, upper_right_ray, only_fissionable=False) - rr_source = openmc.IndependentSource(space=uniform_dist_ray) - - settings.random_ray['distance_active'] = 800.0 - settings.random_ray['distance_inactive'] = 100.0 - settings.random_ray['ray_source'] = rr_source - settings.random_ray['volume_normalized_flux_tallies'] = True - - # Create a rectilinear source region mesh - sr_mesh = openmc.RegularMesh() - sr_mesh.dimension = (14, 14, 14) - sr_mesh.lower_left = (0.0, 0.0, 0.0) - sr_mesh.upper_right = (outer_width, outer_width, outer_width) - settings.random_ray['source_region_meshes'] = [(sr_mesh, [root])] - - # Create the neutron source in the bottom right of the moderator - # Good - fast group appears largest (besides most thermal) - strengths = [1.0] - midpoints = [100.0] - energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths) - - source = openmc.IndependentSource(energy=energy_distribution, constraints={ - 'domains': [source_universe]}, strength=3.14) - - settings.source = [source] - - ########################################################################### - # Define tallies - - estimator = 'tracklength' - - detector1_filter = openmc.CellFilter(detector1) - detector1_tally = openmc.Tally(name="Detector 1 Tally") - detector1_tally.filters = [detector1_filter] - detector1_tally.scores = ['flux'] - detector1_tally.estimator = estimator - - detector2_filter = openmc.CellFilter(detector2) - detector2_tally = openmc.Tally(name="Detector 2 Tally") - detector2_tally.filters = [detector2_filter] - detector2_tally.scores = ['flux'] - detector2_tally.estimator = estimator - - absorber_filter = openmc.MaterialFilter(absorber_mat) - absorber_tally = openmc.Tally(name="Absorber Tally") - absorber_tally.filters = [absorber_filter] - absorber_tally.scores = ['flux'] - absorber_tally.estimator = estimator - - cavity_filter = openmc.MaterialFilter(cavity_mat) - cavity_tally = openmc.Tally(name="Cavity Tally") - cavity_tally.filters = [cavity_filter] - cavity_tally.scores = ['flux'] - cavity_tally.estimator = estimator - - source_filter = openmc.MaterialFilter(source_mat) - source_tally = openmc.Tally(name="Source Tally") - source_tally.filters = [source_filter] - source_tally.scores = ['flux'] - source_tally.estimator = estimator - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([detector1_tally, - detector2_tally, - absorber_tally, - cavity_tally, - source_tally]) - - ########################################################################### - # Assmble Model - - model.geometry = geometry - model.materials = materials_file - model.settings = settings - model.tallies = tallies - - return model diff --git a/openmc/executor.py b/openmc/executor.py index 75094e738..357fa64d5 100644 --- a/openmc/executor.py +++ b/openmc/executor.py @@ -1,6 +1,5 @@ from collections.abc import Iterable from numbers import Integral -import os import subprocess import openmc @@ -10,7 +9,7 @@ from .plots import _get_plot_image def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, plot=False, restart_file=None, threads=None, tracks=False, event_based=None, - openmc_exec='openmc', mpi_args=None, path_input=None): + openmc_exec='openmc', mpi_args=None): """Converts user-readable flags in to command-line arguments to be run with the OpenMC executable via subprocess. @@ -24,7 +23,7 @@ def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, Number of particles to simulate per generation. plot : bool, optional Run in plotting mode. Defaults to False. - restart_file : str or PathLike + restart_file : str, optional Path to restart file to use threads : int, optional Number of OpenMP threads. If OpenMC is compiled with OpenMP threading @@ -32,9 +31,7 @@ def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, to the number of hardware threads available (or a value set by the :envvar:`OMP_NUM_THREADS` environment variable). tracks : bool, optional - Enables the writing of particles tracks. The number of particle - tracks written to tracks.h5 is limited to 1000 unless - Settings.max_tracks is set. Defaults to False. + Write tracks for all particles. Defaults to False. event_based : None or bool, optional Turns on event-based parallelism if True. If None, the value in the Settings will be used. @@ -42,10 +39,7 @@ def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, Path to OpenMC executable. Defaults to 'openmc'. mpi_args : list of str, optional MPI execute command and any additional MPI arguments to pass, - e.g., ['mpiexec', '-n', '8']. - path_input : str or PathLike - Path to a single XML file or a directory containing XML files for the - OpenMC executable to read. + e.g. ['mpiexec', '-n', '8']. .. versionadded:: 0.13.0 @@ -74,8 +68,8 @@ def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, if event_based: args.append('-e') - if isinstance(restart_file, (str, os.PathLike)): - args += ['-r', str(restart_file)] + if isinstance(restart_file, str): + args += ['-r', restart_file] if tracks: args.append('-t') @@ -86,9 +80,6 @@ def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, if mpi_args is not None: args = mpi_args + args - if path_input is not None: - args += [path_input] - return args @@ -103,7 +94,6 @@ def _run(args, output, cwd): # If OpenMC is finished, break loop line = p.stdout.readline() if not line and p.poll() is not None: - p.stdout.close() break lines.append(line) @@ -126,7 +116,7 @@ def _run(args, output, cwd): raise RuntimeError(error_msg) -def plot_geometry(output=True, openmc_exec='openmc', cwd='.', path_input=None): +def plot_geometry(output=True, openmc_exec='openmc', cwd='.'): """Run OpenMC in plotting mode Parameters @@ -137,11 +127,6 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.', path_input=None): Path to OpenMC executable cwd : str, optional Path to working directory to run in - path_input : str - Path to a single XML file or a directory containing XML files for the - OpenMC executable to read. - - .. versionadded:: 0.13.3 Raises ------ @@ -149,13 +134,10 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.', path_input=None): If the `openmc` executable returns a non-zero status """ - args = [openmc_exec, '-p'] - if path_input is not None: - args += [path_input] - _run(args, output, cwd) + _run([openmc_exec, '-p'], output, cwd) -def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None): +def plot_inline(plots, openmc_exec='openmc', cwd='.'): """Display plots inline in a Jupyter notebook. .. versionchanged:: 0.13.0 @@ -165,17 +147,12 @@ def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None): Parameters ---------- - plots : Iterable of openmc.PlotBase + plots : Iterable of openmc.Plot Plots to display openmc_exec : str Path to OpenMC executable cwd : str, optional Path to working directory to run in - path_input : str - Path to a single XML file or a directory containing XML files for the - OpenMC executable to read. - - .. versionadded:: 0.13.3 Raises ------ @@ -192,7 +169,7 @@ def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None): openmc.Plots(plots).export_to_xml(cwd) # Run OpenMC in geometry plotting mode - plot_geometry(False, openmc_exec, cwd, path_input) + plot_geometry(False, openmc_exec, cwd) if plots is not None: images = [_get_plot_image(p, cwd) for p in plots] @@ -200,8 +177,7 @@ def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None): def calculate_volumes(threads=None, output=True, cwd='.', - openmc_exec='openmc', mpi_args=None, - path_input=None): + openmc_exec='openmc', mpi_args=None): """Run stochastic volume calculations in OpenMC. This function runs OpenMC in stochastic volume calculation mode. To specify @@ -228,14 +204,10 @@ def calculate_volumes(threads=None, output=True, cwd='.', Path to OpenMC executable. Defaults to 'openmc'. mpi_args : list of str, optional MPI execute command and any additional MPI arguments to pass, - e.g., ['mpiexec', '-n', '8']. + e.g. ['mpiexec', '-n', '8']. cwd : str, optional Path to working directory to run in. Defaults to the current working directory. - path_input : str or PathLike - Path to a single XML file or a directory containing XML files for the - OpenMC executable to read. - Raises ------ @@ -249,16 +221,14 @@ def calculate_volumes(threads=None, output=True, cwd='.', """ args = _process_CLI_arguments(volume=True, threads=threads, - openmc_exec=openmc_exec, mpi_args=mpi_args, - path_input=path_input) + openmc_exec=openmc_exec, mpi_args=mpi_args) _run(args, output, cwd) def run(particles=None, threads=None, geometry_debug=False, restart_file=None, tracks=False, output=True, cwd='.', - openmc_exec='openmc', mpi_args=None, event_based=False, - path_input=None): + openmc_exec='openmc', mpi_args=None, event_based=False): """Run an OpenMC simulation. Parameters @@ -267,17 +237,15 @@ def run(particles=None, threads=None, geometry_debug=False, Number of particles to simulate per generation. threads : int, optional Number of OpenMP threads. If OpenMC is compiled with OpenMP threading - enabled, the default is implementation-dependent but is usually equal to - the number of hardware threads available (or a value set by the + enabled, the default is implementation-dependent but is usually equal + to the number of hardware threads available (or a value set by the :envvar:`OMP_NUM_THREADS` environment variable). geometry_debug : bool, optional Turn on geometry debugging during simulation. Defaults to False. - restart_file : str or PathLike + restart_file : str, optional Path to restart file to use tracks : bool, optional - Enables the writing of particles tracks. The number of particle tracks - written to tracks.h5 is limited to 1000 unless Settings.max_tracks is - set. Defaults to False. + Write tracks for all particles. Defaults to False. output : bool Capture OpenMC output from standard out cwd : str, optional @@ -286,19 +254,13 @@ def run(particles=None, threads=None, geometry_debug=False, openmc_exec : str, optional Path to OpenMC executable. Defaults to 'openmc'. mpi_args : list of str, optional - MPI execute command and any additional MPI arguments to pass, e.g., - ['mpiexec', '-n', '8']. + MPI execute command and any additional MPI arguments to pass, + e.g. ['mpiexec', '-n', '8']. event_based : bool, optional Turns on event-based parallelism, instead of default history-based .. versionadded:: 0.12 - path_input : str or PathLike - Path to a single XML file or a directory containing XML files for the - OpenMC executable to read. - - .. versionadded:: 0.13.3 - Raises ------ RuntimeError @@ -309,7 +271,6 @@ def run(particles=None, threads=None, geometry_debug=False, args = _process_CLI_arguments( volume=False, geometry_debug=geometry_debug, particles=particles, restart_file=restart_file, threads=threads, tracks=tracks, - event_based=event_based, openmc_exec=openmc_exec, mpi_args=mpi_args, - path_input=path_input) + event_based=event_based, openmc_exec=openmc_exec, mpi_args=mpi_args) _run(args, output, cwd) diff --git a/openmc/filter.py b/openmc/filter.py index 87aeb70c3..7874a775b 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -1,33 +1,30 @@ -from __future__ import annotations from abc import ABCMeta -from collections.abc import Iterable, Sequence +from collections import OrderedDict +from collections.abc import Iterable import hashlib from itertools import product from numbers import Real, Integral -import warnings +from xml.etree import ElementTree as ET -import lxml.etree as ET import numpy as np import pandas as pd import openmc import openmc.checkvalue as cv from .cell import Cell -from .data.reaction import REACTION_NAME, REACTION_MT from .material import Material from .mixin import IDManagerMixin from .surface import Surface from .universe import UniverseBase -from ._xml import get_elem_list, get_text +from ._xml import get_text _FILTER_TYPES = ( 'universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', - 'energyout', 'mu', 'musurface', 'polar', 'azimuthal', 'distribcell', - 'delayedgroup', 'energyfunction', 'cellfrom', 'materialfrom', 'legendre', - 'spatiallegendre', 'sphericalharmonics', 'zernike', 'zernikeradial', 'particle', - 'particleproduction', 'cellinstance', 'collision', 'time', 'parentnuclide', - 'weight', 'meshborn', 'meshsurface', 'meshmaterial', 'reaction', + 'energyout', 'mu', 'polar', 'azimuthal', 'distribcell', 'delayedgroup', + 'energyfunction', 'cellfrom', 'legendre', 'spatiallegendre', + 'sphericalharmonics', 'zernike', 'zernikeradial', 'particle', 'cellinstance', + 'collision', 'time' ) _CURRENT_NAMES = ( @@ -36,6 +33,7 @@ _CURRENT_NAMES = ( 'z-min out', 'z-min in', 'z-max out', 'z-max in' ) +_PARTICLES = {'neutron', 'photon', 'electron', 'positron'} class FilterMeta(ABCMeta): @@ -104,8 +102,6 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): Unique identifier for the filter num_bins : Integral The number of filter bins - shape : tuple - The shape of the filter """ @@ -127,9 +123,9 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): def __gt__(self, other): if type(self) is not type(other): if self.short_name in _FILTER_TYPES and \ - other.short_name in _FILTER_TYPES: + other.short_name in _FILTER_TYPES: delta = _FILTER_TYPES.index(self.short_name) - \ - _FILTER_TYPES.index(other.short_name) + _FILTER_TYPES.index(other.short_name) return delta > 0 else: return False @@ -209,10 +205,6 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): def num_bins(self): return len(self.bins) - @property - def shape(self): - return (self.num_bins,) - def check_bins(self, bins): """Make sure given bins are valid for this filter. @@ -230,7 +222,7 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing filter data """ @@ -248,7 +240,7 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element **kwargs Keyword arguments (e.g., mesh information) @@ -259,15 +251,15 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): Filter object """ - filter_type = get_text(elem, "type") + filter_type = elem.get('type') # If the filter type matches this class's short_name, then # there is no overridden from_xml_element method if filter_type == cls.short_name.lower(): # Get bins from element -- the default here works for any filters # that just store a list of bins that can be represented as integers - filter_id = int(get_text(elem, "id")) - bins = get_elem_list(elem, "bins", int) or [] + filter_id = int(elem.get('id')) + bins = [int(x) for x in get_text(elem, 'bins').split()] return cls(bins, filter_id=filter_id) # Search through all subclasses and find the one matching the HDF5 @@ -276,6 +268,7 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): if filter_type == subclass.short_name.lower(): return subclass.from_xml_element(elem, **kwargs) + def can_merge(self, other): """Determine if filter can be merged with another. @@ -426,7 +419,6 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): class WithIDFilter(Filter): """Abstract parent for filters of types with IDs (Cell, Material, etc.).""" - def __init__(self, bins, filter_id=None): bins = np.atleast_1d(bins) @@ -451,7 +443,7 @@ class UniverseFilter(WithIDFilter): Parameters ---------- bins : openmc.UniverseBase, int, or iterable thereof - The Universes to tally. Either :class:`openmc.UniverseBase` objects or their + The Universes to tally. Either openmc.UniverseBase objects or their Integral ID numbers can be used. filter_id : int Unique identifier for the filter @@ -475,31 +467,7 @@ class MaterialFilter(WithIDFilter): Parameters ---------- bins : openmc.Material, Integral, or iterable thereof - The material(s) to tally. Either :class:`openmc.Material` objects or their - Integral ID numbers can be used. - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - bins : Iterable of Integral - openmc.Material IDs. - id : int - Unique identifier for the filter - num_bins : Integral - The number of filter bins - - """ - expected_type = Material - - -class MaterialFromFilter(WithIDFilter): - """Bins tally event locations based on the Material they occurred in. - - Parameters - ---------- - bins : openmc.Material, Integral, or iterable thereof - The material(s) to tally. Either :class:`openmc.Material` objects or their + The Materials to tally. Either openmc.Material objects or their Integral ID numbers can be used. filter_id : int Unique identifier for the filter @@ -523,7 +491,7 @@ class CellFilter(WithIDFilter): Parameters ---------- bins : openmc.Cell, int, or iterable thereof - The cells to tally. Either :class:`openmc.Cell` objects or their ID numbers can + The cells to tally. Either openmc.Cell objects or their ID numbers can be used. filter_id : int Unique identifier for the filter @@ -565,7 +533,7 @@ class CellFromFilter(WithIDFilter): expected_type = Cell -class CellBornFilter(WithIDFilter): +class CellbornFilter(WithIDFilter): """Bins tally events based on which cell the particle was born in. Parameters @@ -589,14 +557,6 @@ class CellBornFilter(WithIDFilter): expected_type = Cell -# Temporary alias for CellbornFilter -def CellbornFilter(*args, **kwargs): - warnings.warn('The name of "CellbornFilter" has changed to ' - '"CellBornFilter". "CellbornFilter" will be ' - 'removed in the future.', FutureWarning) - return CellBornFilter(*args, **kwargs) - - class CellInstanceFilter(Filter): """Bins tally events based on which cell instance a particle is in. @@ -612,7 +572,7 @@ class CellInstanceFilter(Filter): bins : iterable of 2-tuples or numpy.ndarray The cell instances to tally, given as 2-tuples. For the first value in the tuple, either openmc.Cell objects or their integral ID numbers can - be used. The second value indicates the cell instance. + be used. filter_id : int Unique identifier for the filter @@ -630,7 +590,6 @@ class CellInstanceFilter(Filter): DistribcellFilter """ - def __init__(self, bins, filter_id=None): self.bins = bins self.id = filter_id @@ -686,7 +645,7 @@ class CellInstanceFilter(Filter): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing filter data """ @@ -700,8 +659,8 @@ class CellInstanceFilter(Filter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - bins = get_elem_list(elem, "bins", int) or [] + filter_id = int(elem.get('id')) + bins = [int(x) for x in get_text(elem, 'bins').split()] cell_instances = list(zip(bins[::2], bins[1::2])) return cls(cell_instances, filter_id=filter_id) @@ -732,18 +691,19 @@ class SurfaceFilter(WithIDFilter): class ParticleFilter(Filter): - """Bins tally events based on the particle type. + """Bins tally events based on the Particle type. Parameters ---------- - bins : str, int, openmc.ParticleType, or sequence - The particle types to tally represented as names, PDG numbers, or types. + bins : str, or iterable of str + The particles to tally represented as strings ('neutron', 'photon', + 'electron', 'positron'). filter_id : int Unique identifier for the filter Attributes ---------- - bins : sequence of str + bins : iterable of str The particles to tally id : int Unique identifier for the filter @@ -751,7 +711,6 @@ class ParticleFilter(Filter): The number of filter bins """ - def __eq__(self, other): if type(self) is not type(other): return False @@ -764,16 +723,11 @@ class ParticleFilter(Filter): @Filter.bins.setter def bins(self, bins): - if isinstance(bins, (str, Integral, openmc.ParticleType)): - bins = [bins] - else: - cv.check_type('bins', bins, Sequence, - (str, Integral, openmc.ParticleType)) bins = np.atleast_1d(bins) - normalized = [] - for entry in bins: - normalized.append(str(openmc.ParticleType(entry))) - self._bins = np.array(normalized, dtype=str) + cv.check_iterable_type('filter bins', bins, str) + for edge in bins: + cv.check_value('filter bin', edge, _PARTICLES) + self._bins = bins @classmethod def from_hdf5(cls, group, **kwargs): @@ -788,40 +742,13 @@ class ParticleFilter(Filter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - bins = get_elem_list(elem, "bins", str) or [] + filter_id = int(elem.get('id')) + bins = get_text(elem, 'bins').split() return cls(bins, filter_id=filter_id) -class ParentNuclideFilter(ParticleFilter): - """Bins tally events based on the parent nuclide - - Parameters - ---------- - bins : str, or iterable of str - Names of nuclides (e.g., 'Ni65') - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - bins : iterable of str - Names of nuclides - id : int - Unique identifier for the filter - num_bins : Integral - The number of filter bins - - """ - @Filter.bins.setter - def bins(self, bins): - bins = np.atleast_1d(bins) - cv.check_iterable_type('filter bins', bins, str) - self._bins = bins - - class MeshFilter(Filter): - r"""Bins tally event locations by mesh elements. + """Bins tally event locations onto a regular, rectangular mesh. Parameters ---------- @@ -837,27 +764,8 @@ class MeshFilter(Filter): id : int Unique identifier for the filter translation : Iterable of float - This array specifies a vector that is used to translate (shift) the mesh - for this filter - rotation : Iterable of float - This array specifies the angles in degrees about the x, y, and z axes - that the mesh should be rotated. The rotation applied is an intrinsic - rotation with specified Tait-Bryan angles. That is to say, if the angles - are :math:`(\phi, \theta, \psi)`, then the rotation matrix applied is - :math:`R_z(\psi) R_y(\theta) R_x(\phi)` or - - .. math:: - - \left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\phi \sin\psi - + \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi - \sin\theta \cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi + - \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi - \sin\theta \sin\psi \\ -\sin\theta & \sin\phi \cos\theta & \cos\phi - \cos\theta \end{array} \right ] - - A rotation matrix can also be specified directly by setting this - attribute to a nested list (or 2D numpy array) that specifies each - element of the matrix. + This array specifies a vector that is used to translate (shift) + the mesh for this filter bins : list of tuple A list of mesh indices for each filter bin, e.g. [(1, 1, 1), (2, 1, 1), ...] @@ -870,7 +778,6 @@ class MeshFilter(Filter): self.mesh = mesh self.id = filter_id self._translation = None - self._rotation = None def __hash__(self): string = type(self).__name__ + '\n' @@ -882,7 +789,6 @@ class MeshFilter(Filter): string += '{: <16}=\t{}\n'.format('\tMesh ID', self.mesh.id) string += '{: <16}=\t{}\n'.format('\tID', self.id) string += '{: <16}=\t{}\n'.format('\tTranslation', self.translation) - string += '{: <16}=\t{}\n'.format('\tRotation', self.rotation) return string @classmethod @@ -900,16 +806,13 @@ class MeshFilter(Filter): mesh_obj = kwargs['meshes'][mesh_id] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) + out = cls(mesh_obj, filter_id=filter_id) translation = group.get('translation') if translation: out.translation = translation[()] - rotation = group.get('rotation') - if rotation: - out.rotation = rotation[()] - return out @property @@ -921,17 +824,13 @@ class MeshFilter(Filter): cv.check_type('filter mesh', mesh, openmc.MeshBase) self._mesh = mesh if isinstance(mesh, openmc.UnstructuredMesh): - if mesh.has_statepoint_data: - self.bins = list(range(len(mesh.volumes))) - else: + if mesh.volumes is None: self.bins = [] + else: + self.bins = list(range(len(mesh.volumes))) else: self.bins = list(mesh.indices) - @property - def shape(self): - return self.mesh.dimension - @property def translation(self): return self._translation @@ -942,15 +841,6 @@ class MeshFilter(Filter): cv.check_length('mesh filter translation', t, 3) self._translation = np.asarray(t) - @property - def rotation(self): - return self._rotation - - @rotation.setter - def rotation(self, rotation): - cv.check_length('mesh filter rotation', rotation, 3) - self._rotation = np.asarray(rotation) - def can_merge(self, other): # Mesh filters cannot have more than one bin return False @@ -972,288 +862,84 @@ class MeshFilter(Filter): Returns ------- pandas.DataFrame - A Pandas DataFrame with columns describing the mesh cell indices - corresponding to each filter bin. Column names depend on the mesh - type (e.g., x/y/z for RegularMesh, r/phi/z for CylindricalMesh, - r/theta/phi for SphericalMesh, or element index for - UnstructuredMesh). The number of rows in the DataFrame is the same - as the total number of bins in the corresponding tally, with the - filter bin appropriately tiled to map to the corresponding tally - bins. + A Pandas DataFrame with three columns describing the x,y,z mesh + cell indices corresponding to each filter bin. The number of rows + in the DataFrame is the same as the total number of bins in the + corresponding tally, with the filter bin appropriately tiled to map + to the corresponding tally bins. See also -------- Tally.get_pandas_dataframe(), CrossFilter.get_pandas_dataframe() """ + # Initialize Pandas DataFrame + df = pd.DataFrame() + # Initialize dictionary to build Pandas Multi-index column filter_dict = {} # Append mesh ID as outermost index of multi-index mesh_key = f'mesh {self.mesh.id}' - # Determine index base (0-based for unstructured, 1-based otherwise) - idx_start = 0 if isinstance(self.mesh, openmc.UnstructuredMesh) else 1 + # Find mesh dimensions - use 3D indices for simplicity + n_dim = len(self.mesh.dimension) + if n_dim == 3: + nx, ny, nz = self.mesh.dimension + elif n_dim == 2: + nx, ny = self.mesh.dimension + nz = 1 + else: + nx = self.mesh.dimension + ny = nz = 1 - # Generate a multi-index sub-column for each axis - for label, dim_size in zip(self.mesh._axis_labels, self.mesh.dimension): - filter_dict[mesh_key, label] = _repeat_and_tile( - np.arange(idx_start, idx_start + dim_size), stride, data_size) - stride *= dim_size + # Generate multi-index sub-column for x-axis + filter_dict[mesh_key, 'x'] = _repeat_and_tile( + np.arange(1, nx + 1), stride, data_size) - return pd.DataFrame(filter_dict) + # Generate multi-index sub-column for y-axis + filter_dict[mesh_key, 'y'] = _repeat_and_tile( + np.arange(1, ny + 1), nx * stride, data_size) + + # Generate multi-index sub-column for z-axis + filter_dict[mesh_key, 'z'] = _repeat_and_tile( + np.arange(1, nz + 1), nx * ny * stride, data_size) + + # Initialize a Pandas DataFrame from the mesh dictionary + df = pd.concat([df, pd.DataFrame(filter_dict)]) + + return df def to_xml_element(self): """Return XML Element representing the Filter. Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing filter data """ - element = ET.Element('filter') - element.set('id', str(self.id)) - element.set('type', self.short_name.lower()) - subelement = ET.SubElement(element, 'bins') - subelement.text = str(self.mesh.id) + element = super().to_xml_element() + element[0].text = str(self.mesh.id) if self.translation is not None: element.set('translation', ' '.join(map(str, self.translation))) - if self.rotation is not None: - element.set('rotation', ' '.join(map(str, self.rotation.ravel()))) return element @classmethod - def from_xml_element(cls, elem: ET.Element, **kwargs) -> MeshFilter: + def from_xml_element(cls, elem, **kwargs): mesh_id = int(get_text(elem, 'bins')) mesh_obj = kwargs['meshes'][mesh_id] - filter_id = int(get_text(elem, "id")) + filter_id = int(elem.get('id')) out = cls(mesh_obj, filter_id=filter_id) - translation = get_elem_list(elem, "translation", float) or [] + translation = elem.get('translation') if translation: - out.translation = translation - - rotation = get_elem_list(elem, 'rotation', float) or [] - if rotation: - if len(rotation) == 3: - out.rotation = rotation - elif len(rotation) == 9: - out.rotation = np.array(rotation).reshape(3, 3) + out.translation = [float(x) for x in translation.split()] return out -class MeshBornFilter(MeshFilter): - """Filter events by the mesh cell a particle originated from. - - Parameters - ---------- - mesh : openmc.MeshBase - The mesh object that events will be tallied onto - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - mesh : openmc.MeshBase - The mesh object that events will be tallied onto - id : int - Unique identifier for the filter - translation : Iterable of float - This array specifies a vector that is used to translate (shift) - the mesh for this filter - bins : list of tuple - A list of mesh indices for each filter bin, e.g. [(1, 1, 1), (2, 1, 1), - ...] - num_bins : Integral - The number of filter bins - - """ - - -class MeshMaterialFilter(MeshFilter): - """Filter events by combinations of mesh elements and materials. - - .. versionadded:: 0.15.3 - - Parameters - ---------- - mesh : openmc.MeshBase - The mesh object that events will be tallied onto - bins : iterable of 2-tuples or numpy.ndarray - Combinations of (mesh element, material) to tally, given as 2-tuples. - The first value in the tuple represents the index of the mesh element, - and the second value indicates the material (either a - :class:`openmc.Material` instance of the ID). - filter_id : int - Unique identifier for the filter - - """ - - def __init__(self, mesh: openmc.MeshBase, bins, filter_id=None): - self.mesh = mesh - self.bins = bins - self.id = filter_id - self._translation = None - - @classmethod - def from_volumes(cls, mesh: openmc.MeshBase, volumes: openmc.MeshMaterialVolumes): - """Construct a MeshMaterialFilter from a MeshMaterialVolumes object. - - Parameters - ---------- - mesh : openmc.MeshBase - The mesh object that events will be tallied onto - volumes : openmc.MeshMaterialVolumes - The mesh material volumes to use for the filter - - Returns - ------- - MeshMaterialFilter - A new MeshMaterialFilter instance - - """ - # Get flat arrays of material IDs and element indices - mat_ids = volumes._materials[volumes._materials > -1] - elems, _ = np.where(volumes._materials > -1) - - # Stack them into a 2D array of (element, material) pairs - bins = np.column_stack((elems, mat_ids)) - return cls(mesh, bins) - - def __hash__(self): - data = (type(self).__name__, self.mesh.id, tuple(self.bins.ravel())) - return hash(data) - - def __repr__(self): - string = type(self).__name__ + '\n' - string += '{: <16}=\t{}\n'.format('\tID', self.id) - string += '{: <16}=\t{}\n'.format('\tMesh ID', self.mesh.id) - string += '{: <16}=\n{}\n'.format('\tBins', self.bins) - string += '{: <16}=\t{}\n'.format('\tTranslation', self.translation) - return string - - @property - def shape(self): - return (self.num_bins,) - - @property - def mesh(self): - return self._mesh - - @mesh.setter - def mesh(self, mesh): - cv.check_type('filter mesh', mesh, openmc.MeshBase) - self._mesh = mesh - - @Filter.bins.setter - def bins(self, bins): - pairs = np.empty((len(bins), 2), dtype=int) - for i, (elem, mat) in enumerate(bins): - cv.check_type('element', elem, Integral) - cv.check_type('material', mat, (Integral, openmc.Material)) - pairs[i, 0] = elem - pairs[i, 1] = mat if isinstance(mat, Integral) else mat.id - self._bins = pairs - - def to_xml_element(self): - """Return XML element representing the filter. - - Returns - ------- - element : lxml.etree._Element - XML element containing filter data - - """ - element = ET.Element('filter') - element.set('id', str(self.id)) - element.set('type', self.short_name.lower()) - element.set('mesh', str(self.mesh.id)) - - if self.translation is not None: - element.set('translation', ' '.join(map(str, self.translation))) - - subelement = ET.SubElement(element, 'bins') - subelement.text = ' '.join(str(i) for i in self.bins.ravel()) - - return element - - @classmethod - def from_xml_element(cls, elem: ET.Element, **kwargs) -> MeshMaterialFilter: - filter_id = int(get_text(elem, "id")) - mesh_id = int(get_text(elem, "mesh")) - mesh_obj = kwargs['meshes'][mesh_id] - bins = get_elem_list(elem, "bins", int) or [] - bins = list(zip(bins[::2], bins[1::2])) - out = cls(mesh_obj, bins, filter_id=filter_id) - - translation = get_elem_list(elem, "translation", float) or [] - if translation: - out.translation = translation - return out - - @classmethod - def from_hdf5(cls, group, **kwargs): - if group['type'][()].decode() != cls.short_name.lower(): - raise ValueError("Expected HDF5 data for filter type '" - + cls.short_name.lower() + "' but got '" - + group['type'][()].decode() + " instead") - - if 'meshes' not in kwargs: - raise ValueError(cls.__name__ + " requires a 'meshes' keyword " - "argument.") - - mesh_id = group['mesh'][()] - mesh_obj = kwargs['meshes'][mesh_id] - bins = group['bins'][()] - filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(mesh_obj, bins, filter_id=filter_id) - - translation = group.get('translation') - if translation: - out.translation = translation[()] - - return out - - def get_pandas_dataframe(self, data_size, stride, **kwargs): - """Builds a Pandas DataFrame for the Filter's bins. - - This method constructs a Pandas DataFrame object for the filter with - columns annotated by filter bin information. This is a helper method for - :meth:`Tally.get_pandas_dataframe`. - - Parameters - ---------- - data_size : int - The total number of bins in the tally corresponding to this filter - stride : int - Stride in memory for the filter - - Returns - ------- - pandas.DataFrame - A Pandas DataFrame with a multi-index column for the cell instance. - The number of rows in the DataFrame is the same as the total number - of bins in the corresponding tally, with the filter bin appropriately - tiled to map to the corresponding tally bins. - - See also - -------- - Tally.get_pandas_dataframe(), CrossFilter.get_pandas_dataframe() - - """ - # Repeat and tile bins as necessary to account for other filters. - bins = np.repeat(self.bins, stride, axis=0) - tile_factor = data_size // len(bins) - bins = np.tile(bins, (tile_factor, 1)) - - columns = pd.MultiIndex.from_product([[self.short_name.lower()], - ['element', 'material']]) - return pd.DataFrame(bins, columns=columns) - - class MeshSurfaceFilter(MeshFilter): - """Filter events by surface crossings on a mesh. + """Filter events by surface crossings on a regular, rectangular mesh. Parameters ---------- @@ -1264,6 +950,8 @@ class MeshSurfaceFilter(MeshFilter): Attributes ---------- + bins : Integral + The mesh ID mesh : openmc.MeshBase The mesh object that events will be tallied onto translation : Iterable of float @@ -1272,15 +960,14 @@ class MeshSurfaceFilter(MeshFilter): id : int Unique identifier for the filter bins : list of tuple + A list of mesh indices / surfaces for each filter bin, e.g. [(1, 1, 'x-min out'), (1, 1, 'x-min in'), ...] + num_bins : Integral The number of filter bins """ - @property - def shape(self): - return (self.num_bins,) @MeshFilter.mesh.setter def mesh(self, mesh): @@ -1399,80 +1086,6 @@ class CollisionFilter(Filter): cv.check_greater_than('filter value', x, 0, equality=True) -class ReactionFilter(Filter): - """Bins tally events based on the reaction type (MT number). - - .. versionadded:: 0.15.4 - - Parameters - ---------- - bins : str, int, or iterable thereof - The reaction types to tally. Can be reaction name strings - (e.g., ``'(n,elastic)'``, ``'(n,gamma)'``) or integer MT numbers - (e.g., 2, 102). Integer MT values are automatically converted to their - canonical string representation. - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - bins : numpy.ndarray of str - Reaction name strings - id : int - Unique identifier for the filter - num_bins : int - The number of filter bins - - """ - - def __init__(self, bins, filter_id=None): - self.bins = bins - self.id = filter_id - - @Filter.bins.setter - def bins(self, bins): - if isinstance(bins, (str, Integral)): - bins = [bins] - elif not isinstance(bins, list): - bins = list(bins) - normalized = [] - for b in bins: - if isinstance(b, Integral): - if int(b) not in REACTION_NAME: - raise ValueError(f"No known reaction for MT={b}") - normalized.append(REACTION_NAME[int(b)]) - elif isinstance(b, str): - if b == 'total': - warnings.warn( - "The reaction name 'total' is ambiguous. Use " - "'(n,total)' for neutron total cross section or " - "'photon-total' for photon total. Interpreting as" - "'(n,total)'.") - if b not in REACTION_MT: - raise ValueError(f"Unknown reaction name '{b}'") - normalized.append(REACTION_NAME[REACTION_MT[b]]) - else: - raise TypeError(f"Expected str or int for reaction filter " - f"bin, got {type(b)}") - self._bins = np.array(normalized, dtype=str) - - @classmethod - def from_hdf5(cls, group, **kwargs): - if group['type'][()].decode() != cls.short_name.lower(): - raise ValueError("Expected HDF5 data for filter type '" - + cls.short_name.lower() + "' but got '" - + group['type'][()].decode() + "' instead") - bins = [b.decode() for b in group['bins'][()]] - filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - return cls(bins, filter_id=filter_id) - - @classmethod - def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - bins = get_elem_list(elem, "bins", str) or [] - return cls(bins, filter_id=filter_id) - - class RealFilter(Filter): """Tally modifier that describes phase-space and other characteristics @@ -1498,7 +1111,6 @@ class RealFilter(Filter): The number of filter bins """ - def __init__(self, values, filter_id=None): self.values = np.asarray(values) self.bins = np.vstack((self.values[:-1], self.values[1:])).T @@ -1529,7 +1141,7 @@ class RealFilter(Filter): cv.check_type('filter value', v1, Real) # Make sure that each tuple has values that are increasing - if v1 <= v0: + if v1 < v0: raise ValueError(f'Values {v0} and {v1} appear to be out of ' 'order') @@ -1592,8 +1204,8 @@ class RealFilter(Filter): def get_bin_index(self, filter_bin): i = np.where(self.bins[:, 1] == filter_bin[1])[0] if len(i) == 0: - msg = ('Unable to get the bin index for Filter since ' - f'"{filter_bin}" is not one of the bins') + msg = (f'Unable to get the bin index for Filter since ' + '"{filter_bin}" is not one of the bins') raise ValueError(msg) else: return i[0] @@ -1653,7 +1265,7 @@ class RealFilter(Filter): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing filter data """ @@ -1663,8 +1275,8 @@ class RealFilter(Filter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - bins = get_elem_list(elem, "bins", float) or [] + filter_id = int(elem.get('id')) + bins = [float(x) for x in get_text(elem, 'bins').split()] return cls(bins, filter_id=filter_id) @@ -1675,7 +1287,7 @@ class EnergyFilter(RealFilter): ---------- values : Iterable of Real A list of values for which each successive pair constitutes a range of - energies in [eV] for a single bin. Entries must be positive and ascending. + energies in [eV] for a single bin filter_id : int Unique identifier for the filter @@ -1695,10 +1307,6 @@ class EnergyFilter(RealFilter): """ units = 'eV' - def __init__(self, values, filter_id=None): - cv.check_length('values', values, 2) - super().__init__(values, filter_id) - def get_bin_index(self, filter_bin): # Use lower energy bound to find index for RealFilters deltas = np.abs(self.bins[:, 1] - filter_bin[1]) / filter_bin[1] @@ -1716,38 +1324,6 @@ class EnergyFilter(RealFilter): cv.check_greater_than('filter value', v0, 0., equality=True) cv.check_greater_than('filter value', v1, 0., equality=True) - def get_tabular(self, values, **kwargs): - """Create a tabulated distribution based on tally results with an energy filter - - This method provides an easy way to create a distribution in energy - (e.g., a source spectrum) based on tally results that were obtained from - using an :class:`~openmc.EnergyFilter`. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - values : iterable of float - Array of numeric values, typically from a tally result - **kwargs - Keyword arguments passed to :class:`openmc.stats.Tabular` - - Returns - ------- - openmc.stats.Tabular - Tabular distribution with histogram interpolation - """ - - probabilities = np.array(values, dtype=float) - probabilities /= probabilities.sum() - - # Determine probability per eV, adding extra 0 at the end since it is a histogram - probability_per_ev = probabilities / np.diff(self.values) - probability_per_ev = np.append(probability_per_ev, 0.0) - - kwargs.setdefault('interpolation', 'histogram') - return openmc.stats.Tabular(self.values, probability_per_ev, **kwargs) - @property def lethargy_bin_width(self): """Calculates the base 10 log width of energy bins which is useful when @@ -1774,8 +1350,6 @@ class EnergyFilter(RealFilter): """ - cv.check_value('group_structure', group_structure, - openmc.mgxs.GROUP_STRUCTURES.keys()) return cls(openmc.mgxs.GROUP_STRUCTURES[group_structure.upper()]) @@ -1805,226 +1379,6 @@ class EnergyoutFilter(EnergyFilter): """ - -class ParticleProductionFilter(Filter): - """Bins tally events based on secondary particle type and energy. - - This filter bins secondary particles (e.g., photons, electrons, or recoils) - produced in a reaction by particle type and, optionally, by energy. This is - useful for constructing production matrices or analyzing secondary particle - spectra. Note that unlike other energy filters, the weight that is applied - is equal to the weight of the secondary particle. Thus, to obtain secondary - particle production, it should be used in conjunction with the "events" - score. - - The incident particle type can be filtered using :class:`ParticleFilter`. - - .. versionadded:: 0.15.4 - - Parameters - ---------- - particles : str, int, openmc.ParticleType, or iterable thereof - Type(s) of secondary particle(s) to tally ('photon', 'neutron', etc.) - energies : Iterable of Real or str, optional - A list of energy boundaries in [eV]; each successive pair defines a bin. - Alternatively, the name of the group structure can be given as a string - (must be a key in :data:`openmc.mgxs.GROUP_STRUCTURES`). If not - provided, the filter tallies total secondary particle production without - energy binning. - filter_id : int, optional - Unique identifier for the filter - - Attributes - ---------- - particles : list of openmc.ParticleType - The secondary particle types this filter applies to - energies : numpy.ndarray or None - Energy boundaries in [eV], or None if no energy binning - bins : list - A list of bins; each element fully describes one bin. When energies are - specified, each element is a tuple ``(particle, energy_low, - energy_high)``. When no energies are specified, each element is a - particle name string. - num_bins : int - Total number of filter bins - num_energy_bins : int - Number of energy bins (1 if no energies specified) - shape : tuple of int - Shape of the filter as (n_particles, n_energy_bins) - """ - - def __init__(self, particles, energies=None, filter_id=None): - self.particles = particles - self.energies = energies - self.id = filter_id - - def __repr__(self): - string = type(self).__name__ + '\n' - string += '{: <16}=\t{}\n'.format('\tParticles', - [str(p) for p in self.particles]) - if self.energies is not None: - string += '{: <16}=\t{}\n'.format('\tEnergies', self.energies) - string += '{: <16}=\t{}\n'.format('\tID', self.id) - return string - - @property - def particles(self): - return self._particles - - @particles.setter - def particles(self, particles): - if isinstance(particles, (str, int, openmc.ParticleType)): - self._particles = [openmc.ParticleType(particles)] - else: - self._particles = [openmc.ParticleType(p) for p in particles] - - @property - def energies(self): - return self._energies - - @energies.setter - def energies(self, energies): - if energies is None: - self._energies = None - elif isinstance(energies, str): - cv.check_value('energies', energies, - openmc.mgxs.GROUP_STRUCTURES.keys()) - self._energies = np.array( - openmc.mgxs.GROUP_STRUCTURES[energies.upper()]) - else: - energies = np.asarray(energies, dtype=float) - cv.check_length('energies', energies, 2) - for i in range(len(energies) - 1): - if energies[i + 1] <= energies[i]: - raise ValueError("Energy bins must be monotonically " - "increasing.") - self._energies = energies - - @property - def bins(self): - if self.energies is None: - return [str(p) for p in self.particles] - else: - result = [] - energy_pairs = np.vstack( - (self.energies[:-1], self.energies[1:])).T - for particle in self.particles: - for e_low, e_high in energy_pairs: - result.append((str(particle), e_low, e_high)) - return result - - @bins.setter - def bins(self, bins): - # bins is set indirectly through particles/energies - pass - - def check_bins(self, bins): - pass - - @property - def num_energy_bins(self): - if self.energies is None: - return 1 - else: - return len(self.energies) - 1 - - @property - def num_bins(self): - return len(self.particles) * self.num_energy_bins - - @property - def shape(self): - return (len(self.particles), self.num_energy_bins) - - def to_xml_element(self): - element = ET.Element('filter') - element.set('id', str(self.id)) - element.set('type', self.short_name.lower()) - - subelement = ET.SubElement(element, 'particles') - subelement.text = ' '.join(str(p) for p in self.particles) - - if self.energies is not None: - subelement = ET.SubElement(element, 'energies') - subelement.text = ' '.join(str(e) for e in self.energies) - - return element - - @classmethod - def from_xml_element(cls, elem, **kwargs): - filter_id = int(elem.get('id')) - particles = get_text(elem, 'particles').split() - - bins_elem = elem.find('energies') - if bins_elem is not None: - energies = [float(x) for x in bins_elem.text.split()] - else: - energies = None - - return cls(particles, energies=energies, filter_id=filter_id) - - @classmethod - def from_hdf5(cls, group, **kwargs): - filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - - # Read particle types - particles = [b.decode() if isinstance(b, bytes) else b - for b in group['particles'][()]] - - # Read energy bins if present - if 'energies' in group: - energies = group['energies'][()] - else: - energies = None - - return cls(particles, energies=energies, filter_id=filter_id) - - def get_pandas_dataframe(self, data_size, stride, **kwargs): - """Builds a Pandas DataFrame for the Filter's bins. - - This method constructs a Pandas DataFrame object for the filter with - columns annotated by filter bin information. This is a helper method for - :meth:`Tally.get_pandas_dataframe`. - - Parameters - ---------- - data_size : int - The total number of bins in the tally corresponding to this filter - stride : int - Stride in memory for the filter - - Returns - ------- - pandas.DataFrame - A Pandas DataFrame with columns for particle type and, if energy - bins are specified, energy bin boundaries. - - See also - -------- - Tally.get_pandas_dataframe(), CrossFilter.get_pandas_dataframe() - - """ - filter_dict = {} - key = self.short_name.lower() - n_ebins = self.num_energy_bins - - # Particle column — outer dimension (changes slowest) - particle_names = [str(p) for p in self.particles] - filter_dict[key, 'particle'] = _repeat_and_tile( - np.array(particle_names), n_ebins * stride, data_size) - - # Energy columns only if energies were specified - if self.energies is not None: - energy_pairs = np.vstack( - (self.energies[:-1], self.energies[1:])).T - filter_dict[key, 'energy low [eV]'] = _repeat_and_tile( - energy_pairs[:, 0], stride, data_size) - filter_dict[key, 'energy high [eV]'] = _repeat_and_tile( - energy_pairs[:, 1], stride, data_size) - - return pd.DataFrame(filter_dict) - - class TimeFilter(RealFilter): """Bins tally events based on the particle's time. @@ -2168,20 +1522,6 @@ class DistribcellFilter(Filter): @property def paths(self): - if self._paths is None: - if not hasattr(self, '_geometry'): - raise ValueError( - "Model must be exported before the 'paths' attribute is" \ - "available for a DistribcellFilter.") - - # Determine paths for cell instances - self._geometry.determine_paths() - - # Get paths for the corresponding cell - cell_id = self.bins[0] - cell = self._geometry.get_all_cells()[cell_id] - self._paths = cell.paths - return self._paths @Filter.bins.setter @@ -2192,7 +1532,7 @@ class DistribcellFilter(Filter): # Make sure there is only 1 bin. if not len(bins) == 1: msg = (f'Unable to add bins "{bins}" to a DistribcellFilter since ' - 'only a single distribcell can be used per tally') + 'only a single distribcell can be used per tally') raise ValueError(msg) # Check the type and extract the id, if necessary. @@ -2202,6 +1542,11 @@ class DistribcellFilter(Filter): self._bins = bins + @paths.setter + def paths(self, paths): + cv.check_iterable_type('paths', paths, str) + self._paths = paths + def can_merge(self, other): # Distribcell filters cannot have more than one bin return False @@ -2281,7 +1626,7 @@ class DistribcellFilter(Filter): level_key = f'level {i_level + 1}' # Create a dictionary for this level for Pandas Multi-index - level_dict = {} + level_dict = OrderedDict() # Use the first distribcell path to determine if level # is a universe/cell or lattice level @@ -2345,12 +1690,12 @@ class DistribcellFilter(Filter): # requests Summary geometric information filter_bins = _repeat_and_tile( np.arange(self.num_bins), stride, data_size) - df = pd.DataFrame({self.short_name.lower(): filter_bins}) + df = pd.DataFrame({self.short_name.lower() : filter_bins}) # Concatenate with DataFrame of distribcell instance IDs if level_df is not None: level_df = level_df.dropna(axis=1, how='all') - level_df = level_df.astype(int) + level_df = level_df.astype(np.int) df = pd.concat([level_df, df], axis=1) return df @@ -2384,7 +1729,6 @@ class MuFilter(RealFilter): The number of filter bins """ - def __init__(self, values, filter_id=None): if isinstance(values, Integral): values = np.linspace(-1., 1., values + 1) @@ -2399,44 +1743,6 @@ class MuFilter(RealFilter): cv.check_less_than('filter value', x, 1., equality=True) -class MuSurfaceFilter(MuFilter): - """Bins tally events based on the angle of surface crossing. - - This filter bins events based on the cosine of the angle between the - direction of the particle and the normal to the surface at the point it - crosses. Only used in conjunction with a SurfaceFilter and current score. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - values : int or Iterable of Real - A grid of surface crossing angles which the events will be divided into. - Values represent the cosine of the angle between the direction of the - particle and the normal to the surface at the point it crosses. If an - iterable is given, the values will be used explicitly as grid points. If - a single int is given, the range [-1, 1] will be divided equally into - that number of bins. - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - values : numpy.ndarray - An array of values for which each successive pair constitutes a range of - surface crossing angle cosines for a single bin. - id : int - Unique identifier for the filter - bins : numpy.ndarray - An array of shape (N, 2) where each row is a pair of cosines of surface - crossing angle for a single filter - num_bins : Integral - The number of filter bins - - """ - # Note: inherits implementation from MuFilter - - class PolarFilter(RealFilter): """Bins tally events based on the incident particle's direction. @@ -2550,7 +1856,6 @@ class DelayedGroupFilter(Filter): The number of filter bins """ - def check_bins(self, bins): # Check the bin values. for g in bins: @@ -2570,9 +1875,6 @@ class EnergyFunctionFilter(Filter): A grid of energy values in [eV] y : iterable of Real A grid of interpolant values in [eV] - interpolation : str - Interpolation scheme: {'histogram', 'linear-linear', 'linear-log', - 'log-linear', 'log-log', 'quadratic', 'cubic'} filter_id : int Unique identifier for the filter @@ -2582,9 +1884,6 @@ class EnergyFunctionFilter(Filter): A grid of energy values in [eV] y : iterable of Real A grid of interpolant values in [eV] - interpolation : str - Interpolation scheme: {'histogram', 'linear-linear', 'linear-log', - 'log-linear', 'log-log', 'quadratic', 'cubic'} id : int Unique identifier for the filter num_bins : Integral @@ -2592,25 +1891,14 @@ class EnergyFunctionFilter(Filter): """ - # keys selected to match those in function.py where possible - # skip 6 b/c ENDF-6 reserves this value for - # "special one-dimensional interpolation law" - INTERPOLATION_SCHEMES = {1: 'histogram', 2: 'linear-linear', - 3: 'linear-log', 4: 'log-linear', - 5: 'log-log', 7: 'quadratic', - 8: 'cubic'} - - def __init__(self, energy, y, interpolation='linear-linear', filter_id=None): + def __init__(self, energy, y, filter_id=None): self.energy = energy self.y = y self.id = filter_id - self.interpolation = interpolation def __eq__(self, other): if type(self) is not type(other): return False - elif not self.interpolation == other.interpolation: - return False elif not all(self.energy == other.energy): return False else: @@ -2619,9 +1907,9 @@ class EnergyFunctionFilter(Filter): def __gt__(self, other): if type(self) is not type(other): if self.short_name in _FILTER_TYPES and \ - other.short_name in _FILTER_TYPES: + other.short_name in _FILTER_TYPES: delta = _FILTER_TYPES.index(self.short_name) - \ - _FILTER_TYPES.index(other.short_name) + _FILTER_TYPES.index(other.short_name) return delta > 0 else: return False @@ -2631,9 +1919,9 @@ class EnergyFunctionFilter(Filter): def __lt__(self, other): if type(self) is not type(other): if self.short_name in _FILTER_TYPES and \ - other.short_name in _FILTER_TYPES: + other.short_name in _FILTER_TYPES: delta = _FILTER_TYPES.index(self.short_name) - \ - _FILTER_TYPES.index(other.short_name) + _FILTER_TYPES.index(other.short_name) return delta < 0 else: return False @@ -2644,16 +1932,12 @@ class EnergyFunctionFilter(Filter): string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tEnergy', self.energy) string += '{: <16}=\t{}\n'.format('\tInterpolant', self.y) - string += '{: <16}=\t{}\n'.format('\tInterpolation', - self.interpolation) return hash(string) def __repr__(self): string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tEnergy', self.energy) string += '{: <16}=\t{}\n'.format('\tInterpolant', self.y) - string += '{: <16}=\t{}\n'.format('\tInterpolation', - self.interpolation) string += '{: <16}=\t{}\n'.format('\tID', self.id) return string @@ -2665,16 +1949,10 @@ class EnergyFunctionFilter(Filter): + group['type'][()].decode() + " instead") energy = group['energy'][()] - y_grp = group['y'] - y = y_grp[()] + y = group['y'][()] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(energy, y, filter_id=filter_id) - if 'interpolation' in y_grp.attrs: - out.interpolation = \ - cls.INTERPOLATION_SCHEMES[y_grp.attrs['interpolation'][()]] - - return out + return cls(energy, y, filter_id=filter_id) @classmethod def from_tabulated1d(cls, tab1d): @@ -2696,16 +1974,27 @@ class EnergyFunctionFilter(Filter): if tab1d.n_regions > 1: raise ValueError('Only Tabulated1Ds with a single interpolation ' 'region are supported') - interpolation_val = tab1d.interpolation[0] - if interpolation_val not in cls.INTERPOLATION_SCHEMES.keys(): - raise ValueError('Only histogram, linear-linear, linear-log, log-linear, and ' - 'log-log Tabulated1Ds are supported') - return cls(tab1d.x, tab1d.y, cls.INTERPOLATION_SCHEMES[interpolation_val]) + if tab1d.interpolation[0] != 2: + raise ValueError('Only linear-linear Tabulated1Ds are supported') + + return cls(tab1d.x, tab1d.y) @property def energy(self): return self._energy + @property + def y(self): + return self._y + + @property + def bins(self): + raise AttributeError('EnergyFunctionFilters have no bins.') + + @property + def num_bins(self): + return 1 + @energy.setter def energy(self, energy): # Format the bins as a 1D numpy array. @@ -2718,10 +2007,6 @@ class EnergyFunctionFilter(Filter): self._energy = energy - @property - def y(self): - return self._y - @y.setter def y(self, y): # Format the bins as a 1D numpy array. @@ -2732,43 +2017,16 @@ class EnergyFunctionFilter(Filter): self._y = y - @property - def interpolation(self): - return self._interpolation - - @interpolation.setter - def interpolation(self, val): - cv.check_type('interpolation', val, str) - cv.check_value('interpolation', val, - self.INTERPOLATION_SCHEMES.values()) - - if val == 'quadratic' and len(self.energy) < 3: - raise ValueError( - 'Quadratic interpolation requires 3 or more values.') - - if val == 'cubic' and len(self.energy) < 4: - raise ValueError('Cubic interpolation requires 3 or more values.') - - self._interpolation = val - - @property - def bins(self): - raise AttributeError('EnergyFunctionFilters have no bins.') - @bins.setter def bins(self, bins): raise RuntimeError('EnergyFunctionFilters have no bins.') - @property - def num_bins(self): - return 1 - def to_xml_element(self): """Return XML Element representing the Filter. Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing filter data """ @@ -2782,21 +2040,14 @@ class EnergyFunctionFilter(Filter): subelement = ET.SubElement(element, 'y') subelement.text = ' '.join(str(y) for y in self.y) - subelement = ET.SubElement(element, 'interpolation') - subelement.text = self.interpolation - return element @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - energy = get_elem_list(elem, "energy", float) or [] - y = get_elem_list(elem, "y", float) or [] - out = cls(energy, y, filter_id=filter_id) - interpolation = get_text(elem, "interpolation") - if interpolation is not None: - out.interpolation = interpolation - return out + filter_id = int(elem.get('id')) + energy = [float(x) for x in get_text(elem, 'energy').split()] + y = [float(x) for x in get_text(elem, 'y').split()] + return cls(energy, y, filter_id=filter_id) def can_merge(self, other): return False @@ -2856,26 +2107,3 @@ class EnergyFunctionFilter(Filter): {self.short_name.lower(): filter_bins})]) return df - - -class WeightFilter(RealFilter): - """Bins tally events based on the incoming particle weight. - - Parameters - ---------- - Values : Iterable of float - A list or iterable of the weight boundaries, as float values. - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - id : int - Unique identifier for the filter - bins : numpy.ndarray - An array of integer values representing the weights by which to filter - num_bins : int - The number of filter bins - values : numpy.ndarray - Array of weight boundaries - """ diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index b79c8fc79..1c07f58b7 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -1,10 +1,8 @@ from numbers import Integral, Real - -import lxml.etree as ET +from xml.etree import ElementTree as ET import openmc.checkvalue as cv -from .filter import Filter -from ._xml import get_text +from . import Filter class ExpansionFilter(Filter): @@ -35,7 +33,7 @@ class ExpansionFilter(Filter): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing Legendre filter data """ @@ -50,38 +48,10 @@ class ExpansionFilter(Filter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - order = int(get_text(elem, "order")) + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) return cls(order, filter_id=filter_id) - def merge(self, other): - """Merge this filter with another. - - This overrides the behavior of the parent Filter class, since its - merging technique is to take the union of the set of bins of each - filter. That technique does not apply to expansion filters, since the - argument should be the maximum filter order rather than the list of all - bins. - - Parameters - ---------- - other : openmc.Filter - Filter to merge with - - Returns - ------- - merged_filter : openmc.Filter - Filter resulting from the merge - - """ - - if not self.can_merge(other): - msg = f'Unable to merge "{type(self)}" with "{type(other)}"' - raise ValueError(msg) - - # Create a new filter with these bins and a new auto-generated ID - return type(self)(max(self.order, other.order)) - class LegendreFilter(ExpansionFilter): r"""Score Legendre expansion moments up to specified order. @@ -248,7 +218,7 @@ class SpatialLegendreFilter(ExpansionFilter): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing Legendre filter data """ @@ -264,11 +234,11 @@ class SpatialLegendreFilter(ExpansionFilter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - order = int(get_text(elem, "order")) - axis = get_text(elem, "axis") - minimum = float(get_text(elem, "min")) - maximum = float(get_text(elem, "max")) + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) + axis = elem.find('axis').text + minimum = float(elem.find('min').text) + maximum = float(elem.find('max').text) return cls(order, axis, minimum, maximum, filter_id=filter_id) @@ -353,7 +323,7 @@ class SphericalHarmonicsFilter(ExpansionFilter): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing spherical harmonics filter data """ @@ -363,10 +333,10 @@ class SphericalHarmonicsFilter(ExpansionFilter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - order = int(get_text(elem, "order")) + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) filter = cls(order, filter_id=filter_id) - filter.cosine = get_text(elem, "cosine") + filter.cosine = elem.get('cosine') return filter @@ -503,7 +473,7 @@ class ZernikeFilter(ExpansionFilter): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing Zernike filter data """ @@ -519,11 +489,11 @@ class ZernikeFilter(ExpansionFilter): @classmethod def from_xml_element(cls, elem, **kwargs): - filter_id = int(get_text(elem, "id")) - order = int(get_text(elem, "order")) - x = float(get_text(elem, "x")) - y = float(get_text(elem, "y")) - r = float(get_text(elem, "r")) + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) + x = float(elem.find('x').text) + y = float(elem.find('y').text) + r = float(elem.find('r').text) return cls(order, x, y, r, filter_id=filter_id) diff --git a/openmc/geometry.py b/openmc/geometry.py index 8496fb23a..58a33c1b1 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -1,16 +1,12 @@ -from __future__ import annotations -import os -from collections import defaultdict -from copy import deepcopy +from collections import OrderedDict, defaultdict from collections.abc import Iterable +from copy import deepcopy from pathlib import Path -import warnings -import lxml.etree as ET +from xml.etree import ElementTree as ET import openmc import openmc._xml as xml -from .plots import add_plot_params -from .checkvalue import check_type, check_less_than, check_greater_than, PathLike +from .checkvalue import check_type class Geometry: @@ -26,27 +22,15 @@ class Geometry: ---------- root_universe : openmc.UniverseBase Root universe which contains all others - bounding_box : openmc.BoundingBox + bounding_box : 2-tuple of numpy.array Lower-left and upper-right coordinates of an axis-aligned bounding box of the universe. - merge_surfaces : bool - Whether to remove redundant surfaces when the geometry is exported. - surface_precision : int - Number of decimal places to round to for comparing the coefficients of - surfaces for considering them topologically equivalent. """ - def __init__( - self, - root: openmc.UniverseBase | Iterable[openmc.Cell] | None = None, - merge_surfaces: bool = False, - surface_precision: int = 10 - ): + def __init__(self, root=None): self._root_universe = None self._offsets = {} - self.merge_surfaces = merge_surfaces - self.surface_precision = surface_precision if root is not None: if isinstance(root, openmc.UniverseBase): self.root_universe = root @@ -57,38 +41,18 @@ class Geometry: self._root_universe = univ @property - def root_universe(self) -> openmc.UniverseBase: + def root_universe(self): return self._root_universe + @property + def bounding_box(self): + return self.root_universe.bounding_box + @root_universe.setter def root_universe(self, root_universe): check_type('root universe', root_universe, openmc.UniverseBase) self._root_universe = root_universe - @property - def bounding_box(self) -> openmc.BoundingBox: - return self.root_universe.bounding_box - - @property - def merge_surfaces(self) -> bool: - return self._merge_surfaces - - @merge_surfaces.setter - def merge_surfaces(self, merge_surfaces): - check_type('merge surfaces', merge_surfaces, bool) - self._merge_surfaces = merge_surfaces - - @property - def surface_precision(self) -> int: - return self._surface_precision - - @surface_precision.setter - def surface_precision(self, surface_precision): - check_type('surface precision', surface_precision, int) - check_less_than('surface_precision', surface_precision, 16) - check_greater_than('surface_precision', surface_precision, 0) - self._surface_precision = surface_precision - def add_volume_information(self, volume_calc): """Add volume information from a stochastic volume calculation. @@ -111,38 +75,6 @@ class Geometry: if universe.id in volume_calc.volumes: universe.add_volume_information(volume_calc) - def to_xml_element(self, remove_surfs=False) -> ET.Element: - """Creates a 'geometry' element to be written to an XML file. - - Parameters - ---------- - remove_surfs : bool - Whether or not to remove redundant surfaces from the geometry when - exporting - - """ - # Find and remove redundant surfaces from the geometry - if remove_surfs: - warnings.warn("remove_surfs kwarg will be deprecated soon, please " - "set the Geometry.merge_surfaces attribute instead.") - self.merge_surfaces = True - - if self.merge_surfaces: - self.remove_redundant_surfaces() - - # Create XML representation - element = ET.Element("geometry") - self.root_universe.create_xml_subelement(element) - - # Sort the elements in the file - element[:] = sorted(element, key=lambda x: ( - x.tag, int(x.get('id')))) - - # Clean the indentation in the file to be user-readable - xml.clean_indentation(element) - - return element - def export_to_xml(self, path='geometry.xml', remove_surfs=False): """Export geometry to an XML file. @@ -157,7 +89,20 @@ class Geometry: .. versionadded:: 0.12 """ - root_element = self.to_xml_element(remove_surfs) + # Find and remove redundant surfaces from the geometry + if remove_surfs: + self.remove_redundant_surfaces() + + # Create XML representation + root_element = ET.Element("geometry") + self.root_universe.create_xml_subelement(root_element, memo=set()) + + # Sort the elements in the file + root_element[:] = sorted(root_element, key=lambda x: ( + x.tag, int(x.get('id')))) + + # Clean the indentation in the file to be user-readable + xml.clean_indentation(root_element) # Check if path is a directory p = Path(path) @@ -165,17 +110,18 @@ class Geometry: p /= 'geometry.xml' # Write the XML Tree to the geometry.xml file + xml.reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod - def from_xml_element(cls, elem, materials=None) -> Geometry: - """Generate geometry from an XML element + def from_xml(cls, path='geometry.xml', materials=None): + """Generate geometry from XML file Parameters ---------- - elem : lxml.etree._Element - XML element + path : str, optional + Path to geometry XML file materials : openmc.Materials or None Materials used to assign to cells. If None, an attempt is made to generate it from the materials.xml file. @@ -186,11 +132,6 @@ class Geometry: Geometry object """ - mats = dict() - if materials is not None: - mats.update({str(m.id): m for m in materials}) - mats['void'] = None - # Helper function for keeping a cache of Universe instances universes = {} def get_universe(univ_id): @@ -199,10 +140,13 @@ class Geometry: universes[univ_id] = univ return universes[univ_id] + tree = ET.parse(path) + root = tree.getroot() + # Get surfaces surfaces = {} periodic = {} - for surface in elem.findall('surface'): + for surface in root.findall('surface'): s = openmc.Surface.from_xml_element(surface) surfaces[s.id] = s @@ -216,24 +160,24 @@ class Geometry: surfaces[s1].periodic_surface = surfaces[s2] # Add any DAGMC universes - for e in elem.findall('dagmc_universe'): - dag_univ = openmc.DAGMCUniverse.from_xml_element(e, mats) + for elem in root.findall('dagmc_universe'): + dag_univ = openmc.DAGMCUniverse.from_xml_element(elem) universes[dag_univ.id] = dag_univ # Dictionary that maps each universe to a list of cells/lattices that - # contain it (needed to determine which universe is the elem) + # contain it (needed to determine which universe is the root) child_of = defaultdict(list) - for e in elem.findall('lattice'): - lat = openmc.RectLattice.from_xml_element(e, get_universe) + for elem in root.findall('lattice'): + lat = openmc.RectLattice.from_xml_element(elem, get_universe) universes[lat.id] = lat if lat.outer is not None: child_of[lat.outer].append(lat) for u in lat.universes.ravel(): child_of[u].append(lat) - for e in elem.findall('hex_lattice'): - lat = openmc.HexLattice.from_xml_element(e, get_universe) + for elem in root.findall('hex_lattice'): + lat = openmc.HexLattice.from_xml_element(elem, get_universe) universes[lat.id] = lat if lat.outer is not None: child_of[lat.outer].append(lat) @@ -247,8 +191,15 @@ class Geometry: for u in ring: child_of[u].append(lat) - for e in elem.findall('cell'): - c = openmc.Cell.from_xml_element(e, surfaces, mats, get_universe) + # Create dictionary to easily look up materials + if materials is None: + filename = Path(path).parent / 'materials.xml' + materials = openmc.Materials.from_xml(str(filename)) + mats = {str(m.id): m for m in materials} + mats['void'] = None + + for elem in root.findall('cell'): + c = openmc.Cell.from_xml_element(elem, surfaces, mats, get_universe) if c.fill_type in ('universe', 'lattice'): child_of[c.fill].append(c) @@ -260,43 +211,7 @@ class Geometry: else: raise ValueError('Error determining root universe.') - @classmethod - def from_xml( - cls, - path: PathLike = 'geometry.xml', - materials: PathLike | 'openmc.Materials' | None = 'materials.xml' - ) -> Geometry: - """Generate geometry from XML file - - Parameters - ---------- - path : PathLike, optional - Path to geometry XML file - materials : openmc.Materials or PathLike - Materials used to assign to cells. If PathLike, an attempt is made - to generate materials from the provided xml file. - - Returns - ------- - openmc.Geometry - Geometry object - - """ - - # Using str and os.PathLike here to avoid error when using just the imported PathLike - # TypeError: Subscripted generics cannot be used with class and instance checks - check_type('materials', materials, (str, os.PathLike, openmc.Materials)) - - if isinstance(materials, (str, os.PathLike)): - materials = openmc.Materials.from_xml(materials) - - parser = ET.XMLParser(huge_tree=True) - tree = ET.parse(path, parser=parser) - root = tree.getroot() - - return cls.from_xml_element(root, materials) - - def find(self, point) -> list: + def find(self, point): """Find cells/universes/lattices which contain a given point Parameters @@ -313,7 +228,7 @@ class Geometry: """ return self.root_universe.find(point) - def get_instances(self, paths) -> int | list[int]: + def get_instances(self, paths): """Return the instance number(s) for a cell/material in a geometry path. The instance numbers are used as indices into distributed @@ -360,75 +275,61 @@ class Geometry: return indices if return_list else indices[0] - def get_all_cells(self) -> dict[int, openmc.Cell]: + def get_all_cells(self): """Return all cells in the geometry. Returns ------- - dict + collections.OrderedDict Dictionary mapping cell IDs to :class:`openmc.Cell` instances """ if self.root_universe is not None: - return self.root_universe.get_all_cells() + return self.root_universe.get_all_cells(memo=set()) else: - return {} + return OrderedDict() - def get_all_universes(self) -> dict[int, openmc.Universe]: + def get_all_universes(self): """Return all universes in the geometry. Returns ------- - dict + collections.OrderedDict Dictionary mapping universe IDs to :class:`openmc.Universe` instances """ - universes = {} + universes = OrderedDict() universes[self.root_universe.id] = self.root_universe universes.update(self.root_universe.get_all_universes()) return universes - def get_all_nuclides(self) -> list[str]: - """Return all nuclides within the geometry. - - Returns - ------- - list - Sorted list of all nuclides in materials appearing in the geometry - - """ - all_nuclides = set() - for material in self.get_all_materials().values(): - all_nuclides |= set(material.get_nuclides()) - return sorted(all_nuclides) - - def get_all_materials(self) -> dict[int, openmc.Material]: + def get_all_materials(self): """Return all materials within the geometry. Returns ------- - dict + collections.OrderedDict Dictionary mapping material IDs to :class:`openmc.Material` instances """ if self.root_universe is not None: - return self.root_universe.get_all_materials() + return self.root_universe.get_all_materials(memo=set()) else: - return {} + return OrderedDict() - def get_all_material_cells(self) -> dict[int, openmc.Cell]: + def get_all_material_cells(self): """Return all cells filled by a material Returns ------- - dict + collections.OrderedDict Dictionary mapping cell IDs to :class:`openmc.Cell` instances that are filled with materials or distributed materials. """ - material_cells = {} + material_cells = OrderedDict() for cell in self.get_all_cells().values(): if cell.fill_type in ('material', 'distribmat'): @@ -437,7 +338,7 @@ class Geometry: return material_cells - def get_all_material_universes(self) -> dict[int, openmc.Universe]: + def get_all_material_universes(self): """Return all universes having at least one material-filled cell. This method can be used to find universes that have at least one cell @@ -445,12 +346,12 @@ class Geometry: Returns ------- - dict + collections.OrderedDict Dictionary mapping universe IDs to :class:`openmc.Universe` instances with at least one material-filled cell """ - material_universes = {} + material_universes = OrderedDict() for universe in self.get_all_universes().values(): for cell in universe.cells.values(): @@ -460,16 +361,16 @@ class Geometry: return material_universes - def get_all_lattices(self) -> dict[int, openmc.Lattice]: + def get_all_lattices(self): """Return all lattices defined Returns ------- - dict + collections.OrderedDict Dictionary mapping lattice IDs to :class:`openmc.Lattice` instances """ - lattices = {} + lattices = OrderedDict() for cell in self.get_all_cells().values(): if cell.fill_type == 'lattice': @@ -478,24 +379,46 @@ class Geometry: return lattices - def get_all_surfaces(self) -> dict[int, openmc.Surface]: + def get_all_surfaces(self): """ Return all surfaces used in the geometry Returns ------- - dict + collections.OrderedDict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ - surfaces = {} + surfaces = OrderedDict() for cell in self.get_all_cells().values(): if cell.region is not None: surfaces = cell.region.get_surfaces(surfaces) return surfaces - def _get_domains_by_name(self, name, case_sensitive, matching, domain_type) -> list: + def get_redundant_surfaces(self): + """Return all of the topologically redundant surface IDs + + .. versionadded:: 0.12 + + Returns + ------- + dict + Dictionary whose keys are the ID of a redundant surface and whose + values are the topologically equivalent :class:`openmc.Surface` + that should replace it. + + """ + tally = defaultdict(list) + for surf in self.get_all_surfaces().values(): + coeffs = tuple(surf._coefficients[k] for k in surf._coeff_keys) + key = (surf._type,) + coeffs + tally[key].append(surf) + return {replace.id: keep + for keep, *redundant in tally.values() + for replace in redundant} + + def _get_domains_by_name(self, name, case_sensitive, matching, domain_type): if not case_sensitive: name = name.lower() @@ -512,9 +435,7 @@ class Geometry: domains.sort(key=lambda x: x.id) return domains - def get_materials_by_name( - self, name, case_sensitive=False, matching=False - ) -> list[openmc.Material]: + def get_materials_by_name(self, name, case_sensitive=False, matching=False): """Return a list of materials with matching names. Parameters @@ -535,9 +456,7 @@ class Geometry: """ return self._get_domains_by_name(name, case_sensitive, matching, 'material') - def get_cells_by_name( - self, name, case_sensitive=False, matching=False - ) -> list[openmc.Cell]: + def get_cells_by_name(self, name, case_sensitive=False, matching=False): """Return a list of cells with matching names. Parameters @@ -558,34 +477,7 @@ class Geometry: """ return self._get_domains_by_name(name, case_sensitive, matching, 'cell') - def get_surfaces_by_name( - self, name, case_sensitive=False, matching=False - ) -> list[openmc.Surface]: - """Return a list of surfaces with matching names. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - name : str - The name to search match - case_sensitive : bool - Whether to distinguish upper and lower case letters in each - surface's name (default is False) - matching : bool - Whether the names must match completely (default is False) - - Returns - ------- - list of openmc.Surface - Surfaces matching the queried name - - """ - return self._get_domains_by_name(name, case_sensitive, matching, 'surface') - - def get_cells_by_fill_name( - self, name, case_sensitive=False, matching=False - ) -> list[openmc.Cell]: + def get_cells_by_fill_name(self, name, case_sensitive=False, matching=False): """Return a list of cells with fills with matching names. Parameters @@ -630,9 +522,7 @@ class Geometry: return sorted(cells, key=lambda x: x.id) - def get_universes_by_name( - self, name, case_sensitive=False, matching=False - ) -> list[openmc.Universe]: + def get_universes_by_name(self, name, case_sensitive=False, matching=False): """Return a list of universes with matching names. Parameters @@ -653,9 +543,7 @@ class Geometry: """ return self._get_domains_by_name(name, case_sensitive, matching, 'universe') - def get_lattices_by_name( - self, name, case_sensitive=False, matching=False - ) -> list[openmc.Lattice]: + def get_lattices_by_name(self, name, case_sensitive=False, matching=False): """Return a list of lattices with matching names. Parameters @@ -676,43 +564,17 @@ class Geometry: """ return self._get_domains_by_name(name, case_sensitive, matching, 'lattice') - def remove_redundant_surfaces(self) -> dict[int, openmc.Surface]: - """Remove and return all of the redundant surfaces. + def remove_redundant_surfaces(self): + """Remove redundant surfaces from the geometry""" - Uses surface_precision attribute of Geometry instance for rounding and - comparing surface coefficients. - - .. versionadded:: 0.12 - - Returns - ------- - redundant_surfaces - Dictionary whose keys are the ID of a redundant surface and whose - values are the topologically equivalent :class:`openmc.Surface` - that should replace it. - - """ # Get redundant surfaces - redundancies = defaultdict(list) - for surf in self.get_all_surfaces().values(): - coeffs = tuple(round(surf._coefficients[k], - self.surface_precision) - for k in surf._coeff_keys) - key = (surf._type, surf._boundary_type) + coeffs - redundancies[key].append(surf) + redundant_surfaces = self.get_redundant_surfaces() - redundant_surfaces = {replace.id: keep - for keep, *redundant in redundancies.values() - for replace in redundant} - - if redundant_surfaces: - # Iterate through all cells contained in the geometry - for cell in self.get_all_cells().values(): - # Recursively remove redundant surfaces from regions - if cell.region: - cell.region.remove_redundant_surfaces(redundant_surfaces) - - return redundant_surfaces + # Iterate through all cells contained in the geometry + for cell in self.get_all_cells().values(): + # Recursively remove redundant surfaces from regions + if cell.region: + cell.region.remove_redundant_surfaces(redundant_surfaces) def determine_paths(self, instances_only=False): """Determine paths through CSG tree for cells and materials. @@ -739,45 +601,10 @@ class Geometry: # Recursively traverse the CSG tree to count all cell instances self.root_universe._determine_paths(instances_only=instances_only) - def clone(self) -> Geometry: + def clone(self): """Create a copy of this geometry with new unique IDs for all of its enclosed materials, surfaces, cells, universes and lattices.""" clone = deepcopy(self) clone.root_universe = self.root_universe.clone() return clone - - @add_plot_params - def plot(self, *args, **kwargs): - """Display a slice plot of the geometry. - - .. versionadded:: 0.14.0 - """ - model = openmc.Model() - model.geometry = self - model.materials = self.get_all_materials().values() - - # collect all the material names from the geometry - all_material_names = {m.name for m in model.materials if m.name is not None} - - # makes a placeholder material for each material name if it isn't - # already present on the model. These materials are otherwise missing - # from the geometry and are needed for plotting. - for universe in model.geometry.get_all_universes().values(): - if not isinstance(universe, openmc.DAGMCUniverse): - continue - for name in universe.material_names: - # if this name is already present in the model, skip it - # (this can happen if the same material name is used in multiple - # universes) - if name in all_material_names: - continue - # if the material name is not present on the model, - # create a placeholder material with the same name - # and add it to the model - mat_dag = openmc.Material(name=name) - mat_dag.add_nuclide('H1', 1.0) - model.materials.append(mat_dag) - all_material_names.add(name) - - return model.plot(*args, **kwargs) diff --git a/openmc/lattice.py b/openmc/lattice.py index 21849ec40..464daaf7e 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -1,16 +1,17 @@ from abc import ABC +from collections import OrderedDict from collections.abc import Iterable from copy import deepcopy from math import sqrt, floor from numbers import Real import types +from xml.etree import ElementTree as ET -import lxml.etree as ET import numpy as np import openmc import openmc.checkvalue as cv -from ._xml import get_elem_list, get_text +from ._xml import get_text from .mixin import IDManagerMixin @@ -33,16 +34,16 @@ class Lattice(IDManagerMixin, ABC): Name of the lattice pitch : Iterable of float Pitch of the lattice in each direction in cm - outer : openmc.UniverseBase + outer : openmc.Universe A universe to fill all space outside the lattice - universes : Iterable of Iterable of openmc.UniverseBase + universes : Iterable of Iterable of openmc.Universe A two-or three-dimensional list/array of universes filling each element of the lattice """ next_id = 1 - used_ids = openmc.UniverseBase.used_ids + used_ids = openmc.Universe.used_ids def __init__(self, lattice_id=None, name=''): # Initialize Lattice class attributes @@ -56,14 +57,6 @@ class Lattice(IDManagerMixin, ABC): def name(self): return self._name - @name.setter - def name(self, name): - if name is not None: - cv.check_type('lattice name', name, str) - self._name = name - else: - self._name = '' - @property def pitch(self): return self._pitch @@ -72,15 +65,23 @@ class Lattice(IDManagerMixin, ABC): def outer(self): return self._outer - @outer.setter - def outer(self, outer): - cv.check_type('outer universe', outer, openmc.UniverseBase) - self._outer = outer - @property def universes(self): return self._universes + @name.setter + def name(self, name): + if name is not None: + cv.check_type('lattice name', name, str) + self._name = name + else: + self._name = '' + + @outer.setter + def outer(self, outer): + cv.check_type('outer universe', outer, openmc.Universe) + self._outer = outer + @staticmethod def from_hdf5(group, universes): """Create lattice from HDF5 group @@ -91,7 +92,7 @@ class Lattice(IDManagerMixin, ABC): Group in HDF5 file universes : dict Dictionary mapping universe IDs to instances of - :class:`openmc.UniverseBase`. + :class:`openmc.Universe`. Returns ------- @@ -112,22 +113,22 @@ class Lattice(IDManagerMixin, ABC): Returns ------- - universes : dict + universes : collections.OrderedDict Dictionary whose keys are universe IDs and values are - :class:`openmc.UniverseBase` instances + :class:`openmc.Universe` instances """ - univs = {} + univs = OrderedDict() for k in range(len(self._universes)): for j in range(len(self._universes[k])): - if isinstance(self._universes[k][j], openmc.UniverseBase): + if isinstance(self._universes[k][j], openmc.Universe): u = self._universes[k][j] univs[u._id] = u else: for i in range(len(self._universes[k][j])): u = self._universes[k][j][i] - assert isinstance(u, openmc.UniverseBase) + assert isinstance(u, openmc.Universe) univs[u._id] = u if self.outer is not None: @@ -163,18 +164,18 @@ class Lattice(IDManagerMixin, ABC): Returns ------- - cells : dict + cells : collections.OrderedDict Dictionary whose keys are cell IDs and values are :class:`Cell` instances """ - cells = {} + cells = OrderedDict() - if memo is None: - memo = set() - elif self in memo: + if memo and self in memo: return cells - memo.add(self) + + if memo is not None: + memo.add(self) unique_universes = self.get_unique_universes() @@ -188,16 +189,13 @@ class Lattice(IDManagerMixin, ABC): Returns ------- - materials : dict + materials : collections.OrderedDict Dictionary whose keys are material IDs and values are :class:`Material` instances """ - if memo is None: - memo = set() - - materials = {} + materials = OrderedDict() # Append all Cells in each Cell in the Universe to the dictionary cells = self.get_all_cells(memo) @@ -206,25 +204,20 @@ class Lattice(IDManagerMixin, ABC): return materials - def get_all_universes(self, memo=None): + def get_all_universes(self): """Return all universes that are contained within the lattice Returns ------- - universes : dict + universes : collections.OrderedDict Dictionary whose keys are universe IDs and values are :class:`Universe` instances """ + # Initialize a dictionary of all Universes contained by the Lattice # in each nested Universe level - all_universes = {} - - if memo is None: - memo = set() - elif self in memo: - return all_universes - memo.add(self) + all_universes = OrderedDict() # Get all unique Universes contained in each of the lattice cells unique_universes = self.get_unique_universes() @@ -234,7 +227,7 @@ class Lattice(IDManagerMixin, ABC): # Append all Universes containing each cell to the dictionary for universe in unique_universes.values(): - all_universes.update(universe.get_all_universes(memo)) + all_universes.update(universe.get_all_universes()) return all_universes @@ -253,7 +246,7 @@ class Lattice(IDManagerMixin, ABC): Returns ------- - openmc.UniverseBase + openmc.Universe Universe with given indices """ @@ -377,9 +370,9 @@ class RectLattice(Lattice): pitch : Iterable of float Pitch of the lattice in the x, y, and (if applicable) z directions in cm. - outer : openmc.UniverseBase + outer : openmc.Universe A universe to fill all space outside the lattice - universes : Iterable of Iterable of openmc.UniverseBase + universes : Iterable of Iterable of openmc.Universe A two- or three-dimensional list/array of universes filling each element of the lattice. The first dimension corresponds to the z-direction (if applicable), the second dimension corresponds to the y-direction, and @@ -467,12 +460,6 @@ class RectLattice(Lattice): def lower_left(self): return self._lower_left - @lower_left.setter - def lower_left(self, lower_left): - cv.check_type('lattice lower left corner', lower_left, Iterable, Real) - cv.check_length('lattice lower left corner', lower_left, 2, 3) - self._lower_left = lower_left - @property def ndim(self): if self.pitch is not None: @@ -485,6 +472,12 @@ class RectLattice(Lattice): def shape(self): return self._universes.shape[::-1] + @lower_left.setter + def lower_left(self, lower_left): + cv.check_type('lattice lower left corner', lower_left, Iterable, Real) + cv.check_length('lattice lower left corner', lower_left, 2, 3) + self._lower_left = lower_left + @Lattice.pitch.setter def pitch(self, pitch): cv.check_type('lattice pitch', pitch, Iterable, Real) @@ -640,11 +633,11 @@ class RectLattice(Lattice): cv.check_value('strategy', strategy, ('degenerate', 'lns')) cv.check_type('universes_to_ignore', universes_to_ignore, Iterable, - openmc.UniverseBase) + openmc.Universe) cv.check_type('materials_to_clone', materials_to_clone, Iterable, openmc.Material) cv.check_type('lattice_neighbors', lattice_neighbors, Iterable, - openmc.UniverseBase) + openmc.Universe) cv.check_value('number of lattice_neighbors', len(lattice_neighbors), (0, 8)) cv.check_type('key', key, types.FunctionType) @@ -840,7 +833,7 @@ class RectLattice(Lattice): Parameters ---------- - xml_element : lxml.etree._Element + xml_element : xml.etree.ElementTree.Element XML element to be added to memo : set or None @@ -854,11 +847,10 @@ class RectLattice(Lattice): """ # If the element already contains the Lattice subelement, then return - if memo is None: - memo = set() - elif self in memo: + if memo and self in memo: return - memo.add(self) + if memo is not None: + memo.add(self) # Make sure universes have been assigned if self.universes is None: @@ -884,10 +876,6 @@ class RectLattice(Lattice): dimension = ET.SubElement(lattice_subelement, "dimension") dimension.text = ' '.join(map(str, self.shape)) - # Make sure lower_left has been specified - if self.lower_left is None: - raise ValueError(f"Lattice {self.id} does not have lower_left specified.") - # Export Lattice lower left lower_left = ET.SubElement(lattice_subelement, "lower_left") lower_left.text = ' '.join(map(str, self._lower_left)) @@ -944,7 +932,7 @@ class RectLattice(Lattice): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element `` element get_universe : function Function returning universe (defined in @@ -959,17 +947,18 @@ class RectLattice(Lattice): lat_id = int(get_text(elem, 'id')) name = get_text(elem, 'name') lat = cls(lat_id, name) - lat.lower_left = get_elem_list(elem, "lower_left", float) - lat.pitch = get_elem_list(elem, "pitch", float) + lat.lower_left = [float(i) + for i in get_text(elem, 'lower_left').split()] + lat.pitch = [float(i) for i in get_text(elem, 'pitch').split()] outer = get_text(elem, 'outer') if outer is not None: lat.outer = get_universe(int(outer)) # Get array of universes - dimension = get_elem_list(elem, 'dimension', int) + dimension = get_text(elem, 'dimension').split() shape = np.array(dimension, dtype=int)[::-1] - universes = get_elem_list(elem, 'universes', int) - uarray = np.array([get_universe(u) for u in universes]) + uarray = np.array([get_universe(int(i)) for i in + get_text(elem, 'universes').split()]) uarray.shape = shape lat.universes = uarray return lat @@ -984,7 +973,7 @@ class RectLattice(Lattice): Group in HDF5 file universes : dict Dictionary mapping universe IDs to instances of - :class:`openmc.UniverseBase`. + :class:`openmc.Universe`. Returns ------- @@ -1010,7 +999,7 @@ class RectLattice(Lattice): lattice.outer = universes[outer] # Build array of Universe pointers for the Lattice - uarray = np.empty(universe_ids.shape, dtype=openmc.UniverseBase) + uarray = np.empty(universe_ids.shape, dtype=openmc.Universe) for z in range(universe_ids.shape[0]): for y in range(universe_ids.shape[1]): @@ -1065,9 +1054,9 @@ class HexLattice(Lattice): Pitch of the lattice in cm. The first item in the iterable specifies the pitch in the radial direction and, if the lattice is 3D, the second item in the iterable specifies the pitch in the axial direction. - outer : openmc.UniverseBase + outer : openmc.Universe A universe to fill all space outside the lattice - universes : Nested Iterable of openmc.UniverseBase + universes : Nested Iterable of openmc.Universe A two- or three-dimensional list/array of universes filling each element of the lattice. Each sub-list corresponds to one ring of universes and should be ordered from outermost ring to innermost ring. The universes @@ -1083,11 +1072,8 @@ class HexLattice(Lattice): from the outermost ring), and i is the index with a ring starting from the top and proceeding clockwise. orientation : {'x', 'y'} - The orientation of the lattice. The 'x' orientation means that each - lattice element has two faces that are perpendicular to the x-axis, - while the 'y' orientation means that each lattice element has two faces - that are perpendicular to the y-axis. By default, the orientation is - 'y'. + str by default 'y' orientation of main lattice diagonal another option + - 'x' num_rings : int Number of radial ring positions in the xy-plane num_axial : int @@ -1142,11 +1128,6 @@ class HexLattice(Lattice): def orientation(self): return self._orientation - @orientation.setter - def orientation(self, orientation): - cv.check_value('orientation', orientation.lower(), ('x', 'y')) - self._orientation = orientation.lower() - @property def num_axial(self): return self._num_axial @@ -1155,12 +1136,6 @@ class HexLattice(Lattice): def center(self): return self._center - @center.setter - def center(self, center): - cv.check_type('lattice center', center, Iterable, Real) - cv.check_length('lattice center', center, 2, 3) - self._center = center - @property def indices(self): if self.num_axial is None: @@ -1198,7 +1173,18 @@ class HexLattice(Lattice): @property def ndim(self): - return 2 if isinstance(self.universes[0][0], openmc.UniverseBase) else 3 + return 2 if isinstance(self.universes[0][0], openmc.Universe) else 3 + + @center.setter + def center(self, center): + cv.check_type('lattice center', center, Iterable, Real) + cv.check_length('lattice center', center, 2, 3) + self._center = center + + @orientation.setter + def orientation(self, orientation): + cv.check_value('orientation', orientation.lower(), ('x', 'y')) + self._orientation = orientation.lower() @Lattice.pitch.setter def pitch(self, pitch): @@ -1210,7 +1196,7 @@ class HexLattice(Lattice): @Lattice.universes.setter def universes(self, universes): - cv.check_iterable_type('lattice universes', universes, openmc.UniverseBase, + cv.check_iterable_type('lattice universes', universes, openmc.Universe, min_depth=2, max_depth=3) self._universes = universes @@ -1432,11 +1418,10 @@ class HexLattice(Lattice): def create_xml_subelement(self, xml_element, memo=None): # If this subelement has already been written, return - if memo is None: - memo = set() - elif self in memo: + if memo and self in memo: return - memo.add(self) + if memo is not None: + memo.add(self) lattice_subelement = ET.Element("hex_lattice") lattice_subelement.set("id", str(self._id)) @@ -1517,7 +1502,7 @@ class HexLattice(Lattice): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element `` element get_universe : function Function returning universe (defined in @@ -1532,8 +1517,8 @@ class HexLattice(Lattice): lat_id = int(get_text(elem, 'id')) name = get_text(elem, 'name') lat = cls(lat_id, name) - lat.center = get_elem_list(elem, "center", float) - lat.pitch = get_elem_list(elem, "pitch", float) + lat.center = [float(i) for i in get_text(elem, 'center').split()] + lat.pitch = [float(i) for i in get_text(elem, 'pitch').split()] lat.orientation = get_text(elem, 'orientation', 'y') outer = get_text(elem, 'outer') if outer is not None: @@ -1550,8 +1535,8 @@ class HexLattice(Lattice): univs = [deepcopy(univs) for i in range(n_axial)] # Get flat array of universes - universes = get_elem_list(elem, "universes", int) - uarray = np.array([get_universe(u) for u in universes]) + uarray = np.array([get_universe(int(i)) for i in + get_text(elem, 'universes').split()]) # Fill nested lists j = 0 @@ -1580,7 +1565,6 @@ class HexLattice(Lattice): alpha -= 1 if not lat.is_valid_index((x, alpha, z)): # Reached the bottom - j += 1 break j += 1 else: @@ -1600,7 +1584,6 @@ class HexLattice(Lattice): # Check if we've reached the bottom if y == -n_rings: - j += 1 break while not lat.is_valid_index((alpha, y, z)): @@ -1869,7 +1852,7 @@ class HexLattice(Lattice): largest_index = 6*(num_rings - 1) n_digits_index = len(str(largest_index)) n_digits_ring = len(str(num_rings - 1)) - str_form = f'({{:{n_digits_ring}}},{{:{n_digits_index}}})' + str_form = '({{:{}}},{{:{}}})'.format(n_digits_ring, n_digits_index) pad = ' '*(n_digits_index + n_digits_ring + 3) # Initialize the list for each row. @@ -1974,7 +1957,7 @@ class HexLattice(Lattice): largest_index = 6*(num_rings - 1) n_digits_index = len(str(largest_index)) n_digits_ring = len(str(num_rings - 1)) - str_form = f'({{:{n_digits_ring}}},{{:{n_digits_index}}})' + str_form = '({{:{}}},{{:{}}})'.format(n_digits_ring, n_digits_index) pad = ' '*(n_digits_index + n_digits_ring + 3) # Initialize the list for each row. @@ -2069,7 +2052,7 @@ class HexLattice(Lattice): Group in HDF5 file universes : dict Dictionary mapping universe IDs to instances of - :class:`openmc.UniverseBase`. + :class:`openmc.Universe`. Returns ------- diff --git a/openmc/lib/__init__.py b/openmc/lib/__init__.py index 9b135370f..c14b0d9c2 100644 --- a/openmc/lib/__init__.py +++ b/openmc/lib/__init__.py @@ -13,10 +13,11 @@ functions or objects in :mod:`openmc.lib`, for example: """ from ctypes import CDLL, c_bool, c_int -import importlib.resources import os import sys +import pkg_resources + # Determine shared-library suffix if sys.platform == 'darwin': @@ -26,8 +27,9 @@ else: if os.environ.get('READTHEDOCS', None) != 'True': # Open shared library - _filename = importlib.resources.files(__name__) / f'libopenmc.{_suffix}' - _dll = CDLL(str(_filename)) # TODO: Remove str() when Python 3.12+ + _filename = pkg_resources.resource_filename( + __name__, 'libopenmc.{}'.format(_suffix)) + _dll = CDLL(_filename) else: # For documentation builds, we don't actually have the shared library # available. Instead, we create a mock object so that when the modules @@ -46,13 +48,6 @@ def _coord_levels(): def _libmesh_enabled(): return c_bool.in_dll(_dll, "LIBMESH_ENABLED").value -def _uwuw_enabled(): - return c_bool.in_dll(_dll, "UWUW_ENABLED").value - -def _strict_fp_enabled(): - return c_bool.in_dll(_dll, "STRICT_FP_ENABLED").value - - from .error import * from .core import * from .nuclide import * @@ -64,8 +59,6 @@ from .tally import * from .settings import settings from .math import * from .plot import * -from .weight_windows import * -from .dagmc import * # Flag to denote whether or not openmc.lib.init has been called # TODO: Establish and use a flag in the C++ code to represent the status of the diff --git a/openmc/lib/cell.py b/openmc/lib/cell.py index dfd09d2f9..b53a6be7a 100644 --- a/openmc/lib/cell.py +++ b/openmc/lib/cell.py @@ -11,8 +11,6 @@ from . import _dll from .core import _FortranObjectWithID from .error import _error_handler from .material import Material -from ..bounding_box import BoundingBox - __all__ = ['Cell', 'cells'] @@ -34,10 +32,6 @@ _dll.openmc_cell_get_temperature.argtypes = [ c_int32, POINTER(c_int32), POINTER(c_double)] _dll.openmc_cell_get_temperature.restype = c_int _dll.openmc_cell_get_temperature.errcheck = _error_handler -_dll.openmc_cell_get_density.argtypes = [ - c_int32, POINTER(c_int32), POINTER(c_double)] -_dll.openmc_cell_get_density.restype = c_int -_dll.openmc_cell_get_density.errcheck = _error_handler _dll.openmc_cell_get_name.argtypes = [c_int32, POINTER(c_char_p)] _dll.openmc_cell_get_name.restype = c_int _dll.openmc_cell_get_name.errcheck = _error_handler @@ -62,10 +56,6 @@ _dll.openmc_cell_set_temperature.argtypes = [ c_int32, c_double, POINTER(c_int32), c_bool] _dll.openmc_cell_set_temperature.restype = c_int _dll.openmc_cell_set_temperature.errcheck = _error_handler -_dll.openmc_cell_set_density.argtypes = [ - c_int32, c_double, POINTER(c_int32), c_bool] -_dll.openmc_cell_set_density.restype = c_int -_dll.openmc_cell_set_density.errcheck = _error_handler _dll.openmc_cell_set_translation.argtypes = [c_int32, POINTER(c_double)] _dll.openmc_cell_set_translation.restype = c_int _dll.openmc_cell_set_translation.errcheck = _error_handler @@ -111,8 +101,8 @@ class Cell(_FortranObjectWithID): Name of the cell num_instances : int Number of unique cell instances - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the cell + bounding_box : 2-tuple of numpy.ndarray + Lower-left and upper-right coordinates of bounding box translation : Iterable of float 3-D coordinates of the translation vector rotation : Iterable of float @@ -244,44 +234,6 @@ class Cell(_FortranObjectWithID): _dll.openmc_cell_set_temperature(self._index, T, instance, set_contained) - def get_density(self, instance: int | None = None): - """Get the density of a cell in [g/cm3] - - Parameters - ---------- - instance : int or None - Which instance of the cell - - """ - - if instance is not None: - instance = c_int32(instance) - - rho = c_double() - _dll.openmc_cell_get_density(self._index, instance, rho) - return rho.value - - def set_density(self, rho: float, instance: int | None = None, - set_contained: bool = False): - """Set the density of a cell - - Parameters - ---------- - rho : float - Density of the cell in [g/cm3] - instance : int or None - Which instance of the cell - set_contained : bool - If cell is not filled by a material, whether to set the density - of all filled cells - - """ - - if instance is not None: - instance = c_int32(instance) - - _dll.openmc_cell_set_density(self._index, rho, instance, set_contained) - @property def translation(self): translation = np.zeros(3) @@ -314,7 +266,7 @@ class Cell(_FortranObjectWithID): return rotation_data[9:] else: raise ValueError( - f'Invalid size of rotation matrix: {rot_size}') + 'Invalid size of rotation matrix: {}'.format(rot_size)) @rotation.setter def rotation(self, rotation_data): @@ -337,7 +289,7 @@ class Cell(_FortranObjectWithID): llc[llc == -inf] = -np.inf urc[urc == -inf] = -np.inf - return BoundingBox(llc, urc) + return llc, urc class _CellMapping(Mapping): diff --git a/openmc/lib/core.py b/openmc/lib/core.py index 0ee8c3ff0..479e414ae 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -4,18 +4,13 @@ from ctypes import (c_bool, c_int, c_int32, c_int64, c_double, c_char_p, c_uint64, c_size_t) import sys import os -from pathlib import Path from random import getrandbits -from tempfile import TemporaryDirectory -import traceback as tb import numpy as np from numpy.ctypeslib import as_array from . import _dll from .error import _error_handler -from ..mpi import comm -from openmc.checkvalue import PathLike import openmc.lib import openmc @@ -28,13 +23,10 @@ class _SourceSite(Structure): ('wgt', c_double), ('delayed_group', c_int), ('surf_id', c_int), - ('particle', c_int32), - ('parent_nuclide', c_int), + ('particle', c_int), ('parent_id', c_int64), - ('progeny_id', c_int64), - ('wgt_born', c_double), - ('wgt_ww_born', c_double), - ('n_split', c_int64)] + ('progeny_id', c_int64)] + # Define input type for numpy arrays that will be passed into C++ functions # Must be an int or double array, with single dimension that is contiguous @@ -84,7 +76,6 @@ _dll.openmc_properties_import.restype = c_int _dll.openmc_properties_import.errcheck = _error_handler _dll.openmc_run.restype = c_int _dll.openmc_run.errcheck = _error_handler -_dll.openmc_run_random_ray.restype = None _dll.openmc_reset.restype = c_int _dll.openmc_reset.errcheck = _error_handler _dll.openmc_reset_timers.restype = c_int @@ -103,11 +94,6 @@ _dll.openmc_simulation_finalize.errcheck = _error_handler _dll.openmc_statepoint_write.argtypes = [c_char_p, POINTER(c_bool)] _dll.openmc_statepoint_write.restype = c_int _dll.openmc_statepoint_write.errcheck = _error_handler -_dll.openmc_statepoint_load.argtypes = [c_char_p] -_dll.openmc_statepoint_load.restype = c_int -_dll.openmc_statepoint_load.errcheck = _error_handler -_dll.openmc_statepoint_write.restype = c_int -_dll.openmc_statepoint_write.errcheck = _error_handler _dll.openmc_global_bounding_box.argtypes = [POINTER(c_double), POINTER(c_double)] _dll.openmc_global_bounding_box.restype = c_int @@ -116,6 +102,7 @@ _dll.openmc_sample_external_source.argtypes = [c_size_t, POINTER(c_uint64), POIN _dll.openmc_sample_external_source.restype = c_int _dll.openmc_sample_external_source.errcheck = _error_handler + def global_bounding_box(): """Calculate a global bounding box for the model""" inf = sys.float_info.max @@ -184,54 +171,6 @@ def export_properties(filename=None, output=True): _dll.openmc_properties_export(filename) -def export_weight_windows(filename="weight_windows.h5", output=True): - """Export weight windows. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - filename : PathLike or None - Filename to export weight windows to - output : bool, optional - Whether or not to show output. - - See Also - -------- - openmc.lib.import_weight_windows - - """ - if filename is not None: - filename = c_char_p(str(filename).encode()) - - with quiet_dll(output): - _dll.openmc_weight_windows_export(filename) - - -def import_weight_windows(filename='weight_windows.h5', output=True): - """Import weight windows. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - filename : PathLike or None - Filename to import weight windows from - output : bool, optional - Whether or not to show output. - - See Also - -------- - openmc.lib.export_weight_windows - - """ - if filename is not None: - filename = c_char_p(str(filename).encode()) - - with quiet_dll(output): - _dll.openmc_weight_windows_import(filename) - - def finalize(): """Finalize simulation and free memory""" _dll.openmc_finalize() @@ -482,24 +421,8 @@ def run(output=True): _dll.openmc_run() -def run_random_ray(output=True): - """Run a random ray simulation - - Parameters - ---------- - output : bool, optional - Whether or not to show output. Defaults to showing output - """ - - with quiet_dll(output): - _dll.openmc_run_random_ray() - -def sample_external_source( - n_samples: int = 1000, - prn_seed: int | None = None, - as_array: bool = False -) -> openmc.ParticleList | np.ndarray: - """Sample external source and return source particles. +def sample_external_source(n_samples=1, prn_seed=None): + """Sample external source .. versionadded:: 0.13.1 @@ -510,20 +433,11 @@ def sample_external_source( prn_seed : int Pseudorandom number generator (PRNG) seed; if None, one will be generated randomly. - as_array : bool - If True, return a numpy structured array instead of a - :class:`~openmc.ParticleList`. The array has fields ``'r'`` (float64, - shape 3), ``'u'`` (float64, shape 3), ``'E'`` (float64), ``'time'`` - (float64), ``'wgt'`` (float64), ``'delayed_group'`` (int32), - ``'surf_id'`` (int32), and ``'particle'`` (int32). This avoids the - overhead of constructing individual :class:`~openmc.SourceParticle` - objects and is substantially faster for large sample counts. Returns ------- - openmc.ParticleList or numpy.ndarray - List of sampled source particles, or a structured array when - *as_array* is True. + list of openmc.SourceParticle + List of samples source particles """ if n_samples <= 0: @@ -531,28 +445,19 @@ def sample_external_source( if prn_seed is None: prn_seed = getrandbits(63) - # Pre-allocate output array and sample all particles in a single C call - result = np.empty(n_samples, dtype=_SourceSite) - sites_array = (_SourceSite * n_samples).from_buffer(result) - _dll.openmc_sample_external_source( - c_size_t(n_samples), - c_uint64(prn_seed), - sites_array, - ) + # Call into C API to sample source + sites_array = (_SourceSite * n_samples)() + _dll.openmc_sample_external_source(c_size_t(n_samples), c_uint64(prn_seed), sites_array) - if as_array: - return result - - particles = [ + # Convert to list of SourceParticle and return + return [ openmc.SourceParticle( - r=site.r, u=site.u, E=site.E, time=site.time, - wgt=site.wgt, delayed_group=site.delayed_group, - surf_id=site.surf_id, - particle=openmc.ParticleType(site.particle), + r=site.r, u=site.u, E=site.E, time=site.time, wgt=site.wgt, + delayed_group=site.delayed_group, surf_id=site.surf_id, + particle=openmc.ParticleType(site.particle) ) for site in sites_array ] - return openmc.ParticleList(particles) def simulation_init(): @@ -615,19 +520,6 @@ def statepoint_write(filename=None, write_source=True): _dll.openmc_statepoint_write(filename, c_bool(write_source)) -def statepoint_load(filename: PathLike): - """Load a statepoint file. - - Parameters - ---------- - filename : path-like - Path to the statepoint to load. - - """ - filename = c_char_p(str(filename).encode()) - _dll.openmc_statepoint_load(filename) - - @contextmanager def run_in_memory(**kwargs): """Provides context manager for calling OpenMC shared library functions. @@ -656,106 +548,6 @@ def run_in_memory(**kwargs): finalize() -class TemporarySession: - """Context manager for running via openmc.lib in a temporary directory. - - This class is useful for accessing functionality from openmc.lib without - polluting your current working directory with OpenMC files. It is used - internally as a persistent session to avoid loading cross sections multiple - times. - - Parameters - ---------- - model : openmc.Model, optional - OpenMC model to use for the session. If None, a minimal working model is - created. - cwd : PathLike, optional - Working directory in which to run OpenMC. If None, a temporary directory - is created and deleted automatically. - **init_kwargs - Keyword arguments to pass to :func:`openmc.lib.init`. - - Attributes - ---------- - model : openmc.Model - The OpenMC model used for the session. - comm : mpi4py.MPI.Intracomm - The MPI intracommunicator used for the session. - - """ - def __init__(self, model=None, cwd=None, **init_kwargs): - self.init_kwargs = dict(init_kwargs) - self.cwd = cwd - if model is None: - surf = openmc.Sphere(boundary_type="vacuum") - cell = openmc.Cell(region=-surf) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings = openmc.Settings( - particles=1, batches=1, output={'summary': False}) - self.model = model - - # Determine MPI intercommunicator - self.comm = self.init_kwargs.get('intracomm') or comm - self.init_kwargs['intracomm'] = self.comm - - def __enter__(self): - """Initialize the OpenMC library in a temporary directory.""" - # If already initialized, the context manager is a no-op - self.already_initialized = openmc.lib.is_initialized - if self.already_initialized: - return self - - # Store original working directory - self.orig_dir = Path.cwd() - - if self.cwd is None: - # Set up temporary directory on rank 0 - if self.comm.rank == 0: - self._tmp_dir = TemporaryDirectory() - self.cwd = self._tmp_dir.name - - # Broadcast the path so that all ranks use the same directory - self.cwd = self.comm.bcast(self.cwd) - - # Create and change to specified directory - self.cwd = Path(self.cwd) - self.cwd.mkdir(parents=True, exist_ok=True) - os.chdir(self.cwd) - - # Export model on first rank and initialize OpenMC - if self.comm.rank == 0: - self.model.export_to_model_xml() - self.comm.barrier() - openmc.lib.init(**self.init_kwargs) - - return self - - def __exit__(self, exc_type, exc_value, traceback): - """Finalize the OpenMC library and clean up temporary directory.""" - if self.already_initialized: - return - - # If an exception occurred, abort all ranks immediately - if exc_type is not None: - # Print exception info on the rank that failed - tb.print_exception(exc_type, exc_value, traceback) - sys.stdout.flush() - - # Abort all MPI processes - self.comm.Abort(1) - - try: - finalize() - finally: - os.chdir(self.orig_dir) - - # Make sure all ranks have finalized before deleting temporary dir - self.comm.barrier() - if hasattr(self, '_tmp_dir'): - self._tmp_dir.cleanup() - - class _DLLGlobal: """Data descriptor that exposes global variables from libopenmc.""" def __init__(self, ctype, name): @@ -771,7 +563,7 @@ class _DLLGlobal: class _FortranObject: def __repr__(self): - return f"<{type(self).__name__}(index={self._index})>" + return "{}[{}]".format(type(self).__name__, self._index) class _FortranObjectWithID(_FortranObject): @@ -782,9 +574,6 @@ class _FortranObjectWithID(_FortranObject): # OutOfBoundsError will be raised here by virtue of referencing self.id self.id - def __repr__(self): - return f"<{type(self).__name__}(id={self.id})>" - @contextmanager def quiet_dll(output=True): diff --git a/openmc/lib/dagmc.py b/openmc/lib/dagmc.py deleted file mode 100644 index 18ec81a4b..000000000 --- a/openmc/lib/dagmc.py +++ /dev/null @@ -1,43 +0,0 @@ -from ctypes import c_int, c_int32, POINTER, c_size_t - -import numpy as np - -from . import _dll -from .error import _error_handler - - -__all__ = [ - 'dagmc_universe_cell_ids' -] - -# DAGMC functions -_dll.openmc_dagmc_universe_get_cell_ids.argtypes = [c_int32, POINTER(c_int32), POINTER(c_size_t)] -_dll.openmc_dagmc_universe_get_cell_ids.restype = c_int -_dll.openmc_dagmc_universe_get_cell_ids.errcheck = _error_handler -_dll.openmc_dagmc_universe_get_num_cells.argtypes = [c_int32, POINTER(c_size_t)] -_dll.openmc_dagmc_universe_get_num_cells.restype = c_int -_dll.openmc_dagmc_universe_get_num_cells.errcheck = _error_handler - - -def dagmc_universe_cell_ids(universe_id: int) -> np.ndarray: - """Return an array of cell IDs for a DAGMC universe. - - Parameters - ---------- - dagmc_id : int - ID of the DAGMC universe to get cell IDs from. - - Returns - ------- - numpy.ndarray - DAGMC cell IDs for the universe. - - """ - n = c_size_t() - _dll.openmc_dagmc_universe_get_num_cells(universe_id, n) - cell_ids = np.empty(n.value, dtype=np.int32) - - _dll.openmc_dagmc_universe_get_cell_ids( - universe_id, cell_ids.ctypes.data_as(POINTER(c_int32)), n - ) - return cell_ids diff --git a/openmc/lib/error.py b/openmc/lib/error.py index dbe08e1ef..89e7b6e39 100644 --- a/openmc/lib/error.py +++ b/openmc/lib/error.py @@ -37,5 +37,5 @@ def _error_handler(err, func, args): warn(msg) elif err < 0: if not msg: - msg = f"Unknown error encountered (code {err})." + msg = "Unknown error encountered (code {}).".format(err) raise exc.OpenMCError(msg) diff --git a/openmc/lib/filter.py b/openmc/lib/filter.py index 574a37443..5d2231cc2 100644 --- a/openmc/lib/filter.py +++ b/openmc/lib/filter.py @@ -7,8 +7,6 @@ import numpy as np from numpy.ctypeslib import as_array from openmc.exceptions import AllocationError, InvalidIDError -from openmc.data.function import INTERPOLATION_SCHEME -from openmc import ParticleType from . import _dll from .core import _FortranObjectWithID from .error import _error_handler @@ -18,14 +16,11 @@ from .mesh import _get_mesh __all__ = [ 'Filter', 'AzimuthalFilter', 'CellFilter', 'CellbornFilter', 'CellfromFilter', - 'CellInstanceFilter', 'CollisionFilter', 'DistribcellFilter', 'DelayedGroupFilter', - 'EnergyFilter', 'EnergyoutFilter', 'EnergyFunctionFilter', 'LegendreFilter', - 'MaterialFilter', 'MaterialFromFilter', 'MeshFilter', 'MeshBornFilter', - 'MeshMaterialFilter', 'MeshSurfaceFilter', 'MuFilter', 'MuSurfaceFilter', - 'ParentNuclideFilter', 'ParticleFilter', 'ParticleProductionFilter', 'PolarFilter', - 'ReactionFilter', 'SphericalHarmonicsFilter', 'SpatialLegendreFilter', - 'SurfaceFilter', 'TimeFilter', 'UniverseFilter', 'WeightFilter', 'ZernikeFilter', - 'ZernikeRadialFilter', 'filters' + 'CellInstanceFilter', 'CollisionFilter', 'DistribcellFilter', 'DelayedGroupFilter', + 'EnergyFilter', 'EnergyoutFilter', 'EnergyFunctionFilter', 'LegendreFilter', + 'MaterialFilter', 'MeshFilter', 'MeshSurfaceFilter', 'MuFilter', 'ParticleFilter', + 'PolarFilter', 'SphericalHarmonicsFilter', 'SpatialLegendreFilter', 'SurfaceFilter', + 'UniverseFilter', 'ZernikeFilter', 'ZernikeRadialFilter', 'filters' ] # Tally functions @@ -52,18 +47,9 @@ _dll.openmc_energyfunc_filter_get_y.resttpe = c_int _dll.openmc_energyfunc_filter_get_y.errcheck = _error_handler _dll.openmc_energyfunc_filter_get_y.argtypes = [ c_int32, POINTER(c_size_t), POINTER(POINTER(c_double))] -_dll.openmc_energyfunc_filter_get_interpolation.resttpe = c_int -_dll.openmc_energyfunc_filter_get_interpolation.errcheck = _error_handler -_dll.openmc_energyfunc_filter_get_interpolation.argtypes = [c_int32, POINTER(c_int)] -_dll.openmc_energyfunc_filter_set_interpolation.resttpe = c_int -_dll.openmc_energyfunc_filter_set_interpolation.errcheck = _error_handler -_dll.openmc_energyfunc_filter_set_interpolation.argtypes = [c_int32, c_char_p] _dll.openmc_filter_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_filter_get_id.restype = c_int _dll.openmc_filter_get_id.errcheck = _error_handler -_dll.openmc_filter_get_num_bins.argtypes = [c_int32, POINTER(c_int)] -_dll.openmc_filter_get_num_bins.restype = c_int -_dll.openmc_filter_get_num_bins.errchck = _error_handler _dll.openmc_filter_get_type.argtypes = [c_int32, c_char_p] _dll.openmc_filter_get_type.restype = c_int _dll.openmc_filter_get_type.errcheck = _error_handler @@ -92,50 +78,21 @@ _dll.openmc_mesh_filter_get_mesh.errcheck = _error_handler _dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32] _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler -_dll.openmc_mesh_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] -_dll.openmc_mesh_filter_get_translation.restype = c_int -_dll.openmc_mesh_filter_get_translation.errcheck = _error_handler -_dll.openmc_mesh_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] -_dll.openmc_mesh_filter_set_translation.restype = c_int -_dll.openmc_mesh_filter_set_translation.errcheck = _error_handler -_dll.openmc_mesh_filter_get_rotation.argtypes = [c_int32, POINTER(c_double), - POINTER(c_size_t)] -_dll.openmc_mesh_filter_get_rotation.restype = c_int -_dll.openmc_mesh_filter_get_rotation.errcheck = _error_handler -_dll.openmc_mesh_filter_set_rotation.argtypes = [ - c_int32, POINTER(c_double), c_size_t] -_dll.openmc_mesh_filter_set_rotation.restype = c_int -_dll.openmc_mesh_filter_set_rotation.errcheck = _error_handler -_dll.openmc_meshborn_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_meshborn_filter_get_mesh.restype = c_int -_dll.openmc_meshborn_filter_get_mesh.errcheck = _error_handler -_dll.openmc_meshborn_filter_set_mesh.argtypes = [c_int32, c_int32] -_dll.openmc_meshborn_filter_set_mesh.restype = c_int -_dll.openmc_meshborn_filter_set_mesh.errcheck = _error_handler -_dll.openmc_meshborn_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] -_dll.openmc_meshborn_filter_get_translation.restype = c_int -_dll.openmc_meshborn_filter_get_translation.errcheck = _error_handler -_dll.openmc_meshborn_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] -_dll.openmc_meshborn_filter_set_translation.restype = c_int -_dll.openmc_meshborn_filter_set_translation.errcheck = _error_handler _dll.openmc_meshsurface_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_meshsurface_filter_get_mesh.restype = c_int _dll.openmc_meshsurface_filter_get_mesh.errcheck = _error_handler _dll.openmc_meshsurface_filter_set_mesh.argtypes = [c_int32, c_int32] _dll.openmc_meshsurface_filter_set_mesh.restype = c_int _dll.openmc_meshsurface_filter_set_mesh.errcheck = _error_handler -_dll.openmc_meshsurface_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] -_dll.openmc_meshsurface_filter_get_translation.restype = c_int -_dll.openmc_meshsurface_filter_get_translation.errcheck = _error_handler -_dll.openmc_meshsurface_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] -_dll.openmc_meshsurface_filter_set_translation.restype = c_int -_dll.openmc_meshsurface_filter_set_translation.errcheck = _error_handler +_dll.openmc_mesh_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] +_dll.openmc_mesh_filter_get_translation.restype = c_int +_dll.openmc_mesh_filter_get_translation.errcheck = _error_handler +_dll.openmc_mesh_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] +_dll.openmc_mesh_filter_set_translation.restype = c_int +_dll.openmc_mesh_filter_set_translation.errcheck = _error_handler _dll.openmc_new_filter.argtypes = [c_char_p, POINTER(c_int32)] _dll.openmc_new_filter.restype = c_int _dll.openmc_new_filter.errcheck = _error_handler -_dll.openmc_particle_filter_get_bins.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_particle_filter_get_bins.restype = c_int -_dll.openmc_particle_filter_get_bins.errcheck = _error_handler _dll.openmc_spatial_legendre_filter_get_order.argtypes = [c_int32, POINTER(c_int)] _dll.openmc_spatial_legendre_filter_get_order.restype = c_int _dll.openmc_spatial_legendre_filter_get_order.errcheck = _error_handler @@ -156,6 +113,7 @@ _dll.openmc_zernike_filter_set_order.restype = c_int _dll.openmc_zernike_filter_set_order.errcheck = _error_handler _dll.tally_filters_size.restype = c_size_t + class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() @@ -198,12 +156,6 @@ class Filter(_FortranObjectWithID): def id(self, filter_id): _dll.openmc_filter_set_id(self._index, filter_id) - @property - def n_bins(self): - n = c_int() - _dll.openmc_filter_get_num_bins(self._index, n) - return n.value - class EnergyFilter(Filter): filter_type = 'energy' @@ -295,8 +247,6 @@ class EnergyFunctionFilter(Filter): Independent variable for the interpolation y : numpy.ndarray Dependent variable for the interpolation - interpolation : {'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log', 'quadratic', 'cubic'} - Interpolation scheme """ energy_array = np.asarray(energy) y_array = np.asarray(y) @@ -314,17 +264,6 @@ class EnergyFunctionFilter(Filter): def y(self): return self._get_attr(_dll.openmc_energyfunc_filter_get_y) - @property - def interpolation(self) -> str: - interp = c_int() - _dll.openmc_energyfunc_filter_get_interpolation(self._index, interp) - return INTERPOLATION_SCHEME[interp.value] - - @interpolation.setter - def interpolation(self, interp: str): - interp_ptr = c_char_p(interp.encode()) - _dll.openmc_energyfunc_filter_set_interpolation(self._index, interp_ptr) - def _get_attr(self, cfunc): array_p = POINTER(c_double)() n = c_size_t() @@ -374,43 +313,7 @@ class MaterialFilter(Filter): _dll.openmc_material_filter_set_bins(self._index, n, bins) -class MaterialFromFilter(Filter): - filter_type = 'materialfrom' - - class MeshFilter(Filter): - """Mesh filter stored internally. - - This class exposes a Mesh filter that is stored internally in the OpenMC - library. To obtain a view of a Mesh filter with a given ID, use the - :data:`openmc.lib.filters` mapping. - - Parameters - ---------- - mesh : openmc.lib.Mesh - Mesh to use for the filter - uid : int or None - Unique ID of the Mesh filter - new : bool - When `index` is None, this argument controls whether a new object is - created or a view of an existing object is returned. - index : int - Index in the `filters` array. - - Attributes - ---------- - filter_type : str - Type of filter - mesh : openmc.lib.Mesh - Mesh used for the filter - translation : Iterable of float - 3-D coordinates of the translation vector - rotation : Iterable of float - The rotation matrix or angles of the filter mesh. This can either be - a fully specified 3 x 3 rotation matrix or an Iterable of length 3 - with the angles in degrees about the x, y, and z axes, respectively. - - """ filter_type = 'mesh' def __init__(self, mesh=None, uid=None, new=True, index=None): @@ -438,125 +341,8 @@ class MeshFilter(Filter): def translation(self, translation): _dll.openmc_mesh_filter_set_translation(self._index, (c_double*3)(*translation)) - @property - def rotation(self): - rotation_data = np.zeros(12) - rot_size = c_size_t() - - _dll.openmc_mesh_filter_get_rotation( - self._index, rotation_data.ctypes.data_as(POINTER(c_double)), - rot_size) - rot_size = rot_size.value - - if rot_size == 9: - return rotation_data[:rot_size].shape(3, 3) - elif rot_size in (0, 12): - # If size is 0, rotation_data[9:] will be zeros. This indicates no - # rotation and is the most straightforward way to always return - # an iterable of floats - return rotation_data[9:] - else: - raise ValueError( - f'Invalid size of rotation matrix: {rot_size}') - - @rotation.setter - def rotation(self, rotation_data): - flat_rotation = np.asarray(rotation_data, dtype=float).flatten() - - _dll.openmc_mesh_filter_set_rotation( - self._index, flat_rotation.ctypes.data_as(POINTER(c_double)), - c_size_t(len(flat_rotation))) - -class MeshBornFilter(Filter): - """MeshBorn filter stored internally. - - This class exposes a MeshBorn filter that is stored internally in the OpenMC - library. To obtain a view of a MeshBorn filter with a given ID, use the - :data:`openmc.lib.filters` mapping. - - Parameters - ---------- - mesh : openmc.lib.Mesh - Mesh to use for the filter - uid : int or None - Unique ID of the MeshBorn filter - new : bool - When `index` is None, this argument controls whether a new object is - created or a view of an existing object is returned. - index : int - Index in the `filters` array. - - Attributes - ---------- - filter_type : str - Type of filter - mesh : openmc.lib.Mesh - Mesh used for the filter - translation : Iterable of float - 3-D coordinates of the translation vector - - """ - filter_type = 'meshborn' - - def __init__(self, mesh=None, uid=None, new=True, index=None): - super().__init__(uid, new, index) - if mesh is not None: - self.mesh = mesh - - @property - def mesh(self): - index_mesh = c_int32() - _dll.openmc_meshborn_filter_get_mesh(self._index, index_mesh) - return _get_mesh(index_mesh.value) - - @mesh.setter - def mesh(self, mesh): - _dll.openmc_meshborn_filter_set_mesh(self._index, mesh._index) - - @property - def translation(self): - translation = (c_double*3)() - _dll.openmc_meshborn_filter_get_translation(self._index, translation) - return tuple(translation) - - @translation.setter - def translation(self, translation): - _dll.openmc_meshborn_filter_set_translation(self._index, (c_double*3)(*translation)) - - -class MeshMaterialFilter(Filter): - filter_type = 'meshmaterial' - class MeshSurfaceFilter(Filter): - """MeshSurface filter stored internally. - - This class exposes a MeshSurface filter that is stored internally in the - OpenMC library. To obtain a view of a MeshSurface filter with a given ID, - use the :data:`openmc.lib.filters` mapping. - - Parameters - ---------- - mesh : openmc.lib.Mesh - Mesh to use for the filter - uid : int or None - Unique ID of the MeshSurface filter - new : bool - When `index` is None, this argument controls whether a new object is - created or a view of an existing object is returned. - index : int - Index in the `filters` array. - - Attributes - ---------- - filter_type : str - Type of filter - mesh : openmc.lib.Mesh - Mesh used for the filter - translation : Iterable of float - 3-D coordinates of the translation vector - - """ filter_type = 'meshsurface' def __init__(self, mesh=None, uid=None, new=True, index=None): @@ -577,49 +363,26 @@ class MeshSurfaceFilter(Filter): @property def translation(self): translation = (c_double*3)() - _dll.openmc_meshsurface_filter_get_translation(self._index, translation) + _dll.openmc_mesh_filter_get_translation(self._index, translation) return tuple(translation) @translation.setter def translation(self, translation): - _dll.openmc_meshsurface_filter_set_translation(self._index, (c_double*3)(*translation)) + _dll.openmc_mesh_filter_set_translation(self._index, (c_double*3)(*translation)) class MuFilter(Filter): filter_type = 'mu' -class MuSurfaceFilter(Filter): - filter_type = 'musurface' - - -class ParentNuclideFilter(Filter): - filter_type = 'parentnuclide' - - class ParticleFilter(Filter): filter_type = 'particle' - @property - def bins(self): - particle_i = np.zeros((self.n_bins,), dtype=c_int32) - _dll.openmc_particle_filter_get_bins( - self._index, particle_i.ctypes.data_as(POINTER(c_int32))) - return [ParticleType(i) for i in particle_i] - - -class ParticleProductionFilter(Filter): - filter_type = 'particleproduction' - class PolarFilter(Filter): filter_type = 'polar' -class ReactionFilter(Filter): - filter_type = 'reaction' - - class SphericalHarmonicsFilter(Filter): filter_type = 'sphericalharmonics' @@ -662,18 +425,10 @@ class SurfaceFilter(Filter): filter_type = 'surface' -class TimeFilter(Filter): - filter_type = 'time' - - class UniverseFilter(Filter): filter_type = 'universe' -class WeightFilter(Filter): - filter_type = 'weight' - - class ZernikeFilter(Filter): filter_type = 'zernike' @@ -703,7 +458,6 @@ _FILTER_TYPE_MAP = { 'cellborn': CellbornFilter, 'cellfrom': CellfromFilter, 'cellinstance': CellInstanceFilter, - 'collision': CollisionFilter, 'delayedgroup': DelayedGroupFilter, 'distribcell': DistribcellFilter, 'energy': EnergyFilter, @@ -711,24 +465,15 @@ _FILTER_TYPE_MAP = { 'energyfunction': EnergyFunctionFilter, 'legendre': LegendreFilter, 'material': MaterialFilter, - 'materialfrom': MaterialFromFilter, 'mesh': MeshFilter, - 'meshborn': MeshBornFilter, - 'meshmaterial': MeshMaterialFilter, 'meshsurface': MeshSurfaceFilter, 'mu': MuFilter, - 'musurface': MuSurfaceFilter, - 'parentnuclide': ParentNuclideFilter, 'particle': ParticleFilter, - 'particleproduction': ParticleProductionFilter, 'polar': PolarFilter, - 'reaction': ReactionFilter, 'sphericalharmonics': SphericalHarmonicsFilter, 'spatiallegendre': SpatialLegendreFilter, 'surface': SurfaceFilter, - 'time': TimeFilter, 'universe': UniverseFilter, - 'weight': WeightFilter, 'zernike': ZernikeFilter, 'zernikeradial': ZernikeRadialFilter } diff --git a/openmc/lib/material.py b/openmc/lib/material.py index 0ed8932da..fde197d3d 100644 --- a/openmc/lib/material.py +++ b/openmc/lib/material.py @@ -1,5 +1,5 @@ from collections.abc import Mapping -from ctypes import c_bool, c_int, c_int32, c_double, c_char_p, POINTER, c_size_t +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER, c_size_t from weakref import WeakValueDictionary import numpy as np @@ -60,12 +60,6 @@ _dll.openmc_material_set_name.errcheck = _error_handler _dll.openmc_material_set_volume.argtypes = [c_int32, c_double] _dll.openmc_material_set_volume.restype = c_int _dll.openmc_material_set_volume.errcheck = _error_handler -_dll.openmc_material_get_depletable.argtypes = [c_int32, POINTER(c_bool)] -_dll.openmc_material_get_depletable.restype = c_int -_dll.openmc_material_get_depletable.errcheck = _error_handler -_dll.openmc_material_set_depletable.argtypes = [c_int32, c_bool] -_dll.openmc_material_set_depletable.restype = c_int -_dll.openmc_material_set_depletable.errcheck = _error_handler _dll.n_materials.argtypes = [] _dll.n_materials.restype = c_size_t @@ -95,8 +89,6 @@ class Material(_FortranObjectWithID): List of nuclides in the material densities : numpy.ndarray Array of densities in atom/b-cm - depletable : bool - Whether this material is marked as depletable name : str Name of the material temperature : float @@ -177,16 +169,6 @@ class Material(_FortranObjectWithID): def volume(self, volume): _dll.openmc_material_set_volume(self._index, volume) - @property - def depletable(self): - depletable = c_bool() - _dll.openmc_material_get_depletable(self._index, depletable) - return depletable.value - - @depletable.setter - def depletable(self, depletable): - _dll.openmc_material_set_depletable(self._index, depletable) - @property def nuclides(self): return self._get_densities()[0] diff --git a/openmc/lib/math.py b/openmc/lib/math.py index 8c62f2416..0f61450bf 100644 --- a/openmc/lib/math.py +++ b/openmc/lib/math.py @@ -1,4 +1,5 @@ -from ctypes import c_int, c_double +from ctypes import c_int, c_double, POINTER, c_uint64 +from random import getrandbits import numpy as np from numpy.ctypeslib import ndpointer @@ -6,18 +7,137 @@ from numpy.ctypeslib import ndpointer from . import _dll +_dll.t_percentile.restype = c_double +_dll.t_percentile.argtypes = [c_double, c_int] + +_dll.calc_pn_c.restype = None +_dll.calc_pn_c.argtypes = [c_int, c_double, ndpointer(c_double)] + +_dll.evaluate_legendre.restype = c_double +_dll.evaluate_legendre.argtypes = [c_int, POINTER(c_double), c_double] + +_dll.calc_rn_c.restype = None +_dll.calc_rn_c.argtypes = [c_int, ndpointer(c_double), ndpointer(c_double)] + _dll.calc_zn.restype = None _dll.calc_zn.argtypes = [c_int, c_double, c_double, ndpointer(c_double)] _dll.calc_zn_rad.restype = None _dll.calc_zn_rad.argtypes = [c_int, c_double, ndpointer(c_double)] +_dll.rotate_angle_c.restype = None +_dll.rotate_angle_c.argtypes = [ndpointer(c_double), c_double, + POINTER(c_double), POINTER(c_uint64)] +_dll.maxwell_spectrum.restype = c_double +_dll.maxwell_spectrum.argtypes = [c_double, POINTER(c_uint64)] + +_dll.watt_spectrum.restype = c_double +_dll.watt_spectrum.argtypes = [c_double, c_double, POINTER(c_uint64)] + +_dll.broaden_wmp_polynomials.restype = None +_dll.broaden_wmp_polynomials.argtypes = [c_double, c_double, c_int, + ndpointer(c_double)] + +_dll.normal_variate.restype = c_double +_dll.normal_variate.argtypes = [c_double, c_double, POINTER(c_uint64)] + +def t_percentile(p, df): + """ Calculate the percentile of the Student's t distribution with a + specified probability level and number of degrees of freedom + + Parameters + ---------- + p : float + Probability level + df : int + Degrees of freedom + + Returns + ------- + float + Corresponding t-value + + """ + + return _dll.t_percentile(p, df) + + +def calc_pn(n, x): + """ Calculate the n-th order Legendre polynomial at the value of x. + + Parameters + ---------- + n : int + Legendre order + x : float + Independent variable to evaluate the Legendre at + + Returns + ------- + float + Corresponding Legendre polynomial result + + """ + + pnx = np.empty(n + 1, dtype=np.float64) + _dll.calc_pn_c(n, x, pnx) + return pnx + + +def evaluate_legendre(data, x): + """ Finds the value of f(x) given a set of Legendre coefficients + and the value of x. + + Parameters + ---------- + data : iterable of float + Legendre coefficients + x : float + Independent variable to evaluate the Legendre at + + Returns + ------- + float + Corresponding Legendre expansion result + + """ + + data_arr = np.array(data, dtype=np.float64) + return _dll.evaluate_legendre(len(data), + data_arr.ctypes.data_as(POINTER(c_double)), x) + + +def calc_rn(n, uvw): + """ Calculate the n-th order real Spherical Harmonics for a given angle; + all Rn,m values are provided for all n (where -n <= m <= n). + + Parameters + ---------- + n : int + Harmonics order + uvw : iterable of float + Independent variable to evaluate the Legendre at + + Returns + ------- + numpy.ndarray + Corresponding real harmonics value + + """ + + num_nm = (n + 1) * (n + 1) + rn = np.empty(num_nm, dtype=np.float64) + uvw_arr = np.array(uvw, dtype=np.float64) + _dll.calc_rn_c(n, uvw_arr, rn) + return rn + def calc_zn(n, rho, phi): """ Calculate the n-th order modified Zernike polynomial moment for a given angle (rho, theta) location in the unit disk. The normalization of the polynomials is such that the integral of Z_pq*Z_pq over the unit disk is exactly pi + Parameters ---------- n : int @@ -26,10 +146,12 @@ def calc_zn(n, rho, phi): Radial location in the unit disk phi : float Theta (radians) location in the unit disk + Returns ------- numpy.ndarray Corresponding resulting list of coefficients + """ num_bins = ((n + 1) * (n + 2)) // 2 @@ -43,19 +165,161 @@ def calc_zn_rad(n, rho): moment with no azimuthal dependency (m=0) for a given radial location in the unit disk. The normalization of the polynomials is such that the integral of Z_pq*Z_pq over the unit disk is exactly pi. + Parameters ---------- n : int Maximum order rho : float Radial location in the unit disk + Returns ------- numpy.ndarray Corresponding resulting list of coefficients + """ num_bins = n // 2 + 1 zn_rad = np.zeros(num_bins, dtype=np.float64) _dll.calc_zn_rad(n, rho, zn_rad) return zn_rad + + +def rotate_angle(uvw0, mu, phi, prn_seed=None): + """ Rotates direction cosines through a polar angle whose cosine is + mu and through an azimuthal angle sampled uniformly. + + Parameters + ---------- + uvw0 : iterable of float + Original direction cosine + mu : float + Polar angle cosine to rotate + phi : float + Azimuthal angle; if None, one will be sampled uniformly + prn_seed : int + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + + Returns + ------- + numpy.ndarray + Rotated direction cosine + + """ + + if prn_seed is None: + prn_seed = getrandbits(63) + + uvw0_arr = np.array(uvw0, dtype=np.float64) + if phi is None: + _dll.rotate_angle_c(uvw0_arr, mu, None, c_uint64(prn_seed)) + else: + _dll.rotate_angle_c(uvw0_arr, mu, c_double(phi), c_uint64(prn_seed)) + + uvw = uvw0_arr + + return uvw + + +def maxwell_spectrum(T, prn_seed=None): + """ Samples an energy from the Maxwell fission distribution based + on a direct sampling scheme. + + Parameters + ---------- + T : float + Spectrum parameter + prn_seed : int + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + + Returns + ------- + float + Sampled outgoing energy + + """ + + if prn_seed is None: + prn_seed = getrandbits(63) + + return _dll.maxwell_spectrum(T, c_uint64(prn_seed)) + + +def watt_spectrum(a, b, prn_seed=None): + """ Samples an energy from the Watt energy-dependent fission spectrum. + + Parameters + ---------- + a : float + Spectrum parameter a + b : float + Spectrum parameter b + prn_seed : int + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + + Returns + ------- + float + Sampled outgoing energy + + """ + + if prn_seed is None: + prn_seed = getrandbits(63) + + return _dll.watt_spectrum(a, b, c_uint64(prn_seed)) + + +def normal_variate(mean_value, std_dev, prn_seed=None): + """ Samples an energy from the Normal distribution. + + Parameters + ---------- + mean_value : float + Mean of the Normal distribution + std_dev : float + Standard deviation of the normal distribution + prn_seed : int + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + + Returns + ------- + float + Sampled outgoing normally distributed value + + """ + + if prn_seed is None: + prn_seed = getrandbits(63) + + return _dll.normal_variate(mean_value, std_dev, c_uint64(prn_seed)) + + +def broaden_wmp_polynomials(E, dopp, n): + """ Doppler broadens the windowed multipole curvefit. The curvefit is a + polynomial of the form a/E + b/sqrt(E) + c + d sqrt(E) ... + + Parameters + ---------- + E : float + Energy to evaluate at + dopp : float + sqrt(atomic weight ratio / kT), with kT given in eV + n : int + Number of components to the polynomial + + Returns + ------- + numpy.ndarray + Resultant leading coefficients + + """ + + factors = np.zeros(n, dtype=np.float64) + _dll.broaden_wmp_polynomials(E, dopp, n, factors) + return factors diff --git a/openmc/lib/mesh.py b/openmc/lib/mesh.py index 19e6f74d7..84571628c 100644 --- a/openmc/lib/mesh.py +++ b/openmc/lib/mesh.py @@ -1,8 +1,6 @@ -from collections.abc import Mapping, Sequence -from ctypes import (c_int, c_int32, c_char_p, c_double, POINTER, c_void_p, - create_string_buffer, c_size_t) -from math import sqrt -import sys +from collections.abc import Mapping +from ctypes import (c_int, c_int32, c_char_p, c_double, POINTER, + create_string_buffer) from weakref import WeakValueDictionary import numpy as np @@ -10,20 +8,10 @@ from numpy.ctypeslib import as_array from ..exceptions import AllocationError, InvalidIDError from . import _dll -from .core import _FortranObjectWithID, quiet_dll +from .core import _FortranObjectWithID from .error import _error_handler -from .plot import _Position -from ..bounding_box import BoundingBox -from ..mesh import MeshMaterialVolumes -__all__ = [ - 'Mesh', 'RegularMesh', 'RectilinearMesh', 'CylindricalMesh', - 'SphericalMesh', 'UnstructuredMesh', 'meshes', 'MeshMaterialVolumes' -] - - -arr_2d_int32 = np.ctypeslib.ndpointer(dtype=np.int32, ndim=2, flags='CONTIGUOUS') -arr_2d_double = np.ctypeslib.ndpointer(dtype=np.double, ndim=2, flags='CONTIGUOUS') +__all__ = ['RegularMesh', 'RectilinearMesh', 'CylindricalMesh', 'SphericalMesh', 'meshes'] # Mesh functions _dll.openmc_extend_meshes.argtypes = [c_int32, c_char_p, POINTER(c_int32), @@ -36,26 +24,6 @@ _dll.openmc_mesh_get_id.errcheck = _error_handler _dll.openmc_mesh_set_id.argtypes = [c_int32, c_int32] _dll.openmc_mesh_set_id.restype = c_int _dll.openmc_mesh_set_id.errcheck = _error_handler -_dll.openmc_mesh_get_n_elements.argtypes = [c_int32, POINTER(c_size_t)] -_dll.openmc_mesh_get_n_elements.restype = c_int -_dll.openmc_mesh_get_n_elements.errcheck = _error_handler -_dll.openmc_mesh_get_volumes.argtypes = [c_int32, POINTER(c_double)] -_dll.openmc_mesh_get_volumes.restype = c_int -_dll.openmc_mesh_get_volumes.errcheck = _error_handler -_dll.openmc_mesh_bounding_box.argtypes = [ - c_int32, POINTER(c_double), POINTER(c_double)] -_dll.openmc_mesh_bounding_box.restype = c_int -_dll.openmc_mesh_bounding_box.errcheck = _error_handler -_dll.openmc_mesh_material_volumes.argtypes = [ - c_int32, c_int, c_int, c_int, c_int, arr_2d_int32, arr_2d_double, - c_void_p] -_dll.openmc_mesh_material_volumes.restype = c_int -_dll.openmc_mesh_material_volumes.errcheck = _error_handler -_dll.openmc_mesh_get_plot_bins.argtypes = [ - c_int32, _Position, _Position, c_int, POINTER(c_int), POINTER(c_int32) -] -_dll.openmc_mesh_get_plot_bins.restype = c_int -_dll.openmc_mesh_get_plot_bins.errcheck = _error_handler _dll.openmc_get_mesh_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_mesh_index.restype = c_int _dll.openmc_get_mesh_index.errcheck = _error_handler @@ -155,172 +123,6 @@ class Mesh(_FortranObjectWithID): def id(self, mesh_id): _dll.openmc_mesh_set_id(self._index, mesh_id) - @property - def n_elements(self) -> int: - n = c_size_t() - _dll.openmc_mesh_get_n_elements(self._index, n) - return n.value - - @property - def volumes(self) -> np.ndarray: - volumes = np.empty((self.n_elements,)) - _dll.openmc_mesh_get_volumes( - self._index, volumes.ctypes.data_as(POINTER(c_double))) - return volumes - - @property - def bounding_box(self) -> BoundingBox: - inf = sys.float_info.max - ll = np.zeros(3) - ur = np.zeros(3) - _dll.openmc_mesh_bounding_box( - self._index, - ll.ctypes.data_as(POINTER(c_double)), - ur.ctypes.data_as(POINTER(c_double)) - ) - ll[ll == inf] = np.inf - ur[ur == inf] = np.inf - ll[ll == -inf] = -np.inf - ur[ur == -inf] = -np.inf - return BoundingBox(ll, ur) - - def material_volumes( - self, - n_samples: int | tuple[int, int, int] = 10_000, - max_materials: int = 4, - output: bool = True, - bounding_boxes: bool = False, - ) -> MeshMaterialVolumes: - """Determine volume of materials in each mesh element. - - This method works by raytracing repeatedly through the mesh to count the - estimated volume of each material in all mesh elements. Three sets of - rays are used: one set parallel to the x-axis, one parallel to the - y-axis, and one parallel to the z-axis. - - .. versionadded:: 0.15.0 - - .. versionchanged:: 0.15.1 - Material volumes are now determined by raytracing rather than by - point sampling. - - Parameters - ---------- - n_samples : int or 3-tuple of int - Total number of rays to sample. The number of rays in each direction - is determined by the aspect ratio of the mesh bounding box. When - specified as a 3-tuple, it is interpreted as the number of rays in - the x, y, and z dimensions. - max_materials : int, optional - Estimated maximum number of materials in any given mesh element. - output : bool, optional - Whether or not to show output. - bounding_boxes : bool, optional - Whether or not to compute an axis-aligned bounding box for each - (mesh element, material) combination. When enabled, the bounding - box encloses the ray-estimator prisms used for the volume - estimation. - - Returns - ------- - MeshMaterialVolumes - Dictionary-like object that maps material IDs to an array of volumes - equal in size to the number of mesh elements. - - """ - if isinstance(n_samples, int): - # Determine number of rays in each direction based on aspect ratios - # and using the relation (nx*ny + ny*nz + nx*nz) = n_samples - width_x, width_y, width_z = self.bounding_box.width - ax = width_x / width_z - ay = width_y / width_z - f = sqrt(n_samples/(ax*ay + ax + ay)) - nx = round(f * ax) - ny = round(f * ay) - nz = round(f) - else: - nx, ny, nz = n_samples - - # Value indicating an empty slot in the hash table (matches C++) - EMPTY_SLOT = -2 - - # Preallocate arrays for material indices and volumes - n = self.n_elements - slot_factor = 2 - table_size = slot_factor*max_materials - materials = np.full((n, table_size), EMPTY_SLOT, dtype=np.int32) - volumes = np.zeros((n, table_size), dtype=np.float64) - bboxes = None - if bounding_boxes: - bboxes = np.empty((n, table_size, 6), dtype=np.float64) - bboxes[..., 0:3] = np.inf - bboxes[..., 3:6] = -np.inf - - # Run material volume calculation - while True: - try: - bboxes_ptr = None - if bboxes is not None: - bboxes_ptr = bboxes.ctypes.data_as(POINTER(c_double)) - with quiet_dll(output): - _dll.openmc_mesh_material_volumes( - self._index, nx, ny, nz, table_size, materials, - volumes, bboxes_ptr) - except AllocationError: - # Increase size of result array and try again - table_size *= 2 - materials = np.full((n, table_size), EMPTY_SLOT, dtype=np.int32) - volumes = np.zeros((n, table_size), dtype=np.float64) - if bounding_boxes: - bboxes = np.empty((n, table_size, 6), dtype=np.float64) - bboxes[..., 0:3] = np.inf - bboxes[..., 3:6] = -np.inf - else: - # If no error, break out of loop - break - - return MeshMaterialVolumes(materials, volumes, bboxes) - - def get_plot_bins( - self, - origin: Sequence[float], - width: Sequence[float], - basis: str, - pixels: Sequence[int] - ) -> np.ndarray: - """Get mesh bin indices for a rasterized plot. - - .. versionadded:: 0.15.0 - - Parameters - ---------- - origin : iterable of float - Origin of the plotting view. Should have length 3. - width : iterable of float - Width of the plotting view. Should have length 2. - basis : {'xy', 'xz', 'yz'} - Plotting basis. - pixels : iterable of int - Number of pixels in each direction. Should have length 2. - - Returns - ------- - 2D numpy array with mesh bin indices corresponding to each pixel within - the plotting view. - - """ - origin = _Position(*origin) - width = _Position(*width) - basis = {'xy': 1, 'xz': 2, 'yz': 3}[basis] - pixel_array = (c_int*2)(*pixels) - img_data = np.zeros((pixels[1], pixels[0]), dtype=np.dtype('int32')) - - _dll.openmc_mesh_get_plot_bins( - self._index, origin, width, basis, pixel_array, - img_data.ctypes.data_as(POINTER(c_int32)) - ) - return img_data - class RegularMesh(Mesh): """RegularMesh stored internally. @@ -344,16 +146,10 @@ class RegularMesh(Mesh): The lower-left corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. upper_right : numpy.ndarray - The upper-right corner of the structured mesh. If only two coordinate + The upper-right corner of the structrued mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. width : numpy.ndarray The width of mesh cells in each direction. - n_elements : int - Total number of mesh elements. - volumes : numpy.ndarray - Volume of each mesh element in [cm^3] - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh """ mesh_type = 'regular' @@ -433,15 +229,9 @@ class RectilinearMesh(Mesh): lower_left : numpy.ndarray The lower-left corner of the structured mesh. upper_right : numpy.ndarray - The upper-right corner of the structured mesh. + The upper-right corner of the structrued mesh. width : numpy.ndarray The width of mesh cells in each direction. - n_elements : int - Total number of mesh elements. - volumes : numpy.ndarray - Volume of each mesh element in [cm^3] - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh """ mesh_type = 'rectilinear' @@ -538,15 +328,9 @@ class CylindricalMesh(Mesh): lower_left : numpy.ndarray The lower-left corner of the structured mesh. upper_right : numpy.ndarray - The upper-right corner of the structured mesh. + The upper-right corner of the structrued mesh. width : numpy.ndarray The width of mesh cells in each direction. - n_elements : int - Total number of mesh elements. - volumes : numpy.ndarray - Volume of each mesh element in [cm^3] - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh """ mesh_type = 'cylindrical' @@ -621,7 +405,6 @@ class CylindricalMesh(Mesh): _dll.openmc_cylindrical_mesh_set_grid(self._index, r_grid, nr, phi_grid, nphi, z_grid, nz) - class SphericalMesh(Mesh): """SphericalMesh stored internally. @@ -643,15 +426,9 @@ class SphericalMesh(Mesh): lower_left : numpy.ndarray The lower-left corner of the structured mesh. upper_right : numpy.ndarray - The upper-right corner of the structured mesh. + The upper-right corner of the structrued mesh. width : numpy.ndarray The width of mesh cells in each direction. - n_elements : int - Total number of mesh elements. - volumes : numpy.ndarray - Volume of each mesh element in [cm^3] - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh """ mesh_type = 'spherical' @@ -727,16 +504,11 @@ class SphericalMesh(Mesh): ntheta, phi_grid, nphi) -class UnstructuredMesh(Mesh): - pass - - _MESH_TYPE_MAP = { 'regular': RegularMesh, 'rectilinear': RectilinearMesh, 'cylindrical': CylindricalMesh, - 'spherical': SphericalMesh, - 'unstructured': UnstructuredMesh + 'spherical': SphericalMesh } @@ -757,6 +529,7 @@ class _MeshMapping(Mapping): raise KeyError(str(e)) return _get_mesh(index.value) + def __iter__(self): for i in range(len(self)): yield _get_mesh(i).id diff --git a/openmc/lib/nuclide.py b/openmc/lib/nuclide.py index ef1287cf3..399bb3465 100644 --- a/openmc/lib/nuclide.py +++ b/openmc/lib/nuclide.py @@ -40,14 +40,8 @@ def load_nuclide(name): name : str Name of the nuclide, e.g. 'U235' - Returns - ------- - Nuclide - The class:`Nuclide` that was just loaded. - """ _dll.openmc_load_nuclide(name.encode(), None, 0) - return nuclides[name] class Nuclide(_FortranObject): @@ -97,7 +91,7 @@ class Nuclide(_FortranObject): energy : iterable of float Energy group boundaries in [eV] flux : iterable of float - Flux in each energy group (not normalized per eV) + Flux in each energt group (not normalized per eV) Returns ------- diff --git a/openmc/lib/plot.py b/openmc/lib/plot.py index 196682394..da42ea49e 100644 --- a/openmc/lib/plot.py +++ b/openmc/lib/plot.py @@ -1,15 +1,10 @@ -from collections.abc import Mapping from ctypes import (c_bool, c_int, c_size_t, c_int32, - c_double, c_uint8, Structure, POINTER) -from weakref import WeakValueDictionary + c_double, Structure, POINTER) -from ..exceptions import AllocationError, InvalidIDError from . import _dll -from .core import _FortranObjectWithID from .error import _error_handler import numpy as np -import warnings class _Position(Structure): @@ -36,7 +31,7 @@ class _Position(Structure): elif idx == 2: return self.z else: - raise IndexError(f"{idx} index is invalid for _Position") + raise IndexError("{} index is invalid for _Position".format(idx)) def __setitem__(self, idx, val): if idx == 0: @@ -46,643 +41,225 @@ class _Position(Structure): elif idx == 2: self.z = val else: - raise IndexError(f"{idx} index is invalid for _Position") + raise IndexError("{} index is invalid for _Position".format(idx)) def __repr__(self): - return f"({self.x}, {self.y}, {self.z})" - - -def _extract_slice_data_args(plot): - """Convert a legacy plot-like object into slice_data keyword arguments.""" - try: - kwargs = { - 'origin': tuple(plot.origin), - 'width': (plot.width, plot.height), - 'basis': plot.basis, - 'pixels': (plot.h_res, plot.v_res), - 'show_overlaps': getattr(plot, 'color_overlaps', False), - 'level': getattr(plot, 'level', -1), - } - except AttributeError as exc: - raise TypeError( - "plot must be a legacy plot-like object with origin, width, " - "height, basis, h_res, and v_res attributes." - ) from exc - return kwargs - - -_dll.openmc_slice_data.argtypes = [ - POINTER(c_double * 3), # origin - POINTER(c_double * 3), # u_span - POINTER(c_double * 3), # v_span - POINTER(c_size_t * 2), # pixels - c_bool, # show_overlaps - c_int, # level - c_int32, # filter_index - POINTER(c_int32), # geom_data - POINTER(c_double), # property_data (can be None) -] -_dll.openmc_slice_data.restype = c_int -_dll.openmc_slice_data.errcheck = _error_handler - - -def slice_data(origin, width=None, basis='xy', u_span=None, v_span=None, - pixels=None, show_overlaps=False, level=None, filter=None, - include_properties=True): - """Generate a 2D raster of geometry and property data for plotting. - - Parameters - ---------- - origin : sequence of float - Center position of the plot [x, y, z] - width : sequence of float - Width of the plot [horizontal, vertical]. Mutually exclusive with - u_span/v_span. - basis : {'xy', 'xz', 'yz'} or int - Plot basis. Ignored if u_span/v_span are provided. - u_span : sequence of float, optional - Full-width span vector for the horizontal axis (3 values). Mutually - exclusive with width. - v_span : sequence of float, optional - Full-height span vector for the vertical axis (3 values). Mutually - exclusive with width. - pixels : sequence of int - Number of pixels [horizontal, vertical] - show_overlaps : bool, optional - Whether to detect overlapping cells - level : int, optional - Universe level (None for deepest) - filter : openmc.lib.Filter, optional - Filter for bin index lookup - include_properties : bool, optional - Whether to compute temperature/density - - Returns - ------- - geom_data : numpy.ndarray - Array of shape (v_res, h_res, 3) or (v_res, h_res, 4) with int32 dtype. - Contains [cell_id, cell_instance, material_id] when no filter is provided, - or [cell_id, cell_instance, material_id, filter_bin] when a filter is provided. - property_data : numpy.ndarray or None - Array of shape (v_res, h_res, 2) with float64 dtype containing - [temperature, density], or None if include_properties=False - """ - # Set deepest level as default - if level is None: - level = -1 - if not isinstance(level, int): - raise TypeError("level must be an integer.") - - if pixels is None: - raise ValueError("pixels must be specified.") - if len(pixels) != 2: - raise ValueError("pixels must be a length-2 sequence.") - - if width is not None and (u_span is not None or v_span is not None): - raise ValueError("width is mutually exclusive with u_span/v_span.") - - if u_span is not None or v_span is not None: - if u_span is None or v_span is None: - raise ValueError("Both u_span and v_span must be provided.") - u_span = np.asarray(u_span, dtype=float) - v_span = np.asarray(v_span, dtype=float) - if u_span.shape != (3,) or v_span.shape != (3,): - raise ValueError("u_span and v_span must be length-3 sequences.") - u_norm = np.linalg.norm(u_span) - v_norm = np.linalg.norm(v_span) - if u_norm == 0.0 or v_norm == 0.0: - raise ValueError("u_span and v_span must be non-zero vectors.") - dot = float(np.dot(u_span, v_span)) - ortho_tol = 1.0e-10 * u_norm * v_norm - if abs(dot) > ortho_tol: - raise ValueError("u_span and v_span must be orthogonal.") - else: - if width is None: - raise ValueError("width must be provided when u_span/v_span are not set.") - if len(width) != 2: - raise ValueError("width must be a length-2 sequence.") - basis_map = {'xy': 1, 'xz': 2, 'yz': 3} - if isinstance(basis, str): - basis = basis.lower() - if basis not in basis_map: - raise ValueError(f"{basis} is not a valid plot basis.") - basis = basis_map[basis] - elif isinstance(basis, int): - if basis not in basis_map.values(): - raise ValueError(f"{basis} is not a valid plot basis.") - else: - raise ValueError(f"{basis} is not a valid plot basis.") - - if basis == 1: - u_span = np.array([width[0], 0.0, 0.0], dtype=float) - v_span = np.array([0.0, width[1], 0.0], dtype=float) - elif basis == 2: - u_span = np.array([width[0], 0.0, 0.0], dtype=float) - v_span = np.array([0.0, 0.0, width[1]], dtype=float) - else: - u_span = np.array([0.0, width[0], 0.0], dtype=float) - v_span = np.array([0.0, 0.0, width[1]], dtype=float) - - origin = np.asarray(origin, dtype=float) - if origin.shape != (3,): - raise ValueError("origin must be a length-3 sequence.") - - # Prepare ctypes arrays - origin_arr = (c_double * 3)(*origin) - u_span_arr = (c_double * 3)(*u_span) - v_span_arr = (c_double * 3)(*v_span) - pixels_arr = (c_size_t * 2)(*pixels) - - # Get internal filter index from filter ID if filter is provided - if filter is not None: - filter_index = c_int32() - _dll.openmc_get_filter_index(filter.id, filter_index) - filter_index = filter_index.value - else: - filter_index = -1 - - # Allocate output arrays with dynamic size based on filter - n_geom_fields = 4 if filter is not None else 3 - geom_data = np.zeros((pixels[1], pixels[0], n_geom_fields), dtype=np.int32) - if include_properties: - property_data = np.zeros((pixels[1], pixels[0], 2), dtype=np.float64) - prop_ptr = property_data.ctypes.data_as(POINTER(c_double)) - else: - property_data = None - prop_ptr = None - - _dll.openmc_slice_data( - origin_arr, - u_span_arr, - v_span_arr, - pixels_arr, - show_overlaps, - level, - filter_index, - geom_data.ctypes.data_as(POINTER(c_int32)), - prop_ptr - ) - - return geom_data, property_data - - -def id_map(plot): - """Deprecated compatibility wrapper for geometry ID maps. - - This function is kept for compatibility and will be removed in a future - release. Use `slice_data(..., include_properties=False)` instead. - """ - warnings.warn( - "openmc.lib.id_map is deprecated and will be removed in a future " - "release; use openmc.lib.slice_data(..., include_properties=False).", - FutureWarning, - ) - - kwargs = _extract_slice_data_args(plot) - geom_data, _ = slice_data(include_properties=False, **kwargs) - return geom_data[:, :, :3] - - -def property_map(plot): - """Deprecated compatibility wrapper for temperature/density maps. - - This function is kept for compatibility and will be removed in a future - release. Use `slice_data(..., include_properties=True)` instead. - """ - warnings.warn( - "openmc.lib.property_map is deprecated and will be removed in a " - "future release; use openmc.lib.slice_data(..., " - "include_properties=True).", - FutureWarning, - ) - - kwargs = _extract_slice_data_args(plot) - _, prop_data = slice_data(include_properties=True, **kwargs) - return prop_data - - -_dll.openmc_slice_data_overlap_count.argtypes = [POINTER(c_size_t)] -_dll.openmc_slice_data_overlap_count.restype = c_int -_dll.openmc_slice_data_overlap_count.errcheck = _error_handler - -_dll.openmc_slice_data_overlap_info.argtypes = [c_size_t, POINTER(c_int32)] -_dll.openmc_slice_data_overlap_info.restype = c_int -_dll.openmc_slice_data_overlap_info.errcheck = _error_handler - - -# Python wrappings for overlap functions -def slice_data_overlap_count() -> int: - """Return the number of unique overlaps from the last slice plot. - - Returns - ------- - int - Number of unique overlapping cell pairs detected by the most recent - :func:`slice_data` call with overlap checking enabled. - """ - count = c_size_t() - _dll.openmc_slice_data_overlap_count(count) - return count.value - - -def slice_data_overlap_info() -> np.ndarray: - """Return identifying information for overlaps from the last slice plot. - - Returns - ------- - numpy.ndarray - Array of shape ``(n, 3)`` with int32 dtype, where ``n`` is the number - of unique overlaps detected by the most recent :func:`slice_data` call - with overlap checking enabled. Each row contains ``[universe_id, - cell1_id, cell2_id]``. - """ - n = slice_data_overlap_count() - overlap_info = np.empty((n, 3), dtype=np.int32) - - if n > 0: - _dll.openmc_slice_data_overlap_info( - n, - overlap_info.ctypes.data_as(POINTER(c_int32)), - ) - return overlap_info - - -_dll.openmc_get_plot_index.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_get_plot_index.restype = c_int -_dll.openmc_get_plot_index.errcheck = _error_handler - -_dll.openmc_plot_get_id.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_plot_get_id.restype = c_int -_dll.openmc_plot_get_id.errcheck = _error_handler - -_dll.openmc_plot_set_id.argtypes = [c_int32, c_int32] -_dll.openmc_plot_set_id.restype = c_int -_dll.openmc_plot_set_id.errcheck = _error_handler - -_dll.openmc_plots_size.restype = c_size_t - -_dll.openmc_solidraytrace_plot_create.argtypes = [POINTER(c_int32)] -_dll.openmc_solidraytrace_plot_create.restype = c_int -_dll.openmc_solidraytrace_plot_create.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_pixels.argtypes = [ - c_int32, POINTER(c_int32), POINTER(c_int32)] -_dll.openmc_solidraytrace_plot_get_pixels.restype = c_int -_dll.openmc_solidraytrace_plot_get_pixels.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_pixels.argtypes = [c_int32, c_int32, c_int32] -_dll.openmc_solidraytrace_plot_set_pixels.restype = c_int -_dll.openmc_solidraytrace_plot_set_pixels.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_color_by.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_solidraytrace_plot_get_color_by.restype = c_int -_dll.openmc_solidraytrace_plot_get_color_by.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_color_by.argtypes = [c_int32, c_int32] -_dll.openmc_solidraytrace_plot_set_color_by.restype = c_int -_dll.openmc_solidraytrace_plot_set_color_by.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_default_colors.argtypes = [c_int32] -_dll.openmc_solidraytrace_plot_set_default_colors.restype = c_int -_dll.openmc_solidraytrace_plot_set_default_colors.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_all_opaque.argtypes = [c_int32] -_dll.openmc_solidraytrace_plot_set_all_opaque.restype = c_int -_dll.openmc_solidraytrace_plot_set_all_opaque.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_opaque.argtypes = [c_int32, c_int32, c_bool] -_dll.openmc_solidraytrace_plot_set_opaque.restype = c_int -_dll.openmc_solidraytrace_plot_set_opaque.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_color.argtypes = [c_int32, c_int32, c_uint8, c_uint8, c_uint8] -_dll.openmc_solidraytrace_plot_set_color.restype = c_int -_dll.openmc_solidraytrace_plot_set_color.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_camera_position.argtypes = [ - c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)] -_dll.openmc_solidraytrace_plot_get_camera_position.restype = c_int -_dll.openmc_solidraytrace_plot_get_camera_position.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_camera_position.argtypes = [c_int32, c_double, c_double, c_double] -_dll.openmc_solidraytrace_plot_set_camera_position.restype = c_int -_dll.openmc_solidraytrace_plot_set_camera_position.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_look_at.argtypes = [ - c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)] -_dll.openmc_solidraytrace_plot_get_look_at.restype = c_int -_dll.openmc_solidraytrace_plot_get_look_at.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_look_at.argtypes = [c_int32, c_double, c_double, c_double] -_dll.openmc_solidraytrace_plot_set_look_at.restype = c_int -_dll.openmc_solidraytrace_plot_set_look_at.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_up.argtypes = [ - c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)] -_dll.openmc_solidraytrace_plot_get_up.restype = c_int -_dll.openmc_solidraytrace_plot_get_up.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_up.argtypes = [c_int32, c_double, c_double, c_double] -_dll.openmc_solidraytrace_plot_set_up.restype = c_int -_dll.openmc_solidraytrace_plot_set_up.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_light_position.argtypes = [ - c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)] -_dll.openmc_solidraytrace_plot_get_light_position.restype = c_int -_dll.openmc_solidraytrace_plot_get_light_position.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_light_position.argtypes = [c_int32, c_double, c_double, c_double] -_dll.openmc_solidraytrace_plot_set_light_position.restype = c_int -_dll.openmc_solidraytrace_plot_set_light_position.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_fov.argtypes = [c_int32, POINTER(c_double)] -_dll.openmc_solidraytrace_plot_get_fov.restype = c_int -_dll.openmc_solidraytrace_plot_get_fov.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_fov.argtypes = [c_int32, c_double] -_dll.openmc_solidraytrace_plot_set_fov.restype = c_int -_dll.openmc_solidraytrace_plot_set_fov.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_update_view.argtypes = [c_int32] -_dll.openmc_solidraytrace_plot_update_view.restype = c_int -_dll.openmc_solidraytrace_plot_update_view.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_create_image.argtypes = [c_int32, POINTER(c_uint8), c_int32, c_int32] -_dll.openmc_solidraytrace_plot_create_image.restype = c_int -_dll.openmc_solidraytrace_plot_create_image.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_color.argtypes = [c_int32, c_int32, - POINTER(c_uint8), POINTER(c_uint8), POINTER(c_uint8)] -_dll.openmc_solidraytrace_plot_get_color.restype = c_int -_dll.openmc_solidraytrace_plot_get_color.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_get_diffuse_fraction.argtypes = [ - c_int32, POINTER(c_double)] -_dll.openmc_solidraytrace_plot_get_diffuse_fraction.restype = c_int -_dll.openmc_solidraytrace_plot_get_diffuse_fraction.errcheck = _error_handler - -_dll.openmc_solidraytrace_plot_set_diffuse_fraction.argtypes = [c_int32, c_double] -_dll.openmc_solidraytrace_plot_set_diffuse_fraction.restype = c_int -_dll.openmc_solidraytrace_plot_set_diffuse_fraction.errcheck = _error_handler - - -class SolidRayTracePlot(_FortranObjectWithID): - """Solid ray-traced plot stored internally. - - This class exposes a solid ray-traced plot that is stored internally in - the OpenMC library. To obtain a view of an existing plot with a given ID, - use the :data:`openmc.lib.plots` mapping. - - Parameters - ---------- - uid : int or None - Unique ID of the plot - new : bool - When `index` is None, this argument controls whether a new object is - created or a view of an existing object is returned. - index : int or None - Index in the internal plots array. + return "({}, {}, {})".format(self.x, self.y, self.z) + + +class _PlotBase(Structure): + """A structure defining a 2-D geometry slice with underlying c-types + + C-Type Attributes + ----------------- + origin : openmc.lib.plot._Position + A position defining the origin of the plot. + width_ : openmc.lib.plot._Position + The width of the plot along the x, y, and z axes, respectively + basis_ : c_int + The axes basis of the plot view. + pixels_ : c_size_t[3] + The resolution of the plot in the horizontal and vertical dimensions + level_ : c_int + The universe level for the plot view Attributes ---------- - id : int - Unique ID of the plot. - pixels : tuple of int - Plot image dimensions as ``(width, height)``. - color_by : int - Coloring mode. Use :attr:`COLOR_BY_MATERIAL` or - :attr:`COLOR_BY_CELL`. - camera_position : tuple of float - Camera position as ``(x, y, z)``. - look_at : tuple of float - Point the camera is aimed at as ``(x, y, z)``. - up : tuple of float - Up direction as ``(x, y, z)``. - light_position : tuple of float - Position of the light source as ``(x, y, z)``. - fov : float - Horizontal field-of-view angle in degrees. - diffuse_fraction : float - Fraction of reflected light treated as diffuse (0 to 1). + origin : tuple or list of ndarray + Origin (center) of the plot + width : float + The horizontal dimension of the plot in geometry units (cm) + height : float + The vertical dimension of the plot in geometry units (cm) + basis : string + One of {'xy', 'xz', 'yz'} indicating the horizontal and vertical + axes of the plot. + h_res : int + The horizontal resolution of the plot in pixels + v_res : int + The vertical resolution of the plot in pixels + level : int + The universe level for the plot (default: -1 -> all universes shown) """ + _fields_ = [('origin_', _Position), + ('width_', _Position), + ('basis_', c_int), + ('pixels_', 3*c_size_t), + ('color_overlaps_', c_bool), + ('level_', c_int)] - COLOR_BY_MATERIAL = 0 - COLOR_BY_CELL = 1 - __instances = WeakValueDictionary() - - def __new__(cls, uid=None, new=True, index=None): - mapping = plots - if index is None: - if new: - if uid is not None and uid in mapping: - raise AllocationError( - f'A plot with ID={uid} has already been allocated.' - ) - index = c_int32() - _dll.openmc_solidraytrace_plot_create(index) - index = index.value - else: - index = mapping[uid]._index - - if index not in cls.__instances: - instance = super().__new__(cls) - instance._index = index - if uid is not None: - instance.id = uid - cls.__instances[index] = instance - - return cls.__instances[index] - - def __init__(self, uid=None, new=True, index=None): - super().__init__(uid, new, index) + def __init__(self): + self.level_ = -1 + self.color_overlaps_ = False @property - def id(self): - plot_id = c_int32() - _dll.openmc_plot_get_id(self._index, plot_id) - return plot_id.value - - @id.setter - def id(self, plot_id): - _dll.openmc_plot_set_id(self._index, plot_id) - - @staticmethod - def _get_xyz(getter, index): - x = c_double() - y = c_double() - z = c_double() - getter(index, x, y, z) - return (x.value, y.value, z.value) - - @staticmethod - def _set_xyz(setter, index, xyz): - x, y, z = xyz - setter(index, float(x), float(y), float(z)) + def origin(self): + return self.origin_ @property - def pixels(self): - width = c_int32() - height = c_int32() - _dll.openmc_solidraytrace_plot_get_pixels(self._index, width, height) - return (width.value, height.value) - - @pixels.setter - def pixels(self, pixels): - width, height = pixels - _dll.openmc_solidraytrace_plot_set_pixels( - self._index, int(width), int(height)) + def width(self): + return self.width_.x @property - def color_by(self): - color_by = c_int32() - _dll.openmc_solidraytrace_plot_get_color_by(self._index, color_by) - return color_by.value - - @color_by.setter - def color_by(self, color_by): - _dll.openmc_solidraytrace_plot_set_color_by(self._index, int(color_by)) - - def set_default_colors(self): - _dll.openmc_solidraytrace_plot_set_default_colors(self._index) - - def set_all_opaque(self): - _dll.openmc_solidraytrace_plot_set_all_opaque(self._index) - - def set_visibility(self, domain_id, visible): - _dll.openmc_solidraytrace_plot_set_opaque( - self._index, int(domain_id), bool(visible) - ) - - def set_color(self, domain_id, color): - r, g, b = [int(c) for c in color] - _dll.openmc_solidraytrace_plot_set_color( - self._index, int(domain_id), r, g, b) + def height(self): + return self.width_.y @property - def camera_position(self): - return self._get_xyz(_dll.openmc_solidraytrace_plot_get_camera_position, - self._index) + def basis(self): + if self.basis_ == 1: + return 'xy' + elif self.basis_ == 2: + return 'xz' + elif self.basis_ == 3: + return 'yz' - @camera_position.setter - def camera_position(self, position): - self._set_xyz(_dll.openmc_solidraytrace_plot_set_camera_position, - self._index, position) + raise ValueError("Plot basis {} is invalid".format(self.basis_)) + + @basis.setter + def basis(self, basis): + if isinstance(basis, str): + valid_bases = ('xy', 'xz', 'yz') + basis = basis.lower() + if basis not in valid_bases: + raise ValueError("{} is not a valid plot basis.".format(basis)) + + if basis == 'xy': + self.basis_ = 1 + elif basis == 'xz': + self.basis_ = 2 + elif basis == 'yz': + self.basis_ = 3 + return + + if isinstance(basis, int): + valid_bases = (1, 2, 3) + if basis not in valid_bases: + raise ValueError("{} is not a valid plot basis.".format(basis)) + self.basis_ = basis + return + + raise ValueError("{} of type {} is an" + " invalid plot basis".format(basis, type(basis))) @property - def look_at(self): - return self._get_xyz(_dll.openmc_solidraytrace_plot_get_look_at, - self._index) - - @look_at.setter - def look_at(self, position): - self._set_xyz(_dll.openmc_solidraytrace_plot_set_look_at, - self._index, position) + def h_res(self): + return self.pixels_[0] @property - def up(self): - return self._get_xyz(_dll.openmc_solidraytrace_plot_get_up, self._index) - - @up.setter - def up(self, direction): - self._set_xyz(_dll.openmc_solidraytrace_plot_set_up, self._index, - direction) + def v_res(self): + return self.pixels_[1] @property - def light_position(self): - return self._get_xyz(_dll.openmc_solidraytrace_plot_get_light_position, - self._index) - - @light_position.setter - def light_position(self, position): - self._set_xyz(_dll.openmc_solidraytrace_plot_set_light_position, - self._index, position) + def level(self): + return int(self.level_) @property - def fov(self): - fov = c_double() - _dll.openmc_solidraytrace_plot_get_fov(self._index, fov) - return fov.value + def color_overlaps(self): + return self.color_overlaps_ - @fov.setter - def fov(self, fov): - _dll.openmc_solidraytrace_plot_set_fov(self._index, float(fov)) + @color_overlaps.setter + def color_overlaps(self, color_overlaps): + self.color_overlaps_ = color_overlaps - def update_view(self): - _dll.openmc_solidraytrace_plot_update_view(self._index) + @origin.setter + def origin(self, origin): + self.origin_.x = origin[0] + self.origin_.y = origin[1] + self.origin_.z = origin[2] - def create_image(self): - width, height = self.pixels - image = np.zeros((height, width, 3), dtype=np.uint8) - _dll.openmc_solidraytrace_plot_create_image( - self._index, - image.ctypes.data_as(POINTER(c_uint8)), - width, - height - ) - return image + @width.setter + def width(self, width): + self.width_.x = width - def get_color(self, domain_id): - r = c_uint8() - g = c_uint8() - b = c_uint8() - _dll.openmc_solidraytrace_plot_get_color( - self._index, int(domain_id), r, g, b) - return int(r.value), int(g.value), int(b.value) + @height.setter + def height(self, height): + self.width_.y = height + + @h_res.setter + def h_res(self, h_res): + self.pixels_[0] = h_res + + @v_res.setter + def v_res(self, v_res): + self.pixels_[1] = v_res + + @level.setter + def level(self, level): + self.level_ = level @property - def diffuse_fraction(self): - value = c_double() - _dll.openmc_solidraytrace_plot_get_diffuse_fraction(self._index, value) - return value.value + def color_overlaps(self): + return self.color_overlaps_ - @diffuse_fraction.setter - def diffuse_fraction(self, value): - _dll.openmc_solidraytrace_plot_set_diffuse_fraction( - self._index, float(value)) - - # Backward-compatible setter aliases - def set_pixels(self, width, height): - self.pixels = (width, height) - - def set_color_by(self, color_by): - self.color_by = color_by - - def set_camera_position(self, x, y, z): - self.camera_position = (x, y, z) - - def set_look_at(self, x, y, z): - self.look_at = (x, y, z) - - def set_up(self, x, y, z): - self.up = (x, y, z) - - def set_light_position(self, x, y, z): - self.light_position = (x, y, z) - - def set_fov(self, fov): - self.fov = fov - - def set_diffuse_fraction(self, value): - self.diffuse_fraction = value - - -class _PlotMapping(Mapping): - def __getitem__(self, key): - index = c_int32() - try: - _dll.openmc_get_plot_index(key, index) - except (AllocationError, InvalidIDError) as e: - raise KeyError(str(e)) - return SolidRayTracePlot(index=index.value) - - def __iter__(self): - for i in range(len(self)): - yield SolidRayTracePlot(index=i).id - - def __len__(self): - return _dll.openmc_plots_size() + @color_overlaps.setter + def color_overlaps(self, val): + self.color_overlaps_ = val def __repr__(self): - return repr(dict(self)) + out_str = ["-----", + "Plot:", + "-----", + "Origin: {}".format(self.origin), + "Width: {}".format(self.width), + "Height: {}".format(self.height), + "Basis: {}".format(self.basis), + "HRes: {}".format(self.h_res), + "VRes: {}".format(self.v_res), + "Color Overlaps: {}".format(self.color_overlaps), + "Level: {}".format(self.level)] + return '\n'.join(out_str) -plots = _PlotMapping() +_dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_int32)] +_dll.openmc_id_map.restype = c_int +_dll.openmc_id_map.errcheck = _error_handler + + +def id_map(plot): + """ + Generate a 2-D map of cell and material IDs. Used for in-memory image + generation. + + Parameters + ---------- + plot : openmc.lib.plot._PlotBase + Object describing the slice of the model to be generated + + Returns + ------- + id_map : numpy.ndarray + A NumPy array with shape (vertical pixels, horizontal pixels, 3) of + OpenMC property ids with dtype int32 + + """ + img_data = np.zeros((plot.v_res, plot.h_res, 3), + dtype=np.dtype('int32')) + _dll.openmc_id_map(plot, img_data.ctypes.data_as(POINTER(c_int32))) + return img_data + + +_dll.openmc_property_map.argtypes = [POINTER(_PlotBase), POINTER(c_double)] +_dll.openmc_property_map.restype = c_int +_dll.openmc_property_map.errcheck = _error_handler + + +def property_map(plot): + """ + Generate a 2-D map of cell temperatures and material densities. Used for + in-memory image generation. + + Parameters + ---------- + plot : openmc.lib.plot._PlotBase + Object describing the slice of the model to be generated + + Returns + ------- + property_map : numpy.ndarray + A NumPy array with shape (vertical pixels, horizontal pixels, 2) of + OpenMC property ids with dtype float + + """ + prop_data = np.zeros((plot.v_res, plot.h_res, 2)) + _dll.openmc_property_map(plot, prop_data.ctypes.data_as(POINTER(c_double))) + return prop_data diff --git a/openmc/lib/settings.py b/openmc/lib/settings.py index 4fba8d48b..2e9dd18df 100644 --- a/openmc/lib/settings.py +++ b/openmc/lib/settings.py @@ -12,8 +12,6 @@ _RUN_MODES = {1: 'fixed source', _dll.openmc_set_seed.argtypes = [c_int64] _dll.openmc_get_seed.restype = c_int64 -_dll.openmc_set_stride.argtypes = [c_int64] -_dll.openmc_get_stride.restype = c_int64 _dll.openmc_get_n_batches.argtypes = [POINTER(c_int), c_bool] _dll.openmc_get_n_batches.restype = c_int _dll.openmc_get_n_batches.errcheck = _error_handler @@ -37,7 +35,6 @@ class _Settings: run_CE = _DLLGlobal(c_bool, 'run_CE') verbosity = _DLLGlobal(c_int, 'verbosity') event_based = _DLLGlobal(c_bool, 'event_based') - weight_windows_on = _DLLGlobal(c_bool, 'weight_windows_on') @property def run_mode(self): @@ -55,11 +52,11 @@ class _Settings: current_idx.value = idx break else: - raise ValueError(f'Invalid run mode: {mode}') + raise ValueError('Invalid run mode: {}'.format(mode)) @property def path_statepoint(self): - path = c_char_p.in_dll(_dll, 'path_statepoint_c').value + path = c_char_p.in_dll(_dll, 'path_statepoint').value return path.decode() @property @@ -70,14 +67,6 @@ class _Settings: def seed(self, seed): _dll.openmc_set_seed(seed) - @property - def stride(self): - return _dll.openmc_get_stride() - - @stride.setter - def stride(self, stride): - _dll.openmc_set_stride(stride) - def set_batches(self, n_batches, set_max_batches=True, add_sp_batch=True): """Set number of batches or maximum number of batches diff --git a/openmc/lib/tally.py b/openmc/lib/tally.py index c17b16597..85af8ffff 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -39,9 +39,6 @@ _dll.openmc_tally_get_filters.argtypes = [ c_int32, POINTER(POINTER(c_int32)), POINTER(c_size_t)] _dll.openmc_tally_get_filters.restype = c_int _dll.openmc_tally_get_filters.errcheck = _error_handler -_dll.openmc_tally_get_multiply_density.argtypes = [c_int32, POINTER(c_bool)] -_dll.openmc_tally_get_multiply_density.restype = c_int -_dll.openmc_tally_get_multiply_density.errcheck = _error_handler _dll.openmc_tally_get_n_realizations.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_n_realizations.restype = c_int _dll.openmc_tally_get_n_realizations.errcheck = _error_handler @@ -78,9 +75,6 @@ _dll.openmc_tally_set_estimator.errcheck = _error_handler _dll.openmc_tally_set_id.argtypes = [c_int32, c_int32] _dll.openmc_tally_set_id.restype = c_int _dll.openmc_tally_set_id.errcheck = _error_handler -_dll.openmc_tally_set_multiply_density.argtypes = [c_int32, c_bool] -_dll.openmc_tally_set_multiply_density.restype = c_int -_dll.openmc_tally_set_multiply_density.errcheck = _error_handler _dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)] _dll.openmc_tally_set_nuclides.restype = c_int _dll.openmc_tally_set_nuclides.errcheck = _error_handler @@ -104,15 +98,13 @@ _SCORES = { -5: 'absorption', -6: 'fission', -7: 'nu-fission', -8: 'kappa-fission', -9: 'current', -10: 'events', -11: 'delayed-nu-fission', -12: 'prompt-nu-fission', -13: 'inverse-velocity', -14: 'fission-q-prompt', - -15: 'fission-q-recoverable', -16: 'decay-rate', -17: 'pulse-height', - -18: 'ifp-time-numerator', -19: 'ifp-beta-numerator', - -20: 'ifp-denominator', + -15: 'fission-q-recoverable', -16: 'decay-rate' } _ESTIMATORS = { 0: 'analog', 1: 'tracklength', 2: 'collision' } _TALLY_TYPES = { - 0: 'volume', 1: 'mesh-surface', 2: 'surface', 3: 'pulse-height' + 0: 'volume', 1: 'mesh-surface', 2: 'surface' } @@ -182,10 +174,6 @@ class Tally(_FortranObjectWithID): List of tally filters mean : numpy.ndarray An array containing the sample mean for each bin - multiply_density : bool - Whether reaction rates should be multiplied by atom density - - .. versionadded:: 0.14.0 nuclides : list of str List of nuclides to score results for num_realizations : int @@ -233,10 +221,6 @@ class Tally(_FortranObjectWithID): _dll.openmc_tally_get_active(self._index, active) return active.value - @active.setter - def active(self, active): - _dll.openmc_tally_set_active(self._index, active) - @property def type(self): type = c_int32() @@ -257,6 +241,10 @@ class Tally(_FortranObjectWithID): def estimator(self, estimator): _dll.openmc_tally_set_estimator(self._index, estimator.encode()) + @active.setter + def active(self, active): + _dll.openmc_tally_set_active(self._index, active) + @property def id(self): tally_id = c_int32() @@ -282,30 +270,6 @@ class Tally(_FortranObjectWithID): _dll.openmc_tally_set_filters(self._index, n, indices) - def find_filter(self, filter_type): - """ - Returns the first instance of a filter matching the specified type - - Parameters - ---------- - filter_type : subclass of openmc.lib.Filter - The filter type to match when retrieving a filter instance - - Returns - ------- - filter : openmc.lib.Filter - The filter instance matching the input filter type - - Raises - ------ - ValueError if a filter instance matching the input filter type cannot be found. - """ - for filter in self.filters: - if isinstance(filter, filter_type): - return filter - - raise ValueError(f'No filter of type {filter_type} on tally {self.id}') - @property def mean(self): n = self.num_realizations @@ -399,16 +363,6 @@ class Tally(_FortranObjectWithID): def writable(self, writable): _dll.openmc_tally_set_writable(self._index, writable) - @property - def multiply_density(self): - multiply_density = c_bool() - _dll.openmc_tally_get_multiply_density(self._index, multiply_density) - return multiply_density.value - - @multiply_density.setter - def multiply_density(self, multiply_density): - _dll.openmc_tally_set_multiply_density(self._index, multiply_density) - def reset(self): """Reset results and num_realizations of tally""" _dll.openmc_tally_reset(self._index) diff --git a/openmc/lib/weight_windows.py b/openmc/lib/weight_windows.py deleted file mode 100644 index 2b26d3b55..000000000 --- a/openmc/lib/weight_windows.py +++ /dev/null @@ -1,394 +0,0 @@ -from collections.abc import Mapping -from ctypes import c_double, c_int, c_int32, c_char_p, c_size_t, POINTER -from weakref import WeakValueDictionary - -import numpy as np -from numpy.ctypeslib import as_array - -from openmc import ParticleType -from openmc.exceptions import AllocationError, InvalidIDError -from . import _dll -from .core import _FortranObjectWithID -from .error import _error_handler -from .filter import EnergyFilter, MeshFilter, ParticleFilter -from .mesh import _get_mesh -from .mesh import meshes - - -__all__ = ['WeightWindows', 'weight_windows'] - -_dll.openmc_extend_weight_windows.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] - -_dll.openmc_weight_windows_update_magic.argtypes = 2*[c_int32] + [c_char_p] + 2*[c_double] -_dll.openmc_weight_windows_update_magic.restype = c_int -_dll.openmc_weight_windows_update_magic.errcheck = _error_handler - -_dll.openmc_weight_windows_size.restype = c_size_t - -_dll.openmc_get_weight_windows_index.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_get_weight_windows_index.restype = c_int -_dll.openmc_get_weight_windows_index.errcheck = _error_handler - -_dll.openmc_weight_windows_get_id.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_weight_windows_get_id.restype = c_int -_dll.openmc_weight_windows_get_id.errcheck = _error_handler - -_dll.openmc_weight_windows_set_id.argtypes = [c_int32, c_int32] -_dll.openmc_weight_windows_set_id.restype = c_int -_dll.openmc_weight_windows_set_id.errcheck = _error_handler - -_dll.openmc_weight_windows_set_mesh.argtypes = [c_int32, c_int32] -_dll.openmc_weight_windows_set_mesh.restype = c_int -_dll.openmc_weight_windows_set_mesh.errcheck = _error_handler - -_dll.openmc_weight_windows_get_mesh.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_weight_windows_get_mesh.restype = c_int -_dll.openmc_weight_windows_get_mesh.errcheck = _error_handler - -_dll.openmc_weight_windows_set_energy_bounds.argtypes = [c_int32, POINTER(c_double), c_size_t] -_dll.openmc_weight_windows_set_energy_bounds.restype = c_int -_dll.openmc_weight_windows_set_energy_bounds.errcheck = _error_handler - -_dll.openmc_weight_windows_get_energy_bounds.argtypes = [c_int32, POINTER(POINTER(c_double)), POINTER(c_size_t)] -_dll.openmc_weight_windows_get_energy_bounds.restype = c_int -_dll.openmc_weight_windows_get_energy_bounds.errcheck = _error_handler - -_dll.openmc_weight_windows_set_particle.argtypes = [c_int32, c_int32] -_dll.openmc_weight_windows_set_particle.restype = c_int -_dll.openmc_weight_windows_set_particle.errcheck = _error_handler - -_dll.openmc_weight_windows_get_particle.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_weight_windows_get_particle.restype = c_int -_dll.openmc_weight_windows_get_particle.errcheck = _error_handler - -_dll.openmc_weight_windows_set_bounds.argtypes = [c_int32, POINTER(c_double), POINTER(c_double), c_size_t] -_dll.openmc_weight_windows_set_bounds.restype = c_int -_dll.openmc_weight_windows_set_bounds.errcheck = _error_handler - -_dll.openmc_weight_windows_get_bounds.argtypes = [c_int32, POINTER(POINTER(c_double)), POINTER(POINTER(c_double)), POINTER(c_size_t)] -_dll.openmc_weight_windows_get_bounds.restype = c_int -_dll.openmc_weight_windows_get_bounds.errcheck = _error_handler - -_dll.openmc_weight_windows_get_survival_ratio.argtypes = [c_int32, POINTER(c_double)] -_dll.openmc_weight_windows_get_survival_ratio.restype = c_int -_dll.openmc_weight_windows_get_survival_ratio.errcheck = _error_handler - -_dll.openmc_weight_windows_set_survival_ratio.argtypes = [c_int32, c_double] -_dll.openmc_weight_windows_set_survival_ratio.restype = c_int -_dll.openmc_weight_windows_set_survival_ratio.errcheck = _error_handler - -_dll.openmc_weight_windows_get_max_lower_bound_ratio.argtypes = [c_int32, POINTER(c_double)] -_dll.openmc_weight_windows_get_max_lower_bound_ratio.restype = c_int -_dll.openmc_weight_windows_get_max_lower_bound_ratio.errcheck = _error_handler - -_dll.openmc_weight_windows_set_max_lower_bound_ratio.argtypes = [c_int32, c_double] -_dll.openmc_weight_windows_set_max_lower_bound_ratio.restype = c_int -_dll.openmc_weight_windows_set_max_lower_bound_ratio.errcheck = _error_handler - -_dll.openmc_weight_windows_get_weight_cutoff.argtypes = [c_int32, POINTER(c_double)] -_dll.openmc_weight_windows_get_weight_cutoff.restype = c_int -_dll.openmc_weight_windows_get_weight_cutoff.errcheck = _error_handler - -_dll.openmc_weight_windows_set_weight_cutoff.argtypes = [c_int32, c_double] -_dll.openmc_weight_windows_set_weight_cutoff.restype = c_int -_dll.openmc_weight_windows_set_weight_cutoff.errcheck = _error_handler - -_dll.openmc_weight_windows_get_max_split.argtypes = [c_int32, POINTER(c_int)] -_dll.openmc_weight_windows_get_max_split.restype = c_int -_dll.openmc_weight_windows_get_max_split.errcheck = _error_handler - -_dll.openmc_weight_windows_set_max_split.argtypes = [c_int32, c_int] -_dll.openmc_weight_windows_set_max_split.restype = c_int -_dll.openmc_weight_windows_set_max_split.errcheck = _error_handler - - -class WeightWindows(_FortranObjectWithID): - """WeightWindows stored internally. - - This class exposes a weight windows object that is stored internally in the - OpenMC library. To obtain a view of a weight windows object with a given ID, - use the :data:`openmc.lib.weight_windows` mapping. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - id : int or None - Unique ID of the weight windows - new : bool - When `index` is None, this argument controls whether a new object is - created or a view of an existing object is returned. - index : int or None - Index in the `weight_windows` array. - - Attributes - ---------- - id : int - ID of the weight windows object - mesh : openmc.lib.Mesh - Mesh used for the weight windows - particle : openmc.ParticleType - The particle type to which these weight windows apply - energy_bounds : numpy.ndarray - The energy bounds for the weight windows - bounds : numpy.ndarray - The weight window bounds - """ - __instances = WeakValueDictionary() - - def __new__(cls, id=None, new=True, index=None): - mapping = weight_windows - - if index is None: - if new: - # Determine ID to assign - if id is None: - id = max(mapping, default=0) + 1 - else: - if id in mapping: - raise AllocationError(f'A weight windows object with ID={id} ' - 'has already been allocated.') - - index = c_int32() - _dll.openmc_extend_weight_windows(1, index, None) - index = index.value - else: - index = mapping[id]._index - - if index not in cls.__instances: - instance = super().__new__(cls) - instance._index = index - if id is not None: - instance.id = id - cls.__instances[index] = instance - - return cls.__instances[index] - - @property - def id(self): - ww_id = c_int32() - _dll.openmc_weight_windows_get_id(self._index, ww_id) - return ww_id.value - - @id.setter - def id(self, ww_id): - _dll.openmc_weight_windows_set_id(self._index, ww_id) - - @property - def mesh(self): - mesh_idx = c_int32() - _dll.openmc_weight_windows_get_mesh(self._index, mesh_idx) - return _get_mesh(mesh_idx.value) - - @mesh.setter - def mesh(self, mesh): - _dll.openmc_weight_windows_set_mesh( - weight_windows[self.id]._index, meshes[mesh.id]._index) - - @property - def energy_bounds(self): - data = POINTER(c_double)() - n = c_size_t() - _dll.openmc_weight_windows_get_energy_bounds(self._index, data, n) - return as_array(data, (n.value,)) - - @energy_bounds.setter - def energy_bounds(self, e_bounds): - e_bounds_arr = np.asarray(e_bounds, dtype=float) - e_bounds_ptr = e_bounds_arr.ctypes.data_as(POINTER(c_double)) - _dll.openmc_weight_windows_set_energy_bounds( - self._index, e_bounds_ptr, e_bounds_arr.size) - - @property - def particle(self): - val = c_int32() - _dll.openmc_weight_windows_get_particle(self._index, val) - return ParticleType(val.value) - - @particle.setter - def particle(self, p): - p = ParticleType(p) - _dll.openmc_weight_windows_set_particle(self._index, int(p)) - - @property - def bounds(self): - upper = POINTER(c_double)() - lower = POINTER(c_double)() - size = c_size_t() - _dll.openmc_weight_windows_get_bounds(self._index, lower, upper, size) - lower_arr = as_array(lower, (size.value,)) - upper_arr = as_array(upper, (size.value,)) - return (lower_arr, upper_arr) - - @bounds.setter - def bounds(self, bounds): - lower = np.asarray(bounds[0]) - upper = np.asarray(bounds[1]) - - lower_p = lower.ctypes.data_as(POINTER(c_double)) - upper_p = upper.ctypes.data_as(POINTER(c_double)) - - _dll.openmc_weight_windows_set_bounds(self._index, lower_p, upper_p, lower.size) - - @property - def survival_ratio(self): - ratio = c_double() - _dll.openmc_weight_windows_get_survival_ratio(self._index, ratio) - return ratio.value - - @survival_ratio.setter - def survival_ratio(self, ratio): - _dll.openmc_weight_windows_set_survival_ratio(self._index, ratio) - - @property - def max_lower_bound_ratio(self): - lb_ratio = c_double() - _dll.openmc_weight_windows_get_max_lower_bound_ratio(self._index, lb_ratio) - return lb_ratio.value - - @max_lower_bound_ratio.setter - def max_lower_bound_ratio(self, lb_ratio): - _dll.openmc_weight_windows_set_max_lower_bound_ratio(self._index, lb_ratio) - - @property - def weight_cutoff(self): - cutoff = c_double() - _dll.openmc_weight_windows_get_weight_cutoff(self._index, cutoff) - return cutoff.value - - @weight_cutoff.setter - def weight_cutoff(self, cutoff): - _dll.openmc_weight_windows_set_weight_cutoff(self._index, cutoff) - - @property - def max_split(self): - max_split = c_int() - _dll.openmc_weight_windows_get_max_split(self._index, max_split) - return max_split.value - - @max_split.setter - def max_split(self, max_split): - _dll.openmc_weight_windows_set_max_split(self._index, max_split) - - def update_magic(self, tally, value='mean', threshold=1.0, ratio=5.0): - """Update weight window values using the MAGIC method - - Reference: https://inis.iaea.org/records/231pm-zzy35 - - Parameters - ---------- - tally : openmc.lib.Tally object - The tally used to update weight window information - value : str - Value type used to generate weight windows. One of {'mean', 'rel_err'}. - threshold : float - Threshold for relative error of results used to generate weight window bounds - ratio : float - Ratio of the lower to upper weight window bounds - - """ - _dll.openmc_weight_windows_update_magic(self._index, - tally._index, - c_char_p(value.encode()), - threshold, - ratio) - - @classmethod - def from_tally(cls, tally, particle=ParticleType.NEUTRON): - """Create an instance of the WeightWindows class based on the specified tally. - - Parameters - ---------- - tally : openmc.lib.Tally - The tally used to create the WeightWindows instance. - particle : openmc.ParticleType or str or int, optional - The particle type to use for the WeightWindows instance. Should be - specified as an instance of ParticleType, a PDG number, or as a - name. - - Returns - ------- - WeightWindows - The WeightWindows instance created from the specified tally. - - Raises - ------ - ValueError - If the particle parameter is not an instance of ParticleType, a string, - or an integer PDG number. - ValueError - If the particle parameter is not a valid particle type (i.e., not 'neutron' - or 'photon'). - ValueError - If the specified particle is not included in the bins of the ParticleFilter - of the tally. - ValueError - If the tally does not have a MeshFilter. - """ - # do some checks on particle value - if not isinstance(particle, (ParticleType, str, int)): - raise ValueError( - f"Parameter 'particle' must be {ParticleType} or one of ('neutron', 'photon')." - ) - - # convert particle type if needed - particle = ParticleType(particle) - - if particle not in (ParticleType.NEUTRON, ParticleType.PHOTON): - raise ValueError('Weight windows can only be applied for neutrons or photons') - - try: - particle_filter = tally.find_filter(ParticleFilter) - except ValueError: - particle_filter = None - - # ensure that the tally won't filter out the specified particle - if particle_filter is not None and particle not in particle_filter.bins: - raise ValueError(f'Specified tally for weight windows (Tally {tally.id})' - f' does not track the requested particle: "{particle}"') - - # tally must have a mesh filter - mesh_filter = tally.find_filter(MeshFilter) - - # create a new weight windows instance - out = cls() - - # set mesh and particle - out.mesh = mesh_filter.mesh - out.particle = particle - - # set energy bounds if needed - try: - energy_filter = tally.find_filter(EnergyFilter) - except ValueError: - energy_filter = None - - if energy_filter is not None: - out.energy_bounds = energy_filter.bins - - return out - - -class _WeightWindowsMapping(Mapping): - def __getitem__(self, key): - index = c_int32() - try: - _dll.openmc_get_weight_windows_index(key, index) - except (AllocationError, InvalidIDError) as e: - raise KeyError(str(e)) - return WeightWindows(index=index.value) - - def __iter__(self): - for i in range(len(self)): - yield WeightWindows(index=i).id - - def __len__(self): - return _dll.openmc_weight_windows_size() - - def __repr__(self): - return repr(dict(self)) - - def __delitem__(self): - raise NotImplementedError("WeightWindows object remove not implemented") - -weight_windows = _WeightWindowsMapping() diff --git a/openmc/material.py b/openmc/material.py index 3a92efda2..167eaba84 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1,45 +1,29 @@ -from __future__ import annotations -from collections import defaultdict, namedtuple, Counter +from collections import OrderedDict, defaultdict, namedtuple, Counter from collections.abc import Iterable from copy import deepcopy -from functools import reduce from numbers import Real from pathlib import Path +import os import re -import sys -import tempfile -from typing import TYPE_CHECKING, Literal, Sequence, Dict +import typing # imported separately as py3.8 requires typing.Iterable import warnings +from typing import Optional, Union +from xml.etree import ElementTree as ET -import lxml.etree as ET -import numpy as np import h5py +import numpy as np import openmc import openmc.data import openmc.checkvalue as cv -from ._xml import clean_indentation, get_elem_list, get_text +from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin -from .utility_funcs import input_path -from . import waste -from openmc.checkvalue import PathLike -from openmc.stats import Univariate, Discrete, Mixture, Tabular -from openmc.data.data import _get_element_symbol, JOULE_PER_EV -from openmc.data.function import Tabulated1D -from openmc.data import mass_energy_absorption_coefficient, dose_coefficients - -if TYPE_CHECKING: - from openmc.deplete import Chain # Units for density supported by OpenMC DENSITY_UNITS = ('g/cm3', 'g/cc', 'kg/m3', 'atom/b-cm', 'atom/cm3', 'sum', 'macro') -# Smallest normalized floating point number -_SMALLEST_NORMAL = sys.float_info.min - -_BECQUEREL_PER_CURIE = 3.7e10 NuclideTuple = namedtuple('NuclideTuple', ['name', 'percent', 'percent_type']) @@ -50,10 +34,10 @@ class Material(IDManagerMixin): To create a material, one should create an instance of this class, add nuclides or elements with :meth:`Material.add_nuclide` or :meth:`Material.add_element`, respectively, and set the total material - density with :meth:`Material.set_density()`. Alternatively, you can use - :meth:`Material.add_components()` to pass a dictionary containing all the - component information. The material can then be assigned to a cell using the - :attr:`Cell.fill` attribute. + density with :meth:`Material.set_density()`. Alternatively, you can + use :meth:`Material.add_components()` to pass a dictionary + containing all the component information. The material can then be + assigned to a cell using the :attr:`Cell.fill` attribute. Parameters ---------- @@ -66,26 +50,6 @@ class Material(IDManagerMixin): temperature : float, optional Temperature of the material in Kelvin. If not specified, the material inherits the default temperature applied to the model. - density : float, optional - Density of the material (units defined separately) - density_units : str - Units used for `density`. Can be one of 'g/cm3', 'g/cc', 'kg/m3', - 'atom/b-cm', 'atom/cm3', 'sum', or 'macro'. The 'macro' unit only - applies in the case of a multi-group calculation. Defaults to 'sum'. - depletable : bool, optional - Indicate whether the material is depletable. Defaults to False. - volume : float, optional - Volume of the material in cm^3. This can either be set manually or - calculated in a stochastic volume calculation and added via the - :meth:`Material.add_volume_information` method. - components : dict of str to float or dict - Dictionary mapping element or nuclide names to their atom or weight - percent. To specify enrichment of an element, the entry of - ``components`` for that element must instead be a dictionary containing - the keyword arguments as well as a value for ``'percent'`` - percent_type : {'ao', 'wo'} - Whether the values in `components` should be interpreted as atom percent - ('ao') or weight percent ('wo'). Attributes ---------- @@ -127,41 +91,24 @@ class Material(IDManagerMixin): fissionable_mass : float Mass of fissionable nuclides in the material in [g]. Requires that the :attr:`volume` attribute is set. - ncrystal_cfg : str - NCrystal configuration string - - .. versionadded:: 0.13.3 - """ next_id = 1 used_ids = set() - def __init__( - self, - material_id: int | None = None, - name: str = "", - temperature: float | None = None, - density: float | None = None, - density_units: str = "sum", - depletable: bool | None = False, - volume: float | None = None, - components: dict | None = None, - percent_type: str = "ao", - ): + def __init__(self, material_id=None, name='', temperature=None): # Initialize class attributes self.id = material_id self.name = name self.temperature = temperature self._density = None - self._density_units = density_units - self._depletable = depletable + self._density_units = 'sum' + self._depletable = False self._paths = None self._num_instances = None - self._volume = volume + self._volume = None self._atoms = {} self._isotropic = [] - self._ncrystal_cfg = None # A list of tuples (nuclide, percent, percent type) self._nuclides = [] @@ -173,16 +120,7 @@ class Material(IDManagerMixin): # If specified, a list of table names self._sab = [] - # Set density if provided - if density is not None: - self.set_density(density_units, density) - - # Add components if provided - if components is not None: - self.add_components(components, percent_type=percent_type) - - - def __repr__(self) -> str: + def __repr__(self): string = 'Material\n' string += '{: <16}=\t{}\n'.format('\tID', self._id) string += '{: <16}=\t{}\n'.format('\tName', self._name) @@ -191,14 +129,8 @@ class Material(IDManagerMixin): string += '{: <16}=\t{}'.format('\tDensity', self._density) string += f' [{self._density_units}]\n' - string += '{: <16}=\t{} [cm^3]\n'.format('\tVolume', self._volume) - string += '{: <16}=\t{}\n'.format('\tDepletable', self._depletable) - string += '{: <16}\n'.format('\tS(a,b) Tables') - if self._ncrystal_cfg: - string += '{: <16}=\t{}\n'.format('\tNCrystal conf', self._ncrystal_cfg) - for sab in self._sab: string += '{: <16}=\t{}\n'.format('\tS(a,b)', sab) @@ -206,7 +138,7 @@ class Material(IDManagerMixin): for nuclide, percent, percent_type in self._nuclides: string += '{: <16}'.format('\t{}'.format(nuclide)) - string += f'=\t{percent: <12} [{percent_type}]\n' + string += '=\t{: <12} [{}]\n'.format(percent, percent_type) if self._macroscopic is not None: string += '{: <16}\n'.format('\tMacroscopic Data') @@ -215,55 +147,34 @@ class Material(IDManagerMixin): return string @property - def name(self) -> str | None: + def name(self): return self._name - @name.setter - def name(self, name: str | None): - if name is not None: - cv.check_type(f'name for Material ID="{self._id}"', - name, str) - self._name = name - else: - self._name = '' - @property - def temperature(self) -> float | None: + def temperature(self): return self._temperature - @temperature.setter - def temperature(self, temperature: Real | None): - cv.check_type(f'Temperature for Material ID="{self._id}"', - temperature, (Real, type(None))) - self._temperature = temperature - @property - def density(self) -> float | None: + def density(self): return self._density @property - def density_units(self) -> str: + def density_units(self): return self._density_units @property - def depletable(self) -> bool: + def depletable(self): return self._depletable - @depletable.setter - def depletable(self, depletable: bool): - cv.check_type(f'Depletable flag for Material ID="{self._id}"', - depletable, bool) - self._depletable = depletable - @property - def paths(self) -> list[str]: + def paths(self): if self._paths is None: raise ValueError('Material instance paths have not been determined. ' 'Call the Geometry.determine_paths() method.') return self._paths @property - def num_instances(self) -> int: + def num_instances(self): if self._num_instances is None: raise ValueError( 'Number of material instances have not been determined. Call ' @@ -271,21 +182,15 @@ class Material(IDManagerMixin): return self._num_instances @property - def nuclides(self) -> list[namedtuple]: + def nuclides(self): return self._nuclides @property - def isotropic(self) -> list[str]: + def isotropic(self): return self._isotropic - @isotropic.setter - def isotropic(self, isotropic: Iterable[str]): - cv.check_iterable_type('Isotropic scattering nuclides', isotropic, - str) - self._isotropic = list(isotropic) - @property - def average_molar_mass(self) -> float: + def average_molar_mass(self): # Using the sum of specified atomic or weight amounts as a basis, sum # the mass and moles of the material mass = 0. @@ -299,26 +204,47 @@ class Material(IDManagerMixin): mass += nuc.percent # Compute and return the molar mass - if moles == 0.0: - raise ValueError("Material has no nuclides; cannot compute molar mass") return mass / moles @property - def volume(self) -> float | None: + def volume(self): return self._volume + @name.setter + def name(self, name: Optional[str]): + if name is not None: + cv.check_type(f'name for Material ID="{self._id}"', + name, str) + self._name = name + else: + self._name = '' + + @temperature.setter + def temperature(self, temperature: Optional[Real]): + cv.check_type(f'Temperature for Material ID="{self._id}"', + temperature, (Real, type(None))) + self._temperature = temperature + + @depletable.setter + def depletable(self, depletable: bool): + cv.check_type(f'Depletable flag for Material ID="{self._id}"', + depletable, bool) + self._depletable = depletable + @volume.setter def volume(self, volume: Real): if volume is not None: cv.check_type('material volume', volume, Real) self._volume = volume - @property - def ncrystal_cfg(self) -> str | None: - return self._ncrystal_cfg + @isotropic.setter + def isotropic(self, isotropic: typing.Iterable[str]): + cv.check_iterable_type('Isotropic scattering nuclides', isotropic, + str) + self._isotropic = list(isotropic) @property - def fissionable_mass(self) -> float: + def fissionable_mass(self): if self.volume is None: raise ValueError("Volume must be set in order to determine mass.") density = 0.0 @@ -329,282 +255,8 @@ class Material(IDManagerMixin): / openmc.data.AVOGADRO return density*self.volume - @property - def decay_photon_energy(self) -> Univariate | None: - warnings.warn( - "The 'decay_photon_energy' property has been replaced by the " - "get_decay_photon_energy() method and will be removed in a future " - "version.", FutureWarning) - return self.get_decay_photon_energy(0.0) - - def get_decay_photon_energy( - self, - clip_tolerance: float = 1e-6, - units: str = 'Bq', - volume: float | None = None, - exclude_nuclides: list[str] | None = None, - include_nuclides: list[str] | None = None - ) -> Univariate | None: - r"""Return energy distribution of decay photons from unstable nuclides. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - clip_tolerance : float - Maximum fraction of :math:`\sum_i x_i p_i` for discrete distributions - that will be discarded. - units : {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Bq/m3'} - Specifies the units on the integral of the distribution. - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - exclude_nuclides : list of str, optional - Nuclides to exclude from the photon source calculation. - include_nuclides : list of str, optional - Nuclides to include in the photon source calculation. If specified, - only these nuclides are used. - - Returns - ------- - Univariate or None - Decay photon energy distribution. The integral of this distribution is - the total intensity of the photon source in the requested units. - - """ - cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Bq/m3'}) - - if exclude_nuclides is not None and include_nuclides is not None: - raise ValueError("Cannot specify both exclude_nuclides and include_nuclides") - - if units == 'Bq': - multiplier = volume if volume is not None else self.volume - if multiplier is None: - raise ValueError("volume must be specified if units='Bq'") - elif units == 'Bq/cm3': - multiplier = 1 - elif units == 'Bq/m3': - multiplier = 1e6 - elif units == 'Bq/g': - multiplier = 1.0 / self.get_mass_density() - elif units == 'Bq/kg': - multiplier = 1000.0 / self.get_mass_density() - - dists = [] - probs = [] - for nuc, atoms_per_bcm in self.get_nuclide_atom_densities().items(): - if exclude_nuclides is not None and nuc in exclude_nuclides: - continue - if include_nuclides is not None and nuc not in include_nuclides: - continue - - source_per_atom = openmc.data.decay_photon_energy(nuc) - if source_per_atom is not None and atoms_per_bcm > 0.0: - dists.append(source_per_atom) - probs.append(1e24 * atoms_per_bcm * multiplier) - - # If no photon sources, exit early - if not dists: - return None - - # Get combined distribution, clip low-intensity values in discrete spectra - combined = openmc.data.combine_distributions(dists, probs) - if isinstance(combined, (Discrete, Mixture)): - combined.clip(clip_tolerance, inplace=True) - - # If clipping resulted in a single distribution within a mixture, pick - # out that single distribution - if isinstance(combined, Mixture) and len(combined.distribution) == 1: - combined = combined.distribution[0] - - return combined - - def get_photon_contact_dose_rate( - self, - dose_quantity: str = "absorbed-air", - build_up: float = 2.0, - by_nuclide: bool = False - ) -> float | dict[str, float]: - """Compute the photon contact dose rate (CDR) produced by radioactive decay - of the material. - - The contact dose rate is calculated from decay photon energy spectra for - each nuclide in the material, combined with photon mass attenuation data - for the material and the appropriate response function for the dose quantity. - A slab-geometry approximation and a photon build-up factor are used. - - Absorbed-air dose: - The approach follows the FISPACT-II manual (UKAEA-CCFE-RE(21)02 - May 2021). - Appendix C.7.1. - This method integrates over the photon energy: - - (B/2) * (mu_en_air(E) / mu_material(E)) * E * S(E) - - Effective dose: - The approach uses ICRP-116 effective dose coefficients to convert the photon - fluence due to decay photons to effective dose. - This method integrates over the photon energy: - - (B/2) * (h_e(E) / mu_material(E)) * S(E) - - where: - - mu_en_air(E) is the air mass energy-absorption coefficient, - - mu_material(E) is the photon mass attenuation coefficient of the material, - - S(E) is the photon emission spectrum per atom, - - h_e(E) is the ICRP-116 effective dose coefficient, - - B is the build-up factor, - - E is the photon energy. - - Parameters - ---------- - dose_quantity : {'absorbed-air', 'effective'}, optional - Specifies the dose quantity to be calculated. - The only supported options are 'absorbed-air' which implements the methodology - from FISPACT-II, and 'effective' which uses ICRP-116 effective dose coefficients. - build_up : float, optional. The default value is 2.0 as suggested in the FISPACT-II - manual. - by_nuclide : bool, optional - Specifies if the cdr should be returned for the material as a - whole or per nuclide. Default is False. - - Limitations - ---------- - This method does not implement correction from Bremsstrahlung particles which can be - relevant at close distances. - In addition, it computes the gamma contact dose rate only for the unstable nuclides - for which the radiation source specification is present in the chain file. - - Returns - ------- - cdr : float or dict[str, float] - Contact Dose Rate due to decay photons. - 'absorbed-air': returns the absorbed dose in air [Gy/hr]. - 'effective': returns the effective dose [Sv/hr]. - """ - - cv.check_type("by_nuclide", by_nuclide, bool) - cv.check_type("dose_quantity", dose_quantity, str) - cv.check_value("dose_quantity", dose_quantity, {'absorbed-air', 'effective'}) - cv.check_type("build_up", build_up, Real) - cv.check_greater_than("build_up", build_up, 0.0) - - nuc_densities = self.get_nuclide_atom_densities() - if not nuc_densities: - raise ValueError("Material has no nuclides; cannot compute mass attenuation") - - # Collect partial mass densities ρ_i [g/cm³] and elemental mass - # attenuation coefficients µ_i/ρ_i [cm²/g] per nuclide - nuc_attenuation = [] - for nuc, atom_density_bcm in nuc_densities.items(): - Z = openmc.data.zam(nuc)[0] - mu_over_rho = openmc.data.mass_attenuation_coefficient(Z) - rho_i = ( - atom_density_bcm * 1.0e24 - * openmc.data.atomic_mass(nuc) / openmc.data.AVOGADRO - ) - nuc_attenuation.append((rho_i, mu_over_rho)) - - # Build union energy grid across all nuclides - mu_e_vals = reduce(np.union1d, [t.x for _, t in nuc_attenuation]) - - # Build the material linear attenuation coefficient µ_material(E) [cm⁻¹] - # as the sum of ρ_i * (µ_i/ρ_i)(E) over all nuclides - mu_material_vals = np.zeros(len(mu_e_vals)) - for rho_i, mu_over_rho in nuc_attenuation: - mu_material_vals += rho_i * mu_over_rho(mu_e_vals) - mu_material = Tabulated1D( - mu_e_vals, mu_material_vals, breakpoints=[len(mu_e_vals)], interpolation=[5]) - - # CDR computation - cdr = {} - - geometry_factor_slab = 0.5 - - # ancillary conversion factors for clarity - seconds_per_hour = 3600.0 - grams_per_kg = 1000.0 - sv_per_psv = 1e-12 - - if dose_quantity == 'absorbed-air': - # mu_en/rho for air [cm²/g] as a function of energy [eV] - response_f = mass_energy_absorption_coefficient("air", data_source="nist126") - - # Factor to convert [eV cm²/(b g s)] to [Gy/h] - multiplier = (build_up * geometry_factor_slab * seconds_per_hour - * grams_per_kg * 1e24 * JOULE_PER_EV) - - elif dose_quantity == 'effective': - # effective dose as a function of photon fluence [pSv cm²] - response_f_x, response_f_y = dose_coefficients( - "photon", geometry='AP', data_source='icrp116') - response_f = Tabulated1D(response_f_x, response_f_y, breakpoints=[ - len(response_f_x)], interpolation=[5]) - - # Convert [pSv cm²/(b-s)] to [Sv/h] - multiplier = (build_up * geometry_factor_slab * seconds_per_hour - * sv_per_psv * 1e24) - - for nuc, nuc_atoms_per_bcm in self.get_nuclide_atom_densities().items(): - photon_source_per_atom = openmc.data.decay_photon_energy(nuc) - - # nuclides with no contribution - if photon_source_per_atom is None or nuc_atoms_per_bcm <= 0.0: - cdr[nuc] = 0.0 - continue - - if not isinstance(photon_source_per_atom, (Discrete, Tabular)): - raise ValueError( - f"Unknown decay photon energy data type for nuclide {nuc}" - f"value returned: {type(photon_source_per_atom)}" - ) - - e_vals = photon_source_per_atom.x - p_vals = photon_source_per_atom.p - - # Construct list of energies from (photon source, response function, - # mu_en_air) for clipping to common energy range - e_lists = [e_vals, response_f.x, mu_e_vals] - - # clip distributions for values outside the tabulated values - left_bound = max(a.min() for a in e_lists) - right_bound = min(a.max() for a in e_lists) - - mask = (e_vals >= left_bound) & (e_vals <= right_bound) - e_vals = e_vals[mask] - p_vals = p_vals[mask] - - if isinstance(photon_source_per_atom, Tabular): - # limit the computation to the tabulated mu_en_air range - e_union = reduce(np.union1d, e_lists) - e_union = e_union[(e_union >= left_bound) & (e_union <= right_bound)] - if len(e_union) < 2: - raise ValueError("Not enough overlapping energy points to compute CDR") - - # Histogram interpolation: each new point inherits the value of - # the nearest original point to its left - p_vals = p_vals[np.searchsorted(e_vals, e_union, side='right') - 1] - e_vals = e_union - - mu_vals = mu_material(e_vals) - if dose_quantity == 'absorbed-air': - # Compute (µ_en_air(E) / µ_material(E)) * E * S(E) - integrand = (response_f(e_vals) / mu_vals) * p_vals * e_vals - elif dose_quantity == 'effective': - # Compute (h_e(E) / µ_material(E)) * S(E) - integrand = (response_f(e_vals) / mu_vals) * p_vals - - if isinstance(photon_source_per_atom, Discrete): - cdr_nuc = np.sum(integrand) - elif isinstance(photon_source_per_atom, Tabular): - cdr_nuc = np.trapezoid(integrand, e_vals) - - # Compute air-absorbed dose [Gy/h] or effective dose [Sv/h] - cdr[nuc] = float(cdr_nuc * nuc_atoms_per_bcm * multiplier) - - return cdr if by_nuclide else sum(cdr.values()) - @classmethod - def from_hdf5(cls, group: h5py.Group) -> Material: + def from_hdf5(cls, group: h5py.Group): """Create material from HDF5 group Parameters @@ -658,70 +310,6 @@ class Material(IDManagerMixin): return material - @classmethod - def from_ncrystal(cls, cfg, **kwargs) -> Material: - """Create material from NCrystal configuration string. - - Density, temperature, and material composition, and (ultimately) thermal - neutron scattering will be automatically be provided by NCrystal based - on this string. The name and material_id parameters are simply passed on - to the Material constructor. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - cfg : str - NCrystal configuration string - **kwargs - Keyword arguments passed to :class:`openmc.Material` - - Returns - ------- - openmc.Material - Material instance - - """ - - try: - import NCrystal - except ModuleNotFoundError as e: - raise RuntimeError('The .from_ncrystal method requires' - ' NCrystal to be installed.') from e - nc_mat = NCrystal.createInfo(cfg) - - def openmc_natabund(Z): - #nc_mat.getFlattenedComposition might need natural abundancies. - #This call-back function is used so NCrystal can flatten composition - #using OpenMC's natural abundancies. In practice this function will - #only get invoked in the unlikely case where a material is specified - #by referring both to natural elements and specific isotopes of the - #same element. - elem_name = openmc.data.ATOMIC_SYMBOL[Z] - return [ - (int(iso_name[len(elem_name):]), abund) - for iso_name, abund in openmc.data.isotopes(elem_name) - ] - - flat_compos = nc_mat.getFlattenedComposition( - preferNaturalElements=True, naturalAbundProvider=openmc_natabund) - - # Create the Material - material = cls(temperature=nc_mat.getTemperature(), **kwargs) - - for Z, A_vals in flat_compos: - elemname = openmc.data.ATOMIC_SYMBOL[Z] - for A, frac in A_vals: - if A: - material.add_nuclide(f'{elemname}{A}', frac) - else: - material.add_element(elemname, frac) - - material.set_density('g/cm3', nc_mat.getDensity()) - material._ncrystal_cfg = NCrystal.normaliseCfg(cfg) - - return material - def add_volume_information(self, volume_calc): """Add volume information to a material. @@ -737,11 +325,12 @@ class Material(IDManagerMixin): self._atoms = volume_calc.atoms[self.id] else: raise ValueError('No volume information found for material ID={}.' - .format(self.id)) + .format(self.id)) else: - raise ValueError(f'No volume information found for material ID={self.id}.') + raise ValueError('No volume information found for material ID={}.' + .format(self.id)) - def set_density(self, units: str, density: float | None = None): + def set_density(self, units: str, density: Optional[float] = None): """Set the density of the material Parameters @@ -769,7 +358,7 @@ class Material(IDManagerMixin): '"sum" unit'.format(self.id) raise ValueError(msg) - cv.check_type(f'the density for Material ID="{self.id}"', + cv.check_type('the density for Material ID="{}"'.format(self.id), density, Real) self._density = density @@ -789,16 +378,12 @@ class Material(IDManagerMixin): cv.check_type('nuclide', nuclide, str) cv.check_type('percent', percent, Real) cv.check_value('percent type', percent_type, {'ao', 'wo'}) - cv.check_greater_than('percent', percent, 0, equality=True) if self._macroscopic is not None: msg = 'Unable to add a Nuclide to Material ID="{}" as a ' \ 'macroscopic data-set has already been added'.format(self._id) raise ValueError(msg) - if self._ncrystal_cfg is not None: - raise ValueError("Cannot add nuclides to NCrystal material") - # If nuclide name doesn't look valid, give a warning try: Z, _, _ = openmc.data.zam(nuclide) @@ -841,7 +426,7 @@ class Material(IDManagerMixin): for component, params in components.items(): cv.check_type('component', component, str) - if isinstance(params, Real): + if isinstance(params, float): params = {'percent': params} else: @@ -852,10 +437,11 @@ class Material(IDManagerMixin): params['percent_type'] = percent_type - # check if nuclide - if not component.isalpha(): + ## check if nuclide + if str.isdigit(component[-1]): self.add_nuclide(component, **params) - else: + else: # is element + kwargs = params self.add_element(component, **params) def remove_nuclide(self, nuclide: str): @@ -955,10 +541,9 @@ class Material(IDManagerMixin): self._macroscopic = None def add_element(self, element: str, percent: float, percent_type: str = 'ao', - enrichment: float | None = None, - enrichment_target: str | None = None, - enrichment_type: str | None = None, - cross_sections: str | None = None): + enrichment: Optional[float] = None, + enrichment_target: Optional[str] = None, + enrichment_type: Optional[str] = None): """Add a natural element to the material Parameters @@ -985,8 +570,6 @@ class Material(IDManagerMixin): Default is: 'ao' for two-isotope enrichment; 'wo' for U enrichment .. versionadded:: 0.12 - cross_sections : str, optional - Location of cross_sections.xml file. Notes ----- @@ -998,7 +581,6 @@ class Material(IDManagerMixin): cv.check_type('nuclide', element, str) cv.check_type('percent', percent, Real) - cv.check_greater_than('percent', percent, 0, equality=True) cv.check_value('percent type', percent_type, {'ao', 'wo'}) # Make sure element name is just that @@ -1006,26 +588,25 @@ class Material(IDManagerMixin): raise ValueError("Element name should be given by the " "element's symbol or name, e.g., 'Zr', 'zirconium'") - if self._ncrystal_cfg is not None: - raise ValueError("Cannot add elements to NCrystal material") - # Allow for element identifier to be given as a symbol or name if len(element) > 2: el = element.lower() element = openmc.data.ELEMENT_SYMBOL.get(el) if element is None: - msg = f'Element name "{el}" not recognised' + msg = 'Element name "{}" not recognised'.format(el) raise ValueError(msg) else: if element[0].islower(): - msg = f'Element name "{element}" should start with an uppercase letter' + msg = 'Element name "{}" should start with an uppercase ' \ + 'letter'.format(element) raise ValueError(msg) if len(element) == 2 and element[1].isupper(): - msg = f'Element name "{element}" should end with a lowercase letter' + msg = 'Element name "{}" should end with a lowercase ' \ + 'letter'.format(element) raise ValueError(msg) # skips the first entry of ATOMIC_SYMBOL which is n for neutron if element not in list(openmc.data.ATOMIC_SYMBOL.values())[1:]: - msg = f'Element name "{element}" not recognised' + msg = 'Element name "{}" not recognised'.format(element) raise ValueError(msg) if self._macroscopic is not None: @@ -1064,14 +645,13 @@ class Material(IDManagerMixin): percent_type, enrichment, enrichment_target, - enrichment_type, - cross_sections): + enrichment_type): self.add_nuclide(*nuclide) def add_elements_from_formula(self, formula: str, percent_type: str = 'ao', - enrichment: float | None = None, - enrichment_target: str | None = None, - enrichment_type: str | None = None): + enrichment: Optional[float] = None, + enrichment_target: Optional[str] = None, + enrichment_type: Optional[str] = None): """Add a elements from a chemical formula to the material. .. versionadded:: 0.12 @@ -1116,7 +696,8 @@ class Material(IDManagerMixin): for token in row: if token.isalpha(): if token == "n" or token not in openmc.data.ATOMIC_NUMBER: - msg = f'Formula entry {token} not an element symbol.' + msg = 'Formula entry {} not an element symbol.' \ + .format(token) raise ValueError(msg) elif token not in ['(', ')', ''] and not token.isdigit(): msg = 'Formula must be made from a sequence of ' \ @@ -1200,7 +781,7 @@ class Material(IDManagerMixin): def make_isotropic_in_lab(self): self.isotropic = [x.name for x in self._nuclides] - def get_elements(self) -> list[str]: + def get_elements(self): """Returns all elements in the material .. versionadded:: 0.12 @@ -1214,37 +795,18 @@ class Material(IDManagerMixin): return sorted({re.split(r'(\d+)', i)[0] for i in self.get_nuclides()}) - def get_nuclides(self, element: str | None = None) -> list[str]: - """Returns a list of all nuclides in the material, if the element - argument is specified then just nuclides of that element are returned. - - Parameters - ---------- - element : str - Specifies the element to match when searching through the nuclides - - .. versionadded:: 0.13.2 + def get_nuclides(self): + """Returns all nuclides in the material Returns ------- nuclides : list of str List of nuclide names + """ + return [x.name for x in self._nuclides] - matching_nuclides = [] - if element: - for nuclide in self._nuclides: - if re.split(r'(\d+)', nuclide.name)[0] == element: - if nuclide.name not in matching_nuclides: - matching_nuclides.append(nuclide.name) - else: - for nuclide in self._nuclides: - if nuclide.name not in matching_nuclides: - matching_nuclides.append(nuclide.name) - - return matching_nuclides - - def get_nuclide_densities(self) -> dict[str, tuple]: + def get_nuclide_densities(self): """Returns all nuclides in the material and their densities Returns @@ -1255,29 +817,22 @@ class Material(IDManagerMixin): """ - nuclides = {} + # keep ordered dictionary for testing purposes + nuclides = OrderedDict() for nuclide in self._nuclides: nuclides[nuclide.name] = nuclide return nuclides - def get_nuclide_atom_densities(self, nuclide: str | None = None) -> dict[str, float]: - """Returns one or all nuclides in the material and their atomic - densities in units of atom/b-cm + def get_nuclide_atom_densities(self): + """Returns all nuclides in the material and their atomic densities in + units of atom/b-cm .. versionchanged:: 0.13.1 The values in the dictionary were changed from a tuple containing the nuclide name and the density to just the density. - Parameters - ---------- - nuclides : str, optional - Nuclide for which atom density is desired. If not specified, the - atom density for each nuclide in the material is given. - - .. versionadded:: 0.13.2 - Returns ------- nuclides : dict @@ -1307,11 +862,12 @@ class Material(IDManagerMixin): nuc_densities = [] nuc_density_types = [] - for nuc in self.nuclides: - nucs.append(nuc.name) - nuc_densities.append(nuc.percent) - nuc_density_types.append(nuc.percent_type) + for nuclide in self.nuclides: + nucs.append(nuclide.name) + nuc_densities.append(nuclide.percent) + nuc_density_types.append(nuclide.percent_type) + nucs = np.array(nucs) nuc_densities = np.array(nuc_densities) nuc_density_types = np.array(nuc_density_types) @@ -1339,197 +895,58 @@ class Material(IDManagerMixin): nuc_densities = density * nuc_densities - nuclides = {} + nuclides = OrderedDict() for n, nuc in enumerate(nucs): - if nuclide is None or nuclide == nuc: - nuclides[nuc] = nuc_densities[n] + nuclides[nuc] = nuc_densities[n] return nuclides - def get_element_atom_densities(self, element: str | None = None) -> dict[str, float]: - """Returns one or all elements in the material and their atomic - densities in units of atom/b-cm - - .. versionadded:: 0.15.1 - - Parameters - ---------- - element : str, optional - Element for which atom density is desired. If not specified, the - atom density for each element in the material is given. - - Returns - ------- - elements : dict - Dictionary whose keys are element names and values are densities in - [atom/b-cm] - - """ - if element is not None: - element = _get_element_symbol(element) - - nuc_densities = self.get_nuclide_atom_densities() - - # Initialize an empty dictionary for summed values - densities = {} - - # Accumulate densities for each nuclide - for nuclide, density in nuc_densities.items(): - nuc_element = openmc.data.ATOMIC_SYMBOL[openmc.data.zam(nuclide)[0]] - if element is None or element == nuc_element: - if nuc_element not in densities: - densities[nuc_element] = 0.0 - densities[nuc_element] += float(density) - - # If specific element was requested, make sure it is present - if element is not None and element not in densities: - raise ValueError(f'Element {element} not found in material.') - - return densities - - - def get_activity( - self, - units: str = 'Bq/cm3', - by_nuclide: bool = False, - volume: float | None = None, - chain_file: Literal[False] | None | PathLike | Chain = None - ) -> dict[str, float] | float: - """Return the activity of the material or each nuclide within. + def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False): + """Returns the activity of the material or for each nuclide in the + material in units of [Bq], [Bq/g] or [Bq/cm3]. .. versionadded:: 0.13.1 Parameters ---------- - units : {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Bq/m3', 'Ci', 'Ci/m3'} + units : {'Bq', 'Bq/g', 'Bq/cm3'} Specifies the type of activity to return, options include total - activity [Bq,Ci], specific [Bq/g, Bq/kg] or volumetric activity - [Bq/cm3, Bq/m3, Ci/m3]. Default is volumetric activity [Bq/cm3]. + activity [Bq], specific [Bq/g] or volumetric activity [Bq/cm3]. + Default is volumetric activity [Bq/cm3]. by_nuclide : bool Specifies if the activity should be returned for the material as a whole or per nuclide. Default is False. - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - - .. versionadded:: 0.13.3 - chain_file : False, None, PathLike, or openmc.deplete.Chain, optional - Source of half-life values. If ``False``, only ENDF/B-VIII.0 data is - used. If ``None``, the chain specified by - ``openmc.config['chain_file']`` is used when available. If a path or - :class:`openmc.deplete.Chain` is given, that chain is used. For - ``None`` or an explicit chain, nuclides absent from the chain fall - back to ENDF/B-VIII.0 data. - - .. versionadded:: 0.15.4 Returns ------- Union[dict, float] - If by_nuclide is True then a dictionary whose keys are nuclide names - and values are activity is returned. Otherwise the activity of the - material is returned as a float. + If by_nuclide is True then a dictionary whose keys are nuclide + names and values are activity is returned. Otherwise the activity + of the material is returned as a float. """ - cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Bq/m3', 'Ci', 'Ci/m3'}) + cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/cm3'}) cv.check_type('by_nuclide', by_nuclide, bool) - if volume is None: - volume = self.volume - - if units in {'Bq', 'Ci'} and volume is None: - raise ValueError(f"Volume must be set in order to compute activity in '{units}'.") - if units == 'Bq': - multiplier = volume + multiplier = self.volume elif units == 'Bq/cm3': multiplier = 1 - elif units == 'Bq/m3': - multiplier = 1e6 elif units == 'Bq/g': multiplier = 1.0 / self.get_mass_density() - elif units == 'Bq/kg': - multiplier = 1000.0 / self.get_mass_density() - elif units == 'Ci': - multiplier = volume / _BECQUEREL_PER_CURIE - elif units == 'Ci/m3': - multiplier = 1e6 / _BECQUEREL_PER_CURIE activity = {} for nuclide, atoms_per_bcm in self.get_nuclide_atom_densities().items(): - inv_seconds = openmc.data.decay_constant( - nuclide, chain_file=chain_file) + inv_seconds = openmc.data.decay_constant(nuclide) activity[nuclide] = inv_seconds * 1e24 * atoms_per_bcm * multiplier return activity if by_nuclide else sum(activity.values()) - def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False, - volume: float | None = None) -> dict[str, float] | float: - """Return the decay heat of the material or each nuclide within. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - units : {'W', 'W/g', 'W/kg', 'W/cm3', 'W/m3'} - Specifies the units of decay heat to return. Options include total - heat [W], specific [W/g, W/kg] or volumetric heat [W/cm3, W/m3]. - Default is total heat [W]. - by_nuclide : bool - Specifies if the decay heat should be returned for the material as a - whole or per nuclide. Default is False. - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - - .. versionadded:: 0.13.3 - - Returns - ------- - Union[dict, float] - If `by_nuclide` is True then a dictionary whose keys are nuclide - names and values are decay heat is returned. Otherwise the decay heat - of the material is returned as a float. - """ - - cv.check_value('units', units, {'W', 'W/g', 'W/kg', 'W/cm3', 'W/m3'}) - cv.check_type('by_nuclide', by_nuclide, bool) - - if units == 'W': - multiplier = volume if volume is not None else self.volume - if multiplier is None: - raise ValueError("Volume must be set in order to compute total decay heat.") - elif units == 'W/cm3': - multiplier = 1 - elif units == 'W/m3': - multiplier = 1e6 - elif units == 'W/g': - multiplier = 1.0 / self.get_mass_density() - elif units == 'W/kg': - multiplier = 1000.0 / self.get_mass_density() - - decayheat = {} - for nuclide, atoms_per_bcm in self.get_nuclide_atom_densities().items(): - decay_erg = openmc.data.decay_energy(nuclide) - inv_seconds = openmc.data.decay_constant(nuclide) - decay_erg *= openmc.data.JOULE_PER_EV - decayheat[nuclide] = inv_seconds * decay_erg * 1e24 * atoms_per_bcm * multiplier - - return decayheat if by_nuclide else sum(decayheat.values()) - - def get_nuclide_atoms(self, volume: float | None = None) -> dict[str, float]: + def get_nuclide_atoms(self): """Return number of atoms of each nuclide in the material .. versionadded:: 0.13.1 - Parameters - ---------- - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - - .. versionadded:: 0.13.3 - Returns ------- dict @@ -1537,16 +954,14 @@ class Material(IDManagerMixin): atoms present in the material. """ - if volume is None: - volume = self.volume - if volume is None: + if self.volume is None: raise ValueError("Volume must be set in order to determine atoms.") atoms = {} for nuclide, atom_per_bcm in self.get_nuclide_atom_densities().items(): - atoms[nuclide] = 1.0e24 * atom_per_bcm * volume + atoms[nuclide] = 1.0e24 * atom_per_bcm * self.volume return atoms - def get_mass_density(self, nuclide: str | None = None) -> float: + def get_mass_density(self, nuclide: Optional[str] = None): """Return mass density of one or all nuclides Parameters @@ -1562,13 +977,14 @@ class Material(IDManagerMixin): """ mass_density = 0.0 - for nuc, atoms_per_bcm in self.get_nuclide_atom_densities(nuclide=nuclide).items(): - density_i = 1e24 * atoms_per_bcm * openmc.data.atomic_mass(nuc) \ - / openmc.data.AVOGADRO - mass_density += density_i + for nuc, atoms_per_bcm in self.get_nuclide_atom_densities().items(): + if nuclide is None or nuclide == nuc: + density_i = 1e24 * atoms_per_bcm * openmc.data.atomic_mass(nuc) \ + / openmc.data.AVOGADRO + mass_density += density_i return mass_density - def get_mass(self, nuclide: str | None = None, volume: float | None = None) -> float: + def get_mass(self, nuclide: Optional[str] = None): """Return mass of one or all nuclides. Note that this method requires that the :attr:`Material.volume` has @@ -1579,12 +995,6 @@ class Material(IDManagerMixin): nuclides : str, optional Nuclide for which mass is desired. If not specified, the density for the entire material is given. - volume : float, optional - Volume of the material. If not passed, defaults to using the - :attr:`Material.volume` attribute. - - .. versionadded:: 0.13.3 - Returns ------- @@ -1592,98 +1002,11 @@ class Material(IDManagerMixin): Mass of the nuclide/material in [g] """ - if volume is None: - volume = self.volume - if volume is None: + if self.volume is None: raise ValueError("Volume must be set in order to determine mass.") - return volume*self.get_mass_density(nuclide) + return self.volume*self.get_mass_density(nuclide) - def waste_classification(self, metal: bool = False) -> str: - """Classify the material for near-surface waste disposal. - - This method determines a waste classification for the material based on - the NRC regulations (10 CFR 61.55). Note that the NRC regulations do not - consider many long-lived radionuclides relevant to fusion systems; for - fusion applications, it is recommended to calculate a waste disposal - rating based on limits by Fetter et al. using the - :meth:`~openmc.Material.waste_disposal_rating` method. - - Parameters - ---------- - metal : bool, optional - Whether or not the material is in metal form. - - Returns - ------- - str - The waste disposal classification, which can be "Class A", "Class - B", "Class C", or "GTCC" (greater than class C). - - """ - return waste._waste_classification(self, metal=metal) - - def waste_disposal_rating( - self, - limits: str | dict[str, float] = 'Fetter', - metal: bool = False, - by_nuclide: bool = False, - ) -> float | dict[str, float]: - """Return the waste disposal rating for the material. - - This method returns a waste disposal rating for the material based on a - set of specific activity limits. The waste disposal rating is a single - number that represents the sum of the ratios of the specific activity - for each radionuclide in the material against a nuclide-specific limit. - A value less than 1.0 indicates that the material "meets" the limits - whereas a value greater than 1.0 exceeds the limits. - - Note that the limits for NRC do not consider many long-lived - radionuclides relevant to fusion systems. A paper by `Fetter et al. - `_ applies the NRC - methodology to calculate specific activity limits for an expanded set of - radionuclides. - - Parameters - ---------- - limits : str or dict, optional - The name of a predefined set of specific activity limits or a - dictionary that contains specific activity limits for radionuclides, - where keys are nuclide names and values are activities in units of - [Ci/m3]. The predefined options are: - - - 'Fetter': Uses limits from Fetter et al. (1990) - - 'NRC_long': Uses the 10 CFR 61.55 limits for long-lived - radionuclides - - 'NRC_short_A': Uses the 10 CFR 61.55 class A limits for - short-lived radionuclides - - 'NRC_short_B': Uses the 10 CFR 61.55 class B limits for - short-lived radionuclides - - 'NRC_short_C': Uses the 10 CFR 61.55 class C limits for - short-lived radionuclides - metal : bool, optional - Whether or not the material is in metal form (only applicable for - NRC based limits) - by_nuclide : bool, optional - Whether to return the waste disposal rating for each nuclide in the - material. If True, a dictionary is returned where the keys are the - nuclide names and the values are the waste disposal ratings for each - nuclide. If False, a single float value is returned that represents - the overall waste disposal rating for the material. - - Returns - ------- - float or dict - The waste disposal rating for the material or its constituent - nuclides. - - See also - -------- - Material.waste_classification() - - """ - return waste._waste_disposal_rating(self, limits, metal, by_nuclide) - - def clone(self, memo: dict | None = None) -> Material: + def clone(self, memo: Optional[dict] = None): """Create a copy of this material with a new unique ID. Parameters @@ -1722,54 +1045,35 @@ class Material(IDManagerMixin): return memo[self] - def _get_nuclide_xml(self, nuclide: NuclideTuple) -> ET.Element: + def _get_nuclide_xml(self, nuclide: str): xml_element = ET.Element("nuclide") xml_element.set("name", nuclide.name) - # Prevent subnormal numbers from being written to XML, which causes an - # exception on the C++ side when calling std::stod - val = nuclide.percent - if abs(val) < _SMALLEST_NORMAL: - val = 0.0 - if nuclide.percent_type == 'ao': - xml_element.set("ao", str(val)) + xml_element.set("ao", str(nuclide.percent)) else: - xml_element.set("wo", str(val)) + xml_element.set("wo", str(nuclide.percent)) return xml_element - def _get_macroscopic_xml(self, macroscopic: str) -> ET.Element: + def _get_macroscopic_xml(self, macroscopic: str): xml_element = ET.Element("macroscopic") xml_element.set("name", macroscopic) return xml_element - def _get_nuclides_xml( - self, nuclides: Iterable[NuclideTuple], - nuclides_to_ignore: Iterable[str] | None = None)-> list[ET.Element]: + def _get_nuclides_xml(self, nuclides: typing.Iterable[str]): xml_elements = [] - - # Remove any nuclides to ignore from the XML export - if nuclides_to_ignore: - nuclides = [nuclide for nuclide in nuclides if nuclide.name not in nuclides_to_ignore] - - xml_elements = [self._get_nuclide_xml(nuclide) for nuclide in nuclides] - + for nuclide in nuclides: + xml_elements.append(self._get_nuclide_xml(nuclide)) return xml_elements - def to_xml_element( - self, nuclides_to_ignore: Iterable[str] | None = None) -> ET.Element: + def to_xml_element(self): """Return XML representation of the material - Parameters - ---------- - nuclides_to_ignore : list of str - Nuclides to ignore when exporting to XML. - Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing material data """ @@ -1787,14 +1091,6 @@ class Material(IDManagerMixin): if self._volume: element.set("volume", str(self._volume)) - if self._ncrystal_cfg: - if self._sab: - raise ValueError("NCrystal materials are not compatible with S(a,b).") - if self._macroscopic is not None: - raise ValueError("NCrystal materials are not compatible with macroscopic cross sections.") - - element.set("cfg", str(self._ncrystal_cfg)) - # Create temperature XML subelement if self.temperature is not None: element.set("temperature", str(self.temperature)) @@ -1806,12 +1102,12 @@ class Material(IDManagerMixin): subelement.set("value", str(self._density)) subelement.set("units", self._density_units) else: - raise ValueError(f'Density has not been set for material {self.id}!') + raise ValueError('Density has not been set for material {}!' + .format(self.id)) if self._macroscopic is None: # Create nuclide XML subelements - subelements = self._get_nuclides_xml(self._nuclides, - nuclides_to_ignore=nuclides_to_ignore) + subelements = self._get_nuclides_xml(self._nuclides) for subelement in subelements: element.append(subelement) else: @@ -1833,8 +1129,8 @@ class Material(IDManagerMixin): return element @classmethod - def mix_materials(cls, materials, fracs: Iterable[float], - percent_type: str = 'ao', **kwargs) -> Material: + def mix_materials(cls, materials, fracs: typing.Iterable[float], + percent_type: str = 'ao', name: Optional[str] = None): """Mix materials together based on atom, weight, or volume fractions .. versionadded:: 0.12 @@ -1849,8 +1145,10 @@ class Material(IDManagerMixin): Type of percentage, must be one of 'ao', 'wo', or 'vo', to signify atom percent (molar percent), weight percent, or volume percent, optional. Defaults to 'ao' - **kwargs - Keyword arguments passed to :class:`openmc.Material` + name : str + The name for the new material, optional. Defaults to concatenated + names of input materials with percentages indicated inside + parentheses. Returns ------- @@ -1909,11 +1207,10 @@ class Material(IDManagerMixin): openmc.data.AVOGADRO # Create the new material with the desired name - if "name" not in kwargs: - kwargs["name"] = '-'.join([f'{m.name}({f})' for m, f in + if name is None: + name = '-'.join(['{}({})'.format(m.name, f) for m, f in zip(materials, fracs)]) - - new_mat = cls(**kwargs) + new_mat = openmc.Material(name=name) # Compute atom fractions of nuclides and add them to the new material tot_nuclides_per_cc = np.sum([dens for dens in nuclides_per_cc.values()]) @@ -1931,12 +1228,12 @@ class Material(IDManagerMixin): return new_mat @classmethod - def from_xml_element(cls, elem: ET.Element) -> Material: + def from_xml_element(cls, elem: ET.Element): """Generate material from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1945,156 +1242,54 @@ class Material(IDManagerMixin): Material generated from XML element """ - mat_id = int(get_text(elem, 'id')) - - # Add NCrystal material from cfg string - cfg = get_text(elem, "cfg") - if cfg is not None: - return Material.from_ncrystal(cfg, material_id=mat_id) - + mat_id = int(elem.get('id')) mat = cls(mat_id) - mat.name = get_text(elem, 'name') + mat.name = elem.get('name') - temperature = get_text(elem, "temperature") - if temperature is not None: - mat.temperature = float(temperature) + if "temperature" in elem.attrib: + mat.temperature = float(elem.get("temperature")) - volume = get_text(elem, "volume") - if volume is not None: - mat.volume = float(volume) + if 'volume' in elem.attrib: + mat.volume = float(elem.get('volume')) + mat.depletable = bool(elem.get('depletable')) # Get each nuclide for nuclide in elem.findall('nuclide'): - name = get_text(nuclide, "name") + name = nuclide.attrib['name'] if 'ao' in nuclide.attrib: mat.add_nuclide(name, float(nuclide.attrib['ao'])) elif 'wo' in nuclide.attrib: mat.add_nuclide(name, float(nuclide.attrib['wo']), 'wo') - # Get depletable attribute - depletable = get_text(elem, "depletable") - mat.depletable = depletable in ('true', '1') - # Get each S(a,b) table for sab in elem.findall('sab'): - fraction = float(get_text(sab, "fraction", 1.0)) - name = get_text(sab, "name") - mat.add_s_alpha_beta(name, fraction) + fraction = float(sab.get('fraction', 1.0)) + mat.add_s_alpha_beta(sab.get('name'), fraction) # Get total material density density = elem.find('density') - units = get_text(density, "units") + units = density.get('units') if units == 'sum': mat.set_density(units) else: - value = float(get_text(density, 'value')) + value = float(density.get('value')) mat.set_density(units, value) # Check for isotropic scattering nuclides - isotropic = get_elem_list(elem, "isotropic", str) + isotropic = elem.find('isotropic') if isotropic is not None: - mat.isotropic = isotropic + mat.isotropic = isotropic.text.split() return mat - def deplete( - self, - multigroup_flux: Sequence[float], - energy_group_structure: Sequence[float] | str, - timesteps: Sequence[float] | Sequence[tuple[float, str]], - source_rates: float | Sequence[float], - timestep_units: str = 's', - chain_file: cv.PathLike | "openmc.deplete.Chain" | None = None, - reactions: Sequence[str] | None = None, - ) -> list[openmc.Material]: - """Depletes that material, evolving the nuclide densities - - .. versionadded:: 0.15.3 - - Parameters - ---------- - multigroup_flux: Sequence[float] - Energy-dependent multigroup flux values, where each sublist corresponds - to a specific material. Will be normalized so that it sums to 1. - energy_group_structure : Sequence[float] | str - Energy group boundaries in [eV] or the name of the group structure. - timesteps : iterable of float or iterable of tuple - Array of timesteps. Note that values are not cumulative. The units are - specified by the `timestep_units` argument when `timesteps` is an - iterable of float. Alternatively, units can be specified for each step - by passing an iterable of (value, unit) tuples. - source_rates : float or iterable of float, optional - Source rate in [neutron/sec] or neutron flux in [neutron/s-cm^2] for - each interval in :attr:`timesteps` - timestep_units : {'s', 'min', 'h', 'd', 'a', 'MWd/kg'} - Units for values specified in the `timesteps` argument. 's' means - seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years - and 'MWd/kg' indicates that the values are given in burnup (MW-d of - energy deposited per kilogram of initial heavy metal). - chain_file : PathLike or Chain - Path to the depletion chain XML file or instance of openmc.deplete.Chain. - Defaults to ``openmc.config['chain_file']``. - reactions : list of str, optional - Reactions to get cross sections for. If not specified, all neutron - reactions listed in the depletion chain file are used. - - Returns - ------- - list of openmc.Material, one for each timestep - - """ - - materials = openmc.Materials([self]) - - depleted_materials_dict = materials.deplete( - multigroup_fluxes=[multigroup_flux], - energy_group_structures=[energy_group_structure], - timesteps=timesteps, - source_rates=source_rates, - timestep_units=timestep_units, - chain_file=chain_file, - reactions=reactions, - ) - - return depleted_materials_dict[self.id] - - - def mean_free_path(self, energy: float) -> float: - """Calculate the mean free path of neutrons in the material at a given - energy. - - .. versionadded:: 0.15.3 - - Parameters - ---------- - energy : float - Neutron energy in eV - - Returns - ------- - float - Mean free path in cm - - """ - from openmc.plotter import _calculate_cexs_elem_mat - - energy_grid, cexs = _calculate_cexs_elem_mat( - this=self, - types=["total"], - ) - total_cexs = cexs[0] - - interpolated_cexs = float(np.interp(energy, energy_grid, total_cexs)) - - return 1.0 / interpolated_cexs - class Materials(cv.CheckedList): """Collection of Materials used for an OpenMC simulation. This class corresponds directly to the materials.xml input file. It can be - thought of as a normal Python list where each member is a :class:`Material`. - It behaves like a list as the following example demonstrates: + thought of as a normal Python list where each member is a + :class:`Material`. It behaves like a list as the following example + demonstrates: >>> fuel = openmc.Material() >>> clad = openmc.Material() @@ -2114,9 +1309,9 @@ class Materials(cv.CheckedList): Indicates the path to an XML cross section listing file (usually named cross_sections.xml). If it is not set, the :envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for - continuous-energy calculations and :envvar:`OPENMC_MG_CROSS_SECTIONS` - will be used for multi-group calculations to find the path to the HDF5 - cross section file. + continuous-energy calculations and + :envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group + calculations to find the path to the HDF5 cross section file. """ @@ -2128,13 +1323,13 @@ class Materials(cv.CheckedList): self += materials @property - def cross_sections(self) -> Path | None: + def cross_sections(self): return self._cross_sections @cross_sections.setter def cross_sections(self, cross_sections): if cross_sections is not None: - self._cross_sections = input_path(cross_sections) + self._cross_sections = Path(cross_sections) def append(self, material): """Append material to collection @@ -2164,67 +1359,13 @@ class Materials(cv.CheckedList): for material in self: material.make_isotropic_in_lab() - def _write_xml(self, file, header=True, level=0, spaces_per_level=2, - trailing_indent=True, nuclides_to_ignore=None): - """Writes XML content of the materials to an open file handle. - - Parameters - ---------- - file : IOTextWrapper - Open file handle to write content into. - header : bool - Whether or not to write the XML header - level : int - Indentation level of materials element - spaces_per_level : int - Number of spaces per indentation - trailing_indentation : bool - Whether or not to write a trailing indentation for the materials element - nuclides_to_ignore : list of str - Nuclides to ignore when exporting to XML. - - """ - indentation = level*spaces_per_level*' ' - # Write the header and the opening tag for the root element. - if header: - file.write("\n") - file.write(indentation+'\n') - - # Write the element. - if self.cross_sections is not None: - element = ET.Element('cross_sections') - element.text = str(self.cross_sections) - clean_indentation(element, level=level+1) - element.tail = element.tail.strip(' ') - file.write((level+1)*spaces_per_level*' ') - file.write(ET.tostring(element, encoding="unicode")) - - # Write the elements. - for material in sorted(set(self), key=lambda x: x.id): - element = material.to_xml_element(nuclides_to_ignore=nuclides_to_ignore) - clean_indentation(element, level=level+1) - element.tail = element.tail.strip(' ') - file.write((level+1)*spaces_per_level*' ') - file.write(ET.tostring(element, encoding="unicode")) - - # Write the closing tag for the root element. - file.write(indentation+'\n') - - # Write a trailing indentation for the next element - # at this level if needed - if trailing_indent: - file.write(indentation) - - def export_to_xml(self, path: PathLike = 'materials.xml', - nuclides_to_ignore: Iterable[str] | None = None): + def export_to_xml(self, path: Union[str, os.PathLike] = 'materials.xml'): """Export material collection to an XML file. Parameters ---------- path : str Path to file to write. Defaults to 'materials.xml'. - nuclides_to_ignore : list of str - Nuclides to ignore when exporting to XML. """ # Check if path is a directory @@ -2237,37 +1378,35 @@ class Materials(cv.CheckedList): # one go. with open(str(p), 'w', encoding='utf-8', errors='xmlcharrefreplace') as fh: - self._write_xml(fh, nuclides_to_ignore=nuclides_to_ignore) + + # Write the header and the opening tag for the root element. + fh.write("\n") + fh.write('\n') + + # Write the element. + if self.cross_sections is not None: + element = ET.Element('cross_sections') + element.text = str(self.cross_sections) + clean_indentation(element, level=1) + element.tail = element.tail.strip(' ') + fh.write(' ') + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + ET.ElementTree(element).write(fh, encoding='unicode') + + # Write the elements. + for material in sorted(self, key=lambda x: x.id): + element = material.to_xml_element() + clean_indentation(element, level=1) + element.tail = element.tail.strip(' ') + fh.write(' ') + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + ET.ElementTree(element).write(fh, encoding='unicode') + + # Write the closing tag for the root element. + fh.write('\n') @classmethod - def from_xml_element(cls, elem) -> Materials: - """Generate materials collection from XML file - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.Materials - Materials collection - - """ - # Generate each material - materials = cls() - for material in elem.findall('material'): - materials.append(Material.from_xml_element(material)) - - # Check for cross sections settings - xs = get_text(elem, "cross_sections") - if xs is not None: - materials.cross_sections = xs - - return materials - - @classmethod - def from_xml(cls, path: PathLike = 'materials.xml') -> Materials: + def from_xml(cls, path: Union[str, os.PathLike] = 'materials.xml'): """Generate materials collection from XML file Parameters @@ -2281,128 +1420,17 @@ class Materials(cv.CheckedList): Materials collection """ - parser = ET.XMLParser(huge_tree=True) - tree = ET.parse(path, parser=parser) + tree = ET.parse(path) root = tree.getroot() - return cls.from_xml_element(root) + # Generate each material + materials = cls() + for material in root.findall('material'): + materials.append(Material.from_xml_element(material)) + # Check for cross sections settings + xs = tree.find('cross_sections') + if xs is not None: + materials.cross_sections = xs.text - def deplete( - self, - multigroup_fluxes: Sequence[Sequence[float]], - energy_group_structures: Sequence[Sequence[float] | str], - timesteps: Sequence[float] | Sequence[tuple[float, str]], - source_rates: float | Sequence[float], - timestep_units: str = 's', - chain_file: cv.PathLike | "openmc.deplete.Chain" | None = None, - reactions: Sequence[str] | None = None, - ) -> Dict[int, list[openmc.Material]]: - """Depletes that material, evolving the nuclide densities - - .. versionadded:: 0.15.3 - - Parameters - ---------- - multigroup_fluxes: Sequence[Sequence[float]] - Energy-dependent multigroup flux values, where each sublist corresponds - to a specific material. Will be normalized so that it sums to 1. - energy_group_structures: Sequence[Sequence[float] | str] - Energy group boundaries in [eV] or the name of the group structure. - timesteps : iterable of float or iterable of tuple - Array of timesteps. Note that values are not cumulative. The units are - specified by the `timestep_units` argument when `timesteps` is an - iterable of float. Alternatively, units can be specified for each step - by passing an iterable of (value, unit) tuples. - source_rates : float or iterable of float, optional - Source rate in [neutron/sec] or neutron flux in [neutron/s-cm^2] for - each interval in :attr:`timesteps` - timestep_units : {'s', 'min', 'h', 'd', 'a', 'MWd/kg'} - Units for values specified in the `timesteps` argument. 's' means - seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years - and 'MWd/kg' indicates that the values are given in burnup (MW-d of - energy deposited per kilogram of initial heavy metal). - chain_file : PathLike or Chain - Path to the depletion chain XML file or instance of openmc.deplete.Chain. - Defaults to ``openmc.config['chain_file']``. - reactions : list of str, optional - Reactions to get cross sections for. If not specified, all neutron - reactions listed in the depletion chain file are used. - - Returns - ------- - list of openmc.Material, one for each timestep - - """ - - import openmc.deplete - from .deplete.chain import _get_chain - - # setting all materials to be depletable - for mat in self: - mat.depletable = True - - if len(multigroup_fluxes) != len(self): - raise ValueError("multigroup_fluxes length must match number of materials") - if len(energy_group_structures) != len(self): - raise ValueError("energy_group_structures length must match number of materials") - - chain = _get_chain(chain_file) - - # Create MicroXS objects for all materials - micros = [] - fluxes = [] - - with openmc.lib.TemporarySession(): - for material, flux, energy in zip( - self, multigroup_fluxes, energy_group_structures - ): - if material.volume is None: - raise ValueError( - f"Material {material.id} has no volume; cannot deplete" - ) - temperature = material.temperature or 293.6 - micro_xs = openmc.deplete.MicroXS.from_multigroup_flux( - energies=energy, - multigroup_flux=flux, - chain_file=chain, - temperature=temperature, - reactions=reactions, - ) - micros.append(micro_xs) - fluxes.append(material.volume) - - # Create a single operator for all materials - operator = openmc.deplete.IndependentOperator( - materials=self, - fluxes=fluxes, - micros=micros, - normalization_mode="source-rate", - chain_file=chain, - ) - - integrator = openmc.deplete.PredictorIntegrator( - operator=operator, - timesteps=timesteps, - source_rates=source_rates, - timestep_units=timestep_units, - ) - - with tempfile.TemporaryDirectory() as tmpdir: - # Run integrator - results_path = Path(tmpdir) / "depletion_results.h5" - integrator.integrate(path=results_path) - - # Load depletion results - results = openmc.deplete.Results(results_path) - - # For each material, get activated composition at each timestep - all_depleted_materials = { - material.id: [ - result.get_material(str(material.id)) - for result in results - ] - for material in self - } - - return all_depleted_materials + return materials diff --git a/openmc/mesh.py b/openmc/mesh.py index ff8e14577..af830158c 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -1,189 +1,18 @@ -from __future__ import annotations -import warnings from abc import ABC, abstractmethod -from collections.abc import Iterable, Sequence, Mapping -from functools import wraps -import math -from numbers import Integral, Real +from collections.abc import Iterable +from math import pi +from numbers import Real, Integral from pathlib import Path -from typing import Protocol +import warnings +from xml.etree import ElementTree as ET -import h5py -import lxml.etree as ET import numpy as np -import openmc import openmc.checkvalue as cv -from openmc.checkvalue import PathLike -from .bounding_box import BoundingBox -from ._xml import get_elem_list, get_text +import openmc +from ._xml import get_text from .mixin import IDManagerMixin from .surface import _BOUNDARY_TYPES -from .utility_funcs import input_path - - -class MeshMaterialVolumes(Mapping): - """Results from a material volume in mesh calculation. - - This class provides multiple ways of accessing information about material - volumes in individual mesh elements. First, the class behaves like a - dictionary that maps material IDs to an array of volumes equal in size to - the number of mesh elements. Second, the class provides a :meth:`by_element` - method that gives all the material volumes for a specific mesh element. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - materials : numpy.ndarray - Array of shape (elements, max_materials) storing material IDs - volumes : numpy.ndarray - Array of shape (elements, max_materials) storing material volumes - bboxes : numpy.ndarray, optional - Array of shape (elements, max_materials, 6) storing axis-aligned - bounding boxes for each (element, material) combination with ordering - (xmin, ymin, zmin, xmax, ymax, zmax). Bounding boxes enclose the - ray-estimator prisms used to compute volumes. - - See Also - -------- - openmc.MeshBase.material_volumes - - Examples - -------- - If you want to get the volume of a specific material in every mesh element, - index the object with the material ID: - - >>> volumes = mesh.material_volumes(...) - >>> volumes - {1: <32121 nonzero volumes> - 2: <338186 nonzero volumes> - 3: <49120 nonzero volumes>} - - If you want the volume of all materials in a specific mesh element, use the - :meth:`by_element` method: - - >>> volumes = mesh.material_volumes(...) - >>> volumes.by_element(42) - [(2, 31.87963824195591), (1, 6.129949130817542)] - - """ - def __init__( - self, - materials: np.ndarray, - volumes: np.ndarray, - bboxes: np.ndarray | None = None - ): - self._materials = materials - self._volumes = volumes - self._bboxes = bboxes - - if self._bboxes is not None: - if self._bboxes.shape[:2] != self._materials.shape: - raise ValueError( - 'bboxes must have shape (elements, max_materials, 6) ' - 'matching materials/volumes.' - ) - if self._bboxes.shape[2] != 6: - raise ValueError( - 'bboxes must have shape (elements, max_materials, 6).' - ) - - @property - def has_bounding_boxes(self) -> bool: - return self._bboxes is not None - - @property - def num_elements(self) -> int: - return self._volumes.shape[0] - - def __iter__(self): - for mat in np.unique(self._materials): - if mat > 0: - yield mat - - def __len__(self) -> int: - return (np.unique(self._materials) > 0).sum() - - def __repr__(self) -> str: - ids, counts = np.unique(self._materials, return_counts=True) - return '{' + '\n '.join( - f'{id}: <{count} nonzero volumes>' for id, count in zip(ids, counts) if id > 0) + '}' - - def __getitem__(self, material_id: int) -> np.ndarray: - volumes = np.zeros(self.num_elements) - for i in range(self._volumes.shape[1]): - indices = (self._materials[:, i] == material_id) - volumes[indices] = self._volumes[indices, i] - return volumes - - def by_element( - self, - index_elem: int, - include_bboxes: bool = False - ) -> list[tuple[int | None, float] | tuple[int | None, float, BoundingBox | None]]: - """Get a list of volumes for each material within a specific element. - - Parameters - ---------- - index_elem : int - Mesh element index - - Returns - ------- - list of tuple - If ``include_bboxes`` is False (default), returns tuples of - (material ID, volume). If ``include_bboxes`` is True, returns - tuples of (material ID, volume, bounding box). - - """ - table_size = self._volumes.shape[1] - if include_bboxes and self._bboxes is None: - raise ValueError('Bounding boxes were not computed for this object.') - - results = [] - for i in range(table_size): - m = self._materials[index_elem, i] - if m == -2: - continue - mat_id = m if m > -1 else None - vol = self._volumes[index_elem, i] - - if include_bboxes: - vals = self._bboxes[index_elem, i] - bbox = BoundingBox(vals[0:3], vals[3:6]) - results.append((mat_id, vol, bbox)) - else: - results.append((mat_id, vol)) - - return results - - def save(self, filename: PathLike): - """Save material volumes to a .npz file. - - Parameters - ---------- - filename : path-like - Filename where data will be saved - """ - kwargs = {'materials': self._materials, 'volumes': self._volumes} - if self._bboxes is not None: - kwargs['bboxes'] = self._bboxes - np.savez_compressed(filename, **kwargs) - - @classmethod - def from_npz(cls, filename: PathLike) -> MeshMaterialVolumes: - """Generate material volumes from a .npz file - - Parameters - ---------- - filename : path-like - File where data will be read from - - """ - filedata = np.load(filename) - bboxes = filedata['bboxes'] if 'bboxes' in filedata.files else None - return cls(filedata['materials'], filedata['volumes'], bboxes) class MeshBase(IDManagerMixin, ABC): @@ -202,23 +31,13 @@ class MeshBase(IDManagerMixin, ABC): Unique identifier for the mesh name : str Name of the mesh - lower_left : Iterable of float - The lower-left coordinates - upper_right : Iterable of float - The upper-right coordinates - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh as defined by the upper-right and - lower-left coordinates. - indices : Iterable of tuple - An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] - n_elements : int - Number of elements in the mesh + """ next_id = 1 used_ids = set() - def __init__(self, mesh_id: int | None = None, name: str = ''): + def __init__(self, mesh_id=None, name=''): # Initialize Mesh class attributes self.id = mesh_id self.name = name @@ -228,37 +47,13 @@ class MeshBase(IDManagerMixin, ABC): return self._name @name.setter - def name(self, name: str): + def name(self, name): if name is not None: cv.check_type(f'name for mesh ID="{self._id}"', name, str) self._name = name else: self._name = '' - @property - @abstractmethod - def lower_left(self): - pass - - @property - @abstractmethod - def upper_right(self): - pass - - @property - def bounding_box(self) -> openmc.BoundingBox: - return openmc.BoundingBox(self.lower_left, self.upper_right) - - @property - @abstractmethod - def indices(self): - pass - - @property - @abstractmethod - def n_elements(self): - pass - def __repr__(self): string = type(self).__name__ + '\n' string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) @@ -266,14 +61,13 @@ class MeshBase(IDManagerMixin, ABC): return string def _volume_dim_check(self): - if any(d == 0 for d in self.dimension): - raise RuntimeError( - f'Mesh {self.id} has a zero-size dimension. ' - 'Volumes cannot be provided.' - ) + if self.n_dimension != 3 or \ + any([d == 0 for d in self.dimension]): + raise RuntimeError(f'Mesh {self.id} is not 3D. ' + 'Volumes cannot be provided.') @classmethod - def from_hdf5(cls, group: h5py.Group): + def from_hdf5(cls, group): """Create mesh from HDF5 group Parameters @@ -287,47 +81,28 @@ class MeshBase(IDManagerMixin, ABC): Instance of a MeshBase subclass """ - mesh_type = 'regular' if 'type' not in group.keys() else group['type'][()].decode() - mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) - mesh_name = '' if 'name' not in group else group['name'][()].decode() + mesh_type = group['type'][()].decode() if mesh_type == 'regular': - return RegularMesh.from_hdf5(group, mesh_id, mesh_name) + return RegularMesh.from_hdf5(group) elif mesh_type == 'rectilinear': - return RectilinearMesh.from_hdf5(group, mesh_id, mesh_name) + return RectilinearMesh.from_hdf5(group) elif mesh_type == 'cylindrical': - return CylindricalMesh.from_hdf5(group, mesh_id, mesh_name) + return CylindricalMesh.from_hdf5(group) elif mesh_type == 'spherical': - return SphericalMesh.from_hdf5(group, mesh_id, mesh_name) + return SphericalMesh.from_hdf5(group) elif mesh_type == 'unstructured': - return UnstructuredMesh.from_hdf5(group, mesh_id, mesh_name) + return UnstructuredMesh.from_hdf5(group) else: raise ValueError('Unrecognized mesh type: "' + mesh_type + '"') - def to_xml_element(self): - """Return XML representation of the mesh - - Returns - ------- - element : lxml.etree._Element - XML element containing mesh data - - """ - elem = ET.Element("mesh") - - elem.set("id", str(self._id)) - if self.name: - elem.set("name", self.name) - - return elem - @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generates a mesh from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -339,170 +114,18 @@ class MeshBase(IDManagerMixin, ABC): mesh_type = get_text(elem, 'type') if mesh_type == 'regular' or mesh_type is None: - mesh = RegularMesh.from_xml_element(elem) + return RegularMesh.from_xml_element(elem) elif mesh_type == 'rectilinear': - mesh = RectilinearMesh.from_xml_element(elem) + return RectilinearMesh.from_xml_element(elem) elif mesh_type == 'cylindrical': - mesh = CylindricalMesh.from_xml_element(elem) + return CylindricalMesh.from_xml_element(elem) elif mesh_type == 'spherical': - mesh = SphericalMesh.from_xml_element(elem) + return SphericalMesh.from_xml_element(elem) elif mesh_type == 'unstructured': - mesh = UnstructuredMesh.from_xml_element(elem) + return UnstructuredMesh.from_xml_element(elem) else: raise ValueError(f'Unrecognized mesh type "{mesh_type}" found.') - mesh.name = get_text(elem, 'name', default='') - return mesh - - def get_homogenized_materials( - self, - model: openmc.Model, - n_samples: int | tuple[int, int, int] = 10_000, - include_void: bool = True, - material_volumes: MeshMaterialVolumes | None = None, - **kwargs - ) -> list[openmc.Material]: - """Generate homogenized materials over each element in a mesh. - - .. versionadded:: 0.15.0 - - Parameters - ---------- - model : openmc.Model - Model containing materials to be homogenized and the associated - geometry. - n_samples : int or 2-tuple of int - Total number of rays to sample. The number of rays in each direction - is determined by the aspect ratio of the mesh bounding box. When - specified as a 3-tuple, it is interpreted as the number of rays in - the x, y, and z dimensions. - include_void : bool, optional - Whether homogenization should include voids. - material_volumes : MeshMaterialVolumes, optional - Previously computed mesh material volumes to use for homogenization. - If not provided, they will be computed by calling - :meth:`material_volumes`. - **kwargs - Keyword-arguments passed to :meth:`material_volumes`. - - Returns - ------- - list of openmc.Material - Homogenized material in each mesh element - - """ - if material_volumes is None: - vols = self.material_volumes(model, n_samples, **kwargs) - else: - vols = material_volumes - mat_volume_by_element = [vols.by_element(i) for i in range(vols.num_elements)] - - # Get dictionary of all materials - materials = model._get_all_materials() - - # Create homogenized material for each element - homogenized_materials = [] - for mat_volume_list in mat_volume_by_element: - material_ids, volumes = [list(x) for x in zip(*mat_volume_list)] - total_volume = sum(volumes) - - # Check for void material and remove - try: - index_void = material_ids.index(None) - except ValueError: - pass - else: - material_ids.pop(index_void) - volumes.pop(index_void) - - # If void should be excluded, adjust total volume - if not include_void: - total_volume = sum(volumes) - - # Compute volume fractions - volume_fracs = np.array(volumes) / total_volume - - # Get list of materials and mix 'em up! - mats = [materials[uid] for uid in material_ids] - homogenized_mat = openmc.Material.mix_materials( - mats, volume_fracs, 'vo' - ) - homogenized_mat.volume = total_volume - homogenized_materials.append(homogenized_mat) - - return homogenized_materials - - def material_volumes( - self, - model: openmc.Model, - n_samples: int | tuple[int, int, int] = 10_000, - max_materials: int = 4, - bounding_boxes: bool = False, - **kwargs - ) -> MeshMaterialVolumes: - """Determine volume of materials in each mesh element. - - This method works by raytracing repeatedly through the mesh to count the - estimated volume of each material in all mesh elements. Three sets of - rays are used: one set parallel to the x-axis, one parallel to the - y-axis, and one parallel to the z-axis. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - model : openmc.Model - Model containing materials. - n_samples : int or 3-tuple of int - Total number of rays to sample. The number of rays in each direction - is determined by the aspect ratio of the mesh bounding box. When - specified as a 3-tuple, it is interpreted as the number of rays in - the x, y, and z dimensions. - max_materials : int, optional - Estimated maximum number of materials in any given mesh element. - bounding_boxes : bool, optional - Whether to compute an axis-aligned bounding box for each - (mesh element, material) combination. When enabled, the bounding - box encloses the ray-estimator prisms used for the volume - estimation. - **kwargs : dict - Keyword arguments passed to :func:`openmc.lib.init` - - Returns - ------- - Dictionary-like object that maps material IDs to an array of volumes - equal in size to the number of mesh elements. - - """ - import openmc.lib - - # In order to get mesh into model, we temporarily replace the - # tallies with a single mesh tally using the current mesh - original_tallies = list(model.tallies) - new_tally = openmc.Tally() - new_tally.filters = [openmc.MeshFilter(self)] - new_tally.scores = ['flux'] - model.tallies = [new_tally] - - # Set default arguments - kwargs.setdefault('output', True) - if 'args' in kwargs: - kwargs['args'] = ['-c'] + kwargs['args'] - kwargs.setdefault('args', ['-c']) - - with openmc.lib.TemporarySession(model, **kwargs): - # Get mesh from single tally - mesh = openmc.lib.tallies[new_tally.id].filters[0].mesh - - # Compute material volumes - volumes = mesh.material_volumes( - n_samples, max_materials, output=kwargs['output'], - bounding_boxes=bounding_boxes) - - # Restore original tallies - model.tallies = original_tallies - return volumes - class StructuredMesh(MeshBase): """A base class for structured mesh functionality @@ -536,94 +159,23 @@ class StructuredMesh(MeshBase): def n_dimension(self): pass - @property - @abstractmethod - def _axis_labels(self): - pass - @property @abstractmethod def _grids(self): pass - @abstractmethod - def get_indices_at_coords(self, coords: Sequence[float]) -> tuple: - pass - @property def vertices(self): - """Return coordinates of mesh vertices in Cartesian coordinates. Also - see :meth:`CylindricalMesh.vertices_cylindrical` and - :meth:`SphericalMesh.vertices_spherical` for coordinates in other coordinate - systems. + """Return coordinates of mesh vertices. Returns ------- vertices : numpy.ndarray Returns a numpy.ndarray representing the coordinates of the mesh - vertices with a shape equal to (dim1 + 1, ..., dimn + 1, ndim). X, Y, Z values - can be unpacked with xx, yy, zz = np.rollaxis(mesh.vertices, -1). + vertices with a shape equal to (dim1 + 1, ..., dimn + 1, ndim). """ - return self._generate_vertices(*self._grids) - - @staticmethod - def _generate_vertices(i_grid, j_grid, k_grid): - """Returns an array with shape (i_grid.size, j_grid.size, k_grid.size, 3) - containing the corner vertices of mesh elements. - """ - return np.stack(np.meshgrid(i_grid, j_grid, k_grid, indexing='ij'), axis=-1) - - @staticmethod - def _generate_edge_midpoints(grids): - """Generates the midpoints of mesh element edges for each dimension of the mesh. - - Parameters - ---------- - grids : numpy.ndarray - The vertex grids along each dimension of the mesh. - - Returns - ------- - midpoint_grids : list of numpy.ndarray - The edge midpoints for the i, j, and k midpoints of each element in - i, j, k ordering. The shapes of the resulting grids are - [(ni-1, nj, nk, 3), (ni, nj-1, nk, 3), (ni, nj, nk-1, 3)] - """ - # generate a set of edge midpoints for each dimension - midpoint_grids = [] - # generate the element edge midpoints in order s.t. - # the epxected element ordering is preserved with respect to the corner vertices - - # each grid is comprised of the mid points for one dimension and the - # corner vertices of the other two - for dims in ((0, 1, 2), (1, 0, 2), (2, 0, 1)): - # compute the midpoints along the last dimension - midpoints = grids[dims[0]][:-1] + 0.5 * np.diff(grids[dims[0]]) - - coords = (midpoints, grids[dims[1]], grids[dims[2]]) - - i_grid, j_grid, k_grid = [coords[dims.index(i)] for i in range(3)] - - # re-use the generate vertices method to create the full mesh grid - # transpose to get (i, j, k) ordering of the gridpoints - midpoint_grid = StructuredMesh._generate_vertices(i_grid, j_grid, k_grid) - midpoint_grids.append(midpoint_grid) - - return midpoint_grids - - @property - def midpoint_vertices(self): - """Create vertices that lie on the midpoint of element edges - """ - # generate edge midpoints needed for curvilinear element definition - midpoint_vertices = self._generate_edge_midpoints(self._grids) - - # convert each of the midpoint grids to cartesian coordinates - for vertices in midpoint_vertices: - self._convert_to_cartesian(vertices, self.origin) - - return midpoint_vertices + return np.stack(np.meshgrid(*self._grids, indexing='ij'), axis=-1) @property def centroids(self): @@ -633,395 +185,97 @@ class StructuredMesh(MeshBase): ------- centroids : numpy.ndarray Returns a numpy.ndarray representing the mesh element centroid - coordinates with a shape equal to (dim1, ..., dimn, ndim). X, - Y, Z values can be unpacked with xx, yy, zz = - np.rollaxis(mesh.centroids, -1). + coordinates with a shape equal to (dim1, ..., dimn, ndim). + """ ndim = self.n_dimension - # this line ensures that the vertices aren't adjusted by the origin or - # converted to the Cartesian system for cylindrical and spherical meshes - vertices = StructuredMesh.vertices.fget(self) + vertices = self.vertices s0 = (slice(0, -1),)*ndim + (slice(None),) s1 = (slice(1, None),)*ndim + (slice(None),) return (vertices[s0] + vertices[s1]) / 2 @property - def n_elements(self): + def num_mesh_cells(self): return np.prod(self.dimension) - @property - def num_mesh_cells(self): - warnings.warn( - "The 'num_mesh_cells' attribute is deprecated and will be removed in a future version. " - "Use 'n_elements' instead.", - FutureWarning, stacklevel=2 - ) - return self.n_elements - - def write_data_to_vtk(self, - filename: PathLike, - datasets: dict | None = None, - volume_normalization: bool = True, - curvilinear: bool = False): + def write_data_to_vtk(self, points, filename, datasets, volume_normalization=True): """Creates a VTK object of the mesh Parameters ---------- + points : list or np.array + List of (X,Y,Z) tuples. filename : str Name of the VTK file to write. datasets : dict - Dictionary whose keys are the data labels and values are the data - sets. 1D datasets are expected to be extracted directly from - statepoint data without reordering/reshaping. Multidimensional - datasets are expected to have the same dimensions as the mesh itself - with structured indexing in "C" ordering. See the "expand_dims" flag - of :meth:`~openmc.Tally.get_reshaped_data` on reshaping tally data when using - :class:`~openmc.MeshFilter`'s. + Dictionary whose keys are the data labels + and values are the data sets. volume_normalization : bool, optional - Whether or not to normalize the data by the volume of the mesh - elements. - curvilinear : bool - Whether or not to write curvilinear elements. Only applies to - ``SphericalMesh`` and ``CylindricalMesh``. + Whether or not to normalize the data by + the volume of the mesh elements. Raises ------ - ValueError - When the size of a dataset doesn't match the number of mesh cells + RuntimeError + When the size of a dataset doesn't match the number of cells Returns ------- - vtk.StructuredGrid or vtk.UnstructuredGrid - a VTK grid object representing the mesh - - Examples - -------- - 1D data from a tally with only a mesh filter and heating score: - - # pass the tally mean property of shape (N, 1, 1) directly to this - # method; dimensions of size 1 will automatically removed - >>> heating = tally.mean - >>> mesh.write_data_to_vtk({'heating': heating}) - - Multidimensional data from a tally with only a mesh - - # retrieve a data array with the mesh filter expanded into three - # dimensions, ijk; additional dimensions of size one will - # automatically be removed - >>> heating = tally.get_reshaped_data(expand_dims=True) - >>> mesh.write_data_to_vtk({'heating': heating}) + vtk.vtkStructuredGrid + the VTK object """ + import vtk from vtk.util import numpy_support as nps - # write linear elements using a structured grid - if not curvilinear or isinstance(self, (RegularMesh, RectilinearMesh)): - vtk_grid = self._create_vtk_structured_grid() - writer = vtk.vtkStructuredGridWriter() - # write curvilinear elements using an unstructured grid - else: - vtk_grid = self._create_vtk_unstructured_grid() - writer = vtk.vtkUnstructuredGridWriter() + # check that the data sets are appropriately sized + errmsg = "The size of the dataset {} should be equal to the number of cells" + for label, dataset in datasets.items(): + if isinstance(dataset, np.ndarray): + if not dataset.size == self.dimension[0] * self.dimension[1]* self.dimension[2]: + raise RuntimeError(errmsg.format(label)) + else: + if len(dataset) == self.dimension[0] * self.dimension[1]* self.dimension[2]: + raise RuntimeError(errmsg.format(label)) + cv.check_type('label', label, str) - if datasets is not None: - # maintain a list of the datasets as added to the VTK arrays to - # ensure they persist in memory until the file is written - datasets_out = [] - for label, dataset in datasets.items(): - dataset = self._reshape_vtk_dataset(dataset) - self._check_vtk_dataset(label, dataset) - # If the array data is 3D, assume is in C ordering and transpose - # before flattening to match the ordering expected by the VTK - # array based on the way mesh indices are ordered in the Python - # API - # TODO: update to "C" ordering throughout - if dataset.ndim == 3: - dataset = dataset.T.ravel() - datasets_out.append(dataset) + vtk_grid = vtk.vtkStructuredGrid() - if volume_normalization: - dataset /= self.volumes.T.ravel() + vtk_grid.SetDimensions(*[dim + 1 for dim in self.dimension]) - dataset_array = vtk.vtkDoubleArray() - dataset_array.SetName(label) - dataset_array.SetArray(nps.numpy_to_vtk(dataset), dataset.size, True) - vtk_grid.GetCellData().AddArray(dataset_array) + vtkPts = vtk.vtkPoints() + vtkPts.SetData(nps.numpy_to_vtk(points, deep=True)) + vtk_grid.SetPoints(vtkPts) + # create VTK arrays for each of + # the data sets + + # maintain a list of the datasets as added + # to the VTK arrays to ensure they persist + # in memory until the file is written + datasets_out = [] + for label, dataset in datasets.items(): + dataset = np.asarray(dataset).flatten() + datasets_out.append(dataset) + + if volume_normalization: + dataset /= self.volumes.flatten() + + dataset_array = vtk.vtkDoubleArray() + dataset_array.SetName(label) + dataset_array.SetArray(nps.numpy_to_vtk(dataset), + dataset.size, + True) + vtk_grid.GetCellData().AddArray(dataset_array) + + # write the .vtk file + writer = vtk.vtkStructuredGridWriter() writer.SetFileName(str(filename)) writer.SetInputData(vtk_grid) writer.Write() return vtk_grid - def _create_vtk_structured_grid(self): - """Create a structured grid - - Returns - ------- - vtk.vtkStructuredGrid - a VTK structured grid object representing the mesh - """ - import vtk - from vtk.util import numpy_support as nps - - vtkPts = vtk.vtkPoints() - vtkPts.SetData(nps.numpy_to_vtk(np.swapaxes(self.vertices, 0, 2).reshape(-1, 3), deep=True)) - vtk_grid = vtk.vtkStructuredGrid() - vtk_grid.SetPoints(vtkPts) - vtk_grid.SetDimensions(*[dim + 1 for dim in self.dimension]) - - return vtk_grid - - def _create_vtk_unstructured_grid(self): - """Create an unstructured grid of curvilinear elements - representing the mesh - - Returns - ------- - vtk.vtkUnstructuredGrid - a VTK unstructured grid object representing the mesh - """ - import vtk - from vtk.util import numpy_support as nps - - corner_vertices = np.swapaxes(self.vertices, 0, 2).reshape(-1, 3) - - vtkPts = vtk.vtkPoints() - vtk_grid = vtk.vtkUnstructuredGrid() - vtk_grid.SetPoints(vtkPts) - # add corner vertices to the point set for the unstructured grid - # only insert unique points, we'll get their IDs in the point set to - # define element connectivity later - vtkPts.SetData(nps.numpy_to_vtk(np.unique(corner_vertices, axis=0), deep=True)) - - # create a locator to assist with duplicate points - locator = vtk.vtkPointLocator() - locator.SetDataSet(vtk_grid) - locator.AutomaticOn() # autmoatically adds points to locator - locator.InitPointInsertion(vtkPts, vtkPts.GetBounds()) - locator.BuildLocator() - - # this function is used to add new points to the unstructured - # grid. It will return an existing point ID if the point is alread present - def _insert_point(pnt): - result = locator.IsInsertedPoint(pnt) - if result == -1: - point_id = vtkPts.InsertNextPoint(pnt) - locator.InsertPoint(point_id, pnt) - return point_id - else: - return result - - # Add all points to the unstructured grid, maintaining a flat list of IDs as we go ### - - # flat array storing point IDs for a given vertex - # in the grid - point_ids = [] - - # add element corner vertices to array - for pnt in corner_vertices: - point_ids.append(_insert_point(pnt)) - - # get edge midpoints and add them to the - # list of point IDs - midpoint_vertices = self.midpoint_vertices - for edge_grid in midpoint_vertices: - for pnt in np.swapaxes(edge_grid, 0, 2).reshape(-1, 3): - point_ids.append(_insert_point(pnt)) - - # determine how many elements in each dimension - # and how many points in each grid - n_elem = np.asarray(self.dimension) - n_pnts = n_elem + 1 - - # create hexes and set points for corner - # vertices - for i, j, k in self.indices: - # handle indices indexed from one - i -= 1 - j -= 1 - k -= 1 - - # create a new vtk hex - hex = vtk.vtkQuadraticHexahedron() - - # set connectivity the hex corners - for n, (di, dj, dk) in enumerate(_HEX_VERTEX_CONN): - # compute flat index into the point ID list based on i, j, k - # of the vertex - flat_idx = np.ravel_multi_index((i+di, j+dj, k+dk), n_pnts, order='F') - # set corner vertices - hex.GetPointIds().SetId(n, point_ids[flat_idx]) - - # set connectivity of the hex midpoints - n_midpoint_vertices = [v.size // 3 for v in midpoint_vertices] - for n, (dim, (di, dj, dk)) in enumerate(_HEX_MIDPOINT_CONN): - # initial offset for corner vertices and midpoint dimension - flat_idx = corner_vertices.shape[0] + sum(n_midpoint_vertices[:dim]) - # generate a flat index into the table of point IDs - midpoint_shape = midpoint_vertices[dim].shape[:-1] - flat_idx += np.ravel_multi_index((i+di, j+dj, k+dk), - midpoint_shape, - order='F') - # set hex midpoint connectivity - hex.GetPointIds().SetId(_N_HEX_VERTICES + n, point_ids[flat_idx]) - - # add the hex to the grid - vtk_grid.InsertNextCell(hex.GetCellType(), hex.GetPointIds()) - - return vtk_grid - - @staticmethod - def _reshape_vtk_dataset(dataset): - """Reshape a dataset to be compatible with VTK output - - This method performs the following operations on a dataset: - 1. Convert to numpy array if not already - 2. Remove any trailing dimensions of size 1 - 3. Squeeze out any extra dimensions of size 1 beyond the first 3 - - Parameters - ---------- - dataset : array-like - The dataset to reshape - - Returns - ------- - numpy.ndarray - The reshaped dataset - """ - reshaped_data = np.asarray(dataset) - - # detect flat array with extra dims - if all(d == 1 for d in reshaped_data.shape[1:]): - reshaped_data = reshaped_data.squeeze() - - # remove any higher dimensions with size 1 - if reshaped_data.ndim > 3 and all(d == 1 for d in reshaped_data.shape[3:]): - reshaped_data = reshaped_data.reshape(reshaped_data.shape[:3]) - - if np.shares_memory(reshaped_data, dataset): - return np.copy(reshaped_data) - else: - return reshaped_data - - def _check_vtk_dataset(self, label: str, dataset: np.ndarray): - """Perform some basic checks that a dataset is valid for this Mesh - - Parameters - ---------- - label : str - The label for the dataset being checked - dataset : numpy.ndarray - The dataset array to check against this mesh's dimensions - - """ - cv.check_type('data label', label, str) - - if dataset.size != self.n_elements: - raise ValueError( - f"The size of the dataset '{label}' ({dataset.size}) should be" - f" equal to the number of mesh cells ({self.n_elements})" - ) - - # accept a flat array as-is, assuming it is in the correct order - if dataset.ndim == 1: - return - - if dataset.shape != self.dimension: - raise ValueError( - f'Cannot apply multidimensional dataset "{label}" with ' - f"shape {dataset.shape} to mesh {self.id} " - f"with dimensions {self.dimension}" - ) - - @classmethod - def from_domain( - cls, - domain: HasBoundingBox | BoundingBox, - dimension: Sequence[int] | int | None = None, - mesh_id: int | None = None, - name: str = '', - **kwargs - ) -> StructuredMesh: - """Create a structured mesh from a domain using its bounding box. - - Parameters - ---------- - domain : HasBoundingBox | openmc.BoundingBox - Object used as a template for the mesh extents. If ``domain`` has a - ``bounding_box`` attribute, that bounding box is used directly. - dimension : Iterable of int or int, optional - Number of mesh cells. When omitted, the subclass-specific default is - used. If provided as a single integer, subclasses that support it - interpret it as a target total number of mesh cells. - mesh_id : int, optional - Unique identifier for the mesh. - name : str, optional - Name of the mesh. - **kwargs - Additional keyword arguments forwarded to - :meth:`from_bounding_box`. - - Returns - ------- - openmc.StructuredMesh - Structured mesh instance. - """ - if isinstance(domain, BoundingBox): - bbox = domain - elif hasattr(domain, 'bounding_box'): - bbox = domain.bounding_box - else: - raise TypeError("Domain must be a BoundingBox or have a " - "bounding_box property") - - if dimension is None: - return cls.from_bounding_box( - bbox, mesh_id=mesh_id, name=name, **kwargs) - - return cls.from_bounding_box( - bbox, dimension=dimension, mesh_id=mesh_id, name=name, **kwargs) - - @classmethod - @abstractmethod - def from_bounding_box( - cls, - bbox: openmc.BoundingBox, - dimension: Sequence[int] | int, - mesh_id: int | None = None, - name: str = '', - **kwargs - ) -> StructuredMesh: - """Create a structured mesh from a bounding box. - - Parameters - ---------- - bbox : openmc.BoundingBox - Bounding box used to define the mesh extents. - dimension : Iterable of int or int - Number of mesh cells. The interpretation and any default value are - defined by the concrete mesh type. - mesh_id : int, optional - Unique identifier for the mesh. - name : str, optional - Name of the mesh. - **kwargs - Additional keyword arguments accepted by specific subclasses. - - Returns - ------- - openmc.StructuredMesh - Structured mesh instance. - """ - pass - - -class HasBoundingBox(Protocol): - """Object that has a ``bounding_box`` attribute.""" - bounding_box: openmc.BoundingBox - - class RegularMesh(StructuredMesh): """A regular Cartesian mesh in one, two, or three dimensions @@ -1039,7 +293,7 @@ class RegularMesh(StructuredMesh): name : str Name of the mesh dimension : Iterable of int - The number of mesh cells in each direction (x, y, z). + The number of mesh cells in each direction. n_dimension : int Number of mesh dimensions. lower_left : Iterable of float @@ -1048,9 +302,6 @@ class RegularMesh(StructuredMesh): upper_right : Iterable of float The upper-right corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh as defined by the upper-right and - lower-left coordinates. width : Iterable of float The width of mesh cells in each direction. indices : Iterable of tuple @@ -1059,7 +310,7 @@ class RegularMesh(StructuredMesh): """ - def __init__(self, mesh_id: int | None = None, name: str = ''): + def __init__(self, mesh_id=None, name=''): super().__init__(mesh_id, name) self._dimension = None @@ -1069,13 +320,7 @@ class RegularMesh(StructuredMesh): @property def dimension(self): - return tuple(self._dimension) - - @dimension.setter - def dimension(self, dimension: Iterable[int]): - cv.check_type('mesh dimension', dimension, Iterable, Integral) - cv.check_length('mesh dimension', dimension, 1, 3) - self._dimension = dimension + return self._dimension @property def n_dimension(self): @@ -1084,23 +329,10 @@ class RegularMesh(StructuredMesh): else: return None - @property - def _axis_labels(self): - return ('x', 'y', 'z')[:self.n_dimension] - @property def lower_left(self): return self._lower_left - @lower_left.setter - def lower_left(self, lower_left: Iterable[Real]): - cv.check_type('mesh lower_left', lower_left, Iterable, Real) - cv.check_length('mesh lower_left', lower_left, 1, 3) - self._lower_left = lower_left - - if self.upper_right is not None and any(np.isclose(self.upper_right, lower_left)): - raise ValueError("Mesh cannot have zero thickness in any dimension") - @property def upper_right(self): if self._upper_right is not None: @@ -1112,19 +344,6 @@ class RegularMesh(StructuredMesh): dims = self._dimension return [l + w * d for l, w, d in zip(ls, ws, dims)] - @upper_right.setter - def upper_right(self, upper_right: Iterable[Real]): - cv.check_type('mesh upper_right', upper_right, Iterable, Real) - cv.check_length('mesh upper_right', upper_right, 1, 3) - self._upper_right = upper_right - - if self._width is not None: - self._width = None - warnings.warn("Unsetting width attribute.") - - if self.lower_left is not None and any(np.isclose(self.lower_left, upper_right)): - raise ValueError("Mesh cannot have zero thickness in any dimension") - @property def width(self): if self._width is not None: @@ -1136,16 +355,6 @@ class RegularMesh(StructuredMesh): dims = self._dimension return [(u - l) / d for u, l, d in zip(us, ls, dims)] - @width.setter - def width(self, width: Iterable[Real]): - cv.check_type('mesh width', width, Iterable, Real) - cv.check_length('mesh width', width, 1, 3) - self._width = width - - if self._upper_right is not None: - self._upper_right = None - warnings.warn("Unsetting upper_right attribute.") - @property def volumes(self): """Return Volumes for every mesh cell @@ -1205,19 +414,53 @@ class RegularMesh(StructuredMesh): x1, = self.upper_right return (np.linspace(x0, x1, nx + 1),) + @dimension.setter + def dimension(self, dimension): + cv.check_type('mesh dimension', dimension, Iterable, Integral) + cv.check_length('mesh dimension', dimension, 1, 3) + self._dimension = dimension + + @lower_left.setter + def lower_left(self, lower_left): + cv.check_type('mesh lower_left', lower_left, Iterable, Real) + cv.check_length('mesh lower_left', lower_left, 1, 3) + self._lower_left = lower_left + + @upper_right.setter + def upper_right(self, upper_right): + cv.check_type('mesh upper_right', upper_right, Iterable, Real) + cv.check_length('mesh upper_right', upper_right, 1, 3) + self._upper_right = upper_right + + if self._width is not None: + self._width = None + warnings.warn("Unsetting width attribute.") + + @width.setter + def width(self, width): + cv.check_type('mesh width', width, Iterable, Real) + cv.check_length('mesh width', width, 1, 3) + self._width = width + + if self._upper_right is not None: + self._upper_right = None + warnings.warn("Unsetting upper_right attribute.") + def __repr__(self): string = super().__repr__() string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) string += '{0: <16}{1}{2}\n'.format('\tVoxels', '=\t', self._dimension) string += '{0: <16}{1}{2}\n'.format('\tLower left', '=\t', self._lower_left) - string += '{0: <16}{1}{2}\n'.format('\tUpper Right', '=\t', self.upper_right) - string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self.width) + string += '{0: <16}{1}{2}\n'.format('\tUpper Right', '=\t', self._upper_right) + string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._width) return string @classmethod - def from_hdf5(cls, group: h5py.Group, mesh_id: int, name: str): + def from_hdf5(cls, group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + # Read and assign mesh properties - mesh = cls(mesh_id=mesh_id, name=name) + mesh = cls(mesh_id) mesh.dimension = group['dimension'][()] mesh.lower_left = group['lower_left'][()] if 'width' in group: @@ -1230,13 +473,7 @@ class RegularMesh(StructuredMesh): return mesh @classmethod - def from_rect_lattice( - cls, - lattice: 'openmc.RectLattice', - division: int = 1, - mesh_id: int | None = None, - name: str = '' - ): + def from_rect_lattice(cls, lattice, division=1, mesh_id=None, name=''): """Create mesh from an existing rectangular lattice Parameters @@ -1262,67 +499,25 @@ class RegularMesh(StructuredMesh): shape = np.array(lattice.shape) width = lattice.pitch*shape - mesh = cls(mesh_id=mesh_id, name=name) + mesh = cls(mesh_id, name) mesh.lower_left = lattice.lower_left mesh.upper_right = lattice.lower_left + width mesh.dimension = shape*division return mesh - @classmethod - def from_bounding_box( - cls, - bbox: openmc.BoundingBox, - dimension: Sequence[int] | int = 1000, - mesh_id: int | None = None, - name: str = '', - ) -> RegularMesh: - """Create a RegularMesh from a bounding box. - - Parameters - ---------- - bbox : openmc.BoundingBox - Bounding box used to set the mesh extents. - dimension : Iterable of int or int, optional - The number of mesh cells in each direction (x, y, z). If a single - integer is provided, the total number of cells is distributed - across directions to produce cells with roughly equal widths. - mesh_id : int, optional - Unique identifier for the mesh. - name : str, optional - Name of the mesh. - - Returns - ------- - openmc.RegularMesh - RegularMesh instance. - """ - mesh = cls(mesh_id=mesh_id, name=name) - mesh.lower_left = bbox[0] - mesh.upper_right = bbox[1] - if isinstance(dimension, int): - cv.check_greater_than("dimension", dimension, 1, equality=True) - # If a single integer is provided, divide the domain into that many - # mesh cells with roughly equal lengths in each direction - ideal_cube_volume = bbox.volume / dimension - ideal_cube_size = ideal_cube_volume ** (1 / 3) - dimension = [ - max(1, int(round(side / ideal_cube_size))) - for side in bbox.width - ] - mesh.dimension = dimension - return mesh - def to_xml_element(self): """Return XML representation of the mesh Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing mesh data """ - element = super().to_xml_element() + + element = ET.Element("mesh") + element.set("id", str(self._id)) if self._dimension is not None: subelement = ET.SubElement(element, "dimension") @@ -1341,12 +536,12 @@ class RegularMesh(StructuredMesh): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate mesh from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1356,27 +551,31 @@ class RegularMesh(StructuredMesh): """ mesh_id = int(get_text(elem, 'id')) - mesh = cls(mesh_id=mesh_id) + mesh = cls(mesh_id) - dimension = get_elem_list(elem, "dimension", int) + mesh_type = get_text(elem, 'type') + if mesh_type is not None: + mesh.type = mesh_type + + dimension = get_text(elem, 'dimension') if dimension is not None: - mesh.dimension = dimension + mesh.dimension = [int(x) for x in dimension.split()] - lower_left = get_elem_list(elem, "lower_left", float) + lower_left = get_text(elem, 'lower_left') if lower_left is not None: - mesh.lower_left = lower_left + mesh.lower_left = [float(x) for x in lower_left.split()] - upper_right = get_elem_list(elem, "upper_right", float) + upper_right = get_text(elem, 'upper_right') if upper_right is not None: - mesh.upper_right = upper_right + mesh.upper_right = [float(x) for x in upper_right.split()] - width = get_elem_list(elem, "width", float) + width = get_text(elem, 'width') if width is not None: - mesh.width = width + mesh.width = [float(x) for x in width.split()] return mesh - def build_cells(self, bc: str | None = None): + def build_cells(self, bc=None): """Generates a lattice of universes with the same dimensionality as the mesh object. The individual cells/universes produced will not have material definitions applied and so downstream code @@ -1501,47 +700,41 @@ class RegularMesh(StructuredMesh): return root_cell, cells - def get_indices_at_coords(self, coords: Sequence[float]) -> tuple: - """Finds the index of the mesh element at the specified coordinates. - - .. versionadded:: 0.15.4 + def write_data_to_vtk(self, filename, datasets, volume_normalization=True): + """Creates a VTK object of the mesh Parameters ---------- - coords : Sequence[float] - Cartesian coordinates of the point. + filename : str or pathlib.Path + Name of the VTK file to write. + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + volume_normalization : bool, optional + Whether or not to normalize the data by + the volume of the mesh elements. + Defaults to True. Returns ------- - tuple - Mesh indices matching the dimensionality of the mesh - + vtk.vtkStructuredGrid + the VTK object """ - ndim = self.n_dimension - if len(coords) < ndim: - raise ValueError( - f"coords must have at least {ndim} values for a " - f"{ndim}D mesh, got {len(coords)}" - ) - coords_array = np.array(coords[:ndim]) - lower_left = np.array(self.lower_left) - upper_right = np.array(self.upper_right) - dimension = np.array(self.dimension) + ll, ur = self.lower_left, self.upper_right + x_vals = np.linspace(ll[0], ur[0], num=self.dimension[0] + 1) + y_vals = np.linspace(ll[1], ur[1], num=self.dimension[1] + 1) + z_vals = np.linspace(ll[2], ur[2], num=self.dimension[2] + 1) - if np.any(coords_array < lower_left) or np.any(coords_array > upper_right): - raise ValueError( - f"coords {tuple(coords_array)} are outside mesh bounds " - f"[{tuple(lower_left)}, {tuple(upper_right)}]" - ) - - # Calculate spacing for each dimension - spacing = (upper_right - lower_left) / dimension - - # Calculate indices for each coordinate - indices = np.floor((coords_array - lower_left) / spacing).astype(int) - return tuple(int(i) for i in indices[:ndim]) + # create points + pts_cartesian = np.array([[x, y, z] for z in z_vals for y in y_vals for x in x_vals]) + return super().write_data_to_vtk( + points=pts_cartesian, + filename=filename, + datasets=datasets, + volume_normalization=volume_normalization + ) def Mesh(*args, **kwargs): warnings.warn("Mesh has been renamed RegularMesh. Future versions of " @@ -1566,7 +759,7 @@ class RectilinearMesh(StructuredMesh): name : str Name of the mesh dimension : Iterable of int - The number of mesh cells in each direction (x, y, z). + The number of mesh cells in each direction. n_dimension : int Number of mesh dimensions (always 3 for a RectilinearMesh). x_grid : numpy.ndarray @@ -1578,13 +771,10 @@ class RectilinearMesh(StructuredMesh): indices : Iterable of tuple An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh as defined by the upper-right and - lower-left coordinates. """ - def __init__(self, mesh_id: int = None, name: str = ''): + def __init__(self, mesh_id=None, name=''): super().__init__(mesh_id, name) self._x_grid = None @@ -1601,49 +791,22 @@ class RectilinearMesh(StructuredMesh): def n_dimension(self): return 3 - @property - def _axis_labels(self): - return ('x', 'y', 'z') - @property def x_grid(self): return self._x_grid - @x_grid.setter - def x_grid(self, grid): - cv.check_type('mesh x_grid', grid, Iterable, Real) - self._x_grid = np.asarray(grid, dtype=float) - @property def y_grid(self): return self._y_grid - @y_grid.setter - def y_grid(self, grid): - cv.check_type('mesh y_grid', grid, Iterable, Real) - self._y_grid = np.asarray(grid, dtype=float) - @property def z_grid(self): return self._z_grid - @z_grid.setter - def z_grid(self, grid): - cv.check_type('mesh z_grid', grid, Iterable, Real) - self._z_grid = np.asarray(grid, dtype=float) - @property def _grids(self): return (self.x_grid, self.y_grid, self.z_grid) - @property - def lower_left(self): - return np.array([self.x_grid[0], self.y_grid[0], self.z_grid[0]]) - - @property - def upper_right(self): - return np.array([self.x_grid[-1], self.y_grid[-1], self.z_grid[-1]]) - @property def volumes(self): """Return Volumes for every mesh cell @@ -1675,6 +838,21 @@ class RectilinearMesh(StructuredMesh): for y in range(1, ny + 1) for x in range(1, nx + 1)) + @x_grid.setter + def x_grid(self, grid): + cv.check_type('mesh x_grid', grid, Iterable, Real) + self._x_grid = np.asarray(grid) + + @y_grid.setter + def y_grid(self, grid): + cv.check_type('mesh y_grid', grid, Iterable, Real) + self._y_grid = np.asarray(grid) + + @z_grid.setter + def z_grid(self, grid): + cv.check_type('mesh z_grid', grid, Iterable, Real) + self._z_grid = np.asarray(grid) + def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() @@ -1697,9 +875,11 @@ class RectilinearMesh(StructuredMesh): return string @classmethod - def from_hdf5(cls, group: h5py.Group, mesh_id: int, name: str): + def from_hdf5(cls, group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + # Read and assign mesh properties - mesh = cls(mesh_id=mesh_id, name=name) + mesh = cls(mesh_id) mesh.x_grid = group['x_grid'][()] mesh.y_grid = group['y_grid'][()] mesh.z_grid = group['z_grid'][()] @@ -1707,12 +887,12 @@ class RectilinearMesh(StructuredMesh): return mesh @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate a rectilinear mesh from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1721,11 +901,11 @@ class RectilinearMesh(StructuredMesh): Rectilinear mesh object """ - mesh_id = int(get_text(elem, 'id')) - mesh = cls(mesh_id=mesh_id) - mesh.x_grid = get_elem_list(elem, "x_grid", float) - mesh.y_grid = get_elem_list(elem, "y_grid", float) - mesh.z_grid = get_elem_list(elem, "z_grid", float) + id = int(get_text(elem, 'id')) + mesh = cls(id) + mesh.x_grid = [float(x) for x in get_text(elem, 'x_grid').split()] + mesh.y_grid = [float(y) for y in get_text(elem, 'y_grid').split()] + mesh.z_grid = [float(z) for z in get_text(elem, 'z_grid').split()] return mesh @@ -1734,12 +914,13 @@ class RectilinearMesh(StructuredMesh): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing mesh data """ - element = super().to_xml_element() + element = ET.Element("mesh") + element.set("id", str(self._id)) element.set("type", "rectilinear") subelement = ET.SubElement(element, "x_grid") @@ -1753,89 +934,35 @@ class RectilinearMesh(StructuredMesh): return element - def get_indices_at_coords(self, coords: Sequence[float]) -> tuple[int, int, int]: - """Find the mesh cell indices containing the specified coordinates. - - .. versionadded:: 0.15.4 + def write_data_to_vtk(self, filename, datasets, volume_normalization=True): + """Creates a VTK object of the mesh Parameters ---------- - coords : Sequence[float] - Cartesian coordinates of the point as (x, y, z). + filename : str or pathlib.Path + Name of the VTK file to write. + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + volume_normalization : bool, optional + Whether or not to normalize the data by + the volume of the mesh elements. + Defaults to True. Returns ------- - tuple[int, int, int] - Mesh indices (ix, iy, iz). - - Raises - ------ - ValueError - If coords does not contain exactly 3 values, or if a coordinate is - outside the mesh grid boundaries. + vtk.vtkStructuredGrid + the VTK object """ - if len(coords) != 3: - raise ValueError( - f"coords must contain exactly 3 values for a rectilinear mesh, " - f"got {len(coords)}" - ) + # create points + pts_cartesian = np.array([[x, y, z] for z in self.z_grid for y in self.y_grid for x in self.x_grid]) - grids = (self.x_grid, self.y_grid, self.z_grid) - indices = [] - - for grid, value in zip(grids, coords): - if value < grid[0] or value > grid[-1]: - raise ValueError( - f"Coordinate value {value} is outside the mesh grid boundaries: " - f"[{grid[0]}, {grid[-1]}]" - ) - - idx = np.searchsorted(grid, value, side="right") - 1 - indices.append(int(min(idx, len(grid) - 2))) - - return tuple(indices) - - @classmethod - def from_bounding_box( - cls, - bbox: openmc.BoundingBox, - dimension: Sequence[int] | int = 1000, - mesh_id: int | None = None, - name: str = '', - ) -> RectilinearMesh: - """Create a RectilinearMesh from a bounding box with uniform grids. - - Parameters - ---------- - bbox : openmc.BoundingBox - Bounding box used to set the mesh extents. - dimension : Iterable of int or int, optional - The number of mesh cells in each direction (x, y, z). If a single - integer is provided, the total number of cells is distributed across - the three directions proportionally to the side lengths. - mesh_id : int, optional - Unique identifier for the mesh. - name : str, optional - Name of the mesh. - - Returns - ------- - openmc.RectilinearMesh - RectilinearMesh instance with uniform grids along each axis. - """ - if isinstance(dimension, int): - cv.check_greater_than("dimension", dimension, 1, equality=True) - ideal_cube_volume = bbox.volume / dimension - ideal_cube_size = ideal_cube_volume ** (1 / 3) - dimension = [ - max(1, int(round(side / ideal_cube_size))) - for side in bbox.width - ] - mesh = cls(mesh_id=mesh_id, name=name) - mesh.x_grid = np.linspace(bbox[0][0], bbox[1][0], num=dimension[0] + 1) - mesh.y_grid = np.linspace(bbox[0][1], bbox[1][1], num=dimension[1] + 1) - mesh.z_grid = np.linspace(bbox[0][2], bbox[1][2], num=dimension[2] + 1) - return mesh + return super().write_data_to_vtk( + points=pts_cartesian, + filename=filename, + datasets=datasets, + volume_normalization=volume_normalization + ) class CylindricalMesh(StructuredMesh): @@ -1843,18 +970,6 @@ class CylindricalMesh(StructuredMesh): Parameters ---------- - r_grid : numpy.ndarray - 1-D array of mesh boundary points along the r-axis - Requirement is r >= 0. - z_grid : numpy.ndarray - 1-D array of mesh boundary points along the z-axis relative to the - origin. - phi_grid : numpy.ndarray - 1-D array of mesh boundary points along the phi-axis in radians. - The default value is [0, 2π], i.e. the full phi range. - origin : numpy.ndarray - 1-D array of length 3 the (x,y,z) origin of the mesh in - cartesian coordinates mesh_id : int Unique identifier for the mesh name : str @@ -1867,7 +982,7 @@ class CylindricalMesh(StructuredMesh): name : str Name of the mesh dimension : Iterable of int - The number of mesh cells in each direction (r_grid, phi_grid, z_grid). + The number of mesh cells in each direction. n_dimension : int Number of mesh dimensions (always 3 for a CylindricalMesh). r_grid : numpy.ndarray @@ -1877,41 +992,19 @@ class CylindricalMesh(StructuredMesh): 1-D array of mesh boundary points along the phi-axis in radians. The default value is [0, 2π], i.e. the full phi range. z_grid : numpy.ndarray - 1-D array of mesh boundary points along the z-axis relative to the - origin. - origin : numpy.ndarray - 1-D array of length 3 the (x,y,z) origin of the mesh in - cartesian coordinates + 1-D array of mesh boundary points along the z-axis. indices : Iterable of tuple An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] - lower_left : Iterable of float - The lower-left corner of the structured mesh. If only two coordinate - are given, it is assumed that the mesh is an x-y mesh. - upper_right : Iterable of float - The upper-right corner of the structured mesh. If only two coordinate - are given, it is assumed that the mesh is an x-y mesh. - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh as defined by the upper-right and - lower-left coordinates. """ - def __init__( - self, - r_grid: Sequence[float], - z_grid: Sequence[float], - phi_grid: Sequence[float] = (0, 2*math.pi), - origin: Sequence[float] = (0., 0., 0.), - mesh_id: int | None = None, - name: str = '', - ): + def __init__(self, mesh_id=None, name=''): super().__init__(mesh_id, name) - self.r_grid = r_grid - self.phi_grid = phi_grid - self.z_grid = z_grid - self.origin = origin + self._r_grid = None + self._phi_grid = [0.0, 2*pi] + self._z_grid = None @property def dimension(self): @@ -1923,56 +1016,18 @@ class CylindricalMesh(StructuredMesh): def n_dimension(self): return 3 - @property - def _axis_labels(self): - return ('r', 'phi', 'z') - - @property - def origin(self): - return self._origin - - @origin.setter - def origin(self, coords): - cv.check_type('mesh origin', coords, Iterable, Real) - cv.check_length("mesh origin", coords, 3) - self._origin = np.asarray(coords) - @property def r_grid(self): return self._r_grid - @r_grid.setter - def r_grid(self, grid): - cv.check_type('mesh r_grid', grid, Iterable, Real) - cv.check_length('mesh r_grid', grid, 2) - cv.check_increasing('mesh r_grid', grid) - self._r_grid = np.asarray(grid, dtype=float) - @property def phi_grid(self): return self._phi_grid - @phi_grid.setter - def phi_grid(self, grid): - cv.check_type('mesh phi_grid', grid, Iterable, Real) - cv.check_length('mesh phi_grid', grid, 2) - cv.check_increasing('mesh phi_grid', grid) - grid = np.asarray(grid, dtype=float) - if np.any((grid < 0.0) | (grid > 2*math.pi)): - raise ValueError("phi_grid values must be in [0, 2π].") - self._phi_grid = grid - @property def z_grid(self): return self._z_grid - @z_grid.setter - def z_grid(self, grid): - cv.check_type('mesh z_grid', grid, Iterable, Real) - cv.check_length('mesh z_grid', grid, 2) - cv.check_increasing('mesh z_grid', grid) - self._z_grid = np.asarray(grid, dtype=float) - @property def _grids(self): return (self.r_grid, self.phi_grid, self.z_grid) @@ -1987,27 +1042,25 @@ class CylindricalMesh(StructuredMesh): for p in range(1, np + 1) for r in range(1, nr + 1)) - @property - def lower_left(self): - return np.array(( - self.origin[0] - self.r_grid[-1], - self.origin[1] - self.r_grid[-1], - self.origin[2] + self.z_grid[0] - )) + @r_grid.setter + def r_grid(self, grid): + cv.check_type('mesh r_grid', grid, Iterable, Real) + self._r_grid = np.asarray(grid) - @property - def upper_right(self): - return np.array(( - self.origin[0] + self.r_grid[-1], - self.origin[1] + self.r_grid[-1], - self.origin[2] + self.z_grid[-1] - )) + @phi_grid.setter + def phi_grid(self, grid): + cv.check_type('mesh phi_grid', grid, Iterable, Real) + self._phi_grid = np.asarray(grid) + + @z_grid.setter + def z_grid(self, grid): + cv.check_type('mesh z_grid', grid, Iterable, Real) + self._z_grid = np.asarray(grid) def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() string += fmt.format('\tDimensions', '=\t', self.n_dimension) - string += fmt.format('\tOrigin', '=\t', self.origin) r_grid_str = str(self._r_grid) if self._r_grid is None else len(self._r_grid) string += fmt.format('\tN R pnts:', '=\t', r_grid_str) if self._r_grid is not None: @@ -2025,160 +1078,30 @@ class CylindricalMesh(StructuredMesh): string += fmt.format('\tZ Max:', '=\t', self._z_grid[-1]) return string - def get_indices_at_coords( - self, - coords: Sequence[float] - ) -> tuple[int, int, int]: - """Finds the index of the mesh element at the specified coordinates. - - .. versionadded:: 0.15.0 - - Parameters - ---------- - coords : Sequence[float] - Cartesian coordinates of the point. - - Returns - ------- - tuple[int, int, int] - The r, phi, z indices - - """ - r_value_from_origin = math.hypot(coords[0]-self.origin[0], coords[1]-self.origin[1]) - - if r_value_from_origin < self.r_grid[0] or r_value_from_origin > self.r_grid[-1]: - raise ValueError( - f'The specified x, y ({coords[0]}, {coords[1]}) combine to give an r value of ' - f'{r_value_from_origin} from the origin of {self.origin}.which ' - f'is outside the origin absolute r grid values {self.r_grid}.' - ) - - r_index = np.searchsorted(self.r_grid, r_value_from_origin) - 1 - - z_grid_values = np.array(self.z_grid) + self.origin[2] - - if coords[2] < z_grid_values[0] or coords[2] > z_grid_values[-1]: - raise ValueError( - f'The specified z value ({coords[2]}) from the z origin of ' - f'{self.origin[-1]} is outside of the absolute z grid range {z_grid_values}.' - ) - - z_index = np.argmax(z_grid_values > coords[2]) - 1 - - delta_x = coords[0] - self.origin[0] - delta_y = coords[1] - self.origin[1] - # atan2 returns values in -pi to +pi range - phi_value = math.atan2(delta_y, delta_x) - if delta_x < 0 and delta_y < 0: - # returned phi_value anticlockwise and negative - phi_value += 2 * math.pi - if delta_x > 0 and delta_y < 0: - # returned phi_value anticlockwise and negative - phi_value += 2 * math.pi - - phi_grid_values = np.array(self.phi_grid) - - if phi_value < phi_grid_values[0] or phi_value > phi_grid_values[-1]: - raise ValueError( - f'The phi value ({phi_value}) resulting from the specified x, y ' - f'values is outside of the absolute phi grid range {phi_grid_values}.' - ) - phi_index = np.argmax(phi_grid_values > phi_value) - 1 - - return (r_index, phi_index, z_index) - @classmethod - def from_hdf5(cls, group: h5py.Group, mesh_id: int, name: str): + def from_hdf5(cls, group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + # Read and assign mesh properties - mesh = cls( - mesh_id=mesh_id, - name=name, - r_grid = group['r_grid'][()], - phi_grid = group['phi_grid'][()], - z_grid = group['z_grid'][()], - ) - if 'origin' in group: - mesh.origin = group['origin'][()] + mesh = cls(mesh_id) + mesh.r_grid = group['r_grid'][()] + mesh.phi_grid = group['phi_grid'][()] + mesh.z_grid = group['z_grid'][()] return mesh - @classmethod - def from_bounding_box( - cls, - bbox: openmc.BoundingBox, - dimension: Sequence[int] = (10, 10, 10), - mesh_id: int | None = None, - name: str = '', - phi_grid_bounds: Sequence[float] = (0.0, 2*math.pi), - enclose_domain: bool = False, - ) -> CylindricalMesh: - """Create CylindricalMesh from a bounding box. - - Parameters - ---------- - bbox : openmc.BoundingBox - Bounding box used to set the r_grid and z_grid ranges. - dimension : Iterable of int - The number of equally spaced mesh cells in each direction (r_grid, - phi_grid, z_grid) - mesh_id : int, optional - Unique identifier for the mesh - name : str, optional - Name of the mesh - phi_grid_bounds : numpy.ndarray - Mesh bounds points along the phi-axis in radians. The default value - is (0, 2π), i.e., the full phi range. - enclose_domain : bool - If True, the mesh will encompass the bounding box of the domain. If - False, the mesh will be inscribed within the domain's bounding box. - - Returns - ------- - openmc.CylindricalMesh - CylindricalMesh instance - - """ - if enclose_domain: - outer_radius = 0.5 * np.linalg.norm(bbox.width[:2]) - else: - outer_radius = 0.5 * min(bbox.width[:2]) - - r_grid = np.linspace(0, outer_radius, num=dimension[0]+1) - phi_grid = np.linspace( - phi_grid_bounds[0], - phi_grid_bounds[1], - num=dimension[1]+1 - ) - z_grid = np.linspace( - bbox[0][2], - bbox[1][2], - num=dimension[2]+1 - ) - origin = (bbox.center[0], bbox.center[1], z_grid[0]) - - # make z-grid relative to the origin - z_grid -= origin[2] - - return cls( - r_grid=r_grid, - z_grid=z_grid, - phi_grid=phi_grid, - mesh_id=mesh_id, - name=name, - origin=origin - ) - def to_xml_element(self): """Return XML representation of the mesh Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing mesh data """ - element = super().to_xml_element() + element = ET.Element("mesh") + element.set("id", str(self._id)) element.set("type", "cylindrical") subelement = ET.SubElement(element, "r_grid") @@ -2190,18 +1113,15 @@ class CylindricalMesh(StructuredMesh): subelement = ET.SubElement(element, "z_grid") subelement.text = ' '.join(map(str, self.z_grid)) - subelement = ET.SubElement(element, "origin") - subelement.text = ' '.join(map(str, self.origin)) - return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate a cylindrical mesh from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -2212,14 +1132,10 @@ class CylindricalMesh(StructuredMesh): """ mesh_id = int(get_text(elem, 'id')) - mesh = cls( - r_grid = get_elem_list(elem, "r_grid", float), - phi_grid = get_elem_list(elem, "phi_grid", float), - z_grid = get_elem_list(elem, "z_grid", float), - origin = get_elem_list(elem, "origin", float) or [0., 0., 0.], - mesh_id=mesh_id, - ) - + mesh = cls(mesh_id) + mesh.r_grid = [float(x) for x in get_text(elem, "r_grid").split()] + mesh.phi_grid = [float(x) for x in get_text(elem, "phi_grid").split()] + mesh.z_grid = [float(x) for x in get_text(elem, "z_grid").split()] return mesh @property @@ -2239,58 +1155,52 @@ class CylindricalMesh(StructuredMesh): return np.multiply.outer(np.outer(V_r, V_p), V_z) - @property - def vertices(self): - warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') - return self._convert_to_cartesian(self.vertices_cylindrical, self.origin) + def write_data_to_vtk(self, filename, datasets, volume_normalization=True): + """Creates a VTK object of the mesh - @property - def vertices_cylindrical(self): - """Returns vertices of the mesh in cylindrical coordinates. + Parameters + ---------- + filename : str or pathlib.Path + Name of the VTK file to write. + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + volume_normalization : bool, optional + Whether or not to normalize the data by + the volume of the mesh elements. + Defaults to True. + + Returns + ------- + vtk.vtkStructuredGrid + the VTK object """ - return super().vertices - - @property - def centroids(self): - warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') - return self._convert_to_cartesian(self.centroids_cylindrical, self.origin) - - @property - def centroids_cylindrical(self): - """Returns centroids of the mesh in cylindrical coordinates. - """ - return super().centroids - - @staticmethod - def _convert_to_cartesian(arr, origin: Sequence[float]): - """Converts an array with r, phi, z values in the last dimension (shape (..., 3)) - to Cartesian coordinates. - """ - x = arr[..., 0] * np.cos(arr[..., 1]) + origin[0] - y = arr[..., 0] * np.sin(arr[..., 1]) + origin[1] - arr[..., 0] = x - arr[..., 1] = y - arr[..., 2] += origin[2] - return arr + # create points + pts_cylindrical = np.array( + [ + [r, phi, z] + for z in self.z_grid + for phi in self.phi_grid + for r in self.r_grid + ] + ) + pts_cartesian = np.copy(pts_cylindrical) + r, phi = pts_cylindrical[:, 0], pts_cylindrical[:, 1] + pts_cartesian[:, 0] = r * np.cos(phi) + pts_cartesian[:, 1] = r * np.sin(phi) + return super().write_data_to_vtk( + points=pts_cartesian, + filename=filename, + datasets=datasets, + volume_normalization=volume_normalization + ) class SphericalMesh(StructuredMesh): """A 3D spherical mesh Parameters ---------- - r_grid : numpy.ndarray - 1-D array of mesh boundary points along the r-axis. - Requirement is r >= 0. - phi_grid : numpy.ndarray - 1-D array of mesh boundary points along the phi-axis in radians. - The default value is [0, 2π], i.e. the full phi range. - theta_grid : numpy.ndarray - 1-D array of mesh boundary points along the theta-axis in radians. - The default value is [0, π], i.e. the full theta range. - origin : numpy.ndarray - 1-D array of length 3 the (x,y,z) origin of the mesh in - cartesian coordinates mesh_id : int Unique identifier for the mesh name : str @@ -2303,8 +1213,7 @@ class SphericalMesh(StructuredMesh): name : str Name of the mesh dimension : Iterable of int - The number of mesh cells in each direction (r_grid, - theta_grid, phi_grid). + The number of mesh cells in each direction. n_dimension : int Number of mesh dimensions (always 3 for a SphericalMesh). r_grid : numpy.ndarray @@ -2316,39 +1225,18 @@ class SphericalMesh(StructuredMesh): phi_grid : numpy.ndarray 1-D array of mesh boundary points along the phi-axis in radians. The default value is [0, 2π], i.e. the full phi range. - origin : numpy.ndarray - 1-D array of length 3 the (x,y,z) origin of the mesh in - cartesian coordinates indices : Iterable of tuple An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] - lower_left : numpy.ndarray - The lower-left corner of the structured mesh. If only two coordinate - are given, it is assumed that the mesh is an x-y mesh. - upper_right : numpy.ndarray - The upper-right corner of the structured mesh. If only two coordinate - are given, it is assumed that the mesh is an x-y mesh. - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh as defined by the upper-right and - lower-left coordinates. """ - def __init__( - self, - r_grid: Sequence[float], - phi_grid: Sequence[float] = (0, 2*math.pi), - theta_grid: Sequence[float] = (0, math.pi), - origin: Sequence[float] = (0., 0., 0.), - mesh_id: int | None = None, - name: str = '', - ): + def __init__(self, mesh_id=None, name=''): super().__init__(mesh_id, name) - self.r_grid = r_grid - self.theta_grid = theta_grid - self.phi_grid = phi_grid - self.origin = origin + self._r_grid = None + self._theta_grid = [0, pi] + self._phi_grid = [0, 2*pi] @property def dimension(self): @@ -2360,59 +1248,18 @@ class SphericalMesh(StructuredMesh): def n_dimension(self): return 3 - @property - def _axis_labels(self): - return ('r', 'theta', 'phi') - - @property - def origin(self): - return self._origin - - @origin.setter - def origin(self, coords): - cv.check_type('mesh origin', coords, Iterable, Real) - cv.check_length("mesh origin", coords, 3) - self._origin = np.asarray(coords, dtype=float) - @property def r_grid(self): return self._r_grid - @r_grid.setter - def r_grid(self, grid): - cv.check_type('mesh r_grid', grid, Iterable, Real) - cv.check_length('mesh r_grid', grid, 2) - cv.check_increasing('mesh r_grid', grid) - self._r_grid = np.asarray(grid, dtype=float) - @property def theta_grid(self): return self._theta_grid - @theta_grid.setter - def theta_grid(self, grid): - cv.check_type('mesh theta_grid', grid, Iterable, Real) - cv.check_length('mesh theta_grid', grid, 2) - cv.check_increasing('mesh theta_grid', grid) - grid = np.asarray(grid, dtype=float) - if np.any((grid < 0.0) | (grid > math.pi)): - raise ValueError("theta_grid values must be in [0, π].") - self._theta_grid = grid - @property def phi_grid(self): return self._phi_grid - @phi_grid.setter - def phi_grid(self, grid): - cv.check_type('mesh phi_grid', grid, Iterable, Real) - cv.check_length('mesh phi_grid', grid, 2) - cv.check_increasing('mesh phi_grid', grid) - grid = np.asarray(grid, dtype=float) - if np.any((grid < 0.0) | (grid > 2*math.pi)): - raise ValueError("phi_grid values must be in [0, 2π].") - self._phi_grid = grid - @property def _grids(self): return (self.r_grid, self.theta_grid, self.phi_grid) @@ -2427,21 +1274,25 @@ class SphericalMesh(StructuredMesh): for t in range(1, nt + 1) for r in range(1, nr + 1)) - @property - def lower_left(self): - r = self.r_grid[-1] - return np.array((self.origin[0] - r, self.origin[1] - r, self.origin[2] - r)) + @r_grid.setter + def r_grid(self, grid): + cv.check_type('mesh r_grid', grid, Iterable, Real) + self._r_grid = np.asarray(grid) - @property - def upper_right(self): - r = self.r_grid[-1] - return np.array((self.origin[0] + r, self.origin[1] + r, self.origin[2] + r)) + @theta_grid.setter + def theta_grid(self, grid): + cv.check_type('mesh theta_grid', grid, Iterable, Real) + self._theta_grid = np.asarray(grid) + + @phi_grid.setter + def phi_grid(self, grid): + cv.check_type('mesh phi_grid', grid, Iterable, Real) + self._phi_grid = np.asarray(grid) def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() string += fmt.format('\tDimensions', '=\t', self.n_dimension) - string += fmt.format('\tOrigin', '=\t', self.origin) r_grid_str = str(self._r_grid) if self._r_grid is None else len(self._r_grid) string += fmt.format('\tN R pnts:', '=\t', r_grid_str) if self._r_grid is not None: @@ -2460,93 +1311,29 @@ class SphericalMesh(StructuredMesh): return string @classmethod - def from_hdf5(cls, group: h5py.Group, mesh_id: int, name: str): + def from_hdf5(cls, group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + # Read and assign mesh properties - mesh = cls( - r_grid = group['r_grid'][()], - theta_grid = group['theta_grid'][()], - phi_grid = group['phi_grid'][()], - mesh_id=mesh_id, - name=name - ) - if 'origin' in group: - mesh.origin = group['origin'][()] + mesh = cls(mesh_id) + mesh.r_grid = group['r_grid'][()] + mesh.theta_grid = group['theta_grid'][()] + mesh.phi_grid = group['phi_grid'][()] return mesh - @classmethod - def from_bounding_box( - cls, - bbox: openmc.BoundingBox, - dimension: Sequence[int] = (10, 10, 10), - mesh_id: int | None = None, - name: str = '', - phi_grid_bounds: Sequence[float] = (0.0, 2*math.pi), - theta_grid_bounds: Sequence[float] = (0.0, math.pi), - enclose_domain: bool = False, - ) -> SphericalMesh: - """Create SphericalMesh from a bounding box. - - Parameters - ---------- - bbox : openmc.BoundingBox - Bounding box used to set the r_grid, phi_grid, and theta_grid ranges. - dimension : Iterable of int - The number of equally spaced mesh cells in each direction (r_grid, - phi_grid, theta_grid). Spacing is in angular space (radians) for - phi and theta, and in absolute space for r. - mesh_id : int, optional - Unique identifier for the mesh - name : str, optional - Name of the mesh - phi_grid_bounds : numpy.ndarray - Mesh bounds points along the phi-axis in radians. The default value - is (0, 2π), i.e., the full phi range. - theta_grid_bounds : numpy.ndarray - Mesh bounds points along the theta-axis in radians. The default value - is (0, π), i.e., the full theta range. - enclose_domain : bool - If True, the mesh will encompass the bounding box of the domain. If - False, the mesh will be inscribed within the domain's bounding box. - - Returns - ------- - openmc.SphericalMesh - SphericalMesh instance - - """ - if enclose_domain: - outer_radius = 0.5 * np.linalg.norm(bbox.width) - else: - outer_radius = 0.5 * min(bbox.width) - - r_grid = np.linspace(0, outer_radius, num=dimension[0] + 1) - theta_grid = np.linspace( - theta_grid_bounds[0], - theta_grid_bounds[1], - num=dimension[1]+1 - ) - phi_grid = np.linspace( - phi_grid_bounds[0], - phi_grid_bounds[1], - num=dimension[2]+1 - ) - origin = np.array([bbox.center[0], bbox.center[1], bbox.center[2]]) - - return cls(r_grid=r_grid, phi_grid=phi_grid, theta_grid=theta_grid, - origin=origin, mesh_id=mesh_id, name=name) - def to_xml_element(self): """Return XML representation of the mesh Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing mesh data """ - element = super().to_xml_element() + element = ET.Element("mesh") + element.set("id", str(self._id)) element.set("type", "spherical") subelement = ET.SubElement(element, "r_grid") @@ -2558,18 +1345,15 @@ class SphericalMesh(StructuredMesh): subelement = ET.SubElement(element, "phi_grid") subelement.text = ' '.join(map(str, self.phi_grid)) - subelement = ET.SubElement(element, "origin") - subelement.text = ' '.join(map(str, self.origin)) - return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate a spherical mesh from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -2578,15 +1362,12 @@ class SphericalMesh(StructuredMesh): Spherical mesh object """ - mesh_id = int(get_text(elem, 'id')) - mesh = cls( - mesh_id=mesh_id, - r_grid = get_elem_list(elem, "r_grid", float), - theta_grid = get_elem_list(elem, "theta_grid", float), - phi_grid = get_elem_list(elem, "phi_grid", float), - origin = get_elem_list(elem, "origin", float) or [0., 0., 0.], - ) + mesh_id = int(get_text(elem, 'id')) + mesh = cls(mesh_id) + mesh.r_grid = [float(x) for x in get_text(elem, "r_grid").split()] + mesh.theta_grid = [float(x) for x in get_text(elem, "theta_grid").split()] + mesh.phi_grid = [float(x) for x in get_text(elem, "phi_grid").split()] return mesh @property @@ -2606,130 +1387,48 @@ class SphericalMesh(StructuredMesh): return np.multiply.outer(np.outer(V_r, V_t), V_p) - @property - def vertices(self): - warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') - return self._convert_to_cartesian(self.vertices_spherical, self.origin) - - @property - def vertices_spherical(self): - """Returns vertices of the mesh in cylindrical coordinates. - """ - return super().vertices - - @property - def centroids(self): - warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') - return self._convert_to_cartesian(self.centroids_spherical, self.origin) - - @property - def centroids_spherical(self): - """Returns centroids of the mesh in cylindrical coordinates. - """ - return super().centroids - - - @staticmethod - def _convert_to_cartesian(arr, origin: Sequence[float]): - """Converts an array with r, theta, phi values in the last dimension (shape (..., 3)) - to Cartesian coordinates. - """ - r_xy = arr[..., 0] * np.sin(arr[..., 1]) - x = r_xy * np.cos(arr[..., 2]) - y = r_xy * np.sin(arr[..., 2]) - z = arr[..., 0] * np.cos(arr[..., 1]) - arr[..., 0] = x + origin[0] - arr[..., 1] = y + origin[1] - arr[..., 2] = z + origin[2] - return arr - - def get_indices_at_coords( - self, - coords: Sequence[float] - ) -> tuple[int, int, int]: - """Find the mesh cell indices containing the specified coordinates. - - .. versionadded:: 0.15.4 + def write_data_to_vtk(self, filename, datasets, volume_normalization=True): + """Creates a VTK object of the mesh Parameters ---------- - coords : Sequence[float] - Cartesian coordinates of the point as (x, y, z). + filename : str or pathlib.Path + Name of the VTK file to write. + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + volume_normalization : bool, optional + Whether or not to normalize the data by + the volume of the mesh elements. + Defaults to True. Returns ------- - tuple[int, int, int] - The r, theta, phi indices. - - Raises - ------ - ValueError - If the coordinates fall outside the mesh grid boundaries. - + vtk.vtkStructuredGrid + the VTK object """ - dx = coords[0] - self.origin[0] - dy = coords[1] - self.origin[1] - dz = coords[2] - self.origin[2] - r_value = math.hypot(dx, dy, dz) + # create points + pts_spherical = np.array( + [ + [r, theta, phi] + for phi in self.phi_grid + for theta in self.theta_grid + for r in self.r_grid + ] + ) + pts_cartesian = np.copy(pts_spherical) + r, theta, phi = pts_spherical[:, 0], pts_spherical[:, 1], pts_spherical[:, 2] + pts_cartesian[:, 0] = r * np.sin(phi) * np.cos(theta) + pts_cartesian[:, 1] = r * np.sin(phi) * np.sin(theta) + pts_cartesian[:, 2] = r * np.cos(phi) - if r_value < self.r_grid[0] or r_value > self.r_grid[-1]: - raise ValueError( - f'The r value {r_value} computed from the specified ' - f'coordinates is outside the r grid range ' - f'[{self.r_grid[0]}, {self.r_grid[-1]}].' - ) - - r_index = int(min( - np.searchsorted(self.r_grid, r_value, side='right') - 1, - len(self.r_grid) - 2 - )) - - if r_value == 0.0: - theta_value = 0.0 - phi_value = 0.0 - else: - theta_value = math.acos(dz / r_value) - phi_value = math.atan2(dy, dx) - if phi_value < 0: - phi_value += 2 * math.pi - - if theta_value < self.theta_grid[0] or theta_value > self.theta_grid[-1]: - raise ValueError( - f'The theta value {theta_value} computed from the specified ' - f'coordinates is outside the theta grid range ' - f'[{self.theta_grid[0]}, {self.theta_grid[-1]}].' - ) - - theta_index = int(min( - np.searchsorted(self.theta_grid, theta_value, side='right') - 1, - len(self.theta_grid) - 2 - )) - - if phi_value < self.phi_grid[0] or phi_value > self.phi_grid[-1]: - raise ValueError( - f'The phi value {phi_value} computed from the specified ' - f'coordinates is outside the phi grid range ' - f'[{self.phi_grid[0]}, {self.phi_grid[-1]}].' - ) - - phi_index = int(min( - np.searchsorted(self.phi_grid, phi_value, side='right') - 1, - len(self.phi_grid) - 2 - )) - - return (r_index, theta_index, phi_index) - - -def require_statepoint_data(func): - @wraps(func) - def wrapper(self: UnstructuredMesh, *args, **kwargs): - if not self._has_statepoint_data: - raise AttributeError(f'The "{func.__name__}" property requires ' - 'information about this mesh to be loaded ' - 'from a statepoint file.') - return func(self, *args, **kwargs) - return wrapper + return super().write_data_to_vtk( + points=pts_cartesian, + filename=filename, + datasets=datasets, + volume_normalization=volume_normalization + ) class UnstructuredMesh(MeshBase): @@ -2742,10 +1441,8 @@ class UnstructuredMesh(MeshBase): Parameters ---------- - filename : path-like - Location of the unstructured mesh file. Supported files for 'moab' - library are .h5 and .vtk. Supported files for 'libmesh' library are - exodus mesh files .exo. + filename : str or pathlib.Path + Location of the unstructured mesh file library : {'moab', 'libmesh'} Mesh library used for the unstructured mesh tally mesh_id : int @@ -2754,11 +1451,6 @@ class UnstructuredMesh(MeshBase): Name of the mesh length_multiplier: float Constant multiplier to apply to mesh coordinates - options : str, optional - Special options that control spatial search data structures used. This - is currently only used to set `parameters - `_ for MOAB's AdaptiveKDTree. If - None, OpenMC internally uses a default of "MAX_DEPTH=20;PLANE_SET=2;". Attributes ---------- @@ -2772,14 +1464,9 @@ class UnstructuredMesh(MeshBase): Multiplicative factor to apply to mesh coordinates library : {'moab', 'libmesh'} Mesh library used for the unstructured mesh tally - options : str - Special options that control spatial search data structures used. This - is currently only used to set `parameters - `_ for MOAB's AdaptiveKDTree. If - None, OpenMC internally uses a default of "MAX_DEPTH=20;PLANE_SET=2;". output : bool - Indicates whether or not automatic tally output should be generated for - this mesh + Indicates whether or not automatic tally output should + be generated for this mesh volumes : Iterable of float Volumes of the unstructured mesh elements centroids : numpy.ndarray @@ -2799,21 +1486,14 @@ class UnstructuredMesh(MeshBase): .. versionadded:: 0.13.1 total_volume : float Volume of the unstructured mesh in total - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the mesh as defined by the upper-right and - lower-left coordinates. - """ _UNSUPPORTED_ELEM = -1 _LINEAR_TET = 0 _LINEAR_HEX = 1 - _VTK_TET = 10 - _VTK_HEX = 12 - def __init__(self, filename: PathLike, library: str, mesh_id: int | None = None, - name: str = '', length_multiplier: float = 1.0, - options: str | None = None): + def __init__(self, filename, library, mesh_id=None, name='', + length_multiplier=1.0): super().__init__(mesh_id, name) self.filename = filename self._volumes = None @@ -2823,8 +1503,6 @@ class UnstructuredMesh(MeshBase): self.library = library self._output = False self.length_multiplier = length_multiplier - self.options = options - self._has_statepoint_data = False @property def filename(self): @@ -2832,34 +1510,24 @@ class UnstructuredMesh(MeshBase): @filename.setter def filename(self, filename): - cv.check_type('Unstructured Mesh filename', filename, PathLike) - self._filename = input_path(filename) + cv.check_type('Unstructured Mesh filename', filename, (str, Path)) + self._filename = filename @property def library(self): return self._library @library.setter - def library(self, lib: str): + def library(self, lib): cv.check_value('Unstructured mesh library', lib, ('moab', 'libmesh')) self._library = lib @property - def options(self) -> str | None: - return self._options - - @options.setter - def options(self, options: str | None): - cv.check_type('options', options, (str, type(None))) - self._options = options - - @property - @require_statepoint_data def size(self): return self._size @size.setter - def size(self, size: int): + def size(self, size): cv.check_type("Unstructured mesh size", size, Integral) self._size = size @@ -2868,12 +1536,11 @@ class UnstructuredMesh(MeshBase): return self._output @output.setter - def output(self, val: bool): + def output(self, val): cv.check_type("Unstructured mesh output value", val, bool) self._output = val @property - @require_statepoint_data def volumes(self): """Return Volumes for every mesh cell if populated by a StatePoint file @@ -2887,37 +1554,31 @@ class UnstructuredMesh(MeshBase): return self._volumes @volumes.setter - def volumes(self, volumes: Iterable[Real]): + def volumes(self, volumes): cv.check_type("Unstructured mesh volumes", volumes, Iterable, Real) self._volumes = volumes @property - @require_statepoint_data def total_volume(self): return np.sum(self.volumes) @property - @require_statepoint_data def vertices(self): return self._vertices @property - @require_statepoint_data def connectivity(self): return self._connectivity @property - @require_statepoint_data def element_types(self): return self._element_types @property - @require_statepoint_data def centroids(self): return np.array([self.centroid(i) for i in range(self.n_elements)]) @property - @require_statepoint_data def n_elements(self): if self._n_elements is None: raise RuntimeError("No information about this mesh has " @@ -2925,7 +1586,7 @@ class UnstructuredMesh(MeshBase): return self._n_elements @n_elements.setter - def n_elements(self, val: int): + def n_elements(self, val): cv.check_type('Number of elements', val, Integral) self._n_elements = val @@ -2948,19 +1609,6 @@ class UnstructuredMesh(MeshBase): def n_dimension(self): return 3 - @property - def _axis_labels(self): - return ('element_index',) - - @property - @require_statepoint_data - def indices(self): - return [(i,) for i in range(self.n_elements)] - - @property - def has_statepoint_data(self) -> bool: - return self._has_statepoint_data - def __repr__(self): string = super().__repr__() string += '{: <16}=\t{}\n'.format('\tFilename', self.filename) @@ -2968,22 +1616,9 @@ class UnstructuredMesh(MeshBase): if self.length_multiplier != 1.0: string += '{: <16}=\t{}\n'.format('\tLength multiplier', self.length_multiplier) - if self.options is not None: - string += '{: <16}=\t{}\n'.format('\tOptions', self.options) return string - @property - @require_statepoint_data - def lower_left(self): - return self.vertices.min(axis=0) - - @property - @require_statepoint_data - def upper_right(self): - return self.vertices.max(axis=0) - - @require_statepoint_data - def centroid(self, bin: int): + def centroid(self, bin): """Return the vertex averaged centroid of an element Parameters @@ -3023,145 +1658,90 @@ class UnstructuredMesh(MeshBase): warnings.warn( "The 'UnstructuredMesh.write_vtk_mesh' method has been renamed " "to 'write_data_to_vtk' and will be removed in a future version " - " of OpenMC.", - FutureWarning, + " of OpenMC.", FutureWarning ) self.write_data_to_vtk(**kwargs) - def write_data_to_vtk( - self, - filename: PathLike | None = None, - datasets: dict | None = None, - volume_normalization: bool = True, - ): + def write_data_to_vtk(self, filename=None, datasets=None, volume_normalization=True): """Map data to unstructured VTK mesh elements. - If filename is None, then a filename will be generated based on the mesh - ID, and exported to VTK format. - Parameters ---------- filename : str or pathlib.Path - Name of the VTK file to write. If the filename ends in '.vtkhdf' - then a VTKHDF format file will be written. If the filename ends in - '.vtu' then a binary VTU format file will be written. If the - filename ends in '.vtk' then a legacy VTK file will be written. + Name of the VTK file to write datasets : dict - Dictionary whose keys are the data labels and values are numpy - appropriately sized arrays of the data + Dictionary whose keys are the data labels + and values are numpy appropriately sized arrays + of the data volume_normalization : bool - Whether or not to normalize the data by the volume of the mesh - elements + Whether or not to normalize the data by the + volume of the mesh elements """ - - if Path(filename).suffix == ".vtkhdf": - - self._write_data_to_vtk_hdf5_format( - filename=filename, - datasets=datasets, - volume_normalization=volume_normalization, - ) - - elif Path(filename).suffix == ".vtk" or Path(filename).suffix == ".vtu": - - self._write_data_to_vtk_ascii_format( - filename=filename, - datasets=datasets, - volume_normalization=volume_normalization, - ) - - else: - raise ValueError( - "Unsupported file extension, The filename must end with " - "'.vtkhdf', '.vtu' or '.vtk'" - ) - - def _write_data_to_vtk_ascii_format( - self, - filename: PathLike | None = None, - datasets: dict | None = None, - volume_normalization: bool = True, - ): - from vtkmodules.util import numpy_support - from vtkmodules import vtkCommonCore - from vtkmodules import vtkCommonDataModel - from vtkmodules import vtkIOLegacy - from vtkmodules import vtkIOXML + import vtk + from vtk.util import numpy_support as nps if self.connectivity is None or self.vertices is None: - raise RuntimeError("This mesh has not been loaded from a statepoint file.") + raise RuntimeError('This mesh has not been ' + 'loaded from a statepoint file.') if filename is None: - filename = f"mesh_{self.id}.vtk" + filename = f'mesh_{self.id}.vtk' - if Path(filename).suffix == ".vtk": - writer = vtkIOLegacy.vtkUnstructuredGridWriter() - - elif Path(filename).suffix == ".vtu": - writer = vtkIOXML.vtkXMLUnstructuredGridWriter() - writer.SetCompressorTypeToZLib() - writer.SetDataModeToBinary() + writer = vtk.vtkUnstructuredGridWriter() writer.SetFileName(str(filename)) - grid = vtkCommonDataModel.vtkUnstructuredGrid() + grid = vtk.vtkUnstructuredGrid() - points = vtkCommonCore.vtkPoints() - points.SetData(numpy_support.numpy_to_vtk(self.vertices)) - grid.SetPoints(points) + vtk_pnts = vtk.vtkPoints() + vtk_pnts.SetData(nps.numpy_to_vtk(self.vertices)) + grid.SetPoints(vtk_pnts) n_skipped = 0 + elems = [] for elem_type, conn in zip(self.element_types, self.connectivity): if elem_type == self._LINEAR_TET: - elem = vtkCommonDataModel.vtkTetra() + elem = vtk.vtkTetra() elif elem_type == self._LINEAR_HEX: - elem = vtkCommonDataModel.vtkHexahedron() + elem = vtk.vtkHexahedron() elif elem_type == self._UNSUPPORTED_ELEM: n_skipped += 1 - continue else: - raise RuntimeError( - f"Invalid element type {elem_type} found in mesh {self.id}" - ) - + raise RuntimeError(f'Invalid element type {elem_type} found') for i, c in enumerate(conn): if c == -1: break elem.GetPointIds().SetId(i, c) - - grid.InsertNextCell(elem.GetCellType(), elem.GetPointIds()) + elems.append(elem) if n_skipped > 0: - warnings.warn( - f"{n_skipped} elements were not written because " - "they are not of type linear tet/hex" - ) + warnings.warn(f'{n_skipped} elements were not written because ' + 'they are not of type linear tet/hex') + + for elem in elems: + grid.InsertNextCell(elem.GetCellType(), elem.GetPointIds()) # check that datasets are the correct size datasets_out = [] if datasets is not None: for name, data in datasets.items(): if data.shape != self.dimension: - raise ValueError( - f'Cannot apply dataset "{name}" with ' - f"shape {data.shape} to mesh {self.id} " - f"with dimensions {self.dimension}" - ) + raise ValueError(f'Cannot apply dataset "{name}" with ' + f'shape {data.shape} to mesh {self.id} ' + f'with dimensions {self.dimension}') if volume_normalization: for name, data in datasets.items(): if np.issubdtype(data.dtype, np.integer): - warnings.warn( - f'Integer data set "{name}" will ' - "not be volume-normalized." - ) + warnings.warn(f'Integer data set "{name}" will ' + 'not be volume-normalized.') continue data /= self.volumes # add data to the mesh for name, data in datasets.items(): datasets_out.append(data) - arr = vtkCommonCore.vtkDoubleArray() + arr = vtk.vtkDoubleArray() arr.SetName(name) arr.SetNumberOfTuples(data.size) @@ -3173,120 +1753,25 @@ class UnstructuredMesh(MeshBase): writer.Write() - def _write_data_to_vtk_hdf5_format( - self, - filename: PathLike | None = None, - datasets: dict | None = None, - volume_normalization: bool = True, - ): - # This writer supports linear tetrahedra and linear hexahedra elements - conn_list = [] # flattened connectivity ids - cell_sizes = [] # number of points per cell - vtk_types = [] # VTK cell types per cell (uint8) - n_skipped = 0 - - for conn, etype in zip(self.connectivity, self.element_types): - if etype == self._LINEAR_TET: - ids = conn[:4] - vtk_types.append(self._VTK_TET) - elif etype == self._LINEAR_HEX: - ids = conn[:8] - vtk_types.append(self._VTK_HEX) - elif etype == self._UNSUPPORTED_ELEM: - n_skipped += 1 - continue - else: - raise RuntimeError( - f"Invalid element type {etype} found in mesh {self.id}" - ) - conn_list.extend(ids.tolist()) - cell_sizes.append(len(ids)) - - if n_skipped > 0: - warnings.warn( - f"{n_skipped} elements were not written because " - "they are not of type linear tet/hex" - ) - - connectivity = np.asarray(conn_list, dtype=np.int64) - - # Offsets must be length (numCells + 1) with a leading 0 and - # cumulative end-indices thereafter, per VTK's layout - cell_sizes_arr = np.asarray(cell_sizes, dtype=np.int64) - offsets = np.zeros(cell_sizes_arr.size + 1, dtype=np.int64) - np.cumsum(cell_sizes_arr, out=offsets[1:]) - - for name, data in datasets.items(): - if data.shape != self.dimension: - raise ValueError( - f'Cannot apply dataset "{name}" with ' - f"shape {data.shape} to mesh {self.id} " - f"with dimensions {self.dimension}" - ) - - with h5py.File(filename, "w") as f: - - root = f.create_group("VTKHDF") - vtk_file_format_version = (2, 1) - root.attrs["Version"] = vtk_file_format_version - ascii_type = "UnstructuredGrid".encode("ascii") - root.attrs.create( - "Type", - ascii_type, - dtype=h5py.string_dtype("ascii", len(ascii_type)), - ) - - # Create HDF5 file structure compliant with VTKHDF UnstructuredGrid - n_points = int(len(self.vertices)) - n_cells = int(len(cell_sizes)) - n_conn_ids = int(len(connectivity)) - - root.create_dataset("NumberOfPoints", data=(n_points,), dtype="i8") - root.create_dataset("NumberOfCells", data=(n_cells,), dtype="i8") - root.create_dataset("NumberOfConnectivityIds", data=(n_conn_ids,), dtype="i8") - root.create_dataset("Points", data=self.vertices.astype(np.float64, copy=False), dtype="f8") - root.create_dataset("Types", data=np.asarray(vtk_types, dtype=np.uint8), dtype="uint8") - root.create_dataset("Offsets", data=offsets.astype("i8"), dtype="i8") - root.create_dataset("Connectivity", data=connectivity.astype("i8"), dtype="i8") - - cell_data_group = root.create_group("CellData") - - for name, data in datasets.items(): - if volume_normalization: - data /= self.volumes - cell_data_group.create_dataset( - name, data=data, dtype="float64", chunks=True - ) - @classmethod - def from_hdf5(cls, group: h5py.Group, mesh_id: int, name: str): - filename = group["filename"][()].decode() - library = group["library"][()].decode() - if "options" in group.attrs: - options = group.attrs['options'].decode() - else: - options = None + def from_hdf5(cls, group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + filename = group['filename'][()].decode() + library = group['library'][()].decode() - mesh = cls( - filename=filename, - library=library, - mesh_id=mesh_id, - name=name, - options=options, - ) - mesh._has_statepoint_data = True - vol_data = group["volumes"][()] + mesh = cls(filename, library, mesh_id=mesh_id) + vol_data = group['volumes'][()] mesh.volumes = np.reshape(vol_data, (vol_data.shape[0],)) mesh.n_elements = mesh.volumes.size - vertices = group["vertices"][()] + vertices = group['vertices'][()] mesh._vertices = vertices.reshape((-1, 3)) - connectivity = group["connectivity"][()] + connectivity = group['connectivity'][()] mesh._connectivity = connectivity.reshape((-1, 8)) - mesh._element_types = group["element_types"][()] + mesh._element_types = group['element_types'][()] - if "length_multiplier" in group: - mesh.length_multiplier = group["length_multiplier"][()] + if 'length_multiplier' in group: + mesh.length_multiplier = group['length_multiplier'][()] return mesh @@ -3295,17 +1780,15 @@ class UnstructuredMesh(MeshBase): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing mesh data """ - element = super().to_xml_element() + element = ET.Element("mesh") + element.set("id", str(self._id)) element.set("type", "unstructured") - element.set("library", self._library) - if self.options is not None: - element.set("options", self.options) subelement = ET.SubElement(element, "filename") subelement.text = str(self.filename) @@ -3315,12 +1798,12 @@ class UnstructuredMesh(MeshBase): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate unstructured mesh object from XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -3332,59 +1815,5 @@ class UnstructuredMesh(MeshBase): filename = get_text(elem, 'filename') library = get_text(elem, 'library') length_multiplier = float(get_text(elem, 'length_multiplier', 1.0)) - options = get_text(elem, "options") - return cls(filename, library, mesh_id, '', length_multiplier, options) - - -def _read_meshes(elem): - """Generate dictionary of meshes from a given XML node - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - dict - A dictionary with mesh IDs as keys and openmc.MeshBase - instanaces as values - """ - out = {} - for mesh_elem in elem.findall('mesh'): - mesh = MeshBase.from_xml_element(mesh_elem) - out[mesh.id] = mesh - - return out - - -# hexahedron element connectivity -# lower-k connectivity offsets -_HEX_VERTEX_CONN = ((0, 0, 0), - (1, 0, 0), - (1, 1, 0), - (0, 1, 0)) -# upper-k connectivity offsets -_HEX_VERTEX_CONN += ((0, 0, 1), - (1, 0, 1), - (1, 1, 1), - (0, 1, 1)) - -_N_HEX_VERTICES = 8 - -# lower-k connectivity offsets -_HEX_MIDPOINT_CONN = ((0, (0, 0, 0)), - (1, (1, 0, 0)), - (0, (0, 1, 0)), - (1, (0, 0, 0))) -# upper-k connectivity offsets -_HEX_MIDPOINT_CONN += ((0, (0, 0, 1)), - (1, (1, 0, 1)), - (0, (0, 1, 1)), - (1, (0, 0, 1))) -# mid-plane k connectivity -_HEX_MIDPOINT_CONN += ((2, (0, 0, 0)), - (2, (1, 0, 0)), - (2, (1, 1, 0)), - (2, (0, 1, 0))) + return cls(filename, library, mesh_id, '', length_multiplier) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index 5adbac9c4..459b6a874 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -1,6 +1,6 @@ import numpy as np -from openmc.mgxs.groups import EnergyGroups, convert_flux_groups +from openmc.mgxs.groups import EnergyGroups from openmc.mgxs.library import Library from openmc.mgxs.mgxs import * from openmc.mgxs.mdgxs import * @@ -13,32 +13,21 @@ GROUP_STRUCTURES = {} - "XMAS-172_" designed for LWR analysis ([SAR1990]_, [SAN2004]_) - "SHEM-361_" designed for LWR analysis to eliminate self-shielding calculations of thermal resonances ([HFA2005]_, [SAN2007]_, [HEB2008]_) -- "SCALE-X" (where X is 44 which is designed for criticality analysis, 252 is designed - for thermal reactors and 999 for multipurpose activation) for the SCALE code suite - ([ZAL1999]_ and [REARDEN2013]_) -- "MPACT-X" (where X is 51 (PWR), 60 (BWR), 69 (Magnox)) from the MPACT_ reactor - physics code ([KIM2019]_ and [KIM2020]_) -- "ECCO-33" intended for fast reactor criticality benchmarks. It’s derived as a - subset of VITAMIN‑J +- "SCALE-44" designed for criticality analysis ([ZAL1999]_) - "ECCO-1968_" designed for fine group reactor cell calculations for fast, intermediate and thermal reactor applications ([SAR1990]_) - activation_ energy group structures "VITAMIN-J-42", "VITAMIN-J-175", - "TRIPOLI-315", "LLNL-616", "CCFE-709_" and "UKAEA-1102_" + "TRIPOLI-315", "CCFE-709_" and "UKAEA-1102_" -.. _CASMO: http://large.stanford.edu/courses/2013/ph241/dalvi1/docs/c5.physor2006.pdf -.. _SCALE44: https://www-nds.iaea.org/publications/indc/indc-czr-0001.pdf -.. _ECCO-33: https://serpent.vtt.fi/mediawiki/index.php/ECCO_33-group_structure -.. _SCALE252: https://oecd-nea.org/science/wpncs/amct/workingarea/meeting2013/EGAMCT2013_08.pdf -.. _SCALE999: https://info.ornl.gov/sites/publications/Files/Pub67728.pdf, https://www.nrc.gov/docs/ML1218/ML12184A002.pdf -.. _MPACT: https://vera.ornl.gov/mpact/ +.. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf +.. _SCALE: https://www-nds.iaea.org/publications/indc/indc-czr-0001.pdf .. _XMAS-172: https://www-nds.iaea.org/wimsd/energy.htm -.. _SHEM-361: http://merlin.polymtl.ca/downloads/FP214.pdf +.. _SHEM-361: https://www.polymtl.ca/merlin/downloads/FP214.pdf .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _VITAMIN-J-42: https://www.oecd-nea.org/dbdata/nds_jefreports/jefreport-10.pdf -.. _LLNL-616: https://fispact.ukaea.uk/manual/user_manual.pdf .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure .. _UKAEA-1102: https://fispact.ukaea.uk/wiki/UKAEA-1102_group_structure -.. _ECCO-1968: https://serpent.vtt.fi/mediawiki/index.php/ECCO_1968-group_structure +.. _ECCO-1968: http://serpent.vtt.fi/mediawiki/index.php/ECCO_1968-group_structure .. [SAR1990] Sartori, E., OECD/NEA Data Bank: Standard Energy Group Structures of Cross Section Libraries for Reactor Shielding, Reactor Cell and Fusion Neutronics Applications: VITAMIN-J, ECCO-33, ECCO-2000 and XMAS JEF/DOC-315 @@ -58,18 +47,7 @@ GROUP_STRUCTURES = {} Santamarina-Hfaiedh energy mesh between 22.5 eV and 11.4 keV. International Conference on the Physics of Reactors 2008, PHYSOR 08. 2. 929-938. .. [ZAL1999] K. Záleský and L. Marková (1999), Assessment of Nuclear Data Needs - for Broad-Group SCALE Library Related to VVER Spent Fuel Applications, IAEA. SCALE44_. -.. [REARDEN2013] B. T. Rearden, M. E. Dunn, D. Wiarda, C. Celik, K. Bekar, - M. L. Williams, D. E. Peplow, M. A. Jessee, C. M. Perfetti, - I. C. Gauld, W. A. Wieselquist, J. P. Lefebvre, R. A. Lefebvre, - W. J. Marshall, A. B. Thompson, F. Havluj, S. E. Skutnik, - K. J. Dugan. (2013). Overview of SCALE 6.2. OECD. SCALE252_. -.. [KIM2019] Kim, K.S., Williams, M., Wiarda, D., & Clarno, K. (2019). Development - of the multigroup cross section library for the CASL neutronics simulator MPACT: - Method and procedure. Annals of Nuclear Energy, 133. pp. 46-58. -.. [KIM2020] Kim, K.S., Ade, B., & Luciano, N. (2020). Development - of the MPACT 69-group Library for Magnox Reactor Analysis using VERA. - Proceedings of International Conference on Physics of Reactors PHYSOR2020. + for Broad-Group SCALE Library Related to VVER Spent Fuel Applications, IAEA. """ GROUP_STRUCTURES['CASMO-2'] = np.array([ @@ -85,16 +63,6 @@ GROUP_STRUCTURES['CASMO-25'] = np.array([ 0., 3.e-2, 5.8e-2, 1.4e-1, 2.8e-1, 3.5e-1, 6.25e-1, 9.72e-1, 1.02, 1.097, 1.15, 1.855, 4., 9.877, 1.5968e1, 1.4873e2, 5.53e3, 9.118e3, 1.11e5, 5.e5, 8.21e5, 1.353e6, 2.231e6, 3.679e6, 6.0655e6, 2.e7]) -GROUP_STRUCTURES['ECCO-33'] = np.array([ - 1.0000100000E-05, 1.0000000000E-01, 5.4000000000E-01, 4.0000000000E+00, - 8.3152870000E+00, 1.3709590000E+01, 2.2603290000E+01, 4.0169000000E+01, - 6.7904050000E+01, 9.1660880000E+01, 1.4862540000E+02, 3.0432480000E+02, - 4.5399930000E+02, 7.4851830000E+02, 1.2340980000E+03, 2.0346840000E+03, - 3.3546260000E+03, 5.5308440000E+03, 9.1188200000E+03, 1.5034390000E+04, - 2.4787520000E+04, 4.0867710000E+04, 6.7379470000E+04, 1.1109000000E+05, - 1.8315640000E+05, 3.0197380000E+05, 4.9787070000E+05, 8.2085000000E+05, - 1.3533530000E+06, 2.2313020000E+06, 3.6787940000E+06, 6.0653070000E+06, - 1.0000000000E+07, 1.9640330000E+07]) GROUP_STRUCTURES['CASMO-40'] = np.array([ 0., 1.5e-2, 3.e-2, 4.2e-2, 5.8e-2, 8.e-2, 1.e-1, 1.4e-1, 1.8e-1, 2.2e-1, 2.8e-1, 3.5e-1, 6.25e-1, 8.5e-1, 9.5e-1, @@ -112,30 +80,6 @@ GROUP_STRUCTURES['SCALE-44'] = np.array([1e-5, 3.e-3, 7.5e-3, 1.e-2, 2.53e-2, 3.25e-1, 3.5e-1, 3.75e-1, 4.e-1, 6.25e-1, 1., 1.77, 3., 4.75, 6., 8.1, 1.e1, 3.e1, 1.e2, 5.5e2, 3.e3, 1.7e4, 2.5e4, 1.e5, 4.e5, 9.e5, 1.4e6, 1.85e6, 2.354e6, 2.479e6, 3.e6, 4.8e6, 6.434e6, 8.1873e6, 2.e7]) -GROUP_STRUCTURES['MPACT-51'] = np.array([ - 0., 1.e-2, 3.e-2, 4.e-2, 6.e-2, 8.e-2, 1.e-1, 1.5e-1, 2.e-1, 2.75e-1, - 3.5e-1, 5.e-1, 6.25e-1, 7.5e-1, 9.25e-1, 9.75e-1, 1.010, 1.080, 1.130, - 1.175, 1.250, 1.450, 1.860, 2.470, 3.730, 4.700, 5.000, 5.400, 6.250, - 7.150, 8.100, 1.19e+1, 1.44e+1, 3.e+1, 4.83e+1, 7.6e+1, 1.43e+2, 3.05e+2, - 9.5e+2, 2.25e+3, 9.5e+3, 2.e+4, 5.e+4, 7.3e+4, 2.e+5, 4.92e+5, 8.2e+5, - 1.356e+6, 2.354e+6, 4.304e+6, 6.434e+6, 2.e+7]) -GROUP_STRUCTURES['MPACT-60'] = np.array([ - 0., 1.e-2, 3.e-2, 4.e-2, 6.e-2, 8.e-2, 1.e-1, 1.5e-1, 2.e-1, 2.75e-1, - 3.5e-1, 5.e-1, 6.25e-1, 7.5e-1, 9.25e-1, 9.75e-1, 1.01, 1.08, 1.13, - 1.175, 1.25, 1.45, 1.86, 2.47, 3.73, 4.7, 5., 5.4, 6.25, 7.15, 8.1, - 1.19e+1, 1.44e+1, 3.e+1, 4.83e+1, 7.6e+1, 1.43e+2, 2.095e+2, 3.05e+2, - 6.7e+2, 9.5e+2, 1.55e+3, 2.25e+3, 3.9e+3, 9.5e+3, 1.3e+4, 2.e+4, 3.e+4, - 5.e+4, 7.3e+4, 1.283e+5, 2.e+5, 3.3e+5, 4.92e+5, 6.7e+5, 8.2e+5, 1.356e+6, - 2.354e+6, 4.304e+6, 6.434e+6, 2.e+7]) -GROUP_STRUCTURES['MPACT-69'] = np.array([ - 0., 1.e-2, 3.e-2, 4.e-2, 6.e-2, 8.e-2, 9.e-2, 1.e-1, 1.25e-1, 1.5e-1, - 1.75e-1, 2.e-1, 2.25e-1, 2.5e-1, 2.75e-1, 3.e-1, 3.25e-1, 3.5e-1, 3.75e-1, - 4.e-1, 4.5e-1, 5.e-1, 5.5e-1, 6.e-1, 6.25e-1, 6.5e-1, 7.5e-1, 8.5e-1, - 9.25e-1, 9.75e-1, 1.01, 1.08, 1.13, 1.175, 1.25, 1.45, 1.86, 2.47, 3., - 3.73, 4.7, 5., 5.4, 6.25, 7.15, 8.1, 1.e+1, 1.19e+1, 1.44e+1, 3.e+1, - 4.83e+1, 7.6e+1, 1.43e+2, 3.05e+2, 5.5e+2, 9.5e+2, 2.25e+3, 3.9e+3, 9.5e+3, - 2.e+4, 5.e+4, 7.3e+4, 2.e+5, 4.92e+5, 8.2e+5, 1.356e+6, 2.354e+6, 4.304e+6, - 6.434e+6, 2.e+7]) GROUP_STRUCTURES['CASMO-70'] = np.array([ 0., 5.e-3, 1.e-2, 1.5e-2, 2.e-2, 2.5e-2, 3.e-2, 3.5e-2, 4.2e-2, 5.e-2, 5.8e-2, 6.7e-2, 8.e-2, 1.e-1, 1.4e-1, 1.8e-1, 2.2e-1, @@ -213,34 +157,6 @@ GROUP_STRUCTURES['VITAMIN-J-175'] = np.array([ 1.1052e7, 1.1618e7, 1.2214e7, 1.2523e7, 1.2840e7, 1.3499e7, 1.3840e7, 1.4191e7, 1.4550e7, 1.4918e7, 1.5683e7, 1.6487e7, 1.6905e7, 1.7332e7, 1.9640e7]) -GROUP_STRUCTURES['SCALE-252'] = np.array([ - 0., 1.e-4, 5.e-4, 7.5e-4, 1.e-3, 1.2e-3, 1.5e-3, 2.e-3, 2.5e-3, 3.e-3, - 4.e-3, 5.e-3, 7.5e-3, 1.e-2, 2.53e-2, 3.e-2, 4.e-2, 5.e-2, 6.e-2, 7.e-2, - 8.e-2, 9.e-2, 1.e-1, 1.25e-1, 1.5e-1, 1.75e-1, 2.e-1, 2.25e-1, 2.5e-1, - 2.75e-1, 3.e-1, 3.25e-1, 3.5e-1, 3.75e-1, 4.e-1, 4.5e-1, 5.e-1, 5.5e-1, - 6.e-1, 6.25e-1, 6.5e-1, 7.e-1, 7.5e-1, 8.e-1, 8.5e-1, 9.e-1, 9.25e-1, - 9.5e-1, 9.75e-1, 1., 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, - 1.1, 1.11, 1.12, 1.13, 1.14, 1.15, 1.175, 1.2, 1.225, 1.25, 1.3, 1.35, 1.4, - 1.45, 1.5, 1.59, 1.68, 1.77, 1.86, 1.94, 2., 2.12, 2.21, 2.3, 2.38, 2.47, - 2.57, 2.67, 2.77, 2.87, 2.97, 3., 3.1, 3.2, 3.5, 3.73, 4.1, 4.7, 5., 5.4, - 6., 6.25, 6.5, 6.75, 6.875, 7., 7.15, 8.1, 9.1, 1.e+1, 1.15e+1, 1.19e+1, - 1.29e+1, 1.44e+1, 1.6e+1, 1.7e+1, 1.85e+1, 1.94e+1, 2.e+1, 2.05e+1, - 2.12e+1, 2.175e+1, 2.25e+1, 2.5e+1, 2.75e+1, 3.e+1, 3.125e+1, 3.175e+1, - 3.325e+1, 3.375e+1, 3.5e+1, 3.55e+1, 3.6e+1, 3.7e+1, 3.713e+1, 3.727e+1, - 3.763e+1, 3.8e+1, 3.91e+1, 3.96e+1, 4.1e+1, 4.24e+1, 4.4e+1, 4.52e+1, - 4.83e+1, 5.06e+1, 5.34e+1, 5.8e+1, 6.1e+1, 6.3e+1, 6.5e+1, 6.75e+1, 7.2e+1, - 7.6e+1, 8.e+1, 8.17e+1, 9.e+1, 9.7e+1, 1.012e+2, 1.05e+2, 1.08e+2, 1.13e+2, - 1.16e+2, 1.175e+2, 1.19e+2, 1.22e+2, 1.43e+2, 1.7e+2, 1.8e+2, 1.877e+2, - 1.885e+2, 1.915e+2, 1.93e+2, 2.02e+2, 2.074e+2, 2.095e+2, 2.2e+2, 2.4e+2, - 2.85e+2, 3.05e+2, 5.5e+2, 6.7e+2, 6.83e+2, 9.5e+2, 1.15e+3, 1.5e+3, - 1.55e+3, 1.8e+3, 2.2e+3, 2.25e+3, 2.5e+3, 3.e+3, 3.74e+3, 3.9e+3, 5.7e+3, - 8.03e+3, 9.5e+3, 1.3e+4, 1.7e+4, 2.e+4, 3.e+4, 4.5e+4, 5.e+4, 5.2e+4, - 6.e+4, 7.3e+4, 7.5e+4, 8.2e+4, 8.5e+4, 1.e+5, 1.283e+5, 1.49e+5, 2.e+5, - 2.7e+5, 3.3e+5, 4.e+5, 4.2e+5, 4.4e+5, 4.7e+5, 4.92e+5, 5.5e+5, 5.73e+5, - 6.e+5, 6.7e+5, 6.79e+5, 7.5e+5, 8.2e+5, 8.611e+5, 8.75e+5, 9.e+5, 9.2e+5, - 1.01e+6, 1.1e+6, 1.2e+6, 1.25e+6, 1.317e+6, 1.356e+6, 1.4e+6, 1.5e+6, - 1.85e+6, 2.354e+6, 2.479e+6, 3.e+6, 4.304e+6, 4.8e+6, 6.434e+6, 8.187e+6, - 1.e+7, 1.284e+7, 1.384e+7, 1.455e+7, 1.568e+7, 1.733e+7, 2.e+7]) GROUP_STRUCTURES['TRIPOLI-315'] = np.array([ 1.0e-5, 1.1e-4, 3.000e-3, 5.500e-3, 1.000e-2, 1.500e-2, 2.000e-2, 3.000e-2, 3.200e-2, 3.238e-2, 4.300e-2, 5.900e-2, 7.700e-2, 9.500e-2, 1.000e-1, @@ -361,97 +277,6 @@ GROUP_STRUCTURES['SHEM-361'] = np.array([ 4.06569e+06, 4.96585e+06, 6.06530e+06, 6.70319e+06, 7.40817e+06, 8.18730e+06, 9.04836e+06, 9.99999e+06, 1.16183e+07, 1.38403e+07, 1.49182e+07, 1.96403e+07]) -GROUP_STRUCTURES['LLNL-616'] = np.array([ - 1.0000e-5, 1.0471e-5, 1.0965e-5, 1.1482e-5, 1.2023e-5, 1.2589e-5, 1.3183e-5, - 1.3804e-5, 1.4454e-5, 1.5136e-5, 1.5849e-5, 1.6596e-5, 1.7378e-5, 1.8197e-5, - 1.9055e-5, 1.9953e-5, 2.0893e-5, 2.1878e-5, 2.2909e-5, 2.3988e-5, 2.5119e-5, - 2.6303e-5, 2.7542e-5, 2.8840e-5, 3.0200e-5, 3.1623e-5, 3.3113e-5, 3.4674e-5, - 3.6308e-5, 3.8019e-5, 3.9811e-5, 4.1687e-5, 4.3652e-5, 4.5709e-5, 4.7863e-5, - 5.0119e-5, 5.2481e-5, 5.4954e-5, 5.7544e-5, 6.0256e-5, 6.3096e-5, 6.6069e-5, - 6.9183e-5, 7.2444e-5, 7.5858e-5, 7.9433e-5, 8.3176e-5, 8.7096e-5, 9.1201e-5, - 9.5499e-5, 1.0000e-4, 1.0471e-4, 1.0965e-4, 1.1482e-4, 1.2023e-4, 1.2589e-4, - 1.3183e-4, 1.3804e-4, 1.4454e-4, 1.5136e-4, 1.5849e-4, 1.6596e-4, 1.7378e-4, - 1.8197e-4, 1.9055e-4, 1.9953e-4, 2.0893e-4, 2.1878e-4, 2.2909e-4, 2.3988e-4, - 2.5119e-4, 2.6303e-4, 2.7542e-4, 2.8840e-4, 3.0200e-4, 3.1623e-4, 3.3113e-4, - 3.4674e-4, 3.6308e-4, 3.8019e-4, 3.9811e-4, 4.1687e-4, 4.3652e-4, 4.5709e-4, - 4.7863e-4, 5.0119e-4, 5.2481e-4, 5.4954e-4, 5.7544e-4, 6.0256e-4, 6.3096e-4, - 6.6069e-4, 6.9183e-4, 7.2444e-4, 7.5858e-4, 7.9433e-4, 8.3176e-4, 8.7096e-4, - 9.1201e-4, 9.5499e-4, 1.0000e-3, 1.0471e-3, 1.0965e-3, 1.1482e-3, 1.2023e-3, - 1.2589e-3, 1.3183e-3, 1.3804e-3, 1.4454e-3, 1.5136e-3, 1.5849e-3, 1.6596e-3, - 1.7378e-3, 1.8197e-3, 1.9055e-3, 1.9953e-3, 2.0893e-3, 2.1878e-3, 2.2909e-3, - 2.3988e-3, 2.5119e-3, 2.6303e-3, 2.7542e-3, 2.8840e-3, 3.0200e-3, 3.1623e-3, - 3.3113e-3, 3.4674e-3, 3.6308e-3, 3.8019e-3, 3.9811e-3, 4.1687e-3, 4.3652e-3, - 4.5709e-3, 4.7863e-3, 5.0119e-3, 5.2481e-3, 5.4954e-3, 5.7544e-3, 6.0256e-3, - 6.3096e-3, 6.6069e-3, 6.9183e-3, 7.2444e-3, 7.5858e-3, 7.9433e-3, 8.3176e-3, - 8.7096e-3, 9.1201e-3, 9.5499e-3, 1.0000e-2, 1.0471e-2, 1.0965e-2, 1.1482e-2, - 1.2023e-2, 1.2589e-2, 1.3183e-2, 1.3804e-2, 1.4454e-2, 1.5136e-2, 1.5849e-2, - 1.6596e-2, 1.7378e-2, 1.8197e-2, 1.9055e-2, 1.9953e-2, 2.0893e-2, 2.1878e-2, - 2.2909e-2, 2.3988e-2, 2.5119e-2, 2.6303e-2, 2.7542e-2, 2.8840e-2, 3.0200e-2, - 3.1623e-2, 3.3113e-2, 3.4674e-2, 3.6308e-2, 3.8019e-2, 3.9811e-2, 4.1687e-2, - 4.3652e-2, 4.5709e-2, 4.7863e-2, 5.0119e-2, 5.2481e-2, 5.4954e-2, 5.7544e-2, - 6.0256e-2, 6.3096e-2, 6.6069e-2, 6.9183e-2, 7.2444e-2, 7.5858e-2, 7.9433e-2, - 8.3176e-2, 8.7096e-2, 9.1201e-2, 9.5499e-2, 1.0000e-1, 1.0471e-1, 1.0965e-1, - 1.1482e-1, 1.2023e-1, 1.2589e-1, 1.3183e-1, 1.3804e-1, 1.4454e-1, 1.5136e-1, - 1.5849e-1, 1.6596e-1, 1.7378e-1, 1.8197e-1, 1.9055e-1, 1.9953e-1, 2.0893e-1, - 2.1878e-1, 2.2909e-1, 2.3988e-1, 2.5119e-1, 2.6303e-1, 2.7542e-1, 2.8840e-1, - 3.0200e-1, 3.1623e-1, 3.3113e-1, 3.4674e-1, 3.6308e-1, 3.8019e-1, 3.9811e-1, - 4.1687e-1, 4.3652e-1, 4.5709e-1, 4.7863e-1, 5.0119e-1, 5.2481e-1, 5.4954e-1, - 5.7544e-1, 6.0256e-1, 6.3096e-1, 6.6069e-1, 6.9183e-1, 7.2444e-1, 7.5858e-1, - 7.9433e-1, 8.3176e-1, 8.7096e-1, 9.1201e-1, 9.5499e-1, 1.0000e0, 1.0471e0, - 1.0965e0, 1.1482e0, 1.2023e0, 1.2589e0, 1.3183e0, 1.3804e0, 1.4454e0, - 1.5136e0, 1.5849e0, 1.6596e0, 1.7378e0, 1.8197e0, 1.9055e0, 1.9953e0, - 2.0893e0, 2.1878e0, 2.2909e0, 2.3988e0, 2.5119e0, 2.6303e0, 2.7542e0, - 2.8840e0, 3.0200e0, 3.1623e0, 3.3113e0, 3.4674e0, 3.6308e0, 3.8019e0, - 3.9811e0, 4.1687e0, 4.3652e0, 4.5709e0, 4.7863e0, 5.0119e0, 5.2481e0, - 5.4954e0, 5.7544e0, 6.0256e0, 6.3096e0, 6.6069e0, 6.9183e0, 7.2444e0, - 7.5858e0, 7.9433e0, 8.3176e0, 8.7096e0, 9.1201e0, 9.5499e0, 1.0000e1, - 1.0471e1, 1.0965e1, 1.1482e1, 1.2023e1, 1.2589e1, 1.3183e1, 1.3804e1, - 1.4454e1, 1.5136e1, 1.5849e1, 1.6596e1, 1.7378e1, 1.8197e1, 1.9055e1, - 1.9953e1, 2.0893e1, 2.1878e1, 2.2909e1, 2.3988e1, 2.5119e1, 2.6303e1, - 2.7542e1, 2.8840e1, 3.0200e1, 3.1623e1, 3.3113e1, 3.4674e1, 3.6308e1, - 3.8019e1, 3.9811e1, 4.1687e1, 4.3652e1, 4.5709e1, 4.7863e1, 5.0119e1, - 5.2481e1, 5.4954e1, 5.7544e1, 6.0256e1, 6.3096e1, 6.6069e1, 6.9183e1, - 7.2444e1, 7.5858e1, 7.9433e1, 8.3176e1, 8.7096e1, 9.1201e1, 9.5499e1, - 1.0000e2, 1.0471e2, 1.0965e2, 1.1482e2, 1.2023e2, 1.2589e2, 1.3183e2, - 1.3804e2, 1.4454e2, 1.5136e2, 1.5849e2, 1.6596e2, 1.7378e2, 1.8197e2, - 1.9055e2, 1.9953e2, 2.0893e2, 2.1878e2, 2.2909e2, 2.3988e2, 2.5119e2, - 2.6303e2, 2.7542e2, 2.8840e2, 3.0200e2, 3.1623e2, 3.3113e2, 3.4674e2, - 3.6308e2, 3.8019e2, 3.9811e2, 4.1687e2, 4.3652e2, 4.5709e2, 4.7863e2, - 5.0119e2, 5.2481e2, 5.4954e2, 5.7544e2, 6.0256e2, 6.3096e2, 6.6069e2, - 6.9183e2, 7.2444e2, 7.5858e2, 7.9433e2, 8.3176e2, 8.7096e2, 9.1201e2, - 9.5499e2, 1.0000e3, 1.0471e3, 1.0965e3, 1.1482e3, 1.2023e3, 1.2589e3, - 1.3183e3, 1.3804e3, 1.4454e3, 1.5136e3, 1.5849e3, 1.6596e3, 1.7378e3, - 1.8197e3, 1.9055e3, 1.9953e3, 2.0893e3, 2.1878e3, 2.2909e3, 2.3988e3, - 2.5119e3, 2.6303e3, 2.7542e3, 2.8840e3, 3.0200e3, 3.1623e3, 3.3113e3, - 3.4674e3, 3.6308e3, 3.8019e3, 3.9811e3, 4.1687e3, 4.3652e3, 4.5709e3, - 4.7863e3, 5.0119e3, 5.2481e3, 5.4954e3, 5.7544e3, 6.0256e3, 6.3096e3, - 6.6069e3, 6.9183e3, 7.2444e3, 7.5858e3, 7.9433e3, 8.3176e3, 8.7096e3, - 9.1201e3, 9.5499e3, 1.0000e4, 1.0471e4, 1.0965e4, 1.1482e4, 1.2023e4, - 1.2589e4, 1.3183e4, 1.3804e4, 1.4454e4, 1.5136e4, 1.5849e4, 1.6596e4, - 1.7378e4, 1.8197e4, 1.9055e4, 1.9953e4, 2.0893e4, 2.1878e4, 2.2909e4, - 2.3988e4, 2.5119e4, 2.6303e4, 2.7542e4, 2.8840e4, 3.0200e4, 3.1623e4, - 3.3113e4, 3.4674e4, 3.6308e4, 3.8019e4, 3.9811e4, 4.1687e4, 4.3652e4, - 4.5709e4, 4.7863e4, 5.0119e4, 5.2481e4, 5.4954e4, 5.7544e4, 6.0256e4, - 6.3096e4, 6.6069e4, 6.9183e4, 7.2444e4, 7.5858e4, 7.9433e4, 8.3176e4, - 8.7096e4, 9.1201e4, 9.5499e4, 1.0000e5, 1.0471e5, 1.0965e5, 1.1482e5, - 1.2023e5, 1.2589e5, 1.3183e5, 1.3804e5, 1.4454e5, 1.5136e5, 1.5849e5, - 1.6596e5, 1.7378e5, 1.8197e5, 1.9055e5, 1.9953e5, 2.0893e5, 2.1878e5, - 2.2909e5, 2.3988e5, 2.5119e5, 2.6303e5, 2.7542e5, 2.8840e5, 3.0200e5, - 3.1623e5, 3.3113e5, 3.4674e5, 3.6308e5, 3.8019e5, 3.9811e5, 4.1687e5, - 4.3652e5, 4.5709e5, 4.7863e5, 5.0119e5, 5.2481e5, 5.4954e5, 5.7544e5, - 6.0256e5, 6.3096e5, 6.6069e5, 6.9183e5, 7.2444e5, 7.5858e5, 7.9433e5, - 8.3176e5, 8.7096e5, 9.1201e5, 9.5499e5, 1.0000e6, 1.0471e6, 1.0965e6, - 1.1482e6, 1.2023e6, 1.2589e6, 1.3183e6, 1.3804e6, 1.4454e6, 1.5136e6, - 1.5849e6, 1.6596e6, 1.7378e6, 1.8197e6, 1.9055e6, 1.9953e6, 2.0893e6, - 2.1878e6, 2.2909e6, 2.3988e6, 2.5119e6, 2.6303e6, 2.7542e6, 2.8840e6, - 3.0200e6, 3.1623e6, 3.3113e6, 3.4674e6, 3.6308e6, 3.8019e6, 3.9811e6, - 4.1687e6, 4.3652e6, 4.5709e6, 4.7863e6, 5.0119e6, 5.2481e6, 5.4954e6, - 5.7544e6, 6.0256e6, 6.3096e6, 6.6069e6, 6.9183e6, 7.2444e6, 7.5858e6, - 7.9433e6, 8.3176e6, 8.7096e6, 9.1201e6, 9.5499e6, 1.0000e7, 1.0471e7, - 1.0965e7, 1.1482e7, 1.2023e7, 1.2589e7, 1.3183e7, 1.3804e7, 1.4454e7, - 1.5136e7, 1.5849e7, 1.6596e7, 1.7378e7, 1.8197e7, 1.9055e7, 1.9953e7, - 2.0000e7 -]) GROUP_STRUCTURES['CCFE-709'] = np.array([ 1.e-5, 1.0471e-5, 1.0965e-5, 1.1482e-5, 1.2023e-5, 1.2589e-5, 1.3183e-5, 1.3804e-5, 1.4454e-5, 1.5136e-5, @@ -594,208 +419,7 @@ GROUP_STRUCTURES['CCFE-709'] = np.array([ 2.4000e8, 2.8000e8, 3.2000e8, 3.6000e8, 4.0000e8, 4.4000e8, 4.8000e8, 5.2000e8, 5.6000e8, 6.0000e8, 6.4000e8, 6.8000e8, 7.2000e8, 7.6000e8, 8.0000e8, - 8.4000e8, 8.8000e8, 9.2000e8, 9.6000e8, 1.0000e9]) -GROUP_STRUCTURES['SCALE-999'] = np.array([ - 1.000e-5, 1.000e-4, 5.000e-4, 7.500e-4, 1.000e-3, - 1.200e-3, 1.500e-3, 2.000e-3, 2.500e-3, 3.000e-3, - 4.000e-3, 5.000e-3, 7.500e-3, 1.000e-2, 1.450e-2, - 1.850e-2, 2.100e-2, 2.530e-2, 3.000e-2, 4.000e-2, - 5.000e-2, 6.000e-2, 7.000e-2, 8.000e-2, 9.000e-2, - 1.000e-1, 1.250e-1, 1.500e-1, 1.750e-1, 1.840e-1, - 2.000e-1, 2.250e-1, 2.500e-1, 2.750e-1, 3.000e-1, - 3.250e-1, 3.500e-1, 3.668e-1, 3.750e-1, 4.000e-1, - 4.140e-1, 4.500e-1, 5.000e-1, 5.316e-1, 5.500e-1, - 6.000e-1, 6.250e-1, 6.500e-1, 6.826e-1, 7.000e-1, - 7.500e-1, 8.000e-1, 8.500e-1, 8.764e-1, 9.000e-1, - 9.250e-1, 9.500e-1, 9.750e-1, 1.000e+0, 1.010e+0, - 1.020e+0, 1.030e+0, 1.040e+0, 1.050e+0, 1.060e+0, - 1.070e+0, 1.080e+0, 1.090e+0, 1.100e+0, 1.110e+0, - 1.120e+0, 1.130e+0, 1.140e+0, 1.150e+0, 1.175e+0, - 1.200e+0, 1.225e+0, 1.250e+0, 1.300e+0, 1.350e+0, - 1.400e+0, 1.450e+0, 1.500e+0, 1.545e+0, 1.590e+0, - 1.635e+0, 1.680e+0, 1.725e+0, 1.770e+0, 1.815e+0, - 1.860e+0, 1.900e+0, 1.940e+0, 1.970e+0, 2.000e+0, - 2.060e+0, 2.120e+0, 2.165e+0, 2.210e+0, 2.255e+0, - 2.300e+0, 2.340e+0, 2.380e+0, 2.425e+0, 2.470e+0, - 2.520e+0, 2.570e+0, 2.620e+0, 2.670e+0, 2.720e+0, - 2.770e+0, 2.820e+0, 2.870e+0, 2.920e+0, 2.970e+0, - 3.000e+0, 3.100e+0, 3.200e+0, 3.300e+0, 3.500e+0, - 3.620e+0, 3.730e+0, 3.830e+0, 3.928e+0, 4.000e+0, - 4.100e+0, 4.300e+0, 4.500e+0, 4.750e+0, 4.875e+0, - 5.000e+0, 5.044e+0, 5.250e+0, 5.400e+0, 5.550e+0, - 5.700e+0, 5.850e+0, 6.000e+0, 6.250e+0, 6.375e+0, - 6.500e+0, 6.625e+0, 6.750e+0, 6.875e+0, 7.000e+0, - 7.075e+0, 7.150e+0, 7.625e+0, 8.100e+0, 8.208e+0, - 8.315e+0, 8.708e+0, 9.100e+0, 9.550e+0, 1.000e+1, - 1.034e+1, 1.068e+1, 1.109e+1, 1.150e+1, 1.170e+1, - 1.190e+1, 1.240e+1, 1.290e+1, 1.333e+1, 1.375e+1, - 1.408e+1, 1.440e+1, 1.475e+1, 1.510e+1, 1.555e+1, - 1.600e+1, 1.650e+1, 1.700e+1, 1.730e+1, 1.760e+1, - 1.805e+1, 1.850e+1, 1.875e+1, 1.900e+1, 1.940e+1, - 2.000e+1, 2.050e+1, 2.100e+1, 2.175e+1, 2.250e+1, - 2.375e+1, 2.500e+1, 2.625e+1, 2.750e+1, 2.826e+1, - 2.902e+1, 2.951e+1, 3.000e+1, 3.063e+1, 3.125e+1, - 3.150e+1, 3.175e+1, 3.250e+1, 3.325e+1, 3.350e+1, - 3.375e+1, 3.418e+1, 3.460e+1, 3.500e+1, 3.550e+1, - 3.600e+1, 3.700e+1, 3.713e+1, 3.727e+1, 3.763e+1, - 3.800e+1, 3.855e+1, 3.910e+1, 3.935e+1, 3.960e+1, - 4.030e+1, 4.100e+1, 4.170e+1, 4.240e+1, 4.320e+1, - 4.400e+1, 4.460e+1, 4.520e+1, 4.610e+1, 4.700e+1, - 4.743e+1, 4.785e+1, 4.808e+1, 4.830e+1, 4.875e+1, - 4.920e+1, 4.990e+1, 5.060e+1, 5.130e+1, 5.200e+1, - 5.270e+1, 5.340e+1, 5.620e+1, 5.800e+1, 6.000e+1, - 6.100e+1, 6.122e+1, 6.144e+1, 6.300e+1, 6.500e+1, - 6.625e+1, 6.750e+1, 6.975e+1, 7.200e+1, 7.400e+1, - 7.600e+1, 7.745e+1, 7.889e+1, 7.945e+1, 8.000e+1, - 8.170e+1, 8.200e+1, 8.400e+1, 8.600e+1, 8.800e+1, - 9.000e+1, 9.250e+1, 9.500e+1, 9.700e+1, 1.000e+2, - 1.012e+2, 1.038e+2, 1.050e+2, 1.080e+2, 1.105e+2, - 1.130e+2, 1.160e+2, 1.175e+2, 1.190e+2, 1.205e+2, - 1.220e+2, 1.240e+2, 1.260e+2, 1.280e+2, 1.301e+2, - 1.325e+2, 1.350e+2, 1.375e+2, 1.400e+2, 1.430e+2, - 1.450e+2, 1.475e+2, 1.500e+2, 1.525e+2, 1.550e+2, - 1.575e+2, 1.600e+2, 1.625e+2, 1.650e+2, 1.670e+2, - 1.700e+2, 1.716e+2, 1.739e+2, 1.763e+2, 1.786e+2, - 1.800e+2, 1.877e+2, 1.885e+2, 1.915e+2, 1.930e+2, - 1.962e+2, 1.999e+2, 2.020e+2, 2.074e+2, 2.088e+2, - 2.095e+2, 2.122e+2, 2.145e+2, 2.175e+2, 2.200e+2, - 2.237e+2, 2.269e+2, 2.301e+2, 2.333e+2, 2.367e+2, - 2.400e+2, 2.442e+2, 2.484e+2, 2.527e+2, 2.571e+2, - 2.615e+2, 2.661e+2, 2.707e+2, 2.754e+2, 2.801e+2, - 2.850e+2, 2.899e+2, 2.948e+2, 2.999e+2, 3.050e+2, - 3.107e+2, 3.165e+2, 3.224e+2, 3.284e+2, 3.345e+2, - 3.408e+2, 3.471e+2, 3.536e+2, 3.591e+2, 3.648e+2, - 3.705e+2, 3.764e+2, 3.823e+2, 3.883e+2, 3.944e+2, - 4.007e+2, 4.070e+2, 4.134e+2, 4.199e+2, 4.265e+2, - 4.332e+2, 4.400e+2, 4.470e+2, 4.540e+2, 4.595e+2, - 4.650e+2, 4.706e+2, 4.763e+2, 4.821e+2, 4.879e+2, - 4.937e+2, 4.997e+2, 5.057e+2, 5.118e+2, 5.180e+2, - 5.243e+2, 5.306e+2, 5.370e+2, 5.435e+2, 5.500e+2, - 5.581e+2, 5.662e+2, 5.745e+2, 5.830e+2, 5.932e+2, - 6.036e+2, 6.142e+2, 6.250e+2, 6.359e+2, 6.471e+2, - 6.585e+2, 6.700e+2, 6.765e+2, 6.830e+2, 6.909e+2, - 6.988e+2, 7.069e+2, 7.150e+2, 7.232e+2, 7.316e+2, - 7.400e+2, 7.485e+2, 7.598e+2, 7.712e+2, 7.827e+2, - 7.945e+2, 8.064e+2, 8.185e+2, 8.308e+2, 8.433e+2, - 8.559e+2, 8.688e+2, 8.818e+2, 8.950e+2, 9.085e+2, - 9.221e+2, 9.360e+2, 9.500e+2, 9.555e+2, 9.611e+2, - 9.720e+2, 9.829e+2, 9.940e+2, 1.005e+3, 1.017e+3, - 1.028e+3, 1.040e+3, 1.051e+3, 1.063e+3, 1.075e+3, - 1.087e+3, 1.100e+3, 1.112e+3, 1.125e+3, 1.137e+3, - 1.150e+3, 1.171e+3, 1.191e+3, 1.213e+3, 1.234e+3, - 1.249e+3, 1.265e+3, 1.280e+3, 1.296e+3, 1.312e+3, - 1.328e+3, 1.344e+3, 1.361e+3, 1.377e+3, 1.394e+3, - 1.411e+3, 1.429e+3, 1.446e+3, 1.464e+3, 1.482e+3, - 1.500e+3, 1.525e+3, 1.550e+3, 1.585e+3, 1.610e+3, - 1.636e+3, 1.662e+3, 1.689e+3, 1.716e+3, 1.744e+3, - 1.772e+3, 1.800e+3, 1.828e+3, 1.856e+3, 1.885e+3, - 1.914e+3, 1.943e+3, 1.973e+3, 2.004e+3, 2.035e+3, - 2.075e+3, 2.116e+3, 2.158e+3, 2.200e+3, 2.250e+3, - 2.290e+3, 2.337e+3, 2.386e+3, 2.435e+3, 2.500e+3, - 2.532e+3, 2.580e+3, 2.613e+3, 2.679e+3, 2.747e+3, - 2.808e+3, 2.871e+3, 2.935e+3, 3.000e+3, 3.035e+3, - 3.112e+3, 3.191e+3, 3.272e+3, 3.355e+3, 3.440e+3, - 3.527e+3, 3.616e+3, 3.707e+3, 3.740e+3, 3.819e+3, - 3.900e+3, 3.998e+3, 4.099e+3, 4.202e+3, 4.307e+3, - 4.400e+3, 4.500e+3, 4.620e+3, 4.740e+3, 4.850e+3, - 4.960e+3, 5.100e+3, 5.250e+3, 5.400e+3, 5.531e+3, - 5.645e+3, 5.700e+3, 5.879e+3, 6.000e+3, 6.128e+3, - 6.258e+3, 6.392e+3, 6.528e+3, 6.667e+3, 6.809e+3, - 6.954e+3, 7.102e+3, 7.212e+3, 7.323e+3, 7.437e+3, - 7.552e+3, 7.669e+3, 7.787e+3, 7.908e+3, 8.030e+3, - 8.159e+3, 8.289e+3, 8.422e+3, 8.557e+3, 8.694e+3, - 8.834e+3, 8.975e+3, 9.119e+3, 9.307e+3, 9.500e+3, - 9.763e+3, 1.003e+4, 1.031e+4, 1.060e+4, 1.086e+4, - 1.114e+4, 1.142e+4, 1.171e+4, 1.202e+4, 1.234e+4, - 1.266e+4, 1.300e+4, 1.324e+4, 1.348e+4, 1.373e+4, - 1.398e+4, 1.424e+4, 1.450e+4, 1.476e+4, 1.503e+4, - 1.527e+4, 1.550e+4, 1.574e+4, 1.599e+4, 1.623e+4, - 1.649e+4, 1.674e+4, 1.700e+4, 1.727e+4, 1.755e+4, - 1.783e+4, 1.812e+4, 1.841e+4, 1.870e+4, 1.900e+4, - 1.931e+4, 1.965e+4, 2.000e+4, 2.045e+4, 2.092e+4, - 2.139e+4, 2.188e+4, 2.229e+4, 2.271e+4, 2.314e+4, - 2.358e+4, 2.388e+4, 2.418e+4, 2.450e+4, 2.479e+4, - 2.500e+4, 2.520e+4, 2.552e+4, 2.580e+4, 2.606e+4, - 2.653e+4, 2.700e+4, 2.737e+4, 2.774e+4, 2.812e+4, - 2.850e+4, 2.887e+4, 2.924e+4, 2.962e+4, 3.000e+4, - 3.045e+4, 3.090e+4, 3.136e+4, 3.183e+4, 3.243e+4, - 3.304e+4, 3.367e+4, 3.431e+4, 3.468e+4, 3.507e+4, - 3.545e+4, 3.584e+4, 3.624e+4, 3.663e+4, 3.704e+4, - 3.744e+4, 3.786e+4, 3.827e+4, 3.869e+4, 3.912e+4, - 3.955e+4, 3.998e+4, 4.042e+4, 4.087e+4, 4.136e+4, - 4.186e+4, 4.237e+4, 4.288e+4, 4.340e+4, 4.393e+4, - 4.446e+4, 4.500e+4, 4.565e+4, 4.631e+4, 4.721e+4, - 4.812e+4, 4.905e+4, 5.000e+4, 5.099e+4, 5.200e+4, - 5.248e+4, 5.347e+4, 5.448e+4, 5.551e+4, 5.656e+4, - 5.740e+4, 5.826e+4, 5.912e+4, 6.000e+4, 6.088e+4, - 6.177e+4, 6.267e+4, 6.358e+4, 6.451e+4, 6.545e+4, - 6.641e+4, 6.738e+4, 6.851e+4, 6.965e+4, 7.081e+4, - 7.200e+4, 7.300e+4, 7.399e+4, 7.500e+4, 7.610e+4, - 7.722e+4, 7.835e+4, 7.950e+4, 8.074e+4, 8.200e+4, - 8.250e+4, 8.374e+4, 8.500e+4, 8.652e+4, 8.788e+4, - 8.926e+4, 9.067e+4, 9.210e+4, 9.355e+4, 9.502e+4, - 9.652e+4, 9.804e+4, 1.000e+5, 1.013e+5, 1.027e+5, - 1.040e+5, 1.054e+5, 1.068e+5, 1.082e+5, 1.096e+5, - 1.111e+5, 1.125e+5, 1.139e+5, 1.153e+5, 1.168e+5, - 1.183e+5, 1.197e+5, 1.213e+5, 1.228e+5, 1.241e+5, - 1.255e+5, 1.269e+5, 1.283e+5, 1.291e+5, 1.307e+5, - 1.323e+5, 1.340e+5, 1.357e+5, 1.374e+5, 1.391e+5, - 1.409e+5, 1.426e+5, 1.445e+5, 1.463e+5, 1.481e+5, - 1.490e+5, 1.519e+5, 1.538e+5, 1.557e+5, 1.576e+5, - 1.596e+5, 1.616e+5, 1.637e+5, 1.657e+5, 1.678e+5, - 1.699e+5, 1.721e+5, 1.742e+5, 1.764e+5, 1.786e+5, - 1.809e+5, 1.832e+5, 1.855e+5, 1.878e+5, 1.902e+5, - 1.926e+5, 1.962e+5, 2.000e+5, 2.024e+5, 2.050e+5, - 2.076e+5, 2.102e+5, 2.128e+5, 2.155e+5, 2.182e+5, - 2.209e+5, 2.237e+5, 2.265e+5, 2.294e+5, 2.323e+5, - 2.352e+5, 2.381e+5, 2.411e+5, 2.442e+5, 2.472e+5, - 2.500e+5, 2.527e+5, 2.555e+5, 2.584e+5, 2.612e+5, - 2.641e+5, 2.670e+5, 2.700e+5, 2.732e+5, 2.767e+5, - 2.802e+5, 2.837e+5, 2.873e+5, 2.909e+5, 2.945e+5, - 2.972e+5, 2.985e+5, 3.020e+5, 3.053e+5, 3.088e+5, - 3.122e+5, 3.157e+5, 3.192e+5, 3.228e+5, 3.264e+5, - 3.300e+5, 3.337e+5, 3.379e+5, 3.422e+5, 3.465e+5, - 3.508e+5, 3.553e+5, 3.597e+5, 3.643e+5, 3.688e+5, - 3.735e+5, 3.782e+5, 3.829e+5, 3.877e+5, 3.938e+5, - 4.000e+5, 4.076e+5, 4.138e+5, 4.200e+5, 4.249e+5, - 4.299e+5, 4.349e+5, 4.400e+5, 4.452e+5, 4.505e+5, - 4.553e+5, 4.601e+5, 4.650e+5, 4.700e+5, 4.772e+5, - 4.845e+5, 4.920e+5, 4.995e+5, 5.054e+5, 5.113e+5, - 5.173e+5, 5.234e+5, 5.299e+5, 5.365e+5, 5.432e+5, - 5.500e+5, 5.557e+5, 5.614e+5, 5.672e+5, 5.730e+5, - 5.784e+5, 5.891e+5, 6.000e+5, 6.081e+5, 6.158e+5, - 6.235e+5, 6.313e+5, 6.393e+5, 6.468e+5, 6.545e+5, - 6.622e+5, 6.700e+5, 6.790e+5, 6.926e+5, 7.065e+5, - 7.154e+5, 7.244e+5, 7.335e+5, 7.427e+5, 7.500e+5, - 7.576e+5, 7.653e+5, 7.730e+5, 7.808e+5, 7.904e+5, - 8.002e+5, 8.100e+5, 8.200e+5, 8.301e+5, 8.403e+5, - 8.506e+5, 8.611e+5, 8.750e+5, 8.874e+5, 9.000e+5, - 9.072e+5, 9.200e+5, 9.400e+5, 9.616e+5, 9.800e+5, - 1.003e+6, 1.010e+6, 1.040e+6, 1.070e+6, 1.100e+6, - 1.108e+6, 1.136e+6, 1.165e+6, 1.200e+6, 1.225e+6, - 1.250e+6, 1.287e+6, 1.317e+6, 1.356e+6, 1.400e+6, - 1.423e+6, 1.461e+6, 1.500e+6, 1.536e+6, 1.572e+6, - 1.612e+6, 1.653e+6, 1.695e+6, 1.738e+6, 1.782e+6, - 1.827e+6, 1.850e+6, 1.921e+6, 1.969e+6, 2.019e+6, - 2.070e+6, 2.123e+6, 2.176e+6, 2.231e+6, 2.307e+6, - 2.354e+6, 2.365e+6, 2.385e+6, 2.466e+6, 2.479e+6, - 2.535e+6, 2.592e+6, 2.658e+6, 2.725e+6, 2.794e+6, - 2.865e+6, 2.932e+6, 3.000e+6, 3.080e+6, 3.166e+6, - 3.247e+6, 3.329e+6, 3.413e+6, 3.499e+6, 3.588e+6, - 3.679e+6, 3.772e+6, 3.867e+6, 3.965e+6, 4.066e+6, - 4.183e+6, 4.304e+6, 4.398e+6, 4.493e+6, 4.607e+6, - 4.724e+6, 4.800e+6, 4.882e+6, 4.966e+6, 5.092e+6, - 5.221e+6, 5.353e+6, 5.488e+6, 5.627e+6, 5.770e+6, - 5.916e+6, 6.065e+6, 6.219e+6, 6.376e+6, 6.434e+6, - 6.592e+6, 6.703e+6, 6.873e+6, 7.047e+6, 7.225e+6, - 7.408e+6, 7.596e+6, 7.788e+6, 7.985e+6, 8.187e+6, - 8.395e+6, 8.607e+6, 8.825e+6, 9.048e+6, 9.278e+6, - 9.512e+6, 9.753e+6, 1.000e+7, 1.025e+7, 1.051e+7, - 1.078e+7, 1.105e+7, 1.133e+7, 1.162e+7, 1.191e+7, - 1.221e+7, 1.252e+7, 1.284e+7, 1.317e+7, 1.350e+7, - 1.384e+7, 1.419e+7, 1.455e+7, 1.492e+7, 1.530e+7, - 1.568e+7, 1.608e+7, 1.649e+7, 1.691e+7, 1.733e+7, - 1.790e+7, 1.845e+7, 1.900e+7, 1.964e+7, 2.000e+7]) + 8.4000e8, 8.8000e8, 9.2000e8, 9.6000e8, 1.0000e9,]) GROUP_STRUCTURES['UKAEA-1102'] = np.array([ 1.0000e-5, 1.0471e-5, 1.0965e-5, 1.1482e-5, 1.2023e-5, 1.2589e-5, 1.3183e-5, 1.3804e-5, 1.4454e-5, 1.5136e-5, diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index aea7a6d29..f26218e03 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -5,36 +5,30 @@ from numbers import Real import numpy as np import openmc.checkvalue as cv -import openmc.mgxs class EnergyGroups: - """An energy group structure used for multigroup cross-sections. + """An energy groups structure used for multi-group cross-sections. Parameters ---------- - group_edges : Iterable of float or str - The energy group boundaries in [eV] or the name of the group structure - (Must be a valid key in the openmc.mgxs.GROUP_STRUCTURES dictionary). - - .. versionchanged:: 0.14.0 - Changed to allow a string specifying the group structure name. + group_edges : Iterable of Real + The energy group boundaries [eV] Attributes ---------- - group_edges : np.ndarray - The energy group boundaries in [eV] + group_edges : Iterable of Real + The energy group boundaries [eV] num_groups : int The number of energy groups """ - def __init__(self, group_edges): - if isinstance(group_edges, str): - self._name = group_edges.upper() - group_edges = openmc.mgxs.GROUP_STRUCTURES[self._name] + def __init__(self, group_edges=None): + self._group_edges = None - self.group_edges = group_edges + if group_edges is not None: + self.group_edges = group_edges def __deepcopy__(self, memo): existing = memo.get(id(self)) @@ -65,27 +59,20 @@ class EnergyGroups: def __hash__(self): return hash(tuple(self.group_edges)) - def __repr__(self): - if hasattr(self, '_name'): - return f"" - else: - return f"" - @property def group_edges(self): return self._group_edges - @group_edges.setter - def group_edges(self, edges): - cv.check_type('group edges', edges, Iterable, Real) - cv.check_increasing('group edges', edges) - cv.check_greater_than('number of group edges', len(edges), 1) - self._group_edges = np.array(edges) - @property def num_groups(self): return len(self.group_edges) - 1 + @group_edges.setter + def group_edges(self, edges): + cv.check_type('group edges', edges, Iterable, Real) + cv.check_greater_than('number of group edges', len(edges), 1) + self._group_edges = np.array(edges) + def get_group(self, energy): """Returns the energy group in which the given energy resides. @@ -177,7 +164,7 @@ class EnergyGroups: if groups == 'all': return np.arange(self.num_groups) else: - indices = np.zeros(len(groups), dtype=int) + indices = np.zeros(len(groups), dtype=np.int) for i, group in enumerate(groups): cv.check_greater_than('group', group, 0) @@ -239,7 +226,10 @@ class EnergyGroups: group_edges = np.sort(group_edges) # Create a new condensed EnergyGroups object - return EnergyGroups(group_edges) + condensed_groups = EnergyGroups() + condensed_groups.group_edges = group_edges + + return condensed_groups def can_merge(self, other): """Determine if energy groups can be merged with another. @@ -301,139 +291,3 @@ class EnergyGroups: # Assign merged edges to merged groups merged_groups.group_edges = list(merged_edges) return merged_groups - - -def convert_flux_groups(flux, source_groups, target_groups): - """Convert flux spectrum between energy group structures. - - Uses flux-per-unit-lethargy conservation, which assumes constant flux per - unit lethargy within each source group and distributes flux to target - groups proportionally to their lethargy width. - - .. versionadded:: 0.15.4 - - Parameters - ---------- - flux : Iterable of float - Flux values for source groups. Length must equal - source_groups.num_groups. - source_groups : EnergyGroups or str - Energy group structure of the input flux with boundaries in [eV]. - Can be an EnergyGroups instance or the name of a group structure - (e.g., 'CCFE-709'). - target_groups : EnergyGroups or str - Target energy group structure with boundaries in [eV]. Can be an - EnergyGroups instance or the name of a group structure - (e.g., 'UKAEA-1102'). - - Returns - ------- - numpy.ndarray - Flux values for target groups. Total flux is conserved for - overlapping energy regions. - - Raises - ------ - TypeError - If source_groups or target_groups is not EnergyGroups or str - ValueError - If flux length doesn't match source_groups, or flux contains - negative, NaN, or infinite values - - See Also - -------- - EnergyGroups : Energy group structure class - - Notes - ----- - The assumption of constant flux per unit lethargy within each source - group is physically reasonable for most reactor spectra but is not - exact. For best accuracy, use source spectra with sufficiently fine - energy resolution. - - Examples - -------- - Convert FNS 709-group flux to UKAEA-1102 structure: - - >>> import numpy as np - >>> flux_709 = np.load('tests/fns_flux_709.npy') - >>> flux_1102 = openmc.mgxs.convert_flux_groups(flux_709, 'CCFE-709', 'UKAEA-1102') - - Convert using EnergyGroups instances: - - >>> source = openmc.mgxs.EnergyGroups([1.0, 10.0, 100.0]) - >>> target = openmc.mgxs.EnergyGroups([1.0, 5.0, 10.0, 50.0, 100.0]) - >>> flux_target = openmc.mgxs.convert_flux_groups([1e8, 2e8], source, target) - - References - ---------- - .. [1] J. J. Duderstadt and L. J. Hamilton, "Nuclear Reactor Analysis," - John Wiley & Sons, 1976. - .. [2] M. Fleming and J.-Ch. Sublet, "FISPACT-II User Manual," - UKAEA-R(18)001, UK Atomic Energy Authority, 2018. See GRPCONVERT keyword. - - """ - # Handle string group structure names - if isinstance(source_groups, str): - source_groups = EnergyGroups(source_groups) - if isinstance(target_groups, str): - target_groups = EnergyGroups(target_groups) - - # Type validation - cv.check_type('source_groups', source_groups, EnergyGroups) - cv.check_type('target_groups', target_groups, EnergyGroups) - - # Convert flux to numpy array - flux = np.asarray(flux, dtype=np.float64) - if flux.ndim != 1: - raise ValueError(f'flux must be 1-dimensional, got shape {flux.shape}') - - # Validate flux length matches source groups - if len(flux) != source_groups.num_groups: - raise ValueError( - f'Length of flux ({len(flux)}) must equal number of source ' - f'groups ({source_groups.num_groups})' - ) - - # Check for invalid flux values - if np.any(np.isnan(flux)): - raise ValueError('flux contains NaN values') - if np.any(np.isinf(flux)): - raise ValueError('flux contains infinite values') - if np.any(flux < 0): - raise ValueError('flux values must be non-negative') - - # Get energy edges - source_edges = source_groups.group_edges - target_edges = target_groups.group_edges - num_target = target_groups.num_groups - - # Initialize output array - flux_target = np.zeros(num_target) - - # Main conversion loop: distribute flux using lethargy weighting - for idx_src, flux_src in enumerate(flux): - if flux_src == 0: - continue - - e_low_src = source_edges[idx_src] - e_high_src = source_edges[idx_src + 1] - lethargy_src = np.log(e_high_src / e_low_src) - - for idx_tgt in range(num_target): - e_low_tgt = target_edges[idx_tgt] - e_high_tgt = target_edges[idx_tgt + 1] - - # Skip non-overlapping groups - if e_high_tgt <= e_low_src or e_low_tgt >= e_high_src: - continue - - # Calculate overlap region - e_low_overlap = max(e_low_src, e_low_tgt) - e_high_overlap = min(e_high_src, e_high_tgt) - lethargy_overlap = np.log(e_high_overlap / e_low_overlap) - - # Distribute flux proportionally to lethargy fraction - flux_target[idx_tgt] += flux_src * (lethargy_overlap / lethargy_src) - - return flux_target diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index faa83c048..efe8dbe84 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from collections.abc import Iterable import copy from numbers import Integral @@ -10,10 +11,8 @@ import numpy as np import openmc import openmc.mgxs import openmc.checkvalue as cv -from openmc.checkvalue import PathLike from ..tallies import ESTIMATOR_TYPES -ROOM_TEMPERATURE_KELVIN = 294.0 class Library: """A multi-energy-group and multi-delayed-group cross section library for @@ -73,18 +72,13 @@ class Library: Number of equi-width polar angle bins for angle discretization num_azimuthal : Integral Number of equi-width azimuthal angle bins for angle discretization - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the domain - are included. estimator : str or None The tally estimator used to compute multi-group cross sections. If None, the default for each MGXS type is used. tally_trigger : openmc.Trigger An (optional) tally precision trigger given to each tally used to compute the cross section - all_mgxs : dict + all_mgxs : collections.OrderedDict MGXS objects keyed by domain ID and cross section type sp_filename : str The filename of the statepoint with tally data used to the @@ -113,14 +107,13 @@ class Library: self._energy_groups = None self._num_polar = 1 self._num_azimuthal = 1 - self._nuclides = None self._num_delayed_groups = 0 self._correction = 'P0' self._scatter_format = 'legendre' self._legendre_order = 0 self._histogram_bins = 16 self._tally_trigger = None - self._all_mgxs = {} + self._all_mgxs = OrderedDict() self._sp_filename = None self._keff = None self._sparse = False @@ -152,7 +145,6 @@ class Library: clone._energy_groups = copy.deepcopy(self.energy_groups, memo) clone._num_polar = self.num_polar clone._num_azimuthal = self.num_azimuthal - clone._nuclides = self._nuclides clone._num_delayed_groups = self.num_delayed_groups clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo) clone._all_mgxs = copy.deepcopy(self.all_mgxs) @@ -160,9 +152,9 @@ class Library: clone._keff = self._keff clone._sparse = self.sparse - clone._all_mgxs = {} + clone._all_mgxs = OrderedDict() for domain in self.domains: - clone.all_mgxs[domain.id] = {} + clone.all_mgxs[domain.id] = OrderedDict() for mgxs_type in self.mgxs_types: mgxs = copy.deepcopy(self.all_mgxs[domain.id][mgxs_type]) clone.all_mgxs[domain.id][mgxs_type] = mgxs @@ -179,65 +171,22 @@ class Library: def geometry(self): return self._geometry - @geometry.setter - def geometry(self, geometry): - cv.check_type('geometry', geometry, openmc.Geometry) - self._geometry = geometry - @property def name(self): return self._name - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - @property def mgxs_types(self): return self._mgxs_types - @mgxs_types.setter - def mgxs_types(self, mgxs_types): - all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES + \ - openmc.mgxs.ARBITRARY_VECTOR_TYPES + \ - openmc.mgxs.ARBITRARY_MATRIX_TYPES - if mgxs_types == 'all': - self._mgxs_types = all_mgxs_types - else: - cv.check_iterable_type('mgxs_types', mgxs_types, str) - for mgxs_type in mgxs_types: - cv.check_value('mgxs_type', mgxs_type, all_mgxs_types) - self._mgxs_types = mgxs_types - @property def by_nuclide(self): return self._by_nuclide - @by_nuclide.setter - def by_nuclide(self, by_nuclide): - cv.check_type('by_nuclide', by_nuclide, bool) - - if by_nuclide and self.domain_type == 'mesh': - raise ValueError('Unable to create MGXS library by nuclide with ' - 'mesh domain') - - self._by_nuclide = by_nuclide - @property def domain_type(self): return self._domain_type - @domain_type.setter - def domain_type(self, domain_type): - cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES) - - if self.by_nuclide and domain_type == 'mesh': - raise ValueError('Unable to create MGXS library by nuclide with ' - 'mesh domain') - - self._domain_type = domain_type - @property def domains(self): if self._domains == 'all': @@ -256,6 +205,109 @@ class Library: else: return self._domains + @property + def energy_groups(self): + return self._energy_groups + + @property + def num_delayed_groups(self): + return self._num_delayed_groups + + @property + def num_polar(self): + return self._num_polar + + @property + def num_azimuthal(self): + return self._num_azimuthal + + @property + def correction(self): + return self._correction + + @property + def scatter_format(self): + return self._scatter_format + + @property + def legendre_order(self): + return self._legendre_order + + @property + def histogram_bins(self): + return self._histogram_bins + + @property + def tally_trigger(self): + return self._tally_trigger + + @property + def estimator(self): + return self._estimator + + @property + def num_groups(self): + return self.energy_groups.num_groups + + @property + def all_mgxs(self): + return self._all_mgxs + + @property + def sp_filename(self): + return self._sp_filename + + @property + def keff(self): + return self._keff + + @property + def sparse(self): + return self._sparse + + @geometry.setter + def geometry(self, geometry): + cv.check_type('geometry', geometry, openmc.Geometry) + self._geometry = geometry + + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + + @mgxs_types.setter + def mgxs_types(self, mgxs_types): + all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES + \ + openmc.mgxs.ARBITRARY_VECTOR_TYPES + \ + openmc.mgxs.ARBITRARY_MATRIX_TYPES + if mgxs_types == 'all': + self._mgxs_types = all_mgxs_types + else: + cv.check_iterable_type('mgxs_types', mgxs_types, str) + for mgxs_type in mgxs_types: + cv.check_value('mgxs_type', mgxs_type, all_mgxs_types) + self._mgxs_types = mgxs_types + + @by_nuclide.setter + def by_nuclide(self, by_nuclide): + cv.check_type('by_nuclide', by_nuclide, bool) + + if by_nuclide and self.domain_type == 'mesh': + raise ValueError('Unable to create MGXS library by nuclide with ' + 'mesh domain') + + self._by_nuclide = by_nuclide + + @domain_type.setter + def domain_type(self, domain_type): + cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES) + + if self.by_nuclide and domain_type == 'mesh': + raise ValueError('Unable to create MGXS library by nuclide with ' + 'mesh domain') + + self._domain_type = domain_type + @domains.setter def domains(self, domains): @@ -295,28 +347,11 @@ class Library: self._domains = list(domains) - @property - def nuclides(self): - return self._nuclides - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, str) - self._nuclides = nuclides - - @property - def energy_groups(self): - return self._energy_groups - @energy_groups.setter def energy_groups(self, energy_groups): cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) self._energy_groups = energy_groups - @property - def num_delayed_groups(self): - return self._num_delayed_groups - @num_delayed_groups.setter def num_delayed_groups(self, num_delayed_groups): @@ -326,30 +361,18 @@ class Library: equality=True) self._num_delayed_groups = num_delayed_groups - @property - def num_polar(self): - return self._num_polar - @num_polar.setter def num_polar(self, num_polar): cv.check_type('num_polar', num_polar, Integral) cv.check_greater_than('num_polar', num_polar, 0) self._num_polar = num_polar - @property - def num_azimuthal(self): - return self._num_azimuthal - @num_azimuthal.setter def num_azimuthal(self, num_azimuthal): cv.check_type('num_azimuthal', num_azimuthal, Integral) cv.check_greater_than('num_azimuthal', num_azimuthal, 0) self._num_azimuthal = num_azimuthal - @property - def correction(self): - return self._correction - @correction.setter def correction(self, correction): cv.check_value('correction', correction, ('P0', None)) @@ -367,10 +390,6 @@ class Library: self._correction = correction - @property - def scatter_format(self): - return self._scatter_format - @scatter_format.setter def scatter_format(self, scatter_format): cv.check_value('scatter_format', scatter_format, @@ -384,10 +403,6 @@ class Library: self._scatter_format = scatter_format - @property - def legendre_order(self): - return self._legendre_order - @legendre_order.setter def legendre_order(self, legendre_order): cv.check_type('legendre_order', legendre_order, Integral) @@ -409,10 +424,6 @@ class Library: self._legendre_order = legendre_order - @property - def histogram_bins(self): - return self._histogram_bins - @histogram_bins.setter def histogram_bins(self, histogram_bins): cv.check_type('histogram_bins', histogram_bins, Integral) @@ -432,44 +443,16 @@ class Library: self._histogram_bins = histogram_bins - @property - def tally_trigger(self): - return self._tally_trigger - @tally_trigger.setter def tally_trigger(self, tally_trigger): cv.check_type('tally trigger', tally_trigger, openmc.Trigger) self._tally_trigger = tally_trigger - @property - def estimator(self): - return self._estimator - @estimator.setter def estimator(self, estimator): cv.check_value('estimator', estimator, ESTIMATOR_TYPES) self._estimator = estimator - @property - def num_groups(self): - return self.energy_groups.num_groups - - @property - def all_mgxs(self): - return self._all_mgxs - - @property - def sp_filename(self): - return self._sp_filename - - @property - def keff(self): - return self._keff - - @property - def sparse(self): - return self._sparse - @sparse.setter def sparse(self, sparse): """Convert tally data from NumPy arrays to SciPy list of lists (LIL) @@ -504,7 +487,7 @@ class Library: # Initialize MGXS for each domain and mgxs type and store in dictionary for domain in self.domains: - self.all_mgxs[domain.id] = {} + self.all_mgxs[domain.id] = OrderedDict() for mgxs_type in self.mgxs_types: if mgxs_type in openmc.mgxs.MDGXS_TYPES: mgxs = openmc.mgxs.MDGXS.get_mgxs( @@ -541,30 +524,16 @@ class Library: mgxs.legendre_order = self.legendre_order mgxs.histogram_bins = self.histogram_bins - if self.by_nuclide: - try: - domain_nuclides = domain.get_nuclides() - except AttributeError: - domain_nuclides = None - if self.nuclides: - if domain_nuclides: - mgxs.nuclides = [ - nuclide for nuclide in self.nuclides - if nuclide in domain_nuclides - ] + ["total"] - else: - mgxs.nuclides = self.nuclides - self.all_mgxs[domain.id][mgxs_type] = mgxs - def add_to_tallies(self, tallies, merge=True): - """Add tallies from all MGXS objects to a tallies object. + def add_to_tallies_file(self, tallies_file, merge=True): + """Add all tallies from all MGXS objects to a tallies file. NOTE: This assumes that :meth:`Library.build_library` has been called Parameters ---------- - tallies : openmc.Tallies + tallies_file : openmc.Tallies A Tallies collection to add each MGXS' tallies to generate a 'tallies.xml' input file for OpenMC merge : bool @@ -573,7 +542,7 @@ class Library: """ - cv.check_type('tallies', tallies, openmc.Tallies) + cv.check_type('tallies_file', tallies_file, openmc.Tallies) # Add tallies from each MGXS for each domain and mgxs type for domain in self.domains: @@ -588,15 +557,7 @@ class Library: = list(range(1, self.num_delayed_groups + 1)) for tally in mgxs.tallies.values(): - tallies.append(tally, merge=merge) - - def add_to_tallies_file(self, tallies_file, merge=True): - warn( - "The Library.add_to_tallies_file(...) method has been renamed to" - "add_to_tallies(...) and will be removed in a future version of " - "OpenMC.", FutureWarning - ) - self.add_to_tallies(tallies_file, merge=merge) + tallies_file.append(tally, merge=merge) def load_from_statepoint(self, statepoint): """Extracts tallies in an OpenMC StatePoint with the data needed to @@ -629,7 +590,7 @@ class Library: self._sp_filename = statepoint._f.filename self._geometry = statepoint.summary.geometry - self._atomic_weight_ratios = statepoint.summary.nuclides + self._nuclides = statepoint.summary.nuclides if statepoint.run_mode == 'eigenvalue': self._keff = statepoint.keff.n @@ -695,7 +656,7 @@ class Library: # Check that requested domain is included in library if mgxs_type not in self.mgxs_types: - msg = f'Unable to find MGXS type "{mgxs_type}"' + msg = 'Unable to find MGXS type "{0}"'.format(mgxs_type) raise ValueError(msg) return self.all_mgxs[domain_id][mgxs_type] @@ -861,7 +822,7 @@ class Library: 'since a statepoint has not yet been loaded' raise ValueError(msg) - cv.check_type('filename', filename, (str, PathLike)) + cv.check_type('filename', filename, str) cv.check_type('directory', directory, str) import h5py @@ -904,14 +865,14 @@ class Library: """ - cv.check_type('filename', filename, (str, PathLike)) + cv.check_type('filename', filename, str) cv.check_type('directory', directory, str) # Make directory if it does not exist if not os.path.exists(directory): os.makedirs(directory) - full_filename = os.path.join(directory, f'{filename}.pkl') + full_filename = os.path.join(directory, '{}.pkl'.format(filename)) full_filename = full_filename.replace(' ', '-') # Load and return pickled Library object @@ -940,7 +901,7 @@ class Library: """ - cv.check_type('filename', filename, (str, PathLike)) + cv.check_type('filename', filename, str) cv.check_type('directory', directory, str) # Make directory if it does not exist @@ -955,7 +916,7 @@ class Library: return pickle.load(f) def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro', - subdomain=None, apply_domain_chi=False, temperature=ROOM_TEMPERATURE_KELVIN): + subdomain=None, apply_domain_chi=False): """Generates an openmc.XSdata object describing a multi-group cross section dataset for writing to an openmc.MGXSLibrary object. @@ -991,9 +952,6 @@ class Library: downstream multigroup solvers that precompute a material-specific chi before the transport solve provides group-wise fluxes. Defaults to False. - temperature : float, optional - The temperature to set in the XSdata object. Defaults to 294 K - (room temperature). Returns ------- @@ -1040,7 +998,6 @@ class Library: else: representation = 'isotropic' xsdata = openmc.XSdata(name, self.energy_groups, - temperatures=[temperature], representation=representation) xsdata.num_delayed_groups = self.num_delayed_groups if self.num_polar > 1 or self.num_azimuthal > 1: @@ -1048,7 +1005,7 @@ class Library: xsdata.num_azimuthal = self.num_azimuthal if nuclide != 'total': - xsdata.atomic_weight_ratio = self._atomic_weight_ratios[nuclide] + xsdata.atomic_weight_ratio = self._nuclides[nuclide] if subdomain is None: subdomain = 'all' @@ -1058,61 +1015,45 @@ class Library: # Now get xs data itself if 'nu-transport' in self.mgxs_types and self.correction == 'P0': mymgxs = self.get_mgxs(domain, 'nu-transport') - xsdata.set_total_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuclide], + xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) elif 'transport' in self.mgxs_types and self.correction == 'P0': mymgxs = self.get_mgxs(domain, 'transport') - xsdata.set_total_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuclide], + xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) elif 'total' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'total') - xsdata.set_total_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuclide], + xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'absorption' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'absorption') - xsdata.set_absorption_mgxs(mymgxs, - temperature=temperature, - xs_type=xs_type, + xsdata.set_absorption_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'fission' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'fission') - xsdata.set_fission_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuclide], - subdomain=subdomain) + xsdata.set_fission_mgxs(mymgxs, xs_type=xs_type, + nuclide=[nuclide], subdomain=subdomain) if 'kappa-fission' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'kappa-fission') - xsdata.set_kappa_fission_mgxs(mymgxs, - temperature=temperature, - xs_type=xs_type, + xsdata.set_kappa_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'inverse-velocity' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'inverse-velocity') - xsdata.set_inverse_velocity_mgxs(mymgxs, - temperature=temperature, - xs_type=xs_type, + xsdata.set_inverse_velocity_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'nu-fission matrix' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'nu-fission matrix') - xsdata.set_nu_fission_mgxs(mymgxs, - temperature=temperature, - xs_type=xs_type, + xsdata.set_nu_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) @@ -1122,9 +1063,7 @@ class Library: nuc = "sum" else: nuc = nuclide - xsdata.set_chi_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuc], + xsdata.set_chi_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuc], subdomain=subdomain) if 'chi-prompt' in self.mgxs_types: @@ -1133,10 +1072,8 @@ class Library: nuc = "sum" else: nuc = nuclide - xsdata.set_chi_prompt_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuc], - subdomain=subdomain) + xsdata.set_chi_prompt_mgxs(mymgxs, xs_type=xs_type, + nuclide=[nuc], subdomain=subdomain) if 'chi-delayed' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'chi-delayed') @@ -1144,61 +1081,53 @@ class Library: nuc = "sum" else: nuc = nuclide - xsdata.set_chi_delayed_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, - nuclide=[nuc], - subdomain=subdomain) + xsdata.set_chi_delayed_mgxs(mymgxs, xs_type=xs_type, + nuclide=[nuc], subdomain=subdomain) if 'nu-fission' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'nu-fission') - xsdata.set_nu_fission_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_nu_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'prompt-nu-fission' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'prompt-nu-fission') - xsdata.set_prompt_nu_fission_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_prompt_nu_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'prompt-nu-fission matrix' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'prompt-nu-fission matrix') - xsdata.set_prompt_nu_fission_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_prompt_nu_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'delayed-nu-fission' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'delayed-nu-fission') - xsdata.set_delayed_nu_fission_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_delayed_nu_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'delayed-nu-fission matrix' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'delayed-nu-fission matrix') - xsdata.set_delayed_nu_fission_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_delayed_nu_fission_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) if 'beta' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'beta') - xsdata.set_beta_mgxs(mymgxs, temperature=temperature, xs_type=xs_type, - nuclide=[nuclide], subdomain=subdomain) + xsdata.set_beta_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], + subdomain=subdomain) if 'decay-rate' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'decay-rate') - xsdata.set_decay_rate_mgxs(mymgxs, temperature=temperature, xs_type=xs_type, - nuclide=[nuclide], subdomain=subdomain) + xsdata.set_decay_rate_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], + subdomain=subdomain) # If multiplicity matrix is available, prefer that if 'multiplicity matrix' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'multiplicity matrix') - xsdata.set_multiplicity_matrix_mgxs(mymgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_multiplicity_matrix_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) using_multiplicity = True @@ -1209,7 +1138,6 @@ class Library: scatt_mgxs = self.get_mgxs(domain, 'scatter matrix') nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix') xsdata.set_multiplicity_matrix_mgxs(nuscatt_mgxs, scatt_mgxs, - temperature=temperature, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) @@ -1222,7 +1150,6 @@ class Library: nuscatt_mgxs = \ self.get_mgxs(domain, 'consistent nu-scatter matrix') xsdata.set_multiplicity_matrix_mgxs(nuscatt_mgxs, scatt_mgxs, - temperature=temperature, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) @@ -1237,8 +1164,7 @@ class Library: else: nuscatt_mgxs = \ self.get_mgxs(domain, 'consistent nu-scatter matrix') - xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) else: @@ -1249,8 +1175,7 @@ class Library: else: nuscatt_mgxs = \ self.get_mgxs(domain, 'consistent nu-scatter matrix') - xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) @@ -1290,23 +1215,14 @@ class Library: 'are ignored since multiplicity or nu-scatter matrices '\ 'were not tallied for ' + xsdata_name warn(msg, RuntimeWarning) - - if 'scatter matrix' in self.mgxs_types: - scatt_mgxs = self.get_mgxs(domain, 'scatter matrix') - elif 'consistent scatter matrix' in self.mgxs_types: - scatt_mgxs = self.get_mgxs(domain, 'consistent scatter matrix') - else: - raise ValueError(f'No scatter matrix found for {xsdata_name}.') - - xsdata.set_scatter_matrix_mgxs(scatt_mgxs, temperature=temperature, - xs_type=xs_type, + xsdata.set_scatter_matrix_mgxs(scatt_mgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) return xsdata def create_mg_library(self, xs_type='macro', xsdata_names=None, - apply_domain_chi=False, temperature=ROOM_TEMPERATURE_KELVIN): + apply_domain_chi=False): """Creates an openmc.MGXSLibrary object to contain the MGXS data for the Multi-Group mode of OpenMC. @@ -1332,9 +1248,6 @@ class Library: downstream multigroup solvers that precompute a material-specific chi before the transport solve provides group-wise fluxes. Defaults to False. - temperature : float, optional - The temperature to set in the MGXSLibrary object. Defaults to 294 K - (room temperature). Returns ------- diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index 57cc955ba..287a2961d 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -1,3 +1,4 @@ +from collections import OrderedDict import copy import itertools from numbers import Integral @@ -7,7 +8,6 @@ import numpy as np import openmc import openmc.checkvalue as cv -from openmc.checkvalue import PathLike from openmc.mgxs import MGXS from .mgxs import _DOMAIN_TO_FILTER @@ -21,7 +21,7 @@ MDGXS_TYPES = ( 'delayed-nu-fission matrix' ) -# Maximum number of delayed groups, from include/openmc/constants.h +# Maximum number of delayed groups, from src/constants.F90 MAX_DELAYED_GROUPS = 8 @@ -90,7 +90,7 @@ class MDGXS(MGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -161,7 +161,7 @@ class MDGXS(MGXS): clone._sparse = self.sparse clone._derived = self.derived - clone._tallies = {} + clone._tallies = OrderedDict() for tally_type, tally in self.tallies.items(): clone.tallies[tally_type] = copy.deepcopy(tally, memo) @@ -187,6 +187,13 @@ class MDGXS(MGXS): def delayed_groups(self): return self._delayed_groups + @property + def num_delayed_groups(self): + if self.delayed_groups is None: + return 1 + else: + return len(self.delayed_groups) + @delayed_groups.setter def delayed_groups(self, delayed_groups): @@ -203,13 +210,6 @@ class MDGXS(MGXS): self._delayed_groups = delayed_groups - @property - def num_delayed_groups(self): - if self.delayed_groups is None: - return 1 - else: - return len(self.delayed_groups) - @property def filters(self): @@ -217,7 +217,7 @@ class MDGXS(MGXS): group_edges = self.energy_groups.group_edges energy_filter = openmc.EnergyFilter(group_edges) - if self.delayed_groups is not None: + if self.delayed_groups != None: delayed_filter = openmc.DelayedGroupFilter(self.delayed_groups) filters = [[energy_filter], [delayed_filter, energy_filter]] else: @@ -586,7 +586,7 @@ class MDGXS(MGXS): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=int) + subdomains = np.arange(self.num_subdomains, dtype=np.int) elif self.domain_type == 'mesh': xyz = [range(1, x + 1) for x in self.domain.dimension] subdomains = list(itertools.product(*xyz)) @@ -613,7 +613,7 @@ class MDGXS(MGXS): string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' + xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) # If cross section data has not been computed, only print string header if self.tallies is None: @@ -642,7 +642,7 @@ class MDGXS(MGXS): string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Add the cross section header - string += f'{xs_header: <16}\n' + string += '{0: <16}\n'.format(xs_header) for delayed_group in self.delayed_groups: @@ -723,7 +723,7 @@ class MDGXS(MGXS): """ - cv.check_type('filename', filename, (str, PathLike)) + cv.check_type('filename', filename, str) cv.check_type('directory', directory, str) cv.check_value('format', format, ['csv', 'excel', 'pickle', 'latex']) cv.check_value('xs_type', xs_type, ['macro', 'micro']) @@ -744,9 +744,9 @@ class MDGXS(MGXS): df.to_csv(filename + '.csv', index=False) elif format == 'excel': if self.domain_type == 'mesh': - df.to_excel(filename + '.xlsx') + df.to_excel(filename + '.xls') else: - df.to_excel(filename + '.xlsx', index=False) + df.to_excel(filename + '.xls', index=False) elif format == 'pickle': df.to_pickle(filename + '.pkl') elif format == 'latex': @@ -876,9 +876,9 @@ class MDGXS(MGXS): # Sort the dataframe by domain type id (e.g., distribcell id) and # energy groups such that data is from fast to thermal if self.domain_type == 'mesh': - mesh_str = f'mesh {self.domain.id}' - mesh_cols = [(mesh_str, label) for label in self.domain._axis_labels] - df.sort_values(by=mesh_cols + columns, inplace=True) + mesh_str = 'mesh {0}'.format(self.domain.id) + df.sort_values(by=[(mesh_str, 'x'), (mesh_str, 'y'), + (mesh_str, 'z')] + columns, inplace=True) else: df.sort_values(by=[self.domain_type] + columns, inplace=True) @@ -972,7 +972,7 @@ class ChiDelayed(MDGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`ChiDelayed.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1491,7 +1491,7 @@ class DelayedNuFissionXS(MDGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`DelayedNuFissionXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1630,7 +1630,7 @@ class Beta(MDGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`Beta.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1823,7 +1823,7 @@ class DecayRate(MDGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`DecayRate.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1885,6 +1885,9 @@ class DecayRate(MDGXS): @property def filters(self): + # Create the non-domain specific Filters for the Tallies + group_edges = self.energy_groups.group_edges + if self.delayed_groups is not None: delayed_filter = openmc.DelayedGroupFilter(self.delayed_groups) filters = [[delayed_filter], [delayed_filter]] @@ -2134,7 +2137,7 @@ class MatrixMDGXS(MDGXS): the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -2470,7 +2473,7 @@ class MatrixMDGXS(MDGXS): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=int) + subdomains = np.arange(self.num_subdomains, dtype=np.int) elif self.domain_type == 'mesh': xyz = [range(1, x + 1) for x in self.domain.dimension] subdomains = list(itertools.product(*xyz)) @@ -2497,7 +2500,7 @@ class MatrixMDGXS(MDGXS): string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' + xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) # If cross section data has not been computed, only print string header if self.tallies is None: @@ -2533,7 +2536,7 @@ class MatrixMDGXS(MDGXS): string += '{: <16}=\t{}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += f'{xs_header: <16}\n' + string += '{: <16}\n'.format(xs_header) if self.delayed_groups is not None: @@ -2732,7 +2735,7 @@ class DelayedNuFissionMatrixXS(MatrixMDGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`DelayedNuFissionXS.tally_keys` property and values are instances of :class:`openmc.Tally`. diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 4c13c7508..46a6ed35c 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -1,8 +1,8 @@ +from collections import OrderedDict import copy from numbers import Integral import os import warnings -from textwrap import dedent import h5py import numpy as np @@ -10,7 +10,6 @@ import numpy as np import openmc from openmc.data import REACTION_MT, REACTION_NAME, FISSION_MTS import openmc.checkvalue as cv -from openmc.checkvalue import PathLike from ..tallies import ESTIMATOR_TYPES from . import EnergyGroups @@ -166,7 +165,7 @@ class MGXS: """ - _params = dedent(""" + _params = """ Parameters ---------- domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh @@ -217,7 +216,7 @@ class MGXS: the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -253,7 +252,7 @@ class MGXS: .. versionadded:: 0.13.1 - """) + """ # Store whether or not the number density should be removed for microscopic # values of this data @@ -320,7 +319,7 @@ class MGXS: clone._derived = self.derived clone._mgxs_type = self._mgxs_type - clone._tallies = {} + clone._tallies = OrderedDict() for tally_type, tally in self.tallies.items(): clone.tallies[tally_type] = copy.deepcopy(tally, memo) @@ -454,11 +453,6 @@ class MGXS: def name(self): return self._name - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - @property def rxn_type(self): return self._rxn_type @@ -467,78 +461,30 @@ class MGXS: def by_nuclide(self): return self._by_nuclide - @by_nuclide.setter - def by_nuclide(self, by_nuclide): - cv.check_type('by_nuclide', by_nuclide, bool) - self._by_nuclide = by_nuclide - @property def domain(self): return self._domain - @domain.setter - def domain(self, domain): - cv.check_type('domain', domain, _DOMAINS) - self._domain = domain - - # Assign a domain type - if self.domain_type is None: - if isinstance(domain, openmc.Material): - self._domain_type = 'material' - elif isinstance(domain, openmc.Cell): - self._domain_type = 'cell' - elif isinstance(domain, openmc.Universe): - self._domain_type = 'universe' - elif isinstance(domain, openmc.RegularMesh): - self._domain_type = 'mesh' - @property def domain_type(self): return self._domain_type - @domain_type.setter - def domain_type(self, domain_type): - cv.check_value('domain type', domain_type, DOMAIN_TYPES) - self._domain_type = domain_type - @property def energy_groups(self): return self._energy_groups - @energy_groups.setter - def energy_groups(self, energy_groups): - cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) - self._energy_groups = energy_groups - @property def num_polar(self): return self._num_polar - @num_polar.setter - def num_polar(self, num_polar): - cv.check_type('num_polar', num_polar, Integral) - cv.check_greater_than('num_polar', num_polar, 0) - self._num_polar = num_polar - @property def num_azimuthal(self): return self._num_azimuthal - @num_azimuthal.setter - def num_azimuthal(self, num_azimuthal): - cv.check_type('num_azimuthal', num_azimuthal, Integral) - cv.check_greater_than('num_azimuthal', num_azimuthal, 0) - self._num_azimuthal = num_azimuthal - @property def tally_trigger(self): return self._tally_trigger - @tally_trigger.setter - def tally_trigger(self, tally_trigger): - cv.check_type('tally trigger', tally_trigger, openmc.Trigger) - self._tally_trigger = tally_trigger - @property def num_groups(self): return self.energy_groups.num_groups @@ -565,11 +511,6 @@ class MGXS: def estimator(self): return self._estimator - @estimator.setter - def estimator(self, estimator): - cv.check_value('estimator', estimator, self._valid_estimators) - self._estimator = estimator - @property def tallies(self): @@ -577,7 +518,7 @@ class MGXS: if self._tallies is None: # Initialize a collection of Tallies - self._tallies ={} + self._tallies = OrderedDict() # Create a domain Filter object filter_type = _DOMAIN_TO_FILTER[self.domain_type] @@ -644,31 +585,6 @@ class MGXS: def sparse(self): return self._sparse - @sparse.setter - def sparse(self, sparse): - """Convert tally data from NumPy arrays to SciPy list of lists (LIL) - sparse matrices, and vice versa. - - This property may be used to reduce the amount of data in memory during - tally data processing. The tally data will be stored as SciPy LIL - matrices internally within the Tally object. All tally data access - properties and methods will return data as a dense NumPy array. - - """ - - cv.check_type('sparse', sparse, bool) - - # Sparsify or densify the derived MGXS tallies and the base tallies - if self._xs_tally: - self.xs_tally.sparse = sparse - if self._rxn_rate_tally: - self.rxn_rate_tally.sparse = sparse - - for tally_name in self.tallies: - self.tallies[tally_name].sparse = sparse - - self._sparse = sparse - @property def num_subdomains(self): if self.domain_type.startswith('sum('): @@ -696,11 +612,6 @@ class MGXS: else: return ['sum'] - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, str) - self._nuclides = nuclides - @property def loaded_sp(self): return self._loaded_sp @@ -716,6 +627,94 @@ class MGXS: else: return self._rxn_type + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + + @by_nuclide.setter + def by_nuclide(self, by_nuclide): + cv.check_type('by_nuclide', by_nuclide, bool) + self._by_nuclide = by_nuclide + + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, str) + self._nuclides = nuclides + + @estimator.setter + def estimator(self, estimator): + cv.check_value('estimator', estimator, self._valid_estimators) + self._estimator = estimator + + @domain.setter + def domain(self, domain): + cv.check_type('domain', domain, _DOMAINS) + self._domain = domain + + # Assign a domain type + if self.domain_type is None: + if isinstance(domain, openmc.Material): + self._domain_type = 'material' + elif isinstance(domain, openmc.Cell): + self._domain_type = 'cell' + elif isinstance(domain, openmc.Universe): + self._domain_type = 'universe' + elif isinstance(domain, openmc.RegularMesh): + self._domain_type = 'mesh' + + @domain_type.setter + def domain_type(self, domain_type): + cv.check_value('domain type', domain_type, DOMAIN_TYPES) + self._domain_type = domain_type + + @energy_groups.setter + def energy_groups(self, energy_groups): + cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) + self._energy_groups = energy_groups + + @num_polar.setter + def num_polar(self, num_polar): + cv.check_type('num_polar', num_polar, Integral) + cv.check_greater_than('num_polar', num_polar, 0) + self._num_polar = num_polar + + @num_azimuthal.setter + def num_azimuthal(self, num_azimuthal): + cv.check_type('num_azimuthal', num_azimuthal, Integral) + cv.check_greater_than('num_azimuthal', num_azimuthal, 0) + self._num_azimuthal = num_azimuthal + + @tally_trigger.setter + def tally_trigger(self, tally_trigger): + cv.check_type('tally trigger', tally_trigger, openmc.Trigger) + self._tally_trigger = tally_trigger + + @sparse.setter + def sparse(self, sparse): + """Convert tally data from NumPy arrays to SciPy list of lists (LIL) + sparse matrices, and vice versa. + + This property may be used to reduce the amount of data in memory during + tally data processing. The tally data will be stored as SciPy LIL + matrices internally within the Tally object. All tally data access + properties and methods will return data as a dense NumPy array. + + """ + + cv.check_type('sparse', sparse, bool) + + # Sparsify or densify the derived MGXS tallies and the base tallies + if self._xs_tally: + self.xs_tally.sparse = sparse + if self._rxn_rate_tally: + self.rxn_rate_tally.sparse = sparse + + for tally_name in self.tallies: + self.tallies[tally_name].sparse = sparse + + self._sparse = sparse + @staticmethod def get_mgxs(mgxs_type, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, @@ -919,20 +918,20 @@ class MGXS: # Sum the atomic number densities for all nuclides if nuclides == 'sum': nuclides = self.get_nuclides() - densities = np.zeros(1, dtype=float) + densities = np.zeros(1, dtype=np.float) for nuclide in nuclides: densities[0] += self.get_nuclide_density(nuclide) # Tabulate the atomic number densities for all nuclides elif nuclides == 'all': nuclides = self.get_nuclides() - densities = np.zeros(self.num_nuclides, dtype=float) + densities = np.zeros(self.num_nuclides, dtype=np.float) for i, nuclide in enumerate(nuclides): densities[i] += self.get_nuclide_density(nuclide) # Tabulate the atomic number densities for each specified nuclide else: - densities = np.zeros(len(nuclides), dtype=float) + densities = np.zeros(len(nuclides), dtype=np.float) for i, nuclide in enumerate(nuclides): densities[i] = self.get_nuclide_density(nuclide) @@ -958,7 +957,7 @@ class MGXS: self.xs_tally._nuclides = [] nuclides = self.get_nuclides() for nuclide in nuclides: - self.xs_tally.nuclides.append(nuclide) + self.xs_tally.nuclides.append(openmc.Nuclide(nuclide)) # Remove NaNs which may have resulted from divide-by-zero operations self.xs_tally._mean = np.nan_to_num(self.xs_tally.mean) @@ -1429,7 +1428,7 @@ class MGXS: filter_bins=subdomains) avg_xs.tallies[tally_type] = tally_avg - avg_xs._domain_type = f'sum({self.domain_type})' + avg_xs._domain_type = 'sum({0})'.format(self.domain_type) avg_xs.sparse = self.sparse return avg_xs @@ -1480,7 +1479,7 @@ class MGXS: # Clone this MGXS to initialize the homogenized version homogenized_mgxs = copy.deepcopy(self) homogenized_mgxs._derived = True - name = f'hom({self.domain.name}, ' + name = 'hom({}, '.format(self.domain.name) # Get the domain filter filter_type = _DOMAIN_TO_FILTER[self.domain_type] @@ -1507,7 +1506,7 @@ class MGXS: denom_tally += other_denom_tally # Update the name for the homogenzied MGXS - name += f'{mgxs.domain.name}, ' + name += '{}, '.format(mgxs.domain.name) # Set the properties of the homogenized MGXS homogenized_mgxs._rxn_rate_tally = rxn_rate_tally @@ -1691,7 +1690,7 @@ class MGXS: merged_mgxs.nuclides = self.nuclides + other.nuclides # Null base tallies but merge reaction rate and cross section tallies - merged_mgxs._tallies ={} + merged_mgxs._tallies = OrderedDict() merged_mgxs._rxn_rate_tally = self.rxn_rate_tally.merge(other.rxn_rate_tally) merged_mgxs._xs_tally = self.xs_tally.merge(other.xs_tally) @@ -1721,7 +1720,7 @@ class MGXS: if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=int) + subdomains = np.arange(self.num_subdomains, dtype=np.int) elif self.domain_type == 'mesh': subdomains = list(self.domain.indices) else: @@ -1747,7 +1746,7 @@ class MGXS: string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' + xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) # If cross section data has not been computed, only print string header if self.tallies is None: @@ -1775,7 +1774,7 @@ class MGXS: string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += f'{xs_header: <16}\n' + string += '{0: <16}\n'.format(xs_header) template = '{0: <12}Group {1} [{2: <10} - {3: <10}eV]:\t' average_xs = self.get_xs(nuclides=[nuclide], @@ -1888,7 +1887,7 @@ class MGXS: if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=int) + subdomains = np.arange(self.num_subdomains, dtype=np.int) elif self.domain_type == 'sum(distribcell)': domain_filter = self.xs_tally.find_filter('sum(distribcell)') subdomains = domain_filter.bins @@ -1901,7 +1900,7 @@ class MGXS: if self.by_nuclide: if nuclides == 'all': nuclides = self.get_nuclides() - densities = np.zeros(len(nuclides), dtype=float) + densities = np.zeros(len(nuclides), dtype=np.float) elif nuclides == 'sum': nuclides = ['sum'] else: @@ -1923,7 +1922,7 @@ class MGXS: # Create an HDF5 group for the subdomain if self.domain_type == 'distribcell': - group_name = str(subdomain).zfill(num_digits) + group_name = ''.zfill(num_digits) subdomain_group = domain_group.require_group(group_name) else: subdomain_group = domain_group @@ -1983,7 +1982,7 @@ class MGXS: """ - cv.check_type('filename', filename, (str, PathLike)) + cv.check_type('filename', filename, str) cv.check_type('directory', directory, str) cv.check_value('format', format, ['csv', 'excel', 'pickle', 'latex']) cv.check_value('xs_type', xs_type, ['macro', 'micro']) @@ -2003,9 +2002,9 @@ class MGXS: df.to_csv(filename + '.csv', index=False) elif format == 'excel': if self.domain_type == 'mesh': - df.to_excel(filename + '.xlsx') + df.to_excel(filename + '.xls') else: - df.to_excel(filename + '.xlsx', index=False) + df.to_excel(filename + '.xls', index=False) elif format == 'pickle': df.to_pickle(filename + '.pkl') elif format == 'latex': @@ -2127,15 +2126,15 @@ class MGXS: df['std. dev.'] /= np.tile(densities, tile_factor) # Replace NaNs by zeros (happens if nuclide density is zero) - df['mean'] = df['mean'].replace(np.nan, 0.0) - df['std. dev.'] = df['std. dev.'].replace(np.nan, 0.0) + df['mean'].replace(np.nan, 0.0, inplace=True) + df['std. dev.'].replace(np.nan, 0.0, inplace=True) # Sort the dataframe by domain type id (e.g., distribcell id) and # energy groups such that data is from fast to thermal if self.domain_type == 'mesh': - mesh_str = f'mesh {self.domain.id}' - mesh_cols = [(mesh_str, label) for label in self.domain._axis_labels] - df.sort_values(by=mesh_cols + columns, inplace=True) + mesh_str = 'mesh {0}'.format(self.domain.id) + df.sort_values(by=[(mesh_str, 'x'), (mesh_str, 'y'), + (mesh_str, 'z')] + columns, inplace=True) else: df.sort_values(by=[self.domain_type] + columns, inplace=True) @@ -2448,7 +2447,7 @@ class MatrixMGXS(MGXS): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=int) + subdomains = np.arange(self.num_subdomains, dtype=np.int) elif self.domain_type == 'mesh': subdomains = list(self.domain.indices) else: @@ -2474,7 +2473,7 @@ class MatrixMGXS(MGXS): string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' + xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) # If cross section data has not been computed, only print string header if self.tallies is None: @@ -2510,7 +2509,7 @@ class MatrixMGXS(MGXS): string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += f'{xs_header: <16}\n' + string += '{0: <16}\n'.format(xs_header) template = '{0: <12}Group {1} -> Group {2}:\t\t' average_xs = self.get_xs(nuclides=[nuclide], @@ -2691,7 +2690,7 @@ class TransportXS(MGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`TransportXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -2932,7 +2931,7 @@ class DiffusionCoefficient(TransportXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`TransportXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -3012,137 +3011,30 @@ class DiffusionCoefficient(TransportXS): raise ValueError(msg) # Switch EnergyoutFilter to EnergyFilter - # If 'scatter-1' is not in tallies, it is because the transport correction has - # already occurred on this MGXS in another function or in a previous call to this function. - if 'scatter-1' in self.tallies: - p1_tally = self.tallies['scatter-1'] - old_filt = p1_tally.filters[-2] - new_filt = openmc.EnergyFilter(old_filt.values) - p1_tally.filters[-2] = new_filt - - p1_tally = p1_tally.get_slice(filters=[openmc.LegendreFilter], - filter_bins=[('P1',)],squeeze=True) - p1_tally._scores = ['scatter-1'] - total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] - trans_corr = p1_tally / self.tallies['flux (analog)'] - transport = total_xs - trans_corr - diff_coef = transport**(-1) / 3.0 - self._xs_tally = diff_coef - self._compute_xs() - - else: - self._xs_tally = self.tallies[self._rxn_type] / self.tallies['flux (tracklength)'] - self._compute_xs() - - return self._xs_tally - - def get_condensed_xs(self, coarse_groups): - """Construct an energy-condensed version of this cross section. - - Parameters - ---------- - coarse_groups : openmc.mgxs.EnergyGroups - The coarse energy group structure of interest - - Returns - ------- - MGXS - A new MGXS condensed to the group structure of interest - - """ - - cv.check_type('coarse_groups', coarse_groups, EnergyGroups) - cv.check_less_than('coarse groups', coarse_groups.num_groups, - self.num_groups, equality=True) - cv.check_value('upper coarse energy', coarse_groups.group_edges[-1], - [self.energy_groups.group_edges[-1]]) - cv.check_value('lower coarse energy', coarse_groups.group_edges[0], - [self.energy_groups.group_edges[0]]) - - # Clone this MGXS to initialize the condensed version - condensed_xs = copy.deepcopy(self) - - # If 'scatter-1' is not in tallies, it is because the transport correction has - # already occurred on this MGXS in another function or in a previous call to this function. - if 'scatter-1' in self.tallies: p1_tally = self.tallies['scatter-1'] old_filt = p1_tally.filters[-2] new_filt = openmc.EnergyFilter(old_filt.values) p1_tally.filters[-2] = new_filt + + # Slice Legendre expansion filter and change name of score p1_tally = p1_tally.get_slice(filters=[openmc.LegendreFilter], filter_bins=[('P1',)], squeeze=True) p1_tally._scores = ['scatter-1'] + + # Compute total cross section total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] + + # Compute transport correction term trans_corr = p1_tally / self.tallies['flux (analog)'] + + # Compute the diffusion coefficient transport = total_xs - trans_corr diff_coef = transport**(-1) / 3.0 - diff_coef *= self.tallies['flux (tracklength)'] - flux_tally = condensed_xs.tallies['flux (tracklength)'] - condensed_xs._tallies = {} - condensed_xs._tallies[self._rxn_type] = diff_coef - condensed_xs._tallies['flux (tracklength)'] = flux_tally - condensed_xs._rxn_rate_tally = diff_coef - condensed_xs._xs_tally = None - condensed_xs._sparse = False - condensed_xs._energy_groups = coarse_groups + self._xs_tally = diff_coef + self._compute_xs() - else: - condensed_xs._rxn_rate_tally = None - condensed_xs._xs_tally = None - condensed_xs._sparse = False - condensed_xs._energy_groups = coarse_groups - - # Build energy indices to sum across - energy_indices = [] - for group in range(coarse_groups.num_groups, 0, -1): - low, high = coarse_groups.get_group_bounds(group) - low_index = np.where(self.energy_groups.group_edges == low)[0][0] - energy_indices.append(low_index) - - fine_edges = self.energy_groups.group_edges - - # Condense each of the tallies to the coarse group structure - for tally in condensed_xs.tallies.values(): - - # Make condensed tally derived and null out sum, sum_sq - tally._derived = True - tally._sum = None - tally._sum_sq = None - - # Get tally data arrays reshaped with one dimension per filter - mean = tally.get_reshaped_data(value='mean') - std_dev = tally.get_reshaped_data(value='std_dev') - - # Sum across all applicable fine energy group filters - for i, tally_filter in enumerate(tally.filters): - if not isinstance(tally_filter, (openmc.EnergyFilter, - openmc.EnergyoutFilter)): - continue - elif len(tally_filter.bins) != len(fine_edges) - 1: - continue - elif not np.allclose(tally_filter.bins[:, 0], fine_edges[:-1]): - continue - else: - cedge = coarse_groups.group_edges - tally_filter.values = cedge - tally_filter.bins = np.vstack((cedge[:-1], cedge[1:])).T - mean = np.add.reduceat(mean, energy_indices, axis=i) - std_dev = np.add.reduceat(std_dev**2, energy_indices, - axis=i) - std_dev = np.sqrt(std_dev) - - # Reshape condensed data arrays with one dimension for all filters - mean = np.reshape(mean, tally.shape) - std_dev = np.reshape(std_dev, tally.shape) - - # Override tally's data with the new condensed data - tally._mean = mean - tally._std_dev = std_dev - - # Compute the energy condensed multi-group cross section - condensed_xs.sparse = self.sparse - return condensed_xs + return self._xs_tally @add_params class AbsorptionXS(MGXS): @@ -3395,7 +3287,7 @@ class FissionXS(MGXS): the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`FissionXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -3454,6 +3346,10 @@ class FissionXS(MGXS): def nu(self): return self._nu + @property + def prompt(self): + return self._prompt + @nu.setter def nu(self, nu): cv.check_type('nu', nu, bool) @@ -3466,10 +3362,6 @@ class FissionXS(MGXS): else: self._rxn_type = 'prompt-nu-fission' - @property - def prompt(self): - return self._prompt - @prompt.setter def prompt(self, prompt): cv.check_type('prompt', prompt, bool) @@ -3614,7 +3506,7 @@ class ScatterXS(MGXS): the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`ScatterXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -3924,7 +3816,7 @@ class ScatterMatrixXS(MatrixMGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`ScatterMatrixXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -4007,115 +3899,26 @@ class ScatterMatrixXS(MatrixMGXS): def formulation(self): return self._formulation - @formulation.setter - def formulation(self, formulation): - cv.check_value('formulation', formulation, ('simple', 'consistent')) - self._formulation = formulation - - if self.formulation == 'simple': - self._valid_estimators = ['analog'] - if not self.nu: - self._mgxs_type = 'scatter matrix' - else: - self._mgxs_type = 'nu-scatter matrix' - else: - self._valid_estimators = ['tracklength'] - if not self.nu: - self._mgxs_type = 'consistent scatter matrix' - else: - self._mgxs_type = 'consistent nu-scatter matrix' - @property def correction(self): return self._correction - @correction.setter - def correction(self, correction): - cv.check_value('correction', correction, ('P0', None)) - - if self.scatter_format == SCATTER_LEGENDRE: - if correction == 'P0' and self.legendre_order > 0: - msg = 'The P0 correction will be ignored since the ' \ - 'scattering order {} is greater than '\ - 'zero'.format(self.legendre_order) - warnings.warn(msg) - elif self.scatter_format == SCATTER_HISTOGRAM: - msg = 'The P0 correction will be ignored since the ' \ - 'scatter format is set to histogram' - warnings.warn(msg) - - self._correction = correction - @property def scatter_format(self): return self._scatter_format - @scatter_format.setter - def scatter_format(self, scatter_format): - cv.check_value('scatter_format', scatter_format, MU_TREATMENTS) - self._scatter_format = scatter_format - @property def legendre_order(self): return self._legendre_order - @legendre_order.setter - def legendre_order(self, legendre_order): - cv.check_type('legendre_order', legendre_order, Integral) - cv.check_greater_than('legendre_order', legendre_order, 0, - equality=True) - cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, - equality=True) - - if self.scatter_format == SCATTER_LEGENDRE: - if self.correction == 'P0' and legendre_order > 0: - msg = 'The P0 correction will be ignored since the ' \ - 'scattering order {} is greater than '\ - 'zero'.format(legendre_order) - warnings.warn(msg, RuntimeWarning) - self.correction = None - elif self.scatter_format == SCATTER_HISTOGRAM: - msg = 'The legendre order will be ignored since the ' \ - 'scatter format is set to histogram' - warnings.warn(msg) - - self._legendre_order = legendre_order - @property def histogram_bins(self): return self._histogram_bins - @histogram_bins.setter - def histogram_bins(self, histogram_bins): - cv.check_type('histogram_bins', histogram_bins, Integral) - cv.check_greater_than('histogram_bins', histogram_bins, 0) - - self._histogram_bins = histogram_bins - @property def nu(self): return self._nu - @nu.setter - def nu(self, nu): - cv.check_type('nu', nu, bool) - self._nu = nu - - if self.formulation == 'simple': - if not nu: - self._rxn_type = 'scatter' - self._mgxs_type = 'scatter matrix' - else: - self._rxn_type = 'nu-scatter' - self._mgxs_type = 'nu-scatter matrix' - else: - if not nu: - self._rxn_type = 'scatter' - self._mgxs_type = 'consistent scatter matrix' - else: - self._rxn_type = 'nu-scatter' - self._mgxs_type = 'consistent nu-scatter matrix' - @property def scores(self): @@ -4397,6 +4200,95 @@ class ScatterMatrixXS(MatrixMGXS): return self._xs_tally + @nu.setter + def nu(self, nu): + cv.check_type('nu', nu, bool) + self._nu = nu + + if self.formulation == 'simple': + if not nu: + self._rxn_type = 'scatter' + self._mgxs_type = 'scatter matrix' + else: + self._rxn_type = 'nu-scatter' + self._mgxs_type = 'nu-scatter matrix' + else: + if not nu: + self._rxn_type = 'scatter' + self._mgxs_type = 'consistent scatter matrix' + else: + self._rxn_type = 'nu-scatter' + self._mgxs_type = 'consistent nu-scatter matrix' + + @formulation.setter + def formulation(self, formulation): + cv.check_value('formulation', formulation, ('simple', 'consistent')) + self._formulation = formulation + + if self.formulation == 'simple': + self._valid_estimators = ['analog'] + if not self.nu: + self._mgxs_type = 'scatter matrix' + else: + self._mgxs_type = 'nu-scatter matrix' + else: + self._valid_estimators = ['tracklength'] + if not self.nu: + self._mgxs_type = 'consistent scatter matrix' + else: + self._mgxs_type = 'consistent nu-scatter matrix' + + @correction.setter + def correction(self, correction): + cv.check_value('correction', correction, ('P0', None)) + + if self.scatter_format == SCATTER_LEGENDRE: + if correction == 'P0' and self.legendre_order > 0: + msg = 'The P0 correction will be ignored since the ' \ + 'scattering order {} is greater than '\ + 'zero'.format(self.legendre_order) + warnings.warn(msg) + elif self.scatter_format == SCATTER_HISTOGRAM: + msg = 'The P0 correction will be ignored since the ' \ + 'scatter format is set to histogram' + warnings.warn(msg) + + self._correction = correction + + @scatter_format.setter + def scatter_format(self, scatter_format): + cv.check_value('scatter_format', scatter_format, MU_TREATMENTS) + self._scatter_format = scatter_format + + @legendre_order.setter + def legendre_order(self, legendre_order): + cv.check_type('legendre_order', legendre_order, Integral) + cv.check_greater_than('legendre_order', legendre_order, 0, + equality=True) + cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, + equality=True) + + if self.scatter_format == SCATTER_LEGENDRE: + if self.correction == 'P0' and legendre_order > 0: + msg = 'The P0 correction will be ignored since the ' \ + 'scattering order {} is greater than '\ + 'zero'.format(legendre_order) + warnings.warn(msg, RuntimeWarning) + self.correction = None + elif self.scatter_format == SCATTER_HISTOGRAM: + msg = 'The legendre order will be ignored since the ' \ + 'scatter format is set to histogram' + warnings.warn(msg) + + self._legendre_order = legendre_order + + @histogram_bins.setter + def histogram_bins(self, histogram_bins): + cv.check_type('histogram_bins', histogram_bins, Integral) + cv.check_greater_than('histogram_bins', histogram_bins, 0) + + self._histogram_bins = histogram_bins + def load_from_statepoint(self, statepoint): """Extracts tallies in an OpenMC StatePoint with the data needed to compute multi-group cross sections. @@ -4478,7 +4370,7 @@ class ScatterMatrixXS(MatrixMGXS): slice_xs.legendre_order = legendre_order # Slice the scattering tally - filter_bins = [tuple([f'P{i}' + filter_bins = [tuple(['P{}'.format(i) for i in range(self.legendre_order + 1)])] slice_xs.tallies[self.rxn_type] = \ slice_xs.tallies[self.rxn_type].get_slice( @@ -4615,7 +4507,7 @@ class ScatterMatrixXS(MatrixMGXS): cv.check_less_than( 'moment', moment, self.legendre_order, equality=True) filters.append(openmc.LegendreFilter) - filter_bins.append((f'P{moment}',)) + filter_bins.append(('P{}'.format(moment),)) num_angle_bins = 1 else: num_angle_bins = self.legendre_order + 1 @@ -4786,7 +4678,7 @@ class ScatterMatrixXS(MatrixMGXS): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=int) + subdomains = np.arange(self.num_subdomains, dtype=np.int) elif self.domain_type == 'mesh': subdomains = list(self.domain.indices) else: @@ -4806,7 +4698,7 @@ class ScatterMatrixXS(MatrixMGXS): cv.check_value('xs_type', xs_type, ['macro', 'micro']) if self.correction != 'P0' and self.scatter_format == SCATTER_LEGENDRE: - rxn_type = f'{self.mgxs_type} (P{moment})' + rxn_type = '{0} (P{1})'.format(self.mgxs_type, moment) else: rxn_type = self.mgxs_type @@ -4817,7 +4709,7 @@ class ScatterMatrixXS(MatrixMGXS): string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' + xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) # If cross section data has not been computed, only print string header if self.tallies is None: @@ -4853,7 +4745,7 @@ class ScatterMatrixXS(MatrixMGXS): string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += f'{xs_header: <16}\n' + string += '{0: <16}\n'.format(xs_header) average_xs = self.get_xs(nuclides=[nuclide], subdomains=[subdomain], @@ -4905,7 +4797,8 @@ class ScatterMatrixXS(MatrixMGXS): for azi in range(len(azi_bins) - 1): azi_low, azi_high = azi_bins[azi: azi + 2] string += \ - f'\t\tPolar Angle: [{pol_low:5f} - {pol_high:5f}]' + \ + '\t\tPolar Angle: [{0:5f} - {1:5f}]'.format( + pol_low, pol_high) + \ '\tAzimuthal Angle: [{0:5f} - {1:5f}]'.format( azi_low, azi_high) + '\n' string += print_groups_and_histogram( @@ -5193,7 +5086,7 @@ class NuFissionMatrixXS(MatrixMGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`NuFissionMatrixXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -5354,7 +5247,7 @@ class Chi(MGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`Chi.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -5416,17 +5309,6 @@ class Chi(MGXS): def prompt(self): return self._prompt - @prompt.setter - def prompt(self, prompt): - cv.check_type('prompt', prompt, bool) - self._prompt = prompt - if not self.prompt: - self._rxn_type = 'chi' - self._mgxs_type = 'chi' - else: - self._rxn_type = 'chi-prompt' - self._mgxs_type = 'chi-prompt' - @property def _dont_squeeze(self): """Create a tuple of axes which should not be removed during the get_xs @@ -5483,6 +5365,17 @@ class Chi(MGXS): return self._xs_tally + @prompt.setter + def prompt(self, prompt): + cv.check_type('prompt', prompt, bool) + self._prompt = prompt + if not self.prompt: + self._rxn_type = 'chi' + self._mgxs_type = 'chi' + else: + self._rxn_type = 'chi-prompt' + self._mgxs_type = 'chi-prompt' + def get_homogenized_mgxs(self, other_mgxs): """Construct a homogenized mgxs with other MGXS objects. @@ -5922,7 +5815,7 @@ class MeshSurfaceMGXS(MGXS): the multi-group cross section estimator : {'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -5968,6 +5861,10 @@ class MeshSurfaceMGXS(MGXS): def domain(self): return self._domain + @property + def domain_type(self): + return self._domain_type + @domain.setter def domain(self, domain): cv.check_type('domain', domain, openmc.RegularMesh) @@ -5977,10 +5874,6 @@ class MeshSurfaceMGXS(MGXS): if self.domain_type is None: self._domain_type = 'mesh' - @property - def domain_type(self): - return self._domain_type - @domain_type.setter def domain_type(self, domain_type): cv.check_value('domain type', domain_type, 'mesh') @@ -6227,7 +6120,7 @@ class MeshSurfaceMGXS(MGXS): if 'group out' in df: df = df[df['group out'].isin(groups)] - mesh_str = f'mesh {self.domain.id}' + mesh_str = 'mesh {0}'.format(self.domain.id) col_key = (mesh_str, 'surf') surfaces = df.pop(col_key) df.insert(len(self.domain.dimension), col_key, surfaces) @@ -6309,7 +6202,7 @@ class Current(MeshSurfaceMGXS): the multi-group cross section estimator : {'analog'} The tally estimator used to compute the multi-group cross section - tallies : dict + tallies : collections.OrderedDict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`TotalXS.tally_keys` property and values are instances of :class:`openmc.Tally`. diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index ab9b58b7a..67ad151cc 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1,9 +1,10 @@ import copy from numbers import Real, Integral +import os import h5py import numpy as np -import scipy.integrate +from scipy.integrate import simps from scipy.interpolate import interp1d from scipy.special import eval_legendre @@ -11,24 +12,28 @@ import openmc import openmc.mgxs from openmc.mgxs import SCATTER_TABULAR, SCATTER_LEGENDRE, SCATTER_HISTOGRAM from .checkvalue import check_type, check_value, check_greater_than, \ - check_iterable_type, check_less_than, check_filetype_version, PathLike + check_iterable_type, check_less_than, check_filetype_version ROOM_TEMPERATURE_KELVIN = 294.0 # Supported incoming particle MGXS angular treatment representations REPRESENTATION_ISOTROPIC = 'isotropic' REPRESENTATION_ANGLE = 'angle' -_REPRESENTATIONS = { +_REPRESENTATIONS = [ REPRESENTATION_ISOTROPIC, REPRESENTATION_ANGLE -} +] # Supported scattering angular distribution representations -_SCATTER_TYPES = { +_SCATTER_TYPES = [ SCATTER_TABULAR, SCATTER_LEGENDRE, SCATTER_HISTOGRAM -} +] + +# List of MGXS indexing schemes +_XS_SHAPES = ["[G][G'][Order]", "[G]", "[G']", "[G][G']", "[DG]", "[DG][G]", + "[DG][G']", "[DG][G][G']"] # Number of mu points for conversion between scattering formats _NMU = 257 @@ -256,62 +261,22 @@ class XSdata: def name(self): return self._name - @name.setter - def name(self, name): - - check_type('name for XSdata', name, str) - self._name = name - @property def energy_groups(self): return self._energy_groups - @energy_groups.setter - def energy_groups(self, energy_groups): - - check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups) - if energy_groups.group_edges is None: - msg = 'Unable to assign an EnergyGroups object ' \ - 'with uninitialized group edges' - raise ValueError(msg) - - self._energy_groups = energy_groups - @property def num_delayed_groups(self): return self._num_delayed_groups - @num_delayed_groups.setter - def num_delayed_groups(self, num_delayed_groups): - - check_type('num_delayed_groups', num_delayed_groups, Integral) - check_less_than('num_delayed_groups', num_delayed_groups, - openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) - check_greater_than('num_delayed_groups', num_delayed_groups, 0, - equality=True) - self._num_delayed_groups = num_delayed_groups - @property def representation(self): return self._representation - @representation.setter - def representation(self, representation): - - check_value('representation', representation, _REPRESENTATIONS) - self._representation = representation - @property def atomic_weight_ratio(self): return self._atomic_weight_ratio - @atomic_weight_ratio.setter - def atomic_weight_ratio(self, atomic_weight_ratio): - - check_type('atomic_weight_ratio', atomic_weight_ratio, Real) - check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) - self._atomic_weight_ratio = atomic_weight_ratio - @property def fissionable(self): return self._fissionable @@ -320,55 +285,22 @@ class XSdata: def temperatures(self): return self._temperatures - @temperatures.setter - def temperatures(self, temperatures): - - check_iterable_type('temperatures', temperatures, Real) - self._temperatures = np.array(temperatures) - @property def scatter_format(self): return self._scatter_format - @scatter_format.setter - def scatter_format(self, scatter_format): - - check_value('scatter_format', scatter_format, _SCATTER_TYPES) - self._scatter_format = scatter_format - @property def order(self): return self._order - @order.setter - def order(self, order): - - check_type('order', order, Integral) - check_greater_than('order', order, 0, equality=True) - self._order = order - @property def num_polar(self): return self._num_polar - @num_polar.setter - def num_polar(self, num_polar): - - check_type('num_polar', num_polar, Integral) - check_greater_than('num_polar', num_polar, 0) - self._num_polar = num_polar - @property def num_azimuthal(self): return self._num_azimuthal - @num_azimuthal.setter - def num_azimuthal(self, num_azimuthal): - - check_type('num_azimuthal', num_azimuthal, Integral) - check_greater_than('num_azimuthal', num_azimuthal, 0) - self._num_azimuthal = num_azimuthal - @property def total(self): return self._total @@ -470,6 +402,79 @@ class XSdata: return self._xs_shapes + @name.setter + def name(self, name): + + check_type('name for XSdata', name, str) + self._name = name + + @energy_groups.setter + def energy_groups(self, energy_groups): + + check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups) + if energy_groups.group_edges is None: + msg = 'Unable to assign an EnergyGroups object ' \ + 'with uninitialized group edges' + raise ValueError(msg) + + self._energy_groups = energy_groups + + @num_delayed_groups.setter + def num_delayed_groups(self, num_delayed_groups): + + check_type('num_delayed_groups', num_delayed_groups, Integral) + check_less_than('num_delayed_groups', num_delayed_groups, + openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) + check_greater_than('num_delayed_groups', num_delayed_groups, 0, + equality=True) + self._num_delayed_groups = num_delayed_groups + + @representation.setter + def representation(self, representation): + + check_value('representation', representation, _REPRESENTATIONS) + self._representation = representation + + @atomic_weight_ratio.setter + def atomic_weight_ratio(self, atomic_weight_ratio): + + check_type('atomic_weight_ratio', atomic_weight_ratio, Real) + check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) + self._atomic_weight_ratio = atomic_weight_ratio + + @temperatures.setter + def temperatures(self, temperatures): + + check_iterable_type('temperatures', temperatures, Real) + self._temperatures = np.array(temperatures) + + @scatter_format.setter + def scatter_format(self, scatter_format): + + check_value('scatter_format', scatter_format, _SCATTER_TYPES) + self._scatter_format = scatter_format + + @order.setter + def order(self, order): + + check_type('order', order, Integral) + check_greater_than('order', order, 0, equality=True) + self._order = order + + @num_polar.setter + def num_polar(self, num_polar): + + check_type('num_polar', num_polar, Integral) + check_greater_than('num_polar', num_polar, 0) + self._num_polar = num_polar + + @num_azimuthal.setter + def num_azimuthal(self, num_azimuthal): + + check_type('num_azimuthal', num_azimuthal, Integral) + check_greater_than('num_azimuthal', num_azimuthal, 0) + self._num_azimuthal = num_azimuthal + def add_temperature(self, temperature): """This method re-sizes the attributes of this XSdata object so that it can accommodate an additional temperature. Note that the set_* methods @@ -484,8 +489,7 @@ class XSdata: check_type('temperature', temperature, Real) - temp_store = self.temperatures.tolist() - temp_store.append(temperature) + temp_store = self.temperatures.tolist().append(temperature) self.temperatures = temp_store self._total.append(None) @@ -515,75 +519,6 @@ class XSdata: if np.sum(array) > 0: self._fissionable = True - def add_temperature_data(self, other): - """This method adds temperature-dependent cross section - values from another XSdata object to this XSdata object. - Note: if a temperature datapoint from 'other' already exists in this - object, it will be overridden. - - Parameters - ---------- - other: openmc.XSdata - The other XSdata object to fetch data from - """ - - # Sanity check to make sure they have the same name, energy group structure, - # and delayed group structure - check_value('name', other.name, self.name) - check_value('energy_groups', other.energy_groups, [self.energy_groups]) - check_value('delayed_groups', other.num_delayed_groups, [self.num_delayed_groups]) - - # Add the temperature data. - for temp in other.temperatures: - if temp not in self.temperatures: - self.add_temperature(temp) - - if np.all(other.absorption[other._temperature_index(temp)] != None): - self.set_absorption(other.absorption[other._temperature_index(temp)], temp) - - if np.all(other.beta[other._temperature_index(temp)] != None): - self.set_beta(other.beta[other._temperature_index(temp)], temp) - - if np.all(other.chi[other._temperature_index(temp)] != None): - self.set_chi(other.chi[other._temperature_index(temp)], temp) - - if np.all(other.chi_delayed[other._temperature_index(temp)] != None): - self.set_chi_delayed(other.chi_delayed[other._temperature_index(temp)], temp) - - if np.all(other.chi_prompt[other._temperature_index(temp)] != None): - self.set_chi_prompt(other.chi_prompt[other._temperature_index(temp)], temp) - - if np.all(other.decay_rate[other._temperature_index(temp)] != None): - self.set_decay_rate(other.decay_rate[other._temperature_index(temp)], temp) - - if np.all(other.delayed_nu_fission[other._temperature_index(temp)] != None): - self.set_delayed_nu_fission(other.delayed_nu_fission[other._temperature_index(temp)], temp) - - if np.all(other.fission[other._temperature_index(temp)] != None): - self.set_fission(other.fission[other._temperature_index(temp)], temp) - - if np.all(other.inverse_velocity[other._temperature_index(temp)] != None): - self.set_inverse_velocity(other.inverse_velocity[other._temperature_index(temp)], temp) - - if np.all(other.kappa_fission[other._temperature_index(temp)] != None): - self.set_kappa_fission(other.kappa_fission[other._temperature_index(temp)], temp) - - if np.all(other.multiplicity_matrix[other._temperature_index(temp)] != None): - self.set_multiplicity_matrix(other.multiplicity_matrix[other._temperature_index(temp)], temp) - - if np.all(other.nu_fission[other._temperature_index(temp)] != None): - self.set_nu_fission(other.nu_fission[other._temperature_index(temp)], temp) - - if np.all(other.prompt_nu_fission[other._temperature_index(temp)] != None): - self.set_prompt_nu_fission(other.prompt_nu_fission[other._temperature_index(temp)], temp) - - if np.all(other.scatter_matrix[other._temperature_index(temp)] != None): - self.set_scatter_matrix(other.scatter_matrix[other._temperature_index(temp)], temp) - - if np.all(other.fission[other._temperature_index(temp)] != None): - self.set_total(other.total[other._temperature_index(temp)], temp) - - def set_total(self, total, temperature=ROOM_TEMPERATURE_KELVIN): """This method sets the cross section for this XSdata object at the provided temperature. @@ -1889,12 +1824,6 @@ class XSdata: # Reset and re-generate XSdata.xs_shapes with the new scattering format xsdata._xs_shapes = None - # scipy 1.11+ prefers 'simpson', whereas older versions use 'simps' - if hasattr(scipy.integrate, 'simpson'): - integrate = scipy.integrate.simpson - else: - integrate = scipy.integrate.simps - for i, temp in enumerate(xsdata.temperatures): orig_data = self._scatter_matrix[i] new_shape = orig_data.shape[:-1] + (xsdata.num_orders,) @@ -1932,7 +1861,7 @@ class XSdata: table_fine[..., imu] += ((l + 0.5) * eval_legendre(l, mu_fine[imu]) * orig_data[..., l]) - new_data[..., h_bin] = integrate(table_fine, x=mu_fine) + new_data[..., h_bin] = simps(table_fine, mu_fine) elif self.scatter_format == SCATTER_TABULAR: # Calculate the mu points of the current data @@ -1946,7 +1875,7 @@ class XSdata: for l in range(xsdata.num_orders): y = (interp1d(mu_self, orig_data)(mu_fine) * eval_legendre(l, mu_fine)) - new_data[..., l] = integrate(y, x=mu_fine) + new_data[..., l] = simps(y, mu_fine) elif target_format == SCATTER_TABULAR: # Simply use an interpolating function to get the new data @@ -1965,7 +1894,7 @@ class XSdata: interp = interp1d(mu_self, orig_data) for h_bin in range(xsdata.num_orders): mu_fine = np.linspace(mu[h_bin], mu[h_bin + 1], _NMU) - new_data[..., h_bin] = integrate(interp(mu_fine), x=mu_fine) + new_data[..., h_bin] = simps(interp(mu_fine), mu_fine) elif self.scatter_format == SCATTER_HISTOGRAM: # The histogram format does not have enough information to @@ -1991,7 +1920,7 @@ class XSdata: mu_fine = np.linspace(-1, 1, _NMU) for l in range(xsdata.num_orders): y = interp(mu_fine) * norm * eval_legendre(l, mu_fine) - new_data[..., l] = integrate(y, x=mu_fine) + new_data[..., l] = simps(y, mu_fine) elif target_format == SCATTER_TABULAR: # Simply use an interpolating function to get the new data @@ -2010,7 +1939,7 @@ class XSdata: for h_bin in range(xsdata.num_orders): mu_fine = np.linspace(mu[h_bin], mu[h_bin + 1], _NMU) new_data[..., h_bin] = \ - norm * integrate(interp(mu_fine), x=mu_fine) + norm * simps(interp(mu_fine), mu_fine) # Remove small values resulting from numerical precision issues new_data[..., np.abs(new_data) < 1.E-10] = 0. @@ -2036,7 +1965,7 @@ class XSdata: grp.attrs['fissionable'] = self.fissionable if self.representation is not None: - grp.attrs['representation'] = np.bytes_(self.representation) + grp.attrs['representation'] = np.string_(self.representation) if self.representation == REPRESENTATION_ANGLE: if self.num_azimuthal is not None: grp.attrs['num_azimuthal'] = self.num_azimuthal @@ -2044,9 +1973,9 @@ class XSdata: if self.num_polar is not None: grp.attrs['num_polar'] = self.num_polar - grp.attrs['scatter_shape'] = np.bytes_("[G][G'][Order]") + grp.attrs['scatter_shape'] = np.string_("[G][G'][Order]") if self.scatter_format is not None: - grp.attrs['scatter_format'] = np.bytes_(self.scatter_format) + grp.attrs['scatter_format'] = np.string_(self.scatter_format) if self.order is not None: grp.attrs['order'] = self.order @@ -2402,15 +2331,23 @@ class MGXSLibrary: def energy_groups(self): return self._energy_groups + @property + def num_delayed_groups(self): + return self._num_delayed_groups + + @property + def xsdatas(self): + return self._xsdatas + + @property + def names(self): + return [xsdata.name for xsdata in self.xsdatas] + @energy_groups.setter def energy_groups(self, energy_groups): check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) self._energy_groups = energy_groups - @property - def num_delayed_groups(self): - return self._num_delayed_groups - @num_delayed_groups.setter def num_delayed_groups(self, num_delayed_groups): check_type('num_delayed_groups', num_delayed_groups, Integral) @@ -2420,14 +2357,6 @@ class MGXSLibrary: openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) self._num_delayed_groups = num_delayed_groups - @property - def xsdatas(self): - return self._xsdatas - - @property - def names(self): - return [xsdata.name for xsdata in self.xsdatas] - def add_xsdata(self, xsdata): """Add an XSdata entry to the file. @@ -2576,7 +2505,7 @@ class MGXSLibrary: Parameters ---------- - filename : str or PathLike + filename : str Filename of file, default is mgxs.h5. libver : {'earliest', 'latest'} Compatibility mode for the HDF5 file. 'latest' will produce files @@ -2584,10 +2513,11 @@ class MGXSLibrary: """ - check_type('filename', filename, (str, PathLike)) + check_type('filename', filename, str) + # Create and write to the HDF5 file file = h5py.File(filename, "w", libver=libver) - file.attrs['filetype'] = np.bytes_(_FILETYPE_MGXS_LIBRARY) + file.attrs['filetype'] = np.string_(_FILETYPE_MGXS_LIBRARY) file.attrs['version'] = [_VERSION_MGXS_LIBRARY, 0] file.attrs['energy_groups'] = self.energy_groups.num_groups file.attrs['delayed_groups'] = self.num_delayed_groups @@ -2606,7 +2536,8 @@ class MGXSLibrary: ---------- filename : str, optional Name of HDF5 file containing MGXS data. Default is None. - If not provided, openmc.config['mg_cross_sections'] will be used. + If not provided, the value of the OPENMC_MG_CROSS_SECTIONS + environmental variable will be used Returns ------- @@ -2614,30 +2545,31 @@ class MGXSLibrary: Multi-group cross section data object. """ - # If filename is None, get the cross sections from openmc.config + # If filename is None, get the cross sections from the + # OPENMC_CROSS_SECTIONS environment variable if filename is None: - filename = openmc.config.get('mg_cross_sections') + filename = os.environ.get('OPENMC_MG_CROSS_SECTIONS') # Check to make sure there was an environmental variable. if filename is None: - raise ValueError("Either path or openmc.config['mg_cross_sections']" - "must be set") + raise ValueError("Either path or OPENMC_MG_CROSS_SECTIONS " + "environmental variable must be set") - check_type('filename', filename, (str, PathLike)) - with h5py.File(filename, 'r') as file: + check_type('filename', filename, str) + file = h5py.File(filename, 'r') - # Check filetype and version - check_filetype_version(file, _FILETYPE_MGXS_LIBRARY, - _VERSION_MGXS_LIBRARY) + # Check filetype and version + check_filetype_version(file, _FILETYPE_MGXS_LIBRARY, + _VERSION_MGXS_LIBRARY) - group_structure = file.attrs['group structure'] - num_delayed_groups = file.attrs['delayed_groups'] - energy_groups = openmc.mgxs.EnergyGroups(group_structure) - data = cls(energy_groups, num_delayed_groups) + group_structure = file.attrs['group structure'] + num_delayed_groups = file.attrs['delayed_groups'] + energy_groups = openmc.mgxs.EnergyGroups(group_structure) + data = cls(energy_groups, num_delayed_groups) - for group_name, group in file.items(): - data.add_xsdata(openmc.XSdata.from_hdf5(group, group_name, - energy_groups, - num_delayed_groups)) + for group_name, group in file.items(): + data.add_xsdata(openmc.XSdata.from_hdf5(group, group_name, + energy_groups, + num_delayed_groups)) return data diff --git a/openmc/mixin.py b/openmc/mixin.py index 28c97bfdd..31c26ec76 100644 --- a/openmc/mixin.py +++ b/openmc/mixin.py @@ -39,8 +39,6 @@ class IDManagerMixin: """ - min_id = 0 - @property def id(self): return self._id @@ -66,7 +64,7 @@ class IDManagerMixin: else: name = cls.__name__ cv.check_type(f'{name} ID', uid, Integral) - cv.check_greater_than(f'{name} ID', uid, cls.min_id, equality=True) + cv.check_greater_than(f'{name} ID', uid, 0, equality=True) if uid in cls.used_ids: msg = f'Another {name} instance already exists with id={uid}.' warn(msg, IDWarning) @@ -74,17 +72,12 @@ class IDManagerMixin: cls.used_ids.add(uid) self._id = uid - @classmethod - def reset_ids(cls): - """Reset counters""" - cls.used_ids.clear() - cls.next_id = 1 - def reset_auto_ids(): """Reset counters for all auto-generated IDs""" for cls in IDManagerMixin.__subclasses__(): - cls.reset_ids() + cls.used_ids.clear() + cls.next_id = 1 def reserve_ids(ids, cls=None): diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index e076b080a..41cede08e 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -1,12 +1,16 @@ from collections.abc import Iterable +from functools import partial from math import sqrt +from numbers import Real from operator import attrgetter from warnings import warn -from openmc import Cylinder, Universe, Cell -from .surface_composite import RectangularPrism, HexagonalPrism -from ..checkvalue import (check_type, check_value, check_length, - check_less_than, check_iterable_type) +from openmc import ( + XPlane, YPlane, Plane, ZCylinder, Cylinder, XCylinder, + YCylinder, Universe, Cell) +from ..checkvalue import ( + check_type, check_value, check_length, check_less_than, + check_iterable_type) import openmc.data @@ -39,8 +43,8 @@ def borated_water(boron_ppm, temperature=293., pressure=0.1013, temp_unit='K', press_unit : {'MPa', 'psi'} The units used for the `pressure` argument. density : float - Water density in [g / cm^3]. If specified, this value overrides - the value that is computed from the temperature and pressure arguments. + Water density in [g / cm^3]. If specified, this value overrides the + temperature and pressure arguments. **kwargs All keyword arguments are passed to the created Material object. @@ -95,7 +99,10 @@ def borated_water(boron_ppm, temperature=293., pressure=0.1013, temp_unit='K', frac_B = boron_ppm * 1e-6 / M_B # Build the material. - out = openmc.Material(temperature=T, **kwargs) + if density is None: + out = openmc.Material(temperature=T, **kwargs) + else: + out = openmc.Material(**kwargs) out.add_element('H', frac_H, 'ao') out.add_element('O', frac_O, 'ao') out.add_element('B', frac_B, 'ao') @@ -104,26 +111,271 @@ def borated_water(boron_ppm, temperature=293., pressure=0.1013, temp_unit='K', return out - - def rectangular_prism(width, height, axis='z', origin=(0., 0.), boundary_type='transmission', corner_radius=0.): - warn("The rectangular_prism(...) function has been replaced by the " - "RectangularPrism(...) class. Future versions of OpenMC will not " - "accept rectangular_prism.", FutureWarning) - return -RectangularPrism( - width=width, height=height, axis=axis, origin=origin, - boundary_type=boundary_type, corner_radius=corner_radius) + """Get an infinite rectangular prism from four planar surfaces. + + .. versionchanged:: 0.11 + This function was renamed from `get_rectangular_prism` to + `rectangular_prism`. + + Parameters + ---------- + width: float + Prism width in units of cm. The width is aligned with the y, x, + or x axes for prisms parallel to the x, y, or z axis, respectively. + height: float + Prism height in units of cm. The height is aligned with the z, z, + or y axes for prisms parallel to the x, y, or z axis, respectively. + axis : {'x', 'y', 'z'} + Axis with which the infinite length of the prism should be aligned. + Defaults to 'z'. + origin: Iterable of two floats + Origin of the prism. The two floats correspond to (y,z), (x,z) or + (x,y) for prisms parallel to the x, y or z axis, respectively. + Defaults to (0., 0.). + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'} + Boundary condition that defines the behavior for particles hitting the + surfaces comprising the rectangular prism (default is 'transmission'). + corner_radius: float + Prism corner radius in units of cm. Defaults to 0. + + Returns + ------- + openmc.Region + The inside of a rectangular prism + + """ + + check_type('width', width, Real) + check_type('height', height, Real) + check_type('corner_radius', corner_radius, Real) + check_value('axis', axis, ['x', 'y', 'z']) + check_type('origin', origin, Iterable, Real) + + # Define function to create a plane on given axis + def plane(axis, name, value): + cls = globals()['{}Plane'.format(axis.upper())] + return cls(name='{} {}'.format(name, axis), + boundary_type=boundary_type, + **{axis + '0': value}) + + if axis == 'x': + x1, x2 = 'y', 'z' + elif axis == 'y': + x1, x2 = 'x', 'z' + else: + x1, x2 = 'x', 'y' + + # Get cylinder class corresponding to given axis + cyl = globals()['{}Cylinder'.format(axis.upper())] + + # Create rectangular region + min_x1 = plane(x1, 'minimum', -width/2 + origin[0]) + max_x1 = plane(x1, 'maximum', width/2 + origin[0]) + min_x2 = plane(x2, 'minimum', -height/2 + origin[1]) + max_x2 = plane(x2, 'maximum', height/2 + origin[1]) + if boundary_type == 'periodic': + min_x1.periodic_surface = max_x1 + min_x2.periodic_surface = max_x2 + prism = +min_x1 & -max_x1 & +min_x2 & -max_x2 + + # Handle rounded corners if given + if corner_radius > 0.: + if boundary_type == 'periodic': + raise ValueError('Periodic boundary conditions not permitted when ' + 'rounded corners are used.') + + args = {'r': corner_radius, 'boundary_type': boundary_type} + + args[x1 + '0'] = origin[0] - width/2 + corner_radius + args[x2 + '0'] = origin[1] - height/2 + corner_radius + x1_min_x2_min = cyl(name='{} min {} min'.format(x1, x2), **args) + + args[x1 + '0'] = origin[0] - width/2 + corner_radius + args[x2 + '0'] = origin[1] - height/2 + corner_radius + x1_min_x2_min = cyl(name='{} min {} min'.format(x1, x2), **args) + + args[x1 + '0'] = origin[0] - width/2 + corner_radius + args[x2 + '0'] = origin[1] + height/2 - corner_radius + x1_min_x2_max = cyl(name='{} min {} max'.format(x1, x2), **args) + + args[x1 + '0'] = origin[0] + width/2 - corner_radius + args[x2 + '0'] = origin[1] - height/2 + corner_radius + x1_max_x2_min = cyl(name='{} max {} min'.format(x1, x2), **args) + + args[x1 + '0'] = origin[0] + width/2 - corner_radius + args[x2 + '0'] = origin[1] + height/2 - corner_radius + x1_max_x2_max = cyl(name='{} max {} max'.format(x1, x2), **args) + + x1_min = plane(x1, 'min', -width/2 + origin[0] + corner_radius) + x1_max = plane(x1, 'max', width/2 + origin[0] - corner_radius) + x2_min = plane(x2, 'min', -height/2 + origin[1] + corner_radius) + x2_max = plane(x2, 'max', height/2 + origin[1] - corner_radius) + + corners = (+x1_min_x2_min & -x1_min & -x2_min) | \ + (+x1_min_x2_max & -x1_min & +x2_max) | \ + (+x1_max_x2_min & +x1_max & -x2_min) | \ + (+x1_max_x2_max & +x1_max & +x2_max) + + prism = prism & ~corners + + return prism + + +def get_rectangular_prism(*args, **kwargs): + warn("get_rectangular_prism(...) has been renamed rectangular_prism(...). " + "Future versions of OpenMC will not accept get_rectangular_prism.", + FutureWarning) + return rectangular_prism(*args, **kwargs) def hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), boundary_type='transmission', corner_radius=0.): - warn("The hexagonal_prism(...) function has been replaced by the " - "HexagonalPrism(...) class. Future versions of OpenMC will not " - "accept hexagonal_prism.", FutureWarning) - return -HexagonalPrism( - edge_length=edge_length, orientation=orientation, origin=origin, - boundary_type=boundary_type, corner_radius=corner_radius) + """Create a hexagon region from six surface planes. + + .. versionchanged:: 0.11 + This function was renamed from `get_hexagonal_prism` to + `hexagonal_prism`. + + Parameters + ---------- + edge_length : float + Length of a side of the hexagon in cm + orientation : {'x', 'y'} + An 'x' orientation means that two sides of the hexagon are parallel to + the x-axis and a 'y' orientation means that two sides of the hexagon are + parallel to the y-axis. + origin: Iterable of two floats + Origin of the prism. Defaults to (0., 0.). + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'} + Boundary condition that defines the behavior for particles hitting the + surfaces comprising the hexagonal prism (default is 'transmission'). + corner_radius: float + Prism corner radius in units of cm. Defaults to 0. + + Returns + ------- + openmc.Region + The inside of a hexagonal prism + + """ + + l = edge_length + x, y = origin + + if orientation == 'y': + right = XPlane(x + sqrt(3.)/2*l, boundary_type=boundary_type) + left = XPlane(x - sqrt(3.)/2*l, boundary_type=boundary_type) + c = sqrt(3.)/3. + + # y = -x/sqrt(3) + a + upper_right = Plane(a=c, b=1., d=l+x*c+y, boundary_type=boundary_type) + + # y = x/sqrt(3) + a + upper_left = Plane(a=-c, b=1., d=l-x*c+y, boundary_type=boundary_type) + + # y = x/sqrt(3) - a + lower_right = Plane(a=-c, b=1., d=-l-x*c+y, boundary_type=boundary_type) + + # y = -x/sqrt(3) - a + lower_left = Plane(a=c, b=1., d=-l+x*c+y, boundary_type=boundary_type) + + prism = -right & +left & -upper_right & -upper_left & \ + +lower_right & +lower_left + + if boundary_type == 'periodic': + right.periodic_surface = left + upper_right.periodic_surface = lower_left + lower_right.periodic_surface = upper_left + + elif orientation == 'x': + top = YPlane(y0=y + sqrt(3.)/2*l, boundary_type=boundary_type) + bottom = YPlane(y0=y - sqrt(3.)/2*l, boundary_type=boundary_type) + c = sqrt(3.) + + # y = -sqrt(3)*(x - a) + upper_right = Plane(a=c, b=1., d=c*l+x*c+y, boundary_type=boundary_type) + + # y = sqrt(3)*(x + a) + lower_right = Plane(a=-c, b=1., d=-c*l-x*c+y, + boundary_type=boundary_type) + + # y = -sqrt(3)*(x + a) + lower_left = Plane(a=c, b=1., d=-c*l+x*c+y, boundary_type=boundary_type) + + # y = sqrt(3)*(x + a) + upper_left = Plane(a=-c, b=1., d=c*l-x*c+y, boundary_type=boundary_type) + + prism = -top & +bottom & -upper_right & +lower_right & \ + +lower_left & -upper_left + + if boundary_type == 'periodic': + top.periodic_surface = bottom + upper_right.periodic_surface = lower_left + lower_right.periodic_surface = upper_left + + # Handle rounded corners if given + if corner_radius > 0.: + if boundary_type == 'periodic': + raise ValueError('Periodic boundary conditions not permitted when ' + 'rounded corners are used.') + + c = sqrt(3.)/2 + t = l - corner_radius/c + + # Cylinder with corner radius and boundary type pre-applied + cyl1 = partial(ZCylinder, r=corner_radius, boundary_type=boundary_type) + cyl2 = partial(ZCylinder, r=corner_radius/(2*c), + boundary_type=boundary_type) + + if orientation == 'x': + x_min_y_min_in = cyl1(name='x min y min in', x0=x-t/2, y0=y-c*t) + x_min_y_max_in = cyl1(name='x min y max in', x0=x+t/2, y0=y-c*t) + x_max_y_min_in = cyl1(name='x max y min in', x0=x-t/2, y0=y+c*t) + x_max_y_max_in = cyl1(name='x max y max in', x0=x+t/2, y0=y+c*t) + x_min_in = cyl1(name='x min in', x0=x-t, y0=y) + x_max_in = cyl1(name='x max in', x0=x+t, y0=y) + + x_min_y_min_out = cyl2(name='x min y min out', x0=x-l/2, y0=y-c*l) + x_min_y_max_out = cyl2(name='x min y max out', x0=x+l/2, y0=y-c*l) + x_max_y_min_out = cyl2(name='x max y min out', x0=x-l/2, y0=y+c*l) + x_max_y_max_out = cyl2(name='x max y max out', x0=x+l/2, y0=y+c*l) + x_min_out = cyl2(name='x min out', x0=x-l, y0=y) + x_max_out = cyl2(name='x max out', x0=x+l, y0=y) + + corners = (+x_min_y_min_in & -x_min_y_min_out | + +x_min_y_max_in & -x_min_y_max_out | + +x_max_y_min_in & -x_max_y_min_out | + +x_max_y_max_in & -x_max_y_max_out | + +x_min_in & -x_min_out | + +x_max_in & -x_max_out) + + elif orientation == 'y': + x_min_y_min_in = cyl1(name='x min y min in', x0=x-c*t, y0=y-t/2) + x_min_y_max_in = cyl1(name='x min y max in', x0=x-c*t, y0=y+t/2) + x_max_y_min_in = cyl1(name='x max y min in', x0=x+c*t, y0=y-t/2) + x_max_y_max_in = cyl1(name='x max y max in', x0=x+c*t, y0=y+t/2) + y_min_in = cyl1(name='y min in', x0=x, y0=y-t) + y_max_in = cyl1(name='y max in', x0=x, y0=y+t) + + x_min_y_min_out = cyl2(name='x min y min out', x0=x-c*l, y0=y-l/2) + x_min_y_max_out = cyl2(name='x min y max out', x0=x-c*l, y0=y+l/2) + x_max_y_min_out = cyl2(name='x max y min out', x0=x+c*l, y0=y-l/2) + x_max_y_max_out = cyl2(name='x max y max out', x0=x+c*l, y0=y+l/2) + y_min_out = cyl2(name='y min out', x0=x, y0=y-l) + y_max_out = cyl2(name='y max out', x0=x, y0=y+l) + + corners = (+x_min_y_min_in & -x_min_y_min_out | + +x_min_y_max_in & -x_min_y_max_out | + +x_max_y_min_in & -x_max_y_min_out | + +x_max_y_max_in & -x_max_y_max_out | + +y_min_in & -y_min_out | + +y_max_in & -y_max_out) + + prism = prism & ~corners + + return prism def get_hexagonal_prism(*args, **kwargs): @@ -210,15 +462,16 @@ def pin(surfaces, items, subdivisions=None, divide_vols=True, check_iterable_type("surfaces", surfaces[1:], surf_type) # Check for increasing radii and equal centers - if surf_type is openmc.ZCylinder: + if surf_type is ZCylinder: center_getter = attrgetter("x0", "y0") - elif surf_type is openmc.YCylinder: + elif surf_type is YCylinder: center_getter = attrgetter("x0", "z0") - elif surf_type is openmc.XCylinder: + elif surf_type is XCylinder: center_getter = attrgetter("z0", "y0") else: raise TypeError( - f"Not configured to interpret {surf_type.__name__} surfaces") + "Not configured to interpret {} surfaces".format( + surf_type.__name__)) centers = set() prev_rad = 0 diff --git a/openmc/model/model.py b/openmc/model/model.py index c437d2033..ab99ac978 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -1,46 +1,30 @@ -from __future__ import annotations -from collections.abc import Callable, Iterable, Sequence -import copy -from dataclasses import dataclass, field -from functools import cache +from collections.abc import Iterable +from contextlib import contextmanager +from functools import lru_cache +import os from pathlib import Path -import math -from numbers import Integral, Real -import random -import re -from tempfile import NamedTemporaryFile, TemporaryDirectory -from typing import Any, Protocol -import warnings +from numbers import Integral +from tempfile import NamedTemporaryFile import h5py -import lxml.etree as ET -import numpy as np -from scipy.optimize import curve_fit import openmc -import openmc._xml as xml from openmc.dummy_comm import DummyCommunicator from openmc.executor import _process_CLI_arguments -from openmc.checkvalue import (check_type, check_value, check_greater_than, - check_length, PathLike) +from openmc.checkvalue import check_type, check_value from openmc.exceptions import InvalidIDError -from openmc.plots import add_plot_params, _BASIS_INDICES, id_map_to_rgb -from openmc.utility_funcs import change_directory -# Protocol for a function that is passed to search_keff -class ModelModifier(Protocol): - def __call__(self, val: float, **kwargs: Any) -> None: - ... - - -def _check_pixels(pixels: int | Sequence[int]) -> None: - if isinstance(pixels, Integral): - check_greater_than('pixels', pixels, 0) - else: - check_length('pixels', pixels, 2) - for p in pixels: - check_greater_than('pixels', p, 0) +@contextmanager +def _change_directory(working_dir): + """A context manager for executing in a provided working directory""" + start_dir = Path.cwd() + Path.mkdir(working_dir, exist_ok=True) + os.chdir(working_dir) + try: + yield + finally: + os.chdir(start_dir) class Model: @@ -86,92 +70,47 @@ class Model: """ - def __init__( - self, - geometry: openmc.Geometry | None = None, - materials: openmc.Materials | None = None, - settings: openmc.Settings | None = None, - tallies: openmc.Tallies | None = None, - plots: openmc.Plots | None = None, - ): - self.geometry = openmc.Geometry() if geometry is None else geometry - self.materials = openmc.Materials() if materials is None else materials - self.settings = openmc.Settings() if settings is None else settings - self.tallies = openmc.Tallies() if tallies is None else tallies - self.plots = openmc.Plots() if plots is None else plots + def __init__(self, geometry=None, materials=None, settings=None, + tallies=None, plots=None): + self.geometry = openmc.Geometry() + self.materials = openmc.Materials() + self.settings = openmc.Settings() + self.tallies = openmc.Tallies() + self.plots = openmc.Plots() + + if geometry is not None: + self.geometry = geometry + if materials is not None: + self.materials = materials + if settings is not None: + self.settings = settings + if tallies is not None: + self.tallies = tallies + if plots is not None: + self.plots = plots @property - def geometry(self) -> openmc.Geometry: + def geometry(self): return self._geometry - @geometry.setter - def geometry(self, geometry): - check_type('geometry', geometry, openmc.Geometry) - self._geometry = geometry - @property - def materials(self) -> openmc.Materials: + def materials(self): return self._materials - @materials.setter - def materials(self, materials): - check_type('materials', materials, Iterable, openmc.Material) - if isinstance(materials, openmc.Materials): - self._materials = materials - else: - if not hasattr(self, '_materials'): - self._materials = openmc.Materials() - del self._materials[:] - for mat in materials: - self._materials.append(mat) - @property - def settings(self) -> openmc.Settings: + def settings(self): return self._settings - @settings.setter - def settings(self, settings): - check_type('settings', settings, openmc.Settings) - self._settings = settings - @property - def tallies(self) -> openmc.Tallies: + def tallies(self): return self._tallies - @tallies.setter - def tallies(self, tallies): - check_type('tallies', tallies, Iterable, openmc.Tally) - if isinstance(tallies, openmc.Tallies): - self._tallies = tallies - else: - if not hasattr(self, '_tallies'): - self._tallies = openmc.Tallies() - del self._tallies[:] - for tally in tallies: - self._tallies.append(tally) - @property - def plots(self) -> openmc.Plots: + def plots(self): return self._plots - @plots.setter - def plots(self, plots): - check_type('plots', plots, Iterable, openmc.PlotBase) - if isinstance(plots, openmc.Plots): - self._plots = plots - else: - if not hasattr(self, '_plots'): - self._plots = openmc.Plots() - del self._plots[:] - for plot in plots: - self._plots.append(plot) - @property - def bounding_box(self) -> openmc.BoundingBox: - return self.geometry.bounding_box - - @property - def is_initialized(self) -> bool: + def is_initialized(self): try: import openmc.lib return openmc.lib.is_initialized @@ -179,25 +118,25 @@ class Model: return False @property - @cache - def _materials_by_id(self) -> dict: + @lru_cache(maxsize=None) + def _materials_by_id(self): """Dictionary mapping material ID --> material""" - if self.materials: - mats = self.materials - else: + if self.materials is None: mats = self.geometry.get_all_materials().values() + else: + mats = self.materials return {mat.id: mat for mat in mats} @property - @cache - def _cells_by_id(self) -> dict: + @lru_cache(maxsize=None) + def _cells_by_id(self): """Dictionary mapping cell ID --> cell""" cells = self.geometry.get_all_cells() return {cell.id: cell for cell in cells.values()} @property - @cache - def _cells_by_name(self) -> dict[int, openmc.Cell]: + @lru_cache(maxsize=None) + def _cells_by_name(self): # Get the names maps, but since names are not unique, store a set for # each name key. In this way when the user requests a change by a name, # the change will be applied to all of the same name. @@ -209,8 +148,8 @@ class Model: return result @property - @cache - def _materials_by_name(self) -> dict[int, openmc.Material]: + @lru_cache(maxsize=None) + def _materials_by_name(self): if self.materials is None: mats = self.geometry.get_all_materials().values() else: @@ -222,124 +161,65 @@ class Model: result[mat.name].add(mat) return result - # TODO: This should really get incorporated in lower-level calls to - # get_all_materials, but right now it requires information from the Model object - def _get_all_materials(self) -> dict[int, openmc.Material]: - """Get all materials including those in DAGMC universes + @geometry.setter + def geometry(self, geometry): + check_type('geometry', geometry, openmc.Geometry) + self._geometry = geometry - Returns - ------- - dict - Dictionary mapping material ID to material instances - """ - # Get all materials from the Geometry object - materials = self.geometry.get_all_materials() + @materials.setter + def materials(self, materials): + check_type('materials', materials, Iterable, openmc.Material) + if isinstance(materials, openmc.Materials): + self._materials = materials + else: + del self._materials[:] + for mat in materials: + self._materials.append(mat) - # Account for materials in DAGMC universes - for cell in self.geometry.get_all_cells().values(): - if isinstance(cell.fill, openmc.DAGMCUniverse): - names = cell.fill.material_names - materials.update({ - mat.id: mat for mat in self.materials if mat.name in names - }) + @settings.setter + def settings(self, settings): + check_type('settings', settings, openmc.Settings) + self._settings = settings - return materials + @tallies.setter + def tallies(self, tallies): + check_type('tallies', tallies, Iterable, openmc.Tally) + if isinstance(tallies, openmc.Tallies): + self._tallies = tallies + else: + del self._tallies[:] + for tally in tallies: + self._tallies.append(tally) - def add_kinetics_parameters_tallies(self, num_groups: int | None = None): - """Add tallies for calculating kinetics parameters using the IFP method. - - This method adds tallies to the model for calculating two kinetics - parameters, the generation time and the effective delayed neutron - fraction (beta effective). After a model is run, these parameters can be - determined through the :meth:`openmc.StatePoint.ifp_results` method. - - Parameters - ---------- - num_groups : int, optional - Number of precursor groups to filter the delayed neutron fraction. - If None, only the total effective delayed neutron fraction is - tallied. - - """ - if not any('ifp-time-numerator' in t.scores for t in self.tallies): - gen_time_tally = openmc.Tally(name='IFP time numerator') - gen_time_tally.scores = ['ifp-time-numerator'] - self.tallies.append(gen_time_tally) - if not any('ifp-beta-numerator' in t.scores for t in self.tallies): - beta_tally = openmc.Tally(name='IFP beta numerator') - beta_tally.scores = ['ifp-beta-numerator'] - if num_groups is not None: - beta_tally.filters = [openmc.DelayedGroupFilter(list(range(1, num_groups + 1)))] - self.tallies.append(beta_tally) - if not any('ifp-denominator' in t.scores for t in self.tallies): - denom_tally = openmc.Tally(name='IFP denominator') - denom_tally.scores = ['ifp-denominator'] - self.tallies.append(denom_tally) - - # TODO: This should also be incorporated into lower-level calls in - # settings.py, but it requires information about the tallies currently - # on the active Model - def _assign_fw_cadis_tally_IDs(self): - # Verify that all tallies assigned as targets on WeightWindowGenerators - # exist within model.tallies. If this is the case, convert the .targets - # attribute of each WeightWindowGenerator to a sequence of tally IDs. - if len(self.settings.weight_window_generators) == 0: - return - - # List of valid tally IDs - reference_tally_ids = np.asarray([tal.id for tal in self.tallies]) - - for wwg in self.settings.weight_window_generators: - # Only proceeds if the "targets" attribute is an openmc.Tallies, - # which means it hasn't been checked against model.tallies. - if isinstance(wwg.targets, openmc.Tallies): - id_vec = [] - for tal in wwg.targets: - # check against model tallies for equivalence - id_next = None - for reference_tal in self.tallies: - if tal == reference_tal: - id_next = reference_tal.id - break - - if id_next is None: - raise RuntimeError( - f'Local FW-CADIS target tally {tal.id} not found on model.tallies!') - else: - id_vec.append(id_next) - - wwg.targets = id_vec - - elif isinstance(wwg.targets, np.ndarray): - invalid = wwg.targets[~np.isin(wwg.targets, reference_tally_ids)] - if len(invalid) > 0: - raise RuntimeError( - f'Local FW-CADIS target tally IDs {invalid} not found on model.tallies!') + @plots.setter + def plots(self, plots): + check_type('plots', plots, Iterable, openmc.Plot) + if isinstance(plots, openmc.Plots): + self._plots = plots + else: + del self._plots[:] + for plot in plots: + self._plots.append(plot) @classmethod - def from_xml( - cls, - geometry: PathLike = "geometry.xml", - materials: PathLike = "materials.xml", - settings: PathLike = "settings.xml", - tallies: PathLike = "tallies.xml", - plots: PathLike = "plots.xml", - ) -> Model: + def from_xml(cls, geometry='geometry.xml', materials='materials.xml', + settings='settings.xml', tallies='tallies.xml', + plots='plots.xml'): """Create model from existing XML files Parameters ---------- - geometry : PathLike + geometry : str Path to geometry.xml file - materials : PathLike + materials : str Path to materials.xml file - settings : PathLike + settings : str Path to settings.xml file - tallies : PathLike + tallies : str Path to tallies.xml file .. versionadded:: 0.13.0 - plots : PathLike + plots : str Path to plots.xml file .. versionadded:: 0.13.0 @@ -353,56 +233,12 @@ class Model: materials = openmc.Materials.from_xml(materials) geometry = openmc.Geometry.from_xml(geometry, materials) settings = openmc.Settings.from_xml(settings) - tallies = openmc.Tallies.from_xml( - tallies) if Path(tallies).exists() else None + tallies = openmc.Tallies.from_xml(tallies) if Path(tallies).exists() else None plots = openmc.Plots.from_xml(plots) if Path(plots).exists() else None return cls(geometry, materials, settings, tallies, plots) - @classmethod - def from_model_xml(cls, path: PathLike = "model.xml") -> Model: - """Create model from single XML file - - .. versionadded:: 0.13.3 - - Parameters - ---------- - path : PathLike - Path to model.xml file - """ - parser = ET.XMLParser(huge_tree=True) - tree = ET.parse(path, parser=parser) - root = tree.getroot() - - model = cls() - - meshes = {} - model.settings = openmc.Settings.from_xml_element( - root.find('settings'), meshes) - model.materials = openmc.Materials.from_xml_element( - root.find('materials')) - model.geometry = openmc.Geometry.from_xml_element( - root.find('geometry'), model.materials) - - if root.find('tallies') is not None: - model.tallies = openmc.Tallies.from_xml_element( - root.find('tallies'), meshes) - - if root.find('plots') is not None: - model.plots = openmc.Plots.from_xml_element(root.find('plots')) - - return model - - def init_lib( - self, - threads: int | None = None, - geometry_debug: bool = False, - restart_file: PathLike | None = None, - tracks: bool = False, - output: bool = True, - event_based: bool | None = None, - intracomm=None, - directory: PathLike | None = None, - ): + def init_lib(self, threads=None, geometry_debug=False, restart_file=None, + tracks=False, output=True, event_based=None, intracomm=None): """Initializes the model in memory via the C API .. versionadded:: 0.13.0 @@ -417,12 +253,10 @@ class Model: variable). geometry_debug : bool, optional Turn on geometry debugging during simulation. Defaults to False. - restart_file : PathLike, optional + restart_file : str, optional Path to restart file to use tracks : bool, optional - Enables the writing of particles tracks. The number of particle - tracks written to tracks.h5 is limited to 1000 unless - Settings.max_tracks is set. Defaults to False. + Write tracks for all particles. Defaults to False. output : bool Capture OpenMC output from standard out event_based : None or bool, optional @@ -430,8 +264,6 @@ class Model: the Settings will be used. intracomm : mpi4py.MPI.Intracomm or None, optional MPI intracommunicator - directory : PathLike or None, optional - Directory to write XML files to. Defaults to None. """ import openmc.lib @@ -445,8 +277,7 @@ class Model: args = _process_CLI_arguments( volume=False, geometry_debug=geometry_debug, restart_file=restart_file, threads=threads, tracks=tracks, - event_based=event_based, path_input=directory) - + event_based=event_based) # Args adds the openmc_exec command in the first entry; remove it args = args[1:] @@ -460,10 +291,7 @@ class Model: self._intracomm = DummyCommunicator() if self._intracomm.rank == 0: - if directory is not None: - self.export_to_xml(directory=directory) - else: - self.export_to_xml() + self.export_to_xml() self._intracomm.barrier() # We cannot pass DummyCommunicator to openmc.lib.init so pass instead @@ -471,30 +299,6 @@ class Model: # communicator openmc.lib.init(args=args, intracomm=intracomm, output=output) - def sync_dagmc_universes(self): - """Synchronize all DAGMC universes in the current geometry. - - This method iterates over all DAGMC universes in the geometry and - synchronizes their cells with the current material assignments. Requires - that the model has been initialized via :meth:`Model.init_lib`. - Synchronized DAGMC cells can then be edited and exported as nested - `` overrides inside each `` element. - - .. versionadded:: 0.15.1 - - """ - if self.is_initialized: - if self.materials: - materials = self.materials - else: - materials = list(self.geometry.get_all_materials().values()) - for univ in self.geometry.get_all_universes().values(): - if isinstance(univ, openmc.DAGMCUniverse): - univ.sync_dagmc_cells(materials) - else: - raise ValueError("The model must be initialized before calling " - "this method") - def finalize_lib(self): """Finalize simulation and free memory allocated for the C API @@ -506,15 +310,9 @@ class Model: openmc.lib.finalize() - def deplete( - self, - method: str = "cecm", - final_step: bool = True, - operator_kwargs: dict | None = None, - directory: PathLike = ".", - output: bool = True, - **integrator_kwargs, - ): + def deplete(self, timesteps, method='cecm', final_step=True, + operator_kwargs=None, directory='.', output=True, + **integrator_kwargs): """Deplete model using specified timesteps/power .. versionchanged:: 0.13.0 @@ -523,12 +321,10 @@ class Model: Parameters ---------- - timesteps : iterable of float or iterable of tuple - Array of timesteps. Note that values are not cumulative. The units are - specified by the `timestep_units` argument when `timesteps` is an - iterable of float. Alternatively, units can be specified for each step - by passing an iterable of (value, unit) tuples. - method : str + timesteps : iterable of float + Array of timesteps in units of [s]. Note that values are not + cumulative. + method : str, optional Integration method used for depletion (e.g., 'cecm', 'predictor'). Defaults to 'cecm'. final_step : bool, optional @@ -537,14 +333,14 @@ class Model: operator_kwargs : dict Keyword arguments passed to the depletion operator initializer (e.g., :func:`openmc.deplete.Operator`) - directory : PathLike, optional + directory : str, optional Directory to write XML files to. If it doesn't exist already, it will be created. Defaults to the current working directory output : bool Capture OpenMC output from standard out integrator_kwargs : dict - Remaining keyword arguments passed to the depletion integrator - (e.g., :class:`openmc.deplete.CECMIntegrator`). + Remaining keyword arguments passed to the depletion Integrator + initializer (e.g., :func:`openmc.deplete.integrator.cecm`). """ @@ -562,7 +358,7 @@ class Model: # Store whether or not the library was initialized when we started started_initialized = self.is_initialized - with change_directory(directory): + with _change_directory(Path(directory)): with openmc.lib.quiet_dll(output): # TODO: Support use of IndependentOperator too depletion_operator = dep.CoupledOperator(self, **op_kwargs) @@ -575,7 +371,8 @@ class Model: check_value('method', method, dep.integrators.integrator_by_name.keys()) integrator_class = dep.integrators.integrator_by_name[method] - integrator = integrator_class(depletion_operator, **integrator_kwargs) + integrator = integrator_class(depletion_operator, timesteps, + **integrator_kwargs) # Now perform the depletion with openmc.lib.quiet_dll(output): @@ -598,20 +395,12 @@ class Model: depletion_operator.cleanup_when_done = True depletion_operator.finalize() - def _link_geometry_to_filters(self): - """Establishes a link between distribcell filters and the geometry""" - for tally in self.tallies: - for f in tally.filters: - if isinstance(f, openmc.DistribcellFilter): - f._geometry = self.geometry - - def export_to_xml(self, directory: PathLike = '.', remove_surfs: bool = False, - nuclides_to_ignore: Iterable[str] | None = None): - """Export model to separate XML files. + def export_to_xml(self, directory='.', remove_surfs=False): + """Export model to XML files. Parameters ---------- - directory : PathLike + directory : str Directory to write XML files to. If it doesn't exist already, it will be created. remove_surfs : bool @@ -619,16 +408,12 @@ class Model: exporting. .. versionadded:: 0.13.1 - nuclides_to_ignore : list of str - Nuclides to ignore when exporting to XML. - """ # Create directory if required d = Path(directory) if not d.is_dir(): - d.mkdir(parents=True, exist_ok=True) + d.mkdir(parents=True) - self._assign_fw_cadis_tally_IDs() self.settings.export_to_xml(d) self.geometry.export_to_xml(d, remove_surfs=remove_surfs) @@ -636,104 +421,18 @@ class Model: # for all materials in the geometry and use that to automatically build # a collection. if self.materials: - self.materials.export_to_xml(d, nuclides_to_ignore=nuclides_to_ignore) + self.materials.export_to_xml(d) else: materials = openmc.Materials(self.geometry.get_all_materials() .values()) - materials.export_to_xml(d, nuclides_to_ignore=nuclides_to_ignore) + materials.export_to_xml(d) if self.tallies: self.tallies.export_to_xml(d) if self.plots: self.plots.export_to_xml(d) - self._link_geometry_to_filters() - - def export_to_model_xml(self, path: PathLike = 'model.xml', remove_surfs: bool = False, - nuclides_to_ignore: Iterable[str] | None = None): - """Export model to a single XML file. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - path : str or PathLike - Location of the XML file to write (default is 'model.xml'). Can be a - directory or file path. - remove_surfs : bool - Whether or not to remove redundant surfaces from the geometry when - exporting. - nuclides_to_ignore : list of str - Nuclides to ignore when exporting to XML. - - """ - xml_path = Path(path) - # if the provided path doesn't end with the XML extension, assume the - # input path is meant to be a directory. If the directory does not - # exist, create it and place a 'model.xml' file there. - if not str(xml_path).endswith('.xml'): - if not xml_path.exists(): - xml_path.mkdir(parents=True, exist_ok=True) - elif not xml_path.is_dir(): - raise FileExistsError(f"File exists and is not a directory: '{xml_path}'") - xml_path /= 'model.xml' - # if this is an XML file location and the file's parent directory does - # not exist, create it before continuing - elif not xml_path.parent.exists(): - xml_path.parent.mkdir(parents=True, exist_ok=True) - - if remove_surfs: - warnings.warn("remove_surfs kwarg will be deprecated soon, please " - "set the Geometry.merge_surfaces attribute instead.") - self.geometry.merge_surfaces = True - - # Link FW-CADIS WeightWindowGenerator target tallies, if present - self._assign_fw_cadis_tally_IDs() - - # provide a memo to track which meshes have been written - mesh_memo = set() - settings_element = self.settings.to_xml_element(mesh_memo) - geometry_element = self.geometry.to_xml_element() - - xml.clean_indentation(geometry_element, level=1) - xml.clean_indentation(settings_element, level=1) - - # If a materials collection was specified, export it. Otherwise, look - # for all materials in the geometry and use that to automatically build - # a collection. - if self.materials: - materials = self.materials - else: - materials = openmc.Materials(self.geometry.get_all_materials() - .values()) - - with open(xml_path, 'w', encoding='utf-8', errors='xmlcharrefreplace') as fh: - # write the XML header - fh.write("\n") - fh.write("\n") - # Write the materials collection to the open XML file first. - # This will write the XML header also - materials._write_xml(fh, False, level=1, - nuclides_to_ignore=nuclides_to_ignore) - # Write remaining elements as a tree - fh.write(ET.tostring(geometry_element, encoding="unicode")) - fh.write(ET.tostring(settings_element, encoding="unicode")) - - if self.tallies: - tallies_element = self.tallies.to_xml_element(mesh_memo) - xml.clean_indentation( - tallies_element, level=1, trailing_indent=self.plots) - fh.write(ET.tostring(tallies_element, encoding="unicode")) - if self.plots: - plots_element = self.plots.to_xml_element() - xml.clean_indentation( - plots_element, level=1, trailing_indent=False) - fh.write(ET.tostring(plots_element, encoding="unicode")) - fh.write("\n") - - self._link_geometry_to_filters() - - def import_properties(self, filename: PathLike): + def import_properties(self, filename): """Import physical properties .. versionchanged:: 0.13.0 @@ -741,7 +440,7 @@ class Model: Parameters ---------- - filename : PathLike + filename : str Path to properties HDF5 file See Also @@ -763,34 +462,15 @@ class Model: raise ValueError("Number of cells in properties file doesn't " "match current model.") - # Update temperatures and densities for cells filled with materials + # Update temperatures for cells filled with materials for name, group in cells_group.items(): cell_id = int(name.split()[1]) cell = cells[cell_id] if cell.fill_type in ('material', 'distribmat'): - temperature = group['temperature'][()] - cell.temperature = temperature + cell.temperature = group['temperature'][()] if self.is_initialized: lib_cell = openmc.lib.cells[cell_id] - if temperature.size > 1: - for i, T in enumerate(temperature): - lib_cell.set_temperature(T, i) - else: - lib_cell.set_temperature(temperature[0]) - - if group['density']: - density = group['density'][()] - if density.size > 1: - cell.density = [rho for rho in density] - else: - cell.density = density - if self.is_initialized: - lib_cell = openmc.lib.cells[cell_id] - if density.size > 1: - for i, rho in enumerate(density): - lib_cell.set_density(rho, i) - else: - lib_cell.set_density(density[0]) + lib_cell.set_temperature(group['temperature'][()]) # Make sure number of materials matches mats_group = fh['materials'] @@ -808,28 +488,13 @@ class Model: C_mat = openmc.lib.materials[mat_id] C_mat.set_density(atom_density, 'atom/b-cm') - def run( - self, - particles: int | None = None, - threads: int | None = None, - geometry_debug: bool = False, - restart_file: PathLike | None = None, - tracks: bool = False, - output: bool = True, - cwd: PathLike = ".", - openmc_exec: PathLike = "openmc", - mpi_args: Iterable[str] = None, - event_based: bool | None = None, - export_model_xml: bool = True, - apply_tally_results: bool = False, - **export_kwargs, - ) -> Path: - """Run OpenMC - - If the C API has been initialized, then the C API is used, otherwise, - this method creates the XML files and runs OpenMC via a system call. In - both cases this method returns the path to the last statepoint file - generated. + def run(self, particles=None, threads=None, geometry_debug=False, + restart_file=None, tracks=False, output=True, cwd='.', + openmc_exec='openmc', mpi_args=None, event_based=None): + """Runs OpenMC. If the C API has been initialized, then the C API is + used, otherwise, this method creates the XML files and runs OpenMC via + a system call. In both cases this method returns the path to the last + statepoint file generated. .. versionchanged:: 0.12 Instead of returning the final k-effective value, this function now @@ -849,44 +514,29 @@ class Model: value set by the :envvar:`OMP_NUM_THREADS` environment variable). geometry_debug : bool, optional Turn on geometry debugging during simulation. Defaults to False. - restart_file : str or PathLike + restart_file : str, optional Path to restart file to use tracks : bool, optional - Enables the writing of particles tracks. The number of particle - tracks written to tracks.h5 is limited to 1000 unless - Settings.max_tracks is set. Defaults to False. + Write tracks for all particles. Defaults to False. output : bool, optional Capture OpenMC output from standard out - cwd : PathLike, optional - Path to working directory to run in. Defaults to the current working - directory. + cwd : str, optional + Path to working directory to run in. Defaults to the current + working directory. openmc_exec : str, optional Path to OpenMC executable. Defaults to 'openmc'. mpi_args : list of str, optional - MPI execute command and any additional MPI arguments to pass, e.g. - ['mpiexec', '-n', '8']. + MPI execute command and any additional MPI arguments to pass, + e.g. ['mpiexec', '-n', '8']. event_based : None or bool, optional - Turns on event-based parallelism if True. If None, the value in the - Settings will be used. - export_model_xml : bool, optional - Exports a single model.xml file rather than separate files. Defaults - to True. - - .. versionadded:: 0.13.3 - apply_tally_results : bool - Whether to apply results of the final statepoint file to the - model's tally objects. - - .. versionadded:: 0.15.1 - **export_kwargs - Keyword arguments passed to either :meth:`Model.export_to_model_xml` - or :meth:`Model.export_to_xml`. + Turns on event-based parallelism if True. If None, the value in + the Settings will be used. Returns ------- Path - Path to the last statepoint written by this run (None if no - statepoint was written) + Path to the last statepoint written by this run + (None if no statepoint was written) """ @@ -899,7 +549,7 @@ class Model: last_statepoint = None # Operate in the provided working directory - with change_directory(cwd): + with _change_directory(Path(cwd)): if self.is_initialized: # Handle the run options as applicable # First dont allow ones that must be set via init @@ -930,14 +580,10 @@ class Model: else: # Then run via the command line - if export_model_xml: - self.export_to_model_xml(**export_kwargs) - else: - self.export_to_xml(**export_kwargs) - path_input = export_kwargs.get("path", None) + self.export_to_xml() openmc.run(particles, threads, geometry_debug, restart_file, tracks, output, Path('.'), openmc_exec, mpi_args, - event_based, path_input) + event_based) # Get output directory and return the last statepoint written if self.settings.output and 'path' in self.settings.output: @@ -949,23 +595,11 @@ class Model: if mtime >= tstart: # >= allows for poor clock resolution tstart = mtime last_statepoint = sp - - if apply_tally_results: - self.apply_tally_results(last_statepoint) - return last_statepoint - def calculate_volumes( - self, - threads: int | None = None, - output: bool = True, - cwd: PathLike = ".", - openmc_exec: PathLike = "openmc", - mpi_args: list[str] | None = None, - apply_volumes: bool = True, - export_model_xml: bool = True, - **export_kwargs, - ): + def calculate_volumes(self, threads=None, output=True, cwd='.', + openmc_exec='openmc', mpi_args=None, + apply_volumes=True): """Runs an OpenMC stochastic volume calculation and, if requested, applies volumes to the model @@ -994,21 +628,14 @@ class Model: apply_volumes : bool, optional Whether apply the volume calculation results from this calculation to the model. Defaults to applying the volumes. - export_model_xml : bool, optional - Exports a single model.xml file rather than separate files. Defaults - to True. - **export_kwargs - Keyword arguments passed to either :meth:`Model.export_to_model_xml` - or :meth:`Model.export_to_xml`. - """ if len(self.settings.volume_calculations) == 0: # Then there is no volume calculation specified - raise ValueError("The Settings.volume_calculations attribute must" + raise ValueError("The Settings.volume_calculation attribute must" " be specified before executing this method!") - with change_directory(cwd): + with _change_directory(Path(cwd)): if self.is_initialized: if threads is not None: msg = "Threads must be set via Model.is_initialized(...)" @@ -1022,15 +649,10 @@ class Model: openmc.lib.calculate_volumes(output) else: - if export_model_xml: - self.export_to_model_xml(**export_kwargs) - else: - self.export_to_xml(**export_kwargs) - path_input = export_kwargs.get("path", None) - openmc.calculate_volumes( - threads=threads, output=output, openmc_exec=openmc_exec, - mpi_args=mpi_args, path_input=path_input - ) + self.export_to_xml() + openmc.calculate_volumes(threads=threads, output=output, + openmc_exec=openmc_exec, + mpi_args=mpi_args) # Now we apply the volumes if apply_volumes: @@ -1038,12 +660,7 @@ class Model: for i, vol_calc in enumerate(self.settings.volume_calculations): vol_calc.load_results(f"volume_{i + 1}.h5") # First add them to the Python side - if vol_calc.domain_type == "material" and self.materials: - for material in self.materials: - if material.id in vol_calc.volumes: - material.add_volume_information(vol_calc) - else: - self.geometry.add_volume_information(vol_calc) + self.geometry.add_volume_information(vol_calc) # And now repeat for the C API if self.is_initialized and vol_calc.domain_type == 'material': @@ -1052,489 +669,7 @@ class Model: openmc.lib.materials[domain_id].volume = \ vol_calc.volumes[domain_id].n - - def _set_plot_defaults( - self, - origin: Sequence[float] | None, - width: Sequence[float] | None, - pixels: int | Sequence[int], - basis: str - ): - _check_pixels(pixels) - - x, y, _ = _BASIS_INDICES[basis] - - bb = self.bounding_box - # checks to see if bounding box contains -inf or inf values - if np.isinf(bb.extent[basis]).any(): - if origin is None: - origin = (0, 0, 0) - if width is None: - width = (10, 10) - else: - if origin is None: - # if nan values in the bb.center they get replaced with 0.0 - # this happens when the bounding_box contains inf values - with warnings.catch_warnings(): - warnings.simplefilter("ignore", RuntimeWarning) - origin = np.nan_to_num(bb.center) - if width is None: - bb_width = bb.width - width = (bb_width[x], bb_width[y]) - - if isinstance(pixels, int): - aspect_ratio = width[0] / width[1] - pixels_y = math.sqrt(pixels / aspect_ratio) - pixels = (int(pixels / pixels_y), int(pixels_y)) - - return origin, width, pixels - - def id_map( - self, - origin: Sequence[float] | None = None, - width: Sequence[float] | None = None, - pixels: int | Sequence[int] = 40000, - basis: str = 'xy', - color_overlaps: bool = False, - **init_kwargs - ) -> np.ndarray: - """Generate an ID map for domains based on the plot parameters - - If the model is not yet initialized, it will be initialized with - openmc.lib. If the model is initialized, the model will remain - initialized after this method call exits. - - .. versionadded:: 0.15.3 - - Parameters - ---------- - origin : Sequence[float], optional - Origin of the plot. If unspecified, this argument defaults to the - center of the bounding box if the bounding box does not contain inf - values for the provided basis, otherwise (0.0, 0.0, 0.0). - width : Sequence[float], optional - Width of the plot. If unspecified, this argument defaults to the - width of the bounding box if the bounding box does not contain inf - values for the provided basis, otherwise (10.0, 10.0). - pixels : int | Sequence[int], optional - If an iterable of ints is provided then this directly sets the - number of pixels to use in each basis direction. If a single int is - provided then this sets the total number of pixels in the plot and - the number of pixels in each basis direction is calculated from this - total and the image aspect ratio based on the width argument. - basis : {'xy', 'yz', 'xz'}, optional - Basis of the plot. - color_overlaps : bool, optional - Whether to assign unique IDs (-3) to overlapping regions. If False, - overlapping regions will be assigned the ID of the lowest-numbered - cell that occupies that region. Defaults to False. - **init_kwargs - Keyword arguments passed to :meth:`Model.init_lib`. - - Returns - ------- - id_map : numpy.ndarray - A NumPy array with shape (vertical pixels, horizontal pixels, 3) of - OpenMC property IDs with dtype int32. The last dimension of the - array contains cell IDs, cell instances, and material IDs (in that - order). - """ - ids, _ = self.slice_data( - origin=origin, - width=width, - pixels=pixels, - basis=basis, - show_overlaps=color_overlaps, - level=-1, - include_properties=False, - **init_kwargs, - ) - return ids - - def slice_data( - self, - origin: Sequence[float] | None = None, - width: Sequence[float] | None = None, - pixels: int | Sequence[int] = 40000, - basis: str = 'xy', - u_span: Sequence[float] | None = None, - v_span: Sequence[float] | None = None, - show_overlaps: bool = False, - level: int = -1, - filter: openmc.Filter | None = None, - include_properties: bool = True, - **init_kwargs - ) -> tuple[np.ndarray, np.ndarray | None]: - """Generate geometry and property data for a 2D plot slice. - - This method combines the functionality of :meth:`id_map` and property - mapping into a single call, avoiding duplicate geometry lookups. It also - supports filter bin index lookup for tally visualization. - - .. versionadded:: 0.16.0 - - Parameters - ---------- - origin : Sequence[float], optional - Origin of the plot. If unspecified, this argument defaults to the - center of the bounding box if the bounding box does not contain inf - values for the provided basis, otherwise (0.0, 0.0, 0.0). - width : Sequence[float], optional - Width of the plot. If unspecified, this argument defaults to the - width of the bounding box if the bounding box does not contain inf - values for the provided basis, otherwise (10.0, 10.0). - pixels : int | Sequence[int], optional - If an iterable of ints is provided then this directly sets the - number of pixels to use in each basis direction. If a single int is - provided then this sets the total number of pixels in the plot and - the number of pixels in each basis direction is calculated from this - total and the image aspect ratio based on the width argument. - basis : {'xy', 'yz', 'xz'}, optional - Basis of the plot. - u_span : Sequence[float], optional - Full-width span vector for an oriented slice (3 values). Mutually - exclusive with width. - v_span : Sequence[float], optional - Full-height span vector for an oriented slice (3 values). Mutually - exclusive with width. - show_overlaps : bool, optional - Whether to identify and assign unique IDs (-3) to overlapping - regions. If False, overlapping regions will be assigned the ID of - the lowest-numbered cell that occupies that region. Defaults to - False. - level : int, optional - Universe level to plot (-1 for deepest). Defaults to -1. - filter : openmc.Filter, optional - If provided, the information for each pixel also includes an index - in the filter corresponding to the pixel position. - include_properties : bool, optional - Whether to include temperature/density data. Defaults to True. - **init_kwargs - Keyword arguments passed to :meth:`Model.init_lib`. - - Returns - ------- - geom_data : numpy.ndarray - Shape (v_res, h_res, 3) or (v_res, h_res, 4) int32 array. Contains - [cell_id, cell_instance, material_id] when no filter, or [cell_id, - cell_instance, material_id, filter_bin] with filter. - property_data : numpy.ndarray or None - Shape (v_res, h_res, 2) float64 array with [temperature, density], - or None if include_properties=False. - """ - import openmc.lib - - _check_pixels(pixels) - - if width is not None and (u_span is not None or v_span is not None): - raise ValueError("width is mutually exclusive with u_span/v_span.") - - if u_span is not None or v_span is not None: - if u_span is None or v_span is None: - raise ValueError("Both u_span and v_span must be provided.") - if origin is None: - origin = (0.0, 0.0, 0.0) - if isinstance(pixels, int): - u_norm = np.linalg.norm(u_span) - v_norm = np.linalg.norm(v_span) - aspect_ratio = u_norm / v_norm - pixels_y = math.sqrt(pixels / aspect_ratio) - pixels = (int(pixels / pixels_y), int(pixels_y)) - else: - origin, width, pixels = self._set_plot_defaults( - origin, width, pixels, basis) - - # Silence output by default. Also set arguments to start in volume - # calculation mode to avoid loading cross sections - init_kwargs.setdefault('output', False) - init_kwargs.setdefault('args', ['-c']) - - # If filter does not already appear in the model, temporarily add a - # tally with the filter - original_length = len(self.tallies) - if filter is not None: - filter_ids = {f.id for t in self.tallies for f in t.filters} - if filter.id not in filter_ids: - # Create temporary tally while preserving ID assignment - next_id = openmc.Tally.next_id - temp_tally = openmc.Tally() - temp_tally.filters = [filter] - temp_tally.scores = ['flux'] - self.tallies.append(temp_tally) - openmc.Tally.used_ids.remove(temp_tally.id) - openmc.Tally.next_id = next_id - - with openmc.lib.TemporarySession(self, **init_kwargs): - geom_data, property_data = openmc.lib.slice_data( - origin=origin, - width=width, - basis=basis, - u_span=u_span, - v_span=v_span, - pixels=pixels, - show_overlaps=show_overlaps, - level=level, - filter=filter, - include_properties=include_properties, - ) - - # If filter was temporarily added, remove it - if len(self.tallies) > original_length: - self.tallies.pop() - - return geom_data, property_data - - @add_plot_params - def plot( - self, - origin: Sequence[float] | None = None, - width: Sequence[float] | None = None, - pixels: int | Sequence[int] = 40000, - basis: str = 'xy', - color_by: str = 'cell', - colors: dict | None = None, - seed: int | None = None, - axes=None, - legend: bool = False, - axis_units: str = 'cm', - outline: bool | str = False, - show_overlaps: bool = False, - overlap_color: Sequence[int] | str = (255, 0, 0), - n_samples: int | None = None, - plane_tolerance: float = 1., - legend_kwargs: dict | None = None, - source_kwargs: dict | None = None, - contour_kwargs: dict | None = None, - **kwargs, - ): - """Display a slice plot of the model. - - .. versionadded:: 0.15.1 - """ - import matplotlib.patches as mpatches - import matplotlib.pyplot as plt - - check_type('n_samples', n_samples, int | None) - if n_samples is not None: - check_greater_than('n_samples', n_samples, 0, equality=True) - check_type('plane_tolerance', plane_tolerance, Real) - check_greater_than('plane_tolerance', plane_tolerance, 0.0) - - if legend_kwargs is None: - legend_kwargs = {} - legend_kwargs.setdefault('bbox_to_anchor', (1.05, 1)) - legend_kwargs.setdefault('loc', 2) - legend_kwargs.setdefault('borderaxespad', 0.0) - if source_kwargs is None: - source_kwargs = {} - source_kwargs.setdefault('marker', 'x') - - # Set indices using basis and create axis labels - x, y, z = _BASIS_INDICES[basis] - xlabel, ylabel = f'{basis[0]} [{axis_units}]', f'{basis[1]} [{axis_units}]' - - # Determine extents of plot - origin, width, pixels = self._set_plot_defaults( - origin, width, pixels, basis) - - axis_scaling_factor = {'km': 0.00001, 'm': 0.01, 'cm': 1, 'mm': 10} - - x_min = (origin[x] - 0.5*width[0]) * axis_scaling_factor[axis_units] - x_max = (origin[x] + 0.5*width[0]) * axis_scaling_factor[axis_units] - y_min = (origin[y] - 0.5*width[1]) * axis_scaling_factor[axis_units] - y_max = (origin[y] + 0.5*width[1]) * axis_scaling_factor[axis_units] - - # Determine whether any materials contains macroscopic data and if so, - # set energy mode accordingly and check that mg cross sections path is accessible - for mat in self.geometry.get_all_materials().values(): - if mat._macroscopic is not None: - self.settings.energy_mode = 'multi-group' - if 'mg_cross_sections' not in openmc.config: - raise RuntimeError("'mg_cross_sections' path must be set in " - "openmc.config before plotting.") - break - - # Get plot IDs from the C API - id_map, _ = self.slice_data( - origin=origin, - width=width, - pixels=pixels, - basis=basis, - show_overlaps=show_overlaps, - include_properties=False, - ) - - # Generate colors if not provided - if colors is None and seed is not None: - # Use the colorize method to generate random colors - plot = openmc.SlicePlot() - plot.color_by = color_by - plot.colorize(self.geometry, seed=seed) - colors = plot.colors - - # Convert ID map to RGB image - img = id_map_to_rgb( - id_map=id_map, - color_by=color_by, - colors=colors, - overlap_color=overlap_color - ) - - # Create a figure sized such that the size of the axes within - # exactly matches the number of pixels specified - if axes is None: - px = 1/plt.rcParams['figure.dpi'] - fig, axes = plt.subplots() - axes.set_xlabel(xlabel) - axes.set_ylabel(ylabel) - params = fig.subplotpars - width_px = pixels[0]*px/(params.right - params.left) - height_px = pixels[1]*px/(params.top - params.bottom) - fig.set_size_inches(width_px, height_px) - - if outline: - # Combine R, G, B values into a single int for contour detection - rgb = (img * 256).astype(int) - image_value = (rgb[..., 0] << 16) + \ - (rgb[..., 1] << 8) + (rgb[..., 2]) - - # Set default arguments for contour() - if contour_kwargs is None: - contour_kwargs = {} - contour_kwargs.setdefault('colors', 'k') - contour_kwargs.setdefault('linestyles', 'solid') - contour_kwargs.setdefault('algorithm', 'serial') - - axes.contour( - image_value, - origin="upper", - levels=np.unique(image_value), - extent=(x_min, x_max, y_min, y_max), - **contour_kwargs - ) - - # If only showing outline, set the axis limits and aspect explicitly - if outline == 'only': - axes.set_xlim(x_min, x_max) - axes.set_ylim(y_min, y_max) - axes.set_aspect('equal') - - # Add legend showing which colors represent which material or cell - if legend: - if colors is None or len(colors) == 0: - raise ValueError("Must pass 'colors' dictionary if you " - "are adding a legend via legend=True.") - - if color_by == "cell": - expected_key_type = openmc.Cell - else: - expected_key_type = openmc.Material - - patches = [] - for key, color in colors.items(): - if isinstance(key, int): - raise TypeError( - "Cannot use IDs in colors dict for auto legend.") - elif not isinstance(key, expected_key_type): - raise TypeError( - "Color dict key type does not match color_by") - - # this works whether we're doing cells or materials - label = key.name if key.name != '' else key.id - - # matplotlib takes RGB on 0-1 scale rather than 0-255 - if len(color) == 3 and not isinstance(color, str): - scaled_color = ( - color[0]/255, color[1]/255, color[2]/255) - else: - scaled_color = color - - key_patch = mpatches.Patch(color=scaled_color, label=label) - patches.append(key_patch) - - axes.legend(handles=patches, **legend_kwargs) - - # Plot image and return the axes - if outline != 'only': - axes.imshow(img, extent=(x_min, x_max, y_min, y_max), **kwargs) - - if n_samples: - # Sample external source particles - particles = self.sample_external_source(n_samples) - - # Get points within tolerance of the slice plane - slice_value = origin[z] - xs = [] - ys = [] - tol = plane_tolerance - for particle in particles: - if (slice_value - tol < particle.r[z] < slice_value + tol): - xs.append(particle.r[x] * axis_scaling_factor[axis_units]) - ys.append(particle.r[y] * axis_scaling_factor[axis_units]) - axes.scatter(xs, ys, **source_kwargs) - - return axes - - def sample_external_source( - self, - n_samples: int = 1000, - prn_seed: int | None = None, - as_array: bool = False, - **init_kwargs - ) -> openmc.ParticleList | np.ndarray: - """Sample external source and return source particles. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - n_samples : int - Number of samples - prn_seed : int - Pseudorandom number generator (PRNG) seed; if None, one will be - generated randomly. - as_array : bool - If True, return a numpy structured array instead of a - :class:`~openmc.ParticleList`. - **init_kwargs - Keyword arguments passed to :func:`openmc.lib.init` - - Returns - ------- - openmc.ParticleList or numpy.ndarray - List of sampled source particles, or a structured array when - *as_array* is True. - """ - import openmc.lib - - # Silence output by default. Also set arguments to start in volume - # calculation mode to avoid loading cross sections - init_kwargs.setdefault('output', False) - init_kwargs.setdefault('args', ['-c']) - - with openmc.lib.TemporarySession(self, **init_kwargs): - return openmc.lib.sample_external_source( - n_samples=n_samples, prn_seed=prn_seed, as_array=as_array - ) - - def apply_tally_results(self, statepoint: PathLike | openmc.StatePoint): - """Apply results from a statepoint to tally objects on the Model - - Parameters - ---------- - statepoint : PathLike or openmc.StatePoint - Statepoint file used to update tally results - """ - self.tallies.add_results(statepoint) - - def plot_geometry( - self, - output: bool = True, - cwd: PathLike = ".", - openmc_exec: PathLike = "openmc", - export_model_xml: bool = True, - **export_kwargs, - ): + def plot_geometry(self, output=True, cwd='.', openmc_exec='openmc'): """Creates plot images as specified by the Model.plots attribute .. versionadded:: 0.13.0 @@ -1543,18 +678,12 @@ class Model: ---------- output : bool, optional Capture OpenMC output from standard out - cwd : PathLike, optional + cwd : str, optional Path to working directory to run in. Defaults to the current working directory. - openmc_exec : PathLike, optional + openmc_exec : str, optional Path to OpenMC executable. Defaults to 'openmc'. This only applies to the case when not using the C API. - export_model_xml : bool, optional - Exports a single model.xml file rather than separate files. Defaults - to True. - **export_kwargs - Keyword arguments passed to either :meth:`Model.export_to_model_xml` - or :meth:`Model.export_to_xml`. """ @@ -1563,27 +692,16 @@ class Model: raise ValueError("The Model.plots attribute must be specified " "before executing this method!") - with change_directory(cwd): + with _change_directory(Path(cwd)): if self.is_initialized: # Compute the volumes openmc.lib.plot_geometry(output) else: - if export_model_xml: - self.export_to_model_xml(**export_kwargs) - else: - self.export_to_xml(**export_kwargs) - path_input = export_kwargs.get("path", None) - openmc.plot_geometry(output=output, openmc_exec=openmc_exec, - path_input=path_input) + self.export_to_xml() + openmc.plot_geometry(output=output, openmc_exec=openmc_exec) - def _change_py_lib_attribs( - self, - names_or_ids: Iterable[str] | Iterable[int], - value: float | Iterable[float], - obj_type: str, - attrib_name: str, - density_units: str = "atom/b-cm", - ): + def _change_py_lib_attribs(self, names_or_ids, value, obj_type, + attrib_name, density_units='atom/b-cm'): # Method to do the same work whether it is a cell or material and # a temperature or volume check_type('names_or_ids', names_or_ids, Iterable, (Integral, str)) @@ -1662,9 +780,7 @@ class Model: else: setattr(lib_obj, attrib_name, value) - def rotate_cells( - self, names_or_ids: Iterable[str] | Iterable[int], vector: Iterable[float] - ): + def rotate_cells(self, names_or_ids, vector): """Rotate the identified cell(s) by the specified rotation vector. The rotation is only applied to cells filled with a universe. @@ -1686,9 +802,7 @@ class Model: self._change_py_lib_attribs(names_or_ids, vector, 'cell', 'rotation') - def translate_cells( - self, names_or_ids: Iterable[str] | Iterable[int], vector: Iterable[float] - ): + def translate_cells(self, names_or_ids, vector): """Translate the identified cell(s) by the specified translation vector. The translation is only applied to cells filled with a universe. @@ -1711,12 +825,7 @@ class Model: self._change_py_lib_attribs(names_or_ids, vector, 'cell', 'translation') - def update_densities( - self, - names_or_ids: Iterable[str] | Iterable[int], - density: float, - density_units: str = "atom/b-cm", - ): + def update_densities(self, names_or_ids, density, density_units='atom/b-cm'): """Update the density of a given set of materials to a new value .. note:: If applying this change to a name that is not unique, then @@ -1739,9 +848,7 @@ class Model: self._change_py_lib_attribs(names_or_ids, density, 'material', 'density', density_units) - def update_cell_temperatures( - self, names_or_ids: Iterable[str] | Iterable[int], temperature: float - ): + def update_cell_temperatures(self, names_or_ids, temperature): """Update the temperature of a set of cells to the given value .. note:: If applying this change to a name that is not unique, then @@ -1762,9 +869,7 @@ class Model: self._change_py_lib_attribs(names_or_ids, temperature, 'cell', 'temperature') - def update_material_volumes( - self, names_or_ids: Iterable[str] | Iterable[int], volume: float - ): + def update_material_volumes(self, names_or_ids, volume): """Update the volume of a set of materials to the given value .. note:: If applying this change to a name that is not unique, then @@ -1783,1370 +888,3 @@ class Model: """ self._change_py_lib_attribs(names_or_ids, volume, 'material', 'volume') - - def differentiate_depletable_mats(self, diff_volume_method: str = None): - """Assign distribmats for each depletable material - - .. versionadded:: 0.14.0 - - .. versionchanged:: 0.15.1 - diff_volume_method default is None, do not set volumes on the new - material ovjects. Is now a convenience method for - differentiate_mats(diff_volume_method, depletable_only=True) - - Parameters - ---------- - diff_volume_method : str - Specifies how the volumes of the new materials should be found. - - None: Do not assign volumes to the new materials (Default) - - 'divide equally': Divide the original material volume equally between the new materials - - 'match cell': Set the volume of the material to the volume of the cell they fill - """ - self.differentiate_mats(diff_volume_method, depletable_only=True) - - def differentiate_mats(self, diff_volume_method: str = None, depletable_only: bool = True): - """Assign distribmats for each material - - .. versionadded:: 0.15.1 - - Parameters - ---------- - diff_volume_method : str - Specifies how the volumes of the new materials should be found. - - None: Do not assign volumes to the new materials (Default) - - 'divide equally': Divide the original material volume equally between the new materials - - 'match cell': Set the volume of the material to the volume of the cell they fill - depletable_only : bool - Default is True, only depletable materials will be differentiated. If False, all materials will be - differentiated. - """ - check_value('volume differentiation method', diff_volume_method, ("divide equally", "match cell", None)) - - # Count the number of instances for each cell and material - self.geometry.determine_paths(instances_only=True) - - # Get list of materials - if self.materials: - materials = self.materials - else: - materials = list(self.geometry.get_all_materials().values()) - - # Find all or depletable_only materials which have multiple instance - distribmats = set() - for mat in materials: - # Differentiate all materials with multiple instances - diff_mat = mat.num_instances > 1 - # If depletable_only is True, differentiate only depletable materials - if depletable_only: - diff_mat = diff_mat and mat.depletable - if diff_mat: - # Assign volumes to the materials according to requirements - if diff_volume_method == "divide equally": - if mat.volume is None: - raise RuntimeError( - "Volume not specified for " - f"material with ID={mat.id}.") - else: - mat.volume /= mat.num_instances - elif diff_volume_method == "match cell": - for cell in self.geometry.get_all_material_cells().values(): - if cell.fill == mat: - if not cell.volume: - raise ValueError( - f"Volume of cell ID={cell.id} not specified. " - "Set volumes of cells prior to using " - "diff_volume_method='match cell'.") - distribmats.add(mat) - - if not distribmats: - return - - # Assign distribmats to cells - for cell in self.geometry.get_all_material_cells().values(): - if cell.fill in distribmats: - mat = cell.fill - - # Clone materials - if cell.num_instances > 1: - cell.fill = [mat.clone() for _ in range(cell.num_instances)] - else: - cell.fill = mat.clone() - - # For 'match cell', assign volumes based on the cells - if diff_volume_method == 'match cell': - if cell.fill_type == 'distribmat': - for clone_mat in cell.fill: - clone_mat.volume = cell.volume - else: - cell.fill.volume = cell.volume - - if self.materials is not None: - self.materials = openmc.Materials( - self.geometry.get_all_materials().values() - ) - - @staticmethod - def _auto_generate_mgxs_lib( - model: openmc.model.Model, - groups: openmc.mgxs.EnergyGroups, - correction: str | None, - directory: PathLike, - ) -> openmc.mgxs.Library: - """ - Automatically generate a multi-group cross section libray from a model - with the specified group structure. - - Parameters - ---------- - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - mgxs_path : str - Filename for the MGXS HDF5 file. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : str - Directory to run the simulation in, so as to contain XML files. - - Returns - ------- - mgxs_lib : openmc.mgxs.Library - OpenMC MGXS Library object - """ - - # Initialize MGXS library with a finished OpenMC geometry object - mgxs_lib = openmc.mgxs.Library(model.geometry) - - # Pick energy group structure - mgxs_lib.energy_groups = groups - - # Disable transport correction - mgxs_lib.correction = correction - - # Specify needed cross sections for random ray - if correction == 'P0': - mgxs_lib.mgxs_types = [ - 'nu-transport', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi', - 'kappa-fission' - ] - elif correction is None: - mgxs_lib.mgxs_types = [ - 'total', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi', - 'kappa-fission' - ] - - # Specify a "material" domain type for the cross section tally filters - mgxs_lib.domain_type = "material" - - # Specify the domains over which to compute multi-group cross sections - mgxs_lib.domains = model.geometry.get_all_materials().values() - - # Do not compute cross sections on a nuclide-by-nuclide basis - mgxs_lib.by_nuclide = False - - # Check the library - if no errors are raised, then the library is satisfactory. - mgxs_lib.check_library_for_openmc_mgxs() - - # Construct all tallies needed for the multi-group cross section library - mgxs_lib.build_library() - - # Create a "tallies.xml" file for the MGXS Library - mgxs_lib.add_to_tallies(model.tallies, merge=True) - - # Run - statepoint_filename = model.run(cwd=directory) - - # Load MGXS - with openmc.StatePoint(statepoint_filename) as sp: - mgxs_lib.load_from_statepoint(sp) - - return mgxs_lib - - def _create_mgxs_sources( - self, - groups: openmc.mgxs.EnergyGroups, - spatial_dist: openmc.stats.Spatial, - source_energy: openmc.stats.Univariate | None = None, - ) -> list[openmc.IndependentSource]: - """Create a list of independent sources to use with MGXS generation. - - Note that in all cases, a discrete source that is uniform over all - energy groups is created (strength = 0.01) to ensure that total cross - sections are generated for all energy groups. In the case that the user - has provided a source_energy distribution as an argument, an additional - source (strength = 0.99) is created using that energy distribution. If - the user has not provided a source_energy distribution, but the model - has sources defined, and all of those sources are of IndependentSource - type, then additional sources are created based on the model's existing - sources, keeping their energy distributions but replacing their - spatial/angular distributions, with their combined strength being 0.99. - If the user has not provided a source_energy distribution and no sources - are defined on the model and the run mode is 'eigenvalue', then a - default Watt spectrum source (strength = 0.99) is added. - - Parameters - ---------- - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - spatial_dist : openmc.stats.Spatial - Spatial distribution to use for all sources. - source_energy : openmc.stats.Univariate, optional - Energy distribution to use when generating MGXS data, replacing any - existing sources in the model. - - Returns - ------- - list[openmc.IndependentSource] - A list of independent sources to use for MGXS generation. - """ - # Make a discrete source that is uniform over the bins of the group structure - midpoints = [] - strengths = [] - for i in range(groups.num_groups): - bounds = groups.get_group_bounds(i+1) - midpoints.append((bounds[0] + bounds[1]) / 2.0) - strengths.append(1.0) - - uniform_energy = openmc.stats.Discrete(x=midpoints, p=strengths) - uniform_distribution = openmc.IndependentSource(spatial_dist, energy=uniform_energy, strength=0.01) - sources = [uniform_distribution] - - # If the user provided an energy distribution, use that - if source_energy is not None: - user_energy = openmc.IndependentSource( - space=spatial_dist, energy=source_energy, strength=0.99) - sources.append(user_energy) - - # If the user did not provide an energy distribution, create sources - # based on what is in their model, keeping the energy spectrum but - # replacing the spatial/angular distributions. We only do this if ALL - # sources are of IndependentSource type, as we can't pull the energy - # distribution from e.g. CompiledSource or FileSource types. - else: - if self.settings.source is not None: - for src in self.settings.source: - if not isinstance(src, openmc.IndependentSource): - break - else: - n_user_sources = len(self.settings.source) - for src in self.settings.source: - # Create a new IndependentSource with adjusted strength, space, and angle - user_source = openmc.IndependentSource( - space=spatial_dist, - energy=src.energy, - strength=0.99 / n_user_sources - ) - sources.append(user_source) - else: - # No user sources defined. If we are in eigenvalue mode, then use the default Watt spectrum. - if self.settings.run_mode == 'eigenvalue': - watt_energy = openmc.stats.Watt() - watt_source = openmc.IndependentSource( - space=spatial_dist, energy=watt_energy, strength=0.99) - sources.append(watt_source) - - return sources - - @staticmethod - def _isothermal_infinite_media_mgxs( - material: openmc.Material, - groups: openmc.mgxs.EnergyGroups, - nparticles: int, - correction: str | None, - directory: PathLike, - source: openmc.IndependentSource, - temperature_settings: dict, - temperature: float | None = None, - ) -> openmc.XSdata: - """Generate a single MGXS set for one material, where the geometry is an - infinite medium composed of that material at an isothermal temperature value. - - Parameters - ---------- - material : openmc.Material - The material to generate MGXS for - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : str - Directory to run the simulation in, so as to contain XML files. - source : openmc.IndependentSource - Source to use when generating MGXS. - temperature_settings : dict - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - temperature : float, optional - The isothermal temperature value to apply to the material. If not specified, - defaults to the temperature in the material. - - Returns - ------- - data : openmc.XSdata - The material MGXS for the given temperature isotherm. - """ - model = openmc.Model() - - # Set materials on the model - model.materials = [material] - if temperature is not None: - model.materials[-1].temperature = temperature - - # Settings - model.settings.batches = 100 - model.settings.particles = nparticles - - model.settings.source = source - - model.settings.run_mode = 'fixed source' - model.settings.create_fission_neutrons = False - - model.settings.output = {'summary': True, 'tallies': False} - model.settings.temperature = temperature_settings - - # Geometry - box = openmc.model.RectangularPrism( - 100000.0, 100000.0, boundary_type='reflective') - name = material.name - infinite_cell = openmc.Cell(name=name, fill=model.materials[-1], region=-box) - infinite_universe = openmc.Universe(name=name, cells=[infinite_cell]) - model.geometry.root_universe = infinite_universe - - # Generate MGXS - mgxs_lib = Model._auto_generate_mgxs_lib( - model, groups, correction, directory) - - if temperature is not None: - return mgxs_lib.get_xsdata(domain=material, xsdata_name=name, - temperature=temperature) - else: - return mgxs_lib.get_xsdata(domain=material, xsdata_name=name) - - def _generate_infinite_medium_mgxs( - self, - groups: openmc.mgxs.EnergyGroups, - nparticles: int, - mgxs_path: PathLike, - correction: str | None, - directory: PathLike, - source_energy: openmc.stats.Univariate | None = None, - temperatures: Sequence[float] | None = None, - temperature_settings: dict | None = None, - ) -> None: - """Generate a MGXS library by running multiple OpenMC simulations, each - representing an infinite medium simulation of a single isolated - material. A discrete source is used to sample particles, with an equal - strength spread across each of the energy groups. This is a highly naive - method that ignores all spatial self shielding effects and all resonance - shielding effects between materials. If temperature data points are provided, - isothermal cross sections are generated at each temperature point for - each material to build a temperature interpolation table. - - Note that in all cases, a discrete source that is uniform over all - energy groups is created (strength = 0.01) to ensure that total cross - sections are generated for all energy groups. In the case that the user - has provided a source_energy distribution as an argument, an additional - source (strength = 0.99) is created using that energy distribution. If - the user has not provided a source_energy distribution, but the model - has sources defined, and all of those sources are of IndependentSource - type, then additional sources are created based on the model's existing - sources, keeping their energy distributions but replacing their - spatial/angular distributions, with their combined strength being 0.99. - If the user has not provided a source_energy distribution and no sources - are defined on the model and the run mode is 'eigenvalue', then a - default Watt spectrum source (strength = 0.99) is added. - - Parameters - ---------- - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - mgxs_path : str - Filename for the MGXS HDF5 file. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : str - Directory to run the simulation in, so as to contain XML files. - source_energy : openmc.stats.Univariate, optional - Energy distribution to use when generating MGXS data, replacing any - existing sources in the model. - temperatures : Sequence[float], optional - A list of temperatures to generate MGXS at. Each infinite material region - is isothermal at a given temperature data point for cross - section generation. - temperature_settings : dict, optional - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - """ - - src = self._create_mgxs_sources( - groups, - spatial_dist=openmc.stats.Point(), - source_energy=source_energy - ) - - temp_settings = {} - if temperature_settings is None: - temp_settings = self.settings.temperature - else: - temp_settings = temperature_settings - - if temperatures is None: - mgxs_sets = [] - for material in self.materials: - xs_data = Model._isothermal_infinite_media_mgxs( - material, - groups, - nparticles, - correction, - directory, - src, - temp_settings - ) - mgxs_sets.append(xs_data) - - # Write the file to disk. - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) - for mgxs_set in mgxs_sets: - mgxs_file.add_xsdata(mgxs_set) - mgxs_file.export_to_hdf5(mgxs_path) - else: - # Build a series of XSData objects, one for each isothermal temperature value. - raw_mgxs_sets = {} - for temperature in temperatures: - raw_mgxs_sets[temperature] = [] - for material in self.materials: - xs_data = Model._isothermal_infinite_media_mgxs( - material, - groups, - nparticles, - correction, - directory, - src, - temp_settings, - temperature - ) - raw_mgxs_sets[temperature].append(xs_data) - - # Unpack the isothermal XSData objects and build a single XSData object per material. - mgxs_sets = [] - for m in range(len(self.materials)): - mgxs_sets.append(openmc.XSdata(self.materials[m].name, groups, - temperatures=temperatures)) - mgxs_sets[-1].order = 0 - for temperature in temperatures: - mgxs_sets[-1].add_temperature_data(raw_mgxs_sets[temperature][m]) - - # Write the file to disk. - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) - for mgxs_set in mgxs_sets: - mgxs_file.add_xsdata(mgxs_set) - mgxs_file.export_to_hdf5(mgxs_path) - - @staticmethod - def _create_stochastic_slab_geometry( - materials: Sequence[openmc.Material], - cell_thickness: float = 1.0, - num_repeats: int = 100, - ) -> tuple[openmc.Geometry, openmc.stats.Box]: - """Create a geometry representing a stochastic "sandwich" of materials in a - layered slab geometry. To reduce the impact of the order of materials in - the slab, the materials are applied to 'num_repeats' different randomly - positioned layers of 'cell_thickness' each. - - Parameters - ---------- - materials : list of openmc.Material - List of materials to assign. Each material will appear exactly num_repeats times, - then the ordering is randomly shuffled. - cell_thickness : float, optional - Thickness of each lattice cell in x (default 1.0 cm). - num_repeats : int, optional - Number of repeats for each material (default 100). - - Returns - ------- - geometry : openmc.Geometry - The constructed geometry. - box : openmc.stats.Box - A spatial sampling distribution covering the full slab domain. - """ - if not materials: - raise ValueError("At least one material must be provided.") - - num_materials = len(materials) - total_cells = num_materials * num_repeats - total_width = total_cells * cell_thickness - - # Generate an infinite cell/universe for each material - universes = [] - for i in range(num_materials): - cell = openmc.Cell(fill=materials[i]) - universes.append(openmc.Universe(cells=[cell])) - - # Make a list of randomized material idx assignments for the stochastic slab - assignments = list(range(num_materials)) * num_repeats - random.seed(42) - random.shuffle(assignments) - - # Create a list of the (randomized) universe assignments to be used - # when defining the problem lattice. - lattice_entries = [universes[m] for m in assignments] - - # Create the RectLattice for the 1D material variation in x. - lattice = openmc.RectLattice() - lattice.pitch = (cell_thickness, total_width, total_width) - lattice.lower_left = (0.0, 0.0, 0.0) - lattice.universes = [[lattice_entries]] - lattice.outer = universes[0] - - # Define the six outer surfaces with reflective boundary conditions - rpp = openmc.model.RectangularParallelepiped( - 0.0, total_width, 0.0, total_width, 0.0, total_width, - boundary_type='reflective' - ) - - # Create an outer cell that fills with the lattice. - outer_cell = openmc.Cell(fill=lattice, region=-rpp) - - # Build the geometry - geometry = openmc.Geometry([outer_cell]) - - # Define the spatial distribution that covers the full cubic domain - box = openmc.stats.Box(*outer_cell.bounding_box) - - return geometry, box - - @staticmethod - def _isothermal_stochastic_slab_mgxs( - stoch_geom: openmc.Geometry, - groups: openmc.mgxs.EnergyGroups, - nparticles: int, - correction: str | None, - directory: PathLike, - source: openmc.IndependentSource, - temperature_settings: dict, - temperature: float | None = None, - ) -> dict[str, openmc.XSdata]: - """Generate MGXS assuming a stochastic "sandwich" of materials in a layered - slab geometry. If a temperature is specified, all materials in the slab have - their temperatures set to be isothermal at this temperature. - - Parameters - ---------- - stoch_geom : openmc.Geometry - The stochastic slab geometry. - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : str - Directory to run the simulation in, so as to contain XML files. - source : openmc.IndependentSource - Source to use when generating MGXS. - temperature_settings : dict - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - temperature : float, optional - The isothermal temperature value to apply to the materials in the - slab. If not specified, defaults to the temperature in the materials. - - Returns - ------- - data : dict[str, openmc.XSdata] - A dictionary where the key is the name of the material and the value is the isothermal MGXS. - """ - - model = openmc.Model() - model.geometry = stoch_geom - - if temperature is not None: - for material in model.geometry.get_all_materials().values(): - material.temperature = temperature - - # Settings - model.settings.batches = 200 - model.settings.inactive = 100 - model.settings.particles = nparticles - model.settings.output = {'summary': True, 'tallies': False} - model.settings.temperature = temperature_settings - - # Define the sources - model.settings.source = source - - model.settings.run_mode = 'fixed source' - model.settings.create_fission_neutrons = False - - model.settings.output = {'summary': True, 'tallies': False} - - # Generate MGXS - mgxs_lib = Model._auto_generate_mgxs_lib( - model, groups, correction, directory) - - # Fetch all of the isothermal results. - if temperature is not None: - return { - mat.name : mgxs_lib.get_xsdata(domain=mat, xsdata_name=mat.name, - temperature=temperature) - for mat in mgxs_lib.domains - } - else: - return { - mat.name : mgxs_lib.get_xsdata(domain=mat, xsdata_name=mat.name) - for mat in mgxs_lib.domains - } - - def _generate_stochastic_slab_mgxs( - self, - groups: openmc.mgxs.EnergyGroups, - nparticles: int, - mgxs_path: PathLike, - correction: str | None, - directory: PathLike, - source_energy: openmc.stats.Univariate | None = None, - temperatures: Sequence[float] | None = None, - temperature_settings: dict | None = None, - ) -> None: - """Generate MGXS assuming a stochastic "sandwich" of materials in a layered - slab geometry. While geometry-specific spatial shielding effects are not - captured, this method can be useful when the geometry has materials only - found far from the source region that the "material_wise" method would - not be capable of generating cross sections for. Conversely, this method - will generate cross sections for all materials in the problem regardless - of type. If this is a fixed source problem, a discrete source is used to - sample particles, with an equal strength spread across each of the - energy groups. If temperature data points are provided, - isothermal cross sections are generated at each temperature point for - the stochastic slab to build a temperature interpolation table. - - Parameters - ---------- - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - mgxs_path : str - Filename for the MGXS HDF5 file. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : str - Directory to run the simulation in, so as to contain XML files. - source_energy : openmc.stats.Univariate, optional - Energy distribution to use when generating MGXS data, replacing any - existing sources in the model. In all cases, a discrete source that - is uniform over all energy groups is created (strength = 0.01) to - ensure that total cross sections are generated for all energy - groups. In the case that the user has provided a source_energy - distribution as an argument, an additional source (strength = 0.99) - is created using that energy distribution. If the user has not - provided a source_energy distribution, but the model has sources - defined, and all of those sources are of IndependentSource type, - then additional sources are created based on the model's existing - sources, keeping their energy distributions but replacing their - spatial/angular distributions, with their combined strength being - 0.99. If the user has not provided a source_energy distribution and - no sources are defined on the model and the run mode is - 'eigenvalue', then a default Watt spectrum source (strength = 0.99) - is added. - temperatures : Sequence[float], optional - A list of temperatures to generate MGXS at. Each infinite material region - is isothermal at a given temperature data point for cross - section generation. - temperature_settings : dict, optional - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - """ - - # Stochastic slab geometry - geo, spatial_distribution = Model._create_stochastic_slab_geometry( - self.materials) - - src = self._create_mgxs_sources( - groups, - spatial_dist=spatial_distribution, - source_energy=source_energy - ) - - temp_settings = {} - if temperature_settings is None: - temp_settings = self.settings.temperature - else: - temp_settings = temperature_settings - - if temperatures is None: - mgxs_sets = Model._isothermal_stochastic_slab_mgxs( - geo, - groups, - nparticles, - correction, - directory, - src, - temp_settings - ).values() - - # Write the file to disk. - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) - for mgxs_set in mgxs_sets: - mgxs_file.add_xsdata(mgxs_set) - mgxs_file.export_to_hdf5(mgxs_path) - else: - # Build a series of XSData objects, one for each isothermal temperature value. - raw_mgxs_sets = {} - for temperature in temperatures: - raw_mgxs_sets[temperature] = Model._isothermal_stochastic_slab_mgxs( - geo, - groups, - nparticles, - correction, - directory, - src, - temp_settings, - temperature - ) - - # Unpack the isothermal XSData objects and build a single XSData object per material. - mgxs_sets = [] - for mat in self.materials: - mgxs_sets.append(openmc.XSdata(mat.name, groups, temperatures=temperatures)) - mgxs_sets[-1].order = 0 - for temperature in temperatures: - mgxs_sets[-1].add_temperature_data(raw_mgxs_sets[temperature][mat.name]) - - # Write the file to disk. - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) - for mgxs_set in mgxs_sets: - mgxs_file.add_xsdata(mgxs_set) - mgxs_file.export_to_hdf5(mgxs_path) - - @staticmethod - def _isothermal_materialwise_mgxs( - input_model: openmc.Model, - groups: openmc.mgxs.EnergyGroups, - nparticles: int, - correction: str | None, - directory: PathLike, - temperature_settings: dict, - temperature: float | None = None, - ) -> dict[str, openmc.XSdata]: - """Generate a material-wise MGXS library for the model by running the - original continuous energy OpenMC simulation. If a temperature is - specified, each material in the input model is set to that temperature. - Otherwise, the original material temperatures are used. If temperature - data points are provided, isothermal cross sections are generated at - each temperature point for the whole model to build a temperature - interpolation table. - - Parameters - ---------- - input_model : openmc.Model - The model to use when computing material-wise MGXS. - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : str - Directory to run the simulation in, so as to contain XML files. - temperature_settings : dict - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - temperature : float, optional - The isothermal temperature value to apply to the materials in the - input model. If not specified, defaults to the temperatures in the - materials. - - Returns - ------- - data : dict[str, openmc.XSdata] - A dictionary where the key is the name of the material and the value is the isothermal MGXS. - """ - model = copy.deepcopy(input_model) - model.tallies = openmc.Tallies() - - if temperature is not None: - for material in model.geometry.get_all_materials().values(): - material.temperature = temperature - - # Settings - model.settings.batches = 200 - model.settings.inactive = 100 - model.settings.particles = nparticles - model.settings.output = {'summary': True, 'tallies': False} - model.settings.temperature = temperature_settings - - # Generate MGXS - mgxs_lib = Model._auto_generate_mgxs_lib( - model, groups, correction, directory) - - # Fetch all of the isothermal results. - if temperature is not None: - return { - mat.name : mgxs_lib.get_xsdata(domain=mat, xsdata_name=mat.name, - temperature=temperature) - for mat in mgxs_lib.domains - } - else: - return { - mat.name : mgxs_lib.get_xsdata(domain=mat, xsdata_name=mat.name) - for mat in mgxs_lib.domains - } - - def _generate_material_wise_mgxs( - self, - groups: openmc.mgxs.EnergyGroups, - nparticles: int, - mgxs_path: PathLike, - correction: str | None, - directory: PathLike, - temperatures: Sequence[float] | None = None, - temperature_settings: dict | None = None, - ) -> None: - """Generate a material-wise MGXS library for the model by running the - original continuous energy OpenMC simulation of the full material - geometry and source, and tally MGXS data for each material. This method - accurately conserves reaction rates totaled over the entire simulation - domain. However, when the geometry has materials only found far from the - source region, it is possible the Monte Carlo solver may not be able to - score any tallies to these material types, thus resulting in zero cross - section values for these materials. For such cases, the "stochastic - slab" method may be more appropriate. - - Parameters - ---------- - groups : openmc.mgxs.EnergyGroups - Energy group structure for the MGXS. - nparticles : int - Number of particles to simulate per batch when generating MGXS. - mgxs_path : PathLike - Filename for the MGXS HDF5 file. - correction : str - Transport correction to apply to the MGXS. Options are None and - "P0". - directory : PathLike - Directory to run the simulation in, so as to contain XML files. - temperatures : Sequence[float], optional - A list of temperatures to generate MGXS at. Each infinite material region - is isothermal at a given temperature data point for cross - section generation. - temperature_settings : dict, optional - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - """ - temp_settings = {} - if temperature_settings is None: - temp_settings = self.settings.temperature - else: - temp_settings = temperature_settings - - if temperatures is None: - mgxs_sets = Model._isothermal_materialwise_mgxs( - self, - groups, - nparticles, - correction, - directory, - temp_settings - ).values() - - # Write the file to disk. - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) - for mgxs_set in mgxs_sets: - mgxs_file.add_xsdata(mgxs_set) - mgxs_file.export_to_hdf5(mgxs_path) - else: - # Build a series of XSData objects, one for each isothermal temperature value. - raw_mgxs_sets = {} - for temperature in temperatures: - raw_mgxs_sets[temperature] = Model._isothermal_materialwise_mgxs( - self, - groups, - nparticles, - correction, - directory, - temp_settings, - temperature - ) - - # Unpack the isothermal XSData objects and build a single XSData object per material. - mgxs_sets = [] - for mat in self.materials: - mgxs_sets.append(openmc.XSdata(mat.name, groups, temperatures=temperatures)) - mgxs_sets[-1].order = 0 - for temperature in temperatures: - mgxs_sets[-1].add_temperature_data(raw_mgxs_sets[temperature][mat.name]) - - # Write the file to disk. - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) - for mgxs_set in mgxs_sets: - mgxs_file.add_xsdata(mgxs_set) - mgxs_file.export_to_hdf5(mgxs_path) - - def convert_to_multigroup( - self, - method: str = "material_wise", - groups: str | Sequence[float] | openmc.mgxs.EnergyGroups = "CASMO-2", - nparticles: int = 2000, - overwrite_mgxs_library: bool = False, - mgxs_path: PathLike = "mgxs.h5", - correction: str | None = None, - source_energy: openmc.stats.Univariate | None = None, - temperatures: Sequence[float] | None = None, - temperature_settings: dict | None = None, - ): - """Convert all materials from continuous energy to multigroup. - - If no MGXS data library file is found, generate one using one or more - continuous energy Monte Carlo simulations. - - Parameters - ---------- - method : {"material_wise", "stochastic_slab", "infinite_medium"}, optional - Method to generate the MGXS. - groups : openmc.mgxs.EnergyGroups, str, or sequence of float, optional - Energy group structure for the MGXS. Can be an - :class:`openmc.mgxs.EnergyGroups` object, a string name of a - predefined group structure from :data:`openmc.mgxs.GROUP_STRUCTURES` - (e.g., ``"CASMO-2"``), or a sequence of floats specifying energy - bin boundaries in eV (e.g., ``[0.0, 1e6]`` for a single group). - Defaults to ``"CASMO-2"``. - nparticles : int, optional - Number of particles to simulate per batch when generating MGXS. - overwrite_mgxs_library : bool, optional - Whether to overwrite an existing MGXS library file. - mgxs_path : str, optional - Path to the mgxs.h5 library file. - correction : str, optional - Transport correction to apply to the MGXS. Options are None and - "P0". - source_energy : openmc.stats.Univariate, optional - Energy distribution to use when generating MGXS data, replacing any - existing sources in the model. In all cases, a discrete source that - is uniform over all energy groups is created (strength = 0.01) to - ensure that total cross sections are generated for all energy - groups. In the case that the user has provided a source_energy - distribution as an argument, an additional source (strength = 0.99) - is created using that energy distribution. If the user has not - provided a source_energy distribution, but the model has sources - defined, and all of those sources are of IndependentSource type, - then additional sources are created based on the model's existing - sources, keeping their energy distributions but replacing their - spatial/angular distributions, with their combined strength being - 0.99. If the user has not provided a source_energy distribution and - no sources are defined on the model and the run mode is - 'eigenvalue', then a default Watt spectrum source (strength = 0.99) - is added. Note that this argument is only used when using the - "stochastic_slab" or "infinite_medium" MGXS generation methods. - temperatures : Sequence[float], optional - A list of temperatures to generate MGXS at. Each infinite material region - is isothermal at a given temperature data point for cross - section generation. - temperature_settings : dict, optional - A dictionary of temperature settings to use when generating MGXS. - Valid entries for temperature_settings are the same as the valid - entries in openmc.Settings.temperature_settings. - """ - if not isinstance(groups, openmc.mgxs.EnergyGroups): - groups = openmc.mgxs.EnergyGroups(groups) - - # Do all work (including MGXS generation) in a temporary directory - # to avoid polluting the working directory with residual XML files - with TemporaryDirectory() as tmpdir: - - # Determine if there are DAGMC universes in the model. If so, we need to synchronize - # the dagmc materials with cells. - # TODO: Can this be done without having to init/finalize? - for univ in self.geometry.get_all_universes().values(): - if isinstance(univ, openmc.DAGMCUniverse): - # Initialize in stochastic volume mode (non-transport mode) - # This mode doesn't require - # valid transport settings like particles/batches - original_run_mode = self.settings.run_mode - self.settings.run_mode = 'volume' - self.init_lib(directory=tmpdir) - self.sync_dagmc_universes() - self.finalize_lib() - # Restore original run mode - self.settings.run_mode = original_run_mode - break - - # Temporarily replace each material's name with a unique, valid HDF5 - # dataset name (its name plus ID) for use as its MGXS library entry - # and macroscopic. The ID keeps the name unique even when materials - # share a name; the original names are restored at the end. - original_names = [material.name for material in self.materials] - for material in self.materials: - base = material.name if material.name and material.name.strip() \ - else "material" - material.name = re.sub(r'[^a-zA-Z0-9]', '_', base) + f"_{material.id}" - - # If needed, generate the needed MGXS data library file - if not Path(mgxs_path).is_file() or overwrite_mgxs_library: - if method == "infinite_medium": - self._generate_infinite_medium_mgxs( - groups, nparticles, mgxs_path, correction, tmpdir, source_energy, - temperatures, temperature_settings) - elif method == "material_wise": - self._generate_material_wise_mgxs( - groups, nparticles, mgxs_path, correction, tmpdir, - temperatures, temperature_settings) - elif method == "stochastic_slab": - self._generate_stochastic_slab_mgxs( - groups, nparticles, mgxs_path, correction, tmpdir, source_energy, - temperatures, temperature_settings) - else: - raise ValueError( - f'MGXS generation method "{method}" not recognized') - else: - print(f'Existing MGXS library file "{mgxs_path}" will be used') - - # Convert all continuous energy materials to multigroup - self.materials.cross_sections = mgxs_path - for material in self.materials: - material.set_density('macro', 1.0) - material._nuclides = [] - material._sab = [] - material.add_macroscopic(material.name) - - self.settings.energy_mode = 'multi-group' - - # Restore the user's original material names. - for material, name in zip(self.materials, original_names): - material.name = name - - def convert_to_random_ray(self): - """Convert a multigroup model to use random ray. - - This method determines values for the needed settings and adds them to - the settings.random_ray dictionary so as to enable random ray mode. The - settings that are populated are: - - - 'ray_source' (openmc.IndependentSource): Where random ray starting - points are sampled from. - - 'distance_inactive' (float): The "dead zone" distance at the beginning - of the ray. - - 'distance_active' (float): The "active" distance of the ray - - 'particles' (int): Number of rays to simulate - - The method will determine reasonable defaults for each of the above - variables based on analysis of the model's geometry. The function will - have no effect if the random ray dictionary is already defined in the - model settings. - """ - # If the random ray dictionary is already set, don't overwrite it - if self.settings.random_ray: - warnings.warn("Random ray conversion skipped as " - "settings.random_ray dictionary is already set.") - return - - if self.settings.energy_mode != 'multi-group': - raise ValueError( - "Random ray conversion failed: energy mode must be " - "'multi-group'. Use convert_to_multigroup() first." - ) - - # Helper function for detecting infinity - def _replace_infinity(value): - if np.isinf(value): - return 1.0 if value > 0 else -1.0 - return value - - # Get a bounding box for sampling rays. We can utilize the geometry's bounding box - # though for 2D problems we need to detect the infinities and replace them with an - # arbitrary finite value. - bounding_box = self.geometry.bounding_box - lower_left = [_replace_infinity(v) for v in bounding_box.lower_left] - upper_right = [_replace_infinity(v) for v in bounding_box.upper_right] - uniform_dist_ray = openmc.stats.Box(lower_left, upper_right) - rr_source = openmc.IndependentSource(space=uniform_dist_ray) - self.settings.random_ray['ray_source'] = rr_source - - # For the dead zone and active length, a reasonable guess is the larger of either: - # 1) The maximum chord length through the geometry (as defined by its bounding box) - # 2) 30 cm - # Then, set the active length to be 5x longer than the dead zone length, for the sake of efficiency. - chord_length = np.array(upper_right) - np.array(lower_left) - max_length = max(np.linalg.norm(chord_length), 30.0) - - self.settings.random_ray['distance_inactive'] = max_length - self.settings.random_ray['distance_active'] = 5 * max_length - - # Take a wild guess as to how many rays are needed - self.settings.particles = 2 * int(max_length) - - def keff_search( - self, - func: ModelModifier, - x0: float, - x1: float, - target: float = 1.0, - k_tol: float = 1e-4, - sigma_final: float = 3e-4, - p: float = 0.5, - q: float = 0.95, - memory: int = 4, - x_min: float | None = None, - x_max: float | None = None, - b0: int | None = None, - b_min: int = 20, - b_max: int | None = None, - maxiter: int = 50, - output: bool = False, - func_kwargs: dict[str, Any] | None = None, - run_kwargs: dict[str, Any] | None = None, - ) -> SearchResult: - r"""Perform a keff search on a model parametrized by a single variable. - - This method uses the GRsecant method described in a paper by `Price and - Roskoff `_. The GRsecant - method is a modification of the secant method that accounts for - uncertainties in the function evaluations. The method uses a weighted - linear fit of the most recent function evaluations to predict the next - point to evaluate. It also adaptively changes the number of batches to - meet the target uncertainty value at each iteration. - - The target uncertainty for iteration :math:`n+1` is determined by the - following equation (following Eq. (8) in the paper): - - .. math:: - \sigma_{i+1} = q \sigma_\text{final} \left ( \frac{ \min \left \{ - \left\lvert k_i - k_\text{target} \right\rvert : k=0,1,\dots,n - \right \} }{k_\text{tol}} \right )^p - - where :math:`q` is a multiplicative factor less than 1, given as the - ``sigma_factor`` parameter below. - - Parameters - ---------- - func : ModelModifier - Function that takes the parameter to be searched and makes a - modification to the model. - x0 : float - First guess for the parameter passed to `func` - x1 : float - Second guess for the parameter passed to `func` - target : float, optional - keff value to search for - k_tol : float, optional - Stopping criterion on the function value; the absolute value must be - within ``k_tol`` of zero to be accepted. - sigma_final : float, optional - Maximum accepted k-effective uncertainty for the stopping criterion. - p : float, optional - Exponent used in the stopping criterion. - q : float, optional - Multiplicative factor used in the stopping criterion. - memory : int, optional - Number of most-recent points used in the weighted linear fit of - ``f(x) = a + b x`` to predict the next point. - x_min : float, optional - Minimum allowed value for the parameter ``x``. - x_max : float, optional - Maximum allowed value for the parameter ``x``. - b0 : int, optional - Number of active batches to use for the initial function - evaluations. If None, uses the model's current setting. - b_min : int, optional - Minimum number of active batches to use in a function evaluation. - b_max : int, optional - Maximum number of active batches to use in a function evaluation. - maxiter : int, optional - Maximum number of iterations to perform. - output : bool, optional - Whether or not to display output showing iteration progress. - func_kwargs : dict, optional - Keyword-based arguments to pass to the `func` function. - run_kwargs : dict, optional - Keyword arguments to pass to :meth:`openmc.Model.run` or - :meth:`openmc.lib.run`. - - Returns - ------- - SearchResult - Result object containing the estimated root (parameter value) and - evaluation history (parameters, means, standard deviations, and - batches), plus convergence status and termination reason. - - """ - import openmc.lib - - check_type('model modifier', func, Callable) - check_type('target', target, Real) - if memory < 2: - raise ValueError("memory must be ≥ 2") - func_kwargs = {} if func_kwargs is None else dict(func_kwargs) - run_kwargs = {} if run_kwargs is None else dict(run_kwargs) - run_kwargs.setdefault('output', False) - - # Create lists to store the history of evaluations - xs: list[float] = [] - fs: list[float] = [] - ss: list[float] = [] - gs: list[int] = [] - count = 0 - - # Helper function to evaluate f and store results - def eval_at(x: float, batches: int) -> tuple[float, float]: - # Modify the model with the current guess - func(x, **func_kwargs) - - # Change the number of batches and run the model - batches += self.settings.inactive - if openmc.lib.is_initialized: - openmc.lib.settings.set_batches(batches) - openmc.lib.reset() - openmc.lib.run(**run_kwargs) - sp_filepath = f'statepoint.{batches}.h5' - else: - self.settings.batches = batches - sp_filepath = self.run(**run_kwargs) - - # Extract keff and its uncertainty - with openmc.StatePoint(sp_filepath) as sp: - keff = sp.keff - - if output: - nonlocal count - count += 1 - print(f'Iteration {count}: {batches=}, {x=:.6g}, {keff=:.5f}') - - xs.append(float(x)) - fs.append(float(keff.n - target)) - ss.append(float(keff.s)) - gs.append(int(batches)) - return fs[-1], ss[-1] - - # Default b0 to current model settings if not explicitly provided - if b0 is None: - b0 = self.settings.batches - self.settings.inactive - - # Perform the search (inlined GRsecant) in a temporary directory - with TemporaryDirectory() as tmpdir: - if not openmc.lib.is_initialized: - run_kwargs.setdefault('cwd', tmpdir) - - # ---- Seed with two evaluations - f0, s0 = eval_at(x0, b0) - if abs(f0) <= k_tol and s0 <= sigma_final: - return SearchResult(x0, xs, fs, ss, gs, True, "converged") - f1, s1 = eval_at(x1, b0) - if abs(f1) <= k_tol and s1 <= sigma_final: - return SearchResult(x1, xs, fs, ss, gs, True, "converged") - - for _ in range(maxiter - 2): - # ------ Step 1: propose next x via GRsecant - m = min(memory, len(xs)) - - # Perform a curve fit on f(x) = a + bx accounting for - # uncertainties. This is equivalent to minimizing the function - # in Equation (A.14) - (a, b), _ = curve_fit( - lambda x, a, b: a + b*x, - xs[-m:], fs[-m:], sigma=ss[-m:], absolute_sigma=True - ) - x_new = float(-a / b) - - # Clamp x_new to the bounds if provided - if x_min is not None: - x_new = max(x_new, x_min) - if x_max is not None: - x_new = min(x_new, x_max) - - # ------ Step 2: choose target σ for next run (Eq. 8 + clamp) - - min_abs_f = float(np.min(np.abs(fs))) - base = q * sigma_final - ratio = min_abs_f / k_tol if k_tol > 0 else 1.0 - sig = base * (ratio ** p) - sig_target = max(sig, base) - - # ------ Step 3: choose generations to hit σ_target (Appendix C) - - # Use at least two past points for regression - if len(gs) >= 2 and np.var(np.log(gs)) > 0.0: - # Perform a curve fit based on Eq. (C.3) to solve for ln(k). - # Note that unlike in the paper, we do not leave r as an - # undetermined parameter and choose r=0.5. - (ln_k,), _ = curve_fit( - lambda ln_b, ln_k: ln_k - 0.5*ln_b, - np.log(gs[-4:]), np.log(ss[-4:]), - ) - k = float(np.exp(ln_k)) - else: - k = float(ss[-1] * math.sqrt(gs[-1])) - - b_new = (k / sig_target) ** 2 - - # Clamp and round up to integer - b_new = max(b_min, math.ceil(b_new)) - if b_max is not None: - b_new = min(b_new, b_max) - - # Evaluate at proposed x with batches determined above - f_new, s_new = eval_at(x_new, b_new) - - # Termination based on both criteria (|f| and σ) - if abs(f_new) <= k_tol and s_new <= sigma_final: - return SearchResult(x_new, xs, fs, ss, gs, True, "converged") - - return SearchResult(xs[-1], xs, fs, ss, gs, False, "maxiter") - - -@dataclass -class SearchResult: - """Result of a GRsecant keff search. - - Attributes - ---------- - root : float - Estimated parameter value where f(x) = 0 at termination. - parameters : list[float] - Parameter values (x) evaluated during the search, in order. - keffs : list[float] - Estimated keff values for each evaluation. - stdevs : list[float] - One-sigma uncertainties of keff for each evaluation. - batches : list[int] - Number of active batches used for each evaluation. - converged : bool - Whether both |f| <= k_tol and sigma <= sigma_final were met. - flag : str - Reason for termination (e.g., "converged", "maxiter"). - """ - root: float - parameters: list[float] = field(repr=False) - means: list[float] = field(repr=False) - stdevs: list[float] = field(repr=False) - batches: list[int] = field(repr=False) - converged: bool - flag: str - - @property - def function_calls(self) -> int: - """Number of function evaluations performed.""" - return len(self.parameters) - - @property - def total_batches(self) -> int: - """Total number of active batches used across all evaluations.""" - return sum(self.batches) diff --git a/openmc/model/surface_composite.py b/openmc/model/surface_composite.py index 5962897de..4c76c7786 100644 --- a/openmc/model/surface_composite.py +++ b/openmc/model/surface_composite.py @@ -1,19 +1,10 @@ -from __future__ import annotations from abc import ABC, abstractmethod -from collections.abc import Iterable, Sequence from copy import copy -from functools import partial -from math import sqrt, pi, sin, cos, isclose -from numbers import Real -import warnings -import operator - +from math import sqrt, pi, sin, cos import numpy as np -from scipy.spatial import ConvexHull, Delaunay import openmc -from openmc.checkvalue import (check_greater_than, check_value, check_less_than, - check_iterable_type, check_length, check_type) +from openmc.checkvalue import check_greater_than, check_value class CompositeSurface(ABC): @@ -27,16 +18,12 @@ class CompositeSurface(ABC): return surf def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False): - surf = self if inplace else copy(self) + surf = copy(self) for name in self._surface_names: s = getattr(surf, name) setattr(surf, name, s.rotate(rotation, pivot, order, inplace)) return surf - @property - def component_surfaces(self): - return [getattr(self, name) for name in self._surface_names] - @property def boundary_type(self): return getattr(self, self._surface_names[0]).boundary_type @@ -45,14 +32,12 @@ class CompositeSurface(ABC): def boundary_type(self, boundary_type): # Set boundary type on underlying surfaces, but not for ambiguity plane # on one-sided cones - classes = (XConeOneSided, YConeOneSided, ZConeOneSided, Vessel) for name in self._surface_names: - if isinstance(self, classes) and name.startswith('plane'): - continue - getattr(self, name).boundary_type = boundary_type + if name != 'plane': + getattr(self, name).boundary_type = boundary_type def __repr__(self): - return f"<{type(self).__name__} at 0x{id(self):x}>" + return "<{} at 0x{:x}>".format(type(self).__name__, id(self)) @property @abstractmethod @@ -60,12 +45,12 @@ class CompositeSurface(ABC): """Iterable of attribute names corresponding to underlying surfaces.""" @abstractmethod - def __neg__(self) -> openmc.Region: - """Return the negative half-space of the composite surface.""" - - def __pos__(self) -> openmc.Region: + def __pos__(self): """Return the positive half-space of the composite surface.""" - return ~(-self) + + @abstractmethod + def __neg__(self): + """Return the negative half-space of the composite surface.""" class CylinderSector(CompositeSurface): @@ -96,8 +81,8 @@ class CylinderSector(CompositeSurface): counterclockwise direction with respect to the first basis axis (+y, +z, or +x). Must be greater than :attr:`theta1`. center : iterable of float - Coordinate for central axes of cylinders in the (y, z), (x, z), or (x, y) - basis. Defaults to (0,0). + Coordinate for central axes of cylinders in the (y, z), (z, x), or (x, y) + basis. Defaults to (0,0). axis : {'x', 'y', 'z'} Central axis of the cylinders defining the inner and outer surfaces of the sector. Defaults to 'z'. @@ -125,32 +110,27 @@ class CylinderSector(CompositeSurface): r2, theta1, theta2, - center=(0., 0.), + center=(0.,0.), axis='z', **kwargs): if r2 <= r1: - raise ValueError('r2 must be greater than r1.') + raise ValueError(f'r2 must be greater than r1.') if theta2 <= theta1: - raise ValueError('theta2 must be greater than theta1.') - - # Determine whether the angle between theta1 and theta2 is a reflex - # angle, in which case we need to use a union between the planar - # half-spaces - self._reflex = (theta2 - theta1 > 180.0) + raise ValueError(f'theta2 must be greater than theta1.') phi1 = pi / 180 * theta1 phi2 = pi / 180 * theta2 # Coords for axis-perpendicular planes - p1 = np.array([center[0], center[1], 1.]) + p1 = np.array([0., 0., 1.]) - p2_plane1 = np.array([r1 * cos(phi1) + center[0], r1 * sin(phi1) + center[1], 0.]) - p3_plane1 = np.array([r2 * cos(phi1) + center[0], r2 * sin(phi1) + center[1], 0.]) + p2_plane1 = np.array([r1 * cos(phi1), r1 * sin(phi1), 0.]) + p3_plane1 = np.array([r2 * cos(phi1), r2 * sin(phi1), 0.]) - p2_plane2 = np.array([r1 * cos(phi2) + center[0], r1 * sin(phi2)+ center[1], 0.]) - p3_plane2 = np.array([r2 * cos(phi2) + center[0], r2 * sin(phi2)+ center[1], 0.]) + p2_plane2 = np.array([r1 * cos(phi2), r1 * sin(phi2), 0.]) + p3_plane2 = np.array([r2 * cos(phi2), r2 * sin(phi2), 0.]) points = [p1, p2_plane1, p3_plane1, p2_plane2, p3_plane2] if axis == 'z': @@ -158,7 +138,7 @@ class CylinderSector(CompositeSurface): self.inner_cyl = openmc.ZCylinder(*center, r1, **kwargs) self.outer_cyl = openmc.ZCylinder(*center, r2, **kwargs) elif axis == 'y': - coord_map = [0, 2, 1] + coord_map = [1, 2, 0] self.inner_cyl = openmc.YCylinder(*center, r1, **kwargs) self.outer_cyl = openmc.YCylinder(*center, r2, **kwargs) elif axis == 'x': @@ -166,7 +146,6 @@ class CylinderSector(CompositeSurface): self.inner_cyl = openmc.XCylinder(*center, r1, **kwargs) self.outer_cyl = openmc.XCylinder(*center, r2, **kwargs) - # Reorder the points to correspond to the correct central axis for p in points: p[:] = p[coord_map] @@ -174,9 +153,6 @@ class CylinderSector(CompositeSurface): **kwargs) self.plane2 = openmc.Plane.from_points(p1, p2_plane2, p3_plane2, **kwargs) - if axis == 'y': - self.plane1.flip_normal() - self.plane2.flip_normal() @classmethod def from_theta_alpha(cls, @@ -207,8 +183,8 @@ class CylinderSector(CompositeSurface): with respect to the first basis axis (+y, +z, or +x). Note that negative values translate to an offset in the clockwise direction. center : iterable of float - Coordinate for central axes of cylinders in the (y, z), (x, z), or - (x, y) basis. Defaults to (0,0). + Coordinate for central axes of cylinders in the (y, z), (z, x), or (x, y) + basis. Defaults to (0,0). axis : {'x', 'y', 'z'} Central axis of the cylinders defining the inner and outer surfaces of the sector. Defaults to 'z'. @@ -223,7 +199,7 @@ class CylinderSector(CompositeSurface): offset. """ if theta >= 360. or theta <= 0: - raise ValueError('theta must be less than 360 and greater than 0.') + raise ValueError(f'theta must be less than 360 and greater than 0.') theta1 = alpha theta2 = alpha + theta @@ -231,17 +207,17 @@ class CylinderSector(CompositeSurface): return cls(r1, r2, theta1, theta2, center=center, axis=axis, **kwargs) def __neg__(self): - if self._reflex: - return -self.outer_cyl & +self.inner_cyl & (-self.plane1 | +self.plane2) - else: - return -self.outer_cyl & +self.inner_cyl & -self.plane1 & +self.plane2 + return -self.outer_cyl & +self.inner_cyl & -self.plane1 & +self.plane2 + + def __pos__(self): + return +self.outer_cyl | -self.inner_cyl | +self.plane1 | -self.plane2 class IsogonalOctagon(CompositeSurface): r"""Infinite isogonal octagon composite surface An isogonal octagon is composed of eight planar surfaces. The prism is - parallel to the x, y, or z axis. The remaining two axes (y and z, x and z, + parallel to the x, y, or z axis. The remaining two axes (y and z, z and x, or x and y) serve as a basis for constructing the surfaces. Two surfaces are parallel to the first basis axis, two surfaces are parallel to the second basis axis, and the remaining four surfaces intersect both @@ -249,7 +225,7 @@ class IsogonalOctagon(CompositeSurface): This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is - defined to be the region inside of the octagonal prism. + defined to be the region inside of the octogonal prism. .. versionadded:: 0.13.1 @@ -257,7 +233,7 @@ class IsogonalOctagon(CompositeSurface): ---------- center : iterable of float Coordinate for the central axis of the octagon in the - (y, z), (x, z), or (x, y) basis depending on the axis parameter. + (y, z), (z, x), or (x, y) basis. r1 : float Half-width of octagon across its basis axis-parallel sides in units of cm. Must be less than :math:`r_2\sqrt{2}`. @@ -298,24 +274,24 @@ class IsogonalOctagon(CompositeSurface): def __init__(self, center, r1, r2, axis='z', **kwargs): c1, c2 = center - # Coordinates for axis-perpendicular planes - cright = c1 + r1 - cleft = c1 - r1 + # Coords for axis-perpendicular planes + ctop = c1 + r1 + cbottom = c1 - r1 - ctop = c2 + r1 - cbottom = c2 - r1 + cright = c2 + r1 + cleft = c2 - r1 # Side lengths if r2 > r1 * sqrt(2): - raise ValueError('r2 is greater than sqrt(2) * r1. Octagon' + + raise ValueError(f'r2 is greater than sqrt(2) * r1. Octagon' + ' may be erroneous.') if r1 > r2 * sqrt(2): - raise ValueError('r1 is greater than sqrt(2) * r2. Octagon' + + raise ValueError(f'r1 is greater than sqrt(2) * r2. Octagon' + ' may be erroneous.') L_basis_ax = (r2 * sqrt(2) - r1) - # Coordinates for quadrant planes + # Coords for quadrant planes p1_ur = np.array([L_basis_ax, r1, 0.]) p2_ur = np.array([r1, L_basis_ax, 0.]) p3_ur = np.array([r1, L_basis_ax, 1.]) @@ -324,16 +300,7 @@ class IsogonalOctagon(CompositeSurface): p2_lr = np.array([L_basis_ax, -r1, 0.]) p3_lr = np.array([L_basis_ax, -r1, 1.]) - p1_ll = -p1_ur - p2_ll = -p2_ur - p3_ll = -p3_ur - - p1_ul = -p1_lr - p2_ul = -p2_lr - p3_ul = -p3_lr - - points = [p1_ur, p2_ur, p3_ur, p1_lr, p2_lr, p3_lr, - p1_ll, p2_ll, p3_ll, p1_ul, p2_ul, p3_ul] + points = [p1_ur, p2_ur, p3_ur, p1_lr, p2_lr, p3_lr] # Orientation specific variables if axis == 'z': @@ -343,56 +310,40 @@ class IsogonalOctagon(CompositeSurface): self.right = openmc.XPlane(cright, **kwargs) self.left = openmc.XPlane(cleft, **kwargs) elif axis == 'y': - coord_map = [0, 2, 1] - self.top = openmc.ZPlane(ctop, **kwargs) - self.bottom = openmc.ZPlane(cbottom, **kwargs) - self.right = openmc.XPlane(cright, **kwargs) - self.left = openmc.XPlane(cleft, **kwargs) + coord_map = [1, 2, 0] + self.top = openmc.XPlane(ctop, **kwargs) + self.bottom = openmc.XPlane(cbottom, **kwargs) + self.right = openmc.ZPlane(cright, **kwargs) + self.left = openmc.ZPlane(cleft, **kwargs) elif axis == 'x': coord_map = [2, 0, 1] self.top = openmc.ZPlane(ctop, **kwargs) self.bottom = openmc.ZPlane(cbottom, **kwargs) self.right = openmc.YPlane(cright, **kwargs) self.left = openmc.YPlane(cleft, **kwargs) - self.axis = axis - # Put our coordinates in (x,y,z) order and add the offset + # Put our coordinates in (x,y,z) order for p in points: - p[0] += c1 - p[1] += c2 p[:] = p[coord_map] self.upper_right = openmc.Plane.from_points(p1_ur, p2_ur, p3_ur, **kwargs) self.lower_right = openmc.Plane.from_points(p1_lr, p2_lr, p3_lr, **kwargs) - self.lower_left = openmc.Plane.from_points(p1_ll, p2_ll, p3_ll, + self.lower_left = openmc.Plane.from_points(-p1_ur, -p2_ur, -p3_ur, **kwargs) - self.upper_left = openmc.Plane.from_points(p1_ul, p2_ul, p3_ul, + self.upper_left = openmc.Plane.from_points(-p1_lr, -p2_lr, -p3_lr, **kwargs) def __neg__(self): - if self.axis == 'y': - region = -self.top & +self.bottom & -self.right & +self.left & \ - -self.upper_right & -self.lower_right & +self.lower_left & \ - +self.upper_left - else: - region = -self.top & +self.bottom & -self.right & +self.left & \ - +self.upper_right & +self.lower_right & -self.lower_left & \ - -self.upper_left - - return region + return -self.top & +self.bottom & -self.right & +self.left & \ + +self.upper_right & +self.lower_right & -self.lower_left & \ + -self.upper_left def __pos__(self): - if self.axis == 'y': - region = +self.top | -self.bottom | +self.right | -self.left | \ - +self.upper_right | +self.lower_right | -self.lower_left | \ - -self.upper_left - else: - region = +self.top | -self.bottom | +self.right | -self.left | \ - -self.upper_right | -self.lower_right | +self.lower_left | \ - +self.upper_left - return region + return +self.top | -self.bottom | +self.right | -self.left | \ + -self.upper_right | -self.lower_right | +self.lower_left | \ + +self.upper_left class RightCircularCylinder(CompositeSurface): @@ -416,10 +367,6 @@ class RightCircularCylinder(CompositeSurface): Radius of the cylinder axis : {'x', 'y', 'z'} Axis of the cylinder - upper_fillet_radius : float - Upper edge fillet radius in [cm]. - lower_fillet_radius : float - Lower edge fillet radius in [cm]. **kwargs Keyword arguments passed to underlying cylinder and plane classes @@ -431,173 +378,33 @@ class RightCircularCylinder(CompositeSurface): Bottom planar surface of the cylinder top : openmc.Plane Top planar surface of the cylinder - upper_fillet_torus : openmc.Torus - Surface that creates the filleted edge for the upper end of the - cylinder. Only present if :attr:`upper_fillet_radius` is set. - upper_fillet_cylinder : openmc.Cylinder - Surface that bounds :attr:`upper_fillet_torus` radially. Only present - if :attr:`upper_fillet_radius` is set. - upper_fillet_plane : openmc.Plane - Surface that bounds :attr:`upper_fillet_torus` axially. Only present if - :attr:`upper_fillet_radius` is set. - lower_fillet_torus : openmc.Torus - Surface that creates the filleted edge for the lower end of the - cylinder. Only present if :attr:`lower_fillet_radius` is set. - lower_fillet_cylinder : openmc.Cylinder - Surface that bounds :attr:`lower_fillet_torus` radially. Only present - if :attr:`lower_fillet_radius` is set. - lower_fillet_plane : openmc.Plane - Surface that bounds :attr:`lower_fillet_torus` axially. Only present if - :attr:`lower_fillet_radius` is set. """ _surface_names = ('cyl', 'bottom', 'top') - def __init__(self, center_base, height, radius, axis='z', - upper_fillet_radius=0., lower_fillet_radius=0., **kwargs): + def __init__(self, center_base, height, radius, axis='z', **kwargs): cx, cy, cz = center_base check_greater_than('cylinder height', height, 0.0) check_greater_than('cylinder radius', radius, 0.0) check_value('cylinder axis', axis, ('x', 'y', 'z')) - check_type('upper_fillet_radius', upper_fillet_radius, float) - check_less_than('upper_fillet_radius', upper_fillet_radius, - radius, equality=True) - check_type('lower_fillet_radius', lower_fillet_radius, float) - check_less_than('lower_fillet_radius', lower_fillet_radius, - radius, equality=True) - if axis == 'x': self.cyl = openmc.XCylinder(y0=cy, z0=cz, r=radius, **kwargs) self.bottom = openmc.XPlane(x0=cx, **kwargs) self.top = openmc.XPlane(x0=cx + height, **kwargs) - x1, x2 = 'y', 'z' - axcoord, axcoord1, axcoord2 = 0, 1, 2 elif axis == 'y': self.cyl = openmc.YCylinder(x0=cx, z0=cz, r=radius, **kwargs) self.bottom = openmc.YPlane(y0=cy, **kwargs) self.top = openmc.YPlane(y0=cy + height, **kwargs) - x1, x2 = 'x', 'z' - axcoord, axcoord1, axcoord2 = 1, 0, 2 elif axis == 'z': self.cyl = openmc.ZCylinder(x0=cx, y0=cy, r=radius, **kwargs) self.bottom = openmc.ZPlane(z0=cz, **kwargs) self.top = openmc.ZPlane(z0=cz + height, **kwargs) - x1, x2 = 'x', 'y' - axcoord, axcoord1, axcoord2 = 2, 0, 1 - - def _create_fillet_objects(axis_args, height, center_base, radius, fillet_radius, pos='upper'): - axis, x1, x2, axcoord, axcoord1, axcoord2 = axis_args - fillet_ext = height / 2 - fillet_radius - sign = 1 - if pos == 'lower': - sign = -1 - coord = center_base[axcoord] + (height / 2) + sign * fillet_ext - - # cylinder - cyl_name = f'{pos}_min' - cylinder_args = { - x1 + '0': center_base[axcoord1], - x2 + '0': center_base[axcoord2], - 'r': radius - fillet_radius - } - cls = getattr(openmc, f'{axis.upper()}Cylinder') - cyl = cls(name=f'{cyl_name} {axis}', **cylinder_args) - - #torus - tor_name = f'{axis} {pos}' - tor_args = { - 'a': radius - fillet_radius, - 'b': fillet_radius, - 'c': fillet_radius, - x1 + '0': center_base[axcoord1], - x2 + '0': center_base[axcoord2], - axis + '0': coord - } - cls = getattr(openmc, f'{axis.upper()}Torus') - torus = cls(name=tor_name, **tor_args) - - # plane - p_name = f'{pos} ext' - p_args = {axis + '0': coord} - cls = getattr(openmc, f'{axis.upper()}Plane') - plane = cls(name=p_name, **p_args) - - return cyl, torus, plane - - if upper_fillet_radius > 0. or lower_fillet_radius > 0.: - if 'boundary_type' in kwargs: - if kwargs['boundary_type'] == 'periodic': - raise ValueError('Periodic boundary conditions not permitted when ' - 'rounded corners are used.') - - axis_args = (axis, x1, x2, axcoord, axcoord1, axcoord2) - if upper_fillet_radius > 0.: - cylinder, torus, plane = _create_fillet_objects( - axis_args, height, center_base, radius, upper_fillet_radius) - self.upper_fillet_cylinder = cylinder - self.upper_fillet_torus = torus - self.upper_fillet_plane = plane - self._surface_names += ('upper_fillet_cylinder', - 'upper_fillet_torus', - 'upper_fillet_plane') - - if lower_fillet_radius > 0.: - cylinder, torus, plane = _create_fillet_objects( - axis_args, height, center_base, radius, lower_fillet_radius, - pos='lower' - ) - self.lower_fillet_cylinder = cylinder - self.lower_fillet_torus = torus - self.lower_fillet_plane = plane - - self._surface_names += ('lower_fillet_cylinder', - 'lower_fillet_torus', - 'lower_fillet_plane') - - def _get_fillet(self): - upper_fillet = self._get_upper_fillet() - lower_fillet = self._get_lower_fillet() - has_upper_fillet = upper_fillet is not None - has_lower_fillet = lower_fillet is not None - if has_lower_fillet and has_upper_fillet: - fillet = lower_fillet | upper_fillet - elif has_upper_fillet and not has_lower_fillet: - fillet = upper_fillet - elif not has_upper_fillet and has_lower_fillet: - fillet = lower_fillet - else: - fillet = None - return fillet - - def _get_upper_fillet(self): - has_upper_fillet = hasattr(self, 'upper_fillet_plane') - if has_upper_fillet: - upper_fillet = +self.upper_fillet_cylinder & +self.upper_fillet_torus & +self.upper_fillet_plane - else: - upper_fillet = None - return upper_fillet - - def _get_lower_fillet(self): - has_lower_fillet = hasattr(self, 'lower_fillet_plane') - if has_lower_fillet: - lower_fillet = +self.lower_fillet_cylinder & +self.lower_fillet_torus & -self.lower_fillet_plane - else: - lower_fillet = None - return lower_fillet def __neg__(self): - prism = -self.cyl & +self.bottom & -self.top - fillet = self._get_fillet() - if fillet is not None: - prism = prism & ~fillet - return prism + return -self.cyl & +self.bottom & -self.top def __pos__(self): - prism = +self.cyl | -self.bottom | +self.top - fillet = self._get_fillet() - if fillet is not None: - prism = prism | fillet - return prism + return +self.cyl | -self.bottom | +self.top class RectangularParallelepiped(CompositeSurface): @@ -654,90 +461,10 @@ class RectangularParallelepiped(CompositeSurface): return +self.xmax | -self.xmin | +self.ymax | -self.ymin | +self.zmax | -self.zmin -class OrthogonalBox(CompositeSurface): - """Arbitrarily oriented orthogonal box - - This composite surface is composed of four or six planar surfaces that form - an arbitrarily oriented orthogonal box when combined. - - Parameters - ---------- - v : iterable of float - (x,y,z) coordinates of a corner of the box - a1 : iterable of float - Vector of first side starting from ``v`` - a2 : iterable of float - Vector of second side starting from ``v`` - a3 : iterable of float, optional - Vector of third side starting from ``v``. When not specified, it is - assumed that the box will be infinite along the vector normal to the - plane specified by ``a1`` and ``a2``. - **kwargs - Keyword arguments passed to underlying plane classes - - Attributes - ---------- - ax1_min, ax1_max : openmc.Plane - Planes representing minimum and maximum along first axis - ax2_min, ax2_max : openmc.Plane - Planes representing minimum and maximum along second axis - ax3_min, ax3_max : openmc.Plane - Planes representing minimum and maximum along third axis - - """ - _surface_names = ('ax1_min', 'ax1_max', 'ax2_min', 'ax2_max', 'ax3_min', 'ax3_max') - - def __init__(self, v, a1, a2, a3=None, **kwargs): - v = np.array(v) - a1 = np.array(a1) - a2 = np.array(a2) - if has_a3 := a3 is not None: - a3 = np.array(a3) - else: - a3 = np.cross(a1, a2) # normal to plane specified by a1 and a2 - - # Generate corners of box - p1 = v - p2 = v + a1 - p3 = v + a2 - p4 = v + a3 - p5 = v + a1 + a2 - p6 = v + a2 + a3 - p7 = v + a1 + a3 - - # Generate 6 planes of box - self.ax1_min = openmc.Plane.from_points(p1, p3, p4, **kwargs) - self.ax1_max = openmc.Plane.from_points(p2, p5, p7, **kwargs) - self.ax2_min = openmc.Plane.from_points(p1, p4, p2, **kwargs) - self.ax2_max = openmc.Plane.from_points(p3, p6, p5, **kwargs) - if has_a3: - self.ax3_min = openmc.Plane.from_points(p1, p2, p3, **kwargs) - self.ax3_max = openmc.Plane.from_points(p4, p7, p6, **kwargs) - - # Make sure a point inside the box produces the correct senses. If not, - # flip the plane coefficients so it does. - mid_point = v + (a1 + a2 + a3)/2 - nums = (1, 2, 3) if has_a3 else (1, 2) - for num in nums: - min_surf = getattr(self, f'ax{num}_min') - max_surf = getattr(self, f'ax{num}_max') - if mid_point in -min_surf: - min_surf.flip_normal() - if mid_point in +max_surf: - max_surf.flip_normal() - - def __neg__(self): - region = (+self.ax1_min & -self.ax1_max & - +self.ax2_min & -self.ax2_max) - if hasattr(self, 'ax3_min'): - region &= (+self.ax3_min & -self.ax3_max) - return region - - class XConeOneSided(CompositeSurface): - r"""One-sided cone parallel the x-axis + """One-sided cone parallel the x-axis - A one-sided cone is composed of a normal cone surface and a "disambiguation" + A one-sided cone is composed of a normal cone surface and an "ambiguity" surface that eliminates the ambiguity as to which region of space is included. This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is @@ -748,16 +475,13 @@ class XConeOneSided(CompositeSurface): Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. + Parameter related to the aperature. Defaults to 1. up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -770,7 +494,7 @@ class XConeOneSided(CompositeSurface): cone : openmc.XCone Regular two-sided cone plane : openmc.XPlane - Disambiguation surface + Ambiguity surface up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -788,11 +512,17 @@ class XConeOneSided(CompositeSurface): def __neg__(self): return -self.cone & (+self.plane if self.up else -self.plane) + def __pos__(self): + if self.up: + return (+self.cone & +self.plane) | -self.plane + else: + return (+self.cone & -self.plane) | +self.plane + class YConeOneSided(CompositeSurface): - r"""One-sided cone parallel the y-axis + """One-sided cone parallel the y-axis - A one-sided cone is composed of a normal cone surface and a "disambiguation" + A one-sided cone is composed of a normal cone surface and an "ambiguity" surface that eliminates the ambiguity as to which region of space is included. This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is @@ -803,16 +533,13 @@ class YConeOneSided(CompositeSurface): Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. + Parameter related to the aperature. Defaults to 1. up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -825,7 +552,7 @@ class YConeOneSided(CompositeSurface): cone : openmc.YCone Regular two-sided cone plane : openmc.YPlane - Disambiguation surface + Ambiguity surface up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -841,12 +568,13 @@ class YConeOneSided(CompositeSurface): self.up = up __neg__ = XConeOneSided.__neg__ + __pos__ = XConeOneSided.__pos__ class ZConeOneSided(CompositeSurface): - r"""One-sided cone parallel the z-axis + """One-sided cone parallel the z-axis - A one-sided cone is composed of a normal cone surface and a "disambiguation" + A one-sided cone is composed of a normal cone surface and an "ambiguity" surface that eliminates the ambiguity as to which region of space is included. This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is @@ -857,16 +585,13 @@ class ZConeOneSided(CompositeSurface): Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. + Parameter related to the aperature. Defaults to 1. up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -879,7 +604,7 @@ class ZConeOneSided(CompositeSurface): cone : openmc.ZCone Regular two-sided cone plane : openmc.ZPlane - Disambiguation surface + Ambiguity surface up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -895,1068 +620,4 @@ class ZConeOneSided(CompositeSurface): self.up = up __neg__ = XConeOneSided.__neg__ - - -class Polygon(CompositeSurface): - """Polygon formed from a path of closed points. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - points : np.ndarray - An Nx2 array of points defining the vertices of the polygon. - basis : {'rz', 'xy', 'yz', 'xz'}, optional - 2D basis set for the polygon. The polygon is two dimensional and has - infinite extent in the third (unspecified) dimension. For example, the - 'xy' basis produces a polygon with infinite extent in the +/- z - direction. For the 'rz' basis the phi extent is infinite, thus forming - an axisymmetric surface. - - Attributes - ---------- - points : np.ndarray - An Nx2 array of points defining the vertices of the polygon. - basis : {'rz', 'xy', 'yz', 'xz'} - 2D basis set for the polygon. - regions : list of openmc.Region - A list of :class:`openmc.Region` objects, one for each of the convex polygons - formed during the decomposition of the input polygon. - region : openmc.Union - The union of all the regions comprising the polygon. - """ - - def __init__(self, points, basis='rz'): - check_value('basis', basis, ('xy', 'yz', 'xz', 'rz')) - self._basis = basis - - # Create a constrained triangulation of the validated points. - # The constrained triangulation is set to the _tri attribute - self._constrain_triangulation(self._validate_points(points)) - - # Decompose the polygon into groups of simplices forming convex subsets - # and get the sets of (surface, operator) pairs defining the polygon - self._surfsets = self._decompose_polygon_into_convex_sets() - - # Set surface names as required by CompositeSurface protocol - surfnames = [] - i = 0 - for surfset in self._surfsets: - for surf, op, on_boundary in surfset: - if on_boundary: - setattr(self, f'surface_{i}', surf) - surfnames.append(f'surface_{i}') - i += 1 - self._surfnames = tuple(surfnames) - - # Generate a list of regions whose union represents the polygon. - regions = [] - for surfs_ops in self._surfsets: - regions.append([op(surf) for surf, op, _ in surfs_ops]) - self._regions = [openmc.Intersection(regs) for regs in regions] - - # Create the union of all the convex subsets - self._region = openmc.Union(self._regions) - - def __neg__(self): - return self._region - - @property - def _surface_names(self): - return self._surfnames - - @CompositeSurface.boundary_type.setter - def boundary_type(self, boundary_type): - if boundary_type != 'transmission': - warnings.warn("Setting boundary_type to a value other than " - "'transmission' on Polygon composite surfaces can " - "result in unintended behavior. Please use the " - "regions property of the Polygon to generate " - "individual openmc.Cell objects to avoid unwanted " - "behavior.") - for name in self._surface_names: - getattr(self, name).boundary_type = boundary_type - - @property - def points(self): - return self._tri.points - - @property - def basis(self): - return self._basis - - @property - def _normals(self): - """Generate the outward normal unit vectors for the polygon.""" - # Rotation matrix for 90 degree clockwise rotation (-90 degrees about z - # axis for an 'xy' basis). - rotation = np.array([[0., 1.], [-1., 0.]]) - # Get the unit vectors that point from one point in the polygon to the - # next given that they are ordered counterclockwise and that the final - # point is connected to the first point - tangents = np.diff(self.points, axis=0, append=[self.points[0, :]]) - tangents /= np.linalg.norm(tangents, axis=-1, keepdims=True) - # Rotate the tangent vectors clockwise by 90 degrees, which for a - # counter-clockwise ordered polygon will produce the outward normal - # vectors. - return rotation.dot(tangents.T).T - - @property - def _equations(self): - normals = self._normals - equations = np.empty((normals.shape[0], 3)) - equations[:, :2] = normals - equations[:, 2] = -np.sum(normals*self.points, axis=-1) - return equations - - @property - def regions(self): - return self._regions - - @property - def region(self): - return self._region - - def _validate_points(self, points): - """Ensure the closed path defined by points does not intersect and is - oriented counter-clockwise. - - Parameters - ---------- - points : np.ndarray (Nx2) - An Nx2 array of coordinate pairs describing the vertices. - - Returns - ------- - ordered_points : the input points ordered counter-clockwise - """ - points = np.asarray(points, dtype=float) - check_iterable_type('points', points, float, min_depth=2, max_depth=2) - check_length('points', points[0, :], 2, 2) - - # If the last point is the same as the first, remove it and make sure - # there are still at least 3 points for a valid polygon. - if np.allclose(points[0, :], points[-1, :]): - points = points[:-1, :] - check_length('points', points, 3) - - if len(points) != len(np.unique(points, axis=0)): - raise ValueError('Duplicate points were detected in the Polygon input') - - # Order the points counter-clockwise (necessary for offset method) - # Calculates twice the signed area of the polygon using the "Shoelace - # Formula" https://en.wikipedia.org/wiki/Shoelace_formula - # If signed area is positive the curve is oriented counter-clockwise. - # If the signed area is negative the curve is oriented clockwise. - xpts, ypts = points.T - if np.sum(ypts*(np.roll(xpts, 1) - np.roll(xpts, -1))) < 0: - points = points[::-1, :] - - # Check if polygon is self-intersecting by comparing edges pairwise - n = len(points) - for i in range(n): - p0 = np.append(points[i, :], 0) - p1 = np.append(points[(i + 1) % n, :], 0) - for j in range(i + 1, n): - p2 = np.append(points[j, :], 0) - p3 = np.append(points[(j + 1) % n, :], 0) - # Compute orientation of p0 wrt p2->p3 line segment - cp0 = np.cross(p3-p0, p2-p0)[-1] - # Compute orientation of p1 wrt p2->p3 line segment - cp1 = np.cross(p3-p1, p2-p1)[-1] - # Compute orientation of p2 wrt p0->p1 line segment - cp2 = np.cross(p1-p2, p0-p2)[-1] - # Compute orientation of p3 wrt p0->p1 line segment - cp3 = np.cross(p1-p3, p0-p3)[-1] - - # Group cross products in an array and find out how many are 0 - cross_products = np.array([[cp0, cp1], [cp2, cp3]]) - cps_near_zero = np.isclose(cross_products, 0).astype(int) - num_zeros = np.sum(cps_near_zero) - - # Topologies of 2 finite line segments categorized by the number - # of zero-valued cross products: - # - # 0: No 3 points lie on the same line - # 1: 1 point lies on the same line defined by the other line - # segment, but is not coincident with either of the points - # 2: 2 points are coincident, but the line segments are not - # collinear which guarantees no intersection - # 3: not possible, except maybe floating point issues? - # 4: Both line segments are collinear, simply need to check if - # they overlap or not - # adapted from algorithm linked below and modified to only - # consider intersections on the interior of line segments as - # proper intersections: i.e. segments sharing end points do not - # count as intersections. - # https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ - - if num_zeros == 0: - # If the orientations of p0 and p1 have opposite signs - # and the orientations of p2 and p3 have opposite signs - # then there is an intersection. - if all(np.prod(cross_products, axis=-1) < 0): - raise ValueError('Polygon cannot be self-intersecting') - continue - - elif num_zeros == 1: - # determine which line segment has 2 out of the 3 collinear - # points - idx = np.argwhere(np.sum(cps_near_zero, axis=-1) == 0) - if np.prod(cross_products[idx, :]) < 0: - raise ValueError('Polygon cannot be self-intersecting') - continue - - elif num_zeros == 2: - continue - - elif num_zeros == 3: - warnings.warn('Unclear if Polygon is self-intersecting') - continue - - else: - # All 4 cross products are zero - # Determine number of unique points, x span and y span for - # both line segments - xmin1, xmax1 = min(p0[0], p1[0]), max(p0[0], p1[0]) - ymin1, ymax1 = min(p0[1], p1[1]), max(p0[1], p1[1]) - xmin2, xmax2 = min(p2[0], p3[0]), max(p2[0], p3[0]) - ymin2, ymax2 = min(p2[1], p3[1]), max(p2[1], p3[1]) - xlap = xmin1 < xmax2 and xmin2 < xmax1 - ylap = ymin1 < ymax2 and ymin2 < ymax1 - if xlap or ylap: - raise ValueError('Polygon cannot be self-intersecting') - continue - - return points - - def _constrain_triangulation(self, points, depth=0): - """Generate a constrained triangulation by ensuring all edges of the - Polygon are contained within the simplices. - - Parameters - ---------- - points : np.ndarray (Nx2) - An Nx2 array of coordinate pairs describing the vertices. These - points represent a planar straight line graph. - - Returns - ------- - None - """ - # Only attempt the triangulation up to 5 times. - if depth > 4: - raise RuntimeError('Could not create a valid triangulation after 5' - ' attempts') - - tri = Delaunay(points, qhull_options='QJ') - # Loop through the boundary edges of the polygon. If an edge is not - # included in the triangulation, break it into two line segments. - n = len(points) - new_pts = [] - for i, j in zip(range(n), range(1, n + 1)): - # If both vertices of any edge are not found in any simplex, insert - # a new point between them. - if not any([i in s and j % n in s for s in tri.simplices]): - newpt = (points[i, :] + points[j % n, :]) / 2 - new_pts.append((j, newpt)) - - # If all the edges are included in the triangulation set it, otherwise - # try again with additional points inserted on offending edges. - if not new_pts: - self._tri = tri - else: - for i, pt in new_pts[::-1]: - points = np.insert(points, i, pt, axis=0) - self._constrain_triangulation(points, depth=depth + 1) - - def _group_simplices(self, neighbor_map, group=None): - """Generate a convex grouping of simplices. - - Parameters - ---------- - neighbor_map : dict - A map whose keys are simplex indices for simplices inside the polygon - and whose values are a list of simplex indices that neighbor this - simplex and are also inside the polygon. - group : list - A list of simplex indices that comprise the current convex group. - - Returns - ------- - group : list - The list of simplex indices that comprise the complete convex group. - """ - # If neighbor_map is empty there's nothing left to do - if not neighbor_map: - return group - # If group is empty, grab the next simplex in the dictionary and recurse - if group is None: - # Start with smallest neighbor lists - sidx = sorted(neighbor_map.items(), key=lambda item: len(item[1]))[0][0] - return self._group_simplices(neighbor_map, group=[sidx]) - # Otherwise use the last simplex in the group - else: - sidx = group[-1] - # Remove current simplex from dictionary since it is in a group - neighbors = neighbor_map.pop(sidx, []) - # For each neighbor check if it is part of the same convex - # hull as the rest of the group. If yes, recurse. If no, continue on. - for n in neighbors: - if n in group or neighbor_map.get(n) is None: - continue - test_group = group + [n] - test_point_idx = np.unique(self._tri.simplices[test_group, :]) - test_points = self.points[test_point_idx] - test_hull = ConvexHull(test_points, qhull_options='Qc') - pts_on_hull = len(test_hull.vertices) + len(test_hull.coplanar) - # If test_points are convex (including coplanar) keep adding to - # this group - if len(test_points) == pts_on_hull: - group = self._group_simplices(neighbor_map, group=test_group) - return group - - def _get_convex_hull_surfs(self, qhull): - """Generate a list of surfaces given by a set of linear equations - - Parameters - ---------- - qhull : scipy.spatial.ConvexHull - A ConvexHull object representing the sub-region of the polygon. - - Returns - ------- - surfs_ops : list of (surface, operator) tuples - - """ - basis = self.basis - boundary_eqns = self._equations - # Collect surface/operator pairs such that the intersection of the - # regions defined by these pairs is the inside of the polygon. - surfs_ops = [] - # hull facet equation: dx*x + dy*y + c = 0 - for dx, dy, c in qhull.equations: - # check if this facet is on the boundary of the polygon - facet_eq = np.array([dx, dy, c]) - on_boundary = any([np.allclose(facet_eq, eq) for eq in boundary_eqns]) - # Check if the facet is horizontal - if isclose(dx, 0, abs_tol=1e-8): - if basis in ('xz', 'yz', 'rz'): - surf = openmc.ZPlane(z0=-c/dy) - else: - surf = openmc.YPlane(y0=-c/dy) - # if (0, 1).(dx, dy) < 0 we want positive halfspace instead - op = operator.pos if dy < 0 else operator.neg - # Check if the facet is vertical - elif isclose(dy, 0, abs_tol=1e-8): - if basis in ('xy', 'xz'): - surf = openmc.XPlane(x0=-c/dx) - elif basis == 'yz': - surf = openmc.YPlane(y0=-c/dx) - else: - surf = openmc.ZCylinder(r=-c/dx) - # if (1, 0).(dx, dy) < 0 we want positive halfspace instead - op = operator.pos if dx < 0 else operator.neg - # Otherwise the facet is at an angle - else: - op = operator.neg - if basis == 'xy': - surf = openmc.Plane(a=dx, b=dy, c=0.0, d=-c) - elif basis == 'yz': - surf = openmc.Plane(a=0.0, b=dx, c=dy, d=-c) - elif basis == 'xz': - surf = openmc.Plane(a=dx, b=0.0, c=dy, d=-c) - else: - y0 = -c/dy - r2 = dy**2 / dx**2 - # Check if the *slope* of the facet is positive. If dy/dx < 0 - # then we want up to be True for the one-sided cones. - up = dy / dx < 0 - surf = openmc.model.ZConeOneSided(z0=y0, r2=r2, up=up) - # if (1, -1).(dx, dy) < 0 for up cones we want positive halfspace - # if (1, 1).(dx, dy) < 0 for down cones we want positive halfspace - # otherwise we keep the negative halfspace operator - if (up and dx - dy < 0) or (not up and dx + dy < 0): - op = operator.pos - - surfs_ops.append((surf, op, on_boundary)) - - return surfs_ops - - def _decompose_polygon_into_convex_sets(self): - """Decompose the Polygon into a set of convex polygons. - - Returns - ------- - surfsets : a list of lists of surface, operator pairs - """ - from matplotlib.path import Path - - # Get centroids of all the simplices and determine if they are inside - # the polygon defined by input vertices or not. - centroids = np.mean(self.points[self._tri.simplices], axis=1) - in_polygon = Path(self.points).contains_points(centroids) - self._in_polygon = in_polygon - - # Build a map with keys of simplex indices inside the polygon whose - # values are lists of that simplex's neighbors also inside the - # polygon - neighbor_map = {} - for i, nlist in enumerate(self._tri.neighbors): - if not in_polygon[i]: - continue - neighbor_map[i] = [n for n in nlist if in_polygon[n] and n >=0] - - # Get the groups of simplices forming convex polygons whose union - # comprises the full input polygon. While there are still simplices - # left in the neighbor map, group them together into convex sets. - groups = [] - while neighbor_map: - groups.append(self._group_simplices(neighbor_map)) - self._groups = groups - - # Generate lists of (surface, operator) pairs for each convex - # sub-region. - surfsets = [] - for group in groups: - # Find all the unique points in the convex group of simplices, - # generate the convex hull and find the resulting surfaces and - # unary operators that represent this convex subset of the polygon. - idx = np.unique(self._tri.simplices[group, :]) - qhull = ConvexHull(self.points[idx, :]) - surf_ops = self._get_convex_hull_surfs(qhull) - surfsets.append(surf_ops) - return surfsets - - def offset(self, distance: float | Sequence[float] | np.ndarray) -> Polygon: - """Offset this polygon by a set distance - - Parameters - ---------- - distance : float or sequence of float or np.ndarray - The distance to offset the polygon by. Positive is outward - (expanding) and negative is inward (shrinking). If a float is - provided, the same offset is applied to all vertices. If a list or - tuple is provided, each vertex gets a different offset. If an - iterable or numpy array is provided, each vertex gets a different - offset. - - Returns - ------- - offset_polygon : openmc.model.Polygon - """ - - if isinstance(distance, float): - distance = np.full(len(self.points), distance) - elif isinstance(distance, Sequence): - distance = np.array(distance) - elif not isinstance(distance, np.ndarray): - raise TypeError("Distance must be a float or sequence of float.") - - if len(distance) != len(self.points): - raise ValueError( - f"Length of distance {len(distance)} array must " - f"match number of polygon points {len(self.points)}" - ) - - normals = np.insert(self._normals, 0, self._normals[-1, :], axis=0) - cos2theta = np.sum(normals[1:, :]*normals[:-1, :], axis=-1, keepdims=True) - costheta = np.cos(np.arccos(cos2theta) / 2) - nvec = (normals[1:, :] + normals[:-1, :]) - unit_nvec = nvec / np.linalg.norm(nvec, axis=-1, keepdims=True) - disp_vec = distance[:, np.newaxis] / costheta * unit_nvec - - return type(self)(self.points + disp_vec, basis=self.basis) - - -class CruciformPrism(CompositeSurface): - """Generalized cruciform prism - - This surface represents a prism parallel to an axis formed by planes at - multiple distances from the center. Equivalent to the 'gcross' derived - surface in Serpent. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - distances : iterable of float - A monotonically increasing (or decreasing) iterable of distances in [cm] - that form the planes of the generalized cruciform. - center : iterable of float - The center of the prism in the two non-parallel axes (e.g., (x, y) when - axis is 'z') in [cm] - axis : {'x', 'y', 'z'} - Axis to which the prism is parallel - **kwargs - Keyword arguments passed to underlying plane classes - - """ - - def __init__(self, distances, center=(0., 0.), axis='z', **kwargs): - x0, y0 = center - self.distances = distances - - if axis == 'x': - cls_horizontal = openmc.YPlane - cls_vertical = openmc.ZPlane - elif axis == 'y': - cls_horizontal = openmc.XPlane - cls_vertical = openmc.ZPlane - elif axis == 'z': - cls_horizontal = openmc.XPlane - cls_vertical = openmc.YPlane - else: - raise ValueError("axis must be 'x', 'y', or 'z'") - - # Create each planar surface - surfnames = [] - for i, d in enumerate(distances): - setattr(self, f'hmin{i}', cls_horizontal(x0 - d, **kwargs)) - setattr(self, f'hmax{i}', cls_horizontal(x0 + d, **kwargs)) - setattr(self, f'vmin{i}', cls_vertical(y0 - d, **kwargs)) - setattr(self, f'vmax{i}', cls_vertical(y0 + d, **kwargs)) - surfnames.extend([f'hmin{i}', f'hmax{i}', f'vmin{i}', f'vmax{i}']) - - # Set _surfnames to satisfy CompositeSurface protocol - self._surfnames = tuple(surfnames) - - @property - def _surface_names(self): - return self._surfnames - - @property - def distances(self): - return self._distances - - @distances.setter - def distances(self, values): - values = np.array(values, dtype=float) - # check for positive values - if not (values > 0).all(): - raise ValueError("distances must be positive") - # Check for monotonicity - if (values[1:] > values[:-1]).all() or (values[1:] < values[:-1]).all(): - self._distances = values - else: - raise ValueError("distances must be monotonic") - - def __neg__(self): - n = len(self.distances) - regions = [] - for i in range(n): - regions.append( - +getattr(self, f'hmin{i}') & - -getattr(self, f'hmax{i}') & - +getattr(self, f'vmin{n-1-i}') & - -getattr(self, f'vmax{n-1-i}') - ) - return openmc.Union(regions) - - -# Define function to create a plane on given axis -def _plane(axis, name, value, boundary_type='transmission', albedo=1.0): - cls = getattr(openmc, f'{axis.upper()}Plane') - return cls(value, name=f'{name} {axis}', - boundary_type=boundary_type, albedo=albedo) - - -class RectangularPrism(CompositeSurface): - """Infinite rectangular prism bounded by four planar surfaces. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - width : float - Prism width in units of [cm]. The width is aligned with the x, x, or z - axes for prisms parallel to the x, y, or z axis, respectively. - height : float - Prism height in units of [cm]. The height is aligned with the x, y, or z - axes for prisms parallel to the x, y, or z axis, respectively. - axis : {'x', 'y', 'z'} - Axis with which the infinite length of the prism should be aligned. - origin : Iterable of two floats - Origin of the prism. The two floats correspond to (y,z), (x,z) or (x,y) - for prisms parallel to the x, y or z axis, respectively. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} - Boundary condition that defines the behavior for particles hitting the - surfaces comprising the rectangular prism. - albedo : float, optional - Albedo of the prism's surfaces as a ratio of particle weight after - interaction with the surface to the initial weight. Values must be - positive. Only applicable if the boundary type is 'reflective', - 'periodic', or 'white'. - corner_radius : float - Prism corner radius in units of [cm]. - - """ - _surface_names = ('min_x1', 'max_x1', 'min_x2', 'max_x2') - - def __init__( - self, - width: float, - height: float, - axis: str = 'z', - origin: Sequence[float] = (0., 0.), - boundary_type: str = 'transmission', - albedo: float = 1., - corner_radius: float = 0. - ): - check_type('width', width, Real) - check_type('height', height, Real) - check_type('albedo', albedo, Real) - check_type('corner_radius', corner_radius, Real) - check_value('axis', axis, ('x', 'y', 'z')) - check_type('origin', origin, Iterable, Real) - - if axis == 'x': - x1, x2 = 'y', 'z' - elif axis == 'y': - x1, x2 = 'x', 'z' - else: - x1, x2 = 'x', 'y' - - # Get cylinder class corresponding to given axis - cyl = getattr(openmc, f'{axis.upper()}Cylinder') - - # Create container for boundary arguments - bc_args = {'boundary_type': boundary_type, 'albedo': albedo} - - # Create rectangular region - self.min_x1 = _plane(x1, 'minimum', -width/2 + origin[0], **bc_args) - self.max_x1 = _plane(x1, 'maximum', width/2 + origin[0], **bc_args) - self.min_x2 = _plane(x2, 'minimum', -height/2 + origin[1], **bc_args) - self.max_x2 = _plane(x2, 'maximum', height/2 + origin[1], **bc_args) - if boundary_type == 'periodic': - self.min_x1.periodic_surface = self.max_x1 - self.min_x2.periodic_surface = self.max_x2 - - # Handle rounded corners if given - if corner_radius > 0.: - if boundary_type == 'periodic': - raise ValueError('Periodic boundary conditions not permitted when ' - 'rounded corners are used.') - - args = {'r': corner_radius, 'boundary_type': boundary_type, 'albedo': albedo} - - args[x1 + '0'] = origin[0] - width/2 + corner_radius - args[x2 + '0'] = origin[1] - height/2 + corner_radius - self.x1_min_x2_min = cyl(name=f'{x1} min {x2} min', **args) - - args[x1 + '0'] = origin[0] - width/2 + corner_radius - args[x2 + '0'] = origin[1] + height/2 - corner_radius - self.x1_min_x2_max = cyl(name=f'{x1} min {x2} max', **args) - - args[x1 + '0'] = origin[0] + width/2 - corner_radius - args[x2 + '0'] = origin[1] - height/2 + corner_radius - self.x1_max_x2_min = cyl(name=f'{x1} max {x2} min', **args) - - args[x1 + '0'] = origin[0] + width/2 - corner_radius - args[x2 + '0'] = origin[1] + height/2 - corner_radius - self.x1_max_x2_max = cyl(name=f'{x1} max {x2} max', **args) - - self.x1_min = _plane(x1, 'min', -width/2 + origin[0] + corner_radius, - **bc_args) - self.x1_max = _plane(x1, 'max', width/2 + origin[0] - corner_radius, - **bc_args) - self.x2_min = _plane(x2, 'min', -height/2 + origin[1] + corner_radius, - **bc_args) - self.x2_max = _plane(x2, 'max', height/2 + origin[1] - corner_radius, - **bc_args) - self._surface_names += ( - 'x1_min_x2_min', 'x1_min_x2_max', 'x1_max_x2_min', - 'x1_max_x2_max', 'x1_min', 'x1_max', 'x2_min', 'x2_max' - ) - - def __neg__(self): - prism = +self.min_x1 & -self.max_x1 & +self.min_x2 & -self.max_x2 - - # Cut out corners if a corner radius was given - if hasattr(self, 'x1_min'): - corners = ( - (+self.x1_min_x2_min & -self.x1_min & -self.x2_min) | - (+self.x1_min_x2_max & -self.x1_min & +self.x2_max) | - (+self.x1_max_x2_min & +self.x1_max & -self.x2_min) | - (+self.x1_max_x2_max & +self.x1_max & +self.x2_max) - ) - prism &= ~corners - - return prism - - -class HexagonalPrism(CompositeSurface): - """Hexagonal prism comoposed of six planar surfaces - - .. versionadded:: 0.14.0 - - Parameters - ---------- - edge_length : float - Length of a side of the hexagon in [cm] - orientation : {'x', 'y'} - An 'x' orientation means that two sides of the hexagon are parallel to - the x-axis and a 'y' orientation means that two sides of the hexagon are - parallel to the y-axis. - origin : Iterable of two floats - Origin of the prism. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} - Boundary condition that defines the behavior for particles hitting the - surfaces comprising the hexagonal prism. - albedo : float, optional - Albedo of the prism's surfaces as a ratio of particle weight after - interaction with the surface to the initial weight. Values must be - positive. Only applicable if the boundary type is 'reflective', - 'periodic', or 'white'. - corner_radius : float - Prism corner radius in units of [cm]. - - """ - _surface_names = ('plane_max', 'plane_min', 'upper_right', 'upper_left', - 'lower_right', 'lower_left') - - def __init__( - self, - edge_length: float = 1., - orientation: str = 'y', - origin: Sequence[float] = (0., 0.), - boundary_type: str = 'transmission', - albedo: float = 1., - corner_radius: float = 0. - ): - check_type('edge_length', edge_length, Real) - check_type('albedo', albedo, Real) - check_type('corner_radius', corner_radius, Real) - check_value('orientation', orientation, ('x', 'y')) - check_type('origin', origin, Iterable, Real) - - l = edge_length - x, y = origin - - # Create container for boundary arguments - bc_args = {'boundary_type': boundary_type, 'albedo': albedo} - - if orientation == 'y': - # Left and right planes - self.plane_max = openmc.XPlane(x + sqrt(3.)/2*l, **bc_args) - self.plane_min = openmc.XPlane(x - sqrt(3.)/2*l, **bc_args) - c = sqrt(3.)/3. - - # y = -x/sqrt(3) + a - self.upper_right = openmc.Plane(a=c, b=1., d=l+x*c+y, **bc_args) - - # y = x/sqrt(3) + a - self.upper_left = openmc.Plane(a=-c, b=1., d=l-x*c+y, **bc_args) - - # y = x/sqrt(3) - a - self.lower_right = openmc.Plane(a=-c, b=1., d=-l-x*c+y, **bc_args) - - # y = -x/sqrt(3) - a - self.lower_left = openmc.Plane(a=c, b=1., d=-l+x*c+y, **bc_args) - - elif orientation == 'x': - self.plane_max = openmc.YPlane(y + sqrt(3.)/2*l, **bc_args) - self.plane_min = openmc.YPlane(y - sqrt(3.)/2*l, **bc_args) - c = sqrt(3.) - - # Upper-right surface: y = -sqrt(3)*(x - a) - self.upper_right = openmc.Plane(a=c, b=1., d=c*l+x*c+y, **bc_args) - - # Lower-right surface: y = sqrt(3)*(x + a) - self.lower_right = openmc.Plane(a=-c, b=1., d=-c*l-x*c+y, **bc_args) - - # Lower-left surface: y = -sqrt(3)*(x + a) - self.lower_left = openmc.Plane(a=c, b=1., d=-c*l+x*c+y, **bc_args) - - # Upper-left surface: y = sqrt(3)*(x + a) - self.upper_left = openmc.Plane(a=-c, b=1., d=c*l-x*c+y, **bc_args) - - # Handle periodic boundary conditions - if boundary_type == 'periodic': - self.plane_min.periodic_surface = self.plane_max - self.upper_right.periodic_surface = self.lower_left - self.lower_right.periodic_surface = self.upper_left - - # Handle rounded corners if given - if corner_radius > 0.: - if boundary_type == 'periodic': - raise ValueError('Periodic boundary conditions not permitted ' - 'when rounded corners are used.') - - c = sqrt(3.)/2 - t = l - corner_radius/c - - # Cylinder with corner radius and boundary type pre-applied - cyl1 = partial(openmc.ZCylinder, r=corner_radius, **bc_args) - cyl2 = partial(openmc.ZCylinder, r=corner_radius/(2*c), **bc_args) - - if orientation == 'x': - self.x_min_y_min_in = cyl1(name='x min y min in', x0=x-t/2, y0=y-c*t) - self.x_min_y_max_in = cyl1(name='x min y max in', x0=x+t/2, y0=y-c*t) - self.x_max_y_min_in = cyl1(name='x max y min in', x0=x-t/2, y0=y+c*t) - self.x_max_y_max_in = cyl1(name='x max y max in', x0=x+t/2, y0=y+c*t) - self.min_in = cyl1(name='x min in', x0=x-t, y0=y) - self.max_in = cyl1(name='x max in', x0=x+t, y0=y) - - self.x_min_y_min_out = cyl2(name='x min y min out', x0=x-l/2, y0=y-c*l) - self.x_min_y_max_out = cyl2(name='x min y max out', x0=x+l/2, y0=y-c*l) - self.x_max_y_min_out = cyl2(name='x max y min out', x0=x-l/2, y0=y+c*l) - self.x_max_y_max_out = cyl2(name='x max y max out', x0=x+l/2, y0=y+c*l) - self.min_out = cyl2(name='x min out', x0=x-l, y0=y) - self.max_out = cyl2(name='x max out', x0=x+l, y0=y) - - elif orientation == 'y': - self.x_min_y_min_in = cyl1(name='x min y min in', x0=x-c*t, y0=y-t/2) - self.x_min_y_max_in = cyl1(name='x min y max in', x0=x-c*t, y0=y+t/2) - self.x_max_y_min_in = cyl1(name='x max y min in', x0=x+c*t, y0=y-t/2) - self.x_max_y_max_in = cyl1(name='x max y max in', x0=x+c*t, y0=y+t/2) - self.min_in = cyl1(name='y min in', x0=x, y0=y-t) - self.max_in = cyl1(name='y max in', x0=x, y0=y+t) - - self.x_min_y_min_out = cyl2(name='x min y min out', x0=x-c*l, y0=y-l/2) - self.x_min_y_max_out = cyl2(name='x min y max out', x0=x-c*l, y0=y+l/2) - self.x_max_y_min_out = cyl2(name='x max y min out', x0=x+c*l, y0=y-l/2) - self.x_max_y_max_out = cyl2(name='x max y max out', x0=x+c*l, y0=y+l/2) - self.min_out = cyl2(name='y min out', x0=x, y0=y-l) - self.max_out = cyl2(name='y max out', x0=x, y0=y+l) - - # Add to tuple of surface names - for s in ('in', 'out'): - self._surface_names += ( - f'x_min_y_min_{s}', f'x_min_y_max_{s}', - f'x_max_y_min_{s}', f'x_max_y_max_{s}', - f'min_{s}', f'max_{s}') - - def __neg__(self) -> openmc.Region: - prism = ( - -self.plane_max & +self.plane_min & - -self.upper_right & -self.upper_left & - +self.lower_right & +self.lower_left - ) - - # Cut out corners if a corner radius was given - if hasattr(self, 'min_in'): - corners = ( - +self.x_min_y_min_in & -self.x_min_y_min_out | - +self.x_min_y_max_in & -self.x_min_y_max_out | - +self.x_max_y_min_in & -self.x_max_y_min_out | - +self.x_max_y_max_in & -self.x_max_y_max_out | - +self.min_in & -self.min_out | - +self.max_in & -self.max_out - ) - prism &= ~corners - - return prism - - -def _rotation_matrix(v1, v2): - """Compute rotation matrix that would rotate v1 into v2. - - Parameters - ---------- - v1 : numpy.ndarray - Unrotated vector - v2 : numpy.ndarray - Rotated vector - - Returns - ------- - 3x3 rotation matrix - - """ - # Normalize vectors and compute cosine - u1 = v1 / np.linalg.norm(v1) - u2 = v2 / np.linalg.norm(v2) - cos_angle = np.dot(u1, u2) - - I = np.identity(3) - - # Handle special case where vectors are parallel or anti-parallel - if isclose(abs(cos_angle), 1.0, rel_tol=1e-8): - return np.sign(cos_angle)*I - else: - # Calculate rotation angle - sin_angle = np.sqrt(1 - cos_angle*cos_angle) - - # Calculate axis of rotation - axis = np.cross(u1, u2) - axis /= np.linalg.norm(axis) - - # Create cross-product matrix K - kx, ky, kz = axis - K = np.array([ - [0.0, -kz, ky], - [kz, 0.0, -kx], - [-ky, kx, 0.0] - ]) - - # Create rotation matrix using Rodrigues' rotation formula - return I + K * sin_angle + (K @ K) * (1 - cos_angle) - - -class ConicalFrustum(CompositeSurface): - """Conical frustum. - - A conical frustum, also known as a right truncated cone, is a cone that is - truncated by two parallel planes that are perpendicular to the axis of the - cone. The lower and upper base of the conical frustum are circular faces. - This surface is equivalent to the TRC macrobody in MCNP. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - center_base : iterable of float - Cartesian coordinates of the center of the bottom planar face. - axis : iterable of float - Vector from the center of the bottom planar face to the center of the - top planar face that defines the axis of the cone. The length of this - vector is the height of the conical frustum. - r1 : float - Radius of the lower cone base - r2 : float - Radius of the upper cone base - **kwargs - Keyword arguments passed to underlying plane classes - - Attributes - ---------- - cone : openmc.Cone - Cone surface - plane_bottom : openmc.Plane - Plane surface defining the bottom of the frustum - plane_top : openmc.Plane - Plane surface defining the top of the frustum - - """ - _surface_names = ('cone', 'plane_bottom', 'plane_top') - - def __init__(self, center_base: Sequence[float], axis: Sequence[float], - r1: float, r2: float, **kwargs): - center_base = np.array(center_base) - axis = np.array(axis) - - # Determine length of axis height vector - h = np.linalg.norm(axis) - - # To create the frustum oriented with the correct axis, first we will - # create a cone along the z axis and then rotate it according to the - # given axis. Thus, we first need to determine the apex using the z axis - # as a reference. - x0, y0, z0 = center_base - if r1 != r2: - apex = z0 + r1*h/(r1 - r2) - r_sq = ((r1 - r2)/h)**2 - cone = openmc.ZCone(x0, y0, apex, r2=r_sq, **kwargs) - else: - # In the degenerate case r1 == r2, the cone becomes a cylinder - cone = openmc.ZCylinder(x0, y0, r1, **kwargs) - - # Create the parallel planes - plane_bottom = openmc.ZPlane(z0, **kwargs) - plane_top = openmc.ZPlane(z0 + h, **kwargs) - - # Determine rotation matrix corresponding to specified axis - u = np.array([0., 0., 1.]) - rotation = _rotation_matrix(u, axis) - - # Rotate the surfaces - self.cone = cone.rotate(rotation, pivot=center_base) - self.plane_bottom = plane_bottom.rotate(rotation, pivot=center_base) - self.plane_top = plane_top.rotate(rotation, pivot=center_base) - - def __neg__(self) -> openmc.Region: - return +self.plane_bottom & -self.plane_top & -self.cone - - -class Vessel(CompositeSurface): - """Vessel composed of cylinder with semi-ellipsoid top and bottom. - - This composite surface is represented by a finite cylinder with ellipsoidal - top and bottom surfaces. This surface is equivalent to the 'vesesl' surface - in Serpent. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - r : float - Radius of vessel. - p1 : float - Minimum coordinate for cylindrical part of vessel. - p2 : float - Maximum coordinate for cylindrical part of vessel. - h1 : float - Height of bottom ellipsoidal part of vessel. - h2 : float - Height of top ellipsoidal part of vessel. - center : 2-tuple of float - Coordinate for central axis of the cylinder in the (y, z), (x, z), or - (x, y) basis. Defaults to (0,0). - axis : {'x', 'y', 'z'} - Central axis of the cylinder. - - """ - - _surface_names = ('cyl', 'plane_bottom', 'plane_top', 'bottom', 'top') - - def __init__(self, r: float, p1: float, p2: float, h1: float, h2: float, - center: Sequence[float] = (0., 0.), axis: str = 'z', **kwargs): - if p1 >= p2: - raise ValueError('p1 must be less than p2') - check_value('axis', axis, {'x', 'y', 'z'}) - - c1, c2 = center - cyl_class = getattr(openmc, f'{axis.upper()}Cylinder') - plane_class = getattr(openmc, f'{axis.upper()}Plane') - self.cyl = cyl_class(c1, c2, r, **kwargs) - self.plane_bottom = plane_class(p1) - self.plane_top = plane_class(p2) - - # General equation for an ellipsoid: - # (x-x₀)²/r² + (y-y₀)²/r² + (z-z₀)²/h² = 1 - # (x-x₀)² + (y-y₀)² + (z-z₀)²s² = r² - # Let s = r/h: - # (x² - 2x₀x + x₀²) + (y² - 2y₀y + y₀²) + (z² - 2z₀z + z₀²)s² = r² - # x² + y² + s²z² - 2x₀x - 2y₀y - 2s²z₀z + (x₀² + y₀² + z₀²s² - r²) = 0 - - sb = (r/h1) - st = (r/h2) - kwargs['a'] = kwargs['b'] = kwargs['c'] = 1.0 - kwargs_bottom = kwargs - kwargs_top = kwargs.copy() - - sb2 = sb*sb - st2 = st*st - kwargs_bottom['k'] = c1*c1 + c2*c2 + p1*p1*sb2 - r*r - kwargs_top['k'] = c1*c1 + c2*c2 + p2*p2*st2 - r*r - - if axis == 'x': - kwargs_bottom['a'] *= sb2 - kwargs_top['a'] *= st2 - kwargs_bottom['g'] = -2*p1*sb2 - kwargs_top['g'] = -2*p2*st2 - kwargs_top['h'] = kwargs_bottom['h'] = -2*c1 - kwargs_top['j'] = kwargs_bottom['j'] = -2*c2 - elif axis == 'y': - kwargs_bottom['b'] *= sb2 - kwargs_top['b'] *= st2 - kwargs_top['g'] = kwargs_bottom['g'] = -2*c1 - kwargs_bottom['h'] = -2*p1*sb2 - kwargs_top['h'] = -2*p2*st2 - kwargs_top['j'] = kwargs_bottom['j'] = -2*c2 - elif axis == 'z': - kwargs_bottom['c'] *= sb2 - kwargs_top['c'] *= st2 - kwargs_top['g'] = kwargs_bottom['g'] = -2*c1 - kwargs_top['h'] = kwargs_bottom['h'] = -2*c2 - kwargs_bottom['j'] = -2*p1*sb2 - kwargs_top['j'] = -2*p2*st2 - - self.bottom = openmc.Quadric(**kwargs_bottom) - self.top = openmc.Quadric(**kwargs_top) - - def __neg__(self): - return ((-self.cyl & +self.plane_bottom & -self.plane_top) | - (-self.bottom & -self.plane_bottom) | - (-self.top & +self.plane_top)) + __pos__ = XConeOneSided.__pos__ diff --git a/openmc/model/triso.py b/openmc/model/triso.py index f344b8edd..f486482aa 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -138,20 +138,10 @@ class _Container(ABC): def sphere_radius(self): return self._sphere_radius - @sphere_radius.setter - def sphere_radius(self, sphere_radius): - self._sphere_radius = float(sphere_radius) - self._limits = None - self._cell_length = None - @property def center(self): return self._center - @center.setter - def center(self, center): - self._center = center - @abstractproperty def limits(self): pass @@ -164,6 +154,15 @@ class _Container(ABC): def volume(self): pass + @sphere_radius.setter + def sphere_radius(self, sphere_radius): + self._sphere_radius = float(sphere_radius) + self._limits = None + self._cell_length = None + + @center.setter + def center(self, center): + self._center = center def mesh_cell(self, p): """Calculate the index of the cell in a mesh overlaid on the domain in @@ -301,32 +300,14 @@ class _RectangularPrism(_Container): def width(self): return self._width - @width.setter - def width(self, width): - self._width = float(width) - self._limits = None - self._cell_length = None - @property def depth(self): return self._depth - @depth.setter - def depth(self, depth): - self._depth = float(depth) - self._limits = None - self._cell_length = None - @property def height(self): return self._height - @height.setter - def height(self, height): - self._height = float(height) - self._limits = None - self._cell_length = None - @property def limits(self): if self._limits is None: @@ -335,13 +316,8 @@ class _RectangularPrism(_Container): x, y, z = self.width/2, self.depth/2, self.height/2 self._limits = [[c[0] - x + r, c[1] - y + r, c[2] - z + r], [c[0] + x - r, c[1] + y - r, c[2] + z - r]] - return self._limits - @limits.setter - def limits(self, limits): - self._limits = limits - @property def cell_length(self): if self._cell_length is None: @@ -354,6 +330,28 @@ class _RectangularPrism(_Container): def volume(self): return self.width*self.depth*self.height + @width.setter + def width(self, width): + self._width = float(width) + self._limits = None + self._cell_length = None + + @depth.setter + def depth(self, depth): + self._depth = float(depth) + self._limits = None + self._cell_length = None + + @height.setter + def height(self, height): + self._height = float(height) + self._limits = None + self._cell_length = None + + @limits.setter + def limits(self, limits): + self._limits = limits + @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -472,31 +470,14 @@ class _Cylinder(_Container): def length(self): return self._length - @length.setter - def length(self, length): - self._length = float(length) - self._limits = None - self._cell_length = None - @property def radius(self): return self._radius - @radius.setter - def radius(self, radius): - self._radius = float(radius) - self._limits = None - self._cell_length = None - @property def axis(self): return self._axis - @axis.setter - def axis(self, axis): - self._axis = axis - self._shift = None - @property def shift(self): if self._shift is None: @@ -517,10 +498,6 @@ class _Cylinder(_Container): self._limits = [[z0 - z + r], [z0 + z - r, self.radius - r]] return self._limits - @limits.setter - def limits(self, limits): - self._limits = limits - @property def cell_length(self): if self._cell_length is None: @@ -536,6 +513,27 @@ class _Cylinder(_Container): def volume(self): return self.length*pi*self.radius**2 + @length.setter + def length(self, length): + self._length = float(length) + self._limits = None + self._cell_length = None + + @radius.setter + def radius(self, radius): + self._radius = float(radius) + self._limits = None + self._cell_length = None + + @axis.setter + def axis(self, axis): + self._axis = axis + self._shift = None + + @limits.setter + def limits(self, limits): + self._limits = limits + @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -678,21 +676,10 @@ class _SphericalShell(_Container): def radius(self): return self._radius - @radius.setter - def radius(self, radius): - self._radius = float(radius) - self._limits = None - self._cell_length = None - @property def inner_radius(self): return self._inner_radius - @inner_radius.setter - def inner_radius(self, inner_radius): - self._inner_radius = float(inner_radius) - self._limits = None - @property def limits(self): if self._limits is None: @@ -704,10 +691,6 @@ class _SphericalShell(_Container): self._limits = [[r_min], [r_max]] return self._limits - @limits.setter - def limits(self, limits): - self._limits = limits - @property def cell_length(self): if self._cell_length is None: @@ -720,6 +703,21 @@ class _SphericalShell(_Container): def volume(self): return _volume_sphere(self.radius) - _volume_sphere(self.inner_radius) + @radius.setter + def radius(self, radius): + self._radius = float(radius) + self._limits = None + self._cell_length = None + + @inner_radius.setter + def inner_radius(self, inner_radius): + self._inner_radius = float(inner_radius) + self._limits = None + + @limits.setter + def limits(self, limits): + self._limits = limits + @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -1208,7 +1206,7 @@ def _close_random_pack(domain, spheres, contraction_rate): def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, - contraction_rate=1.e-3, seed=None): + contraction_rate=1.e-3, seed=1): """Generate a random, non-overlapping configuration of spheres within a container. @@ -1237,7 +1235,7 @@ def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, reached using a smaller contraction rate, but the algorithm will take longer to converge. seed : int, optional - Pseudorandom number generator seed passed to :func:`random.seed` + RNG seed. Returns ------ @@ -1280,8 +1278,7 @@ def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, """ # Seed RNG - if seed is not None: - random.seed(seed) + random.seed(seed) # Create container with the correct shape based on the supplied region domain = None @@ -1313,13 +1310,14 @@ def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, # Check packing fraction for close random packing if pf > MAX_PF_CRP: - raise ValueError(f'Packing fraction {pf} is greater than the limit for ' - f'close random packing, {MAX_PF_CRP}') + raise ValueError('Packing fraction {0} is greater than the limit for ' + 'close random packing, {1}'.format(pf, MAX_PF_CRP)) # Check packing fraction for random sequential packing if initial_pf > MAX_PF_RSP: - raise ValueError(f'Initial packing fraction {initial_pf} is greater than' - f'the limit for random sequential packing, {MAX_PF_RSP}') + raise ValueError('Initial packing fraction {0} is greater than the ' + 'limit for random sequential packing, ' + '{1}'.format(initial_pf, MAX_PF_RSP)) # Calculate the sphere radius used in the initial random sequential # packing from the initial packing fraction diff --git a/openmc/nuclide.py b/openmc/nuclide.py index d5ae4bddb..196c8d770 100644 --- a/openmc/nuclide.py +++ b/openmc/nuclide.py @@ -26,7 +26,7 @@ class Nuclide(str): if name.endswith('m'): name = name[:-1] + '_m1' - msg = ('OpenMC nuclides follow the GNDS naming convention. ' + msg = ('OpenMC nuclides follow the GND naming convention. ' f'Nuclide "{orig_name}" is being renamed as "{name}".') warnings.warn(msg) diff --git a/openmc/particle_restart.py b/openmc/particle_restart.py index 44864107d..317d8761b 100644 --- a/openmc/particle_restart.py +++ b/openmc/particle_restart.py @@ -1,7 +1,6 @@ import h5py import openmc.checkvalue as cv -from .particle_type import ParticleType _VERSION_PARTICLE_RESTART = 2 @@ -29,8 +28,8 @@ class Particle: Type of simulation (criticality or fixed source) id : long Identifier of the particle - type : openmc.ParticleType - Particle type + type : int + Particle type (1 = neutron, 2 = photon, 3 = electron, 4 = positron) weight : float Weight of the particle energy : float @@ -53,7 +52,7 @@ class Particle: self.energy = f['energy'][()] self.generations_per_batch = f['generations_per_batch'][()] self.id = f['id'][()] - self.type = ParticleType(f['type'][()]) + self.type = f['type'][()] self.n_particles = f['n_particles'][()] self.run_mode = f['run_mode'][()].decode() self.uvw = f['uvw'][()] diff --git a/openmc/particle_type.py b/openmc/particle_type.py deleted file mode 100644 index 9d7713443..000000000 --- a/openmc/particle_type.py +++ /dev/null @@ -1,228 +0,0 @@ -from numbers import Integral - -from openmc.data import gnds_name, zam, ATOMIC_SYMBOL - - -_PDG_NAME = { - 2112: 'neutron', - 22: 'photon', - 11: 'electron', - -11: 'positron', - 2212: 'H1', -} - -_ALIAS_PDG = { - 'neutron': 2112, - 'n': 2112, - 'photon': 22, - 'gamma': 22, - 'electron': 11, - 'positron': -11, - 'proton': 2212, - 'p': 2212, - 'h1': 2212, - 'deuteron': 1000010020, - 'd': 1000010020, - 'h2': 1000010020, - 'triton': 1000010030, - 't': 1000010030, - 'h3': 1000010030, - 'alpha': 1000020040, - 'he4': 1000020040, -} - -_LEGACY_PARTICLE_INDEX = { - 0: 2112, - 1: 22, - 2: 11, - 3: -11, -} - - -class ParticleType: - """Particle type defined by a PDG number. - - ParticleType uses the Particle Data Group (PDG) Monte Carlo numbering scheme - to uniquely identify particle types. This includes elementary particles - (neutrons, photons, etc.) and nuclear codes for isotopes. - - Parameters - ---------- - value : str, int, or ParticleType - The particle identifier. Can be: - - - A string name (e.g., 'neutron', 'photon', 'He4', 'U235') - - An integer PDG number (e.g., 2112 for neutron) - - A string with PDG prefix (e.g., 'pdg:2112') - - An existing ParticleType instance - - Attributes - ---------- - pdg_number : int - The PDG number for this particle type - zam : tuple of int or None - For nuclear particles, the (Z, A, m) tuple where Z is atomic number, - A is mass number, and m is metastable state. None for elementary particles. - is_nucleus : bool - Whether this particle is a nucleus (ion) - - Examples - -------- - >>> neutron = ParticleType('neutron') - >>> neutron.pdg_number - 2112 - >>> he4 = ParticleType('He4') - >>> he4.zam - (2, 4, 0) - >>> ParticleType(2112) == ParticleType('neutron') - True - - """ - - __slots__ = ('_pdg_number',) - - def __init__(self, value: 'str | int | ParticleType'): - if isinstance(value, ParticleType): - pdg = value._pdg_number - elif isinstance(value, str): - pdg = self._pdg_number_from_string(value) - elif isinstance(value, Integral): - pdg = int(value) - # Handle legacy particle indices (0, 1, 2, 3) - if pdg in _LEGACY_PARTICLE_INDEX: - pdg = _LEGACY_PARTICLE_INDEX[pdg] - else: - raise TypeError(f"Cannot create ParticleType from {type(value).__name__}") - - self._pdg_number = pdg - - def __eq__(self, other): - if isinstance(other, ParticleType): - return self._pdg_number == other._pdg_number - if isinstance(other, Integral): - return self._pdg_number == int(other) - if isinstance(other, str): - try: - return self._pdg_number == ParticleType(other)._pdg_number - except (ValueError, TypeError): - return False - return NotImplemented - - def __hash__(self) -> int: - return hash(self._pdg_number) - - def __int__(self) -> int: - return self._pdg_number - - @property - def pdg_number(self) -> int: - return self._pdg_number - - @staticmethod - def _pdg_number_from_string(value: str) -> int: - """Parse a string to get a PDG number. - - Parameters - ---------- - value : str - Particle identifier string - - Returns - ------- - int - PDG number - - Raises - ------ - ValueError - If string cannot be parsed as a valid particle identifier - - """ - s = value.strip() - if not s: - raise ValueError('Particle identifier cannot be empty.') - - lower = s.lower() - if lower.startswith('pdg:'): - code_str = lower[4:] - try: - return int(code_str) - except ValueError: - raise ValueError(f'Invalid PDG number: {code_str}') - - if lower in _ALIAS_PDG: - return _ALIAS_PDG[lower] - - # Assume it is a GNDS nuclide name - Z, A, m = zam(s) - if Z <= 0 or Z > 999 or A <= 0 or A > 999 or m < 0 or m > 9: - raise ValueError('Invalid Z/A/m for nuclear PDG number.') - return 1000000000 + Z * 10000 + A * 10 + m - - def __repr__(self) -> str: - return f'' - - def __str__(self) -> str: - """Return a canonical string representation of the particle type. - - Returns - ------- - str - Canonical name (e.g., 'neutron', 'He4', 'pdg:12345') - - """ - if self._pdg_number in _PDG_NAME: - return _PDG_NAME[self._pdg_number] - - if (zam_tuple := self.zam) is not None: - Z, A, m = zam_tuple - if Z <= 0 or Z > max(ATOMIC_SYMBOL) or A <= 0 or A > 999: - raise ValueError(f"Invalid nuclear PDG number: {self._pdg_number}") - return gnds_name(Z, A, m) - - return f'pdg:{self._pdg_number}' - - @property - def zam(self) -> 'tuple[int, int, int] | None': - """Return the (Z, A, m) tuple for nuclear particles. - - Returns - ------- - tuple of int or None - For nuclear particles, returns (Z, A, m) where Z is atomic number, - A is mass number, and m is metastable state. Returns None for - elementary particles. - - """ - if self._pdg_number < 1000000000: - return None - Z = (self._pdg_number // 10000) % 1000 - A = (self._pdg_number // 10) % 1000 - m = self._pdg_number % 10 - if Z <= 0 or A <= 0: - return None - else: - return (Z, A, m) - - @property - def is_nucleus(self) -> bool: - """Return whether this particle is a nucleus. - - Returns - ------- - bool - True if the particle is a nucleus (ion), False otherwise - - """ - return self.zam is not None - - -# Define common particle constants -ParticleType.NEUTRON = ParticleType(2112) -ParticleType.PHOTON = ParticleType(22) -ParticleType.ELECTRON = ParticleType(11) -ParticleType.POSITRON = ParticleType(-11) -ParticleType.PROTON = ParticleType(2212) -ParticleType.DEUTERON = ParticleType(1000010020) -ParticleType.TRITON = ParticleType(1000010030) -ParticleType.ALPHA = ParticleType(1000020040) diff --git a/openmc/plots.py b/openmc/plots.py index 531184095..b22ee9125 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -1,23 +1,17 @@ -from collections.abc import Iterable, Mapping, Sequence -from numbers import Integral, Real +from collections.abc import Iterable, Mapping +from numbers import Real, Integral from pathlib import Path -from textwrap import dedent -import warnings +from xml.etree import ElementTree as ET -import h5py -import lxml.etree as ET import numpy as np import openmc import openmc.checkvalue as cv -from openmc.checkvalue import PathLike - -from ._xml import clean_indentation, get_elem_list, get_text +from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin -_BASES = {'xy', 'xz', 'yz'} -_BASIS_INDICES = {'xy': (0, 1, 2), 'xz': (0, 2, 1), 'yz': (1, 2, 0)} +_BASES = ['xy', 'xz', 'yz'] _SVG_COLORS = { 'aliceblue': (240, 248, 255), @@ -169,274 +163,27 @@ _SVG_COLORS = { 'yellowgreen': (154, 205, 50) } -_PLOT_PARAMS = dedent("""\ - - Parameters - ---------- - origin : iterable of float - Coordinates at the origin of the plot. If left as None, - the center of the bounding box will be used to attempt to ascertain - the origin with infinite values being replaced by 0. - width : iterable of float - Width of the plot in each basis direction. If left as none then the - width of the bounding box will be used to attempt to - ascertain the plot width. Defaults to (10, 10) if the bounding box - contains inf values. - pixels : Iterable of int or int - If an iterable of ints is provided then this directly sets the - number of pixels to use in each basis direction. If a single int - is provided then this sets the total number of pixels in the plot - and the number of pixels in each basis direction is calculated - from this total and the image aspect ratio based on the width - argument. - basis : {'xy', 'xz', 'yz'} - The basis directions for the plot - color_by : {'cell', 'material'} - Indicate whether the plot should be colored by cell or by material - colors : dict - Assigns colors to specific materials or cells. Keys are instances of - :class:`Cell` or :class:`Material` and values are RGB 3-tuples, RGBA - 4-tuples, or strings indicating SVG color names. Red, green, blue, - and alpha should all be integers in the range [0, 255], for example: - - .. code-block:: python - - # Make water blue - water = openmc.Cell(fill=h2o) - universe.plot(..., colors={water: (0, 0, 255)) - seed : int - Seed for the random number generator - openmc_exec : str - Path to OpenMC executable. - axes : matplotlib.Axes - Axes to draw to - - .. versionadded:: 0.13.1 - legend : bool - Whether a legend showing material or cell names should be drawn - - .. versionadded:: 0.14.0 - axis_units : {'km', 'm', 'cm', 'mm'} - Units used on the plot axis - - .. versionadded:: 0.14.0 - outline : bool or str - Whether outlines between color boundaries should be drawn. If set to - 'only', only outlines will be drawn. - - .. versionadded:: 0.14.0 - show_overlaps: bool - Indicate whether or not overlapping regions are shown. - Default is False. - overlap_color: Iterable of int or str - Color to apply to overlapping regions. Default is red. - n_samples : int, optional - The number of source particles to sample and add to plot. Defaults - to None which doesn't plot any particles on the plot. - plane_tolerance: float - When plotting a plane the source locations within the plane +/- - the plane_tolerance will be included and those outside of the - plane_tolerance will not be shown - legend_kwargs : dict - Keyword arguments passed to :func:`matplotlib.pyplot.legend`. - - .. versionadded:: 0.14.0 - source_kwargs : dict, optional - Keyword arguments passed to :func:`matplotlib.pyplot.scatter`. - contour_kwargs : dict, optional - Keyword arguments passed to :func:`matplotlib.pyplot.contour`. - **kwargs - Keyword arguments passed to :func:`matplotlib.pyplot.imshow`. - - Returns - ------- - matplotlib.axes.Axes - Axes containing resulting image -""") - - -# Decorator for consistently adding plot parameters to docstrings (Model.plot, -# Geometry.plot, Universe.plot, etc.) -def add_plot_params(func): - func.__doc__ += _PLOT_PARAMS - return func - def _get_plot_image(plot, cwd): from IPython.display import Image # Make sure .png file was created - png_filename = plot.filename if plot.filename is not None else f'plot_{plot.id}' - - # Add file extension if not already present. The C++ code added it - # automatically if it wasn't present. - if Path(png_filename).suffix != ".png": - png_filename += ".png" - - png_file = Path(cwd) / png_filename + stem = plot.filename if plot.filename is not None else f'plot_{plot.id}' + png_file = Path(cwd) / f'{stem}.png' if not png_file.exists(): - raise FileNotFoundError( - f"Could not find .png image for plot {plot.id}. Your version of " - "OpenMC may not be built against libpng.") + raise FileNotFoundError(f"Could not find .png image for plot {plot.id}") return Image(str(png_file)) -def voxel_to_vtk(voxel_file: PathLike, output: PathLike = 'plot.vti'): - """Converts a voxel HDF5 file to a VTK file +class Plot(IDManagerMixin): + """Definition of a finite region of space to be plotted. - .. versionadded:: 0.14.0 + OpenMC is capable of generating two-dimensional slice plots and + three-dimensional voxel plots. Colors that are used in plots can be given as + RGB tuples, e.g. (255, 255, 255) would be white, or by a string indicating a + valid `SVG color `_. - Parameters - ---------- - voxel_file : path-like - Path of the input h5 to convert - output : path-like - Path of the output vti file produced - - Returns - ------- - Path - Path of the .vti file produced - """ - - # imported vtk only if used as vtk is an option dependency - import vtk - - _min_version = (2, 0) - - # Read data from voxel file - with h5py.File(voxel_file, "r") as fh: - # check version - version = tuple(fh.attrs["version"]) - if version < _min_version: - old_version = ".".join(map(str, version)) - min_version = ".".join(map(str, _min_version)) - err_msg = ( - f"This voxel file's version is {old_version}. This function only " - f" supports voxel files with version {min_version} or higher. " - "Please generate a new voxel file using a newer version of OpenMC." - ) - raise ValueError(err_msg) - - dimension = fh.attrs["num_voxels"] - width = fh.attrs["voxel_width"] - lower_left = fh.attrs["lower_left"] - - nx, ny, nz = dimension - - grid = vtk.vtkImageData() - grid.SetDimensions(nx + 1, ny + 1, nz + 1) - grid.SetOrigin(*lower_left) - grid.SetSpacing(*width) - - # transpose data from OpenMC ordering (zyx) to VTK ordering (xyz) - # and flatten to 1-D array - h5data = fh["data"][...] - - data = vtk.vtkIntArray() - data.SetName("id") - # set the array using the h5data array - data.SetArray(h5data, h5data.size, True) - # add data to image grid - grid.GetCellData().AddArray(data) - - writer = vtk.vtkXMLImageDataWriter() - if vtk.vtkVersion.GetVTKMajorVersion() > 5: - writer.SetInputData(grid) - else: - writer.SetInput(grid) - output = str(output) - if not output.endswith(".vti"): - output += ".vti" - writer.SetFileName(output) - writer.Write() - - return output - - -def id_map_to_rgb( - id_map: np.ndarray, - color_by: str = 'cell', - colors: dict | None = None, - overlap_color: Sequence[int] | str = (255, 0, 0) -) -> np.ndarray: - """Convert ID map array to RGB image array. - - Parameters - ---------- - id_map : numpy.ndarray - Array with shape (v_pixels, h_pixels, 3) containing cell IDs, - cell instances, and material IDs - color_by : {'cell', 'material'} - Whether to color by cell or material - colors : dict, optional - Dictionary mapping cells/materials to colors - overlap_color : sequence of int or str, optional - Color to use for overlaps. Defaults to red (255, 0, 0). - - Returns - ------- - numpy.ndarray - RGB image array with shape (v_pixels, h_pixels, 3) with values - in range [0, 1] for matplotlib - """ - # Initialize RGB array with white background (values between 0 and 1 for matplotlib) - img = np.ones(id_map.shape, dtype=float) - - # Get the appropriate index based on color_by - if color_by == 'cell': - id_index = 0 # Cell IDs are in the first channel - elif color_by == 'material': - id_index = 2 # Material IDs are in the third channel - else: - raise ValueError("color_by must be either 'cell' or 'material'") - - # Get all unique IDs in the plot - unique_ids = np.unique(id_map[:, :, id_index]) - - # Generate default colors if not provided - if colors is None: - colors = {} - - # Convert colors dict to use IDs as keys - color_map = {} - for key, color in colors.items(): - if isinstance(key, (openmc.Cell, openmc.Material)): - color_map[key.id] = color - else: - color_map[key] = color - - # Generate random colors for IDs not in color_map - rng = np.random.RandomState(1) - for uid in unique_ids: - if uid > 0 and uid not in color_map: - color_map[uid] = rng.randint(0, 256, (3,)) - - # Apply colors to each pixel - for uid in unique_ids: - if uid == -1: # Background/void - continue - elif uid == -3: # Overlap (only present if color_overlaps was True) - if isinstance(overlap_color, str): - rgb = _SVG_COLORS[overlap_color.lower()] - else: - rgb = overlap_color - mask = id_map[:, :, id_index] == uid - img[mask] = np.array(rgb) / 255.0 - elif uid in color_map: - color = color_map[uid] - if isinstance(color, str): - rgb = _SVG_COLORS[color.lower()] - else: - rgb = color - mask = id_map[:, :, id_index] == uid - img[mask] = np.array(rgb) / 255.0 - - return img - -class PlotBase(IDManagerMixin): - """ Parameters ---------- plot_id : int @@ -450,18 +197,26 @@ class PlotBase(IDManagerMixin): Unique identifier name : str Name of the plot + width : Iterable of float + Width of the plot in each basis direction pixels : Iterable of int - Number of pixels to use in each direction - filename : str + Number of pixels to use in each basis direction + origin : tuple or list of ndarray + Origin (center) of the plot + filename : Path to write the plot to color_by : {'cell', 'material'} Indicate whether the plot should be colored by cell or by material + type : {'slice', 'voxel'} + The type of the plot + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot background : Iterable of int or str Color of the background mask_components : Iterable of openmc.Cell or openmc.Material or int The cells or materials (or corresponding IDs) to mask mask_background : Iterable of int or str - Color to apply to all cells/materials listed in mask_components + Color to apply to all cells/materials not listed in mask_components show_overlaps : bool Indicate whether or not overlapping regions are shown overlap_color : Iterable of int or str @@ -473,6 +228,10 @@ class PlotBase(IDManagerMixin): cell/material). level : int Universe depth to plot at + meshlines : dict + Dictionary defining type, id, linewidth and color of a mesh to be + plotted on top of a plot + """ next_id = 1 @@ -482,9 +241,13 @@ class PlotBase(IDManagerMixin): # Initialize Plot class attributes self.id = plot_id self.name = name + self._width = [4.0, 4.0] self._pixels = [400, 400] + self._origin = [0., 0., 0.] self._filename = None self._color_by = 'cell' + self._type = 'slice' + self._basis = 'xy' self._background = None self._mask_components = None self._mask_background = None @@ -492,19 +255,88 @@ class PlotBase(IDManagerMixin): self._overlap_color = None self._colors = {} self._level = None + self._meshlines = None @property def name(self): return self._name + @property + def width(self): + return self._width + + @property + def pixels(self): + return self._pixels + + @property + def origin(self): + return self._origin + + @property + def filename(self): + return self._filename + + @property + def color_by(self): + return self._color_by + + @property + def type(self): + return self._type + + @property + def basis(self): + return self._basis + + @property + def background(self): + return self._background + + @property + def mask_components(self): + return self._mask_components + + @property + def mask_background(self): + return self._mask_background + + @property + def show_overlaps(self): + return self._show_overlaps + + @property + def overlap_color(self): + return self._overlap_color + + @property + def colors(self): + return self._colors + + @property + def level(self): + return self._level + + @property + def meshlines(self): + return self._meshlines + @name.setter def name(self, name): cv.check_type('plot name', name, str) self._name = name - @property - def pixels(self): - return self._pixels + @width.setter + def width(self, width): + cv.check_type('plot width', width, Iterable, Real) + cv.check_length('plot width', width, 2, 3) + self._width = width + + @origin.setter + def origin(self, origin): + cv.check_type('plot origin', origin, Iterable, Real) + cv.check_length('plot origin', origin, 3) + self._origin = origin @pixels.setter def pixels(self, pixels): @@ -514,75 +346,31 @@ class PlotBase(IDManagerMixin): cv.check_greater_than('plot pixels', dim, 0) self._pixels = pixels - @property - def filename(self): - return self._filename - @filename.setter def filename(self, filename): - cv.check_type('filename', filename, (str, PathLike)) + cv.check_type('filename', filename, str) self._filename = filename - @property - def color_by(self): - return self._color_by - @color_by.setter def color_by(self, color_by): cv.check_value('plot color_by', color_by, ['cell', 'material']) self._color_by = color_by - @property - def background(self): - return self._background + @type.setter + def type(self, plottype): + cv.check_value('plot type', plottype, ['slice', 'voxel']) + self._type = plottype + + @basis.setter + def basis(self, basis): + cv.check_value('plot basis', basis, _BASES) + self._basis = basis @background.setter def background(self, background): self._check_color('plot background', background) self._background = background - @property - def mask_components(self): - return self._mask_components - - @mask_components.setter - def mask_components(self, mask_components): - cv.check_type('plot mask components', mask_components, Iterable, - (openmc.Cell, openmc.Material, Integral)) - self._mask_components = mask_components - - @property - def mask_background(self): - return self._mask_background - - @mask_background.setter - def mask_background(self, mask_background): - self._check_color('plot mask background', mask_background) - self._mask_background = mask_background - - @property - def show_overlaps(self): - return self._show_overlaps - - @show_overlaps.setter - def show_overlaps(self, show_overlaps): - cv.check_type(f'Show overlaps flag for Plot ID="{self.id}"', - show_overlaps, bool) - self._show_overlaps = show_overlaps - - @property - def overlap_color(self): - return self._overlap_color - - @overlap_color.setter - def overlap_color(self, overlap_color): - self._check_color('plot overlap color', overlap_color) - self._overlap_color = overlap_color - - @property - def colors(self): - return self._colors - @colors.setter def colors(self, colors): cv.check_type('plot colors', colors, Mapping) @@ -592,9 +380,27 @@ class PlotBase(IDManagerMixin): self._check_color('plot color value', value) self._colors = colors - @property - def level(self): - return self._level + @mask_components.setter + def mask_components(self, mask_components): + cv.check_type('plot mask components', mask_components, Iterable, + (openmc.Cell, openmc.Material, Integral)) + self._mask_components = mask_components + + @mask_background.setter + def mask_background(self, mask_background): + self._check_color('plot mask background', mask_background) + self._mask_background = mask_background + + @show_overlaps.setter + def show_overlaps(self, show_overlaps): + cv.check_type(f'Show overlaps flag for Plot ID="{self.id}"', + show_overlaps, bool) + self._show_overlaps = show_overlaps + + @overlap_color.setter + def overlap_color(self, overlap_color): + self._check_color('plot overlap color', overlap_color) + self._overlap_color = overlap_color @level.setter def level(self, plot_level): @@ -602,6 +408,34 @@ class PlotBase(IDManagerMixin): cv.check_greater_than('plot level', plot_level, 0, equality=True) self._level = plot_level + @meshlines.setter + def meshlines(self, meshlines): + cv.check_type('plot meshlines', meshlines, dict) + if 'type' not in meshlines: + msg = f'Unable to set the meshlines to "{meshlines}" which ' \ + 'does not have a "type" key' + raise ValueError(msg) + + elif meshlines['type'] not in ['tally', 'entropy', 'ufs', 'cmfd']: + msg = 'Unable to set the meshlines with ' \ + 'type "{}"'.format(meshlines['type']) + raise ValueError(msg) + + if 'id' in meshlines: + cv.check_type('plot meshlines id', meshlines['id'], Integral) + cv.check_greater_than('plot meshlines id', meshlines['id'], 0, + equality=True) + + if 'linewidth' in meshlines: + cv.check_type('plot mesh linewidth', meshlines['linewidth'], Integral) + cv.check_greater_than('plot mesh linewidth', meshlines['linewidth'], + 0, equality=True) + + if 'color' in meshlines: + self._check_color('plot meshlines color', meshlines['color']) + + self._meshlines = meshlines + @staticmethod def _check_color(err_string, color): cv.check_type(err_string, color, Iterable) @@ -615,256 +449,12 @@ class PlotBase(IDManagerMixin): cv.check_greater_than('RGB component', rgb, 0, True) cv.check_less_than('RGB component', rgb, 256) - # Helper function that returns the domain ID given either a - # Cell/Material object or the domain ID itself - @staticmethod - def _get_id(domain): - return domain if isinstance(domain, Integral) else domain.id - - def colorize(self, geometry, seed=1): - """Generate a color scheme for each domain in the plot. - - This routine may be used to generate random, reproducible color schemes. - The colors generated are based upon cell/material IDs in the geometry. - - Parameters - ---------- - geometry : openmc.Geometry - The geometry for which the plot is defined - seed : Integral - The random number seed used to generate the color scheme - - """ - - cv.check_type('geometry', geometry, openmc.Geometry) - cv.check_type('seed', seed, Integral) - cv.check_greater_than('seed', seed, 1, equality=True) - - # Get collections of the domains which will be plotted - if self.color_by == 'material': - domains = geometry.get_all_materials().values() - else: - domains = geometry.get_all_cells().values() - - rng = np.random.RandomState(seed) - - # Generate random colors for each feature - for domain in domains: - self.colors[domain] = rng.randint(0, 256, (3,)) - - def _colors_to_xml(self, element): - for domain, color in sorted(self._colors.items(), - key=lambda x: self._get_id(x[0])): - subelement = ET.SubElement(element, "color") - subelement.set("id", str(self._get_id(domain))) - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.set("rgb", ' '.join(str(x) for x in color)) - - def to_xml_element(self): - """Save common plot attributes to XML element - - Returns - ------- - element : lxml.etree._Element - XML element containing plot data - - """ - - element = ET.Element("plot") - element.set("id", str(self._id)) - if len(self._name) > 0: - element.set("name", str(self.name)) - if self._filename is not None: - element.set("filename", self._filename) - element.set("color_by", self._color_by) - - subelement = ET.SubElement(element, "pixels") - subelement.text = ' '.join(map(str, self._pixels)) - - if self._background is not None: - subelement = ET.SubElement(element, "background") - color = self._background - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.text = ' '.join(str(x) for x in color) - - if self._mask_components is not None: - subelement = ET.SubElement(element, "mask") - subelement.set("components", ' '.join( - str(PlotBase._get_id(d)) for d in self._mask_components)) - color = self._mask_background - if color is not None: - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.set("background", ' '.join( - str(x) for x in color)) - - if self._level is not None: - subelement = ET.SubElement(element, "level") - subelement.text = str(self._level) - - return element - - -class SlicePlot(PlotBase): - """Definition of a 2D slice plot of the geometry. - - Colors that are used in plots can be given as RGB tuples, e.g. - (255, 255, 255) would be white, or by a string indicating a - valid `SVG color `_. - - .. versionadded:: 0.15.4 - - Parameters - ---------- - plot_id : int - Unique identifier for the plot - name : str - Name of the plot - - Attributes - ---------- - id : int - Unique identifier - name : str - Name of the plot - pixels : Iterable of int - Number of pixels to use in each direction (2 values) - filename : str - Path to write the plot to - color_by : {'cell', 'material'} - Indicate whether the plot should be colored by cell or by material - background : Iterable of int or str - Color of the background - mask_components : Iterable of openmc.Cell or openmc.Material or int - The cells or materials (or corresponding IDs) to mask - mask_background : Iterable of int or str - Color to apply to all cells/materials listed in mask_components - show_overlaps : bool - Indicate whether or not overlapping regions are shown - overlap_color : Iterable of int or str - Color to apply to overlapping regions - colors : dict - Dictionary indicating that certain cells/materials should be - displayed with a particular color. The keys can be of type - :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a - cell/material). - level : int - Universe depth to plot at - width : Iterable of float - Width of the plot in each basis direction (2 values) - origin : tuple or list of ndarray - Origin (center) of the plot (3 values) - basis : {'xy', 'xz', 'yz'} - The basis directions for the plot - meshlines : dict - Dictionary defining type, id, linewidth and color of a mesh to be - plotted on top of a plot - - """ - - def __init__(self, plot_id=None, name=''): - super().__init__(plot_id, name) - self._width = [4.0, 4.0] - self._origin = [0., 0., 0.] - self._basis = 'xy' - self._meshlines = None - - @property - def type(self): - warnings.warn( - "The 'type' attribute is deprecated and will be removed in a future version. " - "This is a SlicePlot instance.", - FutureWarning, stacklevel=2 - ) - return 'slice' - - @type.setter - def type(self, value): - raise TypeError( - "Setting plot.type is no longer supported. " - "Use openmc.SlicePlot() for 2D slice plots or openmc.VoxelPlot() for 3D voxel plots." - ) - - @property - def pixels(self): - return self._pixels - - @pixels.setter - def pixels(self, pixels): - cv.check_type('plot pixels', pixels, Iterable, Integral) - cv.check_length('plot pixels', pixels, 2, 2) - for dim in pixels: - cv.check_greater_than('plot pixels', dim, 0) - self._pixels = pixels - - @property - def width(self): - return self._width - - @width.setter - def width(self, width): - cv.check_type('plot width', width, Iterable, Real) - cv.check_length('plot width', width, 2, 2) - self._width = width - - @property - def origin(self): - return self._origin - - @origin.setter - def origin(self, origin): - cv.check_type('plot origin', origin, Iterable, Real) - cv.check_length('plot origin', origin, 3) - self._origin = origin - - @property - def basis(self): - return self._basis - - @basis.setter - def basis(self, basis): - cv.check_value('plot basis', basis, _BASES) - self._basis = basis - - @property - def meshlines(self): - return self._meshlines - - @meshlines.setter - def meshlines(self, meshlines): - cv.check_type('plot meshlines', meshlines, dict) - if 'type' not in meshlines: - msg = f'Unable to set the meshlines to "{meshlines}" which ' \ - 'does not have a "type" key' - raise ValueError(msg) - - elif meshlines['type'] not in ['tally', 'entropy', 'ufs', 'cmfd']: - msg = f"Unable to set the meshlines with type \"{meshlines['type']}\"" - raise ValueError(msg) - - if 'id' in meshlines: - cv.check_type('plot meshlines id', meshlines['id'], Integral) - cv.check_greater_than('plot meshlines id', meshlines['id'], 0, - equality=True) - - if 'linewidth' in meshlines: - cv.check_type('plot mesh linewidth', - meshlines['linewidth'], Integral) - cv.check_greater_than('plot mesh linewidth', meshlines['linewidth'], - 0, equality=True) - - if 'color' in meshlines: - self._check_color('plot meshlines color', meshlines['color']) - - self._meshlines = meshlines - def __repr__(self): - string = 'SlicePlot\n' + string = 'Plot\n' string += '{: <16}=\t{}\n'.format('\tID', self._id) string += '{: <16}=\t{}\n'.format('\tName', self._name) string += '{: <16}=\t{}\n'.format('\tFilename', self._filename) + string += '{: <16}=\t{}\n'.format('\tType', self._type) string += '{: <16}=\t{}\n'.format('\tBasis', self._basis) string += '{: <16}=\t{}\n'.format('\tWidth', self._width) string += '{: <16}=\t{}\n'.format('\tOrigin', self._origin) @@ -928,6 +518,38 @@ class SlicePlot(PlotBase): plot.basis = basis return plot + def colorize(self, geometry, seed=1): + """Generate a color scheme for each domain in the plot. + + This routine may be used to generate random, reproducible color schemes. + The colors generated are based upon cell/material IDs in the geometry. + + Parameters + ---------- + geometry : openmc.Geometry + The geometry for which the plot is defined + seed : Integral + The random number seed used to generate the color scheme + + """ + + cv.check_type('geometry', geometry, openmc.Geometry) + cv.check_type('seed', seed, Integral) + cv.check_greater_than('seed', seed, 1, equality=True) + + # Get collections of the domains which will be plotted + if self.color_by == 'material': + domains = geometry.get_all_materials().values() + else: + domains = geometry.get_all_cells().values() + + # Set the seed for the random number generator + np.random.seed(seed) + + # Generate random colors for each feature + for domain in domains: + self.colors[domain] = np.random.randint(0, 256, (3,)) + def highlight_domains(self, geometry, domains, seed=1, alpha=0.5, background='gray'): """Use alpha compositing to highlight one or more domains in the plot. @@ -980,18 +602,24 @@ class SlicePlot(PlotBase): self._colors[domain] = (r, g, b) def to_xml_element(self): - """Return XML representation of the slice plot + """Return XML representation of the plot Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing plot data """ - element = super().to_xml_element() - element.set("type", "slice") - element.set("basis", self._basis) + element = ET.Element("plot") + element.set("id", str(self._id)) + if self._filename is not None: + element.set("filename", self._filename) + element.set("color_by", self._color_by) + element.set("type", self._type) + + if self._type == 'slice': + element.set("basis", self._basis) subelement = ET.SubElement(element, "origin") subelement.text = ' '.join(map(str, self._origin)) @@ -999,8 +627,40 @@ class SlicePlot(PlotBase): subelement = ET.SubElement(element, "width") subelement.text = ' '.join(map(str, self._width)) + subelement = ET.SubElement(element, "pixels") + subelement.text = ' '.join(map(str, self._pixels)) + + if self._background is not None: + subelement = ET.SubElement(element, "background") + color = self._background + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.text = ' '.join(str(x) for x in color) + + # Helper function that returns the domain ID given either a + # Cell/Material object or the domain ID itself + def get_id(domain): + return domain if isinstance(domain, Integral) else domain.id + if self._colors: - self._colors_to_xml(element) + for domain, color in sorted(self._colors.items(), + key=lambda x: get_id(x[0])): + subelement = ET.SubElement(element, "color") + subelement.set("id", str(get_id(domain))) + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.set("rgb", ' '.join(str(x) for x in color)) + + if self._mask_components is not None: + subelement = ET.SubElement(element, "mask") + subelement.set("components", ' '.join( + str(get_id(d)) for d in self._mask_components)) + color = self._mask_background + if color is not None: + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.set("background", ' '.join( + str(x) for x in color)) if self._show_overlaps: subelement = ET.SubElement(element, "show_overlaps") @@ -1013,14 +673,19 @@ class SlicePlot(PlotBase): subelement = ET.SubElement(element, "overlap_color") subelement.text = ' '.join(str(x) for x in color) + + if self._level is not None: + subelement = ET.SubElement(element, "level") + subelement.text = str(self._level) + if self._meshlines is not None: subelement = ET.SubElement(element, "meshlines") subelement.set("meshtype", self._meshlines['type']) - if 'id' in self._meshlines: + if self._meshlines['id'] is not None: subelement.set("id", str(self._meshlines['id'])) - if 'linewidth' in self._meshlines: + if self._meshlines['linewidth'] is not None: subelement.set("linewidth", str(self._meshlines['linewidth'])) - if 'color' in self._meshlines: + if self._meshlines['color'] is not None: subelement.set("color", ' '.join(map( str, self._meshlines['color']))) @@ -1032,68 +697,74 @@ class SlicePlot(PlotBase): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns ------- - openmc.SlicePlot - SlicePlot object + openmc.Plot + Plot object """ - plot_id = int(get_text(elem, "id")) - name = get_text(elem, 'name', '') - plot = cls(plot_id, name) + plot_id = int(elem.get("id")) + plot = cls(plot_id) if "filename" in elem.keys(): - plot.filename = get_text(elem, "filename") - plot.color_by = get_text(elem, "color_by") - plot.basis = get_text(elem, "basis") + plot.filename = elem.get("filename") + plot.color_by = elem.get("color_by") + plot.type = elem.get("type") + plot.basis = elem.get("basis") - plot.origin = tuple(get_elem_list(elem, "origin", float)) - plot.width = tuple(get_elem_list(elem, "width", float)) - plot.pixels = tuple(get_elem_list(elem, "pixels")) - background = get_elem_list(elem, "background") - if background is not None: - plot._background = tuple(background) + # Helper function to get a tuple of values + def get_tuple(elem, name, dtype=int): + subelem = elem.find(name) + if subelem is not None: + return tuple([dtype(x) for x in subelem.text.split()]) + + plot.origin = get_tuple(elem, "origin", float) + plot.width = get_tuple(elem, "width", float) + plot.pixels = get_tuple(elem, "pixels") + plot._background = get_tuple(elem, "background") # Set plot colors colors = {} for color_elem in elem.findall("color"): - uid = int(get_text(color_elem, "id")) - colors[uid] = tuple(get_elem_list(color_elem, "rgb", int)) + uid = int(color_elem.get("id")) + colors[uid] = tuple([int(x) for x in color_elem.get("rgb").split()]) plot.colors = colors # Set masking information mask_elem = elem.find("mask") if mask_elem is not None: - plot.mask_components = get_elem_list(mask_elem, "components", int) - background = get_elem_list(mask_elem, "background", int) + plot.mask_components = [int(x) for x in mask_elem.get("components").split()] + background = mask_elem.get("background") if background is not None: - plot.mask_background = tuple(background) + plot.mask_background = tuple([int(x) for x in background.split()]) # show overlaps - overlap = get_text(elem, "show_overlaps") - if overlap is not None: - plot.show_overlaps = (overlap in ('true', '1')) - overlap_color = get_elem_list(elem, "overlap_color", int) + overlap_elem = elem.find("show_overlaps") + if overlap_elem is not None: + plot.show_overlaps = (overlap_elem.text in ('true', '1')) + overlap_color = get_tuple(elem, "overlap_color") if overlap_color is not None: - plot.overlap_color = tuple(overlap_color) + plot.overlap_color = overlap_color # Set universe level - level = get_text(elem, "level") + level = elem.find("level") if level is not None: - plot.level = int(level) + plot.level = int(level.text) # Set meshlines mesh_elem = elem.find("meshlines") if mesh_elem is not None: - meshlines = {'type': get_text(mesh_elem, "meshtype")} + meshlines = {'type': mesh_elem.get('meshtype')} if 'id' in mesh_elem.keys(): - meshlines['id'] = int(get_text(mesh_elem, "id")) + meshlines['id'] = int(mesh_elem.get('id')) if 'linewidth' in mesh_elem.keys(): - meshlines['linewidth'] = int(get_text(mesh_elem, "linewidth")) + meshlines['linewidth'] = int(mesh_elem.get('linewidth')) if 'color' in mesh_elem.keys(): - meshlines['color'] = tuple(get_elem_list(mesh_elem, "color", int)) + meshlines['color'] = tuple( + [int(x) for x in mesh_elem.get('color').split()] + ) plot.meshlines = meshlines return plot @@ -1130,945 +801,29 @@ class SlicePlot(PlotBase): return _get_plot_image(self, cwd) - -class VoxelPlot(PlotBase): - """Definition of a 3D voxel plot of the geometry. - - Colors that are used in plots can be given as RGB tuples, e.g. - (255, 255, 255) would be white, or by a string indicating a - valid `SVG color `_. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - plot_id : int - Unique identifier for the plot - name : str - Name of the plot - - Attributes - ---------- - id : int - Unique identifier - name : str - Name of the plot - pixels : Iterable of int - Number of pixels to use in each direction (3 values) - filename : str - Path to write the plot to - color_by : {'cell', 'material'} - Indicate whether the plot should be colored by cell or by material - background : Iterable of int or str - Color of the background - mask_components : Iterable of openmc.Cell or openmc.Material or int - The cells or materials (or corresponding IDs) to mask - mask_background : Iterable of int or str - Color to apply to all cells/materials listed in mask_components - show_overlaps : bool - Indicate whether or not overlapping regions are shown - overlap_color : Iterable of int or str - Color to apply to overlapping regions - colors : dict - Dictionary indicating that certain cells/materials should be - displayed with a particular color. The keys can be of type - :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a - cell/material). - level : int - Universe depth to plot at - width : Iterable of float - Width of the plot in each dimension (3 values) - origin : tuple or list of ndarray - Origin (center) of the plot (3 values) - - """ - - def __init__(self, plot_id=None, name=''): - super().__init__(plot_id, name) - self._width = [4.0, 4.0, 4.0] - self._origin = [0., 0., 0.] - self._pixels = [400, 400, 400] - - @property - def pixels(self): - return self._pixels - - @pixels.setter - def pixels(self, pixels): - cv.check_type('plot pixels', pixels, Iterable, Integral) - cv.check_length('plot pixels', pixels, 3, 3) - for dim in pixels: - cv.check_greater_than('plot pixels', dim, 0) - self._pixels = pixels - - @property - def width(self): - return self._width - - @width.setter - def width(self, width): - cv.check_type('plot width', width, Iterable, Real) - cv.check_length('plot width', width, 3, 3) - self._width = width - - @property - def origin(self): - return self._origin - - @origin.setter - def origin(self, origin): - cv.check_type('plot origin', origin, Iterable, Real) - cv.check_length('plot origin', origin, 3) - self._origin = origin - - def __repr__(self): - string = 'VoxelPlot\n' - string += '{: <16}=\t{}\n'.format('\tID', self._id) - string += '{: <16}=\t{}\n'.format('\tName', self._name) - string += '{: <16}=\t{}\n'.format('\tFilename', self._filename) - string += '{: <16}=\t{}\n'.format('\tWidth', self._width) - string += '{: <16}=\t{}\n'.format('\tOrigin', self._origin) - string += '{: <16}=\t{}\n'.format('\tPixels', self._pixels) - string += '{: <16}=\t{}\n'.format('\tColor by', self._color_by) - string += '{: <16}=\t{}\n'.format('\tBackground', self._background) - string += '{: <16}=\t{}\n'.format('\tMask components', - self._mask_components) - string += '{: <16}=\t{}\n'.format('\tMask background', - self._mask_background) - string += '{: <16}=\t{}\n'.format('\tOverlap Color', - self._overlap_color) - string += '{: <16}=\t{}\n'.format('\tColors', self._colors) - string += '{: <16}=\t{}\n'.format('\tLevel', self._level) - return string - - def to_xml_element(self): - """Return XML representation of the voxel plot - - Returns - ------- - element : lxml.etree._Element - XML element containing plot data - - """ - - element = super().to_xml_element() - element.set("type", "voxel") - - subelement = ET.SubElement(element, "origin") - subelement.text = ' '.join(map(str, self._origin)) - - subelement = ET.SubElement(element, "width") - subelement.text = ' '.join(map(str, self._width)) - - if self._colors: - self._colors_to_xml(element) - - if self._show_overlaps: - subelement = ET.SubElement(element, "show_overlaps") - subelement.text = "true" - - if self._overlap_color is not None: - color = self._overlap_color - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement = ET.SubElement(element, "overlap_color") - subelement.text = ' '.join(str(x) for x in color) - - return element - - @classmethod - def from_xml_element(cls, elem): - """Generate plot object from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.VoxelPlot - VoxelPlot object - - """ - plot_id = int(get_text(elem, "id")) - name = get_text(elem, 'name', '') - plot = cls(plot_id, name) - if "filename" in elem.keys(): - plot.filename = get_text(elem, "filename") - plot.color_by = get_text(elem, "color_by") - - plot.origin = tuple(get_elem_list(elem, "origin", float)) - plot.width = tuple(get_elem_list(elem, "width", float)) - plot.pixels = tuple(get_elem_list(elem, "pixels")) - background = get_elem_list(elem, "background") - if background is not None: - plot._background = tuple(background) - - # Set plot colors - colors = {} - for color_elem in elem.findall("color"): - uid = int(get_text(color_elem, "id")) - colors[uid] = tuple(get_elem_list(color_elem, "rgb", int)) - plot.colors = colors - - # Set masking information - mask_elem = elem.find("mask") - if mask_elem is not None: - plot.mask_components = get_elem_list(mask_elem, "components", int) - background = get_elem_list(mask_elem, "background", int) - if background is not None: - plot.mask_background = tuple(background) - - # show overlaps - overlap = get_text(elem, "show_overlaps") - if overlap is not None: - plot.show_overlaps = (overlap in ('true', '1')) - overlap_color = get_elem_list(elem, "overlap_color", int) - if overlap_color is not None: - plot.overlap_color = tuple(overlap_color) - - # Set universe level - level = get_text(elem, "level") - if level is not None: - plot.level = int(level) - - return plot - - def to_vtk(self, output: PathLike | None = None, - openmc_exec: str = 'openmc', cwd: str = '.'): - """Render plot as a voxel image - - This method runs OpenMC in plotting mode to produce a .vti file. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - output : path-like - Path of the output .vti file produced - openmc_exec : str - Path to OpenMC executable - cwd : str, optional - Path to working directory to run in - - Returns - ------- - Path - Path of the .vti file produced - - """ - # Create plots.xml - Plots([self]).export_to_xml(cwd) - - # Run OpenMC in geometry plotting mode and produces a h5 file - openmc.plot_geometry(False, openmc_exec, cwd) - - h5_voxel_filename = self.filename if self.filename is not None else f'plot_{self.id}' - - # Add file extension if not already present - if Path(h5_voxel_filename).suffix != ".h5": - h5_voxel_filename += ".h5" - - h5_voxel_file = Path(cwd) / h5_voxel_filename - if output is None: - output = h5_voxel_file.with_suffix('.vti') - - return voxel_to_vtk(h5_voxel_file, output) - - -def Plot(plot_id=None, name=''): - """Legacy Plot class for backward compatibility. - - .. deprecated:: 0.15.4 - Use :class:`SlicePlot` for 2D slice plots or :class:`VoxelPlot` for 3D voxel plots. - - """ - warnings.warn( - "The Plot class is deprecated. Use SlicePlot for 2D slice plots " - "or VoxelPlot for 3D voxel plots.", FutureWarning - ) - return SlicePlot(plot_id, name) - - -class RayTracePlot(PlotBase): - """Definition of a camera's view of OpenMC geometry - - The camera projection may either by orthographic or perspective. Perspective - projections are more similar to a pinhole camera, and orthographic - projections preserve parallel lines and distances. - - This is an abstract base class that :class:`WireframeRayTracePlot` and - :class:`SolidRayTracePlot` finish the implementation of. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - plot_id : int - Unique identifier for the plot - name : str - Name of the plot - - Attributes - ---------- - horizontal_field_of_view : float - Field of view horizontally, in units of degrees, defaults to 70. - camera_position : tuple or list of ndarray - Position of the camera in 3D space. Defaults to (1, 0, 0). - look_at : tuple or list of ndarray - The center of the camera's image points to this place in 3D space. - Set to (0, 0, 0) by default. - up : tuple or list of ndarray - Which way is up for the camera. Must not be parallel to the - line between look_at and camera_position. Set to (0, 0, 1) by default. - orthographic_width : float - If set to a nonzero value, an orthographic projection is used. - All rays traced from the orthographic pixel array travel in the - same direction. The width of the starting array must be specified, - unlike with the default perspective projection. The height of the - array is deduced from the ratio of pixel dimensions for the image. - Defaults to zero, i.e. using perspective projection. - """ - - def __init__(self, plot_id=None, name=''): - # Initialize Plot class attributes - super().__init__(plot_id, name) - self._horizontal_field_of_view = 70.0 - self._camera_position = (1.0, 0.0, 0.0) - self._look_at = (0.0, 0.0, 0.0) - self._up = (0.0, 0.0, 1.0) - self._orthographic_width = 0.0 - - @property - def horizontal_field_of_view(self): - return self._horizontal_field_of_view - - @horizontal_field_of_view.setter - def horizontal_field_of_view(self, horizontal_field_of_view): - cv.check_type('plot horizontal field of view', horizontal_field_of_view, - Real) - assert horizontal_field_of_view > 0.0 - assert horizontal_field_of_view < 180.0 - self._horizontal_field_of_view = horizontal_field_of_view - - @property - def camera_position(self): - return self._camera_position - - @camera_position.setter - def camera_position(self, camera_position): - cv.check_type('plot camera position', camera_position, Iterable, Real) - cv.check_length('plot camera position', camera_position, 3) - self._camera_position = camera_position - - @property - def look_at(self): - return self._look_at - - @look_at.setter - def look_at(self, look_at): - cv.check_type('plot look at', look_at, Iterable, Real) - cv.check_length('plot look at', look_at, 3) - self._look_at = look_at - - @property - def up(self): - return self._up - - @up.setter - def up(self, up): - cv.check_type('plot up', up, Iterable, Real) - cv.check_length('plot up', up, 3) - self._up = up - - @property - def orthographic_width(self): - return self._orthographic_width - - @orthographic_width.setter - def orthographic_width(self, orthographic_width): - cv.check_type('plot orthographic width', orthographic_width, Real) - assert orthographic_width >= 0.0 - self._orthographic_width = orthographic_width - - def _check_domains_consistent_with_color_by(self, domains): - """Check domains are the same as the type we are coloring by""" - for region in domains: - # if an integer is passed, we have to assume it was a valid ID - if isinstance(region, int): - continue - - if self._color_by == 'material': - if not isinstance(region, openmc.Material): - raise Exception('Domain list must be materials if ' - 'color_by=material') - else: - if not isinstance(region, openmc.Cell): - raise Exception('Domain list must be cells if ' - 'color_by=cell') - - def to_xml_element(self): - """Return XML representation of the ray trace plot - - Returns - ------- - element : lxml.etree._Element - XML element containing plot data - - """ - - element = super().to_xml_element() - element.set("id", str(self._id)) - - subelement = ET.SubElement(element, "camera_position") - subelement.text = ' '.join(map(str, self._camera_position)) - - subelement = ET.SubElement(element, "look_at") - subelement.text = ' '.join(map(str, self._look_at)) - - subelement = ET.SubElement(element, "horizontal_field_of_view") - subelement.text = str(self._horizontal_field_of_view) - - # do not need to write if orthographic_width == 0.0 - if self._orthographic_width > 0.0: - subelement = ET.SubElement(element, "orthographic_width") - subelement.text = str(self._orthographic_width) - - return element - - def __repr__(self): - string = '' - string += '{: <16}=\t{}\n'.format('\tID', self._id) - string += '{: <16}=\t{}\n'.format('\tName', self._name) - string += '{: <16}=\t{}\n'.format('\tFilename', self._filename) - string += '{: <16}=\t{}\n'.format('\tHorizontal FOV', - self._horizontal_field_of_view) - string += '{: <16}=\t{}\n'.format('\tOrthographic width', - self._orthographic_width) - string += '{: <16}=\t{}\n'.format('\tCamera position', - self._camera_position) - string += '{: <16}=\t{}\n'.format('\tLook at', self._look_at) - string += '{: <16}=\t{}\n'.format('\tUp', self._up) - string += '{: <16}=\t{}\n'.format('\tPixels', self._pixels) - string += '{: <16}=\t{}\n'.format('\tColor by', self._color_by) - string += '{: <16}=\t{}\n'.format('\tBackground', self._background) - string += '{: <16}=\t{}\n'.format('\tColors', self._colors) - string += '{: <16}=\t{}\n'.format('\tLevel', self._level) - return string - - def _read_xml_attributes(self, elem): - """Helper function called by from_xml_element - of child classes. These are common vaues to be - read by any ray traced plot. - - Returns - ------- - None - """ - - filename = get_text(elem, "filename") - if filename is not None: - self.filename = filename - self.color_by = get_text(elem, "color_by") - - horizontal_fov = get_text(elem, "horizontal_field_of_view") - if horizontal_fov is not None: - self.horizontal_field_of_view = float(horizontal_fov) - - orthographic_width = get_text(elem, "orthographic_width") - if orthographic_width is not None: - self.orthographic_width = float(orthographic_width) - - self.pixels = tuple(get_elem_list(elem, "pixels", int)) - self.camera_position = tuple(get_elem_list(elem, "camera_position", float)) - self.look_at = tuple(get_elem_list(elem, "look_at", float)) - - background = get_elem_list(elem, "background", int) - if background is not None: - self.background = tuple(background) - - # Set masking information - if (mask_elem := elem.find("mask")) is not None: - mask_components = get_elem_list(mask_elem, "components", int) - # TODO: set mask components(needs geometry information) - background = get_elem_list(mask_elem, "background", int) - if background is not None: - self.mask_background = tuple(background) - - # Set universe level - level = get_text(elem, "level") - if level is not None: - self.level = int(level) - - -class WireframeRayTracePlot(RayTracePlot): - """Plots wireframes of geometry with volume rendered colors - - Colors are defined in the same manner as the Plot class, but with the - addition of a coloring parameter resembling a macroscopic cross section in - units of inverse centimeters. The volume rendering technique is used to - color regions of the model. An infinite cross section denotes a fully opaque - region, and zero represents a transparent region which will expose the color - of the regions behind it. - - .. versionchanged:: 0.15.1 - Renamed from ProjectionPlot to WireframeRayTracePlot - - Parameters - ---------- - plot_id : int - Unique identifier for the plot - name : str - Name of the plot - - Attributes - ---------- - id : int - Unique identifier - name : str - Name of the plot - pixels : Iterable of int - Number of pixels to use in each direction - filename : str - Path to write the plot to - color_by : {'cell', 'material'} - Indicate whether the plot should be colored by cell or by material - background : Iterable of int or str - Color of the background - mask_components : Iterable of openmc.Cell or openmc.Material or int - The cells or materials (or corresponding IDs) to mask - mask_background : Iterable of int or str - Color to apply to all cells/materials listed in mask_components - show_overlaps : bool - Indicate whether or not overlapping regions are shown - overlap_color : Iterable of int or str - Color to apply to overlapping regions - colors : dict - Dictionary indicating that certain cells/materials should be - displayed with a particular color. The keys can be of type - :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a - cell/material). - level : int - Universe depth to plot at - horizontal_field_of_view : float - Field of view horizontally, in units of degrees, defaults to 70. - camera_position : tuple or list of ndarray - Position of the camera in 3D space. Defaults to (1, 0, 0). - look_at : tuple or list of ndarray - The center of the camera's image points to this place in 3D space. - Set to (0, 0, 0) by default. - up : tuple or list of ndarray - Which way is up for the camera. Must not be parallel to the - line between look_at and camera_position. Set to (0, 0, 1) by default. - orthographic_width : float - If set to a nonzero value, an orthographic projection is used. - All rays traced from the orthographic pixel array travel in the - same direction. The width of the starting array must be specified, - unlike with the default perspective projection. The height of the - array is deduced from the ratio of pixel dimensions for the image. - Defaults to zero, i.e. using perspective projection. - wireframe_thickness : int - Line thickness employed for drawing wireframes around cells or material - regions. Can be set to zero for no wireframes at all. Defaults to one - pixel. - wireframe_color : tuple of ints - RGB color of the wireframe lines. Defaults to black. - wireframe_domains : iterable of either Material or Cells - If provided, the wireframe is only drawn around these. If color_by is by - material, it must be a list of materials, else cells. - xs : dict - A mapping from cell/material IDs to floats. The floating point values - are macroscopic cross sections influencing the volume rendering opacity - of each geometric region. Zero corresponds to perfect transparency, and - infinity equivalent to opaque. These must be set by the user, but - default values can be obtained using the :meth:`set_transparent` method. - """ - - def __init__(self, plot_id=None, name=''): - super().__init__(plot_id, name) - self._wireframe_thickness = 1 - self._wireframe_color = _SVG_COLORS['black'] - self._wireframe_domains = [] - self._xs = {} - - @property - def wireframe_thickness(self): - return self._wireframe_thickness - - @wireframe_thickness.setter - def wireframe_thickness(self, wireframe_thickness): - cv.check_type('plot wireframe thickness', - wireframe_thickness, Integral) - assert wireframe_thickness >= 0 - self._wireframe_thickness = wireframe_thickness - - @property - def wireframe_color(self): - return self._wireframe_color - - @wireframe_color.setter - def wireframe_color(self, wireframe_color): - self._check_color('plot wireframe color', wireframe_color) - self._wireframe_color = wireframe_color - - @property - def wireframe_domains(self): - return self._wireframe_domains - - @wireframe_domains.setter - def wireframe_domains(self, wireframe_domains): - self._wireframe_domains = wireframe_domains - - @property - def xs(self): - return self._xs - - @xs.setter - def xs(self, xs): - cv.check_type('plot xs', xs, Mapping) - for key, value in xs.items(): - cv.check_type('plot xs key', key, (openmc.Cell, openmc.Material)) - cv.check_type('plot xs value', value, Real) - assert value >= 0.0 - self._xs = xs - - def set_transparent(self, geometry): - """Sets all volume rendering XS to zero for the model - - Parameters - ---------- - geometry : openmc.Geometry - The geometry for which the plot is defined - """ - - cv.check_type('geometry', geometry, openmc.Geometry) - - # Get collections of the domains which will be plotted - if self.color_by == 'material': - domains = geometry.get_all_materials().values() - else: - domains = geometry.get_all_cells().values() - - # Generate random colors for each feature - for domain in domains: - self.xs[domain] = 0.0 - - def __repr__(self): - string = 'Wireframe Ray-traced Plot\n' - string += super().__repr__() - string += '{: <16}=\t{}\n'.format('\tWireframe thickness', - self._wireframe_thickness) - string += '{: <16}=\t{}\n'.format('\tWireframe color', - self._wireframe_color) - string += '{: <16}=\t{}\n'.format('\tWireframe domains', - self._wireframe_domains) - string += '{: <16}=\t{}\n'.format('\tTransparencies', self._xs) - return string - - def to_xml_element(self): - """Return XML representation of the projection plot - - Returns - ------- - element : lxml.etree._Element - XML element containing plot data - - """ - element = super().to_xml_element() - element.set("type", "wireframe_raytrace") - - subelement = ET.SubElement(element, "wireframe_thickness") - subelement.text = str(self._wireframe_thickness) - - subelement = ET.SubElement(element, "wireframe_color") - color = self._wireframe_color - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.text = ' '.join(str(x) for x in color) - - self._check_domains_consistent_with_color_by(self.wireframe_domains) - - if self._wireframe_domains: - id_list = [x.id for x in self._wireframe_domains] - subelement = ET.SubElement(element, "wireframe_ids") - subelement.text = ' '.join([str(x) for x in id_list]) - - # note that this differs from the slice plot colors - # in that "xs" must also be specified - if self._colors: - for domain, color in sorted(self._colors.items(), - key=lambda x: x[0].id): - subelement = ET.SubElement(element, "color") - subelement.set("id", str(domain.id)) - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.set("rgb", ' '.join(str(x) for x in color)) - subelement.set("xs", str(self._xs[domain])) - - return element - - @classmethod - def from_xml_element(cls, elem): - """Generate plot object from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.WireframeRayTracePlot - WireframeRayTracePlot object - - """ - - plot_id = int(get_text(elem, "id")) - plot_name = get_text(elem, 'name', '') - plot = cls(plot_id, plot_name) - plot.type = "wireframe_raytrace" - - plot._read_xml_attributes(elem) - - # Attempt to get wireframe thickness.May not be present - wireframe_thickness = get_text(elem, "wireframe_thickness") - if wireframe_thickness is not None: - plot.wireframe_thickness = int(wireframe_thickness) - wireframe_color = get_elem_list(elem, "wireframe_color", int) - if wireframe_color: - plot.wireframe_color = wireframe_color - - # Set plot colors - for color_elem in elem.findall("color"): - uid = int(get_text(color_elem, "id")) - plot.colors[uid] = tuple(get_elem_list(color_elem, "rgb", int)) - plot.xs[uid] = float(get_text(color_elem, "xs")) - - return plot - - -class SolidRayTracePlot(RayTracePlot): - """Phong shading-based rendering of an OpenMC geometry - - This class defines a plot that uses Phong shading to enhance the - visualization of an OpenMC geometry by incorporating diffuse lighting and - configurable opacity for certain regions. It extends :class:`RayTracePlot` - by adding parameters related to lighting and transparency. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - plot_id : int, optional - Unique identifier for the plot - name : str, optional - Name of the plot - - Attributes - ---------- - id : int - Unique identifier - name : str - Name of the plot - pixels : Iterable of int - Number of pixels to use in each direction - filename : str - Path to write the plot to - color_by : {'cell', 'material'} - Indicate whether the plot should be colored by cell or by material - overlap_color : Iterable of int or str - Color to apply to overlapping regions - colors : dict - Dictionary indicating that certain cells/materials should be - displayed with a particular color. The keys can be of type - :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a - cell/material). - horizontal_field_of_view : float - Field of view horizontally, in units of degrees, defaults to 70. - camera_position : tuple or list of ndarray - Position of the camera in 3D space. Defaults to (1, 0, 0). - look_at : tuple or list of ndarray - The center of the camera's image points to this place in 3D space. - Set to (0, 0, 0) by default. - up : tuple or list of ndarray - Which way is up for the camera. Must not be parallel to the - line between look_at and camera_position. Set to (0, 0, 1) by default. - orthographic_width : float - If set to a nonzero value, an orthographic projection is used. - All rays traced from the orthographic pixel array travel in the - same direction. The width of the starting array must be specified, - unlike with the default perspective projection. The height of the - array is deduced from the ratio of pixel dimensions for the image. - Defaults to zero, i.e. using perspective projection. - light_position : tuple or list of float - Position of the light source in 3D space. Defaults to None, which places - the light at the camera position. - diffuse_fraction : float - Fraction of lighting that is diffuse (non-directional). Defaults to 0.1. - Must be between 0 and 1. - opaque_domains : list - List of domains (e.g., cells or materials) that should be rendered as - opaque rather than allowing transparency. - """ - - def __init__(self, plot_id=None, name=''): - super().__init__(plot_id, name) - self._light_position = None - self._diffuse_fraction = 0.1 - self._opaque_domains = [] - - @property - def light_position(self): - return self._light_position - - @light_position.setter - def light_position(self, x): - cv.check_type('plot light position', x, Iterable, Real) - cv.check_length('plot light position', x, 3) - self._light_position = x - - @property - def diffuse_fraction(self): - return self._diffuse_fraction - - @diffuse_fraction.setter - def diffuse_fraction(self, x): - cv.check_type('diffuse fraction', x, Real) - cv.check_greater_than('diffuse fraction', x, 0.0, equality=True) - cv.check_less_than('diffuse fraction', x, 1.0, equality=True) - self._diffuse_fraction = x - - @property - def opaque_domains(self): - return self._opaque_domains - - @opaque_domains.setter - def opaque_domains(self, x): - # Note that _check_domains_consistent_with_color_by checks - # the types within later. This is because we don't necessarily - # know what types are acceptable until the user has set the - # color_by attribute, too. - cv.check_type('opaque domains', x, Iterable) - self._opaque_domains = x - - def __repr__(self): - string = 'Solid Ray-traced Plot\n' - string += super().__repr__() - string += '{: <16}=\t{}\n'.format('\tDiffuse Fraction', - self._diffuse_fraction) - string += '{: <16}=\t{}\n'.format('\tLight position', - self._light_position) - string += '{: <16}=\t{}\n'.format('\tOpaque domains', - self._opaque_domains) - return string - - def to_xml_element(self): - """Return XML representation of the solid ray-traced plot - - Returns - ------- - element : lxml.etree._Element - XML element containing plot data - - """ - element = super().to_xml_element() - element.set("type", "solid_raytrace") - - # no light position means put it at the camera - if self._light_position: - subelement = ET.SubElement(element, "light_position") - subelement.text = ' '.join(map(str, self._light_position)) - - # no diffuse fraction defaults to 0.1 - if self._diffuse_fraction: - subelement = ET.SubElement(element, "diffuse_fraction") - subelement.text = str(self._diffuse_fraction) - - self._check_domains_consistent_with_color_by(self.opaque_domains) - subelement = ET.SubElement(element, "opaque_ids") - - # Extract all IDs, or use the integer value passed in - # explicitly if that was given - subelement.text = ' '.join( - [str(domain) if isinstance(domain, int) else - str(domain.id) for domain in self._opaque_domains]) - - if self._colors: - self._colors_to_xml(element) - - return element - - def _read_phong_attributes(self, elem): - """Read attributes specific to the Phong plot from an XML element""" - light_position = get_elem_list(elem, 'light_position', float) - if light_position is not None: - self.light_position = tuple(light_position) - - diffuse_fraction = get_text(elem, "diffuse_fraction") - if diffuse_fraction is not None: - self.diffuse_fraction = float(diffuse_fraction) - - opaque_domains = get_elem_list(elem, 'opaque_ids', int) - if opaque_domains is not None: - self.opaque_domains = opaque_domains - - @classmethod - def from_xml_element(cls, elem): - """Generate plot object from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.WireframeRayTracePlot - WireframeRayTracePlot object - - """ - - plot_id = int(get_text(elem, "id")) - plot_name = get_text(elem, 'name', '') - plot = cls(plot_id, plot_name) - plot.type = "solid_raytrace" - - plot._read_xml_attributes(elem) - plot._read_phong_attributes(elem) - - # Set plot colors - for color_elem in elem.findall("color"): - uid = get_text(color_elem, "id") - plot.colors[uid] = tuple(get_elem_list(color_elem, "rgb", int)) - - return plot - - class Plots(cv.CheckedList): - """Collection of plots used for an OpenMC simulation. + """Collection of Plots used for an OpenMC simulation. This class corresponds directly to the plots.xml input file. It can be - thought of as a normal Python list where each member is inherits from - :class:`PlotBase`. It behaves like a list as the following example - demonstrates: + thought of as a normal Python list where each member is a :class:`Plot`. It + behaves like a list as the following example demonstrates: - >>> xz_plot = openmc.SlicePlot() - >>> big_plot = openmc.VoxelPlot() - >>> small_plot = openmc.SlicePlot() + >>> xz_plot = openmc.Plot() + >>> big_plot = openmc.Plot() + >>> small_plot = openmc.Plot() >>> p = openmc.Plots((xz_plot, big_plot)) >>> p.append(small_plot) >>> small_plot = p.pop() Parameters ---------- - plots : Iterable of openmc.PlotBase - plots to add to the collection + plots : Iterable of openmc.Plot + Plots to add to the collection """ def __init__(self, plots=None): - super().__init__(PlotBase, 'plots collection') + super().__init__(Plot, 'plots collection') self._plots_file = ET.Element("plots") if plots is not None: self += plots @@ -2078,7 +833,7 @@ class Plots(cv.CheckedList): Parameters ---------- - plot : openmc.PlotBase + plot : openmc.Plot Plot to append """ @@ -2091,7 +846,7 @@ class Plots(cv.CheckedList): ---------- index : int Index in list - plot : openmc.PlotBase + plot : openmc.Plot Plot to insert """ @@ -2116,6 +871,7 @@ class Plots(cv.CheckedList): for plot in self: plot.colorize(geometry, seed) + def highlight_domains(self, geometry, domains, seed=1, alpha=0.5, background='gray'): """Use alpha compositing to highlight one or more domains in the plot. @@ -2151,13 +907,13 @@ class Plots(cv.CheckedList): self._plots_file.append(xml_element) - def to_xml_element(self): - """Create a 'plots' element to be written to an XML file. + def export_to_xml(self, path='plots.xml'): + """Export plot specifications to an XML file. - Returns - ------- - element : lxml.etree._Element - XML element containing all plot elements + Parameters + ---------- + path : str + Path to file to write. Defaults to 'plots.xml'. """ # Reset xml element tree @@ -2168,61 +924,16 @@ class Plots(cv.CheckedList): # Clean the indentation in the file to be user-readable clean_indentation(self._plots_file) - return self._plots_file - - def export_to_xml(self, path='plots.xml'): - """Export plot specifications to an XML file. - - Parameters - ---------- - path : str - Path to file to write. Defaults to 'plots.xml'. - - """ # Check if path is a directory p = Path(path) if p.is_dir(): p /= 'plots.xml' - self.to_xml_element() # Write the XML Tree to the plots.xml file + reorder_attributes(self._plots_file) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(self._plots_file) tree.write(str(p), xml_declaration=True, encoding='utf-8') - @classmethod - def from_xml_element(cls, elem): - """Generate plots collection from XML file - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.Plots - Plots collection - - """ - # Generate each plot - plots = cls() - for e in elem.findall('plot'): - plot_type = get_text(e, "type") - if plot_type == 'wireframe_raytrace': - plots.append(WireframeRayTracePlot.from_xml_element(e)) - elif plot_type == 'solid_raytrace': - plots.append(SolidRayTracePlot.from_xml_element(e)) - elif plot_type == 'slice': - plots.append(SlicePlot.from_xml_element(e)) - elif plot_type == 'voxel': - plots.append(VoxelPlot.from_xml_element(e)) - elif plot_type is None: - # For backward compatibility, assume slice if no type specified - plots.append(SlicePlot.from_xml_element(e)) - else: - raise ValueError("Unknown plot type: {}".format(plot_type)) - return plots - @classmethod def from_xml(cls, path='plots.xml'): """Generate plots collection from XML file @@ -2238,7 +949,11 @@ class Plots(cv.CheckedList): Plots collection """ - parser = ET.XMLParser(huge_tree=True) - tree = ET.parse(path, parser=parser) + tree = ET.parse(path) root = tree.getroot() - return cls.from_xml_element(root) + + # Generate each plot + plots = cls() + for elem in root.findall('plot'): + plots.append(Plot.from_xml_element(elem)) + return plots diff --git a/openmc/plotter.py b/openmc/plotter.py index abd8ab6dd..16760868e 100644 --- a/openmc/plotter.py +++ b/openmc/plotter.py @@ -1,7 +1,6 @@ -from __future__ import annotations from itertools import chain from numbers import Integral, Real -from typing import Dict, Iterable, List +import string import numpy as np @@ -9,15 +8,15 @@ import openmc.checkvalue as cv import openmc.data # Supported keywords for continuous-energy cross section plotting -PLOT_TYPES = {'total', 'scatter', 'elastic', 'inelastic', 'fission', +PLOT_TYPES = ['total', 'scatter', 'elastic', 'inelastic', 'fission', 'absorption', 'capture', 'nu-fission', 'nu-scatter', 'unity', - 'slowing-down power', 'damage'} + 'slowing-down power', 'damage'] # Supported keywords for multi-group cross section plotting -PLOT_TYPES_MGXS = {'total', 'absorption', 'scatter', 'fission', +PLOT_TYPES_MGXS = ['total', 'absorption', 'scatter', 'fission', 'kappa-fission', 'nu-fission', 'prompt-nu-fission', 'deleyed-nu-fission', 'chi', 'chi-prompt', 'chi-delayed', - 'inverse-velocity', 'beta', 'decay-rate', 'unity'} + 'inverse-velocity', 'beta', 'decay-rate', 'unity'] # Create a dictionary which can be used to convert PLOT_TYPES_MGXS to the # openmc.XSdata attribute name needed to access the data _PLOT_MGXS_ATTR = {line: line.replace(' ', '_').replace('-', '_') @@ -54,97 +53,18 @@ _MIN_E = 1.e-5 _MAX_E = 20.e6 -ELEMENT_NAMES = list(openmc.data.ELEMENT_SYMBOL.values())[1:] - - -def _get_legend_label(this, type): - """Gets a label for the element or nuclide or material and reaction plotted""" - if isinstance(this, str): - if type in openmc.data.DADZ: - if this in ELEMENT_NAMES: - return f'{this} {type}' - else: # this is a nuclide so the legend can contain more information - z, a, m = openmc.data.zam(this) - da, dz = openmc.data.DADZ[type] - gnds_name = openmc.data.gnds_name(z + dz, a + da, m) - # makes a string with nuclide reaction and new nuclide - # For example "Be9 (n,2n) Be8" - return f'{this} {type} {gnds_name}' - return f'{this} {type}' - elif this.name == '': - return f'Material {this.id} {type}' - else: - return f'{this.name} {type}' - - -def _get_yaxis_label(reactions, divisor_types): - """Gets a y axis label for the type of data plotted""" - - heat_values = {"heating", "heating-local", "damage-energy"} - - # if all the types are heating a different stem and unit is needed - if all(set(value).issubset(heat_values) for value in reactions.values()): - stem = "Heating" - elif all(isinstance(item, str) for item in reactions.keys()): - for nuc_reactions in reactions.values(): - for reaction in nuc_reactions: - if reaction in heat_values: - raise TypeError( - "Mixture of heating and Microscopic reactions. " - "Invalid type for plotting" - ) - stem = "Microscopic" - elif all(isinstance(item, openmc.Material) for item in reactions.keys()): - stem = 'Macroscopic' - else: - msg = "Mixture of openmc.Material and elements/nuclides. Invalid type for plotting" - raise TypeError(msg) - - if divisor_types: - mid, units = "Data", "" - else: - mid = "Cross Section" - units = { - "Macroscopic": "[1/cm]", - "Microscopic": "[b]", - "Heating": "[eV-barn]", - }[stem] - - return f'{stem} {mid} {units}' - -def _get_title(reactions): - """Gets a title for the type of data plotted""" - if len(reactions) == 1: - this, = reactions - name = this.name if isinstance(this, openmc.Material) else this - return f'Cross Section Plot For {name}' - else: - return 'Cross Section Plot' - - -def plot_xs( - reactions: Dict[str | openmc.Material, List[str]], - divisor_types: Iterable[str] | None = None, - temperature: float = 294.0, - axis: "plt.Axes" | None = None, - sab_name: str | None = None, - ce_cross_sections: str | None = None, - mg_cross_sections: str | None = None, - enrichment: float | None = None, - plot_CE: bool = True, - orders: Iterable[int] | None = None, - divisor_orders: Iterable[int] | None = None, - energy_axis_units: str = "eV", - **kwargs, -) -> "plt.Figure" | None: +def plot_xs(this, types, divisor_types=None, temperature=294., data_type=None, + axis=None, sab_name=None, ce_cross_sections=None, + mg_cross_sections=None, enrichment=None, plot_CE=True, orders=None, + divisor_orders=None, **kwargs): """Creates a figure of continuous-energy cross sections for this item. Parameters ---------- - reactions : dict - keys can be either a nuclide or element in string form or an - openmc.Material object. Values are a list of the types of - cross sections to include in the plot. + this : str or openmc.Material + Object to source data from + types : Iterable of values of PLOT_TYPES + The type of cross sections to include in the plot. divisor_types : Iterable of values of PLOT_TYPES, optional Cross section types which will divide those produced by types before plotting. A type of 'unity' can be used to effectively not @@ -154,18 +74,23 @@ def plot_xs( temperature of 294K will be plotted. Note that the nearest temperature in the library for each nuclide will be used as opposed to using any interpolation. + data_type : {'nuclide', 'element', 'material', 'macroscopic'}, optional + Type of object to plot. If not specified, a guess is made based on the + `this` argument. axis : matplotlib.axes, optional A previously generated axis to use for plotting. If not specified, a new axis and figure will be generated. sab_name : str, optional - Name of S(a,b) library to apply to MT=2 data when applicable. + Name of S(a,b) library to apply to MT=2 data when applicable; only used + for items which are instances of openmc.Element or openmc.Nuclide ce_cross_sections : str, optional Location of cross_sections.xml file. Default is None. mg_cross_sections : str, optional Location of MGXS HDF5 Library file. Default is None. enrichment : float, optional Enrichment for U235 in weight percent. For example, input 4.95 for - 4.95 weight percent enriched U. Default is None. + 4.95 weight percent enriched U. Default is None. This is only used for + items which are instances of openmc.Element plot_CE : bool, optional Denotes whether or not continuous-energy will be plotted. Defaults to plotting the continuous-energy data. @@ -176,13 +101,9 @@ def plot_xs( multi-group data. divisor_orders : Iterable of Integral, optional Same as orders, but for divisor_types - **kwargs : + **kwargs All keyword arguments are passed to :func:`matplotlib.pyplot.figure`. - energy_axis_units : {'eV', 'keV', 'MeV'} - Units used on the plot energy axis - - .. versionadded:: 0.15.0 Returns ------- @@ -196,107 +117,125 @@ def plot_xs( import matplotlib.pyplot as plt cv.check_type("plot_CE", plot_CE, bool) - cv.check_value("energy_axis_units", energy_axis_units, {"eV", "keV", "MeV"}) - axis_scaling_factor = {"eV": 1.0, "keV": 1e-3, "MeV": 1e-6} + if data_type is None: + if isinstance(this, openmc.Nuclide): + data_type = 'nuclide' + elif isinstance(this, openmc.Element): + data_type = 'element' + elif isinstance(this, openmc.Material): + data_type = 'material' + elif isinstance(this, openmc.Macroscopic): + data_type = 'macroscopic' + elif isinstance(this, str): + if this[-1] in string.digits: + data_type = 'nuclide' + else: + data_type = 'element' + else: + raise TypeError("Invalid type for plotting") + + if plot_CE: + # Calculate for the CE cross sections + E, data = calculate_cexs(this, data_type, types, temperature, sab_name, + ce_cross_sections, enrichment) + if divisor_types: + cv.check_length('divisor types', divisor_types, len(types)) + Ediv, data_div = calculate_cexs(this, divisor_types, temperature, + sab_name, ce_cross_sections, + enrichment) + + # Create a new union grid, interpolate data and data_div on to that + # grid, and then do the actual division + Enum = E[:] + E = np.union1d(Enum, Ediv) + data_new = np.zeros((len(types), len(E))) + + for line in range(len(types)): + data_new[line, :] = \ + np.divide(np.interp(E, Enum, data[line, :]), + np.interp(E, Ediv, data_div[line, :])) + if divisor_types[line] != 'unity': + types[line] = types[line] + ' / ' + divisor_types[line] + data = data_new + else: + # Calculate for MG cross sections + E, data = calculate_mgxs(this, data_type, types, orders, temperature, + mg_cross_sections, ce_cross_sections, + enrichment) + + if divisor_types: + cv.check_length('divisor types', divisor_types, len(types)) + Ediv, data_div = calculate_mgxs(this, data_type, divisor_types, + divisor_orders, temperature, + mg_cross_sections, + ce_cross_sections, enrichment) + + # Perform the division + for line in range(len(types)): + data[line, :] /= data_div[line, :] + if divisor_types[line] != 'unity': + types[line] += ' / ' + divisor_types[line] # Generate the plot if axis is None: - fig, ax = plt.subplots(**kwargs) + fig, ax = plt.subplots() else: fig = None ax = axis - - all_types = [] - - for this, types in reactions.items(): - all_types = all_types + types - - if plot_CE: - cv.check_type("this", this, (str, openmc.Material)) - # Calculate for the CE cross sections - E, data = calculate_cexs(this, types, temperature, sab_name, - ce_cross_sections, enrichment) - if divisor_types: - cv.check_length('divisor types', divisor_types, len(types)) - Ediv, data_div = calculate_cexs(this, divisor_types, temperature, - sab_name, ce_cross_sections, - enrichment) - - # Create a new union grid, interpolate data and data_div on to that - # grid, and then do the actual division - Enum = E[:] - E = np.union1d(Enum, Ediv) - data_new = np.zeros((len(types), len(E))) - - for line in range(len(types)): - data_new[line, :] = \ - np.divide(np.interp(E, Enum, data[line, :]), - np.interp(E, Ediv, data_div[line, :])) - if divisor_types[line] != 'unity': - types[line] = types[line] + ' / ' + divisor_types[line] - data = data_new - else: - # Calculate for MG cross sections - E, data = calculate_mgxs(this, types, orders, temperature, - mg_cross_sections, ce_cross_sections, - enrichment) - - if divisor_types: - cv.check_length('divisor types', divisor_types, len(types)) - Ediv, data_div = calculate_mgxs(this, divisor_types, - divisor_orders, temperature, - mg_cross_sections, - ce_cross_sections, enrichment) - - # Perform the division - for line in range(len(types)): - data[line, :] /= data_div[line, :] - if divisor_types[line] != 'unity': - types[line] += ' / ' + divisor_types[line] - - E *= axis_scaling_factor[energy_axis_units] - - # Plot the data - for i in range(len(data)): - data[i, :] = np.nan_to_num(data[i, :]) - if np.sum(data[i, :]) > 0.: - ax.plot(E, data[i, :], label=_get_legend_label(this, types[i])) - # Set to loglog or semilogx depending on if we are plotting a data # type which we expect to vary linearly - if set(all_types).issubset(PLOT_TYPES_LINEAR): - ax.set_xscale('log') - ax.set_yscale('linear') + if set(types).issubset(PLOT_TYPES_LINEAR): + plot_func = ax.semilogx else: - ax.set_xscale('log') - ax.set_yscale('log') + plot_func = ax.loglog - ax.set_xlabel(f"Energy [{energy_axis_units}]") + # Plot the data + for i in range(len(data)): + data[i, :] = np.nan_to_num(data[i, :]) + if np.sum(data[i, :]) > 0.: + plot_func(E, data[i, :], label=types[i]) + + ax.set_xlabel('Energy [eV]') if plot_CE: - ax.set_xlim( - _MIN_E * axis_scaling_factor[energy_axis_units], - _MAX_E * axis_scaling_factor[energy_axis_units], - ) + ax.set_xlim(_MIN_E, _MAX_E) else: ax.set_xlim(E[-1], E[0]) - - ax.set_ylabel(_get_yaxis_label(reactions, divisor_types)) + if divisor_types: + if data_type == 'nuclide': + ylabel = 'Nuclidic Microscopic Data' + elif data_type == 'element': + ylabel = 'Elemental Microscopic Data' + elif data_type == 'material' or data_type == 'macroscopic': + ylabel = 'Macroscopic Data' + else: + if data_type == 'nuclide': + ylabel = 'Microscopic Cross Section [b]' + elif data_type == 'element': + ylabel = 'Elemental Cross Section [b]' + elif data_type == 'material' or data_type == 'macroscopic': + ylabel = 'Macroscopic Cross Section [1/cm]' + ax.set_ylabel(ylabel) ax.legend(loc='best') - ax.set_title(_get_title(reactions)) + name = this.name if data_type == 'material' else this + if len(types) > 1: + ax.set_title('Cross Sections for ' + name) + else: + ax.set_title('Cross Section for ' + name) return fig -def calculate_cexs(this, types, temperature=294., sab_name=None, - cross_sections=None, enrichment=None, ncrystal_cfg=None): +def calculate_cexs(this, data_type, types, temperature=294., sab_name=None, + cross_sections=None, enrichment=None): """Calculates continuous-energy cross sections of a requested type. Parameters ---------- - this : str or openmc.Material - Object to source data from. Nuclides and elements should be input as a - str + this : {str, openmc.Nuclide, openmc.Element, openmc.Material} + Object to source data from + data_type : {'nuclide', 'element', 'material'} + Type of object to plot types : Iterable of values of PLOT_TYPES The type of cross sections to calculate temperature : float, optional @@ -312,8 +251,6 @@ def calculate_cexs(this, types, temperature=294., sab_name=None, Enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). - ncrystal_cfg : str, optional - Configuration string for NCrystal material. Returns ------- @@ -325,44 +262,50 @@ def calculate_cexs(this, types, temperature=294., sab_name=None, """ # Check types - cv.check_type('this', this, (str, openmc.Material)) cv.check_type('temperature', temperature, Real) if sab_name: cv.check_type('sab_name', sab_name, str) if enrichment: cv.check_type('enrichment', enrichment, Real) - if isinstance(this, str): - if this in ELEMENT_NAMES: - energy_grid, data = _calculate_cexs_elem_mat( - this, types, temperature, cross_sections, sab_name, enrichment - ) + if data_type == 'nuclide': + if isinstance(this, str): + nuc = openmc.Nuclide(this) else: - energy_grid, xs = _calculate_cexs_nuclide( - this, types, temperature, sab_name, cross_sections, - ncrystal_cfg - ) - - # Convert xs (Iterable of Callable) to a grid of cross section values - # calculated on the points in energy_grid for consistency with the - # element and material functions. - data = np.zeros((len(types), len(energy_grid))) - for line in range(len(types)): - data[line, :] = xs[line](energy_grid) - else: + nuc = this + energy_grid, xs = _calculate_cexs_nuclide(nuc, types, temperature, + sab_name, cross_sections) + # Convert xs (Iterable of Callable) to a grid of cross section values + # calculated on the points in energy_grid for consistency with the + # element and material functions. + data = np.zeros((len(types), len(energy_grid))) + for line in range(len(types)): + data[line, :] = xs[line](energy_grid) + elif data_type == 'element': + if isinstance(this, str): + elem = openmc.Element(this) + else: + elem = this + energy_grid, data = _calculate_cexs_elem_mat(elem, types, temperature, + cross_sections, sab_name, + enrichment) + elif data_type == 'material': + cv.check_type('this', this, openmc.Material) energy_grid, data = _calculate_cexs_elem_mat(this, types, temperature, cross_sections) + else: + raise TypeError("Invalid type") return energy_grid, data def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, - cross_sections=None, ncrystal_cfg=None): + cross_sections=None): """Calculates continuous-energy cross sections of a requested type. Parameters ---------- - this : str + this : openmc.Nuclide Nuclide object to source data from types : Iterable of str or Integral The type of cross sections to calculate; values can either be those @@ -378,8 +321,6 @@ def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, Name of S(a,b) library to apply to MT=2 data when applicable. cross_sections : str, optional Location of cross_sections.xml file. Default is None. - ncrystal_cfg : str, optional - Configuration string for NCrystal material. Returns ------- @@ -413,8 +354,7 @@ def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, # Prep S(a,b) data if needed if sab_name: - sab = openmc.data.ThermalScattering.from_hdf5( - library.get_by_material(sab_name, data_type='thermal')['path']) + sab = openmc.data.ThermalScattering.from_hdf5(sab_name) # Obtain the nearest temperature if strT in sab.temperatures: sabT = strT @@ -498,19 +438,6 @@ def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, [sab_sum, nuc[mt].xs[nucT]], [sab_Emax]) funcs.append(pw_funcs) - elif ncrystal_cfg: - import NCrystal - nc_scatter = NCrystal.createScatter(ncrystal_cfg) - nc_func = nc_scatter.xsect - nc_emax = 5 # eV # this should be obtained from NCRYSTAL_MAX_ENERGY - energy_grid = np.union1d(np.geomspace(min(energy_grid), - 1.1*nc_emax, - 1000),energy_grid) # NCrystal does not have - # an intrinsic energy grid - pw_funcs = openmc.data.Regions1D( - [nc_func, nuc[mt].xs[nucT]], - [nc_emax]) - funcs.append(pw_funcs) else: funcs.append(nuc[mt].xs[nucT]) elif mt in nuc: @@ -575,8 +502,8 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., Parameters ---------- - this : openmc.Material or str - Object to source data from. Element can be input as str + this : openmc.Material or openmc.Element + Object to source data from types : Iterable of values of PLOT_TYPES The type of cross sections to calculate temperature : float, optional @@ -613,23 +540,22 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., # Load the library library = openmc.data.DataLibrary.from_xml(cross_sections) - ncrystal_cfg = None if isinstance(this, openmc.Material): # Expand elements in to nuclides with atomic densities nuc_fractions = this.get_nuclide_atom_densities() # Create a dict of [nuclide name] = nuclide object to carry forward - # with a common nuclides format between openmc.Material and Elements + # with a common nuclides format between openmc.Material and + # openmc.Element objects nuclides = {nuclide: nuclide for nuclide in nuc_fractions} - # Add NCrystal cfg string if it exists - ncrystal_cfg = this.ncrystal_cfg else: # Expand elements in to nuclides with atomic densities - nuclides = openmc.Element(this).expand(1., 'ao', enrichment=enrichment, + nuclides = this.expand(1., 'ao', enrichment=enrichment, cross_sections=cross_sections) # For ease of processing split out the nuclide and its fraction nuc_fractions = {nuclide[0]: nuclide[1] for nuclide in nuclides} # Create a dict of [nuclide name] = nuclide object to carry forward - # with a common nuclides format between openmc.Material and Elements + # with a common nuclides format between openmc.Material and + # openmc.Element objects nuclides = {nuclide[0]: nuclide[0] for nuclide in nuclides} # Identify the nuclides which have S(a,b) data @@ -637,17 +563,18 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., for nuclide in nuclides.items(): sabs[nuclide[0]] = None if isinstance(this, openmc.Material): - for sab_name, _ in this._sab: + for sab_name in this._sab: sab = openmc.data.ThermalScattering.from_hdf5( library.get_by_material(sab_name, data_type='thermal')['path']) for nuc in sab.nuclides: - sabs[nuc] = sab_name + sabs[nuc] = library.get_by_material(sab_name, + data_type='thermal')['path'] else: if sab_name: - sab = openmc.data.ThermalScattering.from_hdf5( - library.get_by_material(sab_name, data_type='thermal')['path']) + sab = openmc.data.ThermalScattering.from_hdf5(sab_name) for nuc in sab.nuclides: - sabs[nuc] = sab_name + sabs[nuc] = library.get_by_material(sab_name, + data_type='thermal')['path'] # Now we can create the data sets to be plotted xs = {} @@ -655,10 +582,9 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., for nuclide in nuclides.items(): name = nuclide[0] nuc = nuclide[1] - sab_name = sabs[name] - temp_E, temp_xs = calculate_cexs(nuc, types, T, sab_name, cross_sections, - ncrystal_cfg=ncrystal_cfg - ) + sab_tab = sabs[name] + temp_E, temp_xs = calculate_cexs(nuc, 'nuclide', types, T, sab_tab, + cross_sections) E.append(temp_E) # Since the energy grids are different, store the cross sections as # a tabulated function so they can be calculated on any grid needed. @@ -685,7 +611,7 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., return energy_grid, data -def calculate_mgxs(this, types, orders=None, temperature=294., +def calculate_mgxs(this, data_type, types, orders=None, temperature=294., cross_sections=None, ce_cross_sections=None, enrichment=None): """Calculates multi-group cross sections of a requested type. @@ -697,7 +623,9 @@ def calculate_mgxs(this, types, orders=None, temperature=294., Parameters ---------- this : str or openmc.Material - Object to source data from. Nuclides and elements can be input as a str + Object to source data from + data_type : {'nuclide', 'element', 'material', 'macroscopic'} + Type of object to plot types : Iterable of values of PLOT_TYPES_MGXS The type of cross sections to calculate orders : Iterable of Integral, optional @@ -713,6 +641,7 @@ def calculate_mgxs(this, types, orders=None, temperature=294., Location of MGXS HDF5 Library file. Default is None. ce_cross_sections : str, optional Location of continuous-energy cross_sections.xml file. Default is None. + This is used only for expanding an openmc.Element object passed as this enrichment : float, optional Enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None @@ -736,13 +665,13 @@ def calculate_mgxs(this, types, orders=None, temperature=294., cv.check_type("cross_sections", cross_sections, str) library = openmc.MGXSLibrary.from_hdf5(cross_sections) - if this in ELEMENT_NAMES or isinstance(this, openmc.Material): + if data_type in ('nuclide', 'macroscopic'): + mgxs = _calculate_mgxs_nuc_macro(this, types, library, orders, + temperature) + elif data_type in ('element', 'material'): mgxs = _calculate_mgxs_elem_mat(this, types, library, orders, temperature, ce_cross_sections, enrichment) - elif isinstance(this, str): - mgxs = _calculate_mgxs_nuc_macro(this, types, library, orders, - temperature) else: raise TypeError("Invalid type") @@ -774,7 +703,7 @@ def _calculate_mgxs_nuc_macro(this, types, library, orders=None, Parameters ---------- - this : str + this : openmc.Nuclide or openmc.Macroscopic Object to source data from types : Iterable of str The type of cross sections to calculate; values can either be those @@ -912,8 +841,8 @@ def _calculate_mgxs_elem_mat(this, types, library, orders=None, Parameters ---------- - this : str or openmc.Material - Object to source data from. Elements can be input as a str + this : openmc.Element or openmc.Material + Object to source data from types : Iterable of str The type of cross sections to calculate; values can either be those in openmc.PLOT_TYPES_MGXS @@ -962,7 +891,7 @@ def _calculate_mgxs_elem_mat(this, types, library, orders=None, else: T = temperature # Expand elements in to nuclides with atomic densities - nuclides = openmc.Element(this).expand(100., 'ao', enrichment=enrichment, + nuclides = this.expand(100., 'ao', enrichment=enrichment, cross_sections=ce_cross_sections) # For ease of processing split out nuc and nuc_fractions diff --git a/openmc/polynomial.py b/openmc/polynomial.py index 341cdff47..1259c61ca 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -92,7 +92,7 @@ class Zernike(Polynomial): Parameters ---------- coef : Iterable of float - A list of coefficients of each term in Zernike polynomials + A list of coefficients of each term in radial only Zernike polynomials radius : float Domain of Zernike polynomials to be applied on. Default is 1. diff --git a/openmc/region.py b/openmc/region.py index cb9f3abd2..5d0e68020 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,14 +1,11 @@ -from __future__ import annotations from abc import ABC, abstractmethod +from collections import OrderedDict from collections.abc import MutableSequence from copy import deepcopy -import warnings import numpy as np -import openmc -from .bounding_box import BoundingBox -from .plots import add_plot_params +from .checkvalue import check_type class Region(ABC): @@ -20,11 +17,6 @@ class Region(ABC): respective classes are typically not instantiated directly but rather are created through operators of the Surface and Region classes. - Attributes - ---------- - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the region - """ def __and__(self, other): return Intersection((self, other)) @@ -32,19 +24,13 @@ class Region(ABC): def __or__(self, other): return Union((self, other)) - @abstractmethod - def __invert__(self) -> Region: - pass + def __invert__(self): + return Complement(self) @abstractmethod def __contains__(self, point): pass - @property - @abstractmethod - def bounding_box(self) -> BoundingBox: - pass - @abstractmethod def __str__(self): pass @@ -60,17 +46,17 @@ class Region(ABC): Parameters ---------- - surfaces : dict, optional + surfaces: collections.OrderedDict, optional Dictionary mapping surface IDs to :class:`openmc.Surface` instances Returns ------- - surfaces : dict + surfaces: collections.OrderedDict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ if surfaces is None: - surfaces = {} + surfaces = OrderedDict() for region in self: surfaces = region.get_surfaces(surfaces) return surfaces @@ -120,17 +106,17 @@ class Region(ABC): # If special character appears immediately after a non-operator, # create a token with the appropriate half-space if i_start >= 0: + # When an opening parenthesis appears after a non-operator, + # there's an implicit intersection operator between them + if expression[i] == '(': + tokens.append(' ') + j = int(expression[i_start:i]) if j < 0: tokens.append(-surfaces[abs(j)]) else: tokens.append(+surfaces[abs(j)]) - # When an opening parenthesis appears after a non-operator, - # there's an implicit intersection operator between them - if expression[i] == '(': - tokens.append(' ') - if expression[i] in '()|~': # For everything other than intersection, add the operator # to the list of tokens @@ -344,23 +330,6 @@ class Region(ABC): return type(self)(n.rotate(rotation, pivot=pivot, order=order, inplace=inplace, memo=memo) for n in self) - @add_plot_params - def plot(self, *args, **kwargs): - """Display a slice plot of the region. - - .. versionadded:: 0.15.0 - """ - for key in ('color_by', 'colors', 'legend', 'legend_kwargs'): - if key in kwargs: - warnings.warn(f"The '{key}' argument is present but won't be applied in a region plot") - - # Create cell while not perturbing use of autogenerated IDs - next_id = openmc.Cell.next_id - c = openmc.Cell(region=self) - openmc.Cell.used_ids.remove(c.id) - openmc.Cell.next_id = next_id - return c.plot(*args, **kwargs) - class Intersection(Region, MutableSequence): r"""Intersection of two or more regions. @@ -386,16 +355,13 @@ class Intersection(Region, MutableSequence): Attributes ---------- - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the region + bounding_box : tuple of numpy.array + Lower-left and upper-right coordinates of an axis-aligned bounding box """ def __init__(self, nodes): self._nodes = list(nodes) - for node in nodes: - if not isinstance(node, Region): - raise ValueError('Intersection operands must be of type Region') def __and__(self, other): new = Intersection(self) @@ -409,9 +375,6 @@ class Intersection(Region, MutableSequence): self.append(other) return self - def __invert__(self) -> Union: - return Union(~n for n in self) - # Implement mutable sequence protocol by delegating to list def __getitem__(self, key): return self._nodes[key] @@ -448,11 +411,14 @@ class Intersection(Region, MutableSequence): return '(' + ' '.join(map(str, self)) + ')' @property - def bounding_box(self) -> BoundingBox: - box = BoundingBox.infinite() + def bounding_box(self): + lower_left = np.array([-np.inf, -np.inf, -np.inf]) + upper_right = np.array([np.inf, np.inf, np.inf]) for n in self: - box &= n.bounding_box - return box + lower_left_n, upper_right_n = n.bounding_box + lower_left[:] = np.maximum(lower_left, lower_left_n) + upper_right[:] = np.minimum(upper_right, upper_right_n) + return lower_left, upper_right class Union(Region, MutableSequence): @@ -477,16 +443,13 @@ class Union(Region, MutableSequence): Attributes ---------- - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the region + bounding_box : 2-tuple of numpy.array + Lower-left and upper-right coordinates of an axis-aligned bounding box """ def __init__(self, nodes): self._nodes = list(nodes) - for node in nodes: - if not isinstance(node, Region): - raise ValueError('Union operands must be of type Region') def __or__(self, other): new = Union(self) @@ -500,9 +463,6 @@ class Union(Region, MutableSequence): self.append(other) return self - def __invert__(self) -> Intersection: - return Intersection(~n for n in self) - # Implement mutable sequence protocol by delegating to list def __getitem__(self, key): return self._nodes[key] @@ -539,12 +499,14 @@ class Union(Region, MutableSequence): return '(' + ' | '.join(map(str, self)) + ')' @property - def bounding_box(self) -> BoundingBox: - bbox = BoundingBox(np.array([np.inf]*3), - np.array([-np.inf]*3)) + def bounding_box(self): + lower_left = np.array([np.inf, np.inf, np.inf]) + upper_right = np.array([-np.inf, -np.inf, -np.inf]) for n in self: - bbox |= n.bounding_box - return bbox + lower_left_n, upper_right_n = n.bounding_box + lower_left[:] = np.minimum(lower_left, lower_left_n) + upper_right[:] = np.maximum(upper_right, upper_right_n) + return lower_left, upper_right class Complement(Region): @@ -571,12 +533,12 @@ class Complement(Region): ---------- node : openmc.Region Regions to take the complement of - bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the region + bounding_box : tuple of numpy.array + Lower-left and upper-right coordinates of an axis-aligned bounding box """ - def __init__(self, node: Region): + def __init__(self, node): self.node = node def __contains__(self, point): @@ -595,9 +557,6 @@ class Complement(Region): """ return point not in self.node - def __invert__(self) -> Region: - return self.node - def __str__(self): return '~' + str(self.node) @@ -607,30 +566,40 @@ class Complement(Region): @node.setter def node(self, node): - if not isinstance(node, Region): - raise ValueError('Complement operand must be of type Region') + check_type('node', node, Region) self._node = node @property - def bounding_box(self) -> BoundingBox: - return (~self.node).bounding_box + def bounding_box(self): + # Use De Morgan's laws to distribute the complement operator so that it + # only applies to surface half-spaces, thus allowing us to calculate the + # bounding box in the usual recursive manner. + if isinstance(self.node, Union): + temp_region = Intersection(~n for n in self.node) + elif isinstance(self.node, Intersection): + temp_region = Union(~n for n in self.node) + elif isinstance(self.node, Complement): + temp_region = self.node.node + else: + temp_region = ~self.node + return temp_region.bounding_box def get_surfaces(self, surfaces=None): """Recursively find and return all the surfaces referenced by the node Parameters ---------- - surfaces : dict, optional + surfaces: collections.OrderedDict, optional Dictionary mapping surface IDs to :class:`openmc.Surface` instances Returns ------- - surfaces : dict + surfaces: collections.OrderedDict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ if surfaces is None: - surfaces = {} + surfaces = OrderedDict() for region in self.node: surfaces = region.get_surfaces(surfaces) return surfaces diff --git a/openmc/search.py b/openmc/search.py index 70ce011b6..7f6b3b5b9 100644 --- a/openmc/search.py +++ b/openmc/search.py @@ -8,7 +8,7 @@ import openmc.model import openmc.checkvalue as cv -_SCALAR_BRACKETED_METHODS = {'brentq', 'brenth', 'ridder', 'bisect'} +_SCALAR_BRACKETED_METHODS = ['brentq', 'brenth', 'ridder', 'bisect'] def _search_keff(guess, target, model_builder, model_args, print_iterations, diff --git a/openmc/settings.py b/openmc/settings.py index 8120eb073..4372e679f 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -1,23 +1,18 @@ -from collections.abc import Iterable, Mapping, MutableSequence, Sequence +import os +import typing # imported separately as py3.8 requires typing.Iterable +from collections.abc import Iterable, Mapping, MutableSequence from enum import Enum import itertools from math import ceil from numbers import Integral, Real from pathlib import Path -import traceback +from typing import Optional, Union +from xml.etree import ElementTree as ET -import lxml.etree as ET -import warnings -import openmc import openmc.checkvalue as cv -from openmc.checkvalue import PathLike -from openmc.stats.multivariate import MeshSpatial -from ._xml import clean_indentation, get_elem_list, get_text -from .mesh import _read_meshes, RegularMesh, MeshBase -from .source import SourceBase, MeshSource, IndependentSource -from .utility_funcs import input_path -from .volume import VolumeCalculation -from .weight_windows import WeightWindows, WeightWindowGenerator, WeightWindowsList + +from . import RegularMesh, Source, VolumeCalculation, WeightWindows +from ._xml import clean_indentation, get_text, reorder_attributes class RunMode(Enum): @@ -28,7 +23,7 @@ class RunMode(Enum): PARTICLE_RESTART = 'particle restart' -_RES_SCAT_METHODS = {'dbrc', 'rvs'} +_RES_SCAT_METHODS = ['dbrc', 'rvs'] class Settings: @@ -41,10 +36,6 @@ class Settings: Attributes ---------- - atomic_relaxation : bool - Whether to simulate the atomic relaxation cascade (fluorescence photons - and Auger electrons) following photoelectric and incoherent scattering - interactions. batches : int Number of batches to simulate confidence_intervals : bool @@ -52,42 +43,17 @@ class Settings: half-width of the 95% two-sided confidence interval. If False, uncertainties on tally results will be reported as the sample standard deviation. - collision_track : dict - Options for writing collision information. Acceptable keys are: - - :max_collisions: Maximum number of collisions to be banked per file. (int) - :max_collision_track_files: Maximum number of collision_track files. (int) - :mcpl: Output in the form of an MCPL-file. (bool) - :cell_ids: List of cell IDs to define cells in which collisions should be banked. (list of int) - :universe_ids: List of universe IDs to define universes in which collisions should be banked. (list of int) - :material_ids: List of material IDs to define materials in which collisions should be banked. (list of int) - :nuclides: List of nuclides to define nuclides in which collisions should be banked. - (ex: ["I135m", "U233"] ). (list of str) - :reactions: List of reaction to define specific reactions that should be banked - (ex: ["(n,fission)", 2, "(n,2n)"] ). (list of str or int) - :deposited_E_threshold: Number to define the minimum deposited energy during - per collision to trigger banking. (float) - create_delayed_neutrons : bool - Whether delayed neutrons are created in fission. - - .. versionadded:: 0.13.3 create_fission_neutrons : bool Indicate whether fission neutrons should be created or not. cutoff : dict - Dictionary defining weight cutoff, energy cutoff and time cutoff. The - dictionary may have the following keys, 'weight', 'weight_avg', - 'survival_normalization', 'energy_neutron', 'energy_photon', - 'energy_electron', 'energy_positron', 'time_neutron', 'time_photon', - 'time_electron', and 'time_positron'. Value for 'weight' should be a - float indicating weight cutoff below which particle undergo Russian - roulette. Value for 'weight_avg' should be a float indicating weight - assigned to particles that are not killed after Russian roulette. Value - of energy should be a float indicating energy in eV below which particle - type will be killed. Value of time should be a float in seconds. - Particles will be killed exactly at the specified time. Value for - 'survival_normalization' is a bool indicating whether or not the weight - cutoff parameters will be applied relative to the particle's starting - weight or to its current weight. + Dictionary defining weight cutoff and energy cutoff. The dictionary may + have six keys, 'weight', 'weight_avg', 'energy_neutron', 'energy_photon', + 'energy_electron', and 'energy_positron'. Value for 'weight' + should be a float indicating weight cutoff below which particle undergo + Russian roulette. Value for 'weight_avg' should be a float indicating + weight assigned to particles that are not killed after Russian + roulette. Value of energy should be a float indicating energy in eV + below which particle type will be killed. delayed_photon_scaling : bool Indicate whether to scale the fission photon yield by (EGP + EGD)/EGP where EGP is the energy release of prompt photons and EGD is the energy @@ -108,22 +74,14 @@ class Settings: history-based parallelism. .. versionadded:: 0.12 - free_gas_threshold : float - Energy multiplier (in units of :math:`kT`) below which the free gas - scattering treatment is applied for elastic scattering. If not - specified, a value of 400.0 is used. generations_per_batch : int Number of generations per batch - ifp_n_generation : int - Number of generations to consider for the Iterated Fission Probability - method. max_lost_particles : int Maximum number of lost particles .. versionadded:: 0.12 rel_max_lost_particles : float - Maximum number of lost particles, relative to the total number of - particles + Maximum number of lost particles, relative to the total number of particles .. versionadded:: 0.12 inactive : int @@ -146,29 +104,16 @@ class Settings: parallelism. .. versionadded:: 0.12 - max_particle_events : int - Maximum number of allowed particle events per source particle. - - .. versionadded:: 0.15.0 max_order : None or int Maximum scattering order to apply globally when in multi-group mode. - max_history_splits : int + max_splits : int Maximum number of times a particle can split during a history .. versionadded:: 0.13 - max_secondaries : int - Maximum secondary bank size - - .. versionadded:: 0.15.3 max_tracks : int Maximum number of tracks written to a track file (per MPI process). .. versionadded:: 0.13.1 - max_write_lost_particles : int - Maximum number of particle restart files (per MPI process) to write for - lost particles. - - .. versionadded:: 0.14.0 no_reduce : bool Indicate that all user-defined and global tallies should not be reduced across processes in a parallel calculation. @@ -183,68 +128,8 @@ class Settings: Number of particles per generation photon_transport : bool Whether to use photon transport. - plot_seed : int - Initial seed for randomly generated plot colors. ptables : bool Determine whether probability tables are used. - properties_file : PathLike - Location of the properties file to load cell temperatures/densities - and material densities - random_ray : dict - Options for configuring the random ray solver. Acceptable keys are: - - :distance_inactive: - Indicates the total inactive distance in [cm] a ray should travel - :distance_active: - Indicates the total active distance in [cm] a ray should travel - :ray_source: - Starting ray distribution (must be uniform in space and angle) as - specified by a :class:`openmc.SourceBase` object. - :volume_estimator: - Choice of volume estimator for the random ray solver. Options are - 'naive', 'simulation_averaged', or 'hybrid'. - The default is 'hybrid'. - :source_shape: - Assumed shape of the source distribution within each source region. - Options are 'flat' (default), 'linear', or 'linear_xy'. - :volume_normalized_flux_tallies: - 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). - :adjoint: - Whether to run the random ray solver in adjoint mode (bool). The - default is 'False'. - :sample_method: - Sampling method for the ray starting location and direction of - travel. Options are `prng` (default), `halton`, or `s2`. `s2` - modifies the `prng` sampling method such that rays are sampled - with directions (-1, 0, 0) or (1, 0, 0). This is used for verification - against analytic transport benchmarks which are often derivied with - a reduced angular domain. - :source_region_meshes: - List of tuples where each tuple contains a mesh and a list of - domains. Each domain is an instance of openmc.Material, openmc.Cell, - or openmc.Universe. The mesh will be applied to the listed domains - to subdivide source regions so as to improve accuracy and/or conform - with tally meshes. - :diagonal_stabilization_rho: - The rho factor for use with diagonal stabilization. This technique is - applied when negative diagonal (in-group) elements are detected in - the scattering matrix of input MGXS data, which is a common feature - of transport corrected MGXS data. The default is 1.0, which ensures - no negative diagonal elements are present in the iteration matrix and - thus stabilizes the simulation. A value of 0.0 will disable diagonal - stabilization. Values between 0.0 and 1.0 will apply a degree of - stabilization, which may be desirable as stronger diagonal stabilization - also tends to dampen the convergence rate of the solver, thus requiring - more iterations to converge. - :adjoint_source: - Source object used to define localized adjoint source/detector response - function. - - .. versionadded:: 0.15.0 resonance_scattering : dict Settings for resonance elastic scattering. Accepted keys are 'enable' (bool), 'method' (str), 'energy_min' (float), 'energy_max' (float), and @@ -252,29 +137,16 @@ class Settings: rejection correction) or 'rvs' (relative velocity sampling). If not specified, 'rvs' is the default method. The 'energy_min' and 'energy_max' values indicate the minimum and maximum energies above and - below which the resonance elastic scattering method is to be applied. - The 'nuclides' list indicates what nuclides the method should be applied - to. In its absence, the method will be applied to all nuclides with 0 K - elastic scattering data present. + below which the resonance elastic scattering method is to be + applied. The 'nuclides' list indicates what nuclides the method should + be applied to. In its absence, the method will be applied to all + nuclides with 0 K elastic scattering data present. run_mode : {'eigenvalue', 'fixed source', 'plot', 'volume', 'particle restart'} The type of calculation to perform (default is 'eigenvalue') seed : int Seed for the linear congruential pseudorandom number generator - shared_secondary_bank : bool - 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. - - .. versionadded:: 0.15.4 - source : Iterable of openmc.SourceBase + source : Iterable of openmc.Source Distribution of source sites in space, angle, and energy - source_rejection_fraction : float - Minimum fraction of source sites that must be accepted when applying - rejection sampling based on constraints. If not specified, the default - value is 0.05. sourcepoint : dict Options for writing source points. Acceptable keys are: @@ -283,13 +155,10 @@ class Settings: :separate: bool indicating whether the source should be written as a separate file :write: bool indicating whether or not to write the source - :mcpl: bool indicating whether to write the source as an MCPL file statepoint : dict Options for writing state points. Acceptable keys are: - :batches: list of batches at which to write statepoint files - stride : int - Number of random numbers allocated for each source particle history + :batches: list of batches at which to write source surf_source_read : dict Options for reading surface source points. Acceptable keys are: @@ -299,36 +168,17 @@ class Settings: :surface_ids: List of surface ids at which crossing particles are to be banked (int) - :max_particles: Maximum number of particles to be banked on surfaces per - process (int) - :max_source_files: Maximum number of surface source files to be created (int) - :mcpl: Output in the form of an MCPL-file (bool) - :cell: Cell ID used to determine if particles crossing identified - surfaces are to be banked. Particles coming from or going to this - declared cell will be banked (int) - :cellfrom: Cell ID used to determine if particles crossing identified - surfaces are to be banked. Particles coming from this - declared cell will be banked (int) - :cellto: Cell ID used to determine if particles crossing identified - surfaces are to be banked. Particles going to this declared - cell will be banked (int) - surface_grazing_cutoff : float - Surface flux cosine cutoff. If not specified, the default value is - 0.001. For more information, see the surface tally section in the theory - manual. - surface_grazing_ratio : float - Surface flux cosine substitution ratio. If not specified, the default - value is 0.5. For more information, see the surface tally section in the - theory manual. + :max_particles: Maximum number of particles to be banked on + surfaces per process (int) survival_biasing : bool Indicate whether survival biasing is to be used tabular_legendre : dict Determines if a multi-group scattering moment kernel expanded via Legendre polynomials is to be converted to a tabular distribution or - not. Accepted keys are 'enable' and 'num_points'. The value for 'enable' - is a bool stating whether the conversion to tabular is performed; the - value for 'num_points' sets the number of points to use in the tabular - distribution, should 'enable' be True. + not. Accepted keys are 'enable' and 'num_points'. The value for + 'enable' is a bool stating whether the conversion to tabular is + performed; the value for 'num_points' sets the number of points to use + in the tabular distribution, should 'enable' be True. temperature : dict Defines a default temperature and method for treating intermediate temperatures at which nuclear data doesn't exist. Accepted keys are @@ -336,14 +186,12 @@ class Settings: for 'default' should be a float representing the default temperature in Kelvin. The value for 'method' should be 'nearest' or 'interpolation'. If the method is 'nearest', 'tolerance' indicates a range of temperature - within which cross sections may be used. If the method is - 'interpolation', 'tolerance' indicates the range of temperatures outside - of the available cross section temperatures where cross sections will - evaluate to the nearer bound. The value for 'range' should be a pair of - minimum and maximum temperatures which are used to indicate that cross - sections be loaded at all temperatures within the range. 'multipole' is - a boolean indicating whether or not the windowed multipole method should - be used to evaluate resolved resonance cross sections. + within which cross sections may be used. The value for 'range' should be + a pair a minimum and maximum temperatures which are used to indicate + that cross sections be loaded at all temperatures within the + range. 'multipole' is a boolean indicating whether or not the windowed + multipole method should be used to evaluate resolved resonance cross + sections. trace : tuple or list Show detailed information about a single particle, indicated by three integers: the batch number, generation number, and particle number @@ -359,42 +207,22 @@ class Settings: Maximum number of batches simulated. If this is set, the number of batches specified via ``batches`` is interpreted as the minimum number of batches - uniform_source_sampling : bool - Whether to sampling among multiple sources uniformly, applying their - strengths as weights to sampled particles. ufs_mesh : openmc.RegularMesh Mesh to be used for redistributing source sites via the uniform fission site (UFS) method. - use_decay_photons : bool - Produce decay photons from neutron reactions instead of prompt verbosity : int Verbosity during simulation between 1 and 10. Verbosity levels are described in :ref:`verbosity`. volume_calculations : VolumeCalculation or iterable of VolumeCalculation Stochastic volume calculation specifications - weight_windows : WeightWindowsList + weight_windows : WeightWindows iterable of WeightWindows Weight windows to use for variance reduction .. versionadded:: 0.13 - weight_window_checkpoints : dict - Indicates the checkpoints for weight window split/roulettes. Valid keys - include "collision" and "surface". Values must be of type bool. - - .. versionadded:: 0.14.0 - weight_window_generators : WeightWindowGenerator or iterable of WeightWindowGenerator - Weight windows generation parameters to apply during simulation - - .. versionadded:: 0.14.0 - weight_windows_on : bool Whether weight windows are enabled .. versionadded:: 0.13 - - weight_windows_file: Pathlike - Path to a weight window file to load during simulation initialization - - .. versionadded::0.14.0 write_initial_source : bool Indicate whether to write the initial source distribution to file """ @@ -406,7 +234,6 @@ class Settings: self._inactive = None self._max_lost_particles = None self._rel_max_lost_particles = None - self._max_write_lost_particles = None self._particles = None self._keff_trigger = None @@ -415,23 +242,14 @@ class Settings: self._max_order = None # Source subelement - self._source = cv.CheckedList(SourceBase, 'source distributions') - self._source_rejection_fraction = None + self._source = cv.CheckedList(Source, 'source distributions') self._confidence_intervals = None self._electron_treatment = None self._photon_transport = None - self._atomic_relaxation = None - self._plot_seed = None self._ptables = None - self._properties_file = None - self._uniform_source_sampling = None self._seed = None - self._stride = None - self._surface_grazing_cutoff = None - self._surface_grazing_ratio = None self._survival_biasing = None - self._free_gas_threshold = None # Shannon entropy mesh self._entropy_mesh = None @@ -443,12 +261,6 @@ class Settings: self._output = None - # Iterated Fission Probability - self._ifp_n_generation = None - - # Collision track feature - self._collision_track = {} - # Output options self._statepoint = {} self._sourcepoint = {} @@ -478,46 +290,209 @@ class Settings: VolumeCalculation, 'volume calculations') self._create_fission_neutrons = None - self._create_delayed_neutrons = None self._delayed_photon_scaling = None self._material_cell_offsets = None self._log_grid_bins = None self._event_based = None self._max_particles_in_flight = None - self._max_particle_events = None self._write_initial_source = None - self._weight_windows = WeightWindowsList() - self._weight_window_generators = cv.CheckedList( - WeightWindowGenerator, 'weight window generators') + self._weight_windows = cv.CheckedList(WeightWindows, 'weight windows') self._weight_windows_on = None - self._shared_secondary_bank = None - self._weight_windows_file = None - self._weight_window_checkpoints = {} - self._max_history_splits = None + self._max_splits = None self._max_tracks = None - self._max_secondaries = None - self._use_decay_photons = None - - self._random_ray = {} for key, value in kwargs.items(): setattr(self, key, value) - def __setattr__(self, name: str, value): - if not name.startswith('_'): - try: - getattr(self, name) - except AttributeError as e: - msg, = traceback.format_exception_only(e) - msg = msg.strip().split(maxsplit=1)[-1] - warnings.warn(msg, stacklevel=2) - super().__setattr__(name, value) - @property def run_mode(self) -> str: return self._run_mode.value + @property + def batches(self) -> int: + return self._batches + + @property + def generations_per_batch(self) -> int: + return self._generations_per_batch + + @property + def inactive(self) -> int: + return self._inactive + + @property + def max_lost_particles(self) -> int: + return self._max_lost_particles + + @property + def rel_max_lost_particles(self) -> float: + return self._rel_max_lost_particles + + @property + def particles(self) -> int: + return self._particles + + @property + def keff_trigger(self) -> dict: + return self._keff_trigger + + @property + def energy_mode(self) -> str: + return self._energy_mode + + @property + def max_order(self) -> int: + return self._max_order + + @property + def source(self) -> typing.List[Source]: + return self._source + + @property + def confidence_intervals(self) -> bool: + return self._confidence_intervals + + @property + def electron_treatment(self) -> str: + return self._electron_treatment + + @property + def ptables(self) -> bool: + return self._ptables + + @property + def photon_transport(self) -> bool: + return self._photon_transport + + @property + def seed(self) -> int: + return self._seed + + @property + def survival_biasing(self) -> bool: + return self._survival_biasing + + @property + def entropy_mesh(self) -> RegularMesh: + return self._entropy_mesh + + @property + def trigger_active(self) -> bool: + return self._trigger_active + + @property + def trigger_max_batches(self) -> int: + return self._trigger_max_batches + + @property + def trigger_batch_interval(self) -> int: + return self._trigger_batch_interval + + @property + def output(self) -> dict: + return self._output + + @property + def sourcepoint(self) -> dict: + return self._sourcepoint + + @property + def statepoint(self) -> dict: + return self._statepoint + + @property + def surf_source_read(self) -> dict: + return self._surf_source_read + + @property + def surf_source_write(self) -> dict: + return self._surf_source_write + + @property + def no_reduce(self) -> bool: + return self._no_reduce + + @property + def verbosity(self) -> int: + return self._verbosity + + @property + def tabular_legendre(self) -> dict: + return self._tabular_legendre + + @property + def temperature(self) -> dict: + return self._temperature + + @property + def trace(self) -> typing.Iterable: + return self._trace + + @property + def track(self) -> typing.Iterable[typing.Iterable[int]]: + return self._track + + @property + def cutoff(self) -> dict: + return self._cutoff + + @property + def ufs_mesh(self) -> RegularMesh: + return self._ufs_mesh + + @property + def resonance_scattering(self) -> dict: + return self._resonance_scattering + + @property + def volume_calculations(self) -> typing.List[VolumeCalculation]: + return self._volume_calculations + + @property + def create_fission_neutrons(self) -> bool: + return self._create_fission_neutrons + + @property + def delayed_photon_scaling(self) -> bool: + return self._delayed_photon_scaling + + @property + def material_cell_offsets(self) -> bool: + return self._material_cell_offsets + + @property + def log_grid_bins(self) -> int: + return self._log_grid_bins + + @property + def event_based(self) -> bool: + return self._event_based + + @property + def max_particles_in_flight(self) -> int: + return self._max_particles_in_flight + + @property + def write_initial_source(self) -> bool: + return self._write_initial_source + + @property + def weight_windows(self) -> typing.List[WeightWindows]: + return self._weight_windows + + @property + def weight_windows_on(self) -> bool: + return self._weight_windows_on + + @property + def max_splits(self) -> int: + return self._max_splits + + @property + def max_tracks(self) -> int: + return self._max_tracks + @run_mode.setter def run_mode(self, run_mode: str): cv.check_value('run mode', run_mode, {x.value for x in RunMode}) @@ -525,95 +500,53 @@ class Settings: if mode.value == run_mode: self._run_mode = mode - @property - def batches(self) -> int: - return self._batches - @batches.setter def batches(self, batches: int): cv.check_type('batches', batches, Integral) cv.check_greater_than('batches', batches, 0) self._batches = batches - @property - def generations_per_batch(self) -> int: - return self._generations_per_batch - @generations_per_batch.setter def generations_per_batch(self, generations_per_batch: int): - cv.check_type('generations per batch', generations_per_batch, Integral) - cv.check_greater_than('generations per batch', - generations_per_batch, 0) + cv.check_type('generations per patch', generations_per_batch, Integral) + cv.check_greater_than('generations per batch', generations_per_batch, 0) self._generations_per_batch = generations_per_batch - @property - def inactive(self) -> int: - return self._inactive - @inactive.setter def inactive(self, inactive: int): cv.check_type('inactive batches', inactive, Integral) cv.check_greater_than('inactive batches', inactive, 0, True) self._inactive = inactive - @property - def max_lost_particles(self) -> int: - return self._max_lost_particles - @max_lost_particles.setter def max_lost_particles(self, max_lost_particles: int): cv.check_type('max_lost_particles', max_lost_particles, Integral) cv.check_greater_than('max_lost_particles', max_lost_particles, 0) self._max_lost_particles = max_lost_particles - @property - def rel_max_lost_particles(self) -> float: - return self._rel_max_lost_particles - @rel_max_lost_particles.setter def rel_max_lost_particles(self, rel_max_lost_particles: float): cv.check_type('rel_max_lost_particles', rel_max_lost_particles, Real) - cv.check_greater_than('rel_max_lost_particles', - rel_max_lost_particles, 0) + cv.check_greater_than('rel_max_lost_particles', rel_max_lost_particles, 0) cv.check_less_than('rel_max_lost_particles', rel_max_lost_particles, 1) self._rel_max_lost_particles = rel_max_lost_particles - @property - def max_write_lost_particles(self) -> int: - return self._max_write_lost_particles - - @max_write_lost_particles.setter - def max_write_lost_particles(self, max_write_lost_particles: int): - cv.check_type('max_write_lost_particles', - max_write_lost_particles, Integral) - cv.check_greater_than('max_write_lost_particles', - max_write_lost_particles, 0) - self._max_write_lost_particles = max_write_lost_particles - - @property - def particles(self) -> int: - return self._particles - @particles.setter def particles(self, particles: int): cv.check_type('particles', particles, Integral) cv.check_greater_than('particles', particles, 0) self._particles = particles - @property - def keff_trigger(self) -> dict: - return self._keff_trigger - @keff_trigger.setter def keff_trigger(self, keff_trigger: dict): if not isinstance(keff_trigger, dict): msg = f'Unable to set a trigger on keff from "{keff_trigger}" ' \ - 'which is not a Python dictionary' + 'which is not a Python dictionary' raise ValueError(msg) elif 'type' not in keff_trigger: msg = f'Unable to set a trigger on keff from "{keff_trigger}" ' \ - 'which does not have a "type" key' + 'which does not have a "type" key' raise ValueError(msg) elif keff_trigger['type'] not in ['variance', 'std_dev', 'rel_err']: @@ -623,7 +556,7 @@ class Settings: elif 'threshold' not in keff_trigger: msg = f'Unable to set a trigger on keff from "{keff_trigger}" ' \ - 'which does not have a "threshold" key' + 'which does not have a "threshold" key' raise ValueError(msg) elif not isinstance(keff_trigger['threshold'], Real): @@ -633,198 +566,25 @@ class Settings: self._keff_trigger = keff_trigger - @property - def energy_mode(self) -> str: - return self._energy_mode - @energy_mode.setter def energy_mode(self, energy_mode: str): cv.check_value('energy mode', energy_mode, - ['continuous-energy', 'multi-group']) + ['continuous-energy', 'multi-group']) self._energy_mode = energy_mode - @property - def max_order(self) -> int: - return self._max_order - @max_order.setter - def max_order(self, max_order: int | None): + def max_order(self, max_order: Optional[int]): if max_order is not None: cv.check_type('maximum scattering order', max_order, Integral) cv.check_greater_than('maximum scattering order', max_order, 0, True) self._max_order = max_order - @property - def source(self) -> list[SourceBase]: - return self._source - @source.setter - def source(self, source: SourceBase | Iterable[SourceBase]): + def source(self, source: Union[Source, typing.Iterable[Source]]): if not isinstance(source, MutableSequence): source = [source] - self._source = cv.CheckedList( - SourceBase, 'source distributions', source) - - @property - def confidence_intervals(self) -> bool: - return self._confidence_intervals - - @confidence_intervals.setter - def confidence_intervals(self, confidence_intervals: bool): - cv.check_type('confidence interval', confidence_intervals, bool) - self._confidence_intervals = confidence_intervals - - @property - def electron_treatment(self) -> str: - return self._electron_treatment - - @electron_treatment.setter - def electron_treatment(self, electron_treatment: str): - cv.check_value('electron treatment', - electron_treatment, ['led', 'ttb']) - self._electron_treatment = electron_treatment - - @property - def atomic_relaxation(self) -> bool: - return self._atomic_relaxation - - @atomic_relaxation.setter - def atomic_relaxation(self, atomic_relaxation: bool): - cv.check_type('atomic relaxation', atomic_relaxation, bool) - self._atomic_relaxation = atomic_relaxation - - @property - def ptables(self) -> bool: - return self._ptables - - @ptables.setter - def ptables(self, ptables: bool): - cv.check_type('probability tables', ptables, bool) - self._ptables = ptables - - @property - def photon_transport(self) -> bool: - return self._photon_transport - - @photon_transport.setter - def photon_transport(self, photon_transport: bool): - cv.check_type('photon transport', photon_transport, bool) - self._photon_transport = photon_transport - - @property - def uniform_source_sampling(self) -> bool: - return self._uniform_source_sampling - - @uniform_source_sampling.setter - def uniform_source_sampling(self, uniform_source_sampling: bool): - cv.check_type('strength as weights', uniform_source_sampling, bool) - self._uniform_source_sampling = uniform_source_sampling - - @property - def plot_seed(self): - return self._plot_seed - - @plot_seed.setter - def plot_seed(self, seed): - cv.check_type('random plot color seed', seed, Integral) - cv.check_greater_than('random plot color seed', seed, 0) - self._plot_seed = seed - - @property - def seed(self) -> int: - return self._seed - - @seed.setter - def seed(self, seed: int): - cv.check_type('random number generator seed', seed, Integral) - cv.check_greater_than('random number generator seed', seed, 0) - self._seed = seed - - @property - def stride(self) -> int: - return self._stride - - @stride.setter - def stride(self, stride: int): - cv.check_type('random number generator stride', stride, Integral) - cv.check_greater_than('random number generator stride', stride, 0) - self._stride = stride - - @property - def surface_grazing_cutoff(self) -> float: - return self._surface_grazing_cutoff - - @surface_grazing_cutoff.setter - def surface_grazing_cutoff(self, surface_grazing_cutoff: float): - cv.check_type('surface grazing cutoff', surface_grazing_cutoff, float) - cv.check_greater_than('surface grazing cutoff', surface_grazing_cutoff, 0.0) - cv.check_less_than('surface grazing cutoff', surface_grazing_cutoff, 1.0) - self._surface_grazing_cutoff = surface_grazing_cutoff - - @property - def surface_grazing_ratio(self) -> float: - return self._surface_grazing_ratio - - @surface_grazing_ratio.setter - def surface_grazing_ratio(self, surface_grazing_ratio: float): - cv.check_type('surface grazing ratio', surface_grazing_ratio, float) - cv.check_greater_than('surface grazing ratio', surface_grazing_ratio, 0.0) - self._surface_grazing_ratio = surface_grazing_ratio - - @property - def survival_biasing(self) -> bool: - return self._survival_biasing - - @survival_biasing.setter - def survival_biasing(self, survival_biasing: bool): - cv.check_type('survival biasing', survival_biasing, bool) - self._survival_biasing = survival_biasing - - @property - def entropy_mesh(self) -> RegularMesh: - return self._entropy_mesh - - @entropy_mesh.setter - def entropy_mesh(self, entropy: RegularMesh): - cv.check_type('entropy mesh', entropy, RegularMesh) - self._entropy_mesh = entropy - - @property - def trigger_active(self) -> bool: - return self._trigger_active - - @trigger_active.setter - def trigger_active(self, trigger_active: bool): - cv.check_type('trigger active', trigger_active, bool) - self._trigger_active = trigger_active - - @property - def trigger_max_batches(self) -> int: - return self._trigger_max_batches - - @trigger_max_batches.setter - def trigger_max_batches(self, trigger_max_batches: int): - cv.check_type('trigger maximum batches', trigger_max_batches, Integral) - cv.check_greater_than('trigger maximum batches', - trigger_max_batches, 0) - self._trigger_max_batches = trigger_max_batches - - @property - def trigger_batch_interval(self) -> int: - return self._trigger_batch_interval - - @trigger_batch_interval.setter - def trigger_batch_interval(self, trigger_batch_interval: int): - cv.check_type('trigger batch interval', - trigger_batch_interval, Integral) - cv.check_greater_than('trigger batch interval', - trigger_batch_interval, 0) - self._trigger_batch_interval = trigger_batch_interval - - @property - def output(self) -> dict: - return self._output + self._source = cv.CheckedList(Source, 'source distributions', source) @output.setter def output(self, output: dict): @@ -837,9 +597,12 @@ class Settings: cv.check_type("output['path']", value, str) self._output = output - @property - def sourcepoint(self) -> dict: - return self._sourcepoint + @verbosity.setter + def verbosity(self, verbosity: int): + cv.check_type('verbosity', verbosity, Integral) + cv.check_greater_than('verbosity', verbosity, 1, True) + cv.check_less_than('verbosity', verbosity, 10, True) + self._verbosity = verbosity @sourcepoint.setter def sourcepoint(self, sourcepoint: dict): @@ -855,17 +618,11 @@ class Settings: cv.check_type('sourcepoint write', value, bool) elif key == 'overwrite': cv.check_type('sourcepoint overwrite', value, bool) - elif key == 'mcpl': - cv.check_type('sourcepoint mcpl', value, bool) else: raise ValueError(f"Unknown key '{key}' encountered when " "setting sourcepoint options.") self._sourcepoint = sourcepoint - @property - def statepoint(self) -> dict: - return self._statepoint - @statepoint.setter def statepoint(self, statepoint: dict): cv.check_type('statepoint options', statepoint, Mapping) @@ -879,170 +636,117 @@ class Settings: "setting statepoint options.") self._statepoint = statepoint - @property - def surf_source_read(self) -> dict: - return self._surf_source_read - @surf_source_read.setter - def surf_source_read(self, ssr: dict): - cv.check_type('surface source reading options', ssr, Mapping) - for key, value in ssr.items(): + def surf_source_read(self, surf_source_read: dict): + cv.check_type('surface source reading options', surf_source_read, Mapping) + for key, value in surf_source_read.items(): cv.check_value('surface source reading key', key, ('path')) if key == 'path': - cv.check_type('path to surface source file', value, PathLike) - self._surf_source_read = dict(ssr) - - # Resolve path to surface source file - if 'path' in ssr: - self._surf_source_read['path'] = input_path(ssr['path']) - - @property - def surf_source_write(self) -> dict: - return self._surf_source_write + cv.check_type('path to surface source file', value, str) + self._surf_source_read = surf_source_read @surf_source_write.setter def surf_source_write(self, surf_source_write: dict): - cv.check_type("surface source writing options", - surf_source_write, Mapping) + cv.check_type('surface source writing options', surf_source_write, Mapping) for key, value in surf_source_write.items(): - cv.check_value( - "surface source writing key", - key, - ("surface_ids", "max_particles", "max_source_files", - "mcpl", "cell", "cellfrom", "cellto"), - ) - if key == "surface_ids": - cv.check_type( - "surface ids for source banking", value, Iterable, Integral - ) + cv.check_value('surface source writing key', key, + ('surface_ids', 'max_particles')) + if key == 'surface_ids': + cv.check_type('surface ids for source banking', value, + Iterable, Integral) for surf_id in value: - cv.check_greater_than( - "surface id for source banking", surf_id, 0) - - elif key == "mcpl": - cv.check_type("write to an MCPL-format file", value, bool) - elif key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): - name = { - "max_particles": "maximum particle banks on surfaces per process", - "max_source_files": "maximun surface source files to be written", - "cell": "Cell ID for source banking (from or to)", - "cellfrom": "Cell ID for source banking (from only)", - "cellto": "Cell ID for source banking (to only)", - }[key] - cv.check_type(name, value, Integral) - cv.check_greater_than(name, value, 0) - + cv.check_greater_than('surface id for source banking', + surf_id, 0) + elif key == 'max_particles': + cv.check_type('maximum particle banks on surfaces per process', + value, Integral) + cv.check_greater_than('maximum particle banks on surfaces per process', + value, 0) self._surf_source_write = surf_source_write - @property - def collision_track(self) -> dict: - return self._collision_track + @confidence_intervals.setter + def confidence_intervals(self, confidence_intervals: bool): + cv.check_type('confidence interval', confidence_intervals, bool) + self._confidence_intervals = confidence_intervals - @collision_track.setter - def collision_track(self, collision_track: dict): - cv.check_type('Collision tracking options', collision_track, Mapping) - for key, value in collision_track.items(): - cv.check_value('collision_track key', key, - ('cell_ids', 'reactions', 'universe_ids', 'material_ids', 'nuclides', - 'deposited_E_threshold', 'max_collisions', 'max_collision_track_files', 'mcpl')) - if key == 'cell_ids': - cv.check_type('cell ids for collision tracking data banking', value, - Iterable, Integral) - for cell_id in value: - cv.check_greater_than('cell id for collision tracking data banking', - cell_id, 0) - elif key == 'reactions': - cv.check_type('MT numbers for collision tracking data banking', value, - Iterable) - for reaction in value: - if isinstance(reaction, int): - cv.check_greater_than( - 'MT number for collision tracking data banking', reaction, 0 - ) - elif isinstance(reaction, str): - # check against allowed strings? so far let C++ code handle it - pass - else: - raise TypeError( - f"MT number for collision tracking data banking must be a positive int or string, " - f"got {type(reaction).__name__}") - elif key == 'universe_ids': - cv.check_type('universe ids for collision tracking data banking', value, - Iterable, Integral) - for universe_id in value: - cv.check_greater_than('universe id for collision tracking data banking', - universe_id, 0) - elif key == 'material_ids': - cv.check_type('material ids for collision tracking data banking', value, - Iterable, Integral) - for material_id in value: - cv.check_greater_than('material id for collision tracking data banking', - material_id, 0) - elif key == 'nuclides': - cv.check_type('nuclides for collision tracking data banking', value, - Iterable, str) - for nuclide in value: - # If nuclide name doesn't look valid, give a warning - try: - openmc.data.zam(nuclide) - except ValueError: - warnings.warn(f"Nuclide {nuclide} is not valid") - elif key == 'deposited_E_threshold': - cv.check_type('Deposited Energy Threshold for collision tracking data banking', - value, Real) - cv.check_greater_than('Deposited Energy Threshold for collision tracking data banking', - value, 0) - elif key == 'max_collisions': - cv.check_type('maximum collisions banks per file', - value, Integral) - cv.check_greater_than('maximum collisions banks in collision tracking', - value, 0) - elif key == 'max_collision_track_files': - cv.check_type('maximum collisions banks', - value, Integral) - cv.check_greater_than('maximum number of collision_track files ', - value, 0) - elif key == 'mcpl': - cv.check_type('write to an MCPL-format file', value, bool) + @electron_treatment.setter + def electron_treatment(self, electron_treatment: str): + cv.check_value('electron treatment', electron_treatment, ['led', 'ttb']) + self._electron_treatment = electron_treatment - self._collision_track = collision_track + @photon_transport.setter + def photon_transport(self, photon_transport: bool): + cv.check_type('photon transport', photon_transport, bool) + self._photon_transport = photon_transport - @property - def no_reduce(self) -> bool: - return self._no_reduce + @ptables.setter + def ptables(self, ptables: bool): + cv.check_type('probability tables', ptables, bool) + self._ptables = ptables + + @seed.setter + def seed(self, seed: int): + cv.check_type('random number generator seed', seed, Integral) + cv.check_greater_than('random number generator seed', seed, 0) + self._seed = seed + + @survival_biasing.setter + def survival_biasing(self, survival_biasing: bool): + cv.check_type('survival biasing', survival_biasing, bool) + self._survival_biasing = survival_biasing + + @cutoff.setter + def cutoff(self, cutoff: dict): + if not isinstance(cutoff, Mapping): + msg = f'Unable to set cutoff from "{cutoff}" which is not a '\ + 'Python dictionary' + raise ValueError(msg) + for key in cutoff: + if key == 'weight': + cv.check_type('weight cutoff', cutoff[key], Real) + cv.check_greater_than('weight cutoff', cutoff[key], 0.0) + elif key == 'weight_avg': + cv.check_type('average survival weight', cutoff[key], Real) + cv.check_greater_than('average survival weight', + cutoff[key], 0.0) + elif key in ['energy_neutron', 'energy_photon', 'energy_electron', + 'energy_positron']: + cv.check_type('energy cutoff', cutoff[key], Real) + cv.check_greater_than('energy cutoff', cutoff[key], 0.0) + else: + msg = f'Unable to set cutoff to "{key}" which is unsupported ' \ + 'by OpenMC' + + self._cutoff = cutoff + + @entropy_mesh.setter + def entropy_mesh(self, entropy: RegularMesh): + cv.check_type('entropy mesh', entropy, RegularMesh) + self._entropy_mesh = entropy + + @trigger_active.setter + def trigger_active(self, trigger_active: bool): + cv.check_type('trigger active', trigger_active, bool) + self._trigger_active = trigger_active + + @trigger_max_batches.setter + def trigger_max_batches(self, trigger_max_batches: int): + cv.check_type('trigger maximum batches', trigger_max_batches, Integral) + cv.check_greater_than('trigger maximum batches', trigger_max_batches, 0) + self._trigger_max_batches = trigger_max_batches + + @trigger_batch_interval.setter + def trigger_batch_interval(self, trigger_batch_interval: int): + cv.check_type('trigger batch interval', trigger_batch_interval, Integral) + cv.check_greater_than('trigger batch interval', trigger_batch_interval, 0) + self._trigger_batch_interval = trigger_batch_interval @no_reduce.setter def no_reduce(self, no_reduce: bool): cv.check_type('no reduction option', no_reduce, bool) self._no_reduce = no_reduce - @property - def verbosity(self) -> int: - return self._verbosity - - @verbosity.setter - def verbosity(self, verbosity: int): - cv.check_type('verbosity', verbosity, Integral) - cv.check_greater_than('verbosity', verbosity, 1, True) - cv.check_less_than('verbosity', verbosity, 10, True) - self._verbosity = verbosity - - @property - def ifp_n_generation(self) -> int: - return self._ifp_n_generation - - @ifp_n_generation.setter - def ifp_n_generation(self, ifp_n_generation: int): - if ifp_n_generation is not None: - cv.check_type("number of generations", ifp_n_generation, Integral) - cv.check_greater_than("number of generations", ifp_n_generation, 0) - self._ifp_n_generation = ifp_n_generation - - @property - def tabular_legendre(self) -> dict: - return self._tabular_legendre - @tabular_legendre.setter def tabular_legendre(self, tabular_legendre: dict): cv.check_type('tabular_legendre settings', tabular_legendre, Mapping) @@ -1056,10 +760,6 @@ class Settings: cv.check_greater_than('num_points tabular_legendre', value, 0) self._tabular_legendre = tabular_legendre - @property - def temperature(self) -> dict: - return self._temperature - @temperature.setter def temperature(self, temperature: dict): @@ -1084,22 +784,6 @@ class Settings: self._temperature = temperature - @property - def properties_file(self) -> PathLike | None: - return self._properties_file - - @properties_file.setter - def properties_file(self, value: PathLike | None): - if value is None: - self._properties_file = None - else: - cv.check_type('properties file', value, PathLike) - self._properties_file = input_path(value) - - @property - def trace(self) -> Iterable: - return self._trace - @trace.setter def trace(self, trace: Iterable): cv.check_type('trace', trace, Iterable, Integral) @@ -1109,13 +793,9 @@ class Settings: cv.check_greater_than('trace particle', trace[2], 0) self._trace = trace - @property - def track(self) -> Iterable[Iterable[int]]: - return self._track - @track.setter - def track(self, track: Iterable[Iterable[int]]): - cv.check_type('track', track, Sequence) + def track(self, track: typing.Iterable[typing.Iterable[int]]): + cv.check_type('track', track, Iterable) for t in track: if len(t) != 3: msg = f'Unable to set the track to "{t}" since its length is not 3' @@ -1128,40 +808,6 @@ class Settings: cv.check_type('track particle', t[2], Integral) self._track = track - @property - def cutoff(self) -> dict: - return self._cutoff - - @cutoff.setter - def cutoff(self, cutoff: dict): - if not isinstance(cutoff, Mapping): - msg = f'Unable to set cutoff from "{cutoff}" which is not a '\ - 'Python dictionary' - raise ValueError(msg) - for key in cutoff: - if key == 'weight': - cv.check_type('weight cutoff', cutoff[key], Real) - cv.check_greater_than('weight cutoff', cutoff[key], 0.0) - elif key == 'weight_avg': - cv.check_type('average survival weight', cutoff[key], Real) - cv.check_greater_than('average survival weight', - cutoff[key], 0.0) - elif key == 'survival_normalization': - cv.check_type('survival normalization', cutoff[key], bool) - elif key in ['energy_neutron', 'energy_photon', 'energy_electron', - 'energy_positron']: - cv.check_type('energy cutoff', cutoff[key], Real) - cv.check_greater_than('energy cutoff', cutoff[key], 0.0) - else: - msg = f'Unable to set cutoff to "{key}" which is unsupported ' \ - 'by OpenMC' - - self._cutoff = cutoff - - @property - def ufs_mesh(self) -> RegularMesh: - return self._ufs_mesh - @ufs_mesh.setter def ufs_mesh(self, ufs_mesh: RegularMesh): cv.check_type('UFS mesh', ufs_mesh, RegularMesh) @@ -1170,10 +816,6 @@ class Settings: cv.check_length('UFS mesh upper-right corner', ufs_mesh.upper_right, 3) self._ufs_mesh = ufs_mesh - @property - def resonance_scattering(self) -> dict: - return self._resonance_scattering - @resonance_scattering.setter def resonance_scattering(self, res: dict): cv.check_type('resonance scattering settings', res, Mapping) @@ -1198,172 +840,69 @@ class Settings: Iterable, str) self._resonance_scattering = res - @property - def volume_calculations(self) -> list[VolumeCalculation]: - return self._volume_calculations - @volume_calculations.setter def volume_calculations( - self, vol_calcs: VolumeCalculation | Iterable[VolumeCalculation] + self, vol_calcs: Union[VolumeCalculation, typing.Iterable[VolumeCalculation]] ): if not isinstance(vol_calcs, MutableSequence): vol_calcs = [vol_calcs] self._volume_calculations = cv.CheckedList( VolumeCalculation, 'stochastic volume calculations', vol_calcs) - @property - def create_fission_neutrons(self) -> bool: - return self._create_fission_neutrons - @create_fission_neutrons.setter def create_fission_neutrons(self, create_fission_neutrons: bool): cv.check_type('Whether create fission neutrons', create_fission_neutrons, bool) self._create_fission_neutrons = create_fission_neutrons - @property - def create_delayed_neutrons(self) -> bool: - return self._create_delayed_neutrons - - @create_delayed_neutrons.setter - def create_delayed_neutrons(self, create_delayed_neutrons: bool): - cv.check_type('Whether create only prompt neutrons', - create_delayed_neutrons, bool) - self._create_delayed_neutrons = create_delayed_neutrons - - @property - def delayed_photon_scaling(self) -> bool: - return self._delayed_photon_scaling - @delayed_photon_scaling.setter def delayed_photon_scaling(self, value: bool): cv.check_type('delayed photon scaling', value, bool) self._delayed_photon_scaling = value - @property - def material_cell_offsets(self) -> bool: - return self._material_cell_offsets - - @material_cell_offsets.setter - def material_cell_offsets(self, value: bool): - cv.check_type('material cell offsets', value, bool) - self._material_cell_offsets = value - - @property - def log_grid_bins(self) -> int: - return self._log_grid_bins - - @log_grid_bins.setter - def log_grid_bins(self, log_grid_bins: int): - cv.check_type('log grid bins', log_grid_bins, Real) - cv.check_greater_than('log grid bins', log_grid_bins, 0) - self._log_grid_bins = log_grid_bins - - @property - def event_based(self) -> bool: - return self._event_based - @event_based.setter def event_based(self, value: bool): cv.check_type('event based', value, bool) self._event_based = value - @property - def max_particles_in_flight(self) -> int: - return self._max_particles_in_flight - @max_particles_in_flight.setter def max_particles_in_flight(self, value: int): cv.check_type('max particles in flight', value, Integral) cv.check_greater_than('max particles in flight', value, 0) self._max_particles_in_flight = value - @property - def max_particle_events(self) -> int: - return self._max_particle_events + @material_cell_offsets.setter + def material_cell_offsets(self, value: bool): + cv.check_type('material cell offsets', value, bool) + self._material_cell_offsets = value - @max_particle_events.setter - def max_particle_events(self, value: int): - cv.check_type('max particle events', value, Integral) - cv.check_greater_than('max particle events', value, 0) - self._max_particle_events = value - - @property - def write_initial_source(self) -> bool: - return self._write_initial_source + @log_grid_bins.setter + def log_grid_bins(self, log_grid_bins: int): + cv.check_type('log grid bins', log_grid_bins, Real) + cv.check_greater_than('log grid bins', log_grid_bins, 0) + self._log_grid_bins = log_grid_bins @write_initial_source.setter def write_initial_source(self, value: bool): cv.check_type('write initial source', value, bool) self._write_initial_source = value - @property - def weight_windows(self) -> WeightWindowsList: - return self._weight_windows - @weight_windows.setter - def weight_windows(self, value: WeightWindows | Sequence[WeightWindows]): - if not isinstance(value, Sequence): + def weight_windows(self, value: Union[WeightWindows, typing.Iterable[WeightWindows]]): + if not isinstance(value, MutableSequence): value = [value] - self._weight_windows = WeightWindowsList(value) - - @property - def weight_windows_on(self) -> bool: - return self._weight_windows_on + self._weight_windows = cv.CheckedList(WeightWindows, 'weight windows', value) @weight_windows_on.setter - def weight_windows_on(self, value: bool): + def weight_windows_on(self, value): cv.check_type('weight windows on', value, bool) self._weight_windows_on = value - @property - def shared_secondary_bank(self) -> bool: - return self._shared_secondary_bank - - @shared_secondary_bank.setter - def shared_secondary_bank(self, value: bool): - cv.check_type('shared secondary bank', value, bool) - self._shared_secondary_bank = value - - @property - def weight_window_checkpoints(self) -> dict: - return self._weight_window_checkpoints - - @weight_window_checkpoints.setter - def weight_window_checkpoints(self, weight_window_checkpoints: dict): - for key in weight_window_checkpoints.keys(): - cv.check_value('weight_window_checkpoints', - key, ('collision', 'surface')) - self._weight_window_checkpoints = weight_window_checkpoints - - @property - def max_splits(self): - raise AttributeError( - 'max_splits has been deprecated. Please use max_history_splits instead') - - @property - def max_history_splits(self) -> int: - return self._max_history_splits - - @max_history_splits.setter - def max_history_splits(self, value: int): + @max_splits.setter + def max_splits(self, value: int): cv.check_type('maximum particle splits', value, Integral) cv.check_greater_than('max particle splits', value, 0) - self._max_history_splits = value - - @property - def max_secondaries(self) -> int: - return self._max_secondaries - - @max_secondaries.setter - def max_secondaries(self, value: int): - cv.check_type('maximum secondary bank size', value, Integral) - cv.check_greater_than('max secondary bank size', value, 0) - self._max_secondaries = value - - @property - def max_tracks(self) -> int: - return self._max_tracks + self._max_splits = value @max_tracks.setter def max_tracks(self, value: int): @@ -1371,126 +910,6 @@ class Settings: cv.check_greater_than('maximum particle tracks', value, 0, True) self._max_tracks = value - @property - def weight_windows_file(self) -> PathLike | None: - return self._weight_windows_file - - @weight_windows_file.setter - def weight_windows_file(self, value: PathLike | None): - if value is None: - self._weight_windows_file = None - else: - cv.check_type('weight windows file', value, PathLike) - self._weight_windows_file = input_path(value) - - @property - def weight_window_generators(self) -> list[WeightWindowGenerator]: - return self._weight_window_generators - - @weight_window_generators.setter - def weight_window_generators(self, wwgs): - if not isinstance(wwgs, MutableSequence): - wwgs = [wwgs] - self._weight_window_generators = cv.CheckedList( - WeightWindowGenerator, 'weight window generators', wwgs) - - @property - def random_ray(self) -> dict: - return self._random_ray - - @random_ray.setter - def random_ray(self, random_ray: dict): - if not isinstance(random_ray, Mapping): - raise ValueError(f'Unable to set random_ray from "{random_ray}" ' - 'which is not a dict.') - for key, value in random_ray.items(): - if key == 'distance_active': - cv.check_type('active ray length', value, Real) - cv.check_greater_than('active ray length', value, 0.0) - elif key == 'distance_inactive': - cv.check_type('inactive ray length', value, Real) - cv.check_greater_than('inactive ray length', - value, 0.0, True) - elif key == 'ray_source': - cv.check_type('random ray source', value, SourceBase) - elif key == 'volume_estimator': - cv.check_value('volume estimator', value, - ('naive', 'simulation_averaged', - 'hybrid')) - elif key == 'source_shape': - cv.check_value('source shape', value, - ('flat', 'linear', 'linear_xy')) - elif key == 'volume_normalized_flux_tallies': - cv.check_type('volume normalized flux tallies', value, bool) - elif key == 'adjoint': - cv.check_type('adjoint', value, bool) - elif key == 'source_region_meshes': - cv.check_type('source region meshes', value, Iterable) - for mesh, domains in value: - cv.check_type('mesh', mesh, MeshBase) - cv.check_type('domains', domains, Iterable) - valid_types = (openmc.Material, - openmc.Cell, openmc.Universe) - for domain in domains: - if not isinstance(domain, valid_types): - raise ValueError( - f'Invalid domain type: {type(domain)}. Expected ' - 'openmc.Material, openmc.Cell, or openmc.Universe.') - elif key == 'sample_method': - cv.check_value('sample method', value, - ('prng', 'halton', 's2')) - elif key == 'diagonal_stabilization_rho': - cv.check_type('diagonal stabilization rho', value, Real) - cv.check_greater_than('diagonal stabilization rho', - value, 0.0, True) - elif key == 'adjoint_source': - if not isinstance(value, MutableSequence): - value = [value] - for source in value: - if not isinstance(source, SourceBase): - raise ValueError( - f'Invalid adjoint source type: {type(source)}. ' - 'Expected openmc.SourceBase.') - else: - raise ValueError(f'Unable to set random ray to "{key}" which is ' - 'unsupported by OpenMC') - - self._random_ray = random_ray - - @property - def use_decay_photons(self) -> bool: - return self._use_decay_photons - - @use_decay_photons.setter - def use_decay_photons(self, value): - cv.check_type('use decay photons', value, bool) - self._use_decay_photons = value - - @property - def source_rejection_fraction(self) -> float: - return self._source_rejection_fraction - - @source_rejection_fraction.setter - def source_rejection_fraction(self, source_rejection_fraction: float): - cv.check_type('source_rejection_fraction', - source_rejection_fraction, Real) - cv.check_greater_than('source_rejection_fraction', - source_rejection_fraction, 0) - cv.check_less_than('source_rejection_fraction', - source_rejection_fraction, 1) - self._source_rejection_fraction = source_rejection_fraction - - @property - def free_gas_threshold(self) -> float | None: - return self._free_gas_threshold - - @free_gas_threshold.setter - def free_gas_threshold(self, free_gas_threshold: float | None): - if free_gas_threshold is not None: - cv.check_type('free gas threshold', free_gas_threshold, Real) - cv.check_greater_than('free gas threshold', free_gas_threshold, 0.0) - self._free_gas_threshold = free_gas_threshold - def _create_run_mode_subelement(self, root): elem = ET.SubElement(root, "run_mode") elem.text = self._run_mode.value @@ -1520,11 +939,6 @@ class Settings: element = ET.SubElement(root, "rel_max_lost_particles") element.text = str(self._rel_max_lost_particles) - def _create_max_write_lost_particles_subelement(self, root): - if self._max_write_lost_particles is not None: - element = ET.SubElement(root, "max_write_lost_particles") - element.text = str(self._max_write_lost_particles) - def _create_particles_subelement(self, root): if self._particles is not None: element = ET.SubElement(root, "particles") @@ -1547,19 +961,9 @@ class Settings: element = ET.SubElement(root, "max_order") element.text = str(self._max_order) - def _create_source_subelement(self, root, mesh_memo=None): + def _create_source_subelement(self, root): for source in self.source: root.append(source.to_xml_element()) - if isinstance(source, IndependentSource) and isinstance(source.space, MeshSpatial): - path = f"./mesh[@id='{source.space.mesh.id}']" - if root.find(path) is None: - root.append(source.space.mesh.to_xml_element()) - if isinstance(source, MeshSource): - path = f"./mesh[@id='{source.mesh.id}']" - if root.find(path) is None: - root.append(source.mesh.to_xml_element()) - if mesh_memo is not None: - mesh_memo.add(source.mesh.id) def _create_volume_calcs_subelement(self, root): for calc in self.volume_calculations: @@ -1588,11 +992,6 @@ class Settings: subelement.text = ' '.join( str(x) for x in self._statepoint['batches']) - def _create_uniform_source_sampling_subelement(self, root): - if self._uniform_source_sampling is not None: - element = ET.SubElement(root, "uniform_source_sampling") - element.text = str(self._uniform_source_sampling).lower() - def _create_sourcepoint_subelement(self, root): if self._sourcepoint: element = ET.SubElement(root, "source_point") @@ -1615,71 +1014,23 @@ class Settings: subelement = ET.SubElement(element, "overwrite_latest") subelement.text = str(self._sourcepoint['overwrite']).lower() - if 'mcpl' in self._sourcepoint: - subelement = ET.SubElement(element, "mcpl") - subelement.text = str(self._sourcepoint['mcpl']).lower() - def _create_surf_source_read_subelement(self, root): if self._surf_source_read: element = ET.SubElement(root, "surf_source_read") if 'path' in self._surf_source_read: subelement = ET.SubElement(element, "path") - subelement.text = str(self._surf_source_read['path']) + subelement.text = self._surf_source_read['path'] def _create_surf_source_write_subelement(self, root): if self._surf_source_write: element = ET.SubElement(root, "surf_source_write") - if "surface_ids" in self._surf_source_write: + if 'surface_ids' in self._surf_source_write: subelement = ET.SubElement(element, "surface_ids") - subelement.text = " ".join( - str(x) for x in self._surf_source_write["surface_ids"] - ) - if "mcpl" in self._surf_source_write: - subelement = ET.SubElement(element, "mcpl") - subelement.text = str(self._surf_source_write["mcpl"]).lower() - for key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): - if key in self._surf_source_write: - subelement = ET.SubElement(element, key) - subelement.text = str(self._surf_source_write[key]) - - def _create_collision_track_subelement(self, root): - if self._collision_track: - element = ET.SubElement(root, "collision_track") - if 'cell_ids' in self._collision_track: - subelement = ET.SubElement(element, "cell_ids") subelement.text = ' '.join( - str(x) for x in self._collision_track['cell_ids']) - if 'reactions' in self._collision_track: - subelement = ET.SubElement(element, "reactions") - subelement.text = ' '.join( - str(x) for x in self._collision_track['reactions']) - if 'universe_ids' in self._collision_track: - subelement = ET.SubElement(element, "universe_ids") - subelement.text = ' '.join( - str(x) for x in self._collision_track['universe_ids']) - if 'material_ids' in self._collision_track: - subelement = ET.SubElement(element, "material_ids") - subelement.text = ' '.join( - str(x) for x in self._collision_track['material_ids']) - if 'nuclides' in self._collision_track: - subelement = ET.SubElement(element, "nuclides") - subelement.text = ' '.join( - str(x) for x in self._collision_track['nuclides']) - if 'deposited_E_threshold' in self._collision_track: - subelement = ET.SubElement(element, "deposited_E_threshold") - subelement.text = str( - self._collision_track['deposited_E_threshold']) - if 'max_collisions' in self._collision_track: - subelement = ET.SubElement(element, "max_collisions") - subelement.text = str(self._collision_track['max_collisions']) - if 'max_collision_track_files' in self._collision_track: - subelement = ET.SubElement( - element, "max_collision_track_files") - subelement.text = str( - self._collision_track['max_collision_track_files']) - if 'mcpl' in self._collision_track: - subelement = ET.SubElement(element, "mcpl") - subelement.text = str(self._collision_track['mcpl']).lower() + str(x) for x in self._surf_source_write['surface_ids']) + if 'max_particles' in self._surf_source_write: + subelement = ET.SubElement(element, "max_particles") + subelement.text = str(self._surf_source_write['max_particles']) def _create_confidence_intervals(self, root): if self._confidence_intervals is not None: @@ -1691,21 +1042,11 @@ class Settings: element = ET.SubElement(root, "electron_treatment") element.text = str(self._electron_treatment) - def _create_atomic_relaxation_subelement(self, root): - if self._atomic_relaxation is not None: - element = ET.SubElement(root, "atomic_relaxation") - element.text = str(self._atomic_relaxation).lower() - def _create_photon_transport_subelement(self, root): if self._photon_transport is not None: element = ET.SubElement(root, "photon_transport") element.text = str(self._photon_transport).lower() - def _create_plot_seed_subelement(self, root): - if self._plot_seed is not None: - element = ET.SubElement(root, "plot_seed") - element.text = str(self._plot_seed) - def _create_ptables_subelement(self, root): if self._ptables is not None: element = ET.SubElement(root, "ptables") @@ -1716,21 +1057,6 @@ class Settings: element = ET.SubElement(root, "seed") element.text = str(self._seed) - def _create_stride_subelement(self, root): - if self._stride is not None: - element = ET.SubElement(root, "stride") - element.text = str(self._stride) - - def _create_surface_grazing_cutoff_subelement(self, root): - if self._surface_grazing_cutoff is not None: - element = ET.SubElement(root, "surface_grazing_cutoff") - element.text = str(self._surface_grazing_cutoff) - - def _create_surface_grazing_ratio_subelement(self, root): - if self._surface_grazing_ratio is not None: - element = ET.SubElement(root, "surface_grazing_ratio") - element.text = str(self._surface_grazing_ratio) - def _create_survival_biasing_subelement(self, root): if self._survival_biasing is not None: element = ET.SubElement(root, "survival_biasing") @@ -1741,38 +1067,27 @@ class Settings: element = ET.SubElement(root, "cutoff") for key, value in self._cutoff.items(): subelement = ET.SubElement(element, key) - subelement.text = str(value) if key != 'survival_normalization' \ - else str(value).lower() + subelement.text = str(value) - def _create_entropy_mesh_subelement(self, root, mesh_memo=None): - if self.entropy_mesh is None: - return + def _create_entropy_mesh_subelement(self, root): + if self.entropy_mesh is not None: + # use default heuristic for entropy mesh if not set by user + if self.entropy_mesh.dimension is None: + if self.particles is None: + raise RuntimeError("Number of particles must be set in order to " \ + "use entropy mesh dimension heuristic") + else: + n = ceil((self.particles / 20.0)**(1.0 / 3.0)) + d = len(self.entropy_mesh.lower_left) + self.entropy_mesh.dimension = (n,)*d - # use default heuristic for entropy mesh if not set by user - if self.entropy_mesh.dimension is None: - if self.particles is None: - raise RuntimeError("Number of particles must be set in order to " - "use entropy mesh dimension heuristic") - else: - n = ceil((self.particles / 20.0)**(1.0 / 3.0)) - d = len(self.entropy_mesh.lower_left) - self.entropy_mesh.dimension = (n,)*d + # See if a element already exists -- if not, add it + path = f"./mesh[@id='{self.entropy_mesh.id}']" + if root.find(path) is None: + root.append(self.entropy_mesh.to_xml_element()) - # add mesh ID to this element - subelement = ET.SubElement(root, "entropy_mesh") - subelement.text = str(self.entropy_mesh.id) - - # If this mesh has already been written outside the - # settings element, skip writing it again - if mesh_memo and self.entropy_mesh.id in mesh_memo: - return - - # See if a element already exists -- if not, add it - path = f"./mesh[@id='{self.entropy_mesh.id}']" - if root.find(path) is None: - root.append(self.entropy_mesh.to_xml_element()) - if mesh_memo is not None: - mesh_memo.add(self.entropy_mesh.id) + subelement = ET.SubElement(root, "entropy_mesh") + subelement.text = str(self.entropy_mesh.id) def _create_trigger_subelement(self, root): if self._trigger_active is not None: @@ -1793,11 +1108,6 @@ class Settings: element = ET.SubElement(root, "no_reduce") element.text = str(self._no_reduce).lower() - def _create_ifp_n_generation_subelement(self, root): - if self._ifp_n_generation is not None: - element = ET.SubElement(root, "ifp_n_generation") - element.text = str(self._ifp_n_generation) - def _create_tabular_legendre_subelements(self, root): if self.tabular_legendre: element = ET.SubElement(root, "tabular_legendre") @@ -1818,12 +1128,6 @@ class Settings: else: element.text = str(value) - def _create_properties_file_element(self, root): - if self.properties_file is not None: - element = ET.Element("properties_file") - element.text = str(self.properties_file) - root.append(element) - def _create_trace_subelement(self, root): if self._trace is not None: element = ET.SubElement(root, "trace") @@ -1834,27 +1138,15 @@ class Settings: element = ET.SubElement(root, "track") element.text = ' '.join(map(str, itertools.chain(*self._track))) - def _create_ufs_mesh_subelement(self, root, mesh_memo=None): - if self.ufs_mesh is None: - return + def _create_ufs_mesh_subelement(self, root): + if self.ufs_mesh is not None: + # See if a element already exists -- if not, add it + path = f"./mesh[@id='{self.ufs_mesh.id}']" + if root.find(path) is None: + root.append(self.ufs_mesh.to_xml_element()) - subelement = ET.SubElement(root, "ufs_mesh") - subelement.text = str(self.ufs_mesh.id) - - if mesh_memo and self.ufs_mesh.id in mesh_memo: - return - - # See if a element already exists -- if not, add it - path = f"./mesh[@id='{self.ufs_mesh.id}']" - if root.find(path) is None: - root.append(self.ufs_mesh.to_xml_element()) - if mesh_memo is not None: - mesh_memo.add(self.ufs_mesh.id) - - def _create_use_decay_photons_subelement(self, root): - if self._use_decay_photons is not None: - element = ET.SubElement(root, "use_decay_photons") - element.text = str(self._use_decay_photons).lower() + subelement = ET.SubElement(root, "ufs_mesh") + subelement.text = str(self.ufs_mesh.id) def _create_resonance_scattering_subelement(self, root): res = self.resonance_scattering @@ -1881,11 +1173,6 @@ class Settings: elem = ET.SubElement(root, "create_fission_neutrons") elem.text = str(self._create_fission_neutrons).lower() - def _create_create_delayed_neutrons_subelement(self, root): - if self._create_delayed_neutrons is not None: - elem = ET.SubElement(root, "create_delayed_neutrons") - elem.text = str(self._create_delayed_neutrons).lower() - def _create_delayed_photon_scaling_subelement(self, root): if self._delayed_photon_scaling is not None: elem = ET.SubElement(root, "delayed_photon_scaling") @@ -1901,11 +1188,6 @@ class Settings: elem = ET.SubElement(root, "max_particles_in_flight") elem.text = str(self._max_particles_in_flight).lower() - def _create_max_events_subelement(self, root): - if self._max_particle_events is not None: - elem = ET.SubElement(root, "max_particle_events") - elem.text = str(self._max_particle_events).lower() - def _create_material_cell_offsets_subelement(self, root): if self._material_cell_offsets is not None: elem = ET.SubElement(root, "material_cell_offsets") @@ -1921,147 +1203,30 @@ class Settings: elem = ET.SubElement(root, "write_initial_source") elem.text = str(self._write_initial_source).lower() - def _create_weight_windows_subelement(self, root, mesh_memo=None): + def _create_weight_windows_subelement(self, root): for ww in self._weight_windows: # Add weight window information root.append(ww.to_xml_element()) - # if this mesh has already been written, - # skip writing the mesh element - if mesh_memo and ww.mesh.id in mesh_memo: - continue - # See if a element already exists -- if not, add it path = f"./mesh[@id='{ww.mesh.id}']" if root.find(path) is None: root.append(ww.mesh.to_xml_element()) - if mesh_memo is not None: - mesh_memo.add(ww.mesh.id) - def _create_weight_windows_on_subelement(self, root): if self._weight_windows_on is not None: elem = ET.SubElement(root, "weight_windows_on") elem.text = str(self._weight_windows_on).lower() - def _create_shared_secondary_bank_subelement(self, root): - if self._shared_secondary_bank is not None: - elem = ET.SubElement(root, "shared_secondary_bank") - elem.text = str(self._shared_secondary_bank).lower() - - def _create_weight_window_generators_subelement(self, root, mesh_memo=None): - if not self.weight_window_generators: - return - elem = ET.SubElement(root, 'weight_window_generators') - for wwg in self.weight_window_generators: - elem.append(wwg.to_xml_element()) - - # ensure that mesh elements are created if needed - for wwg in self.weight_window_generators: - if mesh_memo is not None and wwg.mesh.id in mesh_memo: - continue - - # See if a element already exists -- if not, add it - path = f"./mesh[@id='{wwg.mesh.id}']" - if root.find(path) is None: - root.append(wwg.mesh.to_xml_element()) - if mesh_memo is not None: - mesh_memo.add(wwg.mesh.id) - - def _create_weight_windows_file_element(self, root): - if self.weight_windows_file is not None: - element = ET.Element("weight_windows_file") - element.text = str(self.weight_windows_file) - root.append(element) - - def _create_weight_window_checkpoints_subelement(self, root): - if not self._weight_window_checkpoints: - return - element = ET.SubElement(root, "weight_window_checkpoints") - - if 'collision' in self._weight_window_checkpoints: - subelement = ET.SubElement(element, "collision") - subelement.text = str( - self._weight_window_checkpoints['collision']).lower() - - if 'surface' in self._weight_window_checkpoints: - subelement = ET.SubElement(element, "surface") - subelement.text = str( - self._weight_window_checkpoints['surface']).lower() - - def _create_max_history_splits_subelement(self, root): - if self._max_history_splits is not None: - elem = ET.SubElement(root, "max_history_splits") - elem.text = str(self._max_history_splits) - - def _create_max_secondaries_subelement(self, root): - if self._max_secondaries is not None: - elem = ET.SubElement(root, "max_secondaries") - elem.text = str(self._max_secondaries) + def _create_max_splits_subelement(self, root): + if self._max_splits is not None: + elem = ET.SubElement(root, "max_splits") + elem.text = str(self._max_splits) def _create_max_tracks_subelement(self, root): if self._max_tracks is not None: elem = ET.SubElement(root, "max_tracks") elem.text = str(self._max_tracks) - def _create_random_ray_subelement(self, root, mesh_memo=None): - if self._random_ray: - element = ET.SubElement(root, "random_ray") - for key, value in self._random_ray.items(): - if key == 'ray_source' and isinstance(value, SourceBase): - subelement = ET.SubElement(element, 'ray_source') - source_element = value.to_xml_element() - if source_element.find('bias') is not None: - raise RuntimeError( - "Ray source distributions should not be biased.") - subelement.append(source_element) - - elif key == 'source_region_meshes': - subelement = ET.SubElement(element, 'source_region_meshes') - for mesh, domains in value: - mesh_elem = ET.SubElement(subelement, 'mesh') - mesh_elem.set('id', str(mesh.id)) - for domain in domains: - domain_elem = ET.SubElement(mesh_elem, 'domain') - domain_elem.set('id', str(domain.id)) - domain_elem.set( - 'type', domain.__class__.__name__.lower()) - if mesh_memo is not None and mesh.id not in mesh_memo: - domain_elem.set('type', domain.__class__.__name__.lower()) - # See if a element already exists -- if not, add it - path = f"./mesh[@id='{mesh.id}']" - if root.find(path) is None: - root.append(mesh.to_xml_element()) - if mesh_memo is not None: - mesh_memo.add(mesh.id) - elif key == 'adjoint_source': - subelement = ET.SubElement(element, 'adjoint_source') - # Check that all entries are valid SourceBase instances, in case - # the random_ray setter was not used to populate dict entries. - if not isinstance(value, MutableSequence): - value = [value] - for source in value: - if not isinstance(source, SourceBase): - raise ValueError( - f'Invalid adjoint source type: {type(source)}. ' - 'Expected openmc.SourceBase.') - subelement.append(source.to_xml_element()) - elif isinstance(value, bool): - subelement = ET.SubElement(element, key) - subelement.text = str(value).lower() - else: - subelement = ET.SubElement(element, key) - subelement.text = str(value) - - def _create_source_rejection_fraction_subelement(self, root): - if self._source_rejection_fraction is not None: - element = ET.SubElement(root, "source_rejection_fraction") - element.text = str(self._source_rejection_fraction) - - def _create_free_gas_threshold_subelement(self, root): - if self._free_gas_threshold is not None: - element = ET.SubElement(root, "free_gas_threshold") - element.text = str(self._free_gas_threshold) - def _eigenvalue_from_xml_element(self, root): elem = root.find('eigenvalue') if elem is not None: @@ -2071,7 +1236,6 @@ class Settings: self._inactive_from_xml_element(elem) self._max_lost_particles_from_xml_element(elem) self._rel_max_lost_particles_from_xml_element(elem) - self._max_write_lost_particles_from_xml_element(elem) self._generations_per_batch_from_xml_element(elem) def _run_mode_from_xml_element(self, root): @@ -2104,11 +1268,6 @@ class Settings: if text is not None: self.rel_max_lost_particles = float(text) - def _max_write_lost_particles_from_xml_element(self, root): - text = get_text(root, 'max_write_lost_particles') - if text is not None: - self.max_write_lost_particles = int(text) - def _generations_per_batch_from_xml_element(self, root): text = get_text(root, 'generations_per_batch') if text is not None: @@ -2121,11 +1280,9 @@ class Settings: threshold = float(get_text(elem, 'threshold')) self.keff_trigger = {'type': trigger, 'threshold': threshold} - def _source_from_xml_element(self, root, meshes=None): + def _source_from_xml_element(self, root): for elem in root.findall('source'): - src = SourceBase.from_xml_element(elem, meshes) - # add newly constructed source object to the list - self.source.append(src) + self.source.append(Source.from_xml_element(elem)) def _volume_calcs_from_xml_element(self, root): volume_elems = root.findall("volume_calc") @@ -2147,66 +1304,43 @@ class Settings: def _statepoint_from_xml_element(self, root): elem = root.find('state_point') if elem is not None: - batches = get_elem_list(elem, "batches", int) - if batches is not None: - self.statepoint['batches'] = batches + text = get_text(elem, 'batches') + if text is not None: + self.statepoint['batches'] = [int(x) for x in text.split()] def _sourcepoint_from_xml_element(self, root): elem = root.find('source_point') if elem is not None: - for key in ('separate', 'write', 'overwrite_latest', 'batches', 'mcpl'): - if key in ('separate', 'write', 'mcpl', 'overwrite_latest'): - value = get_text(elem, key) in ('true', '1') - if key == 'overwrite_latest': - key = 'overwrite' - else: - value = get_elem_list(elem, key, int) + for key in ('separate', 'write', 'overwrite_latest', 'batches'): + value = get_text(elem, key) if value is not None: + if key in ('separate', 'write'): + value = value in ('true', '1') + elif key == 'overwrite_latest': + value = value in ('true', '1') + key = 'overwrite' + else: + value = [int(x) for x in value.split()] self.sourcepoint[key] = value def _surf_source_read_from_xml_element(self, root): elem = root.find('surf_source_read') if elem is not None: - ssr = {} value = get_text(elem, 'path') if value is not None: - ssr['path'] = value - self.surf_source_read = ssr + self.surf_source_read['path'] = value def _surf_source_write_from_xml_element(self, root): elem = root.find('surf_source_write') - if elem is None: - return - for key in ('surface_ids', 'max_particles', 'max_source_files', 'mcpl', 'cell', 'cellto', 'cellfrom'): - if key == 'surface_ids': - value = get_elem_list(elem, key, int) - else: - value = get_text(elem, key) - if value is not None: - if key == 'mcpl': - value = value in ('true', '1') - elif key in ('max_particles', 'max_source_files', 'cell', 'cellfrom', 'cellto'): - value = int(value) - self.surf_source_write[key] = value - - def _collision_track_from_xml_element(self, root): - elem = root.find('collision_track') if elem is not None: - for key in ('cell_ids', 'reactions', 'universe_ids', 'material_ids', 'nuclides', - 'deposited_E_threshold', 'max_collisions', "max_collision_track_files", 'mcpl'): + for key in ('surface_ids', 'max_particles'): value = get_text(elem, key) if value is not None: - if key in ('cell_ids', 'universe_ids', 'material_ids'): + if key == 'surface_ids': value = [int(x) for x in value.split()] - elif key in ('reactions', 'nuclides'): - value = value.split() - elif key in ('max_collisions', 'max_collision_track_files'): + elif key in ('max_particles'): value = int(value) - elif key == 'deposited_E_threshold': - value = float(value) - elif key == 'mcpl': - value = value in ('true', '1') - self.collision_track[key] = value + self.surf_source_write[key] = value def _confidence_intervals_from_xml_element(self, root): text = get_text(root, 'confidence_intervals') @@ -2218,11 +1352,6 @@ class Settings: if text is not None: self.electron_treatment = text - def _atomic_relaxation_from_xml_element(self, root): - text = get_text(root, 'atomic_relaxation') - if text is not None: - self.atomic_relaxation = text in ('true', '1') - def _energy_mode_from_xml_element(self, root): text = get_text(root, 'energy_mode') if text is not None: @@ -2238,16 +1367,6 @@ class Settings: if text is not None: self.photon_transport = text in ('true', '1') - def _uniform_source_sampling_from_xml_element(self, root): - text = get_text(root, 'uniform_source_sampling') - if text is not None: - self.uniform_source_sampling = text in ('true', '1') - - def _plot_seed_from_xml_element(self, root): - text = get_text(root, 'plot_seed') - if text is not None: - self.plot_seed = int(text) - def _ptables_from_xml_element(self, root): text = get_text(root, 'ptables') if text is not None: @@ -2258,21 +1377,6 @@ class Settings: if text is not None: self.seed = int(text) - def _stride_from_xml_element(self, root): - text = get_text(root, 'stride') - if text is not None: - self.stride = int(text) - - def _surface_grazing_cutoff_from_xml_element(self, root): - text = get_text(root, 'surface_grazing_cutoff') - if text is not None: - self.surface_grazing_cutoff = float(text) - - def _surface_grazing_ratio_from_xml_element(self, root): - text = get_text(root, 'surface_grazing_ratio') - if text is not None: - self.surface_grazing_ratio = float(text) - def _survival_biasing_from_xml_element(self, root): text = get_text(root, 'survival_biasing') if text is not None: @@ -2283,24 +1387,18 @@ class Settings: if elem is not None: self.cutoff = {} for key in ('energy_neutron', 'energy_photon', 'energy_electron', - 'energy_positron', 'weight', 'weight_avg', 'time_neutron', - 'time_photon', 'time_electron', 'time_positron', - 'survival_normalization'): + 'energy_positron', 'weight', 'weight_avg'): value = get_text(elem, key) if value is not None: - if key == 'survival_normalization': - self.cutoff[key] = value in ('true', '1') - else: - self.cutoff[key] = float(value) + self.cutoff[key] = float(value) - def _entropy_mesh_from_xml_element(self, root, meshes): + def _entropy_mesh_from_xml_element(self, root): text = get_text(root, 'entropy_mesh') - if text is None: - return - mesh_id = int(text) - if mesh_id not in meshes: - raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') - self.entropy_mesh = meshes[mesh_id] + if text is not None: + path = f"./mesh[@id='{int(text)}']" + elem = root.find(path) + if elem is not None: + self.entropy_mesh = RegularMesh.from_xml_element(elem) def _trigger_from_xml_element(self, root): elem = root.find('trigger') @@ -2323,11 +1421,6 @@ class Settings: if text is not None: self.verbosity = int(text) - def _ifp_n_generation_from_xml_element(self, root): - text = get_text(root, 'ifp_n_generation') - if text is not None: - self.ifp_n_generation = int(text) - def _tabular_legendre_from_xml_element(self, root): elem = root.find('tabular_legendre') if elem is not None: @@ -2347,51 +1440,45 @@ class Settings: text = get_text(root, 'temperature_method') if text is not None: self.temperature['method'] = text - text = get_elem_list(root, "temperature_range", float) + text = get_text(root, 'temperature_range') if text is not None: - self.temperature['range'] = text + self.temperature['range'] = [float(x) for x in text.split()] text = get_text(root, 'temperature_multipole') if text is not None: self.temperature['multipole'] = text in ('true', '1') - def _properties_file_from_xml_element(self, root): - text = get_text(root, 'properties_file') - if text is not None: - self.properties_file = text - def _trace_from_xml_element(self, root): - text = get_elem_list(root, "trace", int) + text = get_text(root, 'trace') if text is not None: - self.trace = text + self.trace = [int(x) for x in text.split()] def _track_from_xml_element(self, root): - values = get_elem_list(root, "track", int) - if values is not None: + text = get_text(root, 'track') + if text is not None: + values = [int(x) for x in text.split()] self.track = list(zip(values[::3], values[1::3], values[2::3])) - def _ufs_mesh_from_xml_element(self, root, meshes): + def _ufs_mesh_from_xml_element(self, root): text = get_text(root, 'ufs_mesh') - if text is None: - return - mesh_id = int(text) - if mesh_id not in meshes: - raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') - self.ufs_mesh = meshes[mesh_id] + if text is not None: + path = f"./mesh[@id='{int(text)}']" + elem = root.find(path) + if elem is not None: + self.ufs_mesh = RegularMesh.from_xml_element(elem) def _resonance_scattering_from_xml_element(self, root): elem = root.find('resonance_scattering') if elem is not None: keys = ('enable', 'method', 'energy_min', 'energy_max', 'nuclides') for key in keys: - if key == 'nuclides': - value = get_elem_list(elem, key, str) - else: - value = get_text(elem, key) + value = get_text(elem, key) if value is not None: if key == 'enable': value = value in ('true', '1') elif key in ('energy_min', 'energy_max'): value = float(value) + elif key == 'nuclides': + value = value.split() self.resonance_scattering[key] = value def _create_fission_neutrons_from_xml_element(self, root): @@ -2399,11 +1486,6 @@ class Settings: if text is not None: self.create_fission_neutrons = text in ('true', '1') - def _create_delayed_neutrons_from_xml_element(self, root): - text = get_text(root, 'create_delayed_neutrons') - if text is not None: - self.create_delayed_neutrons = text in ('true', '1') - def _delayed_photon_scaling_from_xml_element(self, root): text = get_text(root, 'delayed_photon_scaling') if text is not None: @@ -2419,11 +1501,6 @@ class Settings: if text is not None: self.max_particles_in_flight = int(text) - def _max_particle_events_from_xml_element(self, root): - text = get_text(root, 'max_particle_events') - if text is not None: - self.max_particle_events = int(text) - def _material_cell_offsets_from_xml_element(self, root): text = get_text(root, 'material_cell_offsets') if text is not None: @@ -2439,211 +1516,26 @@ class Settings: if text is not None: self.write_initial_source = text in ('true', '1') - def _weight_window_generators_from_xml_element(self, root, meshes=None): - for elem in root.iter('weight_windows_generator'): - wwg = WeightWindowGenerator.from_xml_element(elem, meshes) - self.weight_window_generators.append(wwg) - - def _weight_windows_from_xml_element(self, root, meshes=None): + def _weight_windows_from_xml_element(self, root): for elem in root.findall('weight_windows'): - ww = WeightWindows.from_xml_element(elem, meshes) + ww = WeightWindows.from_xml_element(elem, root) self.weight_windows.append(ww) - def _weight_windows_on_from_xml_element(self, root): text = get_text(root, 'weight_windows_on') if text is not None: self.weight_windows_on = text in ('true', '1') - def _shared_secondary_bank_from_xml_element(self, root): - text = get_text(root, 'shared_secondary_bank') + def _max_splits_from_xml_element(self, root): + text = get_text(root, 'max_splits') if text is not None: - self.shared_secondary_bank = text in ('true', '1') - - def _weight_windows_file_from_xml_element(self, root): - text = get_text(root, 'weight_windows_file') - if text is not None: - self.weight_windows_file = text - - def _weight_window_checkpoints_from_xml_element(self, root): - elem = root.find('weight_window_checkpoints') - if elem is None: - return - for key in ('collision', 'surface'): - value = get_text(elem, key) - if value is not None: - value = value in ('true', '1') - self.weight_window_checkpoints[key] = value - - def _max_history_splits_from_xml_element(self, root): - text = get_text(root, 'max_history_splits') - if text is not None: - self.max_history_splits = int(text) - - def _max_secondaries_from_xml_element(self, root): - text = get_text(root, 'max_secondaries') - if text is not None: - self.max_secondaries = int(text) + self.max_splits = int(text) def _max_tracks_from_xml_element(self, root): text = get_text(root, 'max_tracks') if text is not None: self.max_tracks = int(text) - def _random_ray_from_xml_element(self, root, meshes=None): - elem = root.find('random_ray') - if elem is not None: - self.random_ray = {} - for child in elem: - if child.tag in ('distance_inactive', 'distance_active', 'diagonal_stabilization_rho'): - self.random_ray[child.tag] = float(child.text) - elif child.tag == 'ray_source': - source_element = child.find('source') - source = SourceBase.from_xml_element(source_element) - if child.find('bias') is not None: - raise RuntimeError( - "Ray source distributions should not be biased.") - self.random_ray['ray_source'] = source - elif child.tag == 'volume_estimator': - self.random_ray['volume_estimator'] = child.text - elif child.tag == 'source_shape': - self.random_ray['source_shape'] = child.text - elif child.tag == 'volume_normalized_flux_tallies': - self.random_ray['volume_normalized_flux_tallies'] = ( - child.text in ('true', '1') - ) - elif child.tag == 'adjoint': - self.random_ray['adjoint'] = ( - child.text in ('true', '1') - ) - elif child.tag == 'adjoint_source': - self.random_ray['adjoint_source'] = [] - for subelem in child.findall('source'): - src = SourceBase.from_xml_element(subelem) - # add newly constructed source object to the list - self.random_ray['adjoint_source'].append(src) - elif child.tag == 'sample_method': - self.random_ray['sample_method'] = child.text - elif child.tag == 'source_region_meshes': - self.random_ray['source_region_meshes'] = [] - for mesh_elem in child.findall('mesh'): - mesh_id = int(get_text(mesh_elem, 'id')) - if meshes and mesh_id in meshes: - mesh = meshes[mesh_id] - else: - mesh = MeshBase.from_xml_element(mesh_elem) - domains = [] - for domain_elem in mesh_elem.findall('domain'): - domain_id = int(get_text(domain_elem, "id")) - domain_type = get_text(domain_elem, "type") - if domain_type == 'material': - domain = openmc.Material(domain_id) - elif domain_type == 'cell': - domain = openmc.Cell(domain_id) - elif domain_type == 'universe': - domain = openmc.Universe(domain_id) - domains.append(domain) - self.random_ray['source_region_meshes'].append( - (mesh, domains)) - - def _use_decay_photons_from_xml_element(self, root): - text = get_text(root, 'use_decay_photons') - if text is not None: - self.use_decay_photons = text in ('true', '1') - - def _source_rejection_fraction_from_xml_element(self, root): - text = get_text(root, 'source_rejection_fraction') - if text is not None: - self.source_rejection_fraction = float(text) - - def _free_gas_threshold_from_xml_element(self, root): - text = get_text(root, 'free_gas_threshold') - if text is not None: - self.free_gas_threshold = float(text) - - def to_xml_element(self, mesh_memo=None): - """Create a 'settings' element to be written to an XML file. - - Parameters - ---------- - mesh_memo : set of ints - A set of mesh IDs to keep track of whether a mesh has already been written. - """ - # Reset xml element tree - element = ET.Element("settings") - - self._create_run_mode_subelement(element) - self._create_particles_subelement(element) - self._create_batches_subelement(element) - self._create_inactive_subelement(element) - self._create_max_lost_particles_subelement(element) - self._create_rel_max_lost_particles_subelement(element) - self._create_max_write_lost_particles_subelement(element) - self._create_generations_per_batch_subelement(element) - self._create_keff_trigger_subelement(element) - self._create_source_subelement(element, mesh_memo) - self._create_output_subelement(element) - self._create_statepoint_subelement(element) - self._create_sourcepoint_subelement(element) - self._create_surf_source_read_subelement(element) - self._create_surf_source_write_subelement(element) - self._create_collision_track_subelement(element) - self._create_confidence_intervals(element) - self._create_electron_treatment_subelement(element) - self._create_atomic_relaxation_subelement(element) - self._create_energy_mode_subelement(element) - self._create_max_order_subelement(element) - self._create_photon_transport_subelement(element) - self._create_uniform_source_sampling_subelement(element) - self._create_plot_seed_subelement(element) - self._create_ptables_subelement(element) - self._create_seed_subelement(element) - self._create_stride_subelement(element) - self._create_surface_grazing_cutoff_subelement(element) - self._create_surface_grazing_ratio_subelement(element) - self._create_survival_biasing_subelement(element) - self._create_cutoff_subelement(element) - self._create_entropy_mesh_subelement(element, mesh_memo) - self._create_trigger_subelement(element) - self._create_no_reduce_subelement(element) - self._create_verbosity_subelement(element) - self._create_ifp_n_generation_subelement(element) - self._create_tabular_legendre_subelements(element) - self._create_temperature_subelements(element) - self._create_properties_file_element(element) - self._create_trace_subelement(element) - self._create_track_subelement(element) - self._create_ufs_mesh_subelement(element, mesh_memo) - self._create_resonance_scattering_subelement(element) - self._create_volume_calcs_subelement(element) - self._create_create_fission_neutrons_subelement(element) - self._create_create_delayed_neutrons_subelement(element) - self._create_delayed_photon_scaling_subelement(element) - self._create_event_based_subelement(element) - self._create_max_particles_in_flight_subelement(element) - self._create_max_events_subelement(element) - self._create_material_cell_offsets_subelement(element) - self._create_log_grid_bins_subelement(element) - self._create_write_initial_source_subelement(element) - self._create_weight_windows_subelement(element, mesh_memo) - self._create_weight_windows_on_subelement(element) - self._create_shared_secondary_bank_subelement(element) - self._create_weight_window_generators_subelement(element, mesh_memo) - self._create_weight_windows_file_element(element) - self._create_weight_window_checkpoints_subelement(element) - self._create_max_history_splits_subelement(element) - self._create_max_tracks_subelement(element) - self._create_max_secondaries_subelement(element) - self._create_random_ray_subelement(element, mesh_memo) - self._create_use_decay_photons_subelement(element) - self._create_source_rejection_fraction_subelement(element) - self._create_free_gas_threshold_subelement(element) - - # Clean the indentation in the file to be user-readable - clean_indentation(element) - - return element - - def export_to_xml(self, path: PathLike = 'settings.xml'): + def export_to_xml(self, path: Union[str, os.PathLike] = 'settings.xml'): """Export simulation settings to an XML file. Parameters @@ -2652,7 +1544,57 @@ class Settings: Path to file to write. Defaults to 'settings.xml'. """ - root_element = self.to_xml_element() + + # Reset xml element tree + root_element = ET.Element("settings") + + self._create_run_mode_subelement(root_element) + self._create_particles_subelement(root_element) + self._create_batches_subelement(root_element) + self._create_inactive_subelement(root_element) + self._create_max_lost_particles_subelement(root_element) + self._create_rel_max_lost_particles_subelement(root_element) + self._create_generations_per_batch_subelement(root_element) + self._create_keff_trigger_subelement(root_element) + self._create_source_subelement(root_element) + self._create_output_subelement(root_element) + self._create_statepoint_subelement(root_element) + self._create_sourcepoint_subelement(root_element) + self._create_surf_source_read_subelement(root_element) + self._create_surf_source_write_subelement(root_element) + self._create_confidence_intervals(root_element) + self._create_electron_treatment_subelement(root_element) + self._create_energy_mode_subelement(root_element) + self._create_max_order_subelement(root_element) + self._create_photon_transport_subelement(root_element) + self._create_ptables_subelement(root_element) + self._create_seed_subelement(root_element) + self._create_survival_biasing_subelement(root_element) + self._create_cutoff_subelement(root_element) + self._create_entropy_mesh_subelement(root_element) + self._create_trigger_subelement(root_element) + self._create_no_reduce_subelement(root_element) + self._create_verbosity_subelement(root_element) + self._create_tabular_legendre_subelements(root_element) + self._create_temperature_subelements(root_element) + self._create_trace_subelement(root_element) + self._create_track_subelement(root_element) + self._create_ufs_mesh_subelement(root_element) + self._create_resonance_scattering_subelement(root_element) + self._create_volume_calcs_subelement(root_element) + self._create_create_fission_neutrons_subelement(root_element) + self._create_delayed_photon_scaling_subelement(root_element) + self._create_event_based_subelement(root_element) + self._create_max_particles_in_flight_subelement(root_element) + self._create_material_cell_offsets_subelement(root_element) + self._create_log_grid_bins_subelement(root_element) + self._create_write_initial_source_subelement(root_element) + self._create_weight_windows_subelement(root_element) + self._create_max_splits_subelement(root_element) + self._create_max_tracks_subelement(root_element) + + # Clean the indentation in the file to be user-readable + clean_indentation(root_element) # Check if path is a directory p = Path(path) @@ -2660,106 +1602,12 @@ class Settings: p /= 'settings.xml' # Write the XML Tree to the settings.xml file + reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod - def from_xml_element(cls, elem, meshes=None): - """Generate settings from XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict or None - A dictionary with mesh IDs as keys and mesh instances as values that - have already been read from XML. Pre-existing meshes are used - and new meshes are added to when creating tally objects. - - Returns - ------- - openmc.Settings - Settings object - - """ - # read all meshes under the settings node and update - settings_meshes = _read_meshes(elem) - meshes = {} if meshes is None else meshes - meshes.update(settings_meshes) - - settings = cls() - settings._eigenvalue_from_xml_element(elem) - settings._run_mode_from_xml_element(elem) - settings._particles_from_xml_element(elem) - settings._batches_from_xml_element(elem) - settings._inactive_from_xml_element(elem) - settings._max_lost_particles_from_xml_element(elem) - settings._rel_max_lost_particles_from_xml_element(elem) - settings._max_write_lost_particles_from_xml_element(elem) - settings._generations_per_batch_from_xml_element(elem) - settings._keff_trigger_from_xml_element(elem) - settings._source_from_xml_element(elem, meshes) - settings._volume_calcs_from_xml_element(elem) - settings._output_from_xml_element(elem) - settings._statepoint_from_xml_element(elem) - settings._sourcepoint_from_xml_element(elem) - settings._surf_source_read_from_xml_element(elem) - settings._surf_source_write_from_xml_element(elem) - settings._collision_track_from_xml_element(elem) - settings._confidence_intervals_from_xml_element(elem) - settings._electron_treatment_from_xml_element(elem) - settings._atomic_relaxation_from_xml_element(elem) - settings._energy_mode_from_xml_element(elem) - settings._max_order_from_xml_element(elem) - settings._photon_transport_from_xml_element(elem) - settings._uniform_source_sampling_from_xml_element(elem) - settings._plot_seed_from_xml_element(elem) - settings._ptables_from_xml_element(elem) - settings._seed_from_xml_element(elem) - settings._stride_from_xml_element(elem) - settings._surface_grazing_cutoff_from_xml_element(elem) - settings._surface_grazing_ratio_from_xml_element(elem) - settings._survival_biasing_from_xml_element(elem) - settings._cutoff_from_xml_element(elem) - settings._entropy_mesh_from_xml_element(elem, meshes) - settings._trigger_from_xml_element(elem) - settings._no_reduce_from_xml_element(elem) - settings._verbosity_from_xml_element(elem) - settings._ifp_n_generation_from_xml_element(elem) - settings._tabular_legendre_from_xml_element(elem) - settings._temperature_from_xml_element(elem) - settings._properties_file_from_xml_element(elem) - settings._trace_from_xml_element(elem) - settings._track_from_xml_element(elem) - settings._ufs_mesh_from_xml_element(elem, meshes) - settings._resonance_scattering_from_xml_element(elem) - settings._create_fission_neutrons_from_xml_element(elem) - settings._create_delayed_neutrons_from_xml_element(elem) - settings._delayed_photon_scaling_from_xml_element(elem) - settings._event_based_from_xml_element(elem) - settings._max_particles_in_flight_from_xml_element(elem) - settings._max_particle_events_from_xml_element(elem) - settings._material_cell_offsets_from_xml_element(elem) - settings._log_grid_bins_from_xml_element(elem) - settings._write_initial_source_from_xml_element(elem) - settings._weight_windows_from_xml_element(elem, meshes) - settings._weight_windows_on_from_xml_element(elem) - settings._shared_secondary_bank_from_xml_element(elem) - settings._weight_windows_file_from_xml_element(elem) - settings._weight_window_generators_from_xml_element(elem, meshes) - settings._weight_window_checkpoints_from_xml_element(elem) - settings._max_history_splits_from_xml_element(elem) - settings._max_tracks_from_xml_element(elem) - settings._max_secondaries_from_xml_element(elem) - settings._random_ray_from_xml_element(elem, meshes) - settings._use_decay_photons_from_xml_element(elem) - settings._source_rejection_fraction_from_xml_element(elem) - settings._free_gas_threshold_from_xml_element(elem) - - return settings - - @classmethod - def from_xml(cls, path: PathLike = 'settings.xml'): + def from_xml(cls, path: Union[str, os.PathLike] = 'settings.xml'): """Generate settings from XML file .. versionadded:: 0.13.0 @@ -2775,8 +1623,56 @@ class Settings: Settings object """ - parser = ET.XMLParser(huge_tree=True) - tree = ET.parse(path, parser=parser) + tree = ET.parse(path) root = tree.getroot() - meshes = _read_meshes(root) - return cls.from_xml_element(root, meshes) + + settings = cls() + settings._eigenvalue_from_xml_element(root) + settings._run_mode_from_xml_element(root) + settings._particles_from_xml_element(root) + settings._batches_from_xml_element(root) + settings._inactive_from_xml_element(root) + settings._max_lost_particles_from_xml_element(root) + settings._rel_max_lost_particles_from_xml_element(root) + settings._generations_per_batch_from_xml_element(root) + settings._keff_trigger_from_xml_element(root) + settings._source_from_xml_element(root) + settings._volume_calcs_from_xml_element(root) + settings._output_from_xml_element(root) + settings._statepoint_from_xml_element(root) + settings._sourcepoint_from_xml_element(root) + settings._surf_source_read_from_xml_element(root) + settings._surf_source_write_from_xml_element(root) + settings._confidence_intervals_from_xml_element(root) + settings._electron_treatment_from_xml_element(root) + settings._energy_mode_from_xml_element(root) + settings._max_order_from_xml_element(root) + settings._photon_transport_from_xml_element(root) + settings._ptables_from_xml_element(root) + settings._seed_from_xml_element(root) + settings._survival_biasing_from_xml_element(root) + settings._cutoff_from_xml_element(root) + settings._entropy_mesh_from_xml_element(root) + settings._trigger_from_xml_element(root) + settings._no_reduce_from_xml_element(root) + settings._verbosity_from_xml_element(root) + settings._tabular_legendre_from_xml_element(root) + settings._temperature_from_xml_element(root) + settings._trace_from_xml_element(root) + settings._track_from_xml_element(root) + settings._ufs_mesh_from_xml_element(root) + settings._resonance_scattering_from_xml_element(root) + settings._create_fission_neutrons_from_xml_element(root) + settings._delayed_photon_scaling_from_xml_element(root) + settings._event_based_from_xml_element(root) + settings._max_particles_in_flight_from_xml_element(root) + settings._material_cell_offsets_from_xml_element(root) + settings._log_grid_bins_from_xml_element(root) + settings._write_initial_source_from_xml_element(root) + settings._weight_windows_from_xml_element(root) + settings._max_splits_from_xml_element(root) + settings._max_tracks_from_xml_element(root) + + # TODO: Get volume calculations + + return settings diff --git a/openmc/source.py b/openmc/source.py index 5947540d6..bd4c28ba4 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -1,261 +1,19 @@ -from __future__ import annotations -from abc import ABC, abstractmethod -from collections.abc import Iterable, Sequence -from numbers import Integral, Real -from pathlib import Path -import warnings -from typing import Any +from enum import Enum +from numbers import Real +from xml.etree import ElementTree as ET -import lxml.etree as ET import numpy as np import h5py -import pandas as pd -import openmc import openmc.checkvalue as cv -from openmc.checkvalue import PathLike from openmc.stats.multivariate import UnitSphere, Spatial from openmc.stats.univariate import Univariate -from ._xml import get_elem_list, get_text -from .mesh import MeshBase, StructuredMesh, UnstructuredMesh -from .particle_type import ParticleType -from .statepoint import _VERSION_STATEPOINT -from .utility_funcs import input_path +from ._xml import get_text -class SourceBase(ABC): - """Base class for external sources - - Parameters - ---------- - strength : float - Strength of the source - constraints : dict - Constraints on sampled source particles. Valid keys include 'domains', - 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. - For 'domains', the corresponding value is an iterable of - :class:`openmc.Cell`, :class:`openmc.Material`, or - :class:`openmc.Universe` for which sampled sites must be within. For - 'time_bounds' and 'energy_bounds', the corresponding value is a sequence - of floats giving the lower and upper bounds on time in [s] or energy in - [eV] that the sampled particle must be within. For 'fissionable', the - value is a bool indicating that only sites in fissionable material - should be accepted. The 'rejection_strategy' indicates what should - happen when a source particle is rejected: either 'resample' (pick a new - particle) or 'kill' (accept and terminate). - - Attributes - ---------- - type : {'independent', 'file', 'compiled', 'mesh', 'tokamak'} - Indicator of source type. - strength : float - Strength of the source - constraints : dict - Constraints on sampled source particles. Valid keys include - 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', - 'fissionable', and 'rejection_strategy'. - - """ - - def __init__( - self, - strength: float | None = 1.0, - constraints: dict[str, Any] | None = None - ): - self.strength = strength - self.constraints = constraints - - @property - def strength(self): - return self._strength - - @strength.setter - def strength(self, strength): - cv.check_type('source strength', strength, Real, none_ok=True) - if strength is not None: - cv.check_greater_than('source strength', strength, 0.0, True) - self._strength = strength - - @property - def constraints(self) -> dict[str, Any]: - return self._constraints - - @constraints.setter - def constraints(self, constraints: dict[str, Any] | None): - self._constraints = {} - if constraints is None: - return - - for key, value in constraints.items(): - if key == 'domains': - cv.check_type('domains', value, Iterable, - (openmc.Cell, openmc.Material, openmc.Universe)) - if isinstance(value[0], openmc.Cell): - self._constraints['domain_type'] = 'cell' - elif isinstance(value[0], openmc.Material): - self._constraints['domain_type'] = 'material' - elif isinstance(value[0], openmc.Universe): - self._constraints['domain_type'] = 'universe' - self._constraints['domain_ids'] = [d.id for d in value] - elif key == 'time_bounds': - cv.check_type('time bounds', value, Iterable, Real) - self._constraints['time_bounds'] = tuple(value) - elif key == 'energy_bounds': - cv.check_type('energy bounds', value, Iterable, Real) - self._constraints['energy_bounds'] = tuple(value) - elif key == 'fissionable': - cv.check_type('fissionable', value, bool) - self._constraints['fissionable'] = value - elif key == 'rejection_strategy': - cv.check_value('rejection strategy', - value, ('resample', 'kill')) - self._constraints['rejection_strategy'] = value - else: - raise ValueError( - f'Unknown key in constraints dictionary: {key}') - - @abstractmethod - def populate_xml_element(self, element): - """Add necessary source information to an XML element - - Returns - ------- - element : lxml.etree._Element - XML element containing source data - - """ - - def to_xml_element(self) -> ET.Element: - """Return XML representation of the source - - Returns - ------- - element : xml.etree.ElementTree.Element - XML element containing source data - - """ - element = ET.Element("source") - element.set("type", self.type) - if self.strength is not None: - element.set("strength", str(self.strength)) - self.populate_xml_element(element) - constraints = self.constraints - if constraints: - constraints_elem = ET.SubElement(element, "constraints") - if "domain_ids" in constraints: - dt_elem = ET.SubElement(constraints_elem, "domain_type") - dt_elem.text = constraints["domain_type"] - id_elem = ET.SubElement(constraints_elem, "domain_ids") - id_elem.text = ' '.join(str(uid) - for uid in constraints["domain_ids"]) - if "time_bounds" in constraints: - dt_elem = ET.SubElement(constraints_elem, "time_bounds") - dt_elem.text = ' '.join(str(t) - for t in constraints["time_bounds"]) - if "energy_bounds" in constraints: - dt_elem = ET.SubElement(constraints_elem, "energy_bounds") - dt_elem.text = ' '.join(str(E) - for E in constraints["energy_bounds"]) - if "fissionable" in constraints: - dt_elem = ET.SubElement(constraints_elem, "fissionable") - dt_elem.text = str(constraints["fissionable"]).lower() - if "rejection_strategy" in constraints: - dt_elem = ET.SubElement(constraints_elem, "rejection_strategy") - dt_elem.text = constraints["rejection_strategy"] - - return element - - @classmethod - def from_xml_element(cls, elem: ET.Element, meshes=None) -> SourceBase: - """Generate source from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict - Dictionary with mesh IDs as keys and openmc.MeshBase instances as - values - - Returns - ------- - openmc.SourceBase - Source generated from XML element - - """ - source_type = get_text(elem, 'type') - - if source_type is None: - # attempt to determine source type based on attributes - # for backward compatibility - if get_text(elem, 'file') is not None: - return FileSource.from_xml_element(elem) - elif get_text(elem, 'library') is not None: - return CompiledSource.from_xml_element(elem) - else: - return IndependentSource.from_xml_element(elem) - else: - if source_type == 'independent': - return IndependentSource.from_xml_element(elem, meshes) - elif source_type == 'compiled': - return CompiledSource.from_xml_element(elem) - elif source_type == 'file': - return FileSource.from_xml_element(elem) - elif source_type == 'mesh': - return MeshSource.from_xml_element(elem, meshes) - elif source_type == 'tokamak': - return TokamakSource.from_xml_element(elem) - else: - raise ValueError( - f'Source type {source_type} is not recognized') - - @staticmethod - def _get_constraints(elem: ET.Element) -> dict[str, Any]: - # Find element containing constraints - constraints_elem = elem.find("constraints") - elem = constraints_elem if constraints_elem is not None else elem - - constraints = {} - domain_type = get_text(elem, "domain_type") - if domain_type is not None: - domain_ids = get_elem_list(elem, "domain_ids", int) - - # Instantiate some throw-away domains that are used by the - # constructor to assign IDs - with warnings.catch_warnings(): - warnings.simplefilter('ignore', openmc.IDWarning) - if domain_type == 'cell': - domains = [openmc.Cell(uid) for uid in domain_ids] - elif domain_type == 'material': - domains = [openmc.Material(uid) for uid in domain_ids] - elif domain_type == 'universe': - domains = [openmc.Universe(uid) for uid in domain_ids] - constraints['domains'] = domains - - time_bounds = get_elem_list(elem, "time_bounds", float) - if time_bounds is not None: - constraints['time_bounds'] = time_bounds - - energy_bounds = get_elem_list(elem, "energy_bounds", float) - if energy_bounds is not None: - constraints['energy_bounds'] = energy_bounds - - fissionable = get_text(elem, "fissionable") - if fissionable is not None: - constraints['fissionable'] = fissionable in ('true', '1') - - rejection_strategy = get_text(elem, "rejection_strategy") - if rejection_strategy is not None: - constraints['rejection_strategy'] = rejection_strategy - - return constraints - - -class IndependentSource(SourceBase): +class Source: """Distribution of phase space coordinates for source sites. - .. versionadded:: 0.14.0 - Parameters ---------- space : openmc.stats.Spatial @@ -266,29 +24,18 @@ class IndependentSource(SourceBase): Energy distribution of source sites time : openmc.stats.Univariate time distribution of source sites + filename : str + Source file from which sites should be sampled + library : str + Path to a custom source library + parameters : str + Parameters to be provided to the custom source library + + .. versionadded:: 0.12 strength : float Strength of the source - particle : str or int or openmc.ParticleType - Source particle type (name, PDG number, or type) - domains : iterable of openmc.Cell, openmc.Material, or openmc.Universe - Domains to reject based on, i.e., if a sampled spatial location is not - within one of these domains, it will be rejected. - - .. deprecated:: 0.15.0 - Use the `constraints` argument instead. - constraints : dict - Constraints on sampled source particles. Valid keys include 'domains', - 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. - For 'domains', the corresponding value is an iterable of - :class:`openmc.Cell`, :class:`openmc.Material`, or - :class:`openmc.Universe` for which sampled sites must be within. For - 'time_bounds' and 'energy_bounds', the corresponding value is a sequence - of floats giving the lower and upper bounds on time in [s] or energy in - [eV] that the sampled particle must be within. For 'fissionable', the - value is a bool indicating that only sites in fissionable material - should be accepted. The 'rejection_strategy' indicates what should - happen when a source particle is rejected: either 'resample' (pick a new - particle) or 'kill' (accept and terminate). + particle : {'neutron', 'photon'} + Source particle type Attributes ---------- @@ -300,44 +47,28 @@ class IndependentSource(SourceBase): Energy distribution of source sites time : openmc.stats.Univariate or None time distribution of source sites + file : str or None + Source file from which sites should be sampled + library : str or None + Path to a custom source library + parameters : str + Parameters to be provided to the custom source library strength : float Strength of the source - type : str - Indicator of source type: 'independent' - - .. versionadded:: 0.14.0 - particle : str or int or openmc.ParticleType - Source particle type (alias, PDG number, or GNDS nuclide name) - constraints : dict - Constraints on sampled source particles. Valid keys include - 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', - 'fissionable', and 'rejection_strategy'. + particle : {'neutron', 'photon'} + Source particle type """ - def __init__( - self, - space: openmc.stats.Spatial | None = None, - angle: openmc.stats.UnitSphere | None = None, - energy: openmc.stats.Univariate | None = None, - time: openmc.stats.Univariate | None = None, - strength: float = 1.0, - particle: str | int | ParticleType = 'neutron', - domains: Sequence[openmc.Cell | openmc.Material | - openmc.Universe] | None = None, - constraints: dict[str, Any] | None = None - ): - if domains is not None: - warnings.warn("The 'domains' arguments has been replaced by the " - "'constraints' argument.", FutureWarning) - constraints = {'domains': domains} - - super().__init__(strength=strength, constraints=constraints) - + def __init__(self, space=None, angle=None, energy=None, time=None, filename=None, + library=None, parameters=None, strength=1.0, particle='neutron'): self._space = None self._angle = None self._energy = None self._time = None + self._file = None + self._library = None + self._parameters = None if space is not None: self.space = space @@ -347,83 +78,116 @@ class IndependentSource(SourceBase): self.energy = energy if time is not None: self.time = time + if filename is not None: + self.file = filename + if library is not None: + self.library = library + if parameters is not None: + self.parameters = parameters + self.strength = strength self.particle = particle @property - def type(self) -> str: - return 'independent' + def file(self): + return self._file - def __getattr__(self, name): - cls_names = {'file': 'FileSource', 'library': 'CompiledSource', - 'parameters': 'CompiledSource'} - if name in cls_names: - raise AttributeError( - f'The "{name}" attribute has been deprecated on the ' - f'IndependentSource class. Please use the {cls_names[name]} class.') - else: - super().__getattribute__(name) + @property + def library(self): + return self._library - def __setattr__(self, name, value): - if name in ('file', 'library', 'parameters'): - # Ensure proper AttributeError is thrown - getattr(self, name) - else: - super().__setattr__(name, value) + @property + def parameters(self): + return self._parameters @property def space(self): return self._space + @property + def angle(self): + return self._angle + + @property + def energy(self): + return self._energy + + @property + def time(self): + return self._time + + @property + def strength(self): + return self._strength + + @property + def particle(self): + return self._particle + + @file.setter + def file(self, filename): + cv.check_type('source file', filename, str) + self._file = filename + + @library.setter + def library(self, library_name): + cv.check_type('library', library_name, str) + self._library = library_name + + @parameters.setter + def parameters(self, parameters_path): + cv.check_type('parameters', parameters_path, str) + self._parameters = parameters_path + @space.setter def space(self, space): cv.check_type('spatial distribution', space, Spatial) self._space = space - @property - def angle(self): - return self._angle - @angle.setter def angle(self, angle): cv.check_type('angular distribution', angle, UnitSphere) self._angle = angle - @property - def energy(self): - return self._energy - @energy.setter def energy(self, energy): cv.check_type('energy distribution', energy, Univariate) self._energy = energy - @property - def time(self): - return self._time - @time.setter def time(self, time): cv.check_type('time distribution', time, Univariate) self._time = time - @property - def particle(self) -> ParticleType: - return self._particle + @strength.setter + def strength(self, strength): + cv.check_type('source strength', strength, Real) + cv.check_greater_than('source strength', strength, 0.0, True) + self._strength = strength @particle.setter def particle(self, particle): - self._particle = ParticleType(particle) + cv.check_value('source particle', particle, ['neutron', 'photon']) + self._particle = particle - def populate_xml_element(self, element): - """Add necessary source information to an XML element + def to_xml_element(self): + """Return XML representation of the source Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing source data """ - element.set("particle", str(self.particle)) + element = ET.Element("source") + element.set("strength", str(self.strength)) + if self.particle != 'neutron': + element.set("particle", self.particle) + if self.file is not None: + element.set("file", self.file) + if self.library is not None: + element.set("library", self.library) + if self.parameters is not None: + element.set("parameters", self.parameters) if self.space is not None: element.append(self.space.to_xml_element()) if self.angle is not None: @@ -432,18 +196,16 @@ class IndependentSource(SourceBase): element.append(self.energy.to_xml_element('energy')) if self.time is not None: element.append(self.time.to_xml_element('time')) + return element @classmethod - def from_xml_element(cls, elem: ET.Element, meshes=None) -> SourceBase: + def from_xml_element(cls, elem): """Generate source from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element - meshes : dict - Dictionary with mesh IDs as keys and openmc.MeshBase instaces as - values Returns ------- @@ -451,8 +213,7 @@ class IndependentSource(SourceBase): Source generated from XML element """ - constraints = cls._get_constraints(elem) - source = cls(constraints=constraints) + source = cls() strength = get_text(elem, 'strength') if strength is not None: @@ -462,9 +223,21 @@ class IndependentSource(SourceBase): if particle is not None: source.particle = particle + filename = get_text(elem, 'file') + if filename is not None: + source.file = filename + + library = get_text(elem, 'library') + if library is not None: + source.library = library + + parameters = get_text(elem, 'parameters') + if parameters is not None: + source.parameters = parameters + space = elem.find('space') if space is not None: - source.space = Spatial.from_xml_element(space, meshes) + source.space = Spatial.from_xml_element(space) angle = elem.find('angle') if angle is not None: @@ -481,847 +254,11 @@ class IndependentSource(SourceBase): return source -class MeshSource(SourceBase): - """A source with a spatial distribution over mesh elements - - This class represents a mesh-based source in which random positions are - uniformly sampled within mesh elements and each element can have independent - angle, energy, and time distributions. The element sampled is chosen based - on the relative strengths of the sources applied to the elements. The - strength of the mesh source as a whole is the sum of all source strengths - applied to the elements. - - .. versionadded:: 0.15.0 - - Parameters - ---------- - mesh : openmc.MeshBase - The mesh over which source sites will be generated. - sources : sequence of openmc.SourceBase - Sources for each element in the mesh. Sources must be specified as - either a 1-D array in the order of the mesh indices or a - multidimensional array whose shape matches the mesh shape. If spatial - distributions are set on any of the source objects, they will be ignored - during source site sampling. - constraints : dict - Constraints on sampled source particles. Valid keys include 'domains', - 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. - For 'domains', the corresponding value is an iterable of - :class:`openmc.Cell`, :class:`openmc.Material`, or - :class:`openmc.Universe` for which sampled sites must be within. For - 'time_bounds' and 'energy_bounds', the corresponding value is a sequence - of floats giving the lower and upper bounds on time in [s] or energy in - [eV] that the sampled particle must be within. For 'fissionable', the - value is a bool indicating that only sites in fissionable material - should be accepted. The 'rejection_strategy' indicates what should - happen when a source particle is rejected: either 'resample' (pick a new - particle) or 'kill' (accept and terminate). - - Attributes - ---------- - mesh : openmc.MeshBase - The mesh over which source sites will be generated. - sources : numpy.ndarray of openmc.SourceBase - Sources to apply to each element - strength : float - Strength of the source - type : str - Indicator of source type: 'mesh' - constraints : dict - Constraints on sampled source particles. Valid keys include - 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', - 'fissionable', and 'rejection_strategy'. - - """ - - def __init__( - self, - mesh: MeshBase, - sources: Sequence[SourceBase], - constraints: dict[str, Any] | None = None, - ): - super().__init__(strength=None, constraints=constraints) - self.mesh = mesh - self.sources = sources - - @property - def type(self) -> str: - return "mesh" - - @property - def mesh(self) -> MeshBase: - return self._mesh - - @property - def strength(self) -> float: - return sum(s.strength for s in self.sources) - - @property - def sources(self) -> np.ndarray: - return self._sources - - @mesh.setter - def mesh(self, m): - cv.check_type('source mesh', m, MeshBase) - self._mesh = m - - @sources.setter - def sources(self, s): - cv.check_iterable_type('mesh sources', s, SourceBase, max_depth=3) - - s = np.asarray(s) - - if isinstance(self.mesh, StructuredMesh): - if s.size != self.mesh.n_elements: - raise ValueError( - f'The length of the source array ({s.size}) does not match ' - f'the number of mesh elements ({self.mesh.n_elements}).') - - # If user gave a multidimensional array, flatten in the order - # of the mesh indices - if s.ndim > 1: - s = s.ravel(order='F') - - elif isinstance(self.mesh, UnstructuredMesh): - if s.ndim > 1: - raise ValueError( - 'Sources must be a 1-D array for unstructured mesh') - - self._sources = s - for src in self._sources: - if isinstance(src, IndependentSource) and src.space is not None: - warnings.warn('Some sources on the mesh have spatial ' - 'distributions that will be ignored at runtime.') - break - - @strength.setter - def strength(self, val): - if val is not None: - cv.check_type('mesh source strength', val, Real) - self.set_total_strength(val) - - def set_total_strength(self, strength: float): - """Scales the element source strengths based on a desired total strength. - - Parameters - ---------- - strength : float - Total source strength - - """ - current_strength = self.strength if self.strength != 0.0 else 1.0 - - for s in self.sources: - s.strength *= strength / current_strength - - def normalize_source_strengths(self): - """Update all element source strengths such that they sum to 1.0.""" - self.set_total_strength(1.0) - - def populate_xml_element(self, elem: ET.Element): - """Add necessary source information to an XML element - - Returns - ------- - element : lxml.etree._Element - XML element containing source data - - """ - elem.set("mesh", str(self.mesh.id)) - - # write in the order of mesh indices - for s in self.sources: - elem.append(s.to_xml_element()) - - @classmethod - def from_xml_element(cls, elem: ET.Element, meshes) -> openmc.MeshSource: - """ - Generate MeshSource from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict - A dictionary with mesh IDs as keys and openmc.MeshBase instances as - values - - Returns - ------- - openmc.MeshSource - MeshSource generated from the XML element - """ - mesh_id = int(get_text(elem, 'mesh')) - mesh = meshes[mesh_id] - - sources = [SourceBase.from_xml_element( - e) for e in elem.iterchildren('source')] - constraints = cls._get_constraints(elem) - return cls(mesh, sources, constraints=constraints) - - -def Source(*args, **kwargs): - """ - A function for backward compatibility of sources. Will be removed in the - future. Please update to IndependentSource. - """ - warnings.warn( - "This class is deprecated in favor of 'IndependentSource'", FutureWarning) - return openmc.IndependentSource(*args, **kwargs) - - -class CompiledSource(SourceBase): - """A source based on a compiled shared library - - .. versionadded:: 0.14.0 - - Parameters - ---------- - library : path-like - Path to a compiled shared library - parameters : str - Parameters to be provided to the compiled shared library function - strength : float - Strength of the source - constraints : dict - Constraints on sampled source particles. Valid keys include 'domains', - 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. - For 'domains', the corresponding value is an iterable of - :class:`openmc.Cell`, :class:`openmc.Material`, or - :class:`openmc.Universe` for which sampled sites must be within. For - 'time_bounds' and 'energy_bounds', the corresponding value is a sequence - of floats giving the lower and upper bounds on time in [s] or energy in - [eV] that the sampled particle must be within. For 'fissionable', the - value is a bool indicating that only sites in fissionable material - should be accepted. The 'rejection_strategy' indicates what should - happen when a source particle is rejected: either 'resample' (pick a new - particle) or 'kill' (accept and terminate). - - Attributes - ---------- - library : pathlib.Path - Path to a compiled shared library - parameters : str - Parameters to be provided to the compiled shared library function - strength : float - Strength of the source - type : str - Indicator of source type: 'compiled' - constraints : dict - Constraints on sampled source particles. Valid keys include - 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', - 'fissionable', and 'rejection_strategy'. - - """ - - def __init__( - self, - library: PathLike, - parameters: str | None = None, - strength: float = 1.0, - constraints: dict[str, Any] | None = None - ) -> None: - super().__init__(strength=strength, constraints=constraints) - self.library = library - self._parameters = None - if parameters is not None: - self.parameters = parameters - - @property - def type(self) -> str: - return "compiled" - - @property - def library(self) -> Path: - return self._library - - @library.setter - def library(self, library_name: PathLike): - cv.check_type('library', library_name, PathLike) - self._library = input_path(library_name) - - @property - def parameters(self) -> str: - return self._parameters - - @parameters.setter - def parameters(self, parameters_path): - cv.check_type('parameters', parameters_path, str) - self._parameters = parameters_path - - def populate_xml_element(self, element): - """Add necessary compiled source information to an XML element - - Returns - ------- - element : lxml.etree._Element - XML element containing source data - - """ - element.set("library", str(self.library)) - - if self.parameters is not None: - element.set("parameters", self.parameters) - - @classmethod - def from_xml_element(cls, elem: ET.Element) -> openmc.CompiledSource: - """Generate a compiled source from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict - Dictionary with mesh IDs as keys and openmc.MeshBase instances as - values - - Returns - ------- - openmc.CompiledSource - Source generated from XML element - - """ - kwargs = {'constraints': cls._get_constraints(elem)} - kwargs['library'] = get_text(elem, 'library') - - source = cls(**kwargs) - - strength = get_text(elem, 'strength') - if strength is not None: - source.strength = float(strength) - - parameters = get_text(elem, 'parameters') - if parameters is not None: - source.parameters = parameters - - return source - - -class FileSource(SourceBase): - """A source based on particles stored in a file - - .. versionadded:: 0.14.0 - - Parameters - ---------- - path : path-like - Path to the source file from which sites should be sampled - strength : float - Strength of the source (default is 1.0) - constraints : dict - Constraints on sampled source particles. Valid keys include 'domains', - 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. - For 'domains', the corresponding value is an iterable of - :class:`openmc.Cell`, :class:`openmc.Material`, or - :class:`openmc.Universe` for which sampled sites must be within. For - 'time_bounds' and 'energy_bounds', the corresponding value is a sequence - of floats giving the lower and upper bounds on time in [s] or energy in - [eV] that the sampled particle must be within. For 'fissionable', the - value is a bool indicating that only sites in fissionable material - should be accepted. The 'rejection_strategy' indicates what should - happen when a source particle is rejected: either 'resample' (pick a new - particle) or 'kill' (accept and terminate). - - Attributes - ---------- - path : Pathlike - Source file from which sites should be sampled - strength : float - Strength of the source - type : str - Indicator of source type: 'file' - constraints : dict - Constraints on sampled source particles. Valid keys include - 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', - 'fissionable', and 'rejection_strategy'. - - """ - - def __init__( - self, - path: PathLike, - strength: float = 1.0, - constraints: dict[str, Any] | None = None - ): - super().__init__(strength=strength, constraints=constraints) - self.path = path - - @property - def type(self) -> str: - return "file" - - @property - def path(self) -> PathLike: - return self._path - - @path.setter - def path(self, p: PathLike): - cv.check_type('source file', p, PathLike) - self._path = input_path(p) - - def populate_xml_element(self, element): - """Add necessary file source information to an XML element - - Returns - ------- - element : lxml.etree._Element - XML element containing source data - - """ - if self.path is not None: - element.set("file", str(self.path)) - - @classmethod - def from_xml_element(cls, elem: ET.Element) -> openmc.FileSource: - """Generate file source from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict - Dictionary with mesh IDs as keys and openmc.MeshBase instances as - values - - Returns - ------- - openmc.FileSource - Source generated from XML element - - """ - kwargs = {'constraints': cls._get_constraints(elem)} - kwargs['path'] = get_text(elem, 'file') - strength = get_text(elem, 'strength') - if strength is not None: - kwargs['strength'] = float(strength) - - return cls(**kwargs) - - -class TokamakSource(SourceBase): - r"""A source representing neutron emission from a tokamak plasma. - - This source samples neutron positions from a tokamak plasma geometry using - Miller-style flux surface parameterization. The user provides an emission - profile S(r/a) as a function of normalized minor radius, along with one or - more energy distributions. - - The flux surface parameterization is - - .. math:: - - \begin{aligned} - R &= R_0 + r \cos\left(\alpha + \delta \sin\alpha\right) - + \Delta \left[1 - \left(\frac{r}{a}\right)^2\right] \\ - Z &= Z_\mathrm{shift} + \kappa r \sin\alpha - \end{aligned} - - where :math:`R_0` is major radius, :math:`a` is minor radius, - :math:`\kappa` is elongation, :math:`\delta` is triangularity, - :math:`\Delta` is the Shafranov shift, and :math:`Z_\mathrm{shift}` is - the vertical shift. - - .. versionadded:: 0.15.4 - - Parameters - ---------- - major_radius : float - Major radius R0 in [cm] - minor_radius : float - Minor radius a in [cm] - elongation : float - Plasma elongation κ (must be > 0) - triangularity : float - Plasma triangularity δ (must be in [-1, 1]) - shafranov_shift : float - Shafranov shift Δ in [cm] (must be >= 0 and < a/2) - r_over_a : numpy.ndarray - Normalized minor radius grid points, must start at 0 and end at 1 - emission_density : numpy.ndarray - Emission density S(r) at each r/a point (arbitrary units, must be >= 0). - Values are linearly interpolated between grid points and refined on an - internal grid for radial sampling. Must have the same length as - ``r_over_a`` and contain at least one positive value. - energy : openmc.stats.Univariate or Sequence[openmc.stats.Univariate] - Energy distribution(s). Either a single distribution used at all radii, - or one distribution per ``r_over_a`` grid point. When one distribution - per grid point is given, the energy of a sampled particle is drawn from - one of the two distributions bracketing its sampled radius, selected - stochastically with probability proportional to the proximity of the - radius to each grid point (stochastic interpolation). - time : openmc.stats.Univariate, optional - Time distribution of the source. If None, particles are born at - :math:`t=0`, matching the default behavior of - :class:`openmc.IndependentSource`. - phi_start : float - Starting toroidal angle in [rad] (default: 0) - phi_extent : float - Toroidal angle extent in [rad] (default: 2π) - n_alpha : int - Number of poloidal angle grid points for CDF sampling (default: 101) - vertical_shift : float - Vertical shift of the plasma center in [cm] (default: 0) - strength : float - Strength of the source (default: 1.0) - constraints : dict - Constraints on sampled source particles. See :class:`SourceBase` for - valid keys and values. - - Attributes - ---------- - major_radius : float - Major radius R0 in [cm] - minor_radius : float - Minor radius a in [cm] - elongation : float - Plasma elongation κ - triangularity : float - Plasma triangularity δ - shafranov_shift : float - Shafranov shift Δ in [cm] - r_over_a : numpy.ndarray - Normalized minor radius grid points - emission_density : numpy.ndarray - Emission density S(r) at each r/a point - energy : list of openmc.stats.Univariate - Energy distribution(s) - time : openmc.stats.Univariate or None - Time distribution of the source - phi_start : float - Starting toroidal angle in [rad] - phi_extent : float - Toroidal angle extent in [rad] - n_alpha : int - Number of poloidal angle grid points - vertical_shift : float - Vertical shift of the plasma center in [cm] - strength : float - Strength of the source - type : str - Indicator of source type: 'tokamak' - constraints : dict - Constraints on sampled source particles - - """ - - def __init__( - self, - major_radius: float, - minor_radius: float, - elongation: float, - triangularity: float, - shafranov_shift: float, - r_over_a: Sequence[float], - emission_density: Sequence[float], - energy: Univariate | Sequence[Univariate], - time: Univariate | None = None, - phi_start: float = 0.0, - phi_extent: float = 2.0 * np.pi, - n_alpha: int = 101, - vertical_shift: float = 0.0, - strength: float = 1.0, - constraints: dict[str, Any] | None = None - ): - super().__init__(strength=strength, constraints=constraints) - self.major_radius = major_radius - self.minor_radius = minor_radius - self.elongation = elongation - self.triangularity = triangularity - self.shafranov_shift = shafranov_shift - self.r_over_a = r_over_a - self.emission_density = emission_density - self.phi_start = phi_start - self.phi_extent = phi_extent - self.n_alpha = n_alpha - self.vertical_shift = vertical_shift - self.energy = energy - self.time = time - - self._validate() - - def _validate(self): - """Validate relationships between tokamak source parameters.""" - if self.minor_radius >= self.major_radius: - raise ValueError( - f"minor_radius ({self.minor_radius}) must be smaller than " - f"major_radius ({self.major_radius})") - if self.shafranov_shift >= 0.5 * self.minor_radius: - raise ValueError( - f"shafranov_shift ({self.shafranov_shift}) must be smaller " - f"than half the minor_radius ({0.5 * self.minor_radius})") - if len(self.emission_density) != len(self.r_over_a): - raise ValueError( - f"emission_density (length {len(self.emission_density)}) must " - f"have the same length as r_over_a (length {len(self.r_over_a)})") - if not np.any(self.emission_density > 0.0): - raise ValueError("emission_density must contain a positive value") - if len(self.energy) not in (1, len(self.r_over_a)): - raise ValueError( - f"Number of energy distributions ({len(self.energy)}) must be " - f"either 1 or equal to the number of r_over_a grid points " - f"({len(self.r_over_a)})") - - @property - def type(self) -> str: - return "tokamak" - - @property - def major_radius(self) -> float: - return self._major_radius - - @major_radius.setter - def major_radius(self, value: float): - cv.check_type('major radius', value, Real) - cv.check_greater_than('major radius', value, 0.0) - self._major_radius = value - - @property - def minor_radius(self) -> float: - return self._minor_radius - - @minor_radius.setter - def minor_radius(self, value: float): - cv.check_type('minor radius', value, Real) - cv.check_greater_than('minor radius', value, 0.0) - self._minor_radius = value - - @property - def elongation(self) -> float: - return self._elongation - - @elongation.setter - def elongation(self, value: float): - cv.check_type('elongation', value, Real) - cv.check_greater_than('elongation', value, 0.0) - self._elongation = value - - @property - def triangularity(self) -> float: - return self._triangularity - - @triangularity.setter - def triangularity(self, value: float): - cv.check_type('triangularity', value, Real) - cv.check_greater_than('triangularity', value, -1.0, equality=True) - cv.check_less_than('triangularity', value, 1.0, equality=True) - self._triangularity = value - - @property - def shafranov_shift(self) -> float: - return self._shafranov_shift - - @shafranov_shift.setter - def shafranov_shift(self, value: float): - cv.check_type('Shafranov shift', value, Real) - cv.check_greater_than('Shafranov shift', value, 0.0, equality=True) - self._shafranov_shift = value - - @property - def r_over_a(self) -> np.ndarray: - return self._r_over_a - - @r_over_a.setter - def r_over_a(self, value: Sequence[float]): - value = np.asarray(value, dtype=float) - if value.ndim != 1 or len(value) < 2: - raise ValueError("r_over_a must be a 1-D array with at least 2 points") - if value[0] != 0.0: - raise ValueError("r_over_a must start at 0") - if value[-1] != 1.0: - raise ValueError("r_over_a must end at 1") - if not np.all(np.diff(value) > 0): - raise ValueError("r_over_a must be strictly increasing") - self._r_over_a = value - - @property - def emission_density(self) -> np.ndarray: - return self._emission_density - - @emission_density.setter - def emission_density(self, value: Sequence[float]): - value = np.asarray(value, dtype=float) - if value.ndim != 1: - raise ValueError("emission_density must be a 1-D array") - if np.any(value < 0): - raise ValueError("emission_density values cannot be negative") - self._emission_density = value - - @property - def energy(self) -> list[Univariate]: - return self._energy - - @energy.setter - def energy(self, value: Univariate | Sequence[Univariate]): - if isinstance(value, Univariate): - self._energy = [value] - else: - cv.check_iterable_type('energy distributions', value, Univariate) - self._energy = list(value) - - @property - def time(self) -> Univariate | None: - return self._time - - @time.setter - def time(self, value: Univariate | None): - if value is not None: - cv.check_type('time distribution', value, Univariate) - self._time = value - - @property - def phi_start(self) -> float: - return self._phi_start - - @phi_start.setter - def phi_start(self, value: float): - cv.check_type('phi_start', value, Real) - self._phi_start = value - - @property - def phi_extent(self) -> float: - return self._phi_extent - - @phi_extent.setter - def phi_extent(self, value: float): - cv.check_type('phi_extent', value, Real) - cv.check_greater_than('phi_extent', value, 0.0) - cv.check_less_than('phi_extent', value, 2.0 * np.pi, equality=True) - self._phi_extent = value - - @property - def n_alpha(self) -> int: - return self._n_alpha - - @n_alpha.setter - def n_alpha(self, value: int): - cv.check_type('n_alpha', value, Integral) - cv.check_greater_than('n_alpha', value, 2) - if value < 51: - warnings.warn( - "n_alpha values below 51 may introduce noticeable " - "discretization bias in tokamak source sampling", stacklevel=2) - self._n_alpha = value - - @property - def vertical_shift(self) -> float: - return self._vertical_shift - - @vertical_shift.setter - def vertical_shift(self, value: float): - cv.check_type('vertical shift', value, Real) - self._vertical_shift = value - - def populate_xml_element(self, element): - """Add necessary tokamak source information to an XML element - - Returns - ------- - element : lxml.etree._Element - XML element containing source data - - """ - self._validate() - - # Geometry parameters - ET.SubElement(element, "major_radius").text = str(self.major_radius) - ET.SubElement(element, "minor_radius").text = str(self.minor_radius) - ET.SubElement(element, "elongation").text = str(self.elongation) - ET.SubElement(element, "triangularity").text = str(self.triangularity) - ET.SubElement(element, "shafranov_shift").text = str(self.shafranov_shift) - - # Toroidal angle bounds - ET.SubElement(element, "phi_start").text = str(self.phi_start) - ET.SubElement(element, "phi_extent").text = str(self.phi_extent) - - # Poloidal sampling resolution - ET.SubElement(element, "n_alpha").text = str(self.n_alpha) - - # Vertical shift - if self.vertical_shift != 0.0: - ET.SubElement(element, "vertical_shift").text = str(self.vertical_shift) - - # Emission profile - ET.SubElement(element, "r_over_a").text = ' '.join(str(r) for r in self.r_over_a) - ET.SubElement(element, "emission_density").text = ' '.join(str(s) for s in self.emission_density) - - # Energy distribution(s) - for dist in self.energy: - element.append(dist.to_xml_element('energy')) - - # Time distribution - if self.time is not None: - element.append(self.time.to_xml_element('time')) - - @classmethod - def from_xml_element(cls, elem: ET.Element) -> TokamakSource: - """Generate tokamak source from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.TokamakSource - Source generated from XML element - - """ - # Read geometry parameters - major_radius = float(get_text(elem, 'major_radius')) - minor_radius = float(get_text(elem, 'minor_radius')) - elongation = float(get_text(elem, 'elongation')) - triangularity = float(get_text(elem, 'triangularity')) - shafranov_shift = float(get_text(elem, 'shafranov_shift')) - - # Read optional parameters - phi_start_text = get_text(elem, 'phi_start') - phi_start = float(phi_start_text) if phi_start_text else 0.0 - - phi_extent_text = get_text(elem, 'phi_extent') - phi_extent = float(phi_extent_text) if phi_extent_text else 2.0 * np.pi - - n_alpha_text = get_text(elem, 'n_alpha') - n_alpha = int(n_alpha_text) if n_alpha_text else 101 - - vertical_shift_text = get_text(elem, 'vertical_shift') - vertical_shift = float(vertical_shift_text) if vertical_shift_text else 0.0 - - # Read emission profile - r_over_a = np.array([float(x) for x in get_text(elem, 'r_over_a').split()]) - emission_density = np.array([float(x) for x in get_text(elem, 'emission_density').split()]) - - # Read energy distributions - energy = [Univariate.from_xml_element(e) for e in elem.findall('energy')] - if len(energy) == 1: - energy = energy[0] - - # Read time distribution - time_elem = elem.find('time') - time = Univariate.from_xml_element(time_elem) if time_elem is not None else None - - # Read constraints and strength - constraints = cls._get_constraints(elem) - strength_text = get_text(elem, 'strength') - strength = float(strength_text) if strength_text else 1.0 - - return cls( - major_radius=major_radius, - minor_radius=minor_radius, - elongation=elongation, - triangularity=triangularity, - shafranov_shift=shafranov_shift, - r_over_a=r_over_a, - emission_density=emission_density, - energy=energy, - time=time, - phi_start=phi_start, - phi_extent=phi_extent, - n_alpha=n_alpha, - vertical_shift=vertical_shift, - strength=strength, - constraints=constraints - ) +class ParticleType(Enum): + NEUTRON = 0 + PHOTON = 1 + ELECTRON = 2 + POSITRON = 3 class SourceParticle: @@ -1346,23 +283,12 @@ class SourceParticle: Delayed group particle was created in (neutrons only) surf_id : int Surface ID where particle is at, if any. - particle : ParticleType or str or int - Type of the particle (type, name, or PDG number) + particle : ParticleType + Type of the particle """ - - def __init__( - self, - r: Iterable[float] = (0., 0., 0.), - u: Iterable[float] = (0., 0., 1.), - E: float = 1.0e6, - time: float = 0.0, - wgt: float = 1.0, - delayed_group: int = 0, - surf_id: int = 0, - particle: ParticleType | str | int = ParticleType.NEUTRON - ): - + def __init__(self, r=(0., 0., 0.), u=(0., 0., 1.), E=1.0e6, time=0.0, wgt=1.0, + delayed_group=0, surf_id=0, particle=ParticleType.NEUTRON): self.r = tuple(r) self.u = tuple(u) self.E = float(E) @@ -1372,18 +298,11 @@ class SourceParticle: self.surf_id = surf_id self.particle = particle - @property - def particle(self) -> ParticleType: - return self._particle - - @particle.setter - def particle(self, particle): - self._particle = ParticleType(particle) - def __repr__(self): - return f'' + name = self.particle.name.lower() + return f'' - def to_tuple(self) -> tuple: + def to_tuple(self): """Return source particle attributes as a tuple Returns @@ -1393,13 +312,10 @@ class SourceParticle: """ return (self.r, self.u, self.E, self.time, self.wgt, - self.delayed_group, self.surf_id, self.particle.pdg_number) + self.delayed_group, self.surf_id, self.particle.value) -def write_source_file( - source_particles: Iterable[SourceParticle], - filename: PathLike, **kwargs -): +def write_source_file(source_particles, filename, **kwargs): """Write a source file using a collection of source particles Parameters @@ -1416,330 +332,25 @@ def write_source_file( openmc.SourceParticle """ - cv.check_iterable_type( - "source particles", source_particles, SourceParticle) - pl = ParticleList(source_particles) - pl.export_to_hdf5(filename, **kwargs) + # Create compound datatype for source particles + pos_dtype = np.dtype([('x', ' ParticleList: - """Create particle list from an HDF5 file. - - Parameters - ---------- - filename : path-like - Path to source file to read. - - Returns - ------- - ParticleList instance - - """ - with h5py.File(filename, 'r') as fh: - filetype = fh.attrs['filetype'] - arr = fh['source_bank'][...] - - if filetype != b'source': - raise ValueError(f'File {filename} is not a source file') - - source_particles = [ - SourceParticle(*params, ParticleType(particle)) - for *params, particle in arr - ] - return cls(source_particles) - - @classmethod - def from_mcpl(cls, filename: PathLike) -> ParticleList: - """Create particle list from an MCPL file. - - Parameters - ---------- - filename : path-like - Path to MCPL file to read. - - Returns - ------- - ParticleList instance - - """ - import mcpl - # Process .mcpl file - particles = [] - with mcpl.MCPLFile(filename) as f: - for particle in f.particles: - particle_type = ParticleType(particle.pdgcode) - - # Create a source particle instance. Note that MCPL stores - # energy in MeV and time in ms. - source_particle = SourceParticle( - r=tuple(particle.position), - u=tuple(particle.direction), - E=1.0e6*particle.ekin, - time=1.0e-3*particle.time, - wgt=particle.weight, - particle=particle_type - ) - particles.append(source_particle) - - return cls(particles) - - def __getitem__(self, index): - """ - Return a new ParticleList object containing the particle(s) - at the specified index or slice. - - Parameters - ---------- - index : int, slice or list - The index, slice or list to select from the list of particles - - Returns - ------- - openmc.ParticleList or openmc.SourceParticle - A new object with the selected particle(s) - """ - if isinstance(index, int): - # If it's a single integer, return the corresponding particle - return super().__getitem__(index) - elif isinstance(index, slice): - # If it's a slice, return a new ParticleList object with the - # sliced particles - return ParticleList(super().__getitem__(index)) - elif isinstance(index, list): - # If it's a list of integers, return a new ParticleList object with - # the selected particles. Note that Python 3.10 gets confused if you - # use super() here, so we call list.__getitem__ directly. - return ParticleList([list.__getitem__(self, i) for i in index]) - else: - raise TypeError(f"Invalid index type: {type(index)}. Must be int, " - "slice, or list of int.") - - def to_dataframe(self) -> pd.DataFrame: - """A dataframe representing the source particles - - Returns - ------- - pandas.DataFrame - DataFrame containing the source particles attributes. - """ - # Extract the attributes of the source particles into a list of tuples - data = [(sp.r[0], sp.r[1], sp.r[2], sp.u[0], sp.u[1], sp.u[2], - sp.E, sp.time, sp.wgt, sp.delayed_group, sp.surf_id, - str(sp.particle)) for sp in self] - - # Define the column names for the DataFrame - columns = ['x', 'y', 'z', 'u_x', 'u_y', 'u_z', 'E', 'time', 'wgt', - 'delayed_group', 'surf_id', 'particle'] - - # Create the pandas DataFrame from the data - return pd.DataFrame(data, columns=columns) - - def export_to_hdf5(self, filename: PathLike, **kwargs): - """Export particle list to an HDF5 file. - - This method write out an .h5 file that can be used as a source file in - conjunction with the :class:`openmc.FileSource` class. - - Parameters - ---------- - filename : path-like - Path to source file to write - **kwargs - Keyword arguments to pass to :class:`h5py.File` - - See Also - -------- - openmc.FileSource - - """ - # Create compound datatype for source particles - pos_dtype = np.dtype([('x', ' ParticleList: - """Read a source file and return a list of source particles. - - .. versionadded:: 0.15.0 - - Parameters - ---------- - filename : str or path-like - Path to source file to read - - Returns - ------- - openmc.ParticleList - - See Also - -------- - openmc.SourceParticle - - """ - filename = Path(filename) - if filename.suffix not in ('.h5', '.mcpl'): - raise ValueError('Source file must have a .h5 or .mcpl extension.') - - if filename.suffix == '.h5': - return ParticleList.from_hdf5(filename) - else: - return ParticleList.from_mcpl(filename) - - -def read_collision_track_hdf5(filename): - """Read a collision track file in HDF5 format. - - Parameters - ---------- - filename : str or path-like - Path to the HDF5 collision track file. - - Returns - ------- - numpy.ndarray - Structured array containing collision track data. - - See Also - -------- - read_collision_track_mcpl - read_collision_track_file - """ - - with h5py.File(filename, 'r') as file: - data = file['collision_track_bank'][:] - - return data - - -def read_collision_track_mcpl(file_path): - """Read a collision track file in MCPL format. - - Parameters - ---------- - file_path : str or path-like - Path to the MCPL collision track file. - - Returns - ------- - numpy.ndarray - Structured array of particle collision track information, including - position, direction, energy, weight, reaction data, and identifiers. - - See Also - -------- - read_collision_track_hdf5 - read_collision_track_file - """ - import mcpl - myfile = mcpl.MCPLFile(file_path) - data = { - 'r': [], # for position (x, y, z) - 'u': [], # for direction (ux, uy, uz) - 'E': [], 'dE': [], 'time': [], - 'wgt': [], 'event_mt': [], 'delayed_group': [], - 'cell_id': [], 'nuclide_id': [], 'material_id': [], - 'universe_id': [], 'n_collision': [], 'particle': [], - 'parent_id': [], 'progeny_id': [] - } - - # Read and collect data from the MCPL file - for i, p in enumerate(myfile.particles): - if f'blob_{i}' in myfile.blobs: - blob_data = myfile.blobs[f'blob_{i}'] - decoded_str = blob_data.decode('utf-8') - pairs = decoded_str.split(';') - values_dict = {k.strip(): v.strip() - for k, v in (pair.split(':') for pair in pairs if pair.strip())} - - data['r'].append((p.x, p.y, p.z)) # Append as tuple - data['u'].append((p.ux, p.uy, p.uz)) # Append as tuple - data['E'].append(p.ekin * 1e6) - data['dE'].append(float(values_dict.get('dE', 0))) - data['time'].append(p.time * 1e-3) - data['wgt'].append(p.weight) - data['event_mt'].append(int(values_dict.get('event_mt', 0))) - data['delayed_group'].append( - int(values_dict.get('delayed_group', 0))) - data['cell_id'].append(int(values_dict.get('cell_id', 0))) - data['nuclide_id'].append(int(values_dict.get('nuclide_id', 0))) - data['material_id'].append(int(values_dict.get('material_id', 0))) - data['universe_id'].append(int(values_dict.get('universe_id', 0))) - data['n_collision'].append(int(values_dict.get('n_collision', 0))) - data['particle'].append(ParticleType(p.pdgcode)) - data['parent_id'].append(int(values_dict.get('parent_id', 0))) - data['progeny_id'].append(int(values_dict.get('progeny_id', 0))) - - dtypes = [ - ('r', [('x', 'f8'), ('y', 'f8'), ('z', 'f8')]), - ('u', [('x', 'f8'), ('y', 'f8'), ('z', 'f8')]), - ('E', 'f8'), ('dE', 'f8'), ('time', 'f8'), ('wgt', 'f8'), - ('event_mt', 'f8'), ('delayed_group', 'i4'), ('cell_id', 'i4'), - ('nuclide_id', 'i4'), ('material_id', 'i4'), ('universe_id', 'i4'), - ('n_collision', 'i4'), ('particle', 'i4'), - ('parent_id', 'i8'), ('progeny_id', 'i8') - ] - - structured_array = np.zeros(len(data['r']), dtype=dtypes) - for key in data: - structured_array[key] = data[key] # Assign data - - return structured_array - - -def read_collision_track_file(filename): - """Read a collision track file (HDF5 or MCPL) and return its data. - - Parameters - ---------- - filename : str or path-like - Path to the collision track file to read. Must end with - ``.h5`` or ``.mcpl``. - - Returns - ------- - numpy.ndarray - Structured array containing collision track data. - - See Also - -------- - read_collision_track_hdf5 - read_collision_track_mcpl - """ - - filename = Path(filename) - if filename.suffix not in ('.h5', '.mcpl'): - raise ValueError('Collision track file must have a .h5 or .mcpl extension.') - - if filename.suffix == '.h5': - return read_collision_track_hdf5(filename) - else: - return read_collision_track_mcpl(filename) + # Write array to file + kwargs.setdefault('mode', 'w') + with h5py.File(filename, **kwargs) as fh: + fh.attrs['filetype'] = np.string_("source") + fh.create_dataset('source_bank', data=arr, dtype=source_dtype) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index a10ec3a83..138c0c718 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -1,5 +1,4 @@ from datetime import datetime -from collections import namedtuple import glob import re import os @@ -7,9 +6,7 @@ import warnings import h5py import numpy as np -from pathlib import Path from uncertainties import ufloat -from uncertainties.unumpy import uarray import openmc import openmc.checkvalue as cv @@ -17,9 +14,6 @@ import openmc.checkvalue as cv _VERSION_STATEPOINT = 18 -KineticsParameters = namedtuple("KineticsParameters", ["generation_time", "beta_effective"]) - - class StatePoint: """State information on a simulation at a certain point in time (at the end of a given batch). Statepoints can be used to analyze tally results as well @@ -104,8 +98,6 @@ class StatePoint: and whose values are time values in seconds. seed : int Pseudorandom number generator seed - stride : int - Number of random numbers allocated for each particle history source : numpy.ndarray of compound datatype Array of source sites. The compound datatype has fields 'r', 'u', 'E', 'wgt', 'delayed_group', 'surf_id', and 'particle', corresponding to @@ -243,7 +235,7 @@ class StatePoint: if self._global_tallies is None: data = self._f['global_tallies'][()] gt = np.zeros(data.shape[0], dtype=[ - ('name', 'S14'), ('sum', 'f8'), ('sum_sq', 'f8'), + ('name', 'a14'), ('sum', 'f8'), ('sum_sq', 'f8'), ('mean', 'f8'), ('std_dev', 'f8')]) gt['name'] = ['k-collision', 'k-absorption', 'k-tracklength', 'leakage'] @@ -363,10 +355,6 @@ class StatePoint: def seed(self): return self._f['seed'][()] - @property - def stride(self): - return self._f['stride'][()] - @property def source(self): return self._f['source_bank'][()] if self.source_present else None @@ -379,26 +367,6 @@ class StatePoint: def sparse(self): return self._sparse - @sparse.setter - def sparse(self, sparse): - """Convert tally data from NumPy arrays to SciPy list of lists (LIL) - sparse matrices, and vice versa. - - This property may be used to reduce the amount of data in memory during - tally data processing. The tally data will be stored as SciPy LIL - matrices internally within each Tally object. All tally data access - properties and methods will return data as a dense NumPy array. - - """ - - cv.check_type('sparse', sparse, bool) - self._sparse = sparse - - # Update tally sparsities - if self._tallies_read: - for tally_id in self.tallies: - self.tallies[tally_id].sparse = self.sparse - @property def tallies(self): if self.tallies_present and not self._tallies_read: @@ -427,17 +395,9 @@ class StatePoint: # Create Tally object and assign basic properties tally = openmc.Tally(tally_id) - tally._sp_filename = Path(self._f.filename) + tally._sp_filename = self._f.filename tally.name = group['name'][()].decode() if 'name' in group else '' - # Check if tally has multiply_density attribute - if "multiply_density" in group.attrs: - tally.multiply_density = group.attrs["multiply_density"].item() > 0 - - # Check if tally has higher_moments attribute - if 'higher_moments' in group.attrs: - tally.higher_moments = bool(group.attrs['higher_moments'][()]) - # Read the number of realizations n_realizations = group['n_realizations'][()] @@ -464,11 +424,14 @@ class StatePoint: nuclide_names = group['nuclides'][()] # Add all nuclides to the Tally - tally.nuclides = [name.decode().strip() for name in nuclide_names] + for name in nuclide_names: + nuclide = openmc.Nuclide(name.decode().strip()) + tally.nuclides.append(nuclide) # Add the scores to the Tally scores = group['score_bins'][()] - tally.scores = [score.decode() for score in scores] + for score in scores: + tally.scores.append(score.decode()) # Add Tally to the global dictionary of all Tallies tally.sparse = self.sparse @@ -517,6 +480,26 @@ class StatePoint: def summary(self): return self._summary + @sparse.setter + def sparse(self, sparse): + """Convert tally data from NumPy arrays to SciPy list of lists (LIL) + sparse matrices, and vice versa. + + This property may be used to reduce the amount of data in memory during + tally data processing. The tally data will be stored as SciPy LIL + matrices internally within each Tally object. All tally data access + properties and methods will return data as a dense NumPy array. + + """ + + cv.check_type('sparse', sparse, bool) + self._sparse = sparse + + # Update tally sparsities + if self._tallies_read: + for tally_id in self.tallies: + self.tallies[tally_id].sparse = self.sparse + def close(self): """Close the statepoint HDF5 file and the corresponding summary HDF5 file if present. @@ -539,16 +522,15 @@ class StatePoint: def get_tally(self, scores=[], filters=[], nuclides=[], name=None, id=None, estimator=None, exact_filters=False, - exact_nuclides=False, exact_scores=False, - multiply_density=None, derivative=None, filter_type=None): + exact_nuclides=False, exact_scores=False): """Finds and returns a Tally object with certain properties. This routine searches the list of Tallies and returns the first Tally found which satisfies all of the input parameters. NOTE: If any of the "exact" parameters are False (default), the input - parameters do not need to match the complete Tally specification and may - only represent a subset of the Tally's properties. If an "exact" + parameters do not need to match the complete Tally specification and + may only represent a subset of the Tally's properties. If an "exact" parameter is True then number of scores, filters, or nuclides in the parameters must precisely match those of any matching Tally. @@ -575,18 +557,9 @@ class StatePoint: to those in the matching Tally. If False (default), the nuclides in the parameters may be a subset of those in the matching Tally. exact_scores : bool - If True, the number of scores in the parameters must be identical to - those in the matching Tally. If False (default), the scores in the - parameters may be a subset of those in the matching Tally. Default - is None (no check). - multiply_density : bool, optional - If not None, the Tally must have the multiply_density attribute set - to the same value as this parameter. - derivative : openmc.TallyDerivative, optional - TallyDerivative object to match. - filter_type : type, optional - If not None, the Tally must have at least one Filter that is an - instance of this type. For example `openmc.MeshFilter`. + If True, the number of scores in the parameters must be identical + to those in the matching Tally. If False (default), the scores + in the parameters may be a subset of those in the matching Tally. Returns ------- @@ -614,25 +587,17 @@ class StatePoint: if id and id != test_tally.id: continue - # Determine if Tally has queried estimator, only move on to next tally - # if the estimator is both specified and the tally estimtor does not - # match - if estimator is not None and estimator != test_tally.estimator: + # Determine if Tally has queried estimator + if estimator and estimator != test_tally.estimator: continue # The number of filters, nuclides and scores must exactly match if exact_scores and len(scores) != test_tally.num_scores: continue - if exact_nuclides and nuclides and len(nuclides) != test_tally.num_nuclides: - continue - if exact_nuclides and not nuclides and test_tally.nuclides != ['total']: + if exact_nuclides and len(nuclides) != test_tally.num_nuclides: continue if exact_filters and len(filters) != test_tally.num_filters: continue - if derivative is not None and derivative != test_tally.derivative: - continue - if multiply_density is not None and multiply_density != test_tally.multiply_density: - continue # Determine if Tally has the queried score(s) if scores: @@ -660,10 +625,6 @@ class StatePoint: if not contains_filters: continue - if filter_type is not None: - if not any(isinstance(f, filter_type) for f in test_tally.filters): - continue - # Determine if Tally has the queried Nuclide(s) if nuclides: if not all(nuclide in test_tally.nuclides for nuclide in nuclides): @@ -723,59 +684,6 @@ class StatePoint: cell = cells[cell_id] if not cell._paths: summary.geometry.determine_paths() - tally_filter._paths = cell.paths + tally_filter.paths = cell.paths self._summary = summary - - def get_kinetics_parameters(self) -> KineticsParameters: - """Get kinetics parameters from IFP tallies. - - This method searches the tallies in the statepoint for the tallies - required to compute kinetics parameters using the Iterated Fission - Probability (IFP) method. - - Returns - ------- - KineticsParameters - A named tuple containing the generation time and effective delayed - neutron fraction. If the necessary tallies for one or both - parameters are not found, that parameter is returned as None. - - """ - - denom_tally = None - gen_time_tally = None - beta_tally = None - for tally in self.tallies.values(): - if 'ifp-denominator' in tally.scores: - denom_tally = self.get_tally(scores=['ifp-denominator']) - if 'ifp-time-numerator' in tally.scores: - gen_time_tally = self.get_tally(scores=['ifp-time-numerator']) - if 'ifp-beta-numerator' in tally.scores: - beta_tally = self.get_tally(scores=['ifp-beta-numerator']) - - if denom_tally is None: - return KineticsParameters(None, None) - - def get_ufloat(tally, score): - return uarray(tally.get_values(scores=[score]), - tally.get_values(scores=[score], value='std_dev')) - - denom_values = get_ufloat(denom_tally, 'ifp-denominator') - if gen_time_tally is None: - generation_time = None - else: - gen_time_values = get_ufloat(gen_time_tally, 'ifp-time-numerator') - gen_time_values /= denom_values*self.keff - generation_time = gen_time_values.flatten()[0] - - if beta_tally is None: - beta_effective = None - else: - beta_values = get_ufloat(beta_tally, 'ifp-beta-numerator') - beta_values /= denom_values - beta_effective = beta_values.flatten() - if beta_effective.size == 1: - beta_effective = beta_effective[0] - - return KineticsParameters(generation_time, beta_effective) diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index d48697037..f34bf0d1f 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -1,18 +1,14 @@ -from __future__ import annotations from abc import ABC, abstractmethod -from collections.abc import Iterable, Sequence -from math import cos, pi +from collections.abc import Iterable +from math import pi, cos from numbers import Real -from warnings import warn +from xml.etree import ElementTree as ET -import lxml.etree as ET import numpy as np -import openmc import openmc.checkvalue as cv -from .._xml import get_elem_list, get_text -from ..mesh import MeshBase -from .univariate import PowerLaw, Uniform, Univariate, delta_function +from .._xml import get_text +from .univariate import Univariate, Uniform, PowerLaw class UnitSphere(ABC): @@ -79,9 +75,6 @@ class PolarAzimuthal(UnitSphere): reference_uvw : Iterable of float Direction from which polar angle is measured. Defaults to the positive z-direction. - reference_vwu : Iterable of float - Direction from which azimuthal angle is measured. Defaults to the positive - x-direction. Attributes ---------- @@ -92,9 +85,8 @@ class PolarAzimuthal(UnitSphere): """ - def __init__(self, mu=None, phi=None, reference_uvw=(0., 0., 1.), reference_vwu=(1., 0., 0.)): + def __init__(self, mu=None, phi=None, reference_uvw=(0., 0., 1.)): super().__init__(reference_uvw) - self.reference_vwu = reference_vwu if mu is not None: self.mu = mu else: @@ -105,62 +97,37 @@ class PolarAzimuthal(UnitSphere): else: self.phi = Uniform(0., 2*pi) - @property - def reference_vwu(self): - return self._reference_vwu - - @reference_vwu.setter - def reference_vwu(self, vwu): - cv.check_type('reference v direction', vwu, Iterable, Real) - vwu = np.asarray(vwu) - uvw = self.reference_uvw - cv.check_greater_than('reference v direction must not be parallel to reference u direction', np.linalg.norm(np.cross(vwu,uvw)), 1e-6*np.linalg.norm(vwu)) - vwu -= vwu.dot(uvw)*uvw - cv.check_less_than('reference v direction must be orthogonal to reference u direction', np.abs(vwu.dot(uvw)), 1e-6) - self._reference_vwu = vwu/np.linalg.norm(vwu) - @property def mu(self): return self._mu + @property + def phi(self): + return self._phi + @mu.setter def mu(self, mu): cv.check_type('cosine of polar angle', mu, Univariate) self._mu = mu - @property - def phi(self): - return self._phi - @phi.setter def phi(self, phi): cv.check_type('azimuthal angle', phi, Univariate) self._phi = phi - def to_xml_element(self, element_name: str = None): + def to_xml_element(self): """Return XML representation of the angular distribution - Parameters - ---------- - element_name : str, optional - XML element name - Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing angular distribution data """ - if element_name is not None: - element = ET.Element(element_name) - else: - element = ET.Element('angle') - + element = ET.Element('angle') element.set("type", "mu-phi") if self.reference_uvw is not None: element.set("reference_uvw", ' '.join(map(str, self.reference_uvw))) - if self.reference_vwu is not None: - element.set("reference_vwu", ' '.join(map(str, self.reference_vwu))) element.append(self.mu.to_xml_element('mu')) element.append(self.phi.to_xml_element('phi')) return element @@ -171,7 +138,7 @@ class PolarAzimuthal(UnitSphere): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -181,83 +148,40 @@ class PolarAzimuthal(UnitSphere): """ mu_phi = cls() - uvw = get_elem_list(elem, "reference_uvw", float) - if uvw is not None: - mu_phi.reference_uvw = uvw - vwu = get_elem_list(elem, "reference_vwu", float) - if vwu is not None: - mu_phi.reference_vwu = vwu + params = get_text(elem, 'parameters') + if params is not None: + mu_phi.reference_uvw = [float(x) for x in params.split()] mu_phi.mu = Univariate.from_xml_element(elem.find('mu')) mu_phi.phi = Univariate.from_xml_element(elem.find('phi')) return mu_phi class Isotropic(UnitSphere): - """Isotropic angular distribution. + """Isotropic angular distribution.""" - Parameters - ---------- - bias : openmc.stats.PolarAzimuthal, optional - Distribution for biased sampling. - - Attributes - ---------- - bias : openmc.stats.PolarAzimuthal or None - Distribution for biased sampling - - """ - - def __init__(self, bias: PolarAzimuthal | None = None): + def __init__(self): super().__init__() - self.bias = bias - - @property - def bias(self): - return self._bias - - @bias.setter - def bias(self, bias): - cv.check_type('Biasing distribution', bias, PolarAzimuthal, none_ok=True) - if bias is not None: - if (bias.mu.bias is not None) or (bias.phi.bias is not None): - raise RuntimeError('Biasing distributions should not have their own bias.') - elif (bias.mu.support != (-1., 1.) - or not np.all(np.isclose(bias.phi.support, (0., 2*np.pi)))): - raise ValueError("Biasing distribution for an isotropic " - "distribution should be supported on " - "mu=(-1.0,1.0) and phi=(0.0,2*pi).") - - self._bias = bias def to_xml_element(self): """Return XML representation of the isotropic distribution Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing isotropic distribution data """ element = ET.Element('angle') element.set("type", "isotropic") - - if self.bias is not None: - bias_dist = self.bias - if (bias_dist.mu.bias is not None) or (bias_dist.phi.bias is not None): - raise RuntimeError('Biasing distributions should not have their own bias!') - else: - bias_elem = self.bias.to_xml_element("bias") - element.append(bias_elem) - return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate isotropic distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -266,13 +190,7 @@ class Isotropic(UnitSphere): Isotropic distribution generated from XML element """ - bias_elem = elem.find('bias') - if bias_elem is not None: - bias_dist = PolarAzimuthal.from_xml_element(bias_elem) - return cls(bias=bias_dist) - else: - return cls() - + return cls() class Monodirectional(UnitSphere): @@ -290,7 +208,7 @@ class Monodirectional(UnitSphere): """ - def __init__(self, reference_uvw: Sequence[float] = [1., 0., 0.]): + def __init__(self, reference_uvw=[1., 0., 0.]): super().__init__(reference_uvw) def to_xml_element(self): @@ -298,7 +216,7 @@ class Monodirectional(UnitSphere): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing monodirectional distribution data """ @@ -309,12 +227,12 @@ class Monodirectional(UnitSphere): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate monodirectional distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -324,9 +242,9 @@ class Monodirectional(UnitSphere): """ monodirectional = cls() - uvw = get_elem_list(elem, "reference_uvw", float) - if uvw is not None: - monodirectional.reference_uvw = uvw + params = get_text(elem, 'parameters') + if params is not None: + monodirectional.reference_uvw = [float(x) for x in params.split()] return monodirectional @@ -343,7 +261,7 @@ class Spatial(ABC): @classmethod @abstractmethod - def from_xml_element(cls, elem, meshes=None): + def from_xml_element(cls, elem): distribution = get_text(elem, 'type') if distribution == 'cartesian': return CartesianIndependent.from_xml_element(elem) @@ -355,10 +273,6 @@ class Spatial(ABC): return Box.from_xml_element(elem) elif distribution == 'point': return Point.from_xml_element(elem) - elif distribution == 'mesh': - return MeshSpatial.from_xml_element(elem, meshes) - elif distribution == 'cloud': - return PointCloud.from_xml_element(elem) class CartesianIndependent(Spatial): @@ -387,12 +301,7 @@ class CartesianIndependent(Spatial): """ - def __init__( - self, - x: openmc.stats.Univariate, - y: openmc.stats.Univariate, - z: openmc.stats.Univariate - ): + def __init__(self, x, y, z): self.x = x self.y = y self.z = z @@ -401,24 +310,24 @@ class CartesianIndependent(Spatial): def x(self): return self._x + @property + def y(self): + return self._y + + @property + def z(self): + return self._z + @x.setter def x(self, x): cv.check_type('x coordinate', x, Univariate) self._x = x - @property - def y(self): - return self._y - @y.setter def y(self, y): cv.check_type('y coordinate', y, Univariate) self._y = y - @property - def z(self): - return self._z - @z.setter def z(self, z): cv.check_type('z coordinate', z, Univariate) @@ -429,7 +338,7 @@ class CartesianIndependent(Spatial): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing spatial distribution data """ @@ -441,12 +350,12 @@ class CartesianIndependent(Spatial): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate spatial distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -514,33 +423,33 @@ class SphericalIndependent(Spatial): def r(self): return self._r + @property + def cos_theta(self): + return self._cos_theta + + @property + def phi(self): + return self._phi + + @property + def origin(self): + return self._origin + @r.setter def r(self, r): cv.check_type('r coordinate', r, Univariate) self._r = r - @property - def cos_theta(self): - return self._cos_theta - @cos_theta.setter def cos_theta(self, cos_theta): cv.check_type('cos_theta coordinate', cos_theta, Univariate) self._cos_theta = cos_theta - @property - def phi(self): - return self._phi - @phi.setter def phi(self, phi): cv.check_type('phi coordinate', phi, Univariate) self._phi = phi - @property - def origin(self): - return self._origin - @origin.setter def origin(self, origin): cv.check_type('origin coordinates', origin, Iterable, Real) @@ -552,7 +461,7 @@ class SphericalIndependent(Spatial): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing spatial distribution data """ @@ -565,12 +474,12 @@ class SphericalIndependent(Spatial): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate spatial distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -582,7 +491,7 @@ class SphericalIndependent(Spatial): r = Univariate.from_xml_element(elem.find('r')) cos_theta = Univariate.from_xml_element(elem.find('cos_theta')) phi = Univariate.from_xml_element(elem.find('phi')) - origin = get_elem_list(elem, "origin", float) + origin = [float(x) for x in elem.get('origin').split()] return cls(r, cos_theta, phi, origin=origin) @@ -610,10 +519,6 @@ class CylindricalIndependent(Spatial): origin: Iterable of float, optional coordinates (x0, y0, z0) of the center of the cylindrical reference frame. Defaults to (0.0, 0.0, 0.0) - r_dir : Iterable of float, optional - Unit vector of the cylinder r axis at phi=0. - z_dir : Iterable of float, optional - Unit vector of the cylinder z axis direction. Attributes ---------- @@ -627,92 +532,58 @@ class CylindricalIndependent(Spatial): origin: Iterable of float, optional coordinates (x0, y0, z0) of the center of the cylindrical reference frame. Defaults to (0.0, 0.0, 0.0) - r_dir : Iterable of float, optional - Unit vector of the cylinder r axis at phi=0. - z_dir : Iterable of float, optional - Unit vector of the cylinder z axis direction. """ - def __init__(self, r, phi, z, origin=(0.0, 0.0, 0.0), r_dir=(1.0, 0.0, 0.0), - z_dir=(0.0, 0.0, 1.0)): + def __init__(self, r, phi, z, origin=(0.0, 0.0, 0.0)): self.r = r self.phi = phi self.z = z self.origin = origin - self.z_dir = z_dir - self.r_dir = r_dir @property def r(self): return self._r + @property + def phi(self): + return self._phi + + @property + def z(self): + return self._z + + @property + def origin(self): + return self._origin + @r.setter def r(self, r): cv.check_type('r coordinate', r, Univariate) self._r = r - @property - def phi(self): - return self._phi - @phi.setter def phi(self, phi): cv.check_type('phi coordinate', phi, Univariate) self._phi = phi - @property - def z(self): - return self._z - @z.setter def z(self, z): cv.check_type('z coordinate', z, Univariate) self._z = z - @property - def origin(self): - return self._origin - @origin.setter def origin(self, origin): cv.check_type('origin coordinates', origin, Iterable, Real) origin = np.asarray(origin) self._origin = origin - @property - def z_dir(self): - return self._z_dir - - @z_dir.setter - def z_dir(self, z_dir): - cv.check_type('z-axis direction', z_dir, Iterable, Real) - z_dir = np.array(z_dir) - norm = np.linalg.norm(z_dir) - cv.check_greater_than('z-axis direction magnitude', norm, 0.0) - z_dir /= norm - self._z_dir = z_dir - - @property - def r_dir(self): - return self._r_dir - - @r_dir.setter - def r_dir(self, r_dir): - cv.check_type('r-axis direction', r_dir, Iterable, Real) - r_dir = np.array(r_dir) - r_dir -= np.dot(r_dir, self.z_dir) * self.z_dir - norm = np.linalg.norm(r_dir) - cv.check_greater_than('r-axis direction magnitude', norm, 0.0) - r_dir /= norm - self._r_dir = r_dir - def to_xml_element(self): """Return XML representation of the spatial distribution Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing spatial distribution data """ @@ -721,21 +592,16 @@ class CylindricalIndependent(Spatial): element.append(self.r.to_xml_element('r')) element.append(self.phi.to_xml_element('phi')) element.append(self.z.to_xml_element('z')) - if not np.allclose(self.origin, [0., 0., 0.]): - element.set("origin", ' '.join(map(str, self.origin))) - if not np.allclose(self.r_dir, [1., 0., 0.]): - element.set("r_dir", ' '.join(map(str, self.r_dir))) - if not np.allclose(self.z_dir, [0., 0., 1.]): - element.set("z_dir", ' '.join(map(str, self.z_dir))) + element.set("origin", ' '.join(map(str, self.origin))) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate spatial distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -747,299 +613,8 @@ class CylindricalIndependent(Spatial): r = Univariate.from_xml_element(elem.find('r')) phi = Univariate.from_xml_element(elem.find('phi')) z = Univariate.from_xml_element(elem.find('z')) - origin = get_elem_list(elem, "origin", float) or [0.0, 0.0, 0.0] - r_dir = get_elem_list(elem, "r_dir", float) or [1.0, 0.0, 0.0] - z_dir = get_elem_list(elem, "z_dir", float) or [0.0, 0.0, 1.0] - return cls(r, phi, z, origin=origin, r_dir=r_dir, z_dir=z_dir) - - -class MeshSpatial(Spatial): - """Spatial distribution for a mesh. - - This distribution specifies a mesh to sample over with source strengths - specified for each mesh element. - - .. versionadded:: 0.13.3 - - Parameters - ---------- - mesh : openmc.MeshBase - The mesh instance used for sampling - strengths : iterable of float, optional - An iterable of values that represents the weights of each element. If no - source strengths are specified, they will be equal for all mesh - elements. - volume_normalized : bool, optional - Whether or not the strengths will be multiplied by element volumes at - runtime. Default is True. - bias : iterable of float, optional - An iterable of values giving the selection weights assigned to each - element during biased sampling. - - Attributes - ---------- - mesh : openmc.MeshBase - The mesh instance used for sampling - strengths : numpy.ndarray or None - An array of source strengths for each mesh element - volume_normalized : bool - Whether or not the strengths will be multiplied by element volumes at - runtime. - bias : numpy.ndarray or None - Distribution for biased sampling - """ - - def __init__(self, mesh, strengths=None, volume_normalized=True, - bias: Sequence[float] | None = None): - self.mesh = mesh - self.strengths = strengths - self.volume_normalized = volume_normalized - self.bias = bias - - @property - def mesh(self): - return self._mesh - - @mesh.setter - def mesh(self, mesh): - if mesh is not None: - cv.check_type('mesh instance', mesh, MeshBase) - self._mesh = mesh - - @property - def volume_normalized(self): - return self._volume_normalized - - @volume_normalized.setter - def volume_normalized(self, volume_normalized): - cv.check_type('Multiply strengths by element volumes', volume_normalized, bool) - self._volume_normalized = volume_normalized - - @property - def strengths(self): - return self._strengths - - @strengths.setter - def strengths(self, given_strengths): - if given_strengths is not None: - cv.check_type('strengths array passed in', given_strengths, Iterable, Real) - self._strengths = np.asarray(given_strengths, dtype=float).flatten() - else: - self._strengths = None - - @property - def bias(self): - return self._bias - - @bias.setter - def bias(self, given_bias): - if given_bias is not None: - cv.check_type('Biasing strengths array', given_bias, Iterable, Real) - bias_array = np.asarray(given_bias, dtype=float).flatten() - if bias_array.size != self.strengths.size: - raise ValueError( - 'Bias strengths array must have same size as strengths array.') - else: - self._bias = bias_array - else: - self._bias = None - - @property - def num_strength_bins(self): - if self.strengths is None: - raise ValueError('Strengths are not set') - return self.strengths.size - - def to_xml_element(self): - """Return XML representation of the spatial distribution - - Returns - ------- - element : lxml.etree._Element - XML element containing spatial distribution data - - """ - element = ET.Element('space') - - element.set('type', 'mesh') - element.set("mesh_id", str(self.mesh.id)) - element.set("volume_normalized", str(self.volume_normalized)) - - if self.strengths is not None: - subelement = ET.SubElement(element, 'strengths') - subelement.text = ' '.join(str(e) for e in self.strengths) - - if self.bias is not None: - Univariate._append_array_bias_to_xml(self, element) - - return element - - @classmethod - def from_xml_element(cls, elem, meshes): - """Generate spatial distribution from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict - A dictionary with mesh IDs as keys and openmc.MeshBase instances as - values - - Returns - ------- - openmc.stats.MeshSpatial - Spatial distribution generated from XML element - - """ - - mesh_id = int(get_text(elem, "mesh_id")) - - # check if this mesh has been read in from another location already - if mesh_id not in meshes: - raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') - - volume_normalized = get_text(elem, 'volume_normalized').lower() == 'true' - strengths = get_elem_list(elem, 'strengths', float) - bias_strengths = Univariate._read_array_bias_from_xml(elem) - return cls(meshes[mesh_id], strengths, volume_normalized, bias=bias_strengths) - - -class PointCloud(Spatial): - """Spatial distribution from a point cloud. - - This distribution specifies a discrete list of points, with corresponding - relative probabilities. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - positions : iterable of 3-tuples - The points in space to be sampled - strengths : iterable of float, optional - An iterable of values that represents the relative probabilty of each - point. - bias : iterable of float, optional - An iterable of values representing the relative probability of each - point under biased sampling. - - Attributes - ---------- - positions : numpy.ndarray - The points in space to be sampled with shape (N, 3) - strengths : numpy.ndarray or None - An array of relative probabilities for each mesh point - bias : numpy.ndarray or None - An array of relative probabilities for biased sampling of mesh points - """ - - def __init__( - self, - positions: Sequence[Sequence[float]], - strengths: Sequence[float] | None = None, - bias: Sequence[float] | None = None - ): - self.positions = positions - self.strengths = strengths - self.bias = bias - - @property - def positions(self) -> np.ndarray: - return self._positions - - @positions.setter - def positions(self, positions): - positions = np.array(positions, dtype=float) - if positions.ndim != 2: - raise ValueError('positions must be a 2D array') - elif positions.shape[1] != 3: - raise ValueError('Each position must have 3 values') - self._positions = positions - - @property - def strengths(self) -> np.ndarray: - return self._strengths - - @strengths.setter - def strengths(self, strengths): - if strengths is not None: - strengths = np.array(strengths, dtype=float) - if strengths.ndim != 1: - raise ValueError('strengths must be a 1D array') - elif strengths.size != self.positions.shape[0]: - raise ValueError('strengths must have the same length as positions') - self._strengths = strengths - - @property - def bias(self): - return self._bias - - @bias.setter - def bias(self, given_bias): - if given_bias is not None: - cv.check_type('Biasing strengths array', given_bias, Iterable, Real) - bias_array = np.asarray(given_bias, dtype=float).flatten() - if bias_array.size != self.strengths.size: - raise ValueError( - 'Bias strengths array must have same size as strengths array.') - else: - self._bias = bias_array - else: - self._bias = None - - @property - def num_strength_bins(self) -> int: - if self.strengths is None: - raise ValueError('Strengths are not set') - return self.strengths.size - - def to_xml_element(self) -> ET.Element: - """Return XML representation of the spatial distribution - - Returns - ------- - element : lxml.etree._Element - XML element containing spatial distribution data - - """ - element = ET.Element('space') - element.set('type', 'cloud') - - subelement = ET.SubElement(element, 'coords') - subelement.text = ' '.join(str(e) for e in self.positions.flatten()) - - if self.strengths is not None: - subelement = ET.SubElement(element, 'strengths') - subelement.text = ' '.join(str(e) for e in self.strengths) - - if self.bias is not None: - Univariate._append_array_bias_to_xml(self, element) - - return element - - @classmethod - def from_xml_element(cls, elem: ET.Element) -> PointCloud: - """Generate spatial distribution from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.stats.PointCloud - Spatial distribution generated from XML element - - - """ - coord_data = get_elem_list(elem, 'coords', float) - positions = np.array(coord_data).reshape((-1, 3)) - - strengths = get_elem_list(elem, 'strengths', float) - bias_strengths = Univariate._read_array_bias_from_xml(elem) - return cls(positions, strengths, bias=bias_strengths) + origin = [float(x) for x in elem.get('origin').split()] + return cls(r, phi, z, origin=origin) class Box(Spatial): @@ -1055,9 +630,6 @@ class Box(Spatial): Whether spatial sites should only be accepted if they occur in fissionable materials - .. deprecated:: 0.15.0 - Use the `constraints` argument when defining a source object instead. - Attributes ---------- lower_left : Iterable of float @@ -1068,17 +640,9 @@ class Box(Spatial): Whether spatial sites should only be accepted if they occur in fissionable materials - .. deprecated:: 0.15.0 - Use the `constraints` argument when defining a source object instead. - """ - def __init__( - self, - lower_left: Sequence[float], - upper_right: Sequence[float], - only_fissionable: bool = False - ): + def __init__(self, lower_left, upper_right, only_fissionable=False): self.lower_left = lower_left self.upper_right = upper_right self.only_fissionable = only_fissionable @@ -1087,41 +651,37 @@ class Box(Spatial): def lower_left(self): return self._lower_left + @property + def upper_right(self): + return self._upper_right + + @property + def only_fissionable(self): + return self._only_fissionable + @lower_left.setter def lower_left(self, lower_left): cv.check_type('lower left coordinate', lower_left, Iterable, Real) cv.check_length('lower left coordinate', lower_left, 3) self._lower_left = lower_left - @property - def upper_right(self): - return self._upper_right - @upper_right.setter def upper_right(self, upper_right): cv.check_type('upper right coordinate', upper_right, Iterable, Real) cv.check_length('upper right coordinate', upper_right, 3) self._upper_right = upper_right - @property - def only_fissionable(self): - return self._only_fissionable - @only_fissionable.setter def only_fissionable(self, only_fissionable): cv.check_type('only fissionable', only_fissionable, bool) self._only_fissionable = only_fissionable - if only_fissionable: - warn("The 'only_fissionable' has been deprecated. Use the " - "'constraints' argument when defining a source instead.", - FutureWarning) def to_xml_element(self): """Return XML representation of the box distribution Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing box distribution data """ @@ -1136,12 +696,12 @@ class Box(Spatial): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate box distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1151,7 +711,7 @@ class Box(Spatial): """ only_fissionable = get_text(elem, 'type') == 'fission' - params = get_elem_list(elem, "parameters", float) + params = [float(x) for x in get_text(elem, 'parameters').split()] lower_left = params[:len(params)//2] upper_right = params[len(params)//2:] return cls(lower_left, upper_right, only_fissionable) @@ -1175,7 +735,7 @@ class Point(Spatial): """ - def __init__(self, xyz: Sequence[float] = (0., 0., 0.)): + def __init__(self, xyz=(0., 0., 0.)): self.xyz = xyz @property @@ -1193,7 +753,7 @@ class Point(Spatial): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing point distribution location """ @@ -1204,12 +764,12 @@ class Point(Spatial): return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate point distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1218,17 +778,12 @@ class Point(Spatial): Point distribution generated from XML element """ - xyz = get_elem_list(elem, "parameters", float) + xyz = [float(x) for x in get_text(elem, 'parameters').split()] return cls(xyz) -def spherical_uniform( - r_outer: float, - r_inner: float = 0.0, - thetas: Sequence[float] = (0., pi), - phis: Sequence[float] = (0., 2*pi), - origin: Sequence[float] = (0., 0., 0.) - ): +def spherical_uniform(r_outer, r_inner=0.0, thetas=(0., pi), phis=(0., 2*pi), + origin=(0., 0., 0.)): """Return a uniform spatial distribution over a spherical shell. This function provides a uniform spatial distribution over a spherical @@ -1241,15 +796,15 @@ def spherical_uniform( ---------- r_outer : float Outer radius of the spherical shell in [cm] - r_inner : float + r_inner : float, optional Inner radius of the spherical shell in [cm] - thetas : iterable of float + thetas : iterable of float, optional Starting and ending theta coordinates (angle relative to the z-axis) in radius in a reference frame centered at `origin` - phis : iterable of float + phis : iterable of float, optional Starting and ending phi coordinates (azimuthal angle) in radians in a reference frame centered at `origin` - origin: iterable of float + origin: iterable of float, optional Coordinates (x0, y0, z0) of the center of the spherical reference frame for the distribution. @@ -1264,49 +819,3 @@ def spherical_uniform( phis_dist = Uniform(phis[0], phis[1]) return SphericalIndependent(r_dist, cos_thetas_dist, phis_dist, origin) - - -def cylindrical_uniform( - r_outer: float, - height: float, - r_inner: float = 0.0, - phis: Sequence[float] = (0., 2*pi), - **kwargs, -): - """Return a uniform spatial distribution over a cylindrical shell. - - This function provides a uniform spatial distribution over a cylindrical - shell between `r_inner` and `r_outer`. When `height` is zero, a delta - function is used for the z-distribution, giving a uniform distribution over - a flat ring (annulus) at z=0 in the local coordinate frame. Optionally, the - range of angles can be restricted by the `phis` argument. - - .. versionadded:: 0.15.4 - - Parameters - ---------- - r_outer : float - Outer radius of the cylindrical shell in [cm] - height : float - Height of the cylindrical shell in [cm]. When 0, the distribution is a - flat ring at z=0 in the local frame. - r_inner : float - Inner radius of the cylindrical shell in [cm] - phis : iterable of float - Starting and ending phi coordinates (azimuthal angle) in radians in a - reference frame centered at `origin`. - **kwargs - Keyword arguments passed directly to - :class:`~openmc.stats.CylindricalIndependent` (e.g., ``origin``, - ``r_dir``, ``z_dir``). - - Returns - ------- - openmc.stats.CylindricalIndependent - Uniform distribution over the cylindrical shell - """ - - r_dist = PowerLaw(r_inner, r_outer, 1) - phis_dist = Uniform(phis[0], phis[1]) - z_dist = delta_function(0.0) if height == 0.0 else Uniform(-height/2, height/2) - return CylindricalIndependent(r_dist, phis_dist, z_dist, **kwargs) diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index 1b18bcb17..5298499ce 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -1,42 +1,24 @@ -from __future__ import annotations from abc import ABC, abstractmethod from collections import defaultdict -from collections.abc import Iterable, Sequence -from functools import cache -from math import sqrt, pi, exp, log +from collections.abc import Iterable +from copy import deepcopy from numbers import Real -from pathlib import Path -from warnings import warn +from xml.etree import ElementTree as ET -import lxml.etree as ET import numpy as np -from scipy.integrate import trapezoid -from scipy.special import exprel, hyp1f1, lambertw -import scipy import openmc.checkvalue as cv -from openmc.data import atomic_mass, NEUTRON_MASS -import openmc.data -from .._xml import get_elem_list, get_text +from .._xml import get_text from ..mixin import EqualityMixin -_INTERPOLATION_SCHEMES = { + +_INTERPOLATION_SCHEMES = [ 'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log' -} - - -def exprel2(x): - """Evaluate 2*(exp(x)-1-x)/x^2 without loss of precision near 0""" - return hyp1f1(1, 3, x) - - -def log1prel(x): - """Evaluate log(1+x)/x without loss of precision near 0""" - return np.where(np.abs(x) < 1e-16, 1.0, np.log1p(x) / x) +] class Univariate(EqualityMixin, ABC): @@ -45,55 +27,7 @@ class Univariate(EqualityMixin, ABC): The Univariate class is an abstract class that can be derived to implement a specific probability distribution. - Parameters - ---------- - bias : Iterable of float, optional - Distribution or discrete probabilities for biased sampling or discrete - probabilities for biased sampling. - """ - def __init__(self, bias: Univariate | Sequence[float] | None = None): - self.bias = bias - - @property - def bias(self): - return self._bias - - @bias.setter - def bias(self, bias): - check_bias_support(self, bias) - self._bias = bias - - def _append_bias_to_xml(self, element: ET.Element) -> None: - """Append bias distribution element to XML if present.""" - if self.bias is not None: - if self.bias.bias is not None: - raise RuntimeError('Biasing distributions should not have their own bias.') - bias_elem = self.bias.to_xml_element("bias") - element.append(bias_elem) - - @classmethod - def _read_bias_from_xml(cls, elem: ET.Element): - """Read bias distribution from XML element if present.""" - bias_elem = elem.find('bias') - if bias_elem is not None: - return Univariate.from_xml_element(bias_elem) - return None - - def _append_array_bias_to_xml(self, element: ET.Element) -> None: - """Append array-based bias probabilities to XML.""" - if self.bias is not None: - bias_elem = ET.SubElement(element, "bias") - bias_elem.text = ' '.join(map(str, self.bias)) - - @classmethod - def _read_array_bias_from_xml(cls, elem: ET.Element): - """Read array-based bias probabilities from XML.""" - bias_elem = elem.find('bias') - if bias_elem is not None: - return get_elem_list(elem, "bias", float) - return None - @abstractmethod def to_xml_element(self, element_name): return '' @@ -119,20 +53,17 @@ class Univariate(EqualityMixin, ABC): elif distribution == 'normal': return Normal.from_xml_element(elem) elif distribution == 'muir': - # Support older files where Muir had its own class - return muir(*get_elem_list(elem, "parameters", float)) + return Muir.from_xml_element(elem) elif distribution == 'tabular': return Tabular.from_xml_element(elem) elif distribution == 'legendre': return Legendre.from_xml_element(elem) elif distribution == 'mixture': return Mixture.from_xml_element(elem) - elif distribution == 'decay_spectrum': - return DecaySpectrum.from_xml_element(elem) @abstractmethod - def _sample_unbiased(self, n_samples: int = 1, seed: int | None = None): - """Sample without bias handling. + def sample(n_samples=1, seed=None): + """Sample the univariate distribution Parameters ---------- @@ -144,35 +75,10 @@ class Univariate(EqualityMixin, ABC): Returns ------- numpy.ndarray - The array of sampled values + A 1-D array of sampled values """ pass - def sample(self, n_samples: int = 1, seed: int | None = None): - """Sample the univariate distribution, handling biasing automatically. - - Parameters - ---------- - n_samples : int - Number of sampled values to generate - seed : int or None - Initial random number seed. - - Returns - ------- - tuple of numpy.ndarray - A tuple of (samples, weights) - """ - if self.bias is None: - x = self._sample_unbiased(n_samples, seed) - return x, np.ones_like(x) - else: - if self.bias.bias is not None: - raise RuntimeError('Biasing distributions should not have their own bias.') - x, _ = self.bias.sample(n_samples=n_samples, seed=seed) - weight = self.evaluate(x) / self.bias.evaluate(x) - return x, weight - def integral(self): """Return integral of distribution @@ -185,75 +91,6 @@ class Univariate(EqualityMixin, ABC): """ return 1.0 - @abstractmethod - def evaluate(self, x: float | Sequence[float]): - """Evaluate the probability density at the provided value. - - Parameters - ---------- - x : float or sequence of float - Location to evaluate p(x) - - Returns - ------- - float or numpy.ndarray - Value of p(x) - """ - pass - - @property - @abstractmethod - def support(self): - """Return the support of the probability distribution. - - Returns - ------- - set or tuple of float or dict - Returns the set of unique points assigned probability mass in a - discrete distribution, the sampling interval for a continuous - distribution, or a dictionary storing the discrete and continuous - parts of the support of a mixed random variable - """ - pass - -def _intensity_clip(intensity: Sequence[float], tolerance: float = 1e-6) -> np.ndarray: - """Clip low-importance points from an array of intensities. - - Given an array of intensities, this function returns an array of indices for - points that contribute non-negligibly to the total sum of intensities. - - Parameters - ---------- - intensity : sequence of float - Intensities in arbitrary units. - tolerance : float - Maximum fraction of intensities that will be discarded. - - Returns - ------- - Array of indices - - """ - # Get indices of intensities from largest to smallest - index_sort = np.argsort(intensity)[::-1] - - # Get intensities from largest to smallest - sorted_intensity = np.asarray(intensity)[index_sort] - - # Determine cumulative sum of probabilities - cumsum = np.cumsum(sorted_intensity) - cumsum /= cumsum[-1] - - # Find index that satisfies cutoff - index_cutoff = np.searchsorted(cumsum, 1.0 - tolerance) - - # Now get indices up to cutoff - new_indices = index_sort[:index_cutoff + 1] - - # Put back in the order of the original array and return - new_indices.sort() - return new_indices - class Discrete(Univariate): """Distribution characterized by a probability mass function. @@ -268,9 +105,6 @@ class Discrete(Univariate): Values of the random variable p : Iterable of float Discrete probability for each value - bias : Iterable of float, optional - Alternative discrete probabilities for biased sampling. Defaults to - None for unbiased sampling. Attributes ---------- @@ -278,18 +112,12 @@ class Discrete(Univariate): Values of the random variable p : numpy.ndarray Discrete probability for each value - support : set - Values of the random variable over which the distribution is - nonzero-valued - bias : numpy.ndarray or None - Discrete probabilities for biased sampling """ - def __init__(self, x, p, bias=None): + def __init__(self, x, p): self.x = x self.p = p - super().__init__(bias) def __len__(self): return len(self.x) @@ -298,6 +126,10 @@ class Discrete(Univariate): def x(self): return self._x + @property + def p(self): + return self._p + @x.setter def x(self, x): if isinstance(x, Real): @@ -305,10 +137,6 @@ class Discrete(Univariate): cv.check_type('discrete values', x, Iterable, Real) self._x = np.array(x, dtype=float) - @property - def p(self): - return self._p - @p.setter def p(self, p): if isinstance(p, Real): @@ -318,54 +146,19 @@ class Discrete(Univariate): cv.check_greater_than('discrete probability', pk, 0.0, True) self._p = np.array(p, dtype=float) - @property - def support(self): - return set(np.unique(self._x)) - - @Univariate.bias.setter - def bias(self, bias): - if bias is None: - self._bias = bias - else: - if isinstance(bias, Real): - bias = [bias] - cv.check_type('discrete bias probabilities', bias, Iterable, Real) - for bk in bias: - cv.check_greater_than('discrete probability', bk, 0.0, True) - if len(bias) != len(self.x): - raise RuntimeError("Discrete distribution has unequal number of " - "biased and unbiased probability entries.") - self._bias = np.array(bias, dtype=float) - def cdf(self): return np.insert(np.cumsum(self.p), 0, 0.0) def sample(self, n_samples=1, seed=None): - if self.bias is None: - samples = self._sample_unbiased(n_samples, seed) - return samples, np.ones_like(samples) - else: - rng = np.random.RandomState(seed) - p = self.p / self.p.sum() - b = self.bias / self.bias.sum() - indices = rng.choice(self.x.size, n_samples, p=b) - biased_sample = self.x[indices] - wgt = p[indices] / b[indices] - return biased_sample, wgt - - def _sample_unbiased(self, n_samples=1, seed=None): - rng = np.random.RandomState(seed) + np.random.seed(seed) p = self.p / self.p.sum() - return rng.choice(self.x, n_samples, p=p) + return np.random.choice(self.x, n_samples, p=p) def normalize(self): """Normalize the probabilities stored on the distribution""" norm = sum(self.p) self.p = [val / norm for val in self.p] - def evaluate(self, x): - raise NotImplementedError - def to_xml_element(self, element_name): """Return XML representation of the discrete distribution @@ -376,7 +169,7 @@ class Discrete(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing discrete distribution data """ @@ -385,16 +178,16 @@ class Discrete(Univariate): params = ET.SubElement(element, "parameters") params.text = ' '.join(map(str, self.x)) + ' ' + ' '.join(map(str, self.p)) - self._append_array_bias_to_xml(element) + return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate discrete distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -403,18 +196,13 @@ class Discrete(Univariate): Discrete distribution generated from XML element """ - params = get_elem_list(elem, "parameters", float) + params = [float(x) for x in get_text(elem, 'parameters').split()] x = params[:len(params)//2] p = params[len(params)//2:] - bias_dist = cls._read_array_bias_from_xml(elem) - return cls(x, p, bias=bias_dist) + return cls(x, p) @classmethod - def merge( - cls, - dists: Sequence[Discrete], - probs: Sequence[float] - ): + def merge(cls, dists, probs): """Merge multiple discrete distributions into a single distribution .. versionadded:: 0.13.1 @@ -435,52 +223,18 @@ class Discrete(Univariate): if len(dists) != len(probs): raise ValueError("Number of distributions and probabilities must match.") - biasing = False - for d in dists: - if d.bias is not None: - # If we find that at least one distribution is biased, all - # distributions which are not biased will be assigned their - # default probability vector as a "bias" so that biased - # sampling can occur on the merged distribution. - biasing = True - break - # Combine distributions accounting for duplicate x values x_merged = set() p_merged = defaultdict(float) - new_bias = None + for dist, p_dist in zip(dists, probs): + for x, p in zip(dist.x, dist.p): + x_merged.add(x) + p_merged[x] += p*p_dist - if biasing: - b_merged = defaultdict(float) - - # Generate any missing bias distributions - dists = dists.copy() - for i, d in enumerate(dists): - if d.bias is None: - dists[i] = Discrete(d.x, d.p, bias=d.p) - - for dist, p_dist in zip(dists, probs): - for x, p, b in zip(dist.x, dist.p, dist.bias): - x_merged.add(x) - p_merged[x] += p*p_dist - b_merged[x] += b*p_dist - - # Create values and bias probabilities as arrays - x_arr = np.array(sorted(x_merged)) - new_bias = np.array([b_merged[x] for x in x_arr]) - - else: - for dist, p_dist in zip(dists, probs): - for x, p in zip(dist.x, dist.p): - x_merged.add(x) - p_merged[x] += p*p_dist - - # Create values as array - x_arr = np.array(sorted(x_merged)) - - # Create probabilities as array + # Create values and probabilities as arrays + x_arr = np.array(sorted(x_merged)) p_arr = np.array([p_merged[x] for x in x_arr]) - return cls(x_arr, p_arr, new_bias) + return cls(x_arr, p_arr) def integral(self): """Return integral of distribution @@ -494,91 +248,6 @@ class Discrete(Univariate): """ return np.sum(self.p) - def mean(self) -> float: - """Return mean of the discrete distribution - - The mean is the weighted average of the discrete values. - - .. versionadded:: 0.15.3 - - Returns - ------- - float - Mean of discrete distribution - """ - return np.sum(self.x * self.p) / np.sum(self.p) - - def clip(self, tolerance: float = 1e-6, inplace: bool = False) -> Discrete: - r"""Remove low-importance points from discrete distribution. - - Given a probability mass function :math:`p(x)` with :math:`\{x_1, x_2, - x_3, \dots\}` the possible values of the random variable with - corresponding probabilities :math:`\{p_1, p_2, p_3, \dots\}`, this - function will remove any low-importance points such that :math:`\sum_i - x_i p_i` is preserved to within some threshold. - - For biased distributions, clipping should be performed before the bias - probabilities are added. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - tolerance : float - Maximum fraction of :math:`\sum_i x_i p_i` that will be discarded. - inplace : bool - Whether to modify the current object in-place or return a new one. - - Returns - ------- - Discrete distribution with low-importance points removed - - """ - if self.bias is not None: - raise RuntimeError("Biased discrete distributions should be clipped " - "before applying bias.") - - cv.check_less_than("tolerance", tolerance, 1.0, equality=True) - cv.check_greater_than("tolerance", tolerance, 0.0, equality=True) - - # Compute intensities - intensity = self.p * self.x - - # Get indices for intensities above threshold - indices = _intensity_clip(intensity, tolerance=tolerance) - - # Create new discrete distribution - if inplace: - self.x = self.x[indices] - self.p = self.p[indices] - return self - else: - new_x = self.x[indices] - new_p = self.p[indices] - return type(self)(new_x, new_p) - - -def delta_function(value: float, intensity: float = 1.0) -> Discrete: - """Return a discrete distribution with a single point. - - .. versionadded:: 0.15.1 - - Parameters - ---------- - value : float - Value of the random variable. - intensity : float, optional - When used for an energy distribution, this can be used to assign an - intensity. - - Returns - ------- - Discrete distribution with a single point - - """ - return Discrete([value], [intensity]) - - class Uniform(Univariate): """Distribution with constant probability over a finite interval [a,b] @@ -588,8 +257,6 @@ class Uniform(Univariate): Lower bound of the sampling interval. Defaults to zero. b : float, optional Upper bound of the sampling interval. Defaults to unity. - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. Attributes ---------- @@ -597,19 +264,12 @@ class Uniform(Univariate): Lower bound of the sampling interval b : float Upper bound of the sampling interval - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling """ - def __init__(self, a: float = 0.0, b: float = 1.0, - bias: Univariate | None = None): + def __init__(self, a=0.0, b=1.0): self.a = a self.b = b - super().__init__(bias) def __len__(self): return 2 @@ -618,52 +278,31 @@ class Uniform(Univariate): def a(self): return self._a + @property + def b(self): + return self._b + @a.setter def a(self, a): cv.check_type('Uniform a', a, Real) self._a = a - @property - def b(self): - return self._b - @b.setter def b(self, b): cv.check_type('Uniform b', b, Real) self._b = b - @property - def support(self): - return (self._a, self._b) - def to_tabular(self): - if self.bias is not None: - raise RuntimeError("to_tabular() is not permitted for biased distributions.") prob = 1./(self.b - self.a) t = Tabular([self.a, self.b], [prob, prob], 'histogram') t.c = [0., 1.] return t - def _sample_unbiased(self, n_samples=1, seed=None): - rng = np.random.RandomState(seed) - return rng.uniform(self.a, self.b, n_samples) + def sample(self, n_samples=1, seed=None): + np.random.seed(seed) + return np.random.uniform(self.a, self.b, n_samples) - def evaluate(self, x): - return np.where((self.a <= x) & (x <= self.b), 1/(self.b - self.a), 0.0) - - def mean(self) -> float: - """Return mean of the uniform distribution - - .. versionadded:: 0.15.3 - - Returns - ------- - float - Mean of uniform distribution - """ - return 0.5 * (self.a + self.b) - - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the uniform distribution Parameters @@ -673,23 +312,22 @@ class Uniform(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing uniform distribution data """ element = ET.Element(element_name) element.set("type", "uniform") - element.set("parameters", f'{self.a} {self.b}') - self._append_bias_to_xml(element) + element.set("parameters", '{} {}'.format(self.a, self.b)) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate uniform distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -698,9 +336,8 @@ class Uniform(Univariate): Uniform distribution generated from XML element """ - params = get_elem_list(elem, "parameters", float) - bias_dist = cls._read_bias_from_xml(elem) - return cls(*params, bias=bias_dist) + params = get_text(elem, 'parameters').split() + return cls(*map(float, params)) class PowerLaw(Univariate): @@ -719,8 +356,6 @@ class PowerLaw(Univariate): n : float, optional Power law exponent. Defaults to zero, which is equivalent to a uniform distribution. - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. Attributes ---------- @@ -730,23 +365,13 @@ class PowerLaw(Univariate): Upper bound of the sampling interval n : float Power law exponent - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling """ - def __init__(self, a: float = 0.0, b: float = 1.0, n: float = 0., - bias: Univariate | None = None): - if a >= b: - raise ValueError( - "Lower bound of sampling interval must be less than upper bound.") + def __init__(self, a=0.0, b=1.0, n=0): self.a = a self.b = b self.n = n - super().__init__(bias) def __len__(self): return 3 @@ -755,52 +380,38 @@ class PowerLaw(Univariate): def a(self): return self._a - @a.setter - def a(self, a): - cv.check_type('interval lower bound', a, Real) - if a < 0: - raise ValueError( - "PowerLaw sampling is restricted to positive-valued intervals.") - self._a = a - @property def b(self): return self._b - @b.setter - def b(self, b): - cv.check_type('interval upper bound', b, Real) - if b < 0: - raise ValueError( - "PowerLaw sampling is restricted to positive-valued intervals.") - self._b = b - @property def n(self): return self._n + @a.setter + def a(self, a): + cv.check_type('interval lower bound', a, Real) + self._a = a + + @b.setter + def b(self, b): + cv.check_type('interval upper bound', b, Real) + self._b = b + @n.setter def n(self, n): cv.check_type('power law exponent', n, Real) self._n = n - @property - def support(self): - return (self._a, self._b) - - def _sample_unbiased(self, n_samples=1, seed=None): - rng = np.random.RandomState(seed) - xi = rng.random(n_samples) + def sample(self, n_samples=1, seed=None): + np.random.seed(seed) + xi = np.random.rand(n_samples) pwr = self.n + 1 offset = self.a**pwr span = self.b**pwr - offset return np.power(offset + xi * span, 1/pwr) - def evaluate(self, x): - c = (self.n + 1)/(self.b**(self.n + 1) - self.a**(self.n + 1)) - return np.where((self.a <= x) & (x <= self.b), c * np.abs(x)**self.n, 0.0) - - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the power law distribution Parameters @@ -810,23 +421,22 @@ class PowerLaw(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing distribution data """ element = ET.Element(element_name) element.set("type", "powerlaw") element.set("parameters", f'{self.a} {self.b} {self.n}') - self._append_bias_to_xml(element) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate power law distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -835,9 +445,8 @@ class PowerLaw(Univariate): Distribution generated from XML element """ - params = get_elem_list(elem, "parameters", float) - bias_dist = cls._read_bias_from_xml(elem) - return cls(*map(float, params), bias=bias_dist) + params = get_text(elem, 'parameters').split() + return cls(*map(float, params)) class Maxwell(Univariate): @@ -851,24 +460,16 @@ class Maxwell(Univariate): ---------- theta : float Effective temperature for distribution in eV - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. Attributes ---------- theta : float Effective temperature for distribution in eV - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling """ - def __init__(self, theta, bias: Univariate | None = None): + def __init__(self, theta): self.theta = theta - super().__init__(bias) def __len__(self): return 1 @@ -883,24 +484,17 @@ class Maxwell(Univariate): cv.check_greater_than('Maxwell temperature', theta, 0.0) self._theta = theta - @property - def support(self): - return (0.0, np.inf) - - def _sample_unbiased(self, n_samples=1, seed=None): - rng = np.random.RandomState(seed) - return self.sample_maxwell(self.theta, n_samples, rng=rng) + def sample(self, n_samples=1, seed=None): + np.random.seed(seed) + return self.sample_maxwell(self.theta, n_samples) @staticmethod - def sample_maxwell(t, n_samples: int, rng=None): - if rng is None: - rng = np.random.default_rng() - return rng.gamma(1.5, t, n_samples) + def sample_maxwell(t, n_samples): + r1, r2, r3 = np.random.rand(3, n_samples) + c = np.cos(0.5 * np.pi * r3) + return -t * (np.log(r1) + np.log(r2) * c * c) - def evaluate(self, E): - return scipy.stats.gamma.pdf(E, 1.5, scale=self.theta) - - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the Maxwellian distribution Parameters @@ -910,23 +504,22 @@ class Maxwell(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing Maxwellian distribution data """ element = ET.Element(element_name) element.set("type", "maxwell") element.set("parameters", str(self.theta)) - self._append_bias_to_xml(element) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate Maxwellian distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -936,8 +529,7 @@ class Maxwell(Univariate): """ theta = float(get_text(elem, 'parameters')) - bias_dist = cls._read_bias_from_xml(elem) - return cls(theta, bias=bias_dist) + return cls(theta) class Watt(Univariate): @@ -953,8 +545,6 @@ class Watt(Univariate): First parameter of distribution in units of eV b : float Second parameter of distribution in units of 1/eV - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. Attributes ---------- @@ -962,18 +552,12 @@ class Watt(Univariate): First parameter of distribution in units of eV b : float Second parameter of distribution in units of 1/eV - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling """ - def __init__(self, a=0.988e6, b=2.249e-6, bias: Univariate | None = None): + def __init__(self, a=0.988e6, b=2.249e-6): self.a = a self.b = b - super().__init__(bias) def __len__(self): return 2 @@ -982,38 +566,30 @@ class Watt(Univariate): def a(self): return self._a + @property + def b(self): + return self._b + @a.setter def a(self, a): cv.check_type('Watt a', a, Real) cv.check_greater_than('Watt a', a, 0.0) self._a = a - @property - def b(self): - return self._b - @b.setter def b(self, b): cv.check_type('Watt b', b, Real) cv.check_greater_than('Watt b', b, 0.0) self._b = b - @property - def support(self): - return (0.0, np.inf) - - def _sample_unbiased(self, n_samples=1, seed=None): - rng = np.random.RandomState(seed) - w = Maxwell.sample_maxwell(self.a, n_samples, rng=rng) - u = rng.uniform(-1., 1., n_samples) + def sample(self, n_samples=1, seed=None): + np.random.seed(seed) + w = Maxwell.sample_maxwell(self.a, n_samples) + u = np.random.uniform(-1., 1., n_samples) aab = self.a * self.a * self.b return w + 0.25*aab + u*np.sqrt(aab*w) - def evaluate(self, E): - c = 2.0/(sqrt(pi * self.b) * (self.a**1.5) * exp(self.a*self.b/4)) - return c*np.exp(-E/self.a)*np.sinh(np.sqrt(self.b*E)) - - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the Watt distribution Parameters @@ -1023,23 +599,22 @@ class Watt(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing Watt distribution data """ element = ET.Element(element_name) element.set("type", "watt") - element.set("parameters", f'{self.a} {self.b}') - self._append_bias_to_xml(element) + element.set("parameters", '{} {}'.format(self.a, self.b)) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate Watt distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1048,35 +623,23 @@ class Watt(Univariate): Watt distribution generated from XML element """ - params = get_elem_list(elem, "parameters", float) - bias_dist = cls._read_bias_from_xml(elem) - return cls(*map(float, params), bias=bias_dist) + params = get_text(elem, 'parameters').split() + return cls(*map(float, params)) class Normal(Univariate): - r"""Normally distributed sampling with optional truncation. + r"""Normally distributed sampling. - The normal distribution is characterized by parameters :math:`\mu` and - :math:`\sigma` and has density function :math:`p(X) = 1/(\sqrt{2\pi}\sigma) - e^{-(X-\mu)^2/(2\sigma^2)}`. When truncated to the interval [lower, upper], - the distribution is renormalized so that the PDF integrates to 1 over the - truncation interval. - - .. versionchanged:: 0.15.4 - Added optional truncation bounds via `lower` and `upper` parameters. + The Normal Distribution is characterized by two parameters + :math:`\mu` and :math:`\sigma` and has density function + :math:`p(X) dX = 1/(\sqrt{2\pi}\sigma) e^{-(X-\mu)^2/(2\sigma^2)}` Parameters ---------- mean_value : float - Mean value of the distribution + Mean value of the distribution std_dev : float Standard deviation of the Normal distribution - lower : float, optional - Lower truncation bound. Defaults to -infinity (no lower bound). - upper : float, optional - Upper truncation bound. Defaults to +infinity (no upper bound). - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. Attributes ---------- @@ -1084,115 +647,39 @@ class Normal(Univariate): Mean of the Normal distribution std_dev : float Standard deviation of the Normal distribution - lower : float - Lower truncation bound - upper : float - Upper truncation bound - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling """ - def __init__(self, mean_value, std_dev, lower=-np.inf, upper=np.inf, - bias: Univariate | None = None): + def __init__(self, mean_value, std_dev): self.mean_value = mean_value self.std_dev = std_dev - self.lower = lower - self.upper = upper - self._compute_normalization() - super().__init__(bias) def __len__(self): - if self._is_truncated: - return 4 return 2 @property def mean_value(self): return self._mean_value + @property + def std_dev(self): + return self._std_dev + @mean_value.setter def mean_value(self, mean_value): cv.check_type('Normal mean_value', mean_value, Real) self._mean_value = mean_value - @property - def std_dev(self): - return self._std_dev - @std_dev.setter def std_dev(self, std_dev): cv.check_type('Normal std_dev', std_dev, Real) cv.check_greater_than('Normal std_dev', std_dev, 0.0) self._std_dev = std_dev - @property - def lower(self): - return self._lower + def sample(self, n_samples=1, seed=None): + np.random.seed(seed) + return np.random.normal(self.mean_value, self.std_dev, n_samples) - @lower.setter - def lower(self, lower): - cv.check_type('Normal lower bound', lower, Real) - self._lower = lower - - @property - def upper(self): - return self._upper - - @upper.setter - def upper(self, upper): - cv.check_type('Normal upper bound', upper, Real) - self._upper = upper - - def _compute_normalization(self): - """Compute normalization factor for truncated distribution.""" - # Check if truncation bounds are finite - self._is_truncated = (self._lower > -np.inf or self._upper < np.inf) - - if self._lower >= self._upper: - raise ValueError("Normal distribution lower bound must be less " - "than upper bound.") - - if self._is_truncated: - alpha = (self._lower - self._mean_value) / self._std_dev - beta = (self._upper - self._mean_value) / self._std_dev - cdf_diff = scipy.stats.norm.cdf(beta) - scipy.stats.norm.cdf(alpha) - if cdf_diff <= 0: - raise ValueError("Truncation bounds exclude entire distribution") - self._norm_factor = 1.0 / cdf_diff - else: - self._norm_factor = 1.0 - - @property - def support(self): - return (self._lower, self._upper) - - def _sample_unbiased(self, n_samples=1, seed=None): - rng = np.random.RandomState(seed) - if not self._is_truncated: - return rng.normal(self.mean_value, self.std_dev, n_samples) - else: - # Use scipy's truncated normal for efficient direct sampling - a = (self._lower - self._mean_value) / self._std_dev - b = (self._upper - self._mean_value) / self._std_dev - return scipy.stats.truncnorm.rvs( - a, b, loc=self._mean_value, scale=self._std_dev, - size=n_samples, random_state=rng - ) - - def evaluate(self, x): - """Evaluate PDF at x, returning normalized value for truncated dist.""" - x = np.asarray(x) - f = scipy.stats.norm.pdf(x, self.mean_value, self.std_dev) - if self._is_truncated: - # PDF is zero outside bounds - in_bounds = (x >= self._lower) & (x <= self._upper) - f = np.where(in_bounds, f * self._norm_factor, 0.0) - return f - - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the Normal distribution Parameters @@ -1202,27 +689,22 @@ class Normal(Univariate): Returns ------- - element : lxml.etree._Element - XML element containing Normal distribution data + element : xml.etree.ElementTree.Element + XML element containing Watt distribution data """ element = ET.Element(element_name) element.set("type", "normal") - if self._is_truncated: - element.set("parameters", - f'{self.mean_value} {self.std_dev} {self.lower} {self.upper}') - else: - element.set("parameters", f'{self.mean_value} {self.std_dev}') - self._append_bias_to_xml(element) + element.set("parameters", '{} {}'.format(self.mean_value, self.std_dev)) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate Normal distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1231,187 +713,123 @@ class Normal(Univariate): Normal distribution generated from XML element """ - params = get_elem_list(elem, "parameters", float) - bias_dist = cls._read_bias_from_xml(elem) - if len(params) == 4: - return cls(params[0], params[1], params[2], params[3], bias=bias_dist) - else: - return cls(params[0], params[1], bias=bias_dist) + params = get_text(elem, 'parameters').split() + return cls(*map(float, params)) -def muir(e0: float, m_rat: float, kt: float, bias: Univariate | None = None): - """Generate a Muir energy spectrum +class Muir(Univariate): + """Muir energy spectrum. - The Muir energy spectrum is a normal distribution, but for convenience - reasons allows the user to specify three parameters to define the - distribution: the mean energy of particles ``e0``, the mass of reactants - ``m_rat``, and the ion temperature ``kt``. - - .. versionadded:: 0.13.2 + The Muir energy spectrum is a Gaussian spectrum, but for + convenience reasons allows the user 3 parameters to define + the distribution, e0 the mean energy of particles, the mass + of reactants m_rat, and the ion temperature kt. Parameters ---------- e0 : float - Mean of the Muir distribution in [eV] + Mean of the Muir distribution in units of eV m_rat : float - Ratio of the sum of the masses of the reaction inputs to 1 amu + Ratio of the sum of the masses of the reaction inputs to an + AMU kt : float - Ion temperature for the Muir distribution in [eV] - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. + Ion temperature for the Muir distribution in units of eV - Returns - ------- - openmc.stats.Normal - Corresponding normal distribution - - """ - # https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-05411-MS - std_dev = sqrt(2 * e0 * kt / m_rat) - return Normal(e0, std_dev, bias=bias) - - -# Retain deprecated name for the time being -def Muir(*args, **kwargs): - # warn of name change - warn( - "The Muir(...) class has been replaced by the muir(...) function and " - "will be removed in a future version of OpenMC. Use muir(...) instead.", - FutureWarning - ) - return muir(*args, **kwargs) - - -def fusion_neutron_spectrum( - ion_temp: float, - reactants: str = 'DD', - bias: Univariate | None = None -) -> Normal: - r"""Return a Gaussian energy distribution for fusion neutron emission. - - Computes the mean energy and spectral width of the neutron energy spectrum - from thermonuclear fusion reactions in a plasma with Maxwellian ion velocity - distributions. The mean neutron energy is calculated as - - .. math:: - - \langle E_n \rangle = E_0 + \Delta E_\text{th} - - where :math:`E_0` is the neutron energy at zero ion temperature and - :math:`\Delta E_\text{th}` is the thermal peak shift due to the motion of - the reacting ions. The spectral width is characterized by the FWHM: - - .. math:: - - W_{1/2} = \omega_0 (1 + \delta_\omega) \sqrt{T_i} - - where :math:`\omega_0` is the width at the :math:`T_i \to 0` limit and - :math:`\delta_\omega` is a temperature-dependent correction term. Both - :math:`\Delta E_\text{th}` and :math:`\delta_\omega` are evaluated using - interpolation formulas from `Ballabio et al. - `_: Table III for :math:`0 < - T_i \le 40` keV and Table IV for :math:`40 < T_i < 100` keV. The returned - distribution is a normal (Gaussian) approximation to the spectrum. - - .. versionadded:: 0.15.4 - - Parameters + Attributes ---------- - ion_temp : float - Ion temperature of the plasma in [eV]. - reactants : {'DD', 'DT'} - Fusion reactants. 'DD' corresponds to the D(d,n)\ :sup:`3`\ He reaction - and 'DT' to the T(d,n)\ :math:`\alpha` reaction. - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. - - Returns - ------- - openmc.stats.Normal - Normal distribution with mean and standard deviation corresponding to - the first and second moments of the fusion neutron energy spectrum. Both - the mean and standard deviation are in [eV]. + e0 : float + Mean of the Muir distribution in units of eV + m_rat : float + Ratio of the sum of the masses of the reaction inputs to an + AMU + kt : float + Ion temperature for the Muir distribution in units of eV """ - if ion_temp < 0.0 or ion_temp > 100e3: - raise ValueError("Ion temperature must be between 0 and 100 keV.") - # Formulas from doi:10.1088/0029-5515/38/11/310 - mn = NEUTRON_MASS - md = atomic_mass('H2') - ev_per_c2 = 931.49410372*1e6 - if reactants == 'DD': - mhe3 = atomic_mass('He3') - Q = (md + md - mhe3 - mn)*ev_per_c2 - E_n = mhe3/(mhe3 + mn)*Q - w0 = 82.542 + def __init__(self, e0=14.08e6, m_rat = 5., kt = 20000.): + self.e0 = e0 + self.m_rat = m_rat + self.kt = kt - # Low-T constants for peak shift (Table III) - a1 = 4.69515 - a2 = -0.040729 - a3 = 0.47 - a4 = 0.81844 + def __len__(self): + return 3 - # Low-T constants for width correction (Table III) - b1 = 1.7013e-3 - b2 = 0.16888 - b3 = 0.49 - b4 = 7.9460e-4 + @property + def e0(self): + return self._e0 - # High-T constants for peak shift (Table IV) - a5 = 18.225 - a6 = 2.1525 + @property + def m_rat(self): + return self._m_rat - # High-T constants for width correction (Table IV) - b5 = 8.4619e-3 - b6 = 8.3241e-4 + @property + def kt(self): + return self._kt - elif reactants == 'DT': - mt = atomic_mass('H3') - ma = atomic_mass('He4') - Q = (md + mt - ma - mn)*ev_per_c2 - E_n = ma/(ma + mn)*Q - w0 = 177.259 + @e0.setter + def e0(self, e0): + cv.check_type('Muir e0', e0, Real) + cv.check_greater_than('Muir e0', e0, 0.0) + self._e0 = e0 - # Low-T constants for peak shift (Table III) - a1 = 5.30509 - a2 = 2.4736e-3 - a3 = 1.84 - a4 = 1.3818 + @m_rat.setter + def m_rat(self, m_rat): + cv.check_type('Muir m_rat', m_rat, Real) + cv.check_greater_than('Muir m_rat', m_rat, 0.0) + self._m_rat = m_rat - # Low-T constants for width correction (Table III) - b1 = 5.1068e-4 - b2 = 7.6223e-3 - b3 = 1.78 - b4 = 8.7691e-5 + @kt.setter + def kt(self, kt): + cv.check_type('Muir kt', kt, Real) + cv.check_greater_than('Muir kt', kt, 0.0) + self._kt = kt - # High-T constants for peak shift (Table IV) - a5 = 37.771 - a6 = 0.92181 + @property + def std_dev(self): + return np.sqrt(4.*self.e0*self.kt/self.m_rat) - # High-T constants for width correction (Table IV) - b5 = 2.0199e-3 - b6 = 5.9501e-5 - else: - raise ValueError("Invalid reactants specified. Must be 'DD' or 'DT'.") + def sample(self, n_samples=1, seed=None): + # Based on LANL report LA-05411-MS + np.random.seed(seed) + return np.random.normal(self.e0, self.std_dev, n_samples) - # Ion temperature in keV - T = ion_temp * 1e-3 + def to_xml_element(self, element_name): + """Return XML representation of the Watt distribution - if T <= 40.0: - # Low-temperature interpolation (Table III, 0 < T_i <= 40 keV) - Delta_E = a1/(1 + a2*T**a3)*T**(2/3) + a4*T - delta_w = b1/(1 + b2*T**b3)*T**(2/3) + b4*T - else: - # High-temperature interpolation (Table IV, 40 < T_i < 100 keV) - Delta_E = a5 + a6*T - delta_w = b5 + b6*T + Parameters + ---------- + element_name : str + XML element name - # Calculate FWHM - fwhm = (w0*(1 + delta_w) * sqrt(T))*1e3 + Returns + ------- + element : xml.etree.ElementTree.Element + XML element containing Watt distribution data - sigma = fwhm / (2*sqrt(2*log(2))) - return Normal(E_n + Delta_E * 1e3, sigma, bias=bias) + """ + element = ET.Element(element_name) + element.set("type", "muir") + element.set("parameters", '{} {} {}'.format(self._e0, self._m_rat, self._kt)) + return element + + @classmethod + def from_xml_element(cls, elem): + """Generate Muir distribution from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.stats.Muir + Muir distribution generated from XML element + + """ + params = get_text(elem, 'parameters').split() + return cls(*map(float, params)) class Tabular(Univariate): @@ -1426,16 +844,12 @@ class Tabular(Univariate): x : Iterable of float Tabulated values of the random variable p : Iterable of float - Tabulated probabilities. For histogram interpolation, if the length of - `p` is the same as `x`, the last value is ignored. Probabilities `p` are - given per unit of `x`. + Tabulated probabilities interpolation : {'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'}, optional - Indicates how the density function is interpolated between tabulated - points. Defaults to 'linear-linear'. + Indicate whether the density function is constant between tabulated + points or linearly-interpolated. Defaults to 'linear-linear'. ignore_negative : bool Ignore negative probabilities - bias : openmc.stats.Univariate, optional - Distribution for biased sampling. Attributes ---------- @@ -1443,58 +857,21 @@ class Tabular(Univariate): Tabulated values of the random variable p : numpy.ndarray Tabulated probabilities - interpolation : {'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'} - Indicates how the density function is interpolated between tabulated - points. Defaults to 'linear-linear'. - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling - - Notes - ----- - The probabilities `p` are interpreted per unit of the corresponding - independent variable `x`. This follows the definition of a probability - density function (PDF) in probability theory, where the PDF represents the - relative likelihood of the random variable taking on a particular value per - unit of the variable. For example, if `x` represents energy in eV, then `p` - should represent probabilities per eV. + interpolation : {'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'}, optional + Indicate whether the density function is constant between tabulated + points or linearly-interpolated. """ - def __init__( - self, - x: Sequence[float], - p: Sequence[float], - interpolation: str = 'linear-linear', - ignore_negative: bool = False, - bias: Univariate | None = None - ): + def __init__(self, x, p, interpolation='linear-linear', + ignore_negative=False): + self._ignore_negative = ignore_negative + self.x = x + self.p = p self.interpolation = interpolation - cv.check_type('tabulated values', x, Iterable, Real) - cv.check_type('tabulated probabilities', p, Iterable, Real) - - x = np.array(x, dtype=float) - p = np.array(p, dtype=float) - - if p.size > x.size: - raise ValueError('Number of probabilities exceeds number of table values.') - if self.interpolation != 'histogram' and x.size != p.size: - raise ValueError(f'Tabulated values ({x.size}) and probabilities ' - f'({p.size}) should have the same length') - - if not ignore_negative: - for pk in p: - cv.check_greater_than('tabulated probability', pk, 0.0, True) - - self._x = x - self._p = p - super().__init__(bias) - def __len__(self): - return self.p.size + return len(self.x) @property def x(self): @@ -1508,91 +885,80 @@ class Tabular(Univariate): def interpolation(self): return self._interpolation + @x.setter + def x(self, x): + cv.check_type('tabulated values', x, Iterable, Real) + self._x = np.array(x, dtype=float) + + @p.setter + def p(self, p): + cv.check_type('tabulated probabilities', p, Iterable, Real) + if not self._ignore_negative: + for pk in p: + cv.check_greater_than('tabulated probability', pk, 0.0, True) + self._p = np.array(p, dtype=float) + @interpolation.setter def interpolation(self, interpolation): cv.check_value('interpolation', interpolation, _INTERPOLATION_SCHEMES) self._interpolation = interpolation - @property - def support(self): - return (self._x[0], self._x[-1]) - def cdf(self): + if not self.interpolation in ('histogram', 'linear-linear'): + raise NotImplementedError('Can only generate CDFs for tabular ' + 'distributions using histogram or ' + 'linear-linear interpolation') c = np.zeros_like(self.x) x = self.x p = self.p if self.interpolation == 'histogram': - c[1:] = p[:x.size-1] * np.diff(x) + c[1:] = p[:-1] * np.diff(x) elif self.interpolation == 'linear-linear': c[1:] = 0.5 * (p[:-1] + p[1:]) * np.diff(x) - elif self.interpolation == "linear-log": - m = np.diff(p) / np.diff(np.log(x)) - c[1:] = p[:-1] * np.diff(x) + m * ( - x[1:] * (np.diff(np.log(x)) - 1.0) + x[:-1] - ) - elif self.interpolation == "log-linear": - m = np.diff(np.log(p)) / np.diff(x) - c[1:] = p[:-1] * np.diff(x) * exprel(m * np.diff(x)) - elif self.interpolation == "log-log": - m = np.diff(np.log(x * p)) / np.diff(np.log(x)) - c[1:] = (x * p)[:-1] * np.diff(np.log(x)) * exprel(m * np.diff(np.log(x))) - else: - raise NotImplementedError( - f"Cannot generate CDFs for tabular " - f"distributions using {self.interpolation} interpolation" - ) return np.cumsum(c) def mean(self): """Compute the mean of the tabular distribution""" + if not self.interpolation in ('histogram', 'linear-linear'): + raise NotImplementedError('Can only compute mean for tabular ' + 'distributions using histogram ' + 'or linear-linear interpolation.') + if self.interpolation == 'linear-linear': + mean = 0.0 + self.normalize() + for i in range(1, len(self.x)): + y_min = self.p[i-1] + y_max = self.p[i] + x_min = self.x[i-1] + x_max = self.x[i] - # use normalized probabilities when computing mean - p = self.p / self.cdf().max() - x = self.x - x_min = x[:-1] - x_max = x[1:] - p_min = p[: x.size - 1] + m = (y_max - y_min) / (x_max - x_min) + + exp_val = (1./3.) * m * (x_max**3 - x_min**3) + exp_val += 0.5 * m * x_min * (x_min**2 - x_max**2) + exp_val += 0.5 * y_min * (x_max**2 - x_min**2) + mean += exp_val + + elif self.interpolation == 'histogram': + mean = 0.5 * (self.x[:-1] + self.x[1:]) + mean *= np.diff(self.cdf()) + mean = sum(mean) - if self.interpolation == "linear-linear": - m = np.diff(p) / np.diff(x) - mean = ((1.0 / 3.0) * m * np.diff(x**3) - + 0.5 * (p_min - m * x_min) * np.diff(x**2)).sum() - elif self.interpolation == "linear-log": - m = np.diff(p) / np.diff(np.log(x)) - mean = ( - (1.0 / 4.0) * m * x_min**2 - * ((x_max / x_min)**2 * (2 * np.diff(np.log(x)) - 1) + 1) - + 0.5 * p_min * np.diff(x**2) - ).sum() - elif self.interpolation == "log-linear": - m = np.diff(np.log(p)) / np.diff(x) - mean = (p_min * ( - np.diff(x) ** 2 - * ((0.5 * exprel2(m * np.diff(x)) * (m * np.diff(x) - 1) + 1)) - + np.diff(x) * x_min * exprel(m * np.diff(x))) - ).sum() - elif self.interpolation == "log-log": - m = np.diff(np.log(p)) / np.diff(np.log(x)) - mean = (p_min * x_min**2 * np.diff(np.log(x)) - * exprel((m + 2) * np.diff(np.log(x)))).sum() - elif self.interpolation == "histogram": - mean = (0.5 * (x_min + x_max) * np.diff(x) * p_min).sum() - else: - raise NotImplementedError( - f"Cannot compute mean for tabular " - f"distributions using {self.interpolation} interpolation" - ) return mean def normalize(self): """Normalize the probabilities stored on the distribution""" - self._p /= self.cdf().max() + self.p /= self.cdf().max() - def _sample_unbiased(self, n_samples: int = 1, seed: int | None = None): - rng = np.random.RandomState(seed) - xi = rng.random(n_samples) + def sample(self, n_samples=1, seed=None): + if not self.interpolation in ('histogram', 'linear-linear'): + raise NotImplementedError('Can only sample tabular distributions ' + 'using histogram or ' + 'linear-linear interpolation') + np.random.seed(seed) + xi = np.random.rand(n_samples) # always use normalized probabilities when sampling cdf = self.cdf() @@ -1642,94 +1008,11 @@ class Tabular(Univariate): quad[quad < 0.0] = 0.0 m[non_zero] = x_i[non_zero] + (np.sqrt(quad) - p_i[non_zero]) / m[non_zero] samples_out = m - elif self.interpolation == "linear-log": - # get variable and probability values for the - # next entry - x_i1 = self.x[cdf_idx + 1] - p_i1 = p[cdf_idx + 1] - # compute slope between entries - m = (p_i1 - p_i) / np.log(x_i1 / x_i) - # set values for zero slope - zero = m == 0.0 - m[zero] = x_i[zero] + (xi[zero] - c_i[zero]) / p_i[zero] - - positive = m > 0 - negative = m < 0 - a = p_i / m - 1 - m[positive] = ( - x_i - * ((xi - c_i) / (m * x_i) + a) - / np.real(lambertw((((xi - c_i) / (m * x_i) + a)) * np.exp(a))) - )[positive] - m[negative] = ( - x_i - * ((xi - c_i) / (m * x_i) + a) - / np.real(lambertw((((xi - c_i) / (m * x_i) + a)) * np.exp(a), -1.0)) - )[negative] - samples_out = m - elif self.interpolation == "log-linear": - # get variable and probability values for the - # next entry - x_i1 = self.x[cdf_idx + 1] - p_i1 = p[cdf_idx + 1] - # compute slope between entries - m = np.log(p_i1 / p_i) / (x_i1 - x_i) - f = (xi - c_i) / p_i - - samples_out = x_i + f * log1prel(m * f) - elif self.interpolation == "log-log": - # get variable and probability values for the - # next entry - x_i1 = self.x[cdf_idx + 1] - p_i1 = p[cdf_idx + 1] - # compute slope between entries - m = np.log((x_i1 * p_i1) / (x_i * p_i)) / np.log(x_i1 / x_i) - f = (xi - c_i) / (x_i * p_i) - - samples_out = x_i * np.exp(f * log1prel(m * f)) - else: - raise NotImplementedError( - f"Cannot sample tabular distributions " - f"for {self.inteprolation} interpolation " - ) assert all(samples_out < self.x[-1]) return samples_out - def sample(self, n_samples: int = 1, seed: int | None = None): - if self.bias is None: - samples = self._sample_unbiased(n_samples, seed) - return samples, np.ones_like(samples) - else: - if self.bias.bias is not None: - raise RuntimeError('Biasing distributions should not have their own bias.') - biased_sample, _ = self.bias.sample(n_samples=n_samples, seed=seed) - self.normalize() # must have normalized probabilities to apply correct weights - wgt = np.array([self.evaluate(s) / self.bias.evaluate(s) for s in biased_sample]) - return biased_sample, wgt - - def evaluate(self, x): - if self.interpolation == 'linear-linear': - i = np.searchsorted(self.x, x, side='left') - 1 - if i < 0 or i >= len(self.p) - 1: - return 0.0 - x0, x1 = self.x[i], self.x[i + 1] - p0, p1 = self.p[i], self.p[i + 1] - t = (x - x0) / (x1 - x0) - return (1 - t) * p0 + t * p1 - - elif self.interpolation == 'histogram': - i = np.searchsorted(self.x, x, side='right') - 1 - if i < 0 or i >= len(self.p): - return 0.0 - return self.p[i] - - else: - raise NotImplementedError('Can only evaluate tabular ' - 'distributions using histogram ' - 'or linear-linear interpolation.') - - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the tabular distribution Parameters @@ -1739,7 +1022,7 @@ class Tabular(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing tabular distribution data """ @@ -1749,16 +1032,16 @@ class Tabular(Univariate): params = ET.SubElement(element, "parameters") params.text = ' '.join(map(str, self.x)) + ' ' + ' '.join(map(str, self.p)) - self._append_bias_to_xml(element) + return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate tabular distribution from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1768,12 +1051,10 @@ class Tabular(Univariate): """ interpolation = get_text(elem, 'interpolation') - params = get_elem_list(elem, "parameters", float) - m = (len(params) + 1)//2 # +1 for when len(params) is odd - x = params[:m] - p = params[m:] - bias_dist = cls._read_bias_from_xml(elem) - return cls(x, p, interpolation, bias=bias_dist) + params = [float(x) for x in get_text(elem, 'parameters').split()] + x = params[:len(params)//2] + p = params[len(params)//2:] + return cls(x, p, interpolation) def integral(self): """Return integral of distribution @@ -1786,25 +1067,12 @@ class Tabular(Univariate): Integral of tabular distrbution """ if self.interpolation == 'histogram': - return np.sum(np.diff(self.x) * self.p[:self.x.size-1]) + return np.sum(np.diff(self.x) * self.p[:-1]) elif self.interpolation == 'linear-linear': - return trapezoid(self.p, self.x) - elif self.interpolation == "linear-log": - m = np.diff(self.p) / np.diff(np.log(self.x)) - return np.sum( - self.p[:-1] * np.diff(self.x) - + m * (self.x[1:] * (np.diff(np.log(self.x)) - 1.0) + self.x[:-1]) - ) - elif self.interpolation == "log-linear": - m = np.diff(np.log(self.p)) / np.diff(self.x) - return np.sum(self.p[:-1] * np.diff(self.x) * exprel(m * np.diff(self.x))) - elif self.interpolation == "log-log": - m = np.diff(np.log(self.p)) / np.diff(np.log(self.x)) - return np.sum(self.p[:-1] * self.x[:-1] * np.diff(np.log(self.x)) - * exprel((m + 1) * np.diff(np.log(self.x)))) + return np.trapz(self.p, self.x) else: raise NotImplementedError( - f'integral() not supported for {self.interpolation} interpolation') + f'integral() not supported for {self.inteprolation} interpolation') class Legendre(Univariate): @@ -1816,24 +1084,16 @@ class Legendre(Univariate): coefficients : Iterable of Real Expansion coefficients :math:`a_\ell`. Note that the :math:`(2\ell + 1)/2` factor should not be included. - bias : openmc.stats.Univariate or None, optional - Distribution for biased sampling. Attributes ---------- coefficients : Iterable of Real Expansion coefficients :math:`a_\ell`. Note that the :math:`(2\ell + 1)/2` factor should not be included. - support : tuple of float - A 2-tuple (lower, upper) defining the interval over which the - distribution is nonzero-valued - bias : openmc.stats.Univariate or None - Distribution for biased sampling """ - def __init__(self, coefficients: Sequence[float], bias: Univariate | None = None): - super().__init__(bias) + def __init__(self, coefficients): self.coefficients = coefficients self._legendre_poly = None @@ -1857,19 +1117,9 @@ class Legendre(Univariate): def coefficients(self, coefficients): self._coefficients = np.asarray(coefficients) - @property - def support(self): - raise NotImplementedError - - def _sample_unbiased(self, n_samples=1, seed=None): - raise NotImplementedError - def sample(self, n_samples=1, seed=None): raise NotImplementedError - def evaluate(self, x): - raise NotImplementedError - def to_xml_element(self, element_name): raise NotImplementedError @@ -1887,9 +1137,6 @@ class Mixture(Univariate): Probability of selecting a particular distribution distribution : Iterable of Univariate List of distributions with corresponding probabilities - bias : Iterable of Real, optional - Probability of selecting a particular distribution under biased - sampling Attributes ---------- @@ -1897,20 +1144,10 @@ class Mixture(Univariate): Probability of selecting a particular distribution distribution : Iterable of Univariate List of distributions with corresponding probabilities - support : dict - Dictionary containing discrete and continuous parts of the support - bias : numpy.ndarray or None - Probability of selecting each distribution under biased sampling """ - def __init__( - self, - probability: Sequence[float], - distribution: Sequence[Univariate], - bias: Sequence[float] | None = None - ): - super().__init__(bias) + def __init__(self, probability, distribution): self.probability = probability self.distribution = distribution @@ -1921,6 +1158,10 @@ class Mixture(Univariate): def probability(self): return self._probability + @property + def distribution(self): + return self._distribution + @probability.setter def probability(self, probability): cv.check_type('mixture distribution probabilities', probability, @@ -1928,11 +1169,7 @@ class Mixture(Univariate): for p in probability: cv.check_greater_than('mixture distribution probabilities', p, 0.0, True) - self._probability = np.array(probability, dtype=float) - - @property - def distribution(self): - return self._distribution + self._probability = probability @distribution.setter def distribution(self, distribution): @@ -1940,53 +1177,11 @@ class Mixture(Univariate): Iterable, Univariate) self._distribution = distribution - @Univariate.bias.setter - def bias(self, bias): - if bias is None: - self._bias = bias - else: - cv.check_type('biased mixture distribution probabilities', bias, - Iterable, Real) - for b in bias: - cv.check_greater_than('biased mixture distribution probabilities', - b, 0.0, True) - self._bias = np.array(bias, dtype=float) - - @property - def support(self): - discrete_points = set() - intervals = [] - - for dist in self.distribution: - if isinstance(dist, Discrete): - discrete_points |= dist.support - else: - intervals.append(tuple(dist.support)) - - if intervals: - # simplify union by combining intervals when able - sorted_intervals = sorted(intervals, key=lambda x: x[0]) - merged = [sorted_intervals[0]] - - for current in sorted_intervals[1:]: - prev_start, prev_end = merged[-1] - curr_start, curr_end = current - - if curr_start <= prev_end: - merged[-1] = (prev_start, max(prev_end, curr_end)) - else: - merged.append(current) - - intervals = merged - - return {"discrete": discrete_points, "continuous": intervals} - def cdf(self): return np.insert(np.cumsum(self.probability), 0, 0.0) - def _sample_unbiased(self, n_samples=1, seed=None): - # Mixture uses internal bias mechanism, not base class bias - rng = np.random.RandomState(seed) + def sample(self, n_samples=1, seed=None): + np.random.seed(seed) # Get probability of each distribution accounting for its intensity p = np.array([prob*dist.integral() for prob, dist in @@ -1994,60 +1189,23 @@ class Mixture(Univariate): p /= p.sum() # Sample from the distributions - idx = rng.choice(range(len(self.distribution)), n_samples, p=p) + idx = np.random.choice(range(len(self.distribution)), + n_samples, p=p) # Draw samples from the distributions sampled above out = np.empty_like(idx, dtype=float) - out_wgt = np.empty_like(idx, dtype=float) for i in np.unique(idx): n_dist_samples = np.count_nonzero(idx == i) - samples, weights = self.distribution[i].sample(n_dist_samples) + samples = self.distribution[i].sample(n_dist_samples) out[idx == i] = samples - out_wgt[idx == i] = weights - return out, out_wgt - - def sample(self, n_samples=1, seed=None): - # Mixture uses internal bias mechanism, not base class bias - if self.bias is None: - return self._sample_unbiased(n_samples, seed) - - rng = np.random.RandomState(seed) - - # Get probability of each distribution accounting for its intensity - p = np.array([prob*dist.integral() for prob, dist in - zip(self.probability, self.distribution)]) - p /= p.sum() - - b = np.array([prob*dist.integral() for prob, dist in - zip(self.bias, self.distribution)]) - b /= b.sum() - - # Sample from the distributions using biased probabilities - idx = rng.choice(range(len(self.distribution)), n_samples, p=b) - idx_wgt = np.ones(n_samples) - for i in np.unique(idx): - idx_wgt[idx == i] = p[i]/b[i] - - # Draw samples from the distributions sampled above - out = np.empty_like(idx, dtype=float) - out_wgt = np.empty_like(idx, dtype=float) - for i in np.unique(idx): - n_dist_samples = np.count_nonzero(idx == i) - samples, weights = self.distribution[i].sample(n_dist_samples) - out[idx == i] = samples - out_wgt[idx == i] = weights * idx_wgt[idx == i] - return out, out_wgt - - def evaluate(self, x): - raise NotImplementedError( - "evaluate() is undefined for Mixture distributions") + return out def normalize(self): """Normalize the probabilities stored on the distribution""" norm = sum(self.probability) self.probability = [val / norm for val in self.probability] - def to_xml_element(self, element_name: str): + def to_xml_element(self, element_name): """Return XML representation of the mixture distribution .. versionadded:: 0.13.0 @@ -2059,7 +1217,7 @@ class Mixture(Univariate): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing mixture distribution data """ @@ -2071,18 +1229,17 @@ class Mixture(Univariate): data.set("probability", str(p)) data.append(d.to_xml_element("dist")) - self._append_array_bias_to_xml(element) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate mixture distribution from an XML element .. versionadded:: 0.13.0 Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -2097,8 +1254,7 @@ class Mixture(Univariate): probability.append(float(get_text(pair, 'probability'))) distribution.append(Univariate.from_xml_element(pair.find("dist"))) - bias_dist = cls._read_array_bias_from_xml(elem) - return cls(probability, distribution, bias=bias_dist) + return cls(probability, distribution) def integral(self): """Return integral of the distribution @@ -2115,507 +1271,52 @@ class Mixture(Univariate): for p, dist in zip(self.probability, self.distribution) ]) - def mean(self) -> float: - """Return mean of the mixture distribution - The mean is the weighted average of the means of the component - distributions, weighted by probability * integral. - - .. versionadded:: 0.15.3 - - Returns - ------- - float - Mean of the mixture distribution - """ - # Weight each component by its probability and integral - weights = [p*dist.integral() for p, dist in - zip(self.probability, self.distribution)] - total_weight = sum(weights) - - if total_weight == 0: - return 0.0 - - return sum([w*dist.mean() for w, dist in - zip(weights, self.distribution)]) / total_weight - - def clip(self, tolerance: float = 1e-6, inplace: bool = False) -> Mixture: - r"""Remove low-importance points / distributions - - Like :meth:`Discrete.clip`, this method will remove low-importance - points from discrete distributions contained within the mixture but it - will also clip any distributions that have negligible contributions to - the overall intensity. - - .. versionadded:: 0.14.0 - - Parameters - ---------- - tolerance : float - Maximum fraction of intensities that will be discarded. - inplace : bool - Whether to modify the current object in-place or return a new one. - - Returns - ------- - Distribution with low-importance points / distributions removed - - """ - # Calculate mean * integral for original distribution to compare later. - original_mean_integral = self.mean() * self.integral() - - # Determine indices for any distributions that contribute non-negligibly - # to overall mean * integral - mean_integrals = [prob*dist.mean()*dist.integral() for prob, dist in - zip(self.probability, self.distribution)] - indices = _intensity_clip(mean_integrals, tolerance=tolerance) - - # Clip mixture of distributions - probability = self.probability[indices] - distribution = [self.distribution[i] for i in indices] - - # Clip points from Discrete distributions - distribution = [ - dist.clip(tolerance, inplace) if isinstance(dist, Discrete) else dist - for dist in distribution - ] - - if inplace: - # Set attributes of current object and return - self.probability = probability - self.distribution = distribution - new_dist = self - else: - # Create new distribution - new_dist = type(self)(probability, distribution) - - # Show warning if mean * integral of new distribution is not within - # tolerance of original. For energy distributions, mean * integral - # represents total energy. - new_mean_integral = new_dist.mean() * new_dist.integral() - diff = (original_mean_integral - new_mean_integral)/original_mean_integral - if diff > tolerance: - warn("Clipping mixture distribution resulted in a mean*integral " - f"that is lower by a fraction of {diff} when tolerance={tolerance}.") - - return new_dist - - -class DecaySpectrum(Univariate): - """Energy distribution from decay photon spectra of a mixture of nuclides. - - This distribution stores nuclide names, their atom densities, and the volume - of the region. When written to XML and read by the C++ solver, the nuclide - names are resolved against the depletion chain to obtain the decay photon - energy spectra and decay constants. The resulting distribution is a mixture - of per-nuclide photon spectra weighted by absolute activity. The volume is - necessary so that the C++ solver can compute the total photon emission rate - in [photons/s], which is used as the source strength. - - .. versionadded:: 0.15.4 - - Parameters - ---------- - nuclides : dict - Dictionary mapping nuclide name (str) to atom density (float) in units - of [atom/b-cm]. - volume : float - Volume of the source region in [cm³]. Used together with atom densities - to compute the absolute photon emission rate. - - Attributes - ---------- - nuclides : dict - Dictionary mapping nuclide name to atom density in [atom/b-cm]. - volume : float - Volume of the source region in [cm³]. - - """ - - def __init__(self, nuclides: dict[str, float], volume: float): - super().__init__(bias=None) - self._dist_cache = None - self._dist_cache_key = None - self.nuclides = nuclides - self.volume = volume - - def __len__(self): - return len(self.nuclides) - - @property - def nuclides(self): - return self._nuclides - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_type('nuclides', nuclides, dict) - for name, density in nuclides.items(): - cv.check_type('nuclide name', name, str) - cv.check_type(f'atom density for {name}', density, Real) - cv.check_greater_than(f'atom density for {name}', density, 0.0, True) - self._nuclides = dict(nuclides) - self._dist_cache = None - self._dist_cache_key = None - - @property - def volume(self): - return self._volume - - @volume.setter - def volume(self, volume): - cv.check_type('volume', volume, Real) - cv.check_greater_than('volume', volume, 0.0) - self._volume = float(volume) - self._dist_cache = None - self._dist_cache_key = None - - @staticmethod - def _chain_file_cache_key(): - """Return a hashable key for the active depletion chain.""" - chain_file = openmc.config.get('chain_file') - if chain_file is None: - return None - - path = Path(chain_file).resolve() - try: - stat = path.stat() - except OSError: - return (path, None, None) - return (path, stat.st_mtime, stat.st_size) - - def to_distribution(self): - """Convert to a concrete distribution using decay chain data. - - Builds a combined photon energy distribution by looking up each nuclide - in the depletion chain via :func:`openmc.data.decay_photon_energy` and - weighting by absolute atom count (``density * 1e24 * volume``). The - result is cached on the object; the cache is invalidated automatically - when :attr:`nuclides` or :attr:`volume` are reassigned. - - Requires ``openmc.config['chain_file']`` to be set. - - Returns - ------- - openmc.stats.Univariate or None - Combined photon energy distribution, or ``None`` if no nuclide in - :attr:`nuclides` has a photon source in the chain. - - """ - chain_key = self._chain_file_cache_key() - if self._dist_cache is not None and self._dist_cache_key == chain_key: - return self._dist_cache - - dists = [] - weights = [] - for name, density in self.nuclides.items(): - dist = openmc.data.decay_photon_energy(name) - if dist is not None: - dists.append(dist) - weights.append(density * 1e24 * self.volume) - - if not dists: - return None - - self._dist_cache = combine_distributions(dists, weights) - self._dist_cache_key = chain_key - return self._dist_cache - - def to_xml_element(self, element_name: str): - """Return XML representation of the decay photon distribution - - Parameters - ---------- - element_name : str - XML element name - - Returns - ------- - element : lxml.etree._Element - XML element containing decay photon distribution data - - """ - element = ET.Element(element_name) - element.set("type", "decay_spectrum") - element.set("volume", str(self.volume)) - nuclides = ET.SubElement(element, "nuclides") - nuclides.text = ' '.join(self.nuclides) - parameters = ET.SubElement(element, "parameters") - parameters.text = ' '.join(str(density) for density in self.nuclides.values()) - return element - - @classmethod - def from_xml_element(cls, elem: ET.Element): - """Generate decay photon distribution from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - - Returns - ------- - openmc.stats.DecaySpectrum - Decay photon distribution generated from XML element - - """ - volume = float(elem.get('volume')) - names = get_elem_list(elem, 'nuclides', str) - densities = get_elem_list(elem, 'parameters', float) - nuclides = dict(zip(names, densities)) - return cls(nuclides, volume) - - def _sample_unbiased(self, n_samples=1, seed=None): - dist = self.to_distribution() - if dist is None: - raise RuntimeError( - "DecaySpectrum._sample_unbiased requires chain data but none " - "was found. Ensure openmc.config['chain_file'] is set and the " - "chain contains photon sources for the nuclides present." - ) - return dist.sample(n_samples, seed)[0] - - def integral(self): - """Return integral of the distribution - - Returns the total photon emission rate in [photons/s] by delegating to - :meth:`to_distribution`. Returns ``0.0`` when no chain data is - available (e.g., ``openmc.config['chain_file']`` is not set). - - Returns - ------- - float - Total photon emission rate in [photons/s], or ``0.0`` if chain - data is unavailable. - """ - try: - dist = self.to_distribution() - except Exception: - return 0.0 - if dist is None: - return 0.0 - return dist.integral() - - @staticmethod - @cache - def _photon_integral(nuclide: str, chain_key) -> float | None: - """Return the per-atom photon emission integral for a nuclide""" - dist = openmc.data.decay_photon_energy(nuclide) - return dist.integral() if dist is not None else None - - def clip(self, tolerance: float = 1e-9, inplace: bool = False): - """Remove nuclides with negligible contribution to photon emission. - - Nuclides that are stable or have no photon source in the depletion - chain are removed unconditionally. The remaining nuclides are ranked - by their photon emission rate (proportional to - ``atom_density * decay_constant * photon_yield``) and the least - important are discarded until the cumulative discarded fraction of the - total emission rate exceeds *tolerance*. - - Requires ``openmc.config['chain_file']`` to be set. - - Parameters - ---------- - tolerance : float - Maximum fraction of total photon emission rate that may be - discarded. - inplace : bool - Whether to modify the current object in-place or return a new one. - - Returns - ------- - openmc.stats.DecaySpectrum - Distribution with negligible nuclides removed. - - """ - # Compute per-nuclide emission rate; drop non-emitters - emitting_names = [] - emitting_densities = [] - rates = [] - chain_key = self._chain_file_cache_key() - for name, density in self.nuclides.items(): - integral = DecaySpectrum._photon_integral(name, chain_key) - if integral is None: - continue - emitting_names.append(name) - emitting_densities.append(density) - rates.append(density * self.volume * integral) - - if not emitting_names: - new_nuclides = {} - else: - indices = _intensity_clip(rates, tolerance=tolerance) - new_nuclides = { - emitting_names[i]: emitting_densities[i] for i in indices - } - - if inplace: - self._nuclides = new_nuclides - self._dist_cache = None - self._dist_cache_key = None - return self - return type(self)(new_nuclides, self.volume) - - @property - def support(self): - return (0.0, np.inf) - - def evaluate(self, x): - """Evaluate the probability density at a given value. - - Delegates to the combined distribution built from chain data. Raises - ``NotImplementedError`` if the combined distribution is a - :class:`~openmc.stats.Mixture` (which does not support - ``evaluate()``). - - Parameters - ---------- - x : float - Value at which to evaluate the PDF. - - Returns - ------- - float - Probability density at *x*. - """ - dist = self.to_distribution() - if dist is None: - raise RuntimeError( - "DecaySpectrum.evaluate requires chain data. Ensure " - "openmc.config['chain_file'] is set." - ) - return dist.evaluate(x) - - def mean(self): - """Return the mean of the distribution. - - Delegates to the combined distribution built from chain data. - - Returns - ------- - float - Mean photon energy in [eV]. - """ - dist = self.to_distribution() - if dist is None: - raise RuntimeError( - "DecaySpectrum.mean requires chain data. Ensure " - "openmc.config['chain_file'] is set." - ) - return dist.mean() - - -def combine_distributions( - dists: Sequence[Discrete | Tabular | Mixture], - probs: Sequence[float] -): +def combine_distributions(dists, probs): """Combine distributions with specified probabilities This function can be used to combine multiple instances of - :class:`~openmc.stats.Discrete`, :class:`~openmc.stats.Tabular` and - :class:`~openmc.stats.Mixture` of them. Multiple discrete distributions are - merged into a single distribution and the remainder of the distributions are - put into a :class:`~openmc.stats.Mixture` distribution. + :class:`~openmc.stats.Discrete` and `~openmc.stats.Tabular`. Multiple + discrete distributions are merged into a single distribution and the + remainder of the distributions are put into a :class:`~openmc.stats.Mixture` + distribution. .. versionadded:: 0.13.1 Parameters ---------- - dists : sequence of openmc.stats.Discrete, openmc.stats.Tabular, or openmc.stats.Mixture + dists : iterable of openmc.stats.Univariate Distributions to combine - probs : sequence of float + probs : iterable of float Probability (or intensity) of each distribution """ - new_probs = [] - new_dists = [] - for i, dist in enumerate(dists): - cv.check_type(f'dists[{i}]', dist, (Discrete, Tabular, Mixture)) - cv.check_type(f'probs[{i}]', probs[i], Real) - cv.check_greater_than(f'probs[{i}]', probs[i], 0.0) - if isinstance(dist, Mixture): - if dist.bias is not None: - warn("A Mixture distribution with a bias specified was passed " - "to combine_distributions. The bias will be discarded " - "during flattening.") - for j, d in enumerate(dist.distribution): - cv.check_type(f'dists[{i}].distribution[{j}]', d, (Discrete, Tabular)) - new_probs.append(probs[i]*dist.probability[j]) - new_dists.append(d) - else: - new_probs.append(probs[i]) - new_dists.append(dist) - - probs = new_probs - dists = new_dists + # Get copy of distribution list so as not to modify the argument + dist_list = deepcopy(dists) # Get list of discrete/continuous distribution indices - discrete_index = [i for i, d in enumerate(dists) if isinstance(d, Discrete)] - cont_index = [i for i, d in enumerate(dists) if isinstance(d, Tabular)] + discrete_index = [i for i, d in enumerate(dist_list) if isinstance(d, Discrete)] + cont_index = [i for i, d in enumerate(dist_list) if isinstance(d, Tabular)] - cont_dists = [dists[i] for i in cont_index] - cont_probs = [probs[i] for i in cont_index] + # Apply probabilites to continuous distributions + for i in cont_index: + dist = dist_list[i] + dist.p *= probs[i] if discrete_index: # Create combined discrete distribution - dist_discrete = [dists[i] for i in discrete_index] + dist_discrete = [dist_list[i] for i in discrete_index] discrete_probs = [probs[i] for i in discrete_index] combined_dist = Discrete.merge(dist_discrete, discrete_probs) - if cont_index: - return Mixture(cont_probs + [1.0], cont_dists + [combined_dist]) - else: - return combined_dist - else: - if len(cont_dists) == 1: - dist = cont_dists[0] - return Tabular(dist.x, dist.p * cont_probs[0], - dist.interpolation, bias=dist.bias) - else: - return Mixture(cont_probs, cont_dists) + # Replace multiple discrete distributions with merged + for idx in reversed(discrete_index): + dist_list.pop(idx) + dist_list.append(combined_dist) -def check_bias_support(parent: Univariate, bias: Univariate | None): - """Ensure that bias distributions share the support of the univariate - distribution they are biasing. + # Combine discrete and continuous if present + if len(dist_list) > 1: + probs = [1.0]*len(dist_list) + dist_list[:] = [Mixture(probs, dist_list.copy())] - Parameters - ---------- - parent : openmc.stats.Univariate - Distributions to be biased - bias : openmc.stats.Univariate or None - Proposed bias distribution - - """ - if bias is None: - return - - def mismatch_error(err_type, msg): - raise err_type(f"Support of parent {type(parent).__name__} and bias " - f"{type(bias).__name__} distributions do not match. " - f"{msg}") - - p_sup, b_sup = parent.support, bias.support - - if isinstance(p_sup, set) or isinstance(b_sup, set): - raise RuntimeError("Discrete distributions cannot be used as biasing " - "distributions or be biased by another Univariate " - "distribution. Instead, assign a vector of " - "alternate probabilities to the bias attribute.") - - elif isinstance(p_sup, dict) or isinstance (b_sup, dict): - raise RuntimeError("Mixture distributions cannot be used as biasing " - "distributions or be biased by another Univariate " - "distribution. Instead, instantiate the Mixture " - "object using biased member distributions, or " - "assign a vector of alternative probabilities to " - "the bias attribute.") - - elif isinstance(p_sup, tuple): - if isinstance(b_sup, tuple): - if p_sup != b_sup: - mismatch_error(ValueError, "") - else: - mismatch_error(TypeError, "Incompatible support types.") - - else: - raise TypeError("Unrecognized type for parent distribution support") + return dist_list[0] diff --git a/openmc/summary.py b/openmc/summary.py index ca5cfadd7..43224334d 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -127,23 +127,11 @@ class Summary: self._fast_materials[material.id] = material def _read_surfaces(self): - periodic_surface_ids = set() for group in self._f['geometry/surfaces'].values(): surface = openmc.Surface.from_hdf5(group) # surface may be None for DAGMC surfaces if surface: self._fast_surfaces[surface.id] = surface - if surface.boundary_type == "periodic": - periodic_surface_ids.add(surface.id) - - # Assign periodic surfaces when information is in file - for surface_id in periodic_surface_ids: - group = self._f[f'geometry/surfaces/surface {surface_id}'] - surface = self._fast_surfaces[surface_id] - if 'periodic_surface_id' in group: - periodic_surface_id = int(group['periodic_surface_id'][()]) - surface.periodic_surface = self._fast_surfaces[periodic_surface_id] - def _read_cells(self): @@ -252,9 +240,4 @@ class Summary: Results from a stochastic volume calculation """ - if volume_calc.domain_type == "material" and self.materials: - for material in self.materials: - if material.id in volume_calc.volumes: - material.add_volume_information(volume_calc) - else: - self.geometry.add_volume_information(volume_calc) + self.geometry.add_volume_information(volume_calc) diff --git a/openmc/surface.py b/openmc/surface.py index c2afeb613..2996897a4 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,23 +1,20 @@ -from __future__ import annotations from abc import ABC, abstractmethod +from collections import OrderedDict from collections.abc import Iterable from copy import deepcopy import math from numbers import Real +from xml.etree import ElementTree as ET from warnings import warn, catch_warnings, simplefilter -import lxml.etree as ET import numpy as np -from .checkvalue import check_type, check_value, check_length, check_greater_than +from .checkvalue import check_type, check_value, check_length from .mixin import IDManagerMixin, IDWarning from .region import Region, Intersection, Union -from .bounding_box import BoundingBox -from ._xml import get_elem_list, get_text -_BOUNDARY_TYPES = {'transmission', 'vacuum', 'reflective', 'periodic', 'white'} -_ALBEDO_BOUNDARIES = {'reflective', 'periodic', 'white'} +_BOUNDARY_TYPES = ['transmission', 'vacuum', 'reflective', 'periodic', 'white'] _WARNING_UPPER = """\ "{}(...) accepts an argument named '{}', not '{}'. Future versions of OpenMC \ @@ -38,13 +35,10 @@ class SurfaceCoefficient: value : float or str Value of the coefficient (float) or the name of the coefficient that it is equivalent to (str). - positive : bool - Does the surface coefficient must be positive. Defaults to False. """ - def __init__(self, value, positive=False): + def __init__(self, value): self.value = value - self.positive = positive def __get__(self, instance, owner=None): if instance is None: @@ -59,8 +53,6 @@ class SurfaceCoefficient: if isinstance(self.value, Real): raise AttributeError('This coefficient is read-only') check_type(f'{self.value} coefficient', value, Real) - if self.positive: - check_greater_than(f'{self.value} coefficient', value, 0.0) instance._coefficients[self.value] = value @@ -125,26 +117,21 @@ class Surface(IDManagerMixin, ABC): surface_id : int, optional Unique identifier for the surface. If not specified, an identifier will automatically be assigned. - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. Note that only axis-aligned - periodicity is supported around the x-, y-, and z-axes. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. + freely pass through the surface. Note that periodic boundary conditions + can only be applied to x-, y-, and z-planes, and only axis-aligned + periodicity is supported. name : str, optional Name of the surface. If not specified, the name will be the empty string. Attributes ---------- - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -156,17 +143,14 @@ class Surface(IDManagerMixin, ABC): """ - min_id = 1 next_id = 1 used_ids = set() _atol = 1.e-12 - def __init__(self, surface_id=None, boundary_type='transmission', - albedo=1., name=''): + def __init__(self, surface_id=None, boundary_type='transmission', name=''): self.id = surface_id self.name = name self.boundary_type = boundary_type - self.albedo = albedo # A dictionary of the quadratic surface coefficients # Key - coefficient name @@ -181,20 +165,16 @@ class Surface(IDManagerMixin, ABC): def __repr__(self): string = 'Surface\n' - string += '{0: <20}{1}{2}\n'.format('\tID', '=\t', self._id) - string += '{0: <20}{1}{2}\n'.format('\tName', '=\t', self._name) - string += '{0: <20}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <20}{1}{2}\n'.format('\tBoundary', '=\t', - self._boundary_type) - if (self._boundary_type in _ALBEDO_BOUNDARIES and - not math.isclose(self._albedo, 1.0)): - string += '{0: <20}{1}{2}\n'.format('\tBoundary Albedo', '=\t', - self._albedo) + string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) + string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) + string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) + string += '{0: <16}{1}{2}\n'.format('\tBoundary', '=\t', self._boundary_type) - coefficients = '{0: <20}'.format('\tCoefficients') + '\n' + coefficients = '{0: <16}'.format('\tCoefficients') + '\n' for coeff in self._coefficients: - coefficients += f'{coeff: <20}=\t{self._coefficients[coeff]}\n' + coefficients += '{0: <16}{1}{2}\n'.format( + coeff, '=\t', self._coefficients[coeff]) string += coefficients @@ -204,14 +184,6 @@ class Surface(IDManagerMixin, ABC): def name(self): return self._name - @name.setter - def name(self, name): - if name is not None: - check_type('surface name', name, str) - self._name = name - else: - self._name = '' - @property def type(self): return self._type @@ -220,26 +192,24 @@ class Surface(IDManagerMixin, ABC): def boundary_type(self): return self._boundary_type + @property + def coefficients(self): + return self._coefficients + + @name.setter + def name(self, name): + if name is not None: + check_type('surface name', name, str) + self._name = name + else: + self._name = '' + @boundary_type.setter def boundary_type(self, boundary_type): check_type('boundary type', boundary_type, str) check_value('boundary type', boundary_type, _BOUNDARY_TYPES) self._boundary_type = boundary_type - @property - def albedo(self): - return self._albedo - - @albedo.setter - def albedo(self, albedo): - check_type('albedo', albedo, Real) - check_greater_than('albedo', albedo, 0.0) - self._albedo = float(albedo) - - @property - def coefficients(self): - return self._coefficients - def bounding_box(self, side): """Determine an axis-aligned bounding box. @@ -263,7 +233,8 @@ class Surface(IDManagerMixin, ABC): desired half-space """ - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) def clone(self, memo=None): """Create a copy of this surface with a new unique ID. @@ -315,7 +286,7 @@ class Surface(IDManagerMixin, ABC): coeffs = self._get_base_coeffs() coeffs = np.asarray(coeffs) nonzeros = ~np.isclose(coeffs, 0., rtol=0., atol=self._atol) - norm_factor = coeffs[nonzeros][0] + norm_factor = np.abs(coeffs[nonzeros][0]) return tuple([c/norm_factor for c in coeffs]) def is_equal(self, other): @@ -419,7 +390,7 @@ class Surface(IDManagerMixin, ABC): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing source data """ @@ -432,9 +403,6 @@ class Surface(IDManagerMixin, ABC): element.set("type", self._type) if self.boundary_type != 'transmission': element.set("boundary", self.boundary_type) - if (self.boundary_type in _ALBEDO_BOUNDARIES and - not math.isclose(self.albedo, 1.0)): - element.set("albedo", str(self.albedo)) element.set("coeffs", ' '.join([str(self._coefficients.setdefault(key, 0.0)) for key in self._coeff_keys])) @@ -446,7 +414,7 @@ class Surface(IDManagerMixin, ABC): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -457,17 +425,15 @@ class Surface(IDManagerMixin, ABC): """ # Determine appropriate class - surf_type = get_text(elem, "type") + surf_type = elem.get('type') cls = _SURFACE_CLASSES[surf_type] - # Determine ID, boundary type, boundary albedo, coefficients + # Determine ID, boundary type, coefficients kwargs = {} - kwargs['surface_id'] = int(get_text(elem, "id")) - kwargs['boundary_type'] = get_text(elem, "boundary", "transmission") - if kwargs['boundary_type'] in _ALBEDO_BOUNDARIES: - kwargs['albedo'] = float(get_text(elem, "albedo", 1.0)) - kwargs['name'] = get_text(elem, "name") - coeffs = get_elem_list(elem, "coeffs", float) + kwargs['surface_id'] = int(elem.get('id')) + kwargs['boundary_type'] = elem.get('boundary', 'transmission') + kwargs['name'] = elem.get('name') + coeffs = [float(x) for x in elem.get('coeffs').split()] kwargs.update(dict(zip(cls._coeff_keys, coeffs))) return cls(**kwargs) @@ -497,13 +463,8 @@ class Surface(IDManagerMixin, ABC): name = group['name'][()].decode() if 'name' in group else '' bc = group['boundary_type'][()].decode() - if 'albedo' in group: - bc_alb = float(group['albedo'][()].decode()) - else: - bc_alb = 1.0 coeffs = group['coefficients'][...] - kwargs = {'boundary_type': bc, 'albedo': bc_alb, 'name': name, - 'surface_id': surface_id} + kwargs = {'boundary_type': bc, 'name': name, 'surface_id': surface_id} surf_type = group['type'][()].decode() cls = _SURFACE_CLASSES[surf_type] @@ -578,7 +539,7 @@ class PlaneMixin: else: ur = np.array([v if not np.isnan(v) else np.inf for v in vals]) - return BoundingBox(ll, ur) + return (ll, ur) def evaluate(self, point): """Evaluate the surface equation at a given point. @@ -647,9 +608,7 @@ class PlaneMixin: # Compute new rotated coefficients a, b, c a, b, c = Rmat @ [a, b, c] - kwargs = {'boundary_type': surf.boundary_type, - 'albedo': surf.albedo, - 'name': surf.name} + kwargs = {'boundary_type': surf.boundary_type, 'name': surf.name} if inplace: kwargs['surface_id'] = surf.id @@ -662,7 +621,7 @@ class PlaneMixin: Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing source data """ @@ -689,14 +648,10 @@ class Plane(PlaneMixin, Surface): The 'C' parameter for the plane. Defaults to 0. d : float, optional The 'D' parameter for the plane. Defaults to 0. - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -713,11 +668,9 @@ class Plane(PlaneMixin, Surface): The 'C' parameter for the plane d : float The 'D' parameter for the plane - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -784,38 +737,22 @@ class Plane(PlaneMixin, Surface): Plane Plane that passes through the three points - Raises - ------ - ValueError - If all three points lie along a line - """ # Convert to numpy arrays - p1 = np.asarray(p1, dtype=float) - p2 = np.asarray(p2, dtype=float) - p3 = np.asarray(p3, dtype=float) + p1 = np.asarray(p1) + p2 = np.asarray(p2) + p3 = np.asarray(p3) # Find normal vector to plane by taking cross product of two vectors # connecting p1->p2 and p1->p3 n = np.cross(p2 - p1, p3 - p1) - # Check for points along a line - if np.allclose(n, 0.): - raise ValueError("All three points appear to lie along a line.") - # The equation of the plane will by n·( - p1) = 0. Determine # coefficients a, b, c, and d based on that a, b, c = n d = np.dot(n, p1) return cls(a=a, b=b, c=c, d=d, **kwargs) - def flip_normal(self): - """Modify plane coefficients to reverse the normal vector.""" - self.a = -self.a - self.b = -self.b - self.c = -self.c - self.d = -self.d - class XPlane(PlaneMixin, Surface): """A plane perpendicular to the x axis of the form :math:`x - x_0 = 0` @@ -824,14 +761,11 @@ class XPlane(PlaneMixin, Surface): ---------- x0 : float, optional Location of the plane in [cm]. Defaults to 0. - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. + freely pass through the surface. Only axis-aligned periodicity is + supported, i.e., x-planes can only be paired with x-planes. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -842,11 +776,9 @@ class XPlane(PlaneMixin, Surface): ---------- x0 : float Location of the plane in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -888,14 +820,11 @@ class YPlane(PlaneMixin, Surface): ---------- y0 : float, optional Location of the plane in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. + freely pass through the surface. Only axis-aligned periodicity is + supported, i.e., x-planes can only be paired with x-planes. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -906,11 +835,9 @@ class YPlane(PlaneMixin, Surface): ---------- y0 : float Location of the plane in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -952,14 +879,11 @@ class ZPlane(PlaneMixin, Surface): ---------- z0 : float, optional Location of the plane in [cm]. Defaults to 0. - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. + freely pass through the surface. Only axis-aligned periodicity is + supported, i.e., x-planes can only be paired with x-planes. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -970,11 +894,9 @@ class ZPlane(PlaneMixin, Surface): ---------- z0 : float Location of the plane in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'periodic', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -1146,8 +1068,7 @@ class QuadricMixin: else: base_cls = type(tsurf)._virtual_base # Copy necessary surface attributes to new kwargs dictionary - kwargs = {'boundary_type': tsurf.boundary_type, - 'albedo': tsurf.albedo, 'name': tsurf.name} + kwargs = {'boundary_type': tsurf.boundary_type, 'name': tsurf.name} if inplace: kwargs['surface_id'] = tsurf.id kwargs.update({k: getattr(tsurf, k) for k in base_cls._coeff_keys}) @@ -1200,14 +1121,10 @@ class Cylinder(QuadricMixin, Surface): dz : float, optional z-component of the vector representing the axis of the cylinder. Defaults to 1. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1231,11 +1148,9 @@ class Cylinder(QuadricMixin, Surface): y-component of the vector representing the axis of the cylinder dz : float z-component of the vector representing the axis of the cylinder - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1266,7 +1181,7 @@ class Cylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r', positive=True) + r = SurfaceCoefficient('r') dx = SurfaceCoefficient('dx') dy = SurfaceCoefficient('dy') dz = SurfaceCoefficient('dz') @@ -1278,9 +1193,11 @@ class Cylinder(QuadricMixin, Surface): else -np.inf for xi, dxi in zip(self._origin, self._axis)] ur = [xi + r if np.isclose(dxi, 0., rtol=0., atol=self._atol) else np.inf for xi, dxi in zip(self._origin, self._axis)] - return BoundingBox(np.array(ll), np.array(ur)) + return (np.array(ll), np.array(ur)) + elif side == '+': - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) def _get_base_coeffs(self): # Get x, y, z coordinates of two points @@ -1323,7 +1240,7 @@ class Cylinder(QuadricMixin, Surface): Parameters ---------- p1, p2 : 3-tuples - Points that pass through the cylinder axis. + Points that pass through the plane, p1 will be used as (x0, y0, z0) r : float, optional Radius of the cylinder in [cm]. Defaults to 1. kwargs : dict @@ -1349,7 +1266,7 @@ class Cylinder(QuadricMixin, Surface): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing source data """ @@ -1357,8 +1274,8 @@ class Cylinder(QuadricMixin, Surface): # since the C++ layer doesn't support Cylinders right now with catch_warnings(): simplefilter('ignore', IDWarning) - kwargs = {'boundary_type': self.boundary_type, 'albedo': self.albedo, - 'name': self.name, 'surface_id': self.id} + kwargs = {'boundary_type': self.boundary_type, 'name': self.name, + 'surface_id': self.id} quad_rep = Quadric(*self._get_base_coeffs(), **kwargs) return quad_rep.to_xml_element() @@ -1375,14 +1292,10 @@ class XCylinder(QuadricMixin, Surface): z-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional Radius of the cylinder in [cm]. Defaults to 1. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1398,11 +1311,9 @@ class XCylinder(QuadricMixin, Surface): z-coordinate for the origin of the Cylinder in [cm] r : float Radius of the cylinder in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1432,7 +1343,7 @@ class XCylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient(0.) y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r', positive=True) + r = SurfaceCoefficient('r') dx = SurfaceCoefficient(1.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(0.) @@ -1448,12 +1359,11 @@ class XCylinder(QuadricMixin, Surface): def bounding_box(self, side): if side == '-': - return BoundingBox( - np.array([-np.inf, self.y0 - self.r, self.z0 - self.r]), - np.array([np.inf, self.y0 + self.r, self.z0 + self.r]) - ) + return (np.array([-np.inf, self.y0 - self.r, self.z0 - self.r]), + np.array([np.inf, self.y0 + self.r, self.z0 + self.r])) elif side == '+': - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) def evaluate(self, point): y = point[1] - self.y0 @@ -1473,14 +1383,10 @@ class YCylinder(QuadricMixin, Surface): z-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional Radius of the cylinder in [cm]. Defaults to 1. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1496,11 +1402,9 @@ class YCylinder(QuadricMixin, Surface): z-coordinate for the origin of the Cylinder in [cm] r : float Radius of the cylinder in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1530,7 +1434,7 @@ class YCylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient(0.) z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r', positive=True) + r = SurfaceCoefficient('r') dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(1.) dz = SurfaceCoefficient(0.) @@ -1546,12 +1450,11 @@ class YCylinder(QuadricMixin, Surface): def bounding_box(self, side): if side == '-': - return BoundingBox( - np.array([self.x0 - self.r, -np.inf, self.z0 - self.r]), - np.array([self.x0 + self.r, np.inf, self.z0 + self.r]) - ) + return (np.array([self.x0 - self.r, -np.inf, self.z0 - self.r]), + np.array([self.x0 + self.r, np.inf, self.z0 + self.r])) elif side == '+': - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) def evaluate(self, point): x = point[0] - self.x0 @@ -1571,14 +1474,10 @@ class ZCylinder(QuadricMixin, Surface): y-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional Radius of the cylinder in [cm]. Defaults to 1. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1594,11 +1493,9 @@ class ZCylinder(QuadricMixin, Surface): y-coordinate for the origin of the Cylinder in [cm] r : float Radius of the cylinder in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1628,7 +1525,7 @@ class ZCylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient(0.) - r = SurfaceCoefficient('r', positive=True) + r = SurfaceCoefficient('r') dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(1.) @@ -1644,12 +1541,11 @@ class ZCylinder(QuadricMixin, Surface): def bounding_box(self, side): if side == '-': - return BoundingBox( - np.array([self.x0 - self.r, self.y0 - self.r, -np.inf]), - np.array([self.x0 + self.r, self.y0 + self.r, np.inf]) - ) + return (np.array([self.x0 - self.r, self.y0 - self.r, -np.inf]), + np.array([self.x0 + self.r, self.y0 + self.r, np.inf])) elif side == '+': - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) def evaluate(self, point): x = point[0] - self.x0 @@ -1670,14 +1566,10 @@ class Sphere(QuadricMixin, Surface): z-coordinate of the center of the sphere in [cm]. Defaults to 0. r : float, optional Radius of the sphere in [cm]. Defaults to 1. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the sphere. If not specified, the name will be the empty string. surface_id : int, optional @@ -1694,11 +1586,9 @@ class Sphere(QuadricMixin, Surface): z-coordinate of the center of the sphere in [cm] r : float Radius of the sphere in [cm] - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1728,7 +1618,7 @@ class Sphere(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r', positive=True) + r = SurfaceCoefficient('r') def _get_base_coeffs(self): x0, y0, z0, r = self.x0, self.y0, self.z0, self.r @@ -1741,12 +1631,13 @@ class Sphere(QuadricMixin, Surface): def bounding_box(self, side): if side == '-': - return BoundingBox( - np.array([self.x0 - self.r, self.y0 - self.r, self.z0 - self.r]), - np.array([self.x0 + self.r, self.y0 + self.r, self.z0 + self.r]) - ) + return (np.array([self.x0 - self.r, self.y0 - self.r, + self.z0 - self.r]), + np.array([self.x0 + self.r, self.y0 + self.r, + self.z0 + self.r])) elif side == '+': - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) def evaluate(self, point): x = point[0] - self.x0 @@ -1756,44 +1647,34 @@ class Sphere(QuadricMixin, Surface): class Cone(QuadricMixin, Surface): - r"""A conical surface parallel to the x-, y-, or z-axis. - - .. Note:: - This creates a double cone, which is two one-sided cones that meet at their apex. - For a one-sided cone see :class:`~openmc.model.XConeOneSided`, - :class:`~openmc.model.YConeOneSided`, and :class:`~openmc.model.ZConeOneSided`. + """A conical surface parallel to the x-, y-, or z-axis. Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. + Parameter related to the aperature. Defaults to 1. dx : float, optional x-component of the vector representing the axis of the cone. + Defaults to 0. dy : float, optional y-component of the vector representing the axis of the cone. + Defaults to 0. dz : float, optional z-component of the vector representing the axis of the cone. + Defaults to 1. surface_id : int, optional Unique identifier for the surface. If not specified, an identifier will automatically be assigned. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. - name : str Name of the cone. If not specified, the name will be the empty string. @@ -1806,18 +1687,16 @@ class Cone(QuadricMixin, Surface): z0 : float z-coordinate of the apex in [cm] r2 : float - Parameter related to the aperture + Parameter related to the aperature dx : float x-component of the vector representing the axis of the cone. dy : float y-component of the vector representing the axis of the cone. dz : float z-component of the vector representing the axis of the cone. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1854,7 +1733,7 @@ class Cone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2', positive=True) + r2 = SurfaceCoefficient('r2') dx = SurfaceCoefficient('dx') dy = SurfaceCoefficient('dy') dz = SurfaceCoefficient('dz') @@ -1895,7 +1774,7 @@ class Cone(QuadricMixin, Surface): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing source data """ @@ -1903,43 +1782,30 @@ class Cone(QuadricMixin, Surface): # since the C++ layer doesn't support Cones right now with catch_warnings(): simplefilter('ignore', IDWarning) - kwargs = {'boundary_type': self.boundary_type, - 'albedo': self.albedo, - 'name': self.name, + kwargs = {'boundary_type': self.boundary_type, 'name': self.name, 'surface_id': self.id} quad_rep = Quadric(*self._get_base_coeffs(), **kwargs) return quad_rep.to_xml_element() class XCone(QuadricMixin, Surface): - r"""A cone parallel to the x-axis of the form :math:`(y - y_0)^2 + (z - z_0)^2 = + """A cone parallel to the x-axis of the form :math:`(y - y_0)^2 + (z - z_0)^2 = r^2 (x - x_0)^2`. - .. Note:: - This creates a double cone, which is two one-sided cones that meet at their apex. - For a one-sided cone see :class:`~openmc.model.XConeOneSided`. - Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + Parameter related to the aperature. Defaults to 1. + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cone. If not specified, the name will be the empty string. surface_id : int, optional @@ -1955,12 +1821,10 @@ class XCone(QuadricMixin, Surface): z0 : float z-coordinate of the apex in [cm] r2 : float - Parameter related to the aperture - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + Parameter related to the aperature + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1990,7 +1854,7 @@ class XCone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2', positive=True) + r2 = SurfaceCoefficient('r2') dx = SurfaceCoefficient(1.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(0.) @@ -2014,34 +1878,23 @@ class XCone(QuadricMixin, Surface): class YCone(QuadricMixin, Surface): - r"""A cone parallel to the y-axis of the form :math:`(x - x_0)^2 + (z - z_0)^2 = + """A cone parallel to the y-axis of the form :math:`(x - x_0)^2 + (z - z_0)^2 = r^2 (y - y_0)^2`. - .. Note:: - This creates a double cone, which is two one-sided cones that meet at their apex. - For a one-sided cone see :class:`~openmc.model.YConeOneSided`. - Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + Parameter related to the aperature. Defaults to 1. + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cone. If not specified, the name will be the empty string. surface_id : int, optional @@ -2057,12 +1910,10 @@ class YCone(QuadricMixin, Surface): z0 : float z-coordinate of the apex in [cm] r2 : float - Parameter related to the aperture - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + Parameter related to the aperature + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2092,7 +1943,7 @@ class YCone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2', positive=True) + r2 = SurfaceCoefficient('r2') dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(1.) dz = SurfaceCoefficient(0.) @@ -2116,34 +1967,23 @@ class YCone(QuadricMixin, Surface): class ZCone(QuadricMixin, Surface): - r"""A cone parallel to the z-axis of the form :math:`(x - x_0)^2 + (y - y_0)^2 = + """A cone parallel to the z-axis of the form :math:`(x - x_0)^2 + (y - y_0)^2 = r^2 (z - z_0)^2`. - .. Note:: - This creates a double cone, which is two one-sided cones that meet at their apex. - For a one-sided cone see :class:`~openmc.model.ZConeOneSided`. - Parameters ---------- x0 : float, optional - x-coordinate of the apex in [cm]. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex in [cm]. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex in [cm]. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - The square of the slope of the cone. It is defined as - :math:`\left(\frac{r}{h}\right)^2` for a radius, :math:`r` and an axial - distance :math:`h` from the apex. An easy way to define this quantity is - to take the square of the radius of the cone (in cm) 1 cm from the apex. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + Parameter related to the aperature. Defaults to 1. + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cone. If not specified, the name will be the empty string. surface_id : int, optional @@ -2159,12 +1999,10 @@ class ZCone(QuadricMixin, Surface): z0 : float z-coordinate of the apex in [cm] r2 : float - Parameter related to the aperture. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + Parameter related to the aperature + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2194,7 +2032,7 @@ class ZCone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2', positive=True) + r2 = SurfaceCoefficient('r2') dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(1.) @@ -2225,14 +2063,10 @@ class Quadric(QuadricMixin, Surface): ---------- a, b, c, d, e, f, g, h, j, k : float, optional coefficients for the surface. All default to 0. - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - albedo : float, optional - Albedo of the surfaces as a ratio of particle weight after interaction - with the surface to the initial weight. Values must be positive. Only - applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the surface. If not specified, the name will be the empty string. surface_id : int, optional @@ -2243,11 +2077,9 @@ class Quadric(QuadricMixin, Surface): ---------- a, b, c, d, e, f, g, h, j, k : float coefficients for the surface - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2297,9 +2129,9 @@ class TorusMixin: x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - a = SurfaceCoefficient('a', positive=True) - b = SurfaceCoefficient('b', positive=True) - c = SurfaceCoefficient('c', positive=True) + a = SurfaceCoefficient('a') + b = SurfaceCoefficient('b') + c = SurfaceCoefficient('c') def translate(self, vector, inplace=False): surf = self if inplace else self.clone() @@ -2343,9 +2175,7 @@ class TorusMixin: # Create rotated torus kwargs = { - 'boundary_type': surf.boundary_type, - 'albedo': surf.albedo, - 'name': surf.name, + 'boundary_type': surf.boundary_type, 'name': surf.name, 'a': surf.a, 'b': surf.b, 'c': surf.c } if inplace: @@ -2395,11 +2225,9 @@ class XTorus(TorusMixin, Surface): Minor radius of the torus in [cm] (parallel to axis of revolution) c : float Minor radius of the torus in [cm] (perpendicular to axis of revolution) - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2425,13 +2253,11 @@ class XTorus(TorusMixin, Surface): x0, y0, z0 = self.x0, self.y0, self.z0 a, b, c = self.a, self.b, self.c if side == '-': - return BoundingBox( - np.array([x0 - b, y0 - a - c, z0 - a - c]), - np.array([x0 + b, y0 + a + c, z0 + a + c]) - ) + return (np.array([x0 - b, y0 - a - c, z0 - a - c]), + np.array([x0 + b, y0 + a + c, z0 + a + c])) elif side == '+': - return BoundingBox.infinite() - + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) class YTorus(TorusMixin, Surface): r"""A torus of the form :math:`(y - y_0)^2/B^2 + (\sqrt{(x - x_0)^2 + (z - @@ -2470,11 +2296,9 @@ class YTorus(TorusMixin, Surface): Minor radius of the torus in [cm] (parallel to axis of revolution) c : float Minor radius of the torus (perpendicular to axis of revolution) - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2500,13 +2324,11 @@ class YTorus(TorusMixin, Surface): x0, y0, z0 = self.x0, self.y0, self.z0 a, b, c = self.a, self.b, self.c if side == '-': - return BoundingBox( - np.array([x0 - a - c, y0 - b, z0 - a - c]), - np.array([x0 + a + c, y0 + b, z0 + a + c]) - ) + return (np.array([x0 - a - c, y0 - b, z0 - a - c]), + np.array([x0 + a + c, y0 + b, z0 + a + c])) elif side == '+': - return BoundingBox.infinite() - + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) class ZTorus(TorusMixin, Surface): r"""A torus of the form :math:`(z - z_0)^2/B^2 + (\sqrt{(x - x_0)^2 + (y - @@ -2545,11 +2367,9 @@ class ZTorus(TorusMixin, Surface): Minor radius of the torus in [cm] (parallel to axis of revolution) c : float Minor radius of the torus in [cm] (perpendicular to axis of revolution) - boundary_type : {'transmission', 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. - albedo : float - Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2575,12 +2395,11 @@ class ZTorus(TorusMixin, Surface): x0, y0, z0 = self.x0, self.y0, self.z0 a, b, c = self.a, self.b, self.c if side == '-': - return BoundingBox( - np.array([x0 - a - c, y0 - a - c, z0 - b]), - np.array([x0 + a + c, y0 + a + c, z0 + b]) - ) + return (np.array([x0 - a - c, y0 - a - c, z0 - b]), + np.array([x0 + a + c, y0 + a + c, z0 + b])) elif side == '+': - return BoundingBox.infinite() + return (np.array([-np.inf, -np.inf, -np.inf]), + np.array([np.inf, np.inf, np.inf])) class Halfspace(Region): @@ -2615,7 +2434,7 @@ class Halfspace(Region): Surface which divides Euclidean space. side : {'+', '-'} Indicates whether the positive or negative half-space is used. - bounding_box : openmc.BoundingBox + bounding_box : tuple of numpy.ndarray Lower-left and upper-right coordinates of an axis-aligned bounding box """ @@ -2636,7 +2455,7 @@ class Halfspace(Region): else: return Union((self, other)) - def __invert__(self) -> Halfspace: + def __invert__(self): return -self.surface if self.side == '+' else +self.surface def __contains__(self, point): @@ -2689,17 +2508,17 @@ class Halfspace(Region): Parameters ---------- - surfaces : dict, optional + surfaces: collections.OrderedDict, optional Dictionary mapping surface IDs to :class:`openmc.Surface` instances Returns ------- - surfaces : dict + surfaces: collections.OrderedDict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ if surfaces is None: - surfaces = {} + surfaces = OrderedDict() surfaces[self.surface.id] = self.surface return surfaces diff --git a/openmc/tallies.py b/openmc/tallies.py index ceced4255..d0355f14e 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -1,40 +1,20 @@ -from __future__ import annotations from collections.abc import Iterable, MutableSequence import copy -from functools import partial, reduce, wraps +from functools import partial, reduce from itertools import product -from math import sqrt, log from numbers import Integral, Real import operator from pathlib import Path -import lxml.etree as ET +from xml.etree import ElementTree as ET import h5py import numpy as np import pandas as pd -from scipy.stats import chi2, norm +import scipy.sparse as sps import openmc import openmc.checkvalue as cv -from openmc.filter import ( - Filter, - DistribcellFilter, - EnergyFunctionFilter, - DelayedGroupFilter, - FilterMeta, - MeshFilter, - MeshBornFilter, -) -from openmc.arithmetic import ( - CrossFilter, - AggregateFilter, - CrossScore, - AggregateScore, - CrossNuclide, - AggregateNuclide, -) -from ._sparse_compat import lil_array -from ._xml import clean_indentation, get_elem_list, get_text +from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin from .mesh import MeshBase @@ -48,12 +28,12 @@ _PRODUCT_TYPES = ['tensor', 'entrywise'] # The following indicate acceptable types when setting Tally.scores, # Tally.nuclides, and Tally.filters -_SCORE_CLASSES = (str, CrossScore, AggregateScore) -_NUCLIDE_CLASSES = (str, CrossNuclide, AggregateNuclide) -_FILTER_CLASSES = (Filter, CrossFilter, AggregateFilter) +_SCORE_CLASSES = (str, openmc.CrossScore, openmc.AggregateScore) +_NUCLIDE_CLASSES = (str, openmc.CrossNuclide, openmc.AggregateNuclide) +_FILTER_CLASSES = (openmc.Filter, openmc.CrossFilter, openmc.AggregateFilter) # Valid types of estimators -ESTIMATOR_TYPES = {'tracklength', 'collision', 'analog'} +ESTIMATOR_TYPES = ['tracklength', 'collision', 'analog'] class Tally(IDManagerMixin): @@ -67,18 +47,6 @@ class Tally(IDManagerMixin): will automatically be assigned name : str, optional Name of the tally. If not specified, the name is the empty string. - scores : list of str, optional - List of scores, e.g. ['flux', 'fission'] - filters : list of openmc.Filter, optional - List of filters for the tally - nuclides : list of str, optional - List of nuclides to score results for - estimator : {'analog', 'tracklength', 'collision'}, optional - Type of estimator for the tally - triggers : list of openmc.Trigger, optional - List of tally triggers - derivative : openmc.TallyDerivative, optional - A material perturbation derivative to apply to all scores in the tally Attributes ---------- @@ -86,20 +54,14 @@ class Tally(IDManagerMixin): Unique identifier for the tally name : str Name of the tally - multiply_density : bool - Whether reaction rates should be multiplied by atom density - - .. versionadded:: 0.14.0 filters : list of openmc.Filter List of specified filters for the tally - nuclides : list of str + nuclides : list of openmc.Nuclide List of nuclides to score results for scores : list of str List of defined scores, e.g. 'flux', 'fission', etc. estimator : {'analog', 'tracklength', 'collision'} - Type of estimator for the tally. If unset (None), OpenMC will automatically - select an appropriate estimator based on the tally filters and scores - with a preference for 'tracklength'. + Type of estimator for the tally triggers : list of openmc.Trigger List of tally triggers num_scores : int @@ -122,24 +84,10 @@ class Tally(IDManagerMixin): sum_sq : numpy.ndarray An array containing the sum of each independent realization squared for each bin - sum_third : numpy.ndarray - An array containing the sum of each independent realization to the third power for - each bin - sum_fourth : numpy.ndarray - An array containing the sum of each independent realization to the fourth power for - each bin mean : numpy.ndarray An array containing the sample mean for each bin std_dev : numpy.ndarray An array containing the sample standard deviation for each bin - vov : numpy.ndarray - An array containing the variance of the variance for each tally bin - higher_moments : bool - Whether or not the tally accumulates the sums third and fourth to compute higher-order moments - figure_of_merit : numpy.ndarray - An array containing the figure of merit for each bin - - .. versionadded:: 0.15.3 derived : bool Whether or not the tally is derived from one or more other tallies sparse : bool @@ -153,9 +101,7 @@ class Tally(IDManagerMixin): next_id = 1 used_ids = set() - def __init__(self, tally_id=None, name='', scores=None, filters=None, - nuclides=None, estimator=None, triggers=None, - derivative=None): + def __init__(self, tally_id=None, name=''): # Initialize Tally class attributes self.id = tally_id self.name = name @@ -165,20 +111,14 @@ class Tally(IDManagerMixin): self._estimator = None self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers') self._derivative = None - self._multiply_density = True self._num_realizations = 0 self._with_summary = False self._sum = None self._sum_sq = None - self._sum_third = None - self._sum_fourth = None self._mean = None self._std_dev = None - self._vov = None - self._higher_moments = False - self._simulation_time = None self._with_batch_statistics = False self._derived = False self._sparse = False @@ -186,49 +126,6 @@ class Tally(IDManagerMixin): self._sp_filename = None self._results_read = False - if filters is not None: - self.filters = filters - if nuclides is not None: - self.nuclides = nuclides - if scores is not None: - self.scores = scores - if estimator is not None: - self.estimator = estimator - if triggers is not None: - self.triggers = triggers - if derivative is not None: - self.derivative = derivative - - def __eq__(self, other): - if other.id != self.id: - return False - if other.name != self.name: - return False - # estimators are automatically set based on the tally filters and scores - # during OpenMC initialization if this value is None, so it is not - # considered a requirement for equivalence if it is unset on either - # tally as it implies that the user is allowing OpenMC to select an - # appropriate estimator. If the value is explicitly set on both tallies, - # then the values must match for the tallies to be considered equivalent. - if self.estimator is not None and other.estimator is not None and other.estimator != self.estimator: - return False - if other.filters != self.filters: - return False - # for tallies are loaded from statpoint files - # an empty nuclide list is equivalent to a list with 'total' - other_nuclides = other.nuclides.copy() - self_nuclides = self.nuclides.copy() - if 'total' in other_nuclides: - other_nuclides.remove('total') - if 'total' in self_nuclides: - self_nuclides.remove('total') - if other_nuclides != self_nuclides: - return False - for attr in {'scores', 'triggers', 'derivative', 'multiply_density'}: - if getattr(other, attr) != getattr(self, attr): - return False - return True - def __repr__(self): parts = ['Tally'] parts.append('{: <15}=\t{}'.format('ID', self.id)) @@ -241,58 +138,196 @@ class Tally(IDManagerMixin): parts.append('{: <15}=\t{}'.format('Nuclides', nuclides)) parts.append('{: <15}=\t{}'.format('Scores', self.scores)) parts.append('{: <15}=\t{}'.format('Estimator', self.estimator)) - parts.append('{: <15}=\t{}'.format('Multiply dens.', self.multiply_density)) return '\n\t'.join(parts) - @staticmethod - def ensure_results(f): - """A decorator to be applied to any method that might use tally results. - Results will be loaded if appropriate based on the tally properties. - - Args: - f function: Tally method to wrap - - Returns: - function: Wrapped function that reads tally results before calling - the methodif necessary - """ - @wraps(f) - def read(self): - if self._sp_filename is not None and not self.derived: - self._read_results() - return f(self) - return read - @property def name(self): return self._name + @property + def filters(self): + return self._filters + + @property + def nuclides(self): + return self._nuclides + + @property + def num_nuclides(self): + return len(self._nuclides) + + @property + def scores(self): + return self._scores + + @property + def num_scores(self): + return len(self._scores) + + @property + def num_filters(self): + return len(self.filters) + + @property + def num_filter_bins(self): + return reduce(operator.mul, (f.num_bins for f in self.filters), 1) + + @property + def num_bins(self): + return self.num_filter_bins * self.num_nuclides * self.num_scores + + @property + def shape(self): + return (self.num_filter_bins, self.num_nuclides, self.num_scores) + + @property + def estimator(self): + return self._estimator + + @property + def triggers(self): + return self._triggers + + @property + def num_realizations(self): + return self._num_realizations + + @property + def with_summary(self): + return self._with_summary + + def _read_results(self): + if self._results_read: + return + + # Open the HDF5 statepoint file + with h5py.File(self._sp_filename, 'r') as f: + # Extract Tally data from the file + data = f[f'tallies/tally {self.id}/results'] + sum_ = data[:, :, 0] + sum_sq = data[:, :, 1] + + # Reshape the results arrays + sum_ = np.reshape(sum_, self.shape) + sum_sq = np.reshape(sum_sq, self.shape) + + # Set the data for this Tally + self._sum = sum_ + self._sum_sq = sum_sq + + # Convert NumPy arrays to SciPy sparse LIL matrices + if self.sparse: + self._sum = sps.lil_matrix(self._sum.flatten(), self._sum.shape) + self._sum_sq = sps.lil_matrix(self._sum_sq.flatten(), self._sum_sq.shape) + + # Indicate that Tally results have been read + self._results_read = True + + @property + def sum(self): + if not self._sp_filename or self.derived: + return None + + # Make sure results have been read + self._read_results() + + if self.sparse: + return np.reshape(self._sum.toarray(), self.shape) + else: + return self._sum + + @property + def sum_sq(self): + if not self._sp_filename or self.derived: + return None + + # Make sure results have been read + self._read_results() + + if self.sparse: + return np.reshape(self._sum_sq.toarray(), self.shape) + else: + return self._sum_sq + + @property + def mean(self): + if self._mean is None: + if not self._sp_filename: + return None + + self._mean = self.sum / self.num_realizations + + # Convert NumPy array to SciPy sparse LIL matrix + if self.sparse: + self._mean = sps.lil_matrix(self._mean.flatten(), + self._mean.shape) + + if self.sparse: + return np.reshape(self._mean.toarray(), self.shape) + else: + return self._mean + + @property + def std_dev(self): + if self._std_dev is None: + if not self._sp_filename: + return None + + n = self.num_realizations + nonzero = np.abs(self.mean) > 0 + self._std_dev = np.zeros_like(self.mean) + self._std_dev[nonzero] = np.sqrt((self.sum_sq[nonzero]/n - + self.mean[nonzero]**2)/(n - 1)) + + # Convert NumPy array to SciPy sparse LIL matrix + if self.sparse: + self._std_dev = sps.lil_matrix(self._std_dev.flatten(), + self._std_dev.shape) + + self.with_batch_statistics = True + + if self.sparse: + return np.reshape(self._std_dev.toarray(), self.shape) + else: + return self._std_dev + + @property + def with_batch_statistics(self): + return self._with_batch_statistics + + @property + def derived(self): + return self._derived + + @property + def derivative(self): + return self._derivative + + @property + def sparse(self): + return self._sparse + + @estimator.setter + def estimator(self, estimator): + cv.check_value('estimator', estimator, ESTIMATOR_TYPES) + self._estimator = estimator + + @triggers.setter + def triggers(self, triggers): + cv.check_type('tally triggers', triggers, MutableSequence) + self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers', + triggers) + @name.setter def name(self, name): cv.check_type('tally name', name, str, none_ok=True) self._name = name - @property - def multiply_density(self): - return self._multiply_density - - @multiply_density.setter - def multiply_density(self, value): - cv.check_type('multiply density', value, bool) - self._multiply_density = value - - @property - def higher_moments(self) -> bool: - return self._higher_moments - - @higher_moments.setter - def higher_moments(self, value): - cv.check_type("higher_moments", value, bool) - self._higher_moments = value - - @property - def filters(self): - return self._filters + @derivative.setter + def derivative(self, deriv): + cv.check_type('tally derivative', deriv, openmc.TallyDerivative, + none_ok=True) + self._derivative = deriv @filters.setter def filters(self, filters): @@ -310,11 +345,6 @@ class Tally(IDManagerMixin): self._filters = cv.CheckedList(_FILTER_CLASSES, 'tally filters', filters) - @property - @ensure_results - def nuclides(self): - return self._nuclides - @nuclides.setter def nuclides(self, nuclides): cv.check_type('tally nuclides', nuclides, MutableSequence) @@ -332,14 +362,6 @@ class Tally(IDManagerMixin): self._nuclides = cv.CheckedList(_NUCLIDE_CLASSES, 'tally nuclides', nuclides) - @property - def num_nuclides(self): - return max(len(self._nuclides), 1) - - @property - def scores(self): - return self._scores - @scores.setter def scores(self, scores): cv.check_type('tally scores', scores, MutableSequence) @@ -367,626 +389,31 @@ class Tally(IDManagerMixin): self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores) - @property - def num_scores(self): - return len(self._scores) - - @property - def num_filters(self): - return len(self.filters) - - @property - def num_filter_bins(self): - return reduce(operator.mul, (f.num_bins for f in self.filters), 1) - - @property - def num_bins(self): - return self.num_filter_bins * self.num_nuclides * self.num_scores - - @property - def shape(self): - return (self.num_filter_bins, self.num_nuclides, self.num_scores) - - @property - def estimator(self): - return self._estimator - - @estimator.setter - def estimator(self, estimator): - # allow the estimator to be set to None (let OpenMC choose the estimator at runtime) - cv.check_value('estimator', estimator, ESTIMATOR_TYPES | {None}) - self._estimator = estimator - - @property - def triggers(self): - return self._triggers - - @triggers.setter - def triggers(self, triggers): - cv.check_type('tally triggers', triggers, MutableSequence) - self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers', - triggers) - - @property - @ensure_results - def num_realizations(self): - return self._num_realizations - @num_realizations.setter def num_realizations(self, num_realizations): cv.check_type('number of realizations', num_realizations, Integral) cv.check_greater_than('number of realizations', num_realizations, 0, True) self._num_realizations = num_realizations - @property - def with_summary(self): - return self._with_summary - @with_summary.setter def with_summary(self, with_summary): cv.check_type('with_summary', with_summary, bool) self._with_summary = with_summary - def _read_results(self): - if self._results_read: - return - - # Open the HDF5 statepoint file - with h5py.File(self._sp_filename, 'r') as f: - # Set number of realizations - group = f[f'tallies/tally {self.id}'] - self._num_realizations = int(group['n_realizations'][()]) - - for filt in self.filters: - if isinstance(filt, DistribcellFilter): - filter_group = f[f'tallies/filters/filter {filt.id}'] - filt._num_bins = int(filter_group['n_bins'][()]) - - # Update nuclides - nuclide_names = group['nuclides'][()] - self._nuclides = [name.decode().strip() for name in nuclide_names] - # Check for higher_moments attribute - if "higher_moments" in group.attrs: - self._higher_moments = bool(group.attrs["higher_moments"][()]) - else: - self._higher_moments = False - - # Extract Tally data from the file - data = group['results'] - sum_ = data[:, :, 0] - sum_sq = data[:, :, 1] - - # Reshape the results arrays - sum_ = np.reshape(sum_, self.shape) - sum_sq = np.reshape(sum_sq, self.shape) - - # Set the data for this Tally - self._sum = sum_ - self._sum_sq = sum_sq - - if self._higher_moments: - # Extract additional Tally data when higher moments enabled - sum_third = data[:, :, 2] - sum_fourth = data[:, :, 3] - - # Reshape the results arrays - sum_third = np.reshape(sum_third, self.shape) - sum_fourth = np.reshape(sum_fourth, self.shape) - - # Set the additional data for this Tally - self._sum_third = sum_third - self._sum_fourth = sum_fourth - - # Convert NumPy arrays to SciPy sparse LIL matrices - if self.sparse: - self._sum = lil_array(self._sum.flatten(), self._sum.shape) - self._sum_sq = lil_array(self._sum_sq.flatten(), self._sum_sq.shape) - self._sum_third = lil_array(self._sum_third.flatten(), self._sum_third.shape) - self._sum_fourth = lil_array(self._sum_fourth.flatten(), self._sum_fourth.shape) - - # Read simulation time (needed for figure of merit) - self._simulation_time = f["runtime"]["simulation"][()] - - # Indicate that Tally results have been read - self._results_read = True - - @property - @ensure_results - def sum(self): - if not self._sp_filename or self.derived: - return None - - if self.sparse: - return np.reshape(self._sum.toarray(), self.shape) - else: - return self._sum - - @sum.setter - def sum(self, sum): - cv.check_type('sum', sum, Iterable) - self._sum = sum - - @property - @ensure_results - def sum_sq(self): - if not self._sp_filename or self.derived: - return None - - if self.sparse: - return np.reshape(self._sum_sq.toarray(), self.shape) - else: - return self._sum_sq - - @sum_sq.setter - def sum_sq(self, sum_sq): - cv.check_type('sum_sq', sum_sq, Iterable) - self._sum_sq = sum_sq - - @property - @ensure_results - def sum_third(self): - if not self._higher_moments: - raise ValueError( - "Higher moments have not been enabled for this tally. To make " - "higher moments available, set the higher_moments attribute to " - "True before running a simulation." - ) - - if not self._sp_filename or self.derived: - return None - - if self.sparse: - return np.reshape(self._sum_third.toarray(), self.shape) - else: - return self._sum_third - - @sum_third.setter - def sum_third(self, sum_third): - cv.check_type("sum_third", sum_third, Iterable) - self._sum_third = sum_third - - @property - @ensure_results - def sum_fourth(self): - if not self._higher_moments: - raise ValueError( - "Higher moments have not been enabled for this tally. To make " - "higher moments available, set the higher_moments attribute to " - "True before running a simulation." - ) - - if not self._sp_filename or self.derived: - return None - - if self.sparse: - return np.reshape(self._sum_fourth.toarray(), self.shape) - else: - return self._sum_fourth - - @sum_fourth.setter - def sum_fourth(self, sum_fourth): - cv.check_type("sum_fourth", sum_fourth, Iterable) - self._sum_fourth = sum_fourth - - @property - def mean(self): - if self._mean is None: - if not self._sp_filename: - return None - - self._mean = self.sum / self.num_realizations - - # Convert NumPy array to SciPy sparse LIL matrix - if self.sparse: - self._mean = lil_array(self._mean.flatten(), self._mean.shape) - - if self.sparse: - return np.reshape(self._mean.toarray(), self.shape) - else: - return self._mean - - @property - def std_dev(self): - if self._std_dev is None: - if not self._sp_filename: - return None - - n = self.num_realizations - nonzero = np.abs(self.mean) > 0 - self._std_dev = np.zeros_like(self.mean) - self._std_dev[nonzero] = np.sqrt((self.sum_sq[nonzero]/n - - self.mean[nonzero]**2)/(n - 1)) - - # Convert NumPy array to SciPy sparse LIL matrix - if self.sparse: - self._std_dev = lil_array(self._std_dev.flatten(), self._std_dev.shape) - - self.with_batch_statistics = True - - if self.sparse: - return np.reshape(self._std_dev.toarray(), self.shape) - else: - return self._std_dev - - @property - def vov(self): - if self._vov is None: - n = self.num_realizations - sum1 = self.sum - sum2 = self.sum_sq - sum3 = self.sum_third - sum4 = self.sum_fourth - self._vov = np.zeros_like(sum1, dtype=float) - - # Calculate the variance of the variance (Eq. 2.232 in - # https://doi.org/10.2172/2372634) - numerator = (sum4 - (4.0*sum3*sum1)/n - + (6.0*sum2*(sum1**2))/(n**2) - - (3.0*(sum1)**4)/(n**3)) - denominator = (sum2 - (1.0/n)*(sum1**2))**2 - - mask = denominator > 0.0 - - self._vov[mask] = numerator[mask]/denominator[mask] - 1.0/n - - if self.sparse: - self._vov = lil_array(self._vov.flatten(), self._vov.shape) - - if self.sparse: - return np.reshape(self._vov.toarray(), self.shape) - else: - return self._vov - - @property - def m2(self): - n = self.num_realizations - return self.sum_sq/n - self.mean**2 - - @property - def m3(self): - n = self.num_realizations - mean = self.mean - sum2 = self.sum_sq/n - sum3 = self.sum_third/n - - return sum3 - 3.0*mean*sum2 + 2.0*mean**3 - - @property - def m4(self): - n = self.num_realizations - mean = self.mean - sum2 = self.sum_sq/n - sum3 = self.sum_third/n - sum4 = self.sum_fourth/n - - return sum4 - 4.0*mean*sum3 + 6.0*(mean**2)*sum2 - 3.0*mean**4 - - def skew(self, bias=False) -> np.ndarray: - """Return the sample skewness of each tally bin. - - This method computes and returns the unadjusted or adjusted - Fisher-Pearson coefficient of skewness. - - Parameters - ---------- - bias : bool - If False, calculations are corrected for bias and the adjusted - Fisher-Pearson skewness (:math:`G_1`) is returned. If True, - calculations are not corrected for bias and the unadjusted skewness - (:math:`g_1`) is returned. - - Returns - ------- - float - The skewness of each tally bin - """ - n = self.num_realizations - m2 = self.m2 - m3 = self.m3 - - with np.errstate(divide="ignore", invalid="ignore"): - g1 = np.where(m2 > 0.0, m3/(m2**1.5), 0.0) - - if bias: - return g1 - else: - if n <= 2: - raise ValueError("Insufficient number of independent realizations" - f"for bias-corrected skewness: need n >= 3, got {n=}.") - else: - return sqrt(n*(n - 1))/(n - 2)*g1 - - def kurtosis(self, fisher=True, bias=False) -> np.ndarray: - r"""Return the sample kurtosis of each tally bin. - - This method computes and returns the sample kurtosis using either - Pearson's or Fisher's definition, with or without finite-sample bias - correction. The value returned depends on the `bias` and `fisher` - arguments as follows: - - - **bias=True, fisher=False**: Returns :math:`b_2` (Pearson's kurtosis) - This is the raw fourth standardized moment: :math:`m_4/m_2^2`. For a - normal distribution, :math:`b_2\approx 3`. - - - **bias=True, fisher=True**: Returns :math:`g_2` (excess kurtosis) This - is :math:`b_2 - 3`, centered at 0 for normal distributions. Positive - values indicate heavier tails, negative values lighter tails. - - - **bias=False, fisher=True** (default): Returns :math:`G_2` (adjusted - excess kurtosis). This applies finite-sample bias correction to - :math:`g_2`. This is the recommended estimator for statistical - inference. - - - **bias=False, fisher=False**: Returns bias-corrected Pearson's - kurtosis. This is :math:`G_2 + 3`. - - Parameters - ---------- - fisher : bool, optional - If True (default), Fisher's definition is used (excess kurtosis). If - False, Pearson's definition is used. - bias : bool, optional - If False (default), calculations are corrected for statistical bias - using finite-sample adjustments. If True, calculations use the - biased estimator (population formulas). - - Returns - ------- - numpy.ndarray - The kurtosis of each tally bin - - """ - n = self.num_realizations - m2 = self.m2 - m4 = self.m4 - - with np.errstate(divide="ignore", invalid="ignore"): - b2 = np.where(m2 > 0.0, m4/(m2**2), 0.0) - g2 = b2 - 3.0 - - if bias: - # Biased estimator (g2 or b2) - return g2 if fisher else b2 - else: - # Unbiased estimator with finite-sample correction - if n <= 3: - raise ValueError("Insufficient number of independent realizations" - f"for bias-corrected kurtosis: need n >= 4, got {n=}.") - else: - G2 = ((n - 1)/((n - 2)*(n - 3)))*((n + 1)*g2 + 6.0) - return G2 if fisher else G2 + 3.0 - - def skewtest(self, alternative: str = "two-sided"): - """Perform D'Agostino and Pearson's test for skewness. - - This method tests the null hypothesis that the skewness of the - population that the sample was drawn from is the same as that of a - corresponding normal distribution. - - Parameters - ---------- - alternative : {'two-sided', 'less', 'greater'}, optional - Defines the alternative hypothesis. The following options are - available: - - * 'two-sided': the skewness of the distribution is different from - that of the normal distribution (i.e., non-zero) - * 'less': the skewness of the distribution is less than that of the - normal distribution - * 'greater': the skewness of the distribution is greater than that - of the normal distribution - - Returns - ------- - statistic : np.ndarray - The computed z-score for the skewness test for each tally bin - pvalue : np.ndarray - The p-value for the hypothesis test for each tally bin - - Notes - ----- - This test is based on `D'Agostino and Pearson's test - `_. The test requires at least - 8 realizations to produce valid results. - - """ - n = self.num_realizations - if n < 8: - raise ValueError("Skewness test is not well-defined for n < 8.") - - g1 = self.skew(bias=True) - - # --- Z1 (skewness) --- - y = g1 * sqrt(((n + 1.0)*(n + 3.0))/(6.0*(n - 2.0))) - beta2 = (3.0*(n**2 + 27.0*n - 70.0)*(n + 1.0)*(n + 3.0) - )/((n - 2.0)*(n + 5.0)*(n + 7.0)*(n + 9.0)) - W2 = -1.0 + sqrt(2.0*(beta2 - 1.0)) - delta = 1.0 / sqrt(log(sqrt(W2))) - alpha = sqrt(2.0 / (W2 - 1.0)) - Zb1 = np.where( - y >= 0.0, - delta*np.log((y/alpha) + np.sqrt((y/alpha)**2 + 1.0)), - -delta*np.log((-y/alpha) + np.sqrt((y/alpha)**2 + 1.0)) - ) - - # p-value - if alternative == "two-sided": - p = 2.0 * (1.0 - norm.cdf(np.abs(Zb1))) - elif alternative == "greater": - p = 1.0 - norm.cdf(Zb1) - elif alternative == "less": - p = norm.cdf(Zb1) - else: - raise ValueError("alternative must be 'two-sided', 'greater', or 'less'") - - return Zb1, p - - def kurtosistest(self, alternative: str = "two-sided"): - """Perform D'Agostino and Pearson's test for kurtosis. - - This method tests the null hypothesis that the kurtosis of the - population that the sample was drawn from is the same as that of a - corresponding normal distribution. - - Parameters - ---------- - alternative : {'two-sided', 'less', 'greater'}, optional - Defines the alternative hypothesis. Default is 'two-sided'. The - following options are available: - - * 'two-sided': the kurtosis of the distribution is different from - that of the normal distribution - * 'less': the kurtosis of the distribution is less than that of the - normal distribution - * 'greater': the kurtosis of the distribution is greater than that - of the normal distribution - - Returns - ------- - statistic : np.ndarray - The computed z-score for the kurtosis test for each tally bin - pvalue : np.ndarray - The p-value for the hypothesis test for each tally bin - - Raises - ------ - ValueError - If the number of realizations is less than 20, or if an invalid - alternative hypothesis is specified. - - Notes - ----- - This test is based on `D'Agostino and Pearson's test - `_. The test is typically - recommended for at least 20 realizations to produce valid results. - - """ - n = self.num_realizations - if n < 20: - raise ValueError("Kurtosis test is typically recommended for n >= 20.") - - b2 = self.kurtosis(bias=True, fisher=False) - - # --- Z2 (kurtosis) --- - mean_b2 = 3.0 * (n - 1.0) / (n + 1.0) - var_b2 = (24.0*n*(n - 2.0)*(n - 3.0)/( - (n + 1.0)**2*(n + 3.0)*(n + 5.0))) - x = (b2 - mean_b2)/np.sqrt(var_b2) - moment = ((6.0*(n**2 - 5.0*n + 2.0))/((n + 7.0)*(n + 9.0)) - )*sqrt((6.0*(n + 3.0)*(n + 5.0))/(n*(n - 2.0)*(n - 3.0))) - A = 6.0 + (8.0/moment)*((2.0/moment) + sqrt(1.0 + 4.0/(moment**2))) - Zb2 = (1.0- 2.0/(9.0*A) - ((1.0 - 2.0/A) / (1.0 + (x - )*sqrt(2.0/(A - 4.0))))**(1.0/3.0)) / sqrt(2.0/(9.0*A)) - - # p-value - if alternative == "two-sided": - p = 2.0 * (1.0 - norm.cdf(np.abs(Zb2))) - elif alternative == "greater": - p = 1.0 - norm.cdf(Zb2) - elif alternative == "less": - p = norm.cdf(Zb2) - else: - raise ValueError("alternative must be 'two-sided', 'greater', or 'less'") - - return Zb2, p - - def normaltest(self, alternative: str = "two-sided"): - """Perform D'Agostino and Pearson's omnibus test for normality. - - This method tests the null hypothesis that a sample comes from a normal - distribution. It combines skewness and kurtosis to produce an omnibus - test of normality. - - Parameters - ---------- - alternative : {'two-sided', 'less', 'greater'}, optional - Defines the alternative hypothesis used for the component skewness - and kurtosis tests. Default is 'two-sided'. The following options - are available: - - * 'two-sided': the distribution is different from normal - * 'less': used for the component tests - * 'greater': used for the component tests - - Returns - ------- - statistic : np.ndarray - The computed z-score for the normality test for each tally bin - pvalue : np.ndarray - The p-value for the hypothesis test for each tally bin - - Raises - ------ - ValueError - If the number of realizations is less than 20, or if an invalid - alternative hypothesis is specified. - - Notes - ----- - This test combines a test for skewness and a test for kurtosis to - produce an `omnibus test `_. - The test statistic is: - - .. math:: - - K^2 = Z_1^2 + Z_2^2 - - where :math:`Z_1` is the z-score from the skewness test and :math:`Z_2` - is the z-score from the kurtosis test. This statistic follows a - chi-square distribution with 2 degrees of freedom. - - The test requires at least 20 realizations to produce valid results. - - """ - n = self.num_realizations - if n < 20: - raise ValueError("normaltest requires n >= 20 (per D'Agostino-Pearson).") - - # Use the component tests - Z1, _ = self.skewtest(alternative) - Z2, _ = self.kurtosistest(alternative) - - # Combine as chi-square with df=2 since we have skewness and kurtosis - K2 = Z1*Z1 + Z2*Z2 - p = chi2.sf(K2, df=2) - return K2, p - - @property - def figure_of_merit(self): - mean = self.mean - std_dev = self.std_dev - fom = np.zeros_like(mean) - nonzero = np.abs(mean) > 0 - rel_err = std_dev[nonzero] / mean[nonzero] - fom[nonzero] = 1.0 / (rel_err**2 * self._simulation_time) - return fom - - @property - def with_batch_statistics(self): - return self._with_batch_statistics - @with_batch_statistics.setter def with_batch_statistics(self, with_batch_statistics): cv.check_type('with_batch_statistics', with_batch_statistics, bool) self._with_batch_statistics = with_batch_statistics - @property - def derived(self): - return self._derived + @sum.setter + def sum(self, sum): + cv.check_type('sum', sum, Iterable) + self._sum = sum - @property - def derivative(self): - return self._derivative - - @derivative.setter - def derivative(self, deriv): - cv.check_type('tally derivative', deriv, openmc.TallyDerivative, - none_ok=True) - self._derivative = deriv - - @property - def sparse(self): - return self._sparse + @sum_sq.setter + def sum_sq(self, sum_sq): + cv.check_type('sum_sq', sum_sq, Iterable) + self._sum_sq = sum_sq @sparse.setter def sparse(self, sparse): @@ -1005,17 +432,16 @@ class Tally(IDManagerMixin): # Convert NumPy arrays to SciPy sparse LIL matrices if sparse and not self.sparse: if self._sum is not None: - self._sum = lil_array(self._sum.flatten(), self._sum.shape) + self._sum = sps.lil_matrix(self._sum.flatten(), self._sum.shape) if self._sum_sq is not None: - self._sum_sq = lil_array(self._sum_sq.flatten(), self._sum_sq.shape) - if self._sum_third is not None: - self._sum_third = lil_array(self._sum_third.flatten(), self._sum_third.shape) - if self._sum_fourth is not None: - self._sum_fourth = lil_array(self._sum_fourth.flatten(), self._sum_fourth.shape) + self._sum_sq = sps.lil_matrix(self._sum_sq.flatten(), + self._sum_sq.shape) if self._mean is not None: - self._mean = lil_array(self._mean.flatten(), self._mean.shape) + self._mean = sps.lil_matrix(self._mean.flatten(), + self._mean.shape) if self._std_dev is not None: - self._std_dev = lil_array(self._std_dev.flatten(), self._std_dev.shape) + self._std_dev = sps.lil_matrix(self._std_dev.flatten(), + self._std_dev.shape) self._sparse = True @@ -1025,10 +451,6 @@ class Tally(IDManagerMixin): self._sum = np.reshape(self._sum.toarray(), self.shape) if self._sum_sq is not None: self._sum_sq = np.reshape(self._sum_sq.toarray(), self.shape) - if self._sum_third is not None: - self._sum_third = np.reshape(self._sum_third.toarray(), self.shape) - if self._sum_fourth is not None: - self._sum_fourth = np.reshape(self._sum_fourth.toarray(), self.shape) if self._mean is not None: self._mean = np.reshape(self._mean.toarray(), self.shape) if self._std_dev is not None: @@ -1074,7 +496,7 @@ class Tally(IDManagerMixin): Parameters ---------- - nuclide : str + nuclide : openmc.Nuclide Nuclide to remove """ @@ -1106,8 +528,8 @@ class Tally(IDManagerMixin): return False # Return False if only one tally has a delayed group filter - tally1_dg = self.contains_filter(DelayedGroupFilter) - tally2_dg = other.contains_filter(DelayedGroupFilter) + tally1_dg = self.contains_filter(openmc.DelayedGroupFilter) + tally2_dg = other.contains_filter(openmc.DelayedGroupFilter) if tally1_dg != tally2_dg: return False @@ -1355,34 +777,6 @@ class Tally(IDManagerMixin): merged_tally._sum_sq = np.reshape(merged_sum_sq, merged_tally.shape) - # Concatenate sum_third arrays if present in both tallies - if self._sum_third is not None and other._sum_third is not None: - self_sum_third = self.get_reshaped_data(value="sum_third") - other_sum_third = other_copy.get_reshaped_data(value="sum_third") - - if join_right: - merged_sum_third = np.concatenate((self_sum_third, other_sum_third), - axis=merge_axis) - else: - merged_sum_third = np.concatenate((other_sum_third, self_sum_third), - axis=merge_axis) - - merged_tally._sum_third = np.reshape(merged_sum_third, merged_tally.shape) - - # Concatenate sum_fourth arrays if present in both tallies - if self._sum_fourth is not None and other._sum_fourth is not None: - self_sum_fourth = self.get_reshaped_data(value="sum_fourth") - other_sum_fourth = other_copy.get_reshaped_data(value="sum_fourth") - - if join_right: - merged_sum_fourth = np.concatenate((self_sum_fourth, other_sum_fourth), - axis=merge_axis) - else: - merged_sum_fourth = np.concatenate((other_sum_fourth, self_sum_fourth), - axis=merge_axis) - - merged_tally._sum_fourth = np.reshape(merged_sum_fourth, merged_tally.shape) - # Concatenate mean arrays if present in both tallies if self.mean is not None and other.mean is not None: self_mean = self.get_reshaped_data(value='mean') @@ -1421,7 +815,7 @@ class Tally(IDManagerMixin): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing tally data """ @@ -1435,10 +829,6 @@ class Tally(IDManagerMixin): if self.name != '': element.set("name", self.name) - # Multiply by density - if not self.multiply_density: - element.set("multiply_density", str(self.multiply_density).lower()) - # Optional Tally filters if len(self.filters) > 0: subelement = ET.SubElement(element, "filters") @@ -1472,46 +862,8 @@ class Tally(IDManagerMixin): subelement = ET.SubElement(element, "derivative") subelement.text = str(self.derivative.id) - # Optional higher moments accumulation - if self.higher_moments: - subelement = ET.SubElement(element, "higher_moments") - subelement.text = str(self.higher_moments).lower() - return element - def add_results(self, statepoint: cv.PathLike | openmc.StatePoint): - """Add results from the provided statepoint file to this tally instance - - .. versionadded:: 0.15.1 - - Parameters - ---------- - statepoint : openmc.PathLike or openmc.StatePoint - Statepoint used to update tally results - """ - # derived tallies are populated with data based on combined tallies - # and should not be modified - if self.derived: - return - - if isinstance(statepoint, openmc.StatePoint): - self._sp_filename = Path(statepoint._f.filename) - else: - self._sp_filename = Path(str(statepoint)) - - # reset these properties to ensure that any results access after this - # point are based on the current statepoint file - self._sum = None - self._sum_sq = None - self._sum_third = None - self._sum_fourth = None - self._mean = None - self._std_dev = None - self._vov = None - self._higher_moments = False - self._num_realizations = 0 - self._results_read = False - @classmethod def from_xml_element(cls, elem, **kwargs): """Generate tally object from an XML element @@ -1520,7 +872,7 @@ class Tally(IDManagerMixin): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -1529,33 +881,30 @@ class Tally(IDManagerMixin): Tally object """ - tally_id = int(get_text(elem, "id")) - name = get_text(elem, "name", "") + tally_id = int(elem.get('id')) + name = elem.get('name', '') tally = cls(tally_id=tally_id, name=name) - text = get_text(elem, 'multiply_density') - if text is not None: - tally.multiply_density = text in ('true', '1') - # Read filters - filter_ids = get_elem_list(elem, "filters", int) - if filter_ids is not None: + filters_elem = elem.find('filters') + if filters_elem is not None: + filter_ids = [int(x) for x in filters_elem.text.split()] tally.filters = [kwargs['filters'][uid] for uid in filter_ids] # Read nuclides - nuclides = get_elem_list(elem, "nuclides", str) - if nuclides is not None: - tally.nuclides = nuclides + nuclides_elem = elem.find('nuclides') + if nuclides_elem is not None: + tally.nuclides = nuclides_elem.text.split() # Read scores - scores = get_elem_list(elem, "scores", str) - if scores is not None: - tally.scores = scores + scores_elem = elem.find('scores') + if scores_elem is not None: + tally.scores = scores_elem.text.split() # Set estimator - estimator = get_text(elem, "estimator") - if estimator is not None: - tally.estimator = estimator + estimator_elem = elem.find('estimator') + if estimator_elem is not None: + tally.estimator = estimator_elem.text # Read triggers tally.triggers = [ @@ -1564,9 +913,9 @@ class Tally(IDManagerMixin): ] # Read tally derivative - deriv = get_text(elem, "derivative") - if deriv is not None: - deriv_id = int(deriv) + deriv_elem = elem.find('derivative') + if deriv_elem is not None: + deriv_id = int(deriv_elem.text) tally.derivative = kwargs['derivatives'][deriv_id] return tally @@ -1619,7 +968,7 @@ class Tally(IDManagerMixin): # Also check to see if the desired filter is wrapped up in an # aggregate - elif isinstance(test_filter, AggregateFilter): + elif isinstance(test_filter, openmc.AggregateFilter): if isinstance(test_filter.aggregate_filter, filter_type): return test_filter @@ -1648,10 +997,17 @@ class Tally(IDManagerMixin): in the Tally. """ - # Look for the user-requested nuclide in all of the Tally's nuclides + # Look for the user-requested nuclide in all of the Tally's Nuclides for i, test_nuclide in enumerate(self.nuclides): - if test_nuclide == nuclide: - return i + # If the Summary was linked, then values are Nuclide objects + if isinstance(test_nuclide, openmc.Nuclide): + if test_nuclide.name == nuclide: + return i + + # If the Summary has not been linked, then values are ZAIDs + else: + if test_nuclide == nuclide: + return i msg = (f'Unable to get the nuclide index for Tally since "{nuclide}" ' 'is not one of the nuclides') @@ -1721,7 +1077,7 @@ class Tally(IDManagerMixin): """ - cv.check_type('filters', filters, Iterable, FilterMeta) + cv.check_type('filters', filters, Iterable, openmc.FilterMeta) cv.check_type('filter_bins', filter_bins, Iterable, tuple) # If user did not specify any specific Filters, use them all @@ -1804,7 +1160,7 @@ class Tally(IDManagerMixin): """ for score in scores: - if not isinstance(score, (str, CrossScore)): + if not isinstance(score, (str, openmc.CrossScore)): msg = f'Unable to get score indices for score "{score}" in ' \ f'ID="{self.id}" since it is not a string or CrossScore ' \ 'Tally' @@ -1878,9 +1234,7 @@ class Tally(IDManagerMixin): (value == 'std_dev' and self.std_dev is None) or \ (value == 'rel_err' and self.mean is None) or \ (value == 'sum' and self.sum is None) or \ - (value == 'sum_sq' and self.sum_sq is None) or \ - (value == "sum_third" and self.sum_third is None) or \ - (value == "sum_fourth" and self.sum_fourth is None): + (value == 'sum_sq' and self.sum_sq is None): msg = f'The Tally ID="{self.id}" has no data to return' raise ValueError(msg) @@ -1903,14 +1257,10 @@ class Tally(IDManagerMixin): data = self.sum[indices] elif value == 'sum_sq': data = self.sum_sq[indices] - elif value == "sum_third": - data = self.sum_third[indices] - elif value == "sum_fourth": - data = self.sum_fourth[indices] else: msg = f'Unable to return results from Tally ID="{value}" since ' \ f'the requested value "{self.id}" is not \'mean\', ' \ - '\'std_dev\', \'rel_err\', \'sum\', \'sum_sq\', \'sum_third\' or \'sum_fourth\'' + '\'std_dev\', \'rel_err\', \'sum\', or \'sum_sq\'' raise LookupError(msg) return data @@ -1984,7 +1334,9 @@ class Tally(IDManagerMixin): column_name = 'nuclide' for nuclide in self.nuclides: - if isinstance(nuclide, openmc.AggregateNuclide): + if isinstance(nuclide, openmc.Nuclide): + nuclides.append(nuclide.name) + elif isinstance(nuclide, openmc.AggregateNuclide): nuclides.append(nuclide.name) column_name = f'{nuclide.aggregate_op}(nuclide)' else: @@ -2001,9 +1353,9 @@ class Tally(IDManagerMixin): column_name = 'score' for score in self.scores: - if isinstance(score, (str, CrossScore)): + if isinstance(score, (str, openmc.CrossScore)): scores.append(str(score)) - elif isinstance(score, AggregateScore): + elif isinstance(score, openmc.AggregateScore): scores.append(score.name) column_name = f'{score.aggregate_op}(score)' @@ -2026,7 +1378,7 @@ class Tally(IDManagerMixin): # Expand the columns into Pandas MultiIndices for readability if pd.__version__ >= '0.16': - columns = copy.deepcopy(list(df.columns.values)) + columns = copy.deepcopy(df.columns.values) # Convert all elements in columns list to tuples for i, column in enumerate(columns): @@ -2048,12 +1400,12 @@ class Tally(IDManagerMixin): df.columns = pd.MultiIndex.from_tuples(columns) # Modify the df.to_string method so that it prints formatted strings. - # Credit to https://stackoverflow.com/users/3657742/chrisb for this trick + # Credit to http://stackoverflow.com/users/3657742/chrisb for this trick df.to_string = partial(df.to_string, float_format=float_format.format) return df - def get_reshaped_data(self, value='mean', expand_dims=False): + def get_reshaped_data(self, value='mean'): """Returns an array of tally data with one dimension per filter. The tally data in OpenMC is stored as a 3D array with the dimensions @@ -2065,26 +1417,17 @@ class Tally(IDManagerMixin): This builds and returns a reshaped version of the tally data array with unique dimensions corresponding to each tally filter. For example, - suppose this tally has arrays of data with shape (30,5,5) corresponding - to two filters (2 and 15 bins, respectively), five nuclides and five + suppose this tally has arrays of data with shape (8,5,5) corresponding + to two filters (2 and 4 bins, respectively), five nuclides and five scores. This method will return a version of the data array with the - with a new shape of (2,15,5,5) such that the first two dimensions - correspond directly to the two filters with two and fifteen bins. If - expand_dims is True and our filter above with 15 bins is an instance of - :class:`openmc.MeshFilter` with a shape of (3,5,1). The resulting tally - data array will have a new shape of (2,3,5,1,5,5). + with a new shape of (2,4,5,5) such that the first two dimensions + correspond directly to the two filters with two and four bins. Parameters ---------- value : str A string for the type of value to return - 'mean' (default), 'std_dev', 'rel_err', 'sum', or 'sum_sq' are accepted - expand_dims : bool, optional - Whether or not to expand the dimensions of filters with multiple - dimensions. This will result in more than one dimension per filter - for the returned data array. - - .. versionadded:: 0.13.3 Returns ------- @@ -2096,32 +1439,12 @@ class Tally(IDManagerMixin): # Get the 3D array of data in filters, nuclides and scores data = self.get_values(value=value) - # Build a new array shape with one dimension per filter or expand - # multidimensional filters if desired - new_shape = tuple() - idx0 = None - for i, f in enumerate(self.filters): - if expand_dims: - # Mesh filter indices are backwards so we need to flip them - if type(f) in {MeshFilter, MeshBornFilter}: - fshape = f.shape[::-1] - new_shape += fshape - idx0, idx1 = i, i + len(fshape) - 1 - else: - new_shape += f.shape - else: - new_shape += (np.prod(f.shape),) - + # Build a new array shape with one dimension per filter + new_shape = tuple(f.num_bins for f in self.filters) new_shape += (self.num_nuclides, self.num_scores) # Reshape the data with one dimension for each filter data = np.reshape(data, new_shape) - - # If we had a MeshFilter we should swap the axes to have the same shape - # for the data and the filter - if idx0 is not None: - data = np.swapaxes(data, idx0, idx1) - return data def hybrid_product(self, other, binary_op, filter_product=None, @@ -2290,7 +1613,7 @@ class Tally(IDManagerMixin): else: all_filters = [self_copy.filters, other_copy.filters] for self_filter, other_filter in product(*all_filters): - new_filter = CrossFilter(self_filter, other_filter, + new_filter = openmc.CrossFilter(self_filter, other_filter, binary_op) new_tally.filters.append(new_filter) @@ -2301,7 +1624,7 @@ class Tally(IDManagerMixin): else: all_nuclides = [self_copy.nuclides, other_copy.nuclides] for self_nuclide, other_nuclide in product(*all_nuclides): - new_nuclide = CrossNuclide(self_nuclide, other_nuclide, + new_nuclide = openmc.CrossNuclide(self_nuclide, other_nuclide, binary_op) new_tally.nuclides.append(new_nuclide) @@ -2312,9 +1635,9 @@ class Tally(IDManagerMixin): if score1 == score2: return score1 else: - return CrossScore(score1, score2, binary_op) + return openmc.CrossScore(score1, score2, binary_op) else: - return CrossScore(score1, score2, binary_op) + return openmc.CrossScore(score1, score2, binary_op) # Add scores to the new tally if score_product == 'entrywise': @@ -2523,16 +1846,16 @@ class Tally(IDManagerMixin): # Construct lists of tuples for the bins in each of the two filters filters = [type(filter1), type(filter2)] - if isinstance(filter1, DistribcellFilter): + if isinstance(filter1, openmc.DistribcellFilter): filter1_bins = [b for b in range(filter1.num_bins)] - elif isinstance(filter1, EnergyFunctionFilter): + elif isinstance(filter1, openmc.EnergyFunctionFilter): filter1_bins = [None] else: filter1_bins = filter1.bins - if isinstance(filter2, DistribcellFilter): + if isinstance(filter2, openmc.DistribcellFilter): filter2_bins = [b for b in range(filter2.num_bins)] - elif isinstance(filter2, EnergyFunctionFilter): + elif isinstance(filter2, openmc.EnergyFunctionFilter): filter2_bins = [None] else: filter2_bins = filter2.bins @@ -2665,11 +1988,11 @@ class Tally(IDManagerMixin): raise ValueError(msg) # Check that the scores are valid - if not isinstance(score1, (str, CrossScore)): + if not isinstance(score1, (str, openmc.CrossScore)): msg = 'Unable to swap score1 "{}" in Tally ID="{}" since it is ' \ 'not a string or CrossScore'.format(score1, self.id) raise ValueError(msg) - elif not isinstance(score2, (str, CrossScore)): + elif not isinstance(score2, (str, openmc.CrossScore)): msg = 'Unable to swap score2 "{}" in Tally ID="{}" since it is ' \ 'not a string or CrossScore'.format(score2, self.id) raise ValueError(msg) @@ -2774,7 +2097,7 @@ class Tally(IDManagerMixin): new_tally.sparse = self.sparse else: - msg = f'Unable to add "{other}" to Tally ID="{self.id}"' + msg = 'Unable to add "{}" to Tally ID="{}"'.format(other, self.id) raise ValueError(msg) return new_tally @@ -2845,7 +2168,7 @@ class Tally(IDManagerMixin): new_tally.sparse = self.sparse else: - msg = f'Unable to subtract "{other}" from Tally ID="{self.id}"' + msg = 'Unable to subtract "{}" from Tally ID="{}"'.format(other, self.id) raise ValueError(msg) return new_tally @@ -2916,7 +2239,7 @@ class Tally(IDManagerMixin): new_tally.sparse = self.sparse else: - msg = f'Unable to multiply Tally ID="{self.id}" by "{other}"' + msg = 'Unable to multiply Tally ID="{}" by "{}"'.format(self.id, other) raise ValueError(msg) return new_tally @@ -2975,8 +2298,7 @@ class Tally(IDManagerMixin): new_tally.name = self.name new_tally._mean = self.mean / other new_tally._std_dev = self.std_dev * np.abs(1. / other) - if self.estimator is not None: - new_tally.estimator = self.estimator + new_tally.estimator = self.estimator new_tally.with_summary = self.with_summary new_tally.num_realizations = self.num_realizations @@ -2988,7 +2310,7 @@ class Tally(IDManagerMixin): new_tally.sparse = self.sparse else: - msg = f'Unable to divide Tally ID="{self.id}" by "{other}"' + msg = 'Unable to divide Tally ID="{}" by "{}"'.format(self.id, other) raise ValueError(msg) return new_tally @@ -3063,7 +2385,7 @@ class Tally(IDManagerMixin): new_tally.sparse = self.sparse else: - msg = f'Unable to raise Tally ID="{self.id}" to power "{power}"' + msg = 'Unable to raise Tally ID="{}" to power "{}"'.format(self.id, power) raise ValueError(msg) return new_tally @@ -3240,16 +2562,6 @@ class Tally(IDManagerMixin): new_sum_sq = self.get_values(scores, filters, filter_bins, nuclides, 'sum_sq') new_tally.sum_sq = new_sum_sq - if not self.derived and self._sum_third is not None: - new_sum_third = self.get_values( - scores, filters, filter_bins, nuclides, "sum_third" - ) - new_tally._sum_third = new_sum_third - if not self.derived and self._sum_fourth is not None: - new_sum_fourth = self.get_values( - scores, filters, filter_bins, nuclides, "sum_fourth" - ) - new_tally._sum_fourth = new_sum_fourth if self.mean is not None: new_mean = self.get_values(scores, filters, filter_bins, nuclides, 'mean') @@ -3279,8 +2591,8 @@ class Tally(IDManagerMixin): # Determine the nuclide indices from any of the requested nuclides for nuclide in self.nuclides: - if nuclide not in nuclides: - nuclide_index = self.get_nuclide_index(nuclide) + if nuclide.name not in nuclides: + nuclide_index = self.get_nuclide_index(nuclide.name) nuclide_indices.append(nuclide_index) # Loop over indices in reverse to remove excluded Nuclides @@ -3313,7 +2625,7 @@ class Tally(IDManagerMixin): new_filter.bins = [f.bins[i] for i in bin_indices] # Set number of bins manually for mesh/distribcell filters - if filter_type is DistribcellFilter: + if filter_type is openmc.DistribcellFilter: new_filter._num_bins = f._num_bins # Replace existing filter with new one @@ -3379,16 +2691,16 @@ class Tally(IDManagerMixin): std_dev = self.get_reshaped_data(value='std_dev') # Sum across any filter bins specified by the user - if isinstance(filter_type, FilterMeta): + if isinstance(filter_type, openmc.FilterMeta): find_filter = self.find_filter(filter_type) # If user did not specify filter bins, sum across all bins if len(filter_bins) == 0: bin_indices = np.arange(find_filter.num_bins) - if isinstance(find_filter, DistribcellFilter): + if isinstance(find_filter, openmc.DistribcellFilter): filter_bins = np.arange(find_filter.num_bins) - elif isinstance(find_filter, EnergyFunctionFilter): + elif isinstance(find_filter, openmc.EnergyFunctionFilter): filter_bins = [None] else: filter_bins = find_filter.bins @@ -3417,7 +2729,7 @@ class Tally(IDManagerMixin): # Add AggregateFilter to the tally sum if not remove_filter: - filter_sum = AggregateFilter(self_filter, + filter_sum = openmc.AggregateFilter(self_filter, [tuple(filter_bins)], 'sum') tally_sum.filters.append(filter_sum) @@ -3440,7 +2752,7 @@ class Tally(IDManagerMixin): std_dev = np.sqrt(std_dev) # Add AggregateNuclide to the tally sum - nuclide_sum = AggregateNuclide(nuclides, 'sum') + nuclide_sum = openmc.AggregateNuclide(nuclides, 'sum') tally_sum.nuclides.append(nuclide_sum) # Add a copy of this tally's nuclides to the tally sum @@ -3458,7 +2770,7 @@ class Tally(IDManagerMixin): std_dev = np.sqrt(std_dev) # Add AggregateScore to the tally sum - score_sum = AggregateScore(scores, 'sum') + score_sum = openmc.AggregateScore(scores, 'sum') tally_sum.scores.append(score_sum) # Add a copy of this tally's scores to the tally sum @@ -3531,16 +2843,16 @@ class Tally(IDManagerMixin): std_dev = self.get_reshaped_data(value='std_dev') # Average across any filter bins specified by the user - if isinstance(filter_type, FilterMeta): + if isinstance(filter_type, openmc.FilterMeta): find_filter = self.find_filter(filter_type) # If user did not specify filter bins, average across all bins if len(filter_bins) == 0: bin_indices = np.arange(find_filter.num_bins) - if isinstance(find_filter, DistribcellFilter): + if isinstance(find_filter, openmc.DistribcellFilter): filter_bins = np.arange(find_filter.num_bins) - elif isinstance(find_filter, EnergyFunctionFilter): + elif isinstance(find_filter, openmc.EnergyFunctionFilter): filter_bins = [None] else: filter_bins = find_filter.bins @@ -3570,7 +2882,7 @@ class Tally(IDManagerMixin): # Add AggregateFilter to the tally avg if not remove_filter: - filter_sum = AggregateFilter(self_filter, + filter_sum = openmc.AggregateFilter(self_filter, [tuple(filter_bins)], 'avg') tally_avg.filters.append(filter_sum) @@ -3594,7 +2906,7 @@ class Tally(IDManagerMixin): std_dev = np.sqrt(std_dev) # Add AggregateNuclide to the tally avg - nuclide_avg = AggregateNuclide(nuclides, 'avg') + nuclide_avg = openmc.AggregateNuclide(nuclides, 'avg') tally_avg.nuclides.append(nuclide_avg) # Add a copy of this tally's nuclides to the tally avg @@ -3613,7 +2925,7 @@ class Tally(IDManagerMixin): std_dev = np.sqrt(std_dev) # Add AggregateScore to the tally avg - score_sum = AggregateScore(scores, 'avg') + score_sum = openmc.AggregateScore(scores, 'avg') tally_avg.scores.append(score_sum) # Add a copy of this tally's scores to the tally avg @@ -3690,12 +3002,6 @@ class Tally(IDManagerMixin): if not self.derived and self.sum_sq is not None: new_tally._sum_sq = np.zeros(new_tally.shape, dtype=np.float64) new_tally._sum_sq[diag_indices, :, :] = self.sum_sq - if not self.derived and self._sum_third is not None: - new_tally._sum_third = np.zeros(new_tally.shape, dtype=np.float64) - new_tally._sum_third[diag_indices, :, :] = self.sum_third - if not self.derived and self._sum_fourth is not None: - new_tally._sum_fourth = np.zeros(new_tally.shape, dtype=np.float64) - new_tally._sum_fourth[diag_indices, :, :] = self.sum_fourth if self.mean is not None: new_tally._mean = np.zeros(new_tally.shape, dtype=np.float64) new_tally._mean[diag_indices, :, :] = self.mean @@ -3746,17 +3052,44 @@ class Tallies(cv.CheckedList): if possible. Defaults to False. """ + if not isinstance(tally, Tally): + msg = 'Unable to add a non-Tally "{}" to the ' \ + 'Tallies instance'.format(tally) + raise TypeError(msg) + if merge: + merged = False + # Look for a tally to merge with this one for i, tally2 in enumerate(self): + # If a mergeable tally is found if tally2.can_merge(tally): # Replace tally2 with the merged tally merged_tally = tally2.merge(tally) self[i] = merged_tally - return + merged = True + break - super().append(tally) + # If no mergeable tally was found, simply add this tally + if not merged: + super().append(tally) + + else: + super().append(tally) + + def insert(self, index, item): + """Insert tally before index + + Parameters + ---------- + index : int + Index in list + item : openmc.Tally + Tally to insert + + """ + super().insert(index, item) def merge_tallies(self): """Merge any mergeable tallies together. Note that n-way merges are @@ -3782,34 +3115,21 @@ class Tallies(cv.CheckedList): # Continue iterating from the first loop break - def add_results(self, statepoint: cv.PathLike | openmc.StatePoint): - """Add results from the provided statepoint file - - .. versionadded:: 0.15.1 - - Parameters - ---------- - statepoint : openmc.PathLike or openmc.StatePoint - Statepoint used to update tally results - """ - for tally in self: - tally.add_results(statepoint) - def _create_tally_subelements(self, root_element): for tally in self: root_element.append(tally.to_xml_element()) - def _create_mesh_subelements(self, root_element, memo=None): - already_written = memo if memo else set() + def _create_mesh_subelements(self, root_element): + already_written = set() for tally in self: for f in tally.filters: - if isinstance(f, MeshFilter): - if f.mesh.id in already_written: - continue - if len(f.mesh.name) > 0: - root_element.append(ET.Comment(f.mesh.name)) - root_element.append(f.mesh.to_xml_element()) - already_written.add(f.mesh.id) + if isinstance(f, openmc.MeshFilter): + if f.mesh.id not in already_written: + if len(f.mesh.name) > 0: + root_element.append(ET.Comment(f.mesh.name)) + + root_element.append(f.mesh.to_xml_element()) + already_written.add(f.mesh.id) def _create_filter_subelements(self, root_element): already_written = dict() @@ -3835,21 +3155,6 @@ class Tallies(cv.CheckedList): for d in derivs: root_element.append(d.to_xml_element()) - def to_xml_element(self, memo=None): - """Creates a 'tallies' element to be written to an XML file. - """ - memo = memo if memo is not None else set() - element = ET.Element("tallies") - self._create_mesh_subelements(element, memo) - self._create_filter_subelements(element) - self._create_tally_subelements(element) - self._create_derivative_subelements(element) - - # Clean the indentation in the file to be user-readable - clean_indentation(element) - - return element - def export_to_xml(self, path='tallies.xml'): """Create a tallies.xml file that can be used for a simulation. @@ -3859,7 +3164,15 @@ class Tallies(cv.CheckedList): Path to file to write. Defaults to 'tallies.xml'. """ - root_element = self.to_xml_element() + + root_element = ET.Element("tallies") + self._create_mesh_subelements(root_element) + self._create_filter_subelements(root_element) + self._create_tally_subelements(root_element) + self._create_derivative_subelements(root_element) + + # Clean the indentation in the file to be user-readable + clean_indentation(root_element) # Check if path is a directory p = Path(path) @@ -3867,56 +3180,10 @@ class Tallies(cv.CheckedList): p /= 'tallies.xml' # Write the XML Tree to the tallies.xml file + reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') - @classmethod - def from_xml_element(cls, elem, meshes=None): - """Generate tallies from an XML element - - Parameters - ---------- - elem : lxml.etree._Element - XML element - meshes : dict or None - A dictionary with mesh IDs as keys and mesh instances as values that - have already been read from XML. Pre-existing meshes are used - and new meshes are added to when creating tally objects. - - Returns - ------- - openmc.Tallies - Tallies object - - """ - # Read mesh elements - meshes = {} if meshes is None else meshes - for e in elem.findall('mesh'): - mesh = MeshBase.from_xml_element(e) - meshes[mesh.id] = mesh - - # Read filter elements - filters = {} - for e in elem.findall('filter'): - filter = Filter.from_xml_element(e, meshes=meshes) - filters[filter.id] = filter - - # Read derivative elements - derivatives = {} - for e in elem.findall('derivative'): - deriv = openmc.TallyDerivative.from_xml_element(e) - derivatives[deriv.id] = deriv - - # Read tally elements - tallies = [] - for e in elem.findall('tally'): - tally = openmc.Tally.from_xml_element( - e, filters=filters, derivatives=derivatives - ) - tallies.append(tally) - - return cls(tallies) - @classmethod def from_xml(cls, path='tallies.xml'): """Generate tallies from XML file @@ -3932,7 +3199,33 @@ class Tallies(cv.CheckedList): Tallies object """ - parser = ET.XMLParser(huge_tree=True) - tree = ET.parse(path, parser=parser) + tree = ET.parse(path) root = tree.getroot() - return cls.from_xml_element(root) + + # Read mesh elements + meshes = {} + for elem in root.findall('mesh'): + mesh = MeshBase.from_xml_element(elem) + meshes[mesh.id] = mesh + + # Read filter elements + filters = {} + for elem in root.findall('filter'): + filter = openmc.Filter.from_xml_element(elem, meshes=meshes) + filters[filter.id] = filter + + # Read derivative elements + derivatives = {} + for elem in root.findall('derivative'): + deriv = openmc.TallyDerivative.from_xml_element(elem) + derivatives[deriv.id] = deriv + + # Read tally elements + tallies = [] + for elem in root.findall('tally'): + tally = openmc.Tally.from_xml_element( + elem, filters=filters, derivatives=derivatives + ) + tallies.append(tally) + + return cls(tallies) diff --git a/openmc/tally_derivative.py b/openmc/tally_derivative.py index f7ba5dce5..05a27681d 100644 --- a/openmc/tally_derivative.py +++ b/openmc/tally_derivative.py @@ -1,10 +1,8 @@ from numbers import Integral - -import lxml.etree as ET +from xml.etree import ElementTree as ET import openmc.checkvalue as cv from .mixin import EqualityMixin, IDManagerMixin -from ._xml import get_text class TallyDerivative(EqualityMixin, IDManagerMixin): @@ -62,6 +60,14 @@ class TallyDerivative(EqualityMixin, IDManagerMixin): def variable(self): return self._variable + @property + def material(self): + return self._material + + @property + def nuclide(self): + return self._nuclide + @variable.setter def variable(self, var): if var is not None: @@ -70,20 +76,12 @@ class TallyDerivative(EqualityMixin, IDManagerMixin): ('density', 'nuclide_density', 'temperature')) self._variable = var - @property - def material(self): - return self._material - @material.setter def material(self, mat): if mat is not None: cv.check_type('derivative material', mat, Integral) self._material = mat - @property - def nuclide(self): - return self._nuclide - @nuclide.setter def nuclide(self, nuc): if nuc is not None: @@ -95,7 +93,7 @@ class TallyDerivative(EqualityMixin, IDManagerMixin): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing derivative data """ @@ -114,7 +112,7 @@ class TallyDerivative(EqualityMixin, IDManagerMixin): Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -123,8 +121,8 @@ class TallyDerivative(EqualityMixin, IDManagerMixin): Tally derivative object """ - derivative_id = int(get_text(elem, "id")) - variable = get_text(elem, "variable") - material = int(get_text(elem, "material")) - nuclide = get_text(elem, "nuclide") if variable == "nuclide_density" else None + derivative_id = int(elem.get("id")) + variable = elem.get("variable") + material = int(elem.get("material")) + nuclide = elem.get("nuclide") if variable == "nuclide_density" else None return cls(derivative_id, variable, material, nuclide) diff --git a/openmc/tracks.py b/openmc/tracks.py index 44e3c0eba..9b4b55247 100644 --- a/openmc/tracks.py +++ b/openmc/tracks.py @@ -4,8 +4,7 @@ from collections.abc import Sequence import h5py from .checkvalue import check_filetype_version -from .particle_type import ParticleType -from .source import SourceParticle +from .source import SourceParticle, ParticleType from pathlib import Path @@ -26,7 +25,8 @@ states : numpy.ndarray """ def _particle_track_repr(self): - return f"" + name = self.particle.name.lower() + return f"" ParticleTrack.__repr__ = _particle_track_repr @@ -93,8 +93,8 @@ class Track(Sequence): Parameters ---------- - particle : str or int or openmc.ParticleType - Matching particle type (name, PDG number, or type) + particle : {'neutron', 'photon', 'electron', 'positron'} + Matching particle type state_filter : function Function that takes a state (structured datatype) and returns a bool depending on some criteria. @@ -127,7 +127,7 @@ class Track(Sequence): for t in self: # Check for matching particle if particle is not None: - if t.particle != ParticleType(particle): + if t.particle.name.lower() != particle: continue # Apply arbitrary state filter @@ -185,7 +185,7 @@ class Track(Sequence): def sources(self): sources = [] for particle_track in self: - particle_type = particle_track.particle + particle_type = ParticleType(particle_track.particle) state = particle_track.states[0] sources.append( SourceParticle( @@ -297,16 +297,16 @@ class Tracks(list): for state in pt.states: points.InsertNextPoint(state['r']) - # Create VTK line and assign points to line. - n = pt.states.size - line = vtk.vtkPolyLine() - line.GetPointIds().SetNumberOfIds(n) - for i in range(n): - line.GetPointIds().SetId(i, point_offset + i) - point_offset += n + # Create VTK line and assign points to line. + n = pt.states.size + line = vtk.vtkPolyLine() + line.GetPointIds().SetNumberOfIds(n) + for i in range(n): + line.GetPointIds().SetId(i, point_offset + i) + point_offset += n - # Add line to cell array - cells.InsertNextCell(line) + # Add line to cell array + cells.InsertNextCell(line) data = vtk.vtkPolyData() data.SetPoints(points) diff --git a/openmc/trigger.py b/openmc/trigger.py index 70b6b7a03..c5151aa7e 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -1,11 +1,9 @@ from collections.abc import Iterable from numbers import Real - -import lxml.etree as ET +from xml.etree import ElementTree as ET import openmc.checkvalue as cv from .mixin import EqualityMixin -from ._xml import get_elem_list, get_text class Trigger(EqualityMixin): @@ -18,12 +16,6 @@ class Trigger(EqualityMixin): relative error of scores. threshold : float The threshold for the trigger type. - ignore_zeros : bool - Whether to allow zero tally bins to be ignored. Note that this option - can cause the trigger to fire prematurely if there are zero scores in - any bin at the first evaluation. - - .. versionadded:: 0.15.0 Attributes ---------- @@ -34,22 +26,18 @@ class Trigger(EqualityMixin): The threshold for the trigger type. scores : list of str Scores which should be checked against the trigger - ignore_zeros : bool - Whether to allow zero tally bins to be ignored. """ - def __init__(self, trigger_type: str, threshold: float, ignore_zeros: bool = False): + def __init__(self, trigger_type, threshold): self.trigger_type = trigger_type self.threshold = threshold - self.ignore_zeros = ignore_zeros self._scores = [] def __repr__(self): string = 'Trigger\n' string += '{: <16}=\t{}\n'.format('\tType', self._trigger_type) string += '{: <16}=\t{}\n'.format('\tThreshold', self._threshold) - string += '{: <16}=\t{}\n'.format('\tIgnore Zeros', self._ignore_zeros) string += '{: <16}=\t{}\n'.format('\tScores', self._scores) return string @@ -57,34 +45,25 @@ class Trigger(EqualityMixin): def trigger_type(self): return self._trigger_type + @property + def threshold(self): + return self._threshold + + @property + def scores(self): + return self._scores + @trigger_type.setter def trigger_type(self, trigger_type): cv.check_value('tally trigger type', trigger_type, ['variance', 'std_dev', 'rel_err']) self._trigger_type = trigger_type - @property - def threshold(self): - return self._threshold - @threshold.setter def threshold(self, threshold): cv.check_type('tally trigger threshold', threshold, Real) self._threshold = threshold - @property - def ignore_zeros(self): - return self._ignore_zeros - - @ignore_zeros.setter - def ignore_zeros(self, ignore_zeros): - cv.check_type('tally trigger ignores zeros', ignore_zeros, bool) - self._ignore_zeros = ignore_zeros - - @property - def scores(self): - return self._scores - @scores.setter def scores(self, scores): cv.check_type('trigger scores', scores, Iterable, str) @@ -100,7 +79,7 @@ class Trigger(EqualityMixin): Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing trigger data """ @@ -108,19 +87,17 @@ class Trigger(EqualityMixin): element = ET.Element("trigger") element.set("type", self._trigger_type) element.set("threshold", str(self._threshold)) - if self._ignore_zeros: - element.set("ignore_zeros", "true") if len(self._scores) != 0: element.set("scores", ' '.join(self._scores)) return element @classmethod - def from_xml_element(cls, elem: ET.Element): + def from_xml_element(cls, elem): """Generate trigger object from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -130,16 +107,13 @@ class Trigger(EqualityMixin): """ # Generate trigger object - trigger_type = get_text(elem, "type") - threshold = float(get_text(elem, "threshold")) - ignore_zeros = str(get_text(elem, "ignore_zeros", "false")).lower() - # Try to convert to bool. Let Trigger error out on instantiation. - ignore_zeros = ignore_zeros in ('true', '1') - trigger = cls(trigger_type, threshold, ignore_zeros) + trigger_type = elem.get("type") + threshold = float(elem.get("threshold")) + trigger = cls(trigger_type, threshold) # Add scores if present - scores = get_elem_list(elem, "scores", str) + scores = elem.get("scores") if scores is not None: - trigger.scores = scores + trigger.scores = scores.split() return trigger diff --git a/openmc/universe.py b/openmc/universe.py index 0e64693ba..081fff4ff 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -1,14 +1,23 @@ -from __future__ import annotations from abc import ABC, abstractmethod +from collections import OrderedDict from collections.abc import Iterable -from numbers import Real +from copy import deepcopy +from numbers import Integral, Real +from pathlib import Path +from tempfile import TemporaryDirectory +from xml.etree import ElementTree as ET +import h5py import numpy as np import openmc import openmc.checkvalue as cv + +from ._xml import get_text +from .checkvalue import check_type, check_value from .mixin import IDManagerMixin -from .plots import add_plot_params +from .plots import _SVG_COLORS +from .surface import _BOUNDARY_TYPES class UniverseBase(ABC, IDManagerMixin): @@ -34,7 +43,7 @@ class UniverseBase(ABC, IDManagerMixin): # Keys - Cell IDs # Values - Cells - self._cells = {} + self._cells = OrderedDict() def __repr__(self): string = 'Universe\n' @@ -47,8 +56,8 @@ class UniverseBase(ABC, IDManagerMixin): return self._name @property - def cells(self): - return self._cells + def volume(self): + return self._volume @name.setter def name(self, name): @@ -58,10 +67,6 @@ class UniverseBase(ABC, IDManagerMixin): else: self._name = '' - @property - def volume(self): - return self._volume - @volume.setter def volume(self, volume): if volume is not None: @@ -82,41 +87,17 @@ class UniverseBase(ABC, IDManagerMixin): self._volume = volume_calc.volumes[self.id].n self._atoms = volume_calc.atoms[self.id] else: - raise ValueError( - 'No volume information found for this universe.') + raise ValueError('No volume information found for this universe.') else: raise ValueError('No volume information found for this universe.') - def get_all_universes(self, memo=None): - """Return all universes that are contained within this one. - - Returns - ------- - universes : dict - Dictionary whose keys are universe IDs and values are - :class:`Universe` instances - - """ - if memo is None: - memo = set() - elif self in memo: - return {} - memo.add(self) - - # Append all Universes within each Cell to the dictionary - universes = {} - for cell in self.get_all_cells().values(): - universes.update(cell.get_all_universes(memo)) - - return universes - @abstractmethod def create_xml_subelement(self, xml_element, memo=None): """Add the universe xml representation to an incoming xml element Parameters ---------- - xml_element : lxml.etree._Element + xml_element : xml.etree.ElementTree.Element XML element to be added to memo : set or None @@ -130,137 +111,6 @@ class UniverseBase(ABC, IDManagerMixin): """ - def _determine_paths(self, path='', instances_only=False): - """Count the number of instances for each cell in the universe, and - record the count in the :attr:`Cell.num_instances` properties.""" - - univ_path = path + f'u{self.id}' - - for cell in self.cells.values(): - cell_path = f'{univ_path}->c{cell.id}' - fill = cell._fill - fill_type = cell.fill_type - - # If universe-filled, recursively count cells in filling universe - if fill_type == 'universe': - fill._determine_paths(cell_path + '->', instances_only) - # If lattice-filled, recursively call for all universes in lattice - elif fill_type == 'lattice': - latt = fill - - # Count instances in each universe in the lattice - for index in latt._natural_indices: - latt_path = '{}->l{}({})->'.format( - cell_path, latt.id, ",".join(str(x) for x in index)) - univ = latt.get_universe(index) - univ._determine_paths(latt_path, instances_only) - - else: - if fill_type == 'material': - mat = fill - elif fill_type == 'distribmat': - mat = fill[cell._num_instances] - else: - mat = None - - if mat is not None: - mat._num_instances += 1 - if not instances_only: - mat._paths.append(f'{cell_path}->m{mat.id}') - - # Append current path - cell._num_instances += 1 - if not instances_only: - cell._paths.append(cell_path) - - def add_cells(self, cells): - """Add multiple cells to the universe. - - Parameters - ---------- - cells : Iterable of openmc.Cell - Cells to add - - """ - - if not isinstance(cells, Iterable): - msg = f'Unable to add Cells to Universe ID="{self._id}" since ' \ - f'"{cells}" is not iterable' - raise TypeError(msg) - - for cell in cells: - self.add_cell(cell) - - @abstractmethod - def add_cell(self, cell): - pass - - @abstractmethod - def remove_cell(self, cell): - pass - - def clear_cells(self): - """Remove all cells from the universe.""" - - self._cells.clear() - - def get_all_cells(self, memo=None): - """Return all cells that are contained within the universe - - Returns - ------- - cells : dict - Dictionary whose keys are cell IDs and values are :class:`Cell` - instances - - """ - - if memo is None: - memo = set() - elif self in memo: - return {} - memo.add(self) - - # Add this Universe's cells to the dictionary - cells = {} - cells.update(self._cells) - - # Append all Cells in each Cell in the Universe to the dictionary - for cell in self._cells.values(): - cells.update(cell.get_all_cells(memo)) - - return cells - - def get_all_materials(self, memo=None): - """Return all materials that are contained within the universe - - Returns - ------- - materials : dict - Dictionary whose keys are material IDs and values are - :class:`Material` instances - - """ - - if memo is None: - memo = set() - - materials = {} - - # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells(memo) - for cell in cells.values(): - materials.update(cell.get_all_materials(memo)) - - return materials - - @abstractmethod - def _partial_deepcopy(self): - """Deepcopy all parameters of an openmc.UniverseBase object except its cells. - This should only be used from the openmc.UniverseBase.clone() context. - - """ - def clone(self, clone_materials=True, clone_regions=True, memo=None): """Create a copy of this universe with a new unique ID, and clones all cells within this universe. @@ -288,19 +138,108 @@ class UniverseBase(ABC, IDManagerMixin): # If no memoize'd clone exists, instantiate one if self not in memo: - clone = self._partial_deepcopy() + clone = deepcopy(self) + clone.id = None # Clone all cells for the universe clone - clone._cells = {} + clone._cells = OrderedDict() for cell in self._cells.values(): clone.add_cell(cell.clone(clone_materials, clone_regions, - memo)) + memo)) # Memoize the clone memo[self] = clone return memo[self] + +class Universe(UniverseBase): + """A collection of cells that can be repeated. + + Parameters + ---------- + universe_id : int, optional + Unique identifier of the universe. If not specified, an identifier will + automatically be assigned + name : str, optional + Name of the universe. If not specified, the name is the empty string. + cells : Iterable of openmc.Cell, optional + Cells to add to the universe. By default no cells are added. + + Attributes + ---------- + id : int + Unique identifier of the universe + name : str + Name of the universe + cells : collections.OrderedDict + Dictionary whose keys are cell IDs and values are :class:`Cell` + instances + volume : float + Volume of the universe in cm^3. This can either be set manually or + calculated in a stochastic volume calculation and added via the + :meth:`Universe.add_volume_information` method. + bounding_box : 2-tuple of numpy.array + Lower-left and upper-right coordinates of an axis-aligned bounding box + of the universe. + + """ + + def __init__(self, universe_id=None, name='', cells=None): + super().__init__(universe_id, name) + + if cells is not None: + self.add_cells(cells) + + def __repr__(self): + string = super().__repr__() + string += '{: <16}=\t{}\n'.format('\tGeom', 'CSG') + string += '{: <16}=\t{}\n'.format('\tCells', list(self._cells.keys())) + return string + + @property + def cells(self): + return self._cells + + @property + def bounding_box(self): + regions = [c.region for c in self.cells.values() + if c.region is not None] + if regions: + return openmc.Union(regions).bounding_box + else: + # Infinite bounding box + return openmc.Intersection([]).bounding_box + + @classmethod + def from_hdf5(cls, group, cells): + """Create universe from HDF5 group + + Parameters + ---------- + group : h5py.Group + Group in HDF5 file + cells : dict + Dictionary mapping cell IDs to instances of :class:`openmc.Cell`. + + Returns + ------- + openmc.Universe + Universe instance + + """ + universe_id = int(group.name.split('/')[-1].lstrip('universe ')) + cell_ids = group['cells'][()] + + # Create this Universe + universe = cls(universe_id) + + # Add each Cell to the Universe + for cell_id in cell_ids: + universe.add_cell(cells[cell_id]) + + return universe + def find(self, point): """Find cells/universes/lattices which contain a given point @@ -331,13 +270,166 @@ class UniverseBase(ABC, IDManagerMixin): return [self, cell] + cell.fill.find(p) return [] - @add_plot_params - def plot(self, *args, **kwargs): + def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200), + basis='xy', color_by='cell', colors=None, seed=None, + openmc_exec='openmc', **kwargs): """Display a slice plot of the universe. + + Parameters + ---------- + origin : Iterable of float + Coordinates at the origin of the plot + width : Iterable of float + Width of the plot in each basis direction + pixels : Iterable of int + Number of pixels to use in each basis direction + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot + color_by : {'cell', 'material'} + Indicate whether the plot should be colored by cell or by material + colors : dict + Assigns colors to specific materials or cells. Keys are instances of + :class:`Cell` or :class:`Material` and values are RGB 3-tuples, RGBA + 4-tuples, or strings indicating SVG color names. Red, green, blue, + and alpha should all be floats in the range [0.0, 1.0], for example: + + .. code-block:: python + + # Make water blue + water = openmc.Cell(fill=h2o) + universe.plot(..., colors={water: (0., 0., 1.)) + seed : int + Seed for the random number generator + openmc_exec : str + Path to OpenMC executable. + + .. versionadded:: 0.13.1 + **kwargs + Keyword arguments passed to :func:`matplotlib.pyplot.imshow` + + Returns + ------- + matplotlib.image.AxesImage + Resulting image + """ - model = openmc.Model() - model.geometry = openmc.Geometry(self) - return model.plot(*args, **kwargs) + import matplotlib.image as mpimg + import matplotlib.pyplot as plt + + # Determine extents of plot + if basis == 'xy': + x, y = 0, 1 + elif basis == 'yz': + x, y = 1, 2 + elif basis == 'xz': + x, y = 0, 2 + x_min = origin[x] - 0.5*width[0] + x_max = origin[x] + 0.5*width[0] + y_min = origin[y] - 0.5*width[1] + y_max = origin[y] + 0.5*width[1] + + with TemporaryDirectory() as tmpdir: + model = openmc.Model() + model.geometry = openmc.Geometry(self) + if seed is not None: + model.settings.seed = seed + + # Determine whether any materials contains macroscopic data and if + # so, set energy mode accordingly + for mat in self.get_all_materials().values(): + if mat._macroscopic is not None: + model.settings.energy_mode = 'multi-group' + break + + # Create plot object matching passed arguments + plot = openmc.Plot() + plot.origin = origin + plot.width = width + plot.pixels = pixels + plot.basis = basis + plot.color_by = color_by + if colors is not None: + plot.colors = colors + model.plots.append(plot) + + # Run OpenMC in geometry plotting mode + model.plot_geometry(False, cwd=tmpdir, openmc_exec=openmc_exec) + + # Read image from file + img = mpimg.imread(Path(tmpdir) / f'plot_{plot.id}.png') + + # Create a figure sized such that the size of the axes within + # exactly matches the number of pixels specified + px = 1/plt.rcParams['figure.dpi'] + fig, ax = plt.subplots() + params = fig.subplotpars + width = pixels[0]*px/(params.right - params.left) + height = pixels[0]*px/(params.top - params.bottom) + fig.set_size_inches(width, height) + + # Plot image and return the axes + return ax.imshow(img, extent=(x_min, x_max, y_min, y_max), **kwargs) + + def add_cell(self, cell): + """Add a cell to the universe. + + Parameters + ---------- + cell : openmc.Cell + Cell to add + + """ + + if not isinstance(cell, openmc.Cell): + msg = f'Unable to add a Cell to Universe ID="{self._id}" since ' \ + f'"{cell}" is not a Cell' + raise TypeError(msg) + + cell_id = cell.id + + if cell_id not in self._cells: + self._cells[cell_id] = cell + + def add_cells(self, cells): + """Add multiple cells to the universe. + + Parameters + ---------- + cells : Iterable of openmc.Cell + Cells to add + + """ + + if not isinstance(cells, Iterable): + msg = f'Unable to add Cells to Universe ID="{self._id}" since ' \ + f'"{cells}" is not iterable' + raise TypeError(msg) + + for cell in cells: + self.add_cell(cell) + + def remove_cell(self, cell): + """Remove a cell from the universe. + + Parameters + ---------- + cell : openmc.Cell + Cell to remove + + """ + + if not isinstance(cell, openmc.Cell): + msg = f'Unable to remove a Cell from Universe ID="{self._id}" ' \ + f'since "{cell}" is not a Cell' + raise TypeError(msg) + + # If the Cell is in the Universe's list of Cells, delete it + self._cells.pop(cell.id, None) + + def clear_cells(self): + """Remove all cells from the universe.""" + + self._cells.clear() def get_nuclides(self): """Returns all nuclides in the universe @@ -364,18 +456,19 @@ class UniverseBase(ABC, IDManagerMixin): Returns ------- - nuclides : dict + nuclides : collections.OrderedDict Dictionary whose keys are nuclide names and values are 2-tuples of (nuclide, density) """ - nuclides = {} + nuclides = OrderedDict() - if self._atoms: + if self._atoms is not None: volume = self.volume for name, atoms in self._atoms.items(): + nuclide = openmc.Nuclide(name) density = 1.0e-24 * atoms.n/volume # density in atoms/b-cm - nuclides[name] = (name, density) + nuclides[name] = (nuclide, density) else: raise RuntimeError( 'Volume information is needed to calculate microscopic cross ' @@ -385,141 +478,81 @@ class UniverseBase(ABC, IDManagerMixin): return nuclides - - -class Universe(UniverseBase): - """A collection of cells that can be repeated. - - Parameters - ---------- - universe_id : int, optional - Unique identifier of the universe. If not specified, an identifier will - automatically be assigned - name : str, optional - Name of the universe. If not specified, the name is the empty string. - cells : Iterable of openmc.Cell, optional - Cells to add to the universe. By default no cells are added. - - Attributes - ---------- - id : int - Unique identifier of the universe - name : str - Name of the universe - cells : dict - Dictionary whose keys are cell IDs and values are :class:`Cell` - instances - volume : float - Volume of the universe in cm^3. This can either be set manually or - calculated in a stochastic volume calculation and added via the - :meth:`Universe.add_volume_information` method. - bounding_box : openmc.BoundingBox - Lower-left and upper-right coordinates of an axis-aligned bounding box - of the universe. - - """ - - def __init__(self, universe_id=None, name='', cells=None): - super().__init__(universe_id, name) - - if cells is not None: - self.add_cells(cells) - - def __repr__(self): - string = super().__repr__() - string += '{: <16}=\t{}\n'.format('\tGeom', 'CSG') - string += '{: <16}=\t{}\n'.format('\tCells', list(self._cells.keys())) - return string - - @property - def bounding_box(self) -> openmc.BoundingBox: - regions = [c.region for c in self.cells.values() - if c.region is not None] - if regions: - return openmc.Union(regions).bounding_box - else: - return openmc.BoundingBox.infinite() - - @classmethod - def from_hdf5(cls, group, cells): - """Create universe from HDF5 group - - Parameters - ---------- - group : h5py.Group - Group in HDF5 file - cells : dict - Dictionary mapping cell IDs to instances of :class:`openmc.Cell`. + def get_all_cells(self, memo=None): + """Return all cells that are contained within the universe Returns ------- - openmc.Universe - Universe instance - - """ - universe_id = int(group.name.split('/')[-1].lstrip('universe ')) - cell_ids = group['cells'][()] - - # Create this Universe - universe = cls(universe_id) - - # Add each Cell to the Universe - for cell_id in cell_ids: - universe.add_cell(cells[cell_id]) - - return universe - - - def add_cell(self, cell): - """Add a cell to the universe. - - Parameters - ---------- - cell : openmc.Cell - Cell to add + cells : collections.OrderedDict + Dictionary whose keys are cell IDs and values are :class:`Cell` + instances """ - if not isinstance(cell, openmc.Cell): - msg = f'Unable to add a Cell to Universe ID="{self._id}" since ' \ - f'"{cell}" is not a Cell' - raise TypeError(msg) + cells = OrderedDict() - cell_id = cell.id + if memo and self in memo: + return cells - if cell_id not in self._cells: - self._cells[cell_id] = cell + if memo is not None: + memo.add(self) - def remove_cell(self, cell): - """Remove a cell from the universe. + # Add this Universe's cells to the dictionary + cells.update(self._cells) - Parameters - ---------- - cell : openmc.Cell - Cell to remove + # Append all Cells in each Cell in the Universe to the dictionary + for cell in self._cells.values(): + cells.update(cell.get_all_cells(memo)) + + return cells + + def get_all_materials(self, memo=None): + """Return all materials that are contained within the universe + + Returns + ------- + materials : collections.OrderedDict + Dictionary whose keys are material IDs and values are + :class:`Material` instances """ - if not isinstance(cell, openmc.Cell): - msg = f'Unable to remove a Cell from Universe ID="{self._id}" ' \ - f'since "{cell}" is not a Cell' - raise TypeError(msg) + materials = OrderedDict() - # If the Cell is in the Universe's list of Cells, delete it - self._cells.pop(cell.id, None) + # Append all Cells in each Cell in the Universe to the dictionary + cells = self.get_all_cells(memo) + for cell in cells.values(): + materials.update(cell.get_all_materials(memo)) + + return materials + + def get_all_universes(self): + """Return all universes that are contained within this one. + + Returns + ------- + universes : collections.OrderedDict + Dictionary whose keys are universe IDs and values are + :class:`Universe` instances + + """ + # Append all Universes within each Cell to the dictionary + universes = OrderedDict() + for cell in self.get_all_cells().values(): + universes.update(cell.get_all_universes()) + + return universes def create_xml_subelement(self, xml_element, memo=None): - if memo is None: - memo = set() - # Iterate over all Cells for cell in self._cells.values(): # If the cell was already written, move on - if cell in memo: + if memo and cell in memo: continue - memo.add(cell) + if memo is not None: + memo.add(cell) # Create XML subelement for this Cell cell_element = cell.create_xml_subelement(xml_element, memo) @@ -528,11 +561,306 @@ class Universe(UniverseBase): cell_element.set("universe", str(self._id)) xml_element.append(cell_element) - def _partial_deepcopy(self): - """Clone all of the openmc.Universe object's attributes except for its cells, - as they are copied within the clone function. This should only to be - used within the openmc.UniverseBase.clone() context. + def _determine_paths(self, path='', instances_only=False): + """Count the number of instances for each cell in the universe, and + record the count in the :attr:`Cell.num_instances` properties.""" + + univ_path = path + f'u{self.id}' + + for cell in self.cells.values(): + cell_path = f'{univ_path}->c{cell.id}' + fill = cell._fill + fill_type = cell.fill_type + + # If universe-filled, recursively count cells in filling universe + if fill_type == 'universe': + fill._determine_paths(cell_path + '->', instances_only) + + # If lattice-filled, recursively call for all universes in lattice + elif fill_type == 'lattice': + latt = fill + + # Count instances in each universe in the lattice + for index in latt._natural_indices: + latt_path = '{}->l{}({})->'.format( + cell_path, latt.id, ",".join(str(x) for x in index)) + univ = latt.get_universe(index) + univ._determine_paths(latt_path, instances_only) + + else: + if fill_type == 'material': + mat = fill + elif fill_type == 'distribmat': + mat = fill[cell._num_instances] + else: + mat = None + + if mat is not None: + mat._num_instances += 1 + if not instances_only: + mat._paths.append(f'{cell_path}->m{mat.id}') + + # Append current path + cell._num_instances += 1 + if not instances_only: + cell._paths.append(cell_path) + + +class DAGMCUniverse(UniverseBase): + """A reference to a DAGMC file to be used in the model. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + filename : str + Path to the DAGMC file used to represent this universe. + universe_id : int, optional + Unique identifier of the universe. If not specified, an identifier will + automatically be assigned. + name : str, optional + Name of the universe. If not specified, the name is the empty string. + auto_geom_ids : bool + Set IDs automatically on initialization (True) or report overlaps + in ID space between CSG and DAGMC (False) + auto_mat_ids : bool + Set IDs automatically on initialization (True) or report overlaps + in ID space between OpenMC and UWUW materials (False) + + Attributes + ---------- + id : int + Unique identifier of the universe + name : str + Name of the universe + filename : str + Path to the DAGMC file used to represent this universe. + auto_geom_ids : bool + Set IDs automatically on initialization (True) or report overlaps + in ID space between CSG and DAGMC (False) + auto_mat_ids : bool + Set IDs automatically on initialization (True) or report overlaps + in ID space between OpenMC and UWUW materials (False) + bounding_box : 2-tuple of numpy.array + Lower-left and upper-right coordinates of an axis-aligned bounding box + of the universe. + + .. versionadded:: 0.13.1 + """ + + def __init__(self, + filename, + universe_id=None, + name='', + auto_geom_ids=False, + auto_mat_ids=False): + super().__init__(universe_id, name) + # Initialize class attributes + self.filename = filename + self.auto_geom_ids = auto_geom_ids + self.auto_mat_ids = auto_mat_ids + + def __repr__(self): + string = super().__repr__() + string += '{: <16}=\t{}\n'.format('\tGeom', 'DAGMC') + string += '{: <16}=\t{}\n'.format('\tFile', self.filename) + return string + + @property + def bounding_box(self): + with h5py.File(self.filename) as dagmc_file: + coords = dagmc_file['tstt']['nodes']['coordinates'][()] + lower_left_corner = coords.min(axis=0) + upper_right_corner = coords.max(axis=0) + return (lower_left_corner, upper_right_corner) + + @property + def filename(self): + return self._filename + + @filename.setter + def filename(self, val): + cv.check_type('DAGMC filename', val, (Path, str)) + self._filename = val + + @property + def auto_geom_ids(self): + return self._auto_geom_ids + + @auto_geom_ids.setter + def auto_geom_ids(self, val): + cv.check_type('DAGMC automatic geometry ids', val, bool) + self._auto_geom_ids = val + + @property + def auto_mat_ids(self): + return self._auto_mat_ids + + @auto_mat_ids.setter + def auto_mat_ids(self, val): + cv.check_type('DAGMC automatic material ids', val, bool) + self._auto_mat_ids = val + + def get_all_cells(self, memo=None): + return OrderedDict() + + def get_all_materials(self, memo=None): + return OrderedDict() + + def create_xml_subelement(self, xml_element, memo=None): + if memo and self in memo: + return + + if memo is not None: + memo.add(self) + + # Set xml element values + dagmc_element = ET.Element('dagmc_universe') + dagmc_element.set('id', str(self.id)) + + if self.auto_geom_ids: + dagmc_element.set('auto_geom_ids', 'true') + if self.auto_mat_ids: + dagmc_element.set('auto_mat_ids', 'true') + dagmc_element.set('filename', str(self.filename)) + xml_element.append(dagmc_element) + + def bounding_region(self, bounded_type='box', boundary_type='vacuum', starting_id=10000): + """Creates a either a spherical or box shaped bounding region around + the DAGMC geometry. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + bounded_type : str + The type of bounding surface(s) to use when constructing the region. + Options include a single spherical surface (sphere) or a rectangle + made from six planes (box). + boundary_type : str + Boundary condition that defines the behavior for particles hitting + the surface. Defaults to vacuum boundary condition. Passed into the + surface construction. + starting_id : int + Starting ID of the surface(s) used in the region. For bounded_type + 'box', the next 5 IDs will also be used. Defaults to 10000 to reduce + the chance of an overlap of surface IDs with the DAGMC geometry. + + Returns + ------- + openmc.Region + Region instance """ - clone = openmc.Universe(name=self.name) - clone.volume = self.volume - return clone + + check_type('boundary type', boundary_type, str) + check_value('boundary type', boundary_type, _BOUNDARY_TYPES) + check_type('starting surface id', starting_id, Integral) + check_type('bounded type', bounded_type, str) + check_value('bounded type', bounded_type, ('box', 'sphere')) + + bbox = self.bounding_box + + if bounded_type == 'sphere': + bbox_center = (bbox[0] + bbox[1])/2 + radius = np.linalg.norm(np.asarray(bbox)) + bounding_surface = openmc.Sphere( + surface_id=starting_id, + x0=bbox_center[0], + y0=bbox_center[1], + z0=bbox_center[2], + boundary_type=boundary_type, + r=radius, + ) + + return -bounding_surface + + if bounded_type == 'box': + # defines plane surfaces for all six faces of the bounding box + lower_x = openmc.XPlane(bbox[0][0], surface_id=starting_id) + upper_x = openmc.XPlane(bbox[1][0], surface_id=starting_id+1) + lower_y = openmc.YPlane(bbox[0][1], surface_id=starting_id+2) + upper_y = openmc.YPlane(bbox[1][1], surface_id=starting_id+3) + lower_z = openmc.ZPlane(bbox[0][2], surface_id=starting_id+4) + upper_z = openmc.ZPlane(bbox[1][2], surface_id=starting_id+5) + + region = +lower_x & -upper_x & +lower_y & -upper_y & +lower_z & -upper_z + + for surface in region.get_surfaces().values(): + surface.boundary_type = boundary_type + + return region + + def bounded_universe(self, bounding_cell_id=10000, **kwargs): + """Returns an openmc.Universe filled with this DAGMCUniverse and bounded + with a cell. Defaults to a box cell with a vacuum surface however this + can be changed using the kwargs which are passed directly to + DAGMCUniverse.bounding_region(). + + Parameters + ---------- + bounding_cell_id : int + The cell ID number to use for the bounding cell, defaults to 10000 to reduce + the chance of overlapping ID numbers with the DAGMC geometry. + + Returns + ------- + openmc.Universe + Universe instance + """ + bounding_cell = openmc.Cell(fill=self, cell_id=bounding_cell_id, region=self.bounding_region(**kwargs)) + return openmc.Universe(cells=[bounding_cell]) + + @classmethod + def from_hdf5(cls, group): + """Create DAGMC universe from HDF5 group + + Parameters + ---------- + group : h5py.Group + Group in HDF5 file + + Returns + ------- + openmc.DAGMCUniverse + DAGMCUniverse instance + + """ + id = int(group.name.split('/')[-1].lstrip('universe ')) + fname = group['filename'][()].decode() + name = group['name'][()].decode() if 'name' in group else None + + out = cls(fname, universe_id=id, name=name) + + out.auto_geom_ids = bool(group.attrs['auto_geom_ids']) + out.auto_mat_ids = bool(group.attrs['auto_mat_ids']) + + return out + + @classmethod + def from_xml_element(cls, elem): + """Generate DAGMC universe from XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + `` element + + Returns + ------- + openmc.DAGMCUniverse + DAGMCUniverse instance + + """ + id = int(get_text(elem, 'id')) + fname = get_text(elem, 'filename') + + out = cls(fname, universe_id=id) + + name = get_text(elem, 'name') + if name is not None: + out.name = name + + out.auto_geom_ids = bool(elem.get('auto_geom_ids')) + out.auto_mat_ids = bool(elem.get('auto_mat_ids')) + + return out diff --git a/openmc/utility_funcs.py b/openmc/utility_funcs.py deleted file mode 100644 index 935a58985..000000000 --- a/openmc/utility_funcs.py +++ /dev/null @@ -1,78 +0,0 @@ -from contextlib import contextmanager -import os -from pathlib import Path -from tempfile import TemporaryDirectory - -import h5py - -import openmc -from .checkvalue import PathLike - - -@contextmanager -def change_directory(working_dir: PathLike | None = None, *, tmpdir: bool = False): - """Context manager for executing in a provided working directory - - Parameters - ---------- - working_dir : path-like - Directory to switch to. - tmpdir : bool - Whether to use a temporary directory instead of a specific working directory - - """ - orig_dir = Path.cwd() - - # Set up temporary directory if requested - if tmpdir: - tmp = TemporaryDirectory() - working_dir = tmp.name - elif working_dir is None: - raise ValueError('Must pass working_dir argument or specify tmpdir=True.') - - working_dir = Path(working_dir) - working_dir.mkdir(parents=True, exist_ok=True) - os.chdir(working_dir) - try: - yield - finally: - os.chdir(orig_dir) - if tmpdir: - tmp.cleanup() - - -def input_path(filename: PathLike) -> Path: - """Return a path object for an input file based on global configuration - - Parameters - ---------- - filename : PathLike - Path to input file - - Returns - ------- - pathlib.Path - Path object - - """ - if openmc.config['resolve_paths']: - return Path(filename).resolve() - else: - return Path(filename) - - -@contextmanager -def h5py_file_or_group(group_or_filename: PathLike | h5py.Group, *args, **kwargs): - """Context manager for opening an HDF5 file or using an existing group - - Parameters - ---------- - group_or_filename : path-like or h5py.Group - Path to HDF5 file, or group from an existing HDF5 file - - """ - if isinstance(group_or_filename, h5py.Group): - yield group_or_filename - else: - with h5py.File(group_or_filename, *args, **kwargs) as f: - yield f diff --git a/openmc/volume.py b/openmc/volume.py index c44adf98a..5411b3c1d 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -1,16 +1,17 @@ +from collections import OrderedDict from collections.abc import Iterable, Mapping from numbers import Real, Integral +from xml.etree import ElementTree as ET import warnings -import h5py -import lxml.etree as ET import numpy as np import pandas as pd +import h5py from uncertainties import ufloat import openmc import openmc.checkvalue as cv -from openmc._xml import get_elem_list, get_text +from openmc._xml import get_text _VERSION_VOLUME = 1 @@ -121,83 +122,34 @@ class VolumeCalculation: raise ValueError('Could not automatically determine bounding box ' 'for stochastic volume calculation.') - if np.isinf(self.lower_left).any() or np.isinf(self.upper_right).any(): - raise ValueError('Lower-left and upper-right bounding box ' - 'coordinates must be finite.') - @property def ids(self): return self._ids - @ids.setter - def ids(self, ids): - cv.check_type('domain IDs', ids, Iterable, Real) - self._ids = ids - @property def samples(self): return self._samples - @samples.setter - def samples(self, samples): - cv.check_type('number of samples', samples, Integral) - cv.check_greater_than('number of samples', samples, 0) - self._samples = samples - @property def lower_left(self): return self._lower_left - @lower_left.setter - def lower_left(self, lower_left): - name = 'lower-left bounding box coordinates', - cv.check_type(name, lower_left, Iterable, Real) - cv.check_length(name, lower_left, 3) - self._lower_left = lower_left - @property def upper_right(self): return self._upper_right - @upper_right.setter - def upper_right(self, upper_right): - name = 'upper-right bounding box coordinates' - cv.check_type(name, upper_right, Iterable, Real) - cv.check_length(name, upper_right, 3) - self._upper_right = upper_right - @property def threshold(self): return self._threshold - @threshold.setter - def threshold(self, threshold): - name = 'volume std. dev. threshold' - cv.check_type(name, threshold, Real) - cv.check_greater_than(name, threshold, 0.0) - self._threshold = threshold - @property def trigger_type(self): return self._trigger_type - @trigger_type.setter - def trigger_type(self, trigger_type): - cv.check_value('tally trigger type', trigger_type, - ('variance', 'std_dev', 'rel_err')) - self._trigger_type = trigger_type - @property def iterations(self): return self._iterations - @iterations.setter - def iterations(self, iterations): - name = 'volume calculation iterations' - cv.check_type(name, iterations, Integral) - cv.check_greater_than(name, iterations, 0) - self._iterations = iterations - @property def domain_type(self): return self._domain_type @@ -206,20 +158,10 @@ class VolumeCalculation: def atoms(self): return self._atoms - @atoms.setter - def atoms(self, atoms): - cv.check_type('atoms', atoms, Mapping) - self._atoms = atoms - @property def volumes(self): return self._volumes - @volumes.setter - def volumes(self, volumes): - cv.check_type('volumes', volumes, Mapping) - self._volumes = volumes - @property def atoms_dataframe(self): items = [] @@ -230,6 +172,61 @@ class VolumeCalculation: return pd.DataFrame.from_records(items, columns=columns) + @ids.setter + def ids(self, ids): + cv.check_type('domain IDs', ids, Iterable, Real) + self._ids = ids + + @samples.setter + def samples(self, samples): + cv.check_type('number of samples', samples, Integral) + cv.check_greater_than('number of samples', samples, 0) + self._samples = samples + + @lower_left.setter + def lower_left(self, lower_left): + name = 'lower-left bounding box coordinates', + cv.check_type(name, lower_left, Iterable, Real) + cv.check_length(name, lower_left, 3) + self._lower_left = lower_left + + @upper_right.setter + def upper_right(self, upper_right): + name = 'upper-right bounding box coordinates' + cv.check_type(name, upper_right, Iterable, Real) + cv.check_length(name, upper_right, 3) + self._upper_right = upper_right + + @threshold.setter + def threshold(self, threshold): + name = 'volume std. dev. threshold' + cv.check_type(name, threshold, Real) + cv.check_greater_than(name, threshold, 0.0) + self._threshold = threshold + + @trigger_type.setter + def trigger_type(self, trigger_type): + cv.check_value('tally trigger type', trigger_type, + ('variance', 'std_dev', 'rel_err')) + self._trigger_type = trigger_type + + @iterations.setter + def iterations(self, iterations): + name = 'volume calculation iterations' + cv.check_type(name, iterations, Integral) + cv.check_greater_than(name, iterations, 0) + self._iterations = iterations + + @volumes.setter + def volumes(self, volumes): + cv.check_type('volumes', volumes, Mapping) + self._volumes = volumes + + @atoms.setter + def atoms(self, atoms): + cv.check_type('atoms', atoms, Mapping) + self._atoms = atoms + def set_trigger(self, threshold, trigger_type): """Set a trigger on the volume calculation @@ -284,7 +281,7 @@ class VolumeCalculation: volumes[domain_id] = volume nucnames = group['nuclides'][()] atoms_ = group['atoms'][()] - atom_dict = {} + atom_dict = OrderedDict() for name_i, atoms_i in zip(nucnames, atoms_): atom_dict[name_i.decode()] = ufloat(*atoms_i) atoms[domain_id] = atom_dict @@ -336,7 +333,7 @@ class VolumeCalculation: Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing volume calculation data """ @@ -365,7 +362,7 @@ class VolumeCalculation: Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element Returns @@ -375,10 +372,13 @@ class VolumeCalculation: """ domain_type = get_text(elem, "domain_type") - ids = get_elem_list(elem, "domain_ids", int) + domain_ids = get_text(elem, "domain_ids").split() + ids = [int(x) for x in domain_ids] samples = int(get_text(elem, "samples")) - lower_left = tuple(get_elem_list(elem, "lower_left", float)) - upper_right = tuple(get_elem_list(elem, "upper_right", float)) + lower_left = get_text(elem, "lower_left").split() + lower_left = tuple([float(x) for x in lower_left]) + upper_right = get_text(elem, "upper_right").split() + upper_right = tuple([float(x) for x in upper_right]) # Instantiate some throw-away domains that are used by the constructor # to assign IDs diff --git a/openmc/waste.py b/openmc/waste.py deleted file mode 100644 index 80cfc0adc..000000000 --- a/openmc/waste.py +++ /dev/null @@ -1,286 +0,0 @@ -from __future__ import annotations - -import openmc -from openmc.data import half_life - - -def _waste_classification(mat: openmc.Material, metal: bool = True) -> str: - """Classify a material for near-surface waste disposal. - - This method determines a waste classification for a material based on the - NRC regulations (10 CFR 61.55). - - Parameters - ---------- - mat : openmc.Material - The material to classify. - metal : bool, optional - Whether or not the material is in metal form. This changes the - acceptable limits in Tables 1 and 2 for certain nuclides. - - Returns - ------- - str - The waste disposal classification, which can be "Class A", "Class B", - "Class C", or "GTCC" (greater than class C). - - """ - # Determine metrics based on Tables 1 and 2 using sum of fractions rule for - # mixture of radionuclides from §61.55(a)(7) - ratio1 = _waste_disposal_rating(mat, 'NRC_long', metal=metal) - ratio2 = [ - _waste_disposal_rating(mat, 'NRC_short_A', metal=metal), - _waste_disposal_rating(mat, 'NRC_short_B', metal=metal), - _waste_disposal_rating(mat, 'NRC_short_C', metal=metal), - ] - - # Determine which nuclides are present in Table 1 and Table 2 - table1_nuclides_present = (ratio1 > 0.0) - table2_nuclides_present = any(x > 0.0 for x in ratio2) - - # Helper function for classifying based on Table 2 - def classify_table2(col1, col2, col3): - if col1 < 1.0: - return "Class A" - elif col2 < 1.0: - return "Class B" - elif col3 < 1.0: - return "Class C" - else: - return "GTCC" - - if table1_nuclides_present and table2_nuclides_present: - # Classification based on §61.55(a)(5) - if ratio1 < 0.1: - return classify_table2(*ratio2) - elif ratio1 < 1.0: - return "Class C" if ratio2[2] < 1.0 else "GTCC" - else: - return "GTCC" - - elif table1_nuclides_present: - # Classification based on §61.55(a)(3) - if ratio1 < 0.1: - return "Class A" - elif ratio1 < 1.0: - return "Class C" - else: - return "GTCC" - - elif table2_nuclides_present: - # Classification based on §61.55(a)(4) - return classify_table2(*ratio2) - - else: - # Classification based on §61.55(a)(6) - return "Class A" - - -def _waste_disposal_rating( - mat: openmc.Material, - limits: str | dict[str, float] = 'Fetter', - metal: bool = False, - by_nuclide: bool = False, -) -> float | dict[str, float]: - """Return the waste disposal rating for a material. - - This method returns a waste disposal rating for the material based on a set - of specific activity limits. The waste disposal rating is a single number - that represents the sum of the ratios of the specific activity for each - radionuclide in the material against a nuclide-specific limit. A value less - than 1.0 indicates that the material "meets" the limits whereas a value - greater than 1.0 exceeds the limits. - - Parameters - ---------- - mat : openmc.Material - The material to classify. - limits : str or dict, optional - The name of a predefined set of specific activity limits or a dictionary - that contains specific activity limits for radionuclides, where keys are - nuclide names and values are activities in units of [Ci/m3]. The - predefined options are: - - - 'Fetter': Uses limits from Fetter et al. (1990) - - 'NRC_long': Uses the 10 CFR 61.55 limits for long-lived radionuclides - - 'NRC_short_A': Uses the 10 CFR 61.55 class A limits for short-lived - radionuclides - - 'NRC_short_B': Uses the 10 CFR 61.55 class B limits for short-lived - radionuclides - - 'NRC_short_C': Uses the 10 CFR 61.55 class C limits for short-lived - radionuclides - metal : bool, optional - Whether or not the material is in metal form (only applicable for NRC - based limits) - by_nuclide : bool, optional - Whether to return the waste disposal rating for each nuclide in the - material. If True, a dictionary is returned where the keys are the - nuclide names and the values are the waste disposal ratings for each - nuclide. If False, a single float value is returned that represents the - overall waste disposal rating for the material. - - Returns - ------- - float or dict - The waste disposal rating for the material or its constituent nuclides. - - """ - if limits == 'Fetter': - # Specific activity limits for radionuclides with half-lives between 5 - # years and 1e12 years from Table 2 in Fetter - limits = { - "Be10": 5.0e3, - "C14": 6.0e2, - "Al26": 9.0e-2, - "Si32": 6.0e2, - "Cl36": 1.0e1, - "Ar39": 2.0e4, - "Ar42": 2.0e4, - "K40": 2.0e0, - "Ca41": 1.0e4, - "Ti44": 2.0e2, - "Fe60": 1.0e-1, - "Co60": 3.0e8, - "Ni59": 9.0e2, - "Ni63": 7.0e5, - "Se79": 5.0e1, - "Kr81": 3.0e1, - "Sr90": 8.0e5, - "Nb91": 2.0e2, - "Nb92": 2.0e-1, - "Nb94": 2.0e-1, - "Mo93": 4.0e3, - "Tc97": 4.0e-1, - "Tc98": 1.0e-2, - "Tc99": 6.0e-2, - "Pd107": 9.0e2, - "Ag108_m1": 3.0e0, - "Sn121_m1": 7.0e5, - "Sn126": 1.0e-1, - "I129": 2.0e0, - "Cs137": 5.0e4, - "Ba133": 2.0e8, - "La137": 2.0e2, - "Sm151": 5.0e7, - "Eu150_m1": 3.0e3, - "Eu152": 3.0e5, - "Eu154": 5.0e6, - "Gd148": 2.0e5, - "Gd150": 2.0e3, - "Tb157": 5.0e3, - "Tb158": 4.0e0, - "Dy154": 1.0e3, - "Ho166_m1": 2.0e-1, - "Hf178_m1": 9.0e3, - "Hf182": 2.0e-1, - "Re186_m1": 2.0e1, - "Ir192_m1": 1.0e0, - "Pt193": 2.0e8, - "Hg194": 5.0e-1, - "Pb202": 6.0e-1, - "Pb210": 3.0e7, - "Bi207": 9.0e3, - "Bi208": 8.0e-2, - "Bi210_m1": 1.0e0, - "Po209": 3.0e3, - "Ra226": 1.0e-1, - "Ra228": 3.0e7, - "Ac227": 5.0e5, - "Th229": 2.0e0, - "Th230": 3.0e-1, - "Th232": 1.0e-1, - "Pa231": 7.0e-1, - "U232": 3.0e1, - "U233": 2.0e1, - "U234": 9.0e1, - "U235": 2.0e0, - "Np236": 1.0e0, - "Np237": 1.0e0, - "Pu238": 7.0e4, - "Pu239": 1.0e3, - "Pu240": 1.0e3, - "Pu241": 2.0e3, - "Pu242": 1.0e3, - "Pu244": 9.0e-1, - "Am241": 5.0e1, - "Am242_m1": 3.0e2, - "Am243": 2.0e0, - "Cm243": 6.0e2, - "Cm244": 5.0e5, - "Cm245": 5.0e0, - "Cm246": 8.0e2, - "Cm248": 8.0e2, - } - - elif limits == 'NRC_long': - # Specific activity limits for long-lived radionuclides from Table 1 in - # 10 CFR 61.55 in Ci/m3. - limits = { - 'C14': 8.0, - 'Tc99': 3.0, - 'I129': 0.08, - } - if metal: - limits['C14'] = 80.0 - limits['Ni59'] = 220.0 - limits['Nb94'] = 0.2 - - # Convert values in nCi/g to Ci/m3 - factor = (1e6 * mat.get_mass_density()) / 1e9 - limits.update({ - 'Pu241': 3500.0 * factor, - 'Cm242': 20000.0 * factor, - 'Np237': 100.0 * factor, - 'Pu238': 100.0 * factor, - 'Pu239': 100.0 * factor, - 'Pu240': 100.0 * factor, - 'Pu242': 100.0 * factor, - 'Pu244': 100.0 * factor, - 'Am241': 100.0 * factor, - 'Am243': 100.0 * factor, - 'Cm243': 100.0 * factor, - 'Cm244': 100.0 * factor, - 'Cm245': 100.0 * factor, - 'Cm246': 100.0 * factor, - 'Cm247': 100.0 * factor, - 'Cm248': 100.0 * factor, - 'Bk247': 100.0 * factor, - 'Cf249': 100.0 * factor, - 'Cf250': 100.0 * factor, - 'Cf251': 100.0 * factor, - }) - - elif limits == 'NRC_short_A': - # Get Class A specific activity limits for short-lived radionuclides - # from Table 2 in 10 CFR 61.55 - limits = { - 'H3': 40.0, - 'Co60': 700.0, - 'Ni63': 35.0 if metal else 3.5, - 'Sr90': 0.04, - 'Cs137': 1.0 - } - - # Add radionuclides with half-lives < 5 years to limits for class A - five_years = 60.0 * 60.0 * 24.0 * 365.25 * 5.0 - for nuc in mat.get_nuclides(): - if half_life(nuc) is not None and half_life(nuc) < five_years: - limits[nuc] = 700.0 - - elif limits == 'NRC_short_B': - # Get Class B specific activity limits for short-lived radionuclides - # from Table 2 in 10 CFR 61.55 - limits = {'Ni63': 700.0 if metal else 70.0, 'Sr90': 150.0, 'Cs137': 44.0} - - elif limits == 'NRC_short_C': - # Get Class C specific activity limits for short-lived radionuclides - # from Table 2 in 10 CFR 61.55 - limits = {'Ni63': 7000.0 if metal else 700.0, 'Sr90': 7000.0, 'Cs137': 4600.0} - - # Calculate the sum of the fractions of the activity of each radionuclide - # compared to the specified limits - ratio = {} - for nuc, ci_m3 in mat.get_activity(units="Ci/m3", by_nuclide=True).items(): - if nuc in limits: - ratio[nuc] = ci_m3 / limits[nuc] - return ratio if by_nuclide else sum(ratio.values()) diff --git a/openmc/weight_windows.py b/openmc/weight_windows.py index 63af2596e..9183bb08b 100644 --- a/openmc/weight_windows.py +++ b/openmc/weight_windows.py @@ -1,22 +1,15 @@ -from __future__ import annotations +from collections.abc import Iterable from numbers import Real, Integral -from collections.abc import Iterable, Sequence -from pathlib import Path -from typing import Self -import warnings -import lxml.etree as ET +from xml.etree import ElementTree as ET import numpy as np -import h5py -import openmc -from openmc.mesh import MeshBase, RectilinearMesh, CylindricalMesh, SphericalMesh, UnstructuredMesh -from openmc.tallies import Tallies +from openmc.filter import _PARTICLES +from openmc.mesh import MeshBase, RectilinearMesh, UnstructuredMesh import openmc.checkvalue as cv -from openmc.checkvalue import PathLike -from ._xml import get_elem_list, get_text, clean_indentation + +from ._xml import get_text from .mixin import IDManagerMixin -from .particle_type import ParticleType class WeightWindows(IDManagerMixin): @@ -49,9 +42,8 @@ class WeightWindows(IDManagerMixin): Ratio of the lower to upper weight window bounds energy_bounds : Iterable of Real A list of values for which each successive pair constitutes a range of - energies in [eV] for a single bin. If no energy bins are provided, the - maximum and minimum energy for the data available at runtime. - particle_type : str or int or openmc.ParticleType + energies in [eV] for a single bin + particle_type : {'neutron', 'photon'} Particle type the weight windows apply to survival_ratio : float Ratio of the survival weight to the lower weight window bound for @@ -93,7 +85,7 @@ class WeightWindows(IDManagerMixin): survival_ratio : float Ratio of the survival weight to the lower weight window bound for rouletting - max_lower_bound_ratio : float + max_lower_bound_ratio: float Maximum allowed ratio of a particle's weight to the weight window's lower bound. (Default: 1.0) max_split : int @@ -109,26 +101,20 @@ class WeightWindows(IDManagerMixin): next_id = 1 used_ids = set() - def __init__( - self, - mesh: MeshBase, - lower_ww_bounds: Iterable[float], - upper_ww_bounds: Iterable[float] | None = None, - upper_bound_ratio: float | None = None, - energy_bounds: Iterable[Real] | None = None, - particle_type: str | int | openmc.ParticleType = 'neutron', - survival_ratio: float = 3.0, - max_lower_bound_ratio: float | None = None, - max_split: int = 10, - weight_cutoff: float = 1.e-38, - id: int | None = None - ): + def __init__(self, mesh, lower_ww_bounds, + upper_ww_bounds=None, + upper_bound_ratio=None, + energy_bounds=None, + particle_type='neutron', + survival_ratio=3, + max_lower_bound_ratio=None, + max_split=10, + weight_cutoff=1.e-38, + id=None): self.mesh = mesh self.id = id self.particle_type = particle_type - self._energy_bounds = None - if energy_bounds is not None: - self.energy_bounds = energy_bounds + self.energy_bounds = energy_bounds self.lower_ww_bounds = lower_ww_bounds if upper_ww_bounds is not None and upper_bound_ratio: @@ -160,13 +146,12 @@ class WeightWindows(IDManagerMixin): self.max_split = max_split self.weight_cutoff = weight_cutoff - def __repr__(self) -> str: + def __repr__(self): string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tID', self._id) - string += '{: <16}=\t{}\n'.format('\tMesh', self.mesh) + string += '{: <16}=\t{}\n'.format('\tMesh:', self.mesh) string += '{: <16}=\t{}\n'.format('\tParticle Type', self._particle_type) string += '{: <16}=\t{}\n'.format('\tEnergy Bounds', self._energy_bounds) - string += '{: <16}=\t{}\n'.format('\tMax lower bound ratio', self.max_lower_bound_ratio) string += '{: <16}=\t{}\n'.format('\tLower WW Bounds', self._lower_ww_bounds) string += '{: <16}=\t{}\n'.format('\tUpper WW Bounds', self._upper_ww_bounds) string += '{: <16}=\t{}\n'.format('\tSurvival Ratio', self._survival_ratio) @@ -174,76 +159,45 @@ class WeightWindows(IDManagerMixin): string += '{: <16}=\t{}\n'.format('\tWeight Cutoff', self._weight_cutoff) return string - def __eq__(self, other: WeightWindows) -> bool: - # ensure that `other` is a WeightWindows object - if not isinstance(other, WeightWindows): - return False - - # TODO: add ability to check mesh equality - - # check several attributes directly - attrs = ('particle_type', - 'survival_ratio', - 'max_lower_bound_ratio', - 'max_split', - 'weight_cutoff') - for attr in attrs: - if getattr(self, attr) != getattr(other, attr): - return False - - # save most expensive checks for last - if not np.array_equal(self.energy_bounds, other.energy_bounds): - return False - - if not np.array_equal(self.lower_ww_bounds, other.lower_ww_bounds): - return False - - if not np.array_equal(self.upper_ww_bounds, other.upper_ww_bounds): - return False - - return True - @property - def mesh(self) -> MeshBase: + def mesh(self): return self._mesh @mesh.setter - def mesh(self, mesh: MeshBase): + def mesh(self, mesh): cv.check_type('Weight window mesh', mesh, MeshBase) self._mesh = mesh @property - def particle_type(self) -> ParticleType: + def particle_type(self): return self._particle_type @particle_type.setter def particle_type(self, pt): - ptype = ParticleType(pt) - if ptype not in {ParticleType.NEUTRON, ParticleType.PHOTON}: - raise ValueError("Weight windows can only be applied for neutrons or photons") - self._particle_type = ptype + cv.check_value('Particle type', pt, _PARTICLES) + self._particle_type = pt @property - def energy_bounds(self) -> Iterable[Real]: + def energy_bounds(self): return self._energy_bounds @energy_bounds.setter - def energy_bounds(self, bounds: Iterable[float]): + def energy_bounds(self, bounds): cv.check_type('Energy bounds', bounds, Iterable, Real) self._energy_bounds = np.asarray(bounds) @property - def num_energy_bins(self) -> int: + def num_energy_bins(self): if self.energy_bounds is None: - return 1 + raise ValueError('Energy bounds are not set') return self.energy_bounds.size - 1 @property - def lower_ww_bounds(self) -> np.ndarray: + def lower_ww_bounds(self): return self._lower_ww_bounds @lower_ww_bounds.setter - def lower_ww_bounds(self, bounds: Iterable[float]): + def lower_ww_bounds(self, bounds): cv.check_iterable_type('Lower WW bounds', bounds, Real, @@ -252,17 +206,17 @@ class WeightWindows(IDManagerMixin): # reshape data according to mesh and energy bins bounds = np.asarray(bounds) if isinstance(self.mesh, UnstructuredMesh): - bounds = bounds.reshape(-1, self.num_energy_bins) + bounds.reshape(-1, self.num_energy_bins) else: - bounds = bounds.reshape(*self.mesh.dimension, self.num_energy_bins) + bounds.reshape(*self.mesh.dimension, self.num_energy_bins) self._lower_ww_bounds = bounds @property - def upper_ww_bounds(self) -> np.ndarray: + def upper_ww_bounds(self): return self._upper_ww_bounds @upper_ww_bounds.setter - def upper_ww_bounds(self, bounds: Iterable[float]): + def upper_ww_bounds(self, bounds): cv.check_iterable_type('Upper WW bounds', bounds, Real, @@ -271,56 +225,56 @@ class WeightWindows(IDManagerMixin): # reshape data according to mesh and energy bins bounds = np.asarray(bounds) if isinstance(self.mesh, UnstructuredMesh): - bounds = bounds.reshape(-1, self.num_energy_bins) + bounds.reshape(-1, self.num_energy_bins) else: - bounds = bounds.reshape(*self.mesh.dimension, self.num_energy_bins) + bounds.reshape(*self.mesh.dimension, self.num_energy_bins) self._upper_ww_bounds = bounds @property - def survival_ratio(self) -> float: + def survival_ratio(self): return self._survival_ratio @survival_ratio.setter - def survival_ratio(self, val: float): + def survival_ratio(self, val): cv.check_type('Survival ratio', val, Real) cv.check_greater_than('Survival ratio', val, 1.0, True) self._survival_ratio = val @property - def max_lower_bound_ratio(self) -> float: + def max_lower_bound_ratio(self): return self._max_lower_bound_ratio @max_lower_bound_ratio.setter - def max_lower_bound_ratio(self, val: float): + def max_lower_bound_ratio(self, val): cv.check_type('Maximum lower bound ratio', val, Real) - cv.check_greater_than('Maximum lower bound ratio', val, 1.0, equality=True) + cv.check_greater_than('Maximum lower bound ratio', val, 1.0) self._max_lower_bound_ratio = val @property - def max_split(self) -> int: + def max_split(self): return self._max_split @max_split.setter - def max_split(self, val: int): + def max_split(self, val): cv.check_type('Max split', val, Integral) self._max_split = val @property - def weight_cutoff(self) -> float: + def weight_cutoff(self): return self._weight_cutoff @weight_cutoff.setter - def weight_cutoff(self, cutoff: float): + def weight_cutoff(self, cutoff): cv.check_type('Weight cutoff', cutoff, Real) cv.check_greater_than('Weight cutoff', cutoff, 0.0, True) self._weight_cutoff = cutoff - def to_xml_element(self) -> ET.Element: + def to_xml_element(self): """Return an XML representation of the weight window settings Returns ------- - element : lxml.etree._Element + element : xml.etree.ElementTree.Element XML element containing the weight window information """ element = ET.Element('weight_windows') @@ -331,11 +285,10 @@ class WeightWindows(IDManagerMixin): subelement.text = str(self.mesh.id) subelement = ET.SubElement(element, 'particle_type') - subelement.text = str(self.particle_type) + subelement.text = self.particle_type - if self.energy_bounds is not None: - subelement = ET.SubElement(element, 'energy_bounds') - subelement.text = ' '.join(str(e) for e in self.energy_bounds) + subelement = ET.SubElement(element, 'energy_bounds') + subelement.text = ' '.join(str(e) for e in self.energy_bounds) subelement = ET.SubElement(element, 'lower_ww_bounds') subelement.text = ' '.join(str(b) for b in self.lower_ww_bounds.ravel('F')) @@ -359,15 +312,15 @@ class WeightWindows(IDManagerMixin): return element @classmethod - def from_xml_element(cls, elem: ET.Element, meshes: dict[int, MeshBase]) -> Self: + def from_xml_element(cls, elem, root): """Generate weight window settings from an XML element Parameters ---------- - elem : lxml.etree._Element + elem : xml.etree.ElementTree.Element XML element - meshes : dict - Dictionary mapping IDs to mesh objects + root : xml.etree.ElementTree.Element + Root element for the file where meshes can be found Returns ------- @@ -376,21 +329,18 @@ class WeightWindows(IDManagerMixin): """ # Get mesh for weight windows mesh_id = int(get_text(elem, 'mesh')) - if mesh_id not in meshes: - raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') - mesh = meshes[mesh_id] + path = f"./mesh[@id='{mesh_id}']" + mesh_elem = root.find(path) + if mesh_elem is not None: + mesh = MeshBase.from_xml_element(mesh_elem) # Read all other parameters - lower_ww_bounds = get_elem_list(elem, "lower_ww_bounds", float) - upper_ww_bounds = get_elem_list(elem, "upper_ww_bounds", float) - e_bounds = get_elem_list(elem, "energy_bounds", float) + lower_ww_bounds = [float(l) for l in get_text(elem, 'lower_ww_bounds').split()] + upper_ww_bounds = [float(u) for u in get_text(elem, 'upper_ww_bounds').split()] + e_bounds = [float(b) for b in get_text(elem, 'energy_bounds').split()] particle_type = get_text(elem, 'particle_type') survival_ratio = float(get_text(elem, 'survival_ratio')) - ww_shape = (len(e_bounds) - 1,) + mesh.dimension[::-1] - lower_ww_bounds = np.array(lower_ww_bounds).reshape(ww_shape).T - upper_ww_bounds = np.array(upper_ww_bounds).reshape(ww_shape).T - max_lower_bound_ratio = None if get_text(elem, 'max_lower_bound_ratio'): max_lower_bound_ratio = float(get_text(elem, 'max_lower_bound_ratio')) @@ -413,7 +363,7 @@ class WeightWindows(IDManagerMixin): ) @classmethod - def from_hdf5(cls, group: h5py.Group, meshes: dict[int, MeshBase]) -> Self: + def from_hdf5(cls, group, meshes): """Create weight windows from HDF5 group Parameters @@ -431,15 +381,10 @@ class WeightWindows(IDManagerMixin): id = int(group.name.split('/')[-1].lstrip('weight_windows')) mesh_id = group['mesh'][()] - mesh = meshes[mesh_id] - ptype = group['particle_type'][()].decode() e_bounds = group['energy_bounds'][()] - # weight window bounds are stored with the shape (e, k, j, i) - # in C++ and HDF5 -- the opposite of how they are stored here - shape = (e_bounds.size - 1, *mesh.dimension[::-1]) - lower_ww_bounds = group['lower_ww_bounds'][()].reshape(shape).T - upper_ww_bounds = group['upper_ww_bounds'][()].reshape(shape).T + lower_ww_bounds = group['lower_ww_bounds'][()] + upper_ww_bounds = group['upper_ww_bounds'][()] survival_ratio = group['survival_ratio'][()] max_lower_bound_ratio = None @@ -450,7 +395,7 @@ class WeightWindows(IDManagerMixin): weight_cutoff = group['weight_cutoff'][()] return cls( - mesh=mesh, + mesh=meshes[mesh_id], lower_ww_bounds=lower_ww_bounds, upper_ww_bounds=upper_ww_bounds, energy_bounds=e_bounds, @@ -463,7 +408,7 @@ class WeightWindows(IDManagerMixin): ) -def wwinp_to_wws(path: PathLike) -> WeightWindowsList: +def wwinp_to_wws(path): """Create WeightWindows instances from a wwinp file .. versionadded:: 0.13.1 @@ -475,617 +420,159 @@ def wwinp_to_wws(path: PathLike) -> WeightWindowsList: Returns ------- - WeightWindowsList - """ - warnings.warn( - "This function is deprecated in favor of 'WeightWindowsList.from_wwinp'", - FutureWarning - ) - return WeightWindowsList.from_wwinp(path) - - -class WeightWindowGenerator: - """Class passed to setting to govern weight window generation - using the OpenMC executable - - Parameters - ---------- - mesh : :class:`openmc.MeshBase` - Mesh used to represent the weight windows spatially - energy_bounds : Iterable of Real - A list of values for which each successive pair constitutes a range of - energies in [eV] for a single bin. If no energy bins are provided, the - maximum and minimum energy for the data available at runtime. - particle_type : str or int or openmc.ParticleType - Particle type the weight windows apply to - method : {'magic', 'fw_cadis'} - The weight window generation methodology applied during an update. - targets : :class:`openmc.Tallies` or iterable of int - Target tallies for local variance reduction via FW-CADIS. - max_realizations : int - The upper limit for number of tally realizations when generating weight - windows. - update_interval : int - The number of tally realizations between updates. - on_the_fly : bool - Whether or not to apply weight windows on the fly. - - Attributes - ---------- - mesh : openmc.MeshBase - Mesh used to represent the weight windows spatially - energy_bounds : Iterable of Real - A list of values for which each successive pair constitutes a range of - energies in [eV] for a single bin - particle_type : openmc.ParticleType - Particle type the weight windows apply to - method : {'magic', 'fw_cadis'} - The weight window generation methodology applied during an update. - targets : :class:`openmc.Tallies` or numpy.ndarray - Target tallies for local variance reduction via FW-CADIS. - max_realizations : int - The upper limit for number of tally realizations when generating weight - windows. - update_interval : int - The number of tally realizations between updates. - update_parameters : dict - A set of parameters related to the update. - on_the_fly : bool - Whether or not to apply weight windows on the fly. + list of openmc.WeightWindows """ - _WWG_PARAMS = {'value': str, 'threshold': float, 'ratio': float} + with open(path) as wwinp: + # BLOCK 1 + header = wwinp.readline().split(None, 4) + # read file type, time-dependence, number of + # particles, mesh type and problem identifier + _if, iv, ni, nr = [int(x) for x in header[:4]] + probid = header[4] if len(header) > 4 else "" - def __init__( - self, - mesh: openmc.MeshBase, - energy_bounds: Sequence[float] | None = None, - particle_type: str | int | openmc.ParticleType = 'neutron', - method: str = 'magic', - targets: openmc.Tallies | Iterable[int] | None = None, - max_realizations: int = 1, - update_interval: int = 1, - on_the_fly: bool = True - ): - self._update_parameters = None + # header value checks + if _if != 1: + raise ValueError(f'Found incorrect file type, if: {_if}') - self.mesh = mesh - self._energy_bounds = None - if energy_bounds is not None: - self.energy_bounds = energy_bounds - self.particle_type = particle_type - self.method = method - self.targets = targets - self.max_realizations = max_realizations - self.update_interval = update_interval - self.on_the_fly = on_the_fly + if iv > 1: + # read number of time bins for each particle, 'nt(1...ni)' + nt = np.fromstring(wwinp.readline(), sep=' ', dtype=int) - def __repr__(self): - string = type(self).__name__ + '\n' - string += f'\t{"Mesh":<20}=\t{self.mesh.id}\n' - string += f'\t{"Particle:":<20}=\t{str(self.particle_type)}\n' - string += f'\t{"Energy Bounds:":<20}=\t{self.energy_bounds}\n' - string += f'\t{"Method":<20}=\t{self.method}\n' - string += f'\t{"Max Realizations:":<20}=\t{self.max_realizations}\n' - string += f'\t{"Update Interval:":<20}=\t{self.update_interval}\n' - string += f'\t{"On The Fly:":<20}=\t{self.on_the_fly}\n' - if self.update_parameters is not None: - string += f'\t{"Update Parameters:":<20}\n\t\t\t{self.update_parameters}\n' - string - - return string - - @property - def mesh(self) -> openmc.MeshBase: - return self._mesh - - @mesh.setter - def mesh(self, m: openmc.MeshBase): - cv.check_type('mesh', m, openmc.MeshBase) - self._mesh = m - - @property - def energy_bounds(self) -> Iterable[Real]: - return self._energy_bounds - - @energy_bounds.setter - def energy_bounds(self, eb: Iterable[float]): - cv.check_type('energy bounds', eb, Iterable, Real) - self._energy_bounds = eb - - @property - def particle_type(self) -> ParticleType: - return self._particle_type - - @particle_type.setter - def particle_type(self, pt): - ptype = ParticleType(pt) - if ptype not in {ParticleType.NEUTRON, ParticleType.PHOTON}: - raise ValueError("Weight windows can only be applied for neutrons or photons") - self._particle_type = ptype - - @property - def method(self) -> str: - return self._method - - @method.setter - def method(self, m: str): - cv.check_type('generation method', m, str) - cv.check_value('generation method', m, ('magic', 'fw_cadis')) - self._method = m - if self._update_parameters is not None: - try: - self._check_update_parameters() - except (TypeError, KeyError): - warnings.warn(f'Update parameters are invalid for the "{m}" method.') - - @property - def targets(self) -> openmc.Tallies: - return self._targets - - @targets.setter - def targets(self, t): - if t is None: - self._targets = t + # raise error if time bins are present for now + raise ValueError('Time-dependent weight windows ' + 'are not yet supported') else: - cv.check_type('Local FW-CADIS target tallies', t, Iterable) - cv.check_greater_than('Local FW-CADIS target tallies', len(t), 0) - if not isinstance(t, openmc.Tallies): - cv.check_iterable_type('Local FW-CADIS target tallies', t, int) - t = np.asarray(list(t), dtype=int) - self._targets = t - - @property - def max_realizations(self) -> int: - return self._max_realizations - - @max_realizations.setter - def max_realizations(self, m: int): - cv.check_type('max tally realizations', m, Integral) - cv.check_greater_than('max tally realizations', m, 0) - self._max_realizations = m - - @property - def update_interval(self) -> int: - return self._update_interval - - @update_interval.setter - def update_interval(self, ui: int): - cv.check_type('update interval', ui, Integral) - cv.check_greater_than('update interval', ui , 0) - self._update_interval = ui - - @property - def update_parameters(self) -> dict: - return self._update_parameters - - def _check_update_parameters(self, params: dict): - if self.method == 'magic' or self.method == 'fw_cadis': - check_params = self._WWG_PARAMS - - for key, val in params.items(): - if key not in check_params: - raise ValueError(f'Invalid param "{key}" for {self.method} ' - 'weight window generation') - cv.check_type(f'weight window generation param: "{key}"', val, self._WWG_PARAMS[key]) - - @update_parameters.setter - def update_parameters(self, params: dict): - self._check_update_parameters(params) - self._update_parameters = params - - @property - def on_the_fly(self) -> bool: - return self._on_the_fly - - @on_the_fly.setter - def on_the_fly(self, otf: bool): - cv.check_type('on the fly generation', otf, bool) - self._on_the_fly = otf - - def _update_parameters_subelement(self, element: ET.Element): - if not self.update_parameters: - return - params_element = ET.SubElement(element, 'update_parameters') - for pname, value in self.update_parameters.items(): - param_element = ET.SubElement(params_element, pname) - param_element.text = str(value) - - @classmethod - def _sanitize_update_parameters(cls, method: str, update_parameters: dict): - """ - Attempt to convert update parameters to their appropriate types - - Parameters - ---------- - method : str - The update method for which these update parameters should comply - update_parameters : dict - The update parameters as-read from the XML node (keys: str, values: str) - """ - if method == 'magic' or method == 'fw_cadis': - check_params = cls._WWG_PARAMS - - for param, param_type in check_params.items(): - if param in update_parameters: - update_parameters[param] = param_type(update_parameters[param]) - - def to_xml_element(self): - """Creates a 'weight_window_generator' element to be written to an XML file. - """ - element = ET.Element('weight_windows_generator') - - mesh_elem = ET.SubElement(element, 'mesh') - mesh_elem.text = str(self.mesh.id) - if self.energy_bounds is not None: - subelement = ET.SubElement(element, 'energy_bounds') - subelement.text = ' '.join(str(e) for e in self.energy_bounds) - particle_elem = ET.SubElement(element, 'particle_type') - particle_elem.text = str(self.particle_type) - realizations_elem = ET.SubElement(element, 'max_realizations') - realizations_elem.text = str(self.max_realizations) - update_interval_elem = ET.SubElement(element, 'update_interval') - update_interval_elem.text = str(self.update_interval) - otf_elem = ET.SubElement(element, 'on_the_fly') - otf_elem.text = str(self.on_the_fly).lower() - method_elem = ET.SubElement(element, 'method') - method_elem.text = self.method - if self.targets is not None: - if self.method != 'fw_cadis': - raise ValueError( - "FW-CADIS update method is required in order to use " \ - "target tallies for WeightWindowGenerator.") - elif isinstance(self.targets, openmc.Tallies): - raise RuntimeError( - "FW-CADIS target tallies must be checked to ensure they are " \ - "present on model.tallies. Use model.export_to_xml() or " \ - "model.export_to_model_xml() to link FW-CADIS target tallies.") - else: - targets_elem = ET.SubElement(element, 'targets') - targets_elem.text = ' '.join(str(tally_id) for tally_id in self.targets) - - if self.update_parameters is not None: - self._update_parameters_subelement(element) - - clean_indentation(element) - - return element - - @classmethod - def from_xml_element(cls, elem: ET.Element, meshes: dict) -> Self: - """ - Create a weight window generation object from an XML element - - Parameters - ---------- - elem : xml.etree.ElementTree.Element - XML element - meshes : dict - A dictionary with IDs as keys and openmc.MeshBase instances as values - - Returns - ------- - openmc.WeightWindowGenerator - """ - - mesh_id = int(get_text(elem, 'mesh')) - mesh = meshes[mesh_id] - - energy_bounds = get_elem_list(elem, "energy_bounds", float) - particle_type = get_text(elem, 'particle_type') - - wwg = cls(mesh, energy_bounds, particle_type) - - wwg.max_realizations = int(get_text(elem, 'max_realizations')) - wwg.update_interval = int(get_text(elem, 'update_interval')) - wwg.on_the_fly = bool(get_text(elem, 'on_the_fly')) - wwg.method = get_text(elem, 'method') - targets_elem = elem.find('targets') - if targets_elem is not None: - if wwg.method != 'fw_cadis': - raise ValueError( - "FW-CADIS update method is required in order to use " \ - "target tallies for WeightWindowGenerator.") - else: - wwg.targets = get_elem_list(elem, "targets") - - if elem.find('update_parameters') is not None: - update_parameters = {} - params_elem = elem.find('update_parameters') - for entry in params_elem: - update_parameters[entry.tag] = entry.text - - cls._sanitize_update_parameters(wwg.method, update_parameters) - wwg.update_parameters = update_parameters - - return wwg - -def hdf5_to_wws(path='weight_windows.h5') -> WeightWindowsList: - """Create a WeightWindowsList from a weight windows HDF5 file - - .. versionadded:: 0.14.0 - - Parameters - ---------- - path : cv.PathLike - Path to the weight windows hdf5 file - - Returns - ------- - WeightWindowsList - """ - warnings.warn( - "This function is deprecated in favor of 'WeightWindowsList.from_hdf5'", - FutureWarning - ) - return WeightWindowsList.from_hdf5(path) - - -class WeightWindowsList(list): - """A list of WeightWindows objects. - - .. versionadded:: 0.15.3 - - Parameters - ---------- - iterable : iterable of openmc.WeightWindows - An iterable of WeightWindows objects to initialize the list with - - """ - def __init__(self, iterable: Iterable[WeightWindows] = ()): - super().__init__(iterable) - - @classmethod - def from_hdf5(cls, path: PathLike = 'weight_windows.h5') -> Self: - """Create WeightWindowsList from a weight windows HDF5 file. - - Parameters - ---------- - path : PathLike - Path to the weight windows hdf5 file - - Returns - ------- - WeightWindowsList - A list of WeightWindows objects read from the file - """ - - with h5py.File(path) as h5_file: - # read in all of the meshes in the mesh node - meshes = {} - for mesh_group in h5_file['meshes']: - mesh = MeshBase.from_hdf5(h5_file['meshes'][mesh_group]) - meshes[mesh.id] = mesh - wws = [ - WeightWindows.from_hdf5(ww, meshes) - for ww in h5_file['weight_windows'].values() - ] - - return cls(wws) - - @classmethod - def from_wwinp(cls, path: PathLike) -> Self: - """Create WeightWindowsList from a wwinp file. - - Parameters - ---------- - path : PathLike - Path to the wwinp file - - Returns - ------- - WeightWindowsList - A list of WeightWindows objects read from the file - """ - - with open(path) as wwinp: - # BLOCK 1 - header = wwinp.readline().split(None, 4) - # read file type, time-dependence, number of - # particles, mesh type and problem identifier - _if, iv, ni, nr = [int(x) for x in header[:4]] - - # header value checks - if _if != 1: - raise ValueError(f'Found incorrect file type, if: {_if}') - - if iv > 1: - # read number of time bins for each particle, 'nt(1...ni)' - nt = np.fromstring(wwinp.readline(), sep=' ', dtype=int) - - # raise error if time bins are present for now - raise ValueError('Time-dependent weight windows ' - 'are not yet supported') - else: - nt = ni * [1] - - # read number of energy bins for each particle, 'ne(1...ni)' - ne = np.fromstring(wwinp.readline(), sep=' ', dtype=int) - - # read coarse mesh dimensions and lower left corner - mesh_description = np.fromstring(wwinp.readline(), sep=' ') - nfx, nfy, nfz = mesh_description[:3].astype(int) - xyz0 = mesh_description[3:] - - # read cylindrical and spherical mesh vectors if present - if nr == 16: - # read number of coarse bins - line_arr = np.fromstring(wwinp.readline(), sep=' ') - ncx, ncy, ncz = line_arr[:3].astype(int) - # read polar vector (x1, y1, z1) - xyz1 = line_arr[3:] - # read azimuthal vector (x2, y2, z2) - line_arr = np.fromstring(wwinp.readline(), sep=' ') - xyz2 = line_arr[:3] - - # Get polar and azimuthal axes - polar_axis = xyz1 - xyz0 - azimuthal_axis = xyz2 - xyz0 - - # Check for polar axis other than (0, 0, 1) - norm = np.linalg.norm(polar_axis) - if not np.isclose(polar_axis[2]/norm, 1.0): - raise NotImplementedError('Polar axis not aligned to z-axis not supported') - - # Check for azimuthal axis other than (1, 0, 0) - norm = np.linalg.norm(azimuthal_axis) - if not np.isclose(azimuthal_axis[0]/norm, 1.0): - raise NotImplementedError('Azimuthal axis not aligned to x-axis not supported') - - # read geometry type - nwg = int(line_arr[-1]) - - elif nr == 10: - # read rectilinear data: - # number of coarse mesh bins and mesh type - ncx, ncy, ncz, nwg = \ - np.fromstring(wwinp.readline(), sep=' ').astype(int) - else: - raise RuntimeError(f'Invalid mesh description (nr) found: {nr}') - - # read BLOCK 2 and BLOCK 3 data into a single array - ww_data = np.fromstring(wwinp.read(), sep=' ') - - # extract mesh data from the ww_data array - start_idx = 0 - - # first values in the mesh definition arrays are the first - # coordinate of the grid - end_idx = start_idx + 1 + 3 * ncx - i0, i_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] - start_idx = end_idx - - end_idx = start_idx + 1 + 3 * ncy - j0, j_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] - start_idx = end_idx - - end_idx = start_idx + 1 + 3 * ncz - k0, k_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] - start_idx = end_idx - - # mesh consistency checks - if nr == 16 and nwg == 1 or nr == 10 and nwg != 1: - raise ValueError(f'Mesh description in header ({nr}) ' - f'does not match the mesh type ({nwg})') - - if nr == 10 and (xyz0 != (i0, j0, k0)).any(): - raise ValueError(f'Mesh origin in the header ({xyz0}) ' - f' does not match the origin in the mesh ' - f' description ({i0, j0, k0})') - - # create openmc mesh object - grids = [] - mesh_definition = [(i0, i_vals, nfx), (j0, j_vals, nfy), (k0, k_vals, nfz)] - for grid0, grid_vals, n_pnts in mesh_definition: - # file spec checks for the mesh definition - if (grid_vals[2::3] != 1.0).any(): - raise ValueError('One or more mesh ratio value, qx, ' - 'is not equal to one') - - s = int(grid_vals[::3].sum()) - if s != n_pnts: - raise ValueError(f'Sum of the fine bin entries, {s}, does ' - f'not match the number of fine bins, {n_pnts}') - - # extend the grid based on the next coarse bin endpoint, px - # and the number of fine bins in the coarse bin, sx - intervals = grid_vals.reshape(-1, 3) - coords = [grid0] - for sx, px, qx in intervals: - coords += np.linspace(coords[-1], px, int(sx + 1)).tolist()[1:] - - grids.append(np.array(coords)) - - if nwg == 1: - mesh = RectilinearMesh() - mesh.x_grid, mesh.y_grid, mesh.z_grid = grids - elif nwg == 2: - mesh = CylindricalMesh( - r_grid=grids[0], - z_grid=grids[1], - phi_grid=grids[2], - origin = xyz0, - ) - elif nwg == 3: - mesh = SphericalMesh( - r_grid=grids[0], - theta_grid=grids[1], - phi_grid=grids[2], - origin = xyz0 - ) - - # extract weight window values from array - wws = cls() - for ne_i, nt_i, particle_type in zip(ne, nt, ('neutron', 'photon')): - # no information to read for this particle if - # either the energy bins or time bins are empty - if ne_i == 0 or nt_i == 0: - continue - - if iv > 1: - # time bins are parsed but unused for now - end_idx = start_idx + nt_i - time_bounds = ww_data[start_idx:end_idx] - np.insert(time_bounds, (0,), (0.0,)) - start_idx = end_idx - - # read energy boundaries - end_idx = start_idx + ne_i - energy_bounds = np.insert(ww_data[start_idx:end_idx], (0,), (0.0,)) - # convert from MeV to eV - energy_bounds *= 1e6 + nt = ni * [1] + + if nr == 16: + raise NotImplementedError('Cylindrical and spherical mesh ' + 'types are not yet supported') + + # read number of energy bins for each particle, 'ne(1...ni)' + ne = np.fromstring(wwinp.readline(), sep=' ', dtype=int) + + # read coarse mesh dimensions and lower left corner + mesh_description = np.fromstring(wwinp.readline(), sep=' ') + nfx, nfy, nfz = mesh_description[:3].astype(int) + xyz0 = mesh_description[3:] + + # read cylindrical and spherical mesh vectors if present + if nr == 16: + # read number of coarse bins + line_arr = np.fromstring(wwinp.readline(), sep=' ') + ncx, ncy, ncz = line_arr[:3].astype(int) + # read polar vector (x1, y1, z1) + xyz1 = line_arr[3:] - xyz0 + polar_vec = xyz1 / np.linalg.norm(xyz1) + # read azimuthal vector (x2, y2, z2) + line_arr = np.fromstring(wwinp.readline(), sep=' ') + xyz2 = line_arr[:3] - xyz0 + azimuthal_vec = xyz2 / np.linalg.norm(xyz2) + # read geometry type + nwg = int(line_arr[-1]) + elif nr == 10: + # read rectilinear data: + # number of coarse mesh bins and mesh type + ncx, ncy, ncz, nwg = \ + np.fromstring(wwinp.readline(), sep=' ').astype(int) + else: + raise RuntimeError(f'Invalid mesh description (nr) found: {nr}') + + # read BLOCK 2 and BLOCK 3 data into a single array + ww_data = np.fromstring(wwinp.read(), sep=' ') + + # extract mesh data from the ww_data array + start_idx = 0 + + # first values in the mesh definition arrays are the first + # coordinate of the grid + end_idx = start_idx + 1 + 3 * ncx + x0, x_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + start_idx = end_idx + + end_idx = start_idx + 1 + 3 * ncy + y0, y_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + start_idx = end_idx + + end_idx = start_idx + 1 + 3 * ncz + z0, z_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + start_idx = end_idx + + # mesh consistency checks + if nr == 16 and nwg == 1: + raise ValueError(f'Mesh description in header ({nr}) ' + f'does not match the mesh type ({nwg})') + + if (xyz0 != (x0, y0, z0)).any(): + raise ValueError(f'Mesh origin in the header ({xyz0}) ' + f' does not match the origin in the mesh ' + f' description ({x0, y0, z0})') + + # create openmc mesh object + grids = [] + mesh_definition = [(x0, x_vals, nfx), (y0, y_vals, nfy), (z0, z_vals, nfz)] + for grid0, grid_vals, n_pnts in mesh_definition: + # file spec checks for the mesh definition + if (grid_vals[2::3] != 1.0).any(): + raise ValueError('One or more mesh ratio value, qx, ' + 'is not equal to one') + + if grid_vals[::3].sum() != n_pnts: + raise ValueError('Sum of the fine bin entries, s, does ' + 'not match the number of fine bins') + + # extend the grid based on the next coarse bin endpoint, px + # and the number of fine bins in the coarse bin, sx + intervals = grid_vals.reshape(-1, 3) + coords = [grid0] + for sx, px, qx in intervals: + coords += np.linspace(coords[-1], px, int(sx + 1)).tolist()[1:] + + grids.append(np.array(coords)) + + mesh = RectilinearMesh() + mesh.x_grid, mesh.y_grid, mesh.z_grid = grids + + # extract weight window values from array + wws = [] + for ne_i, nt_i, particle_type in zip(ne, nt, ('neutron', 'photon')): + # no information to read for this particle if + # either the energy bins or time bins are empty + if ne_i == 0 or nt_i == 0: + continue + + if iv > 1: + # time bins are parsed but unused for now + end_idx = start_idx + nt_i + time_bounds = ww_data[start_idx:end_idx] + np.insert(time_bounds, (0,), (0.0,)) start_idx = end_idx - # read weight window values - end_idx = start_idx + (nfx * nfy * nfz) * nt_i * ne_i + # read energy boundaries + end_idx = start_idx + ne_i + energy_bounds = np.insert(ww_data[start_idx:end_idx], (0,), (0.0,)) + # convert from MeV to eV + energy_bounds *= 1e6 + start_idx = end_idx - # read values and reshape according to ordering - # slowest to fastest: t, e, z, y, x - # reorder with transpose since our ordering is x, y, z, e, t - ww_shape = (nt_i, ne_i, nfz, nfy, nfx) - ww_values = ww_data[start_idx:end_idx].reshape(ww_shape).T - # Only use first time bin since we don't support time dependent weight - # windows yet. - ww_values = ww_values[:, :, :, :, 0] - start_idx = end_idx + # read weight window values + end_idx = start_idx + (nfx * nfy * nfz) * nt_i * ne_i - # create a weight window object - ww = WeightWindows(id=None, - mesh=mesh, - lower_ww_bounds=ww_values, - upper_bound_ratio=5.0, - energy_bounds=energy_bounds, - particle_type=particle_type) - wws.append(ww) + # read values and reshape according to ordering + # slowest to fastest: z, y, x, e + ww_values = ww_data[start_idx:end_idx].reshape(nfz, nfy, nfx, ne_i) + # swap z and x axes for correct shape and (ijk, e) mesh indexing + ww_values = np.swapaxes(ww_values, 2, 0) + start_idx = end_idx - return wws + # create a weight window object + ww = WeightWindows(id=None, + mesh=mesh, + lower_ww_bounds=ww_values, + upper_bound_ratio=5.0, + energy_bounds=energy_bounds, + particle_type=particle_type) + wws.append(ww) - def export_to_hdf5(self, path: PathLike = 'weight_windows.h5', **init_kwargs): - """Write weight windows to an HDF5 file. - - Parameters - ---------- - path : PathLike - Path to the file to write weight windows to - **init_kwargs - Keyword arguments passed to :func:`openmc.lib.init` - - """ - import openmc.lib - cv.check_type('path', path, PathLike) - - # Create a temporary model with the weight windows - model = openmc.Model() - sph = openmc.Sphere(boundary_type='vacuum') - cell = openmc.Cell(region=-sph) - model.geometry = openmc.Geometry([cell]) - model.settings.weight_windows = self - model.settings.particles = 100 - model.settings.batches = 1 - - # Get absolute path before moving to temporary directory - path = Path(path).resolve() - - # Load the model with openmc.lib and then export it to an HDF5 file - with openmc.lib.TemporarySession(model, **init_kwargs): - openmc.lib.export_weight_windows(path) + return wws diff --git a/pyproject.toml b/pyproject.toml index c769fb7d7..ac6735593 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,77 +1,2 @@ [build-system] -requires = ["setuptools", "setuptools-scm", "wheel"] -build-backend = "setuptools.build_meta" - -[project] -name = "openmc" -authors = [ - {name = "The OpenMC Development Team", email = "openmc@anl.gov"}, -] -description = "OpenMC" -dynamic = ["version"] -requires-python = ">=3.12" -license = {file = "LICENSE"} -classifiers = [ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Natural Language :: English", - "Topic :: Scientific/Engineering", - "Programming Language :: C++", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", -] -dependencies = [ - "numpy", - "h5py", - "scipy", - "ipython", - "matplotlib", - "pandas", - "lxml", - "uncertainties", - "endf", -] - -[project.optional-dependencies] -depletion-mpi = ["mpi4py"] -docs = [ - "breathe", - "sphinx", - "sphinxcontrib-katex", - "sphinx-numfig", - "jupyter", - "sphinxcontrib-svg2pdfconverter", - "sphinx-rtd-theme" -] -test = [ - "packaging", - "pytest", - "pytest-cov>=4.0", - "pytest-rerunfailures", - "colorama", - "openpyxl", -] -ci = ["coverage>=7.4", "gcovr>=7.2"] -vtk = ["vtk"] - -[project.urls] -Homepage = "https://openmc.org" -Documentation = "https://docs.openmc.org" -Repository = "https://github.com/openmc-dev/openmc" -Issues = "https://github.com/openmc-dev/openmc/issues" - -[tool.setuptools.packages.find] -include = ['openmc*'] -exclude = ['tests*'] - -[tool.setuptools.package-data] -"openmc.data.dose" = ["**/*.txt", "*.h5"] -"openmc.data" = ["*.txt", "*.DAT", "*.json", "*.h5"] -"openmc.lib" = ["libopenmc.dylib", "libopenmc.so"] - -[tool.setuptools_scm] +requires = ["setuptools", "wheel", "numpy<1.22", "cython"] diff --git a/schemas.xml b/schemas.xml new file mode 100644 index 000000000..3e586ec6a --- /dev/null +++ b/schemas.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/scripts/openmc-ace-to-hdf5 b/scripts/openmc-ace-to-hdf5 new file mode 100755 index 000000000..7c391fd6f --- /dev/null +++ b/scripts/openmc-ace-to-hdf5 @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 + +"""This script can be used to create HDF5 nuclear data libraries used by +OpenMC. There are four different ways you can specify ACE libraries that are to +be converted: + +1. List each ACE library as a positional argument. This is very useful in + conjunction with the usual shell utilities (ls, find, etc.). +2. Use the --xsdir option to specify a MCNP xsdir file. +3. Use the --xsdata option to specify a Serpent xsdata file. + +The script does not use any extra information from xsdir/xsdata files to +determine whether the nuclide is metastable. Instead, the --metastable argument +can be used to specify whether the ZAID naming convention follows the NNDC data +convention (1000*Z + A + 300 + 100*m), or the MCNP data convention (essentially +the same as NNDC, except that the first metastable state of Am242 is 95242 and +the ground state is 95642). + +""" + +import argparse +from functools import partial +import os +from pathlib import Path +import warnings + +import openmc.data +from openmc.data.ace import TableType + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=CustomFormatter +) +parser.add_argument('libraries', nargs='*', + help='ACE libraries to convert to HDF5') +parser.add_argument('-d', '--destination', type=Path, default=Path.cwd(), + help='Directory to create new library in') +parser.add_argument('-m', '--metastable', choices=['mcnp', 'nndc'], + default='nndc', + help='How to interpret ZAIDs for metastable nuclides') +parser.add_argument('--xsdir', help='MCNP xsdir file that lists ' + 'ACE libraries') +parser.add_argument('--xsdata', help='Serpent xsdata file that lists ' + 'ACE libraries') +parser.add_argument('--libver', choices=['earliest', 'latest'], + default='earliest', help="Output HDF5 versioning. Use " + "'earliest' for backwards compatibility or 'latest' for " + "performance") +args = parser.parse_args() + +if not args.destination.is_dir(): + args.destination.mkdir(parents=True, exist_ok=True) + +ace_libraries = [] +if args.xsdir is not None: + ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdir(args.xsdir)) +elif args.xsdata is not None: + ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdata(args.xsdata)) +else: + ace_libraries = [Path(lib) for lib in args.libraries] + +converted = {} +library = openmc.data.DataLibrary() + +for path in ace_libraries: + # Check that ACE library exists + if not os.path.exists(path): + warnings.warn("ACE library '{}' does not exist.".format(path)) + continue + + lib = openmc.data.ace.Library(path) + for table in lib.tables: + # Check type of the ACE table and determine appropriate class / + # conversion function + if table.data_type == TableType.NEUTRON_CONTINUOUS: + name = table.zaid + cls = openmc.data.IncidentNeutron + converter = partial(cls.from_ace, metastable_scheme=args.metastable) + elif table.data_type == TableType.THERMAL_SCATTERING: + # Adjust name to be the new thermal scattering name + name = openmc.data.get_thermal_name(table.zaid) + cls = openmc.data.ThermalScattering + converter = cls.from_ace + else: + print("Can't convert ACE table {}".format(table.name)) + continue + + if name not in converted: + try: + data = converter(table) + except Exception as e: + print('Failed to convert {}: {}'.format(table.name, e)) + continue + + print('Converting {} (ACE) to {} (HDF5)'.format(table.name, data.name)) + + # Determine output filename + outfile = args.destination / (data.name.replace('.', '_') + '.h5') + data.export_to_hdf5(outfile, 'w', libver=args.libver) + + # Register with library + library.register_file(outfile) + + # Add nuclide to list + converted[name] = outfile + else: + # Read existing HDF5 file + data = cls.from_hdf5(converted[name]) + + # Add data for new temperature + try: + print('Converting {} (ACE) to {} (HDF5)' + .format(table.name, data.name)) + data.add_temperature_from_ace(table, args.metastable) + except Exception as e: + print('Failed to convert {}: {}'.format(table.name, e)) + continue + + # Re-export + data.export_to_hdf5(converted[name], 'w', libver=args.libver) + +# Write cross_sections.xml +library.export_to_xml(args.destination / 'cross_sections.xml') diff --git a/scripts/openmc-make-test-data b/scripts/openmc-make-test-data new file mode 100755 index 000000000..4d26db7fb --- /dev/null +++ b/scripts/openmc-make-test-data @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 + +""" +Download ENDF/B-VII.1 ENDF and ACE files from NNDC and WMP files from GitHub and +generate a full HDF5 library with incident neutron, incident photon, thermal +scattering data, and windowed multipole data. This data is used for OpenMC's +regression test suite. +""" + +import glob +import os +from pathlib import Path +import tarfile +import tempfile +from urllib.parse import urljoin +import zipfile + +import openmc.data +from openmc._utils import download + +base_ace = 'https://www.nndc.bnl.gov/endf/b7.1/aceFiles/' +base_endf = 'https://www.nndc.bnl.gov/endf/b7.1/zips/' +base_wmp = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/' +files = [ + (base_ace, 'ENDF-B-VII.1-neutron-293.6K.tar.gz', '9729a17eb62b75f285d8a7628ace1449'), + (base_ace, 'ENDF-B-VII.1-tsl.tar.gz', 'e17d827c92940a30f22f096d910ea186'), + (base_endf, 'ENDF-B-VII.1-neutrons.zip', 'e5d7f441fc4c92893322c24d1725e29c'), + (base_endf, 'ENDF-B-VII.1-photoat.zip', '5192f94e61f0b385cf536f448ffab4a4'), + (base_endf, 'ENDF-B-VII.1-atomic_relax.zip', 'fddb6035e7f2b6931e51a58fc754bd10'), + (base_wmp, 'WMP_Library_v1.1.tar.gz', '8523895928dd6ba63fba803e3a45d4f3') +] + + +def fix_zaid(table, old, new): + filename = os.path.join('tsl', table) + with open(filename, 'r') as fh: + text = fh.read() + text = text.replace(old, new, 1) + with open(filename, 'w') as fh: + fh.write(text) + +pwd = Path.cwd() +output_dir = pwd / 'nndc_hdf5' +os.makedirs('nndc_hdf5/photon', exist_ok=True) + +with tempfile.TemporaryDirectory() as tmpdir: + # Temporarily change dir + os.chdir(tmpdir) + + # ========================================================================= + # Download files from NNDC server + for base, fname, checksum in files: + download(urljoin(base, fname), checksum) + + # ========================================================================= + # EXTRACT FILES FROM TGZ + + for _, f, _ in files: + print('Extracting {}...'.format(f)) + path = Path(f) + if path.suffix == '.gz': + with tarfile.open(f, 'r') as tgz: + if 'tsl' in f: + tgz.extractall(path='tsl') + else: + tgz.extractall() + elif path.suffix == '.zip': + zipfile.ZipFile(f).extractall() + + # ========================================================================= + # FIX ZAID ASSIGNMENTS FOR VARIOUS S(A,B) TABLES + + print('Fixing ZAIDs for S(a,b) tables') + fix_zaid('bebeo.acer', '8016', ' 0') + fix_zaid('obeo.acer', '4009', ' 0') + + library = openmc.data.DataLibrary() + + # ========================================================================= + # INCIDENT NEUTRON DATA + + neutron_files = sorted(glob.glob('ENDF-B-VII.1-neutron-293.6K/*.ace')) + for f in neutron_files: + print('Converting {}...'.format(os.path.basename(f))) + data = openmc.data.IncidentNeutron.from_ace(f) + + # Check for fission energy release data on MF=1, MT=458 + endf_filename = 'neutrons/n-{:03}_{}_{:03}{}.endf'.format( + data.atomic_number, + data.atomic_symbol, + data.mass_number, + 'm{}'.format(data.metastable) if data.metastable else '' + ) + ev = openmc.data.endf.Evaluation(endf_filename) + if (1, 458) in ev.section: + endf_data = openmc.data.IncidentNeutron.from_endf(ev) + data.fission_energy = endf_data.fission_energy + + # Add 0K elastic scattering data for select nuclides + if data.name in ('U235', 'U238', 'Pu239'): + data.add_elastic_0K_from_endf(endf_filename) + + # Determine filename + outfile = output_dir / (data.name + '.h5') + data.export_to_hdf5(outfile, 'w', 'earliest') + + # Register with library + library.register_file(outfile) + + # ========================================================================= + # THERMAL SCATTERING DATA + + thermal_files = sorted(glob.glob('tsl/*.acer')) + for f in thermal_files: + print('Converting {}...'.format(os.path.basename(f))) + data = openmc.data.ThermalScattering.from_ace(f) + + # Determine filename + outfile = output_dir / (data.name + '.h5') + data.export_to_hdf5(outfile, 'w', 'earliest') + + # Register with library + library.register_file(outfile) + + # ========================================================================= + # INCIDENT PHOTON DATA + + for z in range(1, 101): + element = openmc.data.ATOMIC_SYMBOL[z] + print('Generating HDF5 file for Z={} ({})...'.format(z, element)) + + # Generate instance of IncidentPhoton + photo_file = Path('photoat') / 'photoat-{:03}_{}_000.endf'.format(z, element) + atom_file = Path('atomic_relax') / 'atom-{:03}_{}_000.endf'.format(z, element) + data = openmc.data.IncidentPhoton.from_endf(photo_file, atom_file) + + # Write HDF5 file and register it + outfile = output_dir / 'photon' / (element + '.h5') + data.export_to_hdf5(outfile, 'w', 'earliest') + library.register_file(outfile) + + # ========================================================================= + # WINDOWED MULTIPOLE DATA + + # Move data into output directory + os.rename('WMP_Library', str(output_dir / 'wmp')) + + # Add multipole data to library + for f in sorted(glob.glob('{}/wmp/*.h5'.format(output_dir))): + print('Registering WMP file {}...'.format(f)) + library.register_file(f) + + library.export_to_xml(output_dir / 'cross_sections.xml') + + # ========================================================================= + # CREATE TARBALL AND MOVE BACK + + print('Creating compressed archive...') + test_tar = pwd / 'nndc_hdf5_test.tar.xz' + with tarfile.open(str(test_tar), 'w:xz') as txz: + txz.add(output_dir) + + # Change back to original directory + os.chdir(str(pwd)) diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally new file mode 100755 index 000000000..2a4fcd743 --- /dev/null +++ b/scripts/openmc-plot-mesh-tally @@ -0,0 +1,344 @@ +#!/usr/bin/env python3 + +"""Python script to plot tally data generated by OpenMC.""" + + +import os +import sys +import argparse +import tkinter as tk +import tkinter.filedialog as filedialog +import tkinter.font as font +import tkinter.messagebox as messagebox +import tkinter.ttk as ttk + +import matplotlib +matplotlib.use("TkAgg") +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk +from matplotlib.figure import Figure +import matplotlib.pyplot as plt +import numpy as np + +from openmc import StatePoint, MeshFilter, UnstructuredMesh + +_COMBOBOX_SELECTED = '<>' + + +def mesh_filter_check(filter): + """ + Check that the filter is a usable mesh filter + """ + return isinstance(filter, MeshFilter) and not isinstance(filter.mesh, UnstructuredMesh) + + +class MeshPlotter(tk.Frame): + def __init__(self, parent, filename): + super().__init__(parent) + + self.labels = { + 'Cell': 'Cell:', + 'Cellborn': 'Cell born:', + 'Surface': 'Surface:', + 'Material': 'Material:', + 'Universe': 'Universe:', + 'Energy': 'Energy in:', + 'Energyout': 'Energy out:' + } + + self.filterBoxes = {} + + # Read data from source or leakage fraction file + self.get_file_data(filename) + + # Set up top-level window + top = self.winfo_toplevel() + top.title('Mesh Tally Plotter: ' + filename) + top.rowconfigure(0, weight=1) + top.columnconfigure(0, weight=1) + self.grid(sticky=tk.W+tk.N) + + # Create widgets and draw to screen + self.create_widgets() + self.update() + + def create_widgets(self): + figureFrame = tk.Frame(self) + figureFrame.grid(row=0, column=0) + + # Create the Figure and Canvas + self.dpi = 100 + self.fig = Figure((5.0, 5.0), dpi=self.dpi) + self.canvas = FigureCanvasTkAgg(self.fig, master=figureFrame) + self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) + + # Create the navigation toolbar, tied to the canvas + self.mpl_toolbar = NavigationToolbar2Tk(self.canvas, figureFrame) + self.mpl_toolbar.update() + self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) + + # Create frame for comboboxes + self.selectFrame = tk.Frame(self) + self.selectFrame.grid(row=1, column=0, sticky=tk.W+tk.E) + + # Tally selection + labelTally = tk.Label(self.selectFrame, text='Tally:') + labelTally.grid(row=0, column=0, sticky=tk.W) + self.tallyBox = ttk.Combobox(self.selectFrame, state='readonly') + self.tallyBox['values'] = [self.datafile.tallies[i].id + for i in self.meshTallies] + self.tallyBox.current(0) + self.tallyBox.grid(row=0, column=1, sticky=tk.W+tk.E) + self.tallyBox.bind(_COMBOBOX_SELECTED, self.update) + + # Planar basis selection + labelBasis = tk.Label(self.selectFrame, text='Basis:') + labelBasis.grid(row=1, column=0, sticky=tk.W) + self.basisBox = ttk.Combobox(self.selectFrame, state='readonly') + self.basisBox['values'] = ('xy', 'yz', 'xz') + self.basisBox.current(0) + self.basisBox.grid(row=1, column=1, sticky=tk.W+tk.E) + self.basisBox.bind(_COMBOBOX_SELECTED, self.update) + + # Axial level + labelAxial = tk.Label(self.selectFrame, text='Axial level:') + labelAxial.grid(row=2, column=0, sticky=tk.W) + self.axialBox = ttk.Combobox(self.selectFrame, state='readonly') + self.axialBox.grid(row=2, column=1, sticky=tk.W+tk.E) + self.axialBox.bind(_COMBOBOX_SELECTED, self.redraw) + + # Option for mean/uncertainty + labelMean = tk.Label(self.selectFrame, text='Mean/Uncertainty:') + labelMean.grid(row=3, column=0, sticky=tk.W) + self.meanBox = ttk.Combobox(self.selectFrame, state='readonly') + self.meanBox['values'] = ('Mean', 'Absolute uncertainty', + 'Relative uncertainty') + self.meanBox.current(0) + self.meanBox.grid(row=3, column=1, sticky=tk.W+tk.E) + self.meanBox.bind(_COMBOBOX_SELECTED, self.update) + + # Scores + labelScore = tk.Label(self.selectFrame, text='Score:') + labelScore.grid(row=4, column=0, sticky=tk.W) + self.scoreBox = ttk.Combobox(self.selectFrame, state='readonly') + self.scoreBox.grid(row=4, column=1, sticky=tk.W+tk.E) + self.scoreBox.bind(_COMBOBOX_SELECTED, self.redraw) + + # Filter label + boldfont = font.Font(weight='bold') + labelFilters = tk.Label(self.selectFrame, text='Filters:', + font=boldfont) + labelFilters.grid(row=5, column=0, sticky=tk.W) + + def update(self, event=None): + widget = event.widget if event else None + + tally_id = self.meshTallies[self.tallyBox.current()] + selectedTally = self.datafile.tallies[tally_id] + + # Get mesh for selected tally + self.mesh = selectedTally.find_filter(MeshFilter).mesh + + # Get mesh dimensions + if len(self.mesh.dimension) == 2: + self.nx, self.ny = self.mesh.dimension + self.nz = 1 + else: + self.nx, self.ny, self.nz = self.mesh.dimension + + # Repopulate comboboxes baesd on current basis selection + text = self.basisBox.get() + if text == 'xy': + self.axialBox['values'] = [str(i+1) for i in range(self.nz)] + elif text == 'yz': + self.axialBox['values'] = [str(i+1) for i in range(self.nx)] + else: + self.axialBox['values'] = [str(i+1) for i in range(self.ny)] + self.axialBox.current(0) + + # If update() was called by a change in the basis combobox, we don't + # need to repopulate the filters + if widget == self.basisBox: + self.redraw() + return + + # Update scores + self.scoreBox['values'] = selectedTally.scores + self.scoreBox.current(0) + + # Remove any filter labels/comboboxes that exist + for row in range(6, self.selectFrame.grid_size()[1]): + for w in self.selectFrame.grid_slaves(row=row): + w.grid_forget() + w.destroy() + + # create a label/combobox for each filter in selected tally + count = 0 + for f in selectedTally.filters: + filterType = f.short_name + if filterType == 'Mesh': + continue + count += 1 + + # Create label and combobox for this filter + label = tk.Label(self.selectFrame, text=self.labels[filterType]) + label.grid(row=count+6, column=0, sticky=tk.W) + combobox = ttk.Combobox(self.selectFrame, state='readonly') + self.filterBoxes[filterType] = combobox + + # Set combobox items + if filterType in ['Energy', 'Energyout']: + combobox['values'] = ['{} to {}'.format(*ebin) + for ebin in f.bins] + else: + combobox['values'] = [str(i) for i in f.bins] + + combobox.current(0) + combobox.grid(row=count+6, column=1, sticky=tk.W+tk.E) + combobox.bind(_COMBOBOX_SELECTED, self.redraw) + + # If There are no filters, leave a 'None available' message + if count == 0: + count += 1 + label = tk.Label(self.selectFrame, text="None Available") + label.grid(row=count+6, column=0, sticky=tk.W) + + self.redraw() + + def redraw(self, event=None): + basis = self.basisBox.current() + 1 + axial_level = self.axialBox.current() + 1 + mbvalue = self.meanBox.get() + + # Get selected tally + tally_id = self.meshTallies[self.tallyBox.current()] + selectedTally = self.datafile.tallies[tally_id] + + # Create spec_list + spec_list = [] + for f in selectedTally.filters: + if f.short_name == 'Mesh': + mesh_filter = f + continue + elif f.short_name in ['Energy', 'Energyout']: + index = self.filterBoxes[f.short_name].current() + ebin = f.bins[index] + spec_list.append((type(f), (ebin,))) + else: + index = self.filterBoxes[f.short_name].current() + spec_list.append((type(f), (index,))) + + dims = (self.nx, self.ny, self.nz) + + text = self.basisBox.get() + if text == 'xy': + h_ind = 0 + v_ind = 1 + elif text == 'yz': + h_ind = 1 + v_ind = 2 + else: + h_ind = 0 + v_ind = 2 + + axial_ind = 3 - (h_ind + v_ind) + dims = (dims[h_ind], dims[v_ind]) + + mesh_dim = len(self.mesh.dimension) + if mesh_dim == 3: + mesh_indices = [0,0,0] + else: + mesh_indices = [0,0] + + matrix = np.zeros(dims) + for i in range(dims[0]): + for j in range(dims[1]): + if mesh_dim == 3: + mesh_indices[h_ind] = i + 1 + mesh_indices[v_ind] = j + 1 + mesh_indices[axial_ind] = axial_level + else: + mesh_indices[0] = i + 1 + mesh_indices[1] = j + 1 + filters, filter_bins = zip(*spec_list + [ + (type(mesh_filter), (tuple(mesh_indices),))]) + mean = selectedTally.get_values( + [self.scoreBox.get()], filters, filter_bins) + stdev = selectedTally.get_values( + [self.scoreBox.get()], filters, filter_bins, + value='std_dev') + if mbvalue == 'Mean': + matrix[i, j] = mean + elif mbvalue == 'Absolute uncertainty': + matrix[i, j] = stdev + else: + if mean > 0.: + matrix[i, j] = stdev/mean + else: + matrix[i, j] = 0. + + # Clear the figure + self.fig.clear() + + # Make figure, set up color bar + self.axes = self.fig.add_subplot(111) + cax = self.axes.imshow(matrix.transpose(), vmin=0.0, vmax=matrix.max(), + interpolation='none', origin='lower') + self.fig.colorbar(cax) + + self.axes.set_xticks([]) + self.axes.set_yticks([]) + self.axes.set_aspect('equal') + + # Draw canvas + self.canvas.draw() + + def get_file_data(self, filename): + # Create StatePoint object and read in data + self.datafile = StatePoint(filename) + + meshes = self.datafile.meshes + if any(isinstance(m, UnstructuredMesh) for m in meshes.values()): + warn_msg = "Unstructured meshes are present in the" \ + " statepoint file but are not currently" \ + " supported by this script" + messagebox.showwarning("Unstructured Meshes", message=warn_msg) + + # Find which tallies are mesh tallies + self.meshTallies = [] + for itally, tally in self.datafile.tallies.items(): + if any([mesh_filter_check(f) for f in tally.filters]): + self.meshTallies.append(itally) + + if not self.meshTallies: + messagebox.showerror("Invalid StatePoint File", + "File does not contain mesh tallies!") + sys.exit(1) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('statepoint', nargs='?', help='Statepoint file') + args = parser.parse_args() + + # Hide root window + root = tk.Tk() + root.withdraw() + + # If no filename given as command-line argument, open file dialog + if args.statepoint is None: + filename = filedialog.askopenfilename(title='Select statepoint file', + initialdir='.') + else: + filename = args.statepoint + + if filename: + # Check to make sure file exists + if not os.path.isfile(filename): + messagebox.showerror("File not found", + "Could not find regular file: " + filename) + sys.exit(1) + + app = MeshPlotter(root, filename) + root.deiconify() + root.mainloop() diff --git a/scripts/openmc-track-combine b/scripts/openmc-track-combine new file mode 100755 index 000000000..f69f2151c --- /dev/null +++ b/scripts/openmc-track-combine @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +"""Combine multiple HDF5 particle track files.""" + +import argparse + +import openmc + + +def main(): + # Parse command-line arguments + parser = argparse.ArgumentParser( + description='Combine particle track files into a single .h5 file.') + parser.add_argument('input', metavar='IN', nargs='+', + help='Input HDF5 particle track filename(s).') + parser.add_argument('-o', '--out', metavar='OUT', default='tracks.h5', + help='Output HDF5 particle track file.') + + args = parser.parse_args() + openmc.Tracks.combine(args.input, args.out) + + +if __name__ == '__main__': + main() diff --git a/scripts/openmc-track-to-vtk b/scripts/openmc-track-to-vtk new file mode 100755 index 000000000..82439bea7 --- /dev/null +++ b/scripts/openmc-track-to-vtk @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +"""Convert HDF5 particle track to VTK poly data. + +""" + +import argparse + +import openmc +import vtk + + +def _parse_args(): + # Create argument parser. + parser = argparse.ArgumentParser( + description='Convert particle track file(s) to a .pvtp file.') + parser.add_argument('input', metavar='IN', type=str, + help='Input particle track data filename.') + parser.add_argument('-o', '--out', metavar='OUT', type=str, dest='out', + help='Output VTK poly data filename.') + + # Parse and return commandline arguments. + return parser.parse_args() + + +def main(): + # Parse commandline arguments. + args = _parse_args() + + # Make sure that the output filename ends with '.pvtp'. + if not args.out: + args.out = 'tracks.pvtp' + elif not args.out.endswith('.pvtp'): + args.out += '.pvtp' + + # Write coordinate values to points array. + track_file = openmc.Tracks(args.input) + track_file.write_to_vtk(args.out) + +if __name__ == '__main__': + main() diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs new file mode 100755 index 000000000..c47f888c8 --- /dev/null +++ b/scripts/openmc-update-inputs @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +"""Update OpenMC's input XML files to the latest format. + +""" + +import argparse +from difflib import get_close_matches +from itertools import chain +from random import randint +from shutil import move +import xml.etree.ElementTree as ET + +import openmc.data + + +description = "Update OpenMC's input XML files to the latest format." +epilog = """\ +If any of the given files do not match the most up-to-date formatting, then they +will be automatically rewritten. The old out-of-date files will not be deleted; +they will be moved to a new file with '.original' appended to their name. + +Formatting changes that will be made: + +geometry.xml: Lattices containing 'outside' attributes/tags will be replaced + with lattices containing 'outer' attributes, and the appropriate + cells/universes will be added. Any 'surfaces' attributes/elements on a cell + will be renamed 'region'. + +materials.xml: Nuclide names will be changed from ACE aliases (e.g., Am-242m) to + HDF5/GND names (e.g., Am242_m1). Thermal scattering table names will be + changed from ACE aliases (e.g., HH2O) to HDF5/GND names (e.g., c_H_in_H2O). + +""" + + +def parse_args(): + """Read the input files from the commandline.""" + # Create argument parser. + parser = argparse.ArgumentParser( + description=description, + epilog=epilog, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('input', metavar='IN', type=str, nargs='+', + help='Input XML file(s).') + + # Parse and return commandline arguments. + return parser.parse_args() + + +def get_universe_ids(geometry_root): + """Return a set of universe id numbers.""" + root = geometry_root + out = set() + + # Get the ids of universes defined by cells. + for cell in root.iter('cell'): + # Get universe attributes/elements + if 'universe' in cell.attrib: + uid = cell.attrib['universe'] + out.add(int(uid)) + elif cell.find('universe') is not None: + elem = cell.find('universe') + uid = elem.text + out.add(int(uid)) + else: + # Default to universe 0 + out.add(0) + + # Get the ids of universes defined by lattices. + for lat in root.iter('lattice'): + # Get id attributes. + if 'id' in lat.attrib: + uid = lat.attrib['id'] + out.add(int(uid)) + + # Get id elements. + elif lat.find('id') is not None: + elem = lat.find('id') + uid = elem.text + out.add(int(uid)) + + return out + + +def get_cell_ids(geometry_root): + """Return a set of cell id numbers.""" + root = geometry_root + out = set() + + # Get the ids of universes defined by cells. + for cell in root.iter('cell'): + # Get id attributes. + if 'id' in cell.attrib: + cid = cell.attrib['id'] + out.add(int(cid)) + + # Get id elements. + elif cell.find('id') is not None: + elem = cell.find('id') + cid = elem.text + out.add(int(cid)) + + return out + + +def find_new_id(current_ids, preferred=None): + """Return a new id that is not already present in current_ids.""" + distance_from_preferred = 21 + max_random_attempts = 10000 + + # First, try to find an id near the preferred number. + if preferred is not None: + assert isinstance(preferred, int) + for i in range(1, distance_from_preferred): + if (preferred - i not in current_ids) and (preferred - i > 0): + return preferred - i + if (preferred + i not in current_ids) and (preferred + i > 0): + return preferred + i + + # If that was unsuccessful, attempt to randomly guess a new id number. + for i in range(max_random_attempts): + num = randint(1, 2147483647) + if num not in current_inds: + return num + + # Raise an error if an id was not found. + raise RuntimeError('Could not find a unique id number for a new universe.') + + +def get_lat_id(lattice_element): + """Return the id integer of the lattice_element.""" + assert isinstance(lattice_element, ET.Element) + if 'id' in lattice_element.attrib: + return int(lattice_element.attrib['id'].strip()) + elif any([child.tag == 'id' for child in lattice_element]): + elem = lattice_element.find('id') + return int(elem.text.strip()) + else: + raise RuntimeError('Could not find the id for a lattice.') + + +def pop_lat_outside(lattice_element): + """Return lattice's outside material and remove from attributes/elements.""" + assert isinstance(lattice_element, ET.Element) + + # Check attributes. + if 'outside' in lattice_element.attrib: + material = lattice_element.attrib['outside'].strip() + del lattice_element.attrib['outside'] + + # Check subelements. + elif any([child.tag == 'outside' for child in lattice_element]): + elem = lattice_element.find('outside') + material = elem.text.strip() + lattice_element.remove(elem) + + # No 'outside' specified. This means the outside is a void. + else: + material = 'void' + + return material + + +def update_geometry(geometry_root): + """Update the given XML geometry tree. Return True if changes were made.""" + root = geometry_root + was_updated = False + + # Get a set of already-used universe and cell ids. + uids = get_universe_ids(root) + cids = get_cell_ids(root) + taken_ids = uids.union(cids) + + # Replace 'outside' with 'outer' in lattices. + for lat in chain(root.iter('lattice'), root.iter('hex_lattice')): + # Get the lattice's id. + lat_id = get_lat_id(lat) + + # Ignore lattices that have 'outer' specified. + if any([child.tag == 'outer' for child in lat]): continue + if 'outer' in lat.attrib: continue + + # Pop the 'outside' material. + material = pop_lat_outside(lat) + + # Get an id number for a new outer universe. Ideally, the id should + # be close to the lattice's id. + new_uid = find_new_id(taken_ids, preferred=lat_id) + assert new_uid not in taken_ids + + # Add the new universe filled with the old 'outside' material to the + # geometry. + new_cell = ET.Element('cell') + new_cell.attrib['id'] = str(new_uid) + new_cell.attrib['universe'] = str(new_uid) + new_cell.attrib['material'] = material + root.append(new_cell) + taken_ids.add(new_uid) + + # Add the new universe to the lattice's 'outer' attribute. + lat.attrib['outer'] = str(new_uid) + + was_updated = True + + # Remove 'type' from lattice definitions. + for lat in root.iter('lattice'): + elem = lat.find('type') + if elem is not None: + lat.remove(elem) + was_updated = True + if 'type' in lat.attrib: + del lat.attrib['type'] + was_updated = True + + # Change 'width' to 'pitch' in lattice definitions. + for lat in root.iter('lattice'): + elem = lat.find('width') + if elem is not None: + elem.tag = 'pitch' + was_updated = True + if 'width' in lat.attrib: + lat.attrib['pitch'] = lat.attrib['width'] + del lat.attrib['width'] + was_updated = True + + # Change 'surfaces' to 'region' in cell definitions + for cell in root.iter('cell'): + elem = cell.find('surfaces') + if elem is not None: + elem.tag = 'region' + was_updated = True + if 'surfaces' in cell.attrib: + cell.attrib['region'] = cell.attrib['surfaces'] + del cell.attrib['surfaces'] + was_updated = True + + return was_updated + +def update_materials(root): + """Update the given XML materials tree. Return True if changes were made.""" + was_updated = False + + for material in root.findall('material'): + for nuclide in material.findall('nuclide'): + if 'name' in nuclide.attrib: + nucname = nuclide.attrib['name'].replace('-', '') + # If a nuclide name is in the ZAID notation (e.g., a number), + # convert it to the proper nuclide name. + if nucname.strip().isnumeric(): + nucname = openmc.data.ace.get_metadata(int(nucname))[0] + nucname = nucname.replace('Nat', '0') + if nucname.endswith('m'): + nucname = nucname[:-1] + '_m1' + nuclide.set('name', nucname) + was_updated = True + + elif nuclide.find('name') is not None: + name_elem = nuclide.find('name') + nucname = name_elem.text + nucname = nucname.replace('-', '') + nucname = nucname.replace('Nat', '0') + if nucname.endswith('m'): + nucname = nucname[:-1] + '_m1' + name_elem.text = nucname + was_updated = True + + for sab in material.findall('sab'): + if 'name' in sab.attrib: + sabname = sab.attrib['name'] + sab.set('name', openmc.data.get_thermal_name(sabname)) + was_updated = True + + elif sab.find('name') is not None: + name_elem = sab.find('name') + sabname = name_elem.text + name_elem.text = openmc.data.get_thermal_name(sabname) + was_updated = True + + return was_updated + + +if __name__ == '__main__': + args = parse_args() + for fname in args.input: + # Parse the XML data. + tree = ET.parse(fname) + root = tree.getroot() + was_updated = False + + if root.tag == 'geometry': + was_updated = update_geometry(root) + elif root.tag == 'materials': + was_updated = update_materials(root) + + if was_updated: + # Move the original geometry file to preserve it. + move(fname, fname + '.original') + + # Write a new geometry file. + tree.write(fname, xml_declaration=True) diff --git a/scripts/openmc-update-mgxs b/scripts/openmc-update-mgxs new file mode 100755 index 000000000..aac6959b7 --- /dev/null +++ b/scripts/openmc-update-mgxs @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +"""Update OpenMC's deprecated multi-group cross section XML files to the latest +HDF5-based format. + +""" + +import os +import warnings +import xml.etree.ElementTree as ET + +import argparse +import numpy as np + +import openmc.mgxs_library + + +def parse_args(): + """Read the input files from the commandline.""" + # Create argument parser + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-i', '--input', type=argparse.FileType('r'), + help='input XML file') + parser.add_argument('-o', '--output', nargs='?', default='', + help='output file, in HDF5 format') + args = vars(parser.parse_args()) + + if args['output'] == '': + filename = args['input'].name + extension = os.path.splitext(filename) + if extension == '.xml': + filename = filename[:filename.rfind('.')] + '.h5' + args['output'] = filename + + # Parse and return commandline arguments. + return args + + +def get_data(element, entry): + value = element.find(entry) + if value is not None: + value = value.text.strip() + elif entry in element.attrib: + value = element.attrib[entry].strip() + else: + value = None + + return value + + +def main(): + args = parse_args() + + # Parse the XML data. + tree = ET.parse(args['input']) + root = tree.getroot() + + # Get old metadata + group_structure = tree.find('group_structure').text.strip() + group_structure = np.array(group_structure.split(), dtype=float) + # Convert from MeV to eV + group_structure *= 1.e6 + energy_groups = openmc.mgxs.EnergyGroups(group_structure) + + inverse_velocity = tree.find('inverse-velocity') + if inverse_velocity is not None: + inverse_velocity = inverse_velocity.text.split() + inverse_velocity = np.array(inverse_velocity, dtype=float) + else: + inverse_velocity = None + + xsd = [] + names = [] + + # Now move on to the cross section data itself + for xsdata_elem in root.iter('xsdata'): + name = get_data(xsdata_elem, 'name') + + temperature = get_data(xsdata_elem, 'kT') + if temperature is not None: + temperature = float(temperature) / openmc.data.K_BOLTZMANN * 1.E6 + else: + temperature = 294. + temperatures = [temperature] + + awr = get_data(xsdata_elem, 'awr') + if awr is not None: + awr = float(awr) + + representation = get_data(xsdata_elem, 'representation') + if representation is None: + representation = 'isotropic' + if representation == 'angle': + n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) + n_pol = int(get_data(xsdata_elem, 'num_polar')) + + scatter_format = get_data(xsdata_elem, 'scatt_type') + if scatter_format is None: + scatter_format = 'legendre' + + order = int(get_data(xsdata_elem, 'order')) + + tab_leg = get_data(xsdata_elem, 'tabular_legendre') + if tab_leg is not None: + warnings.warn('The tabular_legendre option has moved to the ' + 'settings.xml file and must be added manually') + + # Either add the data to a previously existing xsdata (if it is + # for the same 'name' but a different temperature), or create a + # new one. + try: + # It is in our list, so store that entry + i = names.index(name) + except ValueError: + # It is not in our list, so add it + i = -1 + xsd.append(openmc.XSdata(name, energy_groups, + temperatures=temperatures, + representation=representation)) + if awr is not None: + xsd[-1].atomic_weight_ratio = awr + if representation == 'angle': + xsd[-1].num_azimuthal = n_azi + xsd[-1].num_polar = n_pol + xsd[-1].scatter_format = scatter_format + xsd[-1].order = order + names.append(name) + + if scatter_format == 'legendre': + order_dim = order + 1 + else: + order_dim = order + + if i != -1: + xsd[i].add_temperature(temperature) + + total = get_data(xsdata_elem, 'total') + if total is not None: + total = np.array(total.split(), dtype=float) + total.shape = xsd[i].xs_shapes['[G]'] + xsd[i].set_total(total, temperature) + + if inverse_velocity is not None: + xsd[i].set_inverse_velocity(inverse_velocity, temperature) + + absorption = get_data(xsdata_elem, 'absorption') + absorption = np.array(absorption.split(), dtype=float) + absorption.shape = xsd[i].xs_shapes['[G]'] + xsd[i].set_absorption(absorption, temperature) + + scatter = get_data(xsdata_elem, 'scatter') + scatter = np.array(scatter.split(), dtype=float) + # This is now a flattened-array of something that started with a + # shape of [Order][G][G']; we need to unflatten and then switch the + # ordering + in_shape = (order_dim, energy_groups.num_groups, + energy_groups.num_groups) + if representation == 'angle': + in_shape = (n_pol, n_azi) + in_shape + scatter.shape = in_shape + scatter = np.swapaxes(scatter, 2, 3) + scatter = np.swapaxes(scatter, 3, 4) + else: + scatter.shape = in_shape + scatter = np.swapaxes(scatter, 0, 1) + scatter = np.swapaxes(scatter, 1, 2) + + xsd[i].set_scatter_matrix(scatter, temperature) + + multiplicity = get_data(xsdata_elem, 'multiplicity') + if multiplicity is not None: + multiplicity = np.array(multiplicity.split(), dtype=float) + multiplicity.shape = xsd[i].xs_shapes["[G][G']"] + xsd[i].set_multiplicity_matrix(multiplicity, temperature) + + fission = get_data(xsdata_elem, 'fission') + if fission is not None: + fission = np.array(fission.split(), dtype=float) + fission.shape = xsd[i].xs_shapes['[G]'] + xsd[i].set_fission(fission, temperature) + + kappa_fission = get_data(xsdata_elem, 'kappa_fission') + if kappa_fission is not None: + kappa_fission = np.array(kappa_fission.split(), dtype=float) + kappa_fission.shape = xsd[i].xs_shapes['[G]'] + xsd[i].set_kappa_fission(kappa_fission, temperature) + + chi = get_data(xsdata_elem, 'chi') + if chi is not None: + chi = np.array(chi.split(), dtype=float) + chi.shape = xsd[i].xs_shapes['[G]'] + xsd[i].set_chi(chi, temperature) + else: + chi = None + + nu_fission = get_data(xsdata_elem, 'nu_fission') + if nu_fission is not None: + nu_fission = np.array(nu_fission.split(), dtype=float) + if chi is not None: + nu_fission.shape = xsd[i].xs_shapes['[G]'] + else: + nu_fission.shape = xsd[i].xs_shapes["[G][G']"] + xsd[i].set_nu_fission(nu_fission, temperature) + + # Build library as we go, but first we have enough to initialize it + lib = openmc.MGXSLibrary(energy_groups) + lib.add_xsdatas(xsd) + lib.export_to_hdf5(args['output']) + + +if __name__ == '__main__': + main() diff --git a/scripts/openmc-validate-xml b/scripts/openmc-validate-xml new file mode 100755 index 000000000..f36ba2b5d --- /dev/null +++ b/scripts/openmc-validate-xml @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +import os +import sys +import glob +import lxml.etree as etree +from subprocess import call +from optparse import OptionParser + +# Command line parsing +parser = OptionParser() +parser.add_option('-r', '--relaxng-path', dest='relaxng', + help="Path to RelaxNG files.") +parser.add_option('-i', '--input-path', dest='inputs', default=os.getcwd(), + help="Path to OpenMC input files." ) +(options, args) = parser.parse_args() + +# Colored output +if sys.stdout.isatty(): + OK = '\033[92m' + FAIL = '\033[91m' + NOT_FOUND = '\033[93m' + ENDC = '\033[0m' + BOLD = '\033[1m' +else: + OK = '' + FAIL = '' + ENDC = '' + BOLD = '' + NOT_FOUND = '' + +# Get absolute paths +if options.relaxng is not None: + relaxng_path = os.path.abspath(options.relaxng) +if options.inputs is not None: + inputs_path = os.path.abspath(options.inputs) + +# Search for relaxng path if not set +if options.relaxng is None: + xml_validate_path = os.path.abspath(os.path.dirname(sys.argv[0])) + if "bin" in xml_validate_path: + relaxng_path = os.path.join(xml_validate_path, "..", "share", "relaxng") + elif os.path.join("src", "utils") in xml_validate_path: + relaxng_path = os.path.join(xml_validate_path, "..", "relaxng") + else: + raise Exception("Set RelaxNG path with -r command line option.") +if not os.path.exists(relaxng_path): + raise Exception("RelaxNG path: {0} does not exist, set with -r " + "command line option.".format(relaxng_path)) + +# Make sure there are .rng files in RelaxNG path +rng_files = glob.glob(os.path.join(relaxng_path, "*.rng")) +if len(rng_files) == 0: + raise Exception("No .rng files found in RelaxNG " + "path: {0}.".format(relaxng_path)) + +# Get list of xml input files +xml_files = glob.glob(os.path.join(inputs_path, "*.xml")) +if len(xml_files) == 0: + raise Exception("No .xml files found at input path: {0}" + ".".format(inputs_path)) + +# Begin loop around input files +for xml_file in xml_files: + + text = "Validating {0}".format(os.path.basename(xml_file)) + print(text + '.'*(30 - len(text)), end="") + + # Validate the XML file + try: + xml_tree = etree.parse(xml_file) + except etree.XMLSyntaxError as e: + print(BOLD + FAIL + '[XML ERROR]' + ENDC) + print(" {0}".format(e)) + continue + + # Get xml_filename prefix + xml_prefix = os.path.basename(xml_file) + xml_prefix = xml_prefix.split(".")[0] + + # Search for rng file + rng_file = os.path.join(relaxng_path, xml_prefix + ".rng") + if rng_file in rng_files: + + # read in RelaxNG + relaxng_doc = etree.parse(rng_file) + relaxng = etree.RelaxNG(relaxng_doc) + + # validate xml file again RelaxNG + try: + relaxng.assertValid(xml_tree) + print(BOLD + OK + '[VALID]' + ENDC) + except (etree.DocumentInvalid, TypeError) as e: + print(BOLD + FAIL + '[NOT VALID]' + ENDC) + print(" {0}".format(e)) + + # RNG file does not exist + else: + print(BOLD + NOT_FOUND + '[NO RELAXNG FOUND]' + ENDC) diff --git a/scripts/openmc-voxel-to-vtk b/scripts/openmc-voxel-to-vtk new file mode 100755 index 000000000..33251144f --- /dev/null +++ b/scripts/openmc-voxel-to-vtk @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +import struct +import sys +from argparse import ArgumentParser + +import numpy as np +import h5py +import vtk + +_min_version = (2, 0) + + +def main(): + # Process command line arguments + parser = ArgumentParser() + parser.add_argument('voxel_file', help='Path to voxel file') + parser.add_argument('-o', '--output', action='store', + default='plot', help='Path to output VTK file.') + args = parser.parse_args() + + # Read data from voxel file + fh = h5py.File(args.voxel_file, 'r') + + # check version + version = tuple(fh.attrs['version']) + if version < _min_version: + old_version = ".".join(map(str,version)) + min_version = ".".join(map(str,_min_version)) + err_msg = "This voxel file's version is {}. This script " \ + "only supports voxel files with version {} or " \ + "higher. Please generate a new voxel file using " \ + "a newer version of OpenMC.".format(old_version, min_version) + raise ValueError(err_msg) + + dimension = fh.attrs['num_voxels'] + width = fh.attrs['voxel_width'] + lower_left = fh.attrs['lower_left'] + + nx, ny, nz = dimension + upper_right = lower_left + width*dimension + + grid = vtk.vtkImageData() + grid.SetDimensions(nx+1, ny+1, nz+1) + grid.SetOrigin(*lower_left) + grid.SetSpacing(*width) + + # transpose data from OpenMC ordering (zyx) to VTK ordering (xyz) + # and flatten to 1-D array + print("Reading and translating data...") + h5data = fh['data'][...] + + data = vtk.vtkIntArray() + data.SetName("id") + # set the array using the h5data array + data.SetArray(h5data, h5data.size, True) + # add data to image grid + grid.GetCellData().AddArray(data) + + writer = vtk.vtkXMLImageDataWriter() + if vtk.vtkVersion.GetVTKMajorVersion() > 5: + writer.SetInputData(grid) + else: + writer.SetInput(grid) + if not args.output.endswith(".vti"): + args.output += ".vti" + writer.SetFileName(args.output) + print("Writing VTK file {}...".format(args.output)) + writer.Write() + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py new file mode 100755 index 000000000..477f29dec --- /dev/null +++ b/setup.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +import glob +import sys +import numpy as np + +from setuptools import setup, find_packages +try: + from Cython.Build import cythonize + have_cython = True +except ImportError: + have_cython = False + + +# Determine shared library suffix +if sys.platform == 'darwin': + suffix = 'dylib' +else: + suffix = 'so' + +# Get version information from __init__.py. This is ugly, but more reliable than +# using an import. +with open('openmc/__init__.py', 'r') as f: + version = f.readlines()[-1].split()[-1].strip("'") + +kwargs = { + 'name': 'openmc', + 'version': version, + 'packages': find_packages(exclude=['tests*']), + 'scripts': glob.glob('scripts/openmc-*'), + + # Data files and libraries + 'package_data': { + 'openmc.lib': ['libopenmc.{}'.format(suffix)], + 'openmc.data': ['mass16.txt', 'BREMX.DAT', 'half_life.json', '*.h5'], + 'openmc.data.effective_dose': ['*.txt'] + }, + + # Metadata + 'author': 'The OpenMC Development Team', + 'author_email': 'openmc@anl.gov', + 'description': 'OpenMC', + 'url': 'https://openmc.org', + 'download_url': 'https://github.com/openmc-dev/openmc/releases', + 'project_urls': { + 'Issue Tracker': 'https://github.com/openmc-dev/openmc/issues', + 'Documentation': 'https://docs.openmc.org', + 'Source Code': 'https://github.com/openmc-dev/openmc', + }, + 'classifiers': [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Topic :: Scientific/Engineering' + 'Programming Language :: C++', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + ], + + # Dependencies + 'python_requires': '>=3.6', + 'install_requires': [ + 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib', + 'pandas', 'lxml', 'uncertainties' + ], + 'extras_require': { + 'depletion-mpi': ['mpi4py'], + 'docs': ['sphinx', 'sphinxcontrib-katex', 'sphinx-numfig', 'jupyter', + 'sphinxcontrib-svg2pdfconverter', 'sphinx-rtd-theme'], + 'test': ['pytest', 'pytest-cov', 'colorama'], + 'vtk': ['vtk'], + }, +} + +# If Cython is present, add resonance reconstruction and fast float_endf +if have_cython: + kwargs.update({ + 'ext_modules': cythonize('openmc/data/*.pyx'), + 'include_dirs': [np.get_include()] + }) + +setup(**kwargs) diff --git a/src/atomic_mass.cpp b/src/atomic_mass.cpp deleted file mode 100644 index 0e63c9603..000000000 --- a/src/atomic_mass.cpp +++ /dev/null @@ -1,3569 +0,0 @@ -#include "openmc/atomic_mass.h" - -namespace openmc { - -// Atomic masses in [u] from AME2020 and CODATA 2018 -std::unordered_map ATOMIC_MASS = { - {11, MASS_ELECTRON}, - {22, 0.0}, - {2112, MASS_NEUTRON}, - {2212, MASS_PROTON}, - {1000010020, MASS_DEUTRON}, - {1000020030, MASS_HELION}, - {1000020040, MASS_ALPHA}, - {1000010030, 3.01604928132}, - {1000030030, 3.030775}, - {1000010040, 4.026431867}, - {1000030040, 4.027185561}, - {1000010050, 5.035311492}, - {1000020050, 5.012057224}, - {1000030050, 5.0125378}, - {1000040050, 5.03987}, - {1000010060, 6.044955437}, - {1000020060, 6.018885889}, - {1000030060, 6.01512288742}, - {1000040060, 6.0197264090000004}, - {1000050060, 6.0508}, - {1000010070, 7.052749}, - {1000020070, 7.027990652}, - {1000030070, 7.01600343426}, - {1000040070, 7.016928714}, - {1000050070, 7.029712}, - {1000020080, 8.033934388}, - {1000030080, 8.022486244}, - {1000040080, 8.005305102}, - {1000050080, 8.024607315}, - {1000060080, 8.037643039}, - {1000020090, 9.043946414}, - {1000030090, 9.026790191}, - {1000040090, 9.012183062}, - {1000050090, 9.013329645}, - {1000060090, 9.031037202}, - {1000020100, 10.052815306}, - {1000030100, 10.035483453}, - {1000040100, 10.013534692}, - {1000050100, 10.012936862}, - {1000060100, 10.016853217}, - {1000070100, 10.04165354}, - {1000030110, 11.043723581}, - {1000040110, 11.02166108}, - {1000050110, 11.009305166}, - {1000060110, 11.011432597}, - {1000070110, 11.026157593}, - {1000080110, 11.051249828}, - {1000030120, 12.052613942}, - {1000040120, 12.026922082}, - {1000050120, 12.014352638}, - {1000060120, 12.0}, - {1000070120, 12.01861318}, - {1000080120, 12.034367726}, - {1000030130, 13.061171503}, - {1000040130, 13.036134506}, - {1000050130, 13.017779981}, - {1000060130, 13.00335483534}, - {1000070130, 13.005738609}, - {1000080130, 13.024815435}, - {1000090130, 13.045121}, - {1000040140, 14.04289292}, - {1000050140, 14.02540401}, - {1000060140, 14.00324198862}, - {1000070140, 14.00307400425}, - {1000080140, 14.008596706}, - {1000090140, 14.034315196}, - {1000040150, 15.053490215}, - {1000050150, 15.031087023}, - {1000060150, 15.010599256}, - {1000070150, 15.00010889827}, - {1000080150, 15.003065636}, - {1000090150, 15.017785139}, - {1000100150, 15.043172977}, - {1000040160, 16.061672036}, - {1000050160, 16.039841045}, - {1000060160, 16.014701255}, - {1000070160, 16.006101925}, - {1000080160, 15.99491461926}, - {1000090160, 16.011460278}, - {1000100160, 16.02575086}, - {1000050170, 17.046931399}, - {1000060170, 17.02257865}, - {1000070170, 17.008448876}, - {1000080170, 16.99913175595}, - {1000090170, 17.002095237}, - {1000100170, 17.017713962}, - {1000110170, 17.037273}, - {1000050180, 18.055601683}, - {1000060180, 18.02675193}, - {1000070180, 18.014077563}, - {1000080180, 17.99915961214}, - {1000090180, 18.000937324}, - {1000100180, 18.005708696}, - {1000110180, 18.026879388}, - {1000050190, 19.064166}, - {1000060190, 19.034797594}, - {1000070190, 19.017022389}, - {1000080190, 19.003577969}, - {1000090190, 18.99840316207}, - {1000100190, 19.001880906}, - {1000110190, 19.013880264}, - {1000120190, 19.03417992}, - {1000050200, 20.074505644}, - {1000060200, 20.040261732}, - {1000070200, 20.023367295}, - {1000080200, 20.004075357}, - {1000090200, 19.999981252}, - {1000100200, 19.99244017525}, - {1000110200, 20.007354301}, - {1000120200, 20.018763075}, - {1000050210, 21.084147485}, - {1000060210, 21.049}, - {1000070210, 21.027087573}, - {1000080210, 21.008654948}, - {1000090210, 20.999948893}, - {1000100210, 20.993846685}, - {1000110210, 20.997654459}, - {1000120210, 21.011705764}, - {1000130210, 21.029082}, - {1000060220, 22.05755399}, - {1000070220, 22.034100918}, - {1000080220, 22.009965744}, - {1000090220, 22.002998812}, - {1000100220, 21.991385113}, - {1000110220, 21.994437547}, - {1000120220, 21.999570597}, - {1000130220, 22.01954}, - {1000140220, 22.036114}, - {1000060230, 23.06889}, - {1000070230, 23.039421}, - {1000080230, 23.015696686}, - {1000090230, 23.003526875}, - {1000100230, 22.994466905}, - {1000110230, 22.98976928195}, - {1000120230, 22.994123768}, - {1000130230, 23.007244351}, - {1000140230, 23.025711}, - {1000070240, 24.05039}, - {1000080240, 24.019861}, - {1000090240, 24.00809937}, - {1000100240, 23.993610649}, - {1000110240, 23.990963012}, - {1000120240, 23.985041689}, - {1000130240, 23.999947598}, - {1000140240, 24.01153543}, - {1000150240, 24.036522}, - {1000070250, 25.0601}, - {1000080250, 25.029338919}, - {1000090250, 25.012167727}, - {1000100250, 24.997814797}, - {1000110250, 24.989953974}, - {1000120250, 24.985836966}, - {1000130250, 24.990428308}, - {1000140250, 25.004108798}, - {1000150250, 25.021675}, - {1000080260, 26.037210155}, - {1000090260, 26.020048065}, - {1000100260, 26.000516496}, - {1000110260, 25.992634649}, - {1000120260, 25.982592972}, - {1000130260, 25.986891876}, - {1000140260, 25.992333818}, - {1000150260, 26.01178}, - {1000160260, 26.029716}, - {1000080270, 27.047955}, - {1000090270, 27.026981897}, - {1000100270, 27.007569462}, - {1000110270, 26.994076408}, - {1000120270, 26.984340647}, - {1000130270, 26.981538408}, - {1000140270, 26.986704687}, - {1000150270, 26.999292499}, - {1000160270, 27.018777}, - {1000080280, 28.05591}, - {1000090280, 28.035860448}, - {1000100280, 28.012130767}, - {1000110280, 27.998939}, - {1000120280, 27.983875426}, - {1000130280, 27.981910009}, - {1000140280, 27.97692653442}, - {1000150280, 27.99232646}, - {1000160280, 28.004372762}, - {1000170280, 28.030349}, - {1000090290, 29.043103}, - {1000100290, 29.019753}, - {1000110290, 29.002877091}, - {1000120290, 28.988607163}, - {1000130290, 28.980453164}, - {1000140290, 28.97649466434}, - {1000150290, 28.981800368}, - {1000160290, 28.996678}, - {1000170290, 29.015053}, - {1000180290, 29.040761}, - {1000090300, 30.052561}, - {1000100300, 30.024992235}, - {1000110300, 30.009097931}, - {1000120300, 29.990465454}, - {1000130300, 29.982969171}, - {1000140300, 29.973770137}, - {1000150300, 29.97831349}, - {1000160300, 29.98490677}, - {1000170300, 30.005018333}, - {1000180300, 30.023694}, - {1000090310, 31.061023}, - {1000100310, 31.033474816}, - {1000110310, 31.013146654}, - {1000120310, 30.996648232}, - {1000130310, 30.983949754}, - {1000140310, 30.975363196}, - {1000150310, 30.97376199768}, - {1000160310, 30.979557002}, - {1000170310, 30.992448097}, - {1000180310, 31.012158}, - {1000190310, 31.03678}, - {1000100320, 32.03972}, - {1000110320, 32.020011024}, - {1000120320, 31.999110138}, - {1000130320, 31.988084338}, - {1000140320, 31.974151538}, - {1000150320, 31.973907643}, - {1000160320, 31.97207117354}, - {1000170320, 31.985684605}, - {1000180320, 31.997637824}, - {1000190320, 32.023607}, - {1000100330, 33.049523}, - {1000110330, 33.025529}, - {1000120330, 33.005327862}, - {1000130330, 32.990877685}, - {1000140330, 32.977976964}, - {1000150330, 32.971725692}, - {1000160330, 32.97145890862}, - {1000170330, 32.977451988}, - {1000180330, 32.989925545}, - {1000190330, 33.008095}, - {1000200330, 33.033312}, - {1000100340, 34.056728}, - {1000110340, 34.03401}, - {1000120340, 34.008935455}, - {1000130340, 33.996781924}, - {1000140340, 33.978538045}, - {1000150340, 33.973645886}, - {1000160340, 33.967867011}, - {1000170340, 33.97376249}, - {1000180340, 33.980270092}, - {1000190340, 33.99869}, - {1000200340, 34.015985}, - {1000110350, 35.040614}, - {1000120350, 35.01679}, - {1000130350, 34.999759816}, - {1000140350, 34.984550111}, - {1000150350, 34.973314045}, - {1000160350, 34.969032321}, - {1000170350, 34.968852694}, - {1000180350, 34.975257719}, - {1000190350, 34.988005406}, - {1000200350, 35.005572}, - {1000210350, 35.029093}, - {1000110360, 36.049279}, - {1000120360, 36.021879}, - {1000130360, 36.006388}, - {1000140360, 35.986649271}, - {1000150360, 35.97825961}, - {1000160360, 35.967080692}, - {1000170360, 35.968306822}, - {1000180360, 35.967545106}, - {1000190360, 35.981301887}, - {1000200360, 35.993074388}, - {1000210360, 36.017338}, - {1000110370, 37.057042}, - {1000120370, 37.030286265}, - {1000130370, 37.010531}, - {1000140370, 36.992945191}, - {1000150370, 36.979606942}, - {1000160370, 36.9711255}, - {1000170370, 36.965902573}, - {1000180370, 36.966776301}, - {1000190370, 36.97337589}, - {1000200370, 36.985897849}, - {1000210370, 37.004058}, - {1000220370, 37.027021}, - {1000110380, 38.066458}, - {1000120380, 38.03658}, - {1000130380, 38.017681}, - {1000140380, 37.995523}, - {1000150380, 37.984303105}, - {1000160380, 37.9711633}, - {1000170380, 37.968010408}, - {1000180380, 37.962732102}, - {1000190380, 37.969081114}, - {1000200380, 37.976319223}, - {1000210380, 37.995438}, - {1000220380, 38.012206}, - {1000110390, 39.075123}, - {1000120390, 39.045921}, - {1000130390, 39.02307}, - {1000140390, 39.002491}, - {1000150390, 38.986285865}, - {1000160390, 38.97513385}, - {1000170390, 38.968008151}, - {1000180390, 38.964313037}, - {1000190390, 38.96370648482}, - {1000200390, 38.970710811}, - {1000210390, 38.984784953}, - {1000220390, 39.002684}, - {1000230390, 39.02423}, - {1000120400, 40.053194}, - {1000130400, 40.03094}, - {1000140400, 40.006083641}, - {1000150400, 39.991262221}, - {1000160400, 39.975482561}, - {1000170400, 39.970415466}, - {1000180400, 39.96238312204}, - {1000190400, 39.963998165}, - {1000200400, 39.96259085}, - {1000210400, 39.977967275}, - {1000220400, 39.990345146}, - {1000230400, 40.013387}, - {1000120410, 41.062373}, - {1000130410, 41.037134}, - {1000140410, 41.014171}, - {1000150410, 40.994654}, - {1000160410, 40.979593451}, - {1000170410, 40.970684525}, - {1000180410, 40.96450057}, - {1000190410, 40.96182525611}, - {1000200410, 40.962277905}, - {1000210410, 40.969251163}, - {1000220410, 40.983148}, - {1000230410, 41.000333}, - {1000240410, 41.021911}, - {1000130420, 42.045078}, - {1000140420, 42.018078}, - {1000150420, 42.00117214}, - {1000160420, 41.9810651}, - {1000170420, 41.973342}, - {1000180420, 41.963045737}, - {1000190420, 41.962402305}, - {1000200420, 41.95861778}, - {1000210420, 41.965516686}, - {1000220420, 41.973049369}, - {1000230420, 41.99182}, - {1000240420, 42.007579}, - {1000130430, 43.05182}, - {1000140430, 43.026119}, - {1000150430, 43.005411}, - {1000160430, 42.986907635}, - {1000170430, 42.9740637}, - {1000180430, 42.965636056}, - {1000190430, 42.960734701}, - {1000200430, 42.958766381}, - {1000210430, 42.961150425}, - {1000220430, 42.96852842}, - {1000230430, 42.980766}, - {1000240430, 42.997885}, - {1000250430, 43.018647}, - {1000140440, 44.031466}, - {1000150440, 44.011927}, - {1000160440, 43.990118846}, - {1000170440, 43.978014918}, - {1000180440, 43.964923814}, - {1000190440, 43.961586984}, - {1000200440, 43.955481489}, - {1000210440, 43.959402818}, - {1000220440, 43.959689936}, - {1000230440, 43.974440977}, - {1000240440, 43.985591}, - {1000250440, 44.008009}, - {1000140450, 45.039818}, - {1000150450, 45.017134}, - {1000160450, 44.996414}, - {1000170450, 44.980394353}, - {1000180450, 44.968039731}, - {1000190450, 44.960691491}, - {1000200450, 44.95618627}, - {1000210450, 44.955907051}, - {1000220450, 44.958120758}, - {1000230450, 44.965768498}, - {1000240450, 44.97905}, - {1000250450, 44.994654}, - {1000260450, 45.015467}, - {1000150460, 46.02452}, - {1000160460, 46.000687}, - {1000170460, 45.985254926}, - {1000180460, 45.968039243999996}, - {1000190460, 45.961981584}, - {1000200460, 45.953687726}, - {1000210460, 45.955167034}, - {1000220460, 45.952626356}, - {1000230460, 45.960197389}, - {1000240460, 45.968360969}, - {1000250460, 45.986669}, - {1000260460, 46.001299}, - {1000150470, 47.030929}, - {1000160470, 47.00773}, - {1000170470, 46.989715}, - {1000180470, 46.972767112}, - {1000190470, 46.961661612}, - {1000200470, 46.954541134}, - {1000210470, 46.952402444}, - {1000220470, 46.951757491}, - {1000230470, 46.954903558}, - {1000240470, 46.962894995}, - {1000250470, 46.975774}, - {1000260470, 46.992346}, - {1000270470, 47.011401}, - {1000160480, 48.013301}, - {1000170480, 47.995405}, - {1000180480, 47.976001}, - {1000190480, 47.965341184}, - {1000200480, 47.952522654}, - {1000210480, 47.952222903}, - {1000220480, 47.947940677}, - {1000230480, 47.9522509}, - {1000240480, 47.954029431}, - {1000250480, 47.96854876}, - {1000260480, 47.980667}, - {1000270480, 48.001857}, - {1000280480, 48.019515}, - {1000160490, 49.021891}, - {1000170490, 49.000794}, - {1000180490, 48.981685}, - {1000190490, 48.968210753}, - {1000200490, 48.955662625}, - {1000210490, 48.950013159}, - {1000220490, 48.947864391}, - {1000230490, 48.948510509}, - {1000240490, 48.95133372}, - {1000250490, 48.95961335}, - {1000260490, 48.973429}, - {1000270490, 48.989501}, - {1000280490, 49.009157}, - {1000170500, 50.008266}, - {1000180500, 49.985797}, - {1000190500, 49.972380015}, - {1000200500, 49.957499215}, - {1000210500, 49.952187437}, - {1000220500, 49.944785622}, - {1000230500, 49.947156681}, - {1000240500, 49.946042209}, - {1000250500, 49.954238157}, - {1000260500, 49.962988}, - {1000270500, 49.981117}, - {1000280500, 49.996286}, - {1000170510, 51.015341}, - {1000180510, 50.993033}, - {1000190510, 50.975828664}, - {1000200510, 50.960995663}, - {1000210510, 50.953568838}, - {1000220510, 50.946609468}, - {1000230510, 50.943957664}, - {1000240510, 50.944765388}, - {1000250510, 50.94820877}, - {1000260510, 50.956855137}, - {1000270510, 50.970647}, - {1000280510, 50.987493}, - {1000170520, 52.024004}, - {1000180520, 51.998519}, - {1000190520, 51.981602}, - {1000200520, 51.963213646}, - {1000210520, 51.95649617}, - {1000220520, 51.946883509}, - {1000230520, 51.944773636}, - {1000240520, 51.940504714}, - {1000250520, 51.94555909}, - {1000260520, 51.948113364}, - {1000270520, 51.963130224}, - {1000280520, 51.975781}, - {1000290520, 51.997982}, - {1000180530, 53.00729}, - {1000190530, 52.9868}, - {1000200530, 52.968451}, - {1000210530, 52.958379173}, - {1000220530, 52.949670714}, - {1000230530, 52.94433494}, - {1000240530, 52.940646304}, - {1000250530, 52.941287497}, - {1000260530, 52.945305629}, - {1000270530, 52.954203278}, - {1000280530, 52.96819}, - {1000290530, 52.985894}, - {1000180540, 54.013484}, - {1000190540, 53.994471}, - {1000200540, 53.972989}, - {1000210540, 53.963029359}, - {1000220540, 53.950892}, - {1000230540, 53.946432009}, - {1000240540, 53.938877359}, - {1000250540, 53.940355772}, - {1000260540, 53.939608189}, - {1000270540, 53.948459075}, - {1000280540, 53.957833}, - {1000290540, 53.977198}, - {1000300540, 53.993879}, - {1000190550, 55.000505}, - {1000200550, 54.979978}, - {1000210550, 54.966889637}, - {1000220550, 54.955091}, - {1000230550, 54.947262}, - {1000240550, 54.940836637}, - {1000250550, 54.93804304}, - {1000260550, 54.938291158}, - {1000270550, 54.941996416}, - {1000280550, 54.951329846}, - {1000290550, 54.966038}, - {1000300550, 54.984681}, - {1000190560, 56.008567}, - {1000200560, 55.985496}, - {1000210560, 55.972607611}, - {1000220560, 55.957677675}, - {1000230560, 55.950420082}, - {1000240560, 55.940648977}, - {1000250560, 55.938902816}, - {1000260560, 55.934935537}, - {1000270560, 55.939838032}, - {1000280560, 55.942127761}, - {1000290560, 55.958529278}, - {1000300560, 55.972743}, - {1000310560, 55.995878}, - {1000190570, 57.015169}, - {1000200570, 56.992958}, - {1000210570, 56.977047999999996}, - {1000220570, 56.963068098}, - {1000230570, 56.952297}, - {1000240570, 56.943612112}, - {1000250570, 56.938285944}, - {1000260570, 56.93539195}, - {1000270570, 56.936289819}, - {1000280570, 56.939791394}, - {1000290570, 56.949211686}, - {1000300570, 56.965056}, - {1000310570, 56.983457}, - {1000190580, 58.023543}, - {1000200580, 57.998357}, - {1000210580, 57.983382}, - {1000220580, 57.966808519}, - {1000230580, 57.956595985}, - {1000240580, 57.944184501}, - {1000250580, 57.940066643}, - {1000260580, 57.933273575}, - {1000270580, 57.935751292}, - {1000280580, 57.93534165}, - {1000290580, 57.944532283}, - {1000300580, 57.954590296}, - {1000310580, 57.974728999999996}, - {1000320580, 57.991863}, - {1000190590, 59.030864}, - {1000200590, 59.006237}, - {1000210590, 58.988374}, - {1000220590, 58.972217}, - {1000230590, 58.959623343}, - {1000240590, 58.948345426}, - {1000250590, 58.940391111}, - {1000260590, 58.934873492}, - {1000270590, 58.933193523999996}, - {1000280590, 58.934345442}, - {1000290590, 58.939496713}, - {1000300590, 58.949311886}, - {1000310590, 58.963757}, - {1000320590, 58.982426}, - {1000200600, 60.011809}, - {1000210600, 59.995115}, - {1000220600, 59.976275}, - {1000230600, 59.964479215}, - {1000240600, 59.949641656}, - {1000250600, 59.943136574}, - {1000260600, 59.934070249}, - {1000270600, 59.933815536}, - {1000280600, 59.930785129}, - {1000290600, 59.937363787}, - {1000300600, 59.941841317}, - {1000310600, 59.957498}, - {1000320600, 59.970445}, - {1000330600, 59.993945}, - {1000200610, 61.020408}, - {1000210610, 61.000537}, - {1000220610, 60.982426}, - {1000230610, 60.967603529}, - {1000240610, 60.95437813}, - {1000250610, 60.944452541}, - {1000260610, 60.936746241}, - {1000270610, 60.932476031}, - {1000280610, 60.931054819}, - {1000290610, 60.933457375}, - {1000300610, 60.939506964}, - {1000310610, 60.949398861}, - {1000320610, 60.963725}, - {1000330610, 60.981535}, - {1000210620, 62.007848}, - {1000220620, 61.986903}, - {1000230620, 61.972932556}, - {1000240620, 61.95614292}, - {1000250620, 61.947907384}, - {1000260620, 61.936791809}, - {1000270620, 61.934058198}, - {1000280620, 61.928344753}, - {1000290620, 61.932594803}, - {1000300620, 61.934333359}, - {1000310620, 61.944189639}, - {1000320620, 61.954761}, - {1000330620, 61.973784}, - {1000210630, 63.014031}, - {1000220630, 62.993709}, - {1000230630, 62.976661}, - {1000240630, 62.961161}, - {1000250630, 62.949664672}, - {1000260630, 62.940272698}, - {1000270630, 62.93359963}, - {1000280630, 62.929669021}, - {1000290630, 62.929597119}, - {1000300630, 62.93321114}, - {1000310630, 62.939294194}, - {1000320630, 62.949628}, - {1000330630, 62.964036}, - {1000340630, 62.981911}, - {1000220640, 63.998411}, - {1000230640, 63.98248}, - {1000240640, 63.963886}, - {1000250640, 63.953849369}, - {1000260640, 63.940987761}, - {1000270640, 63.935810176}, - {1000280640, 63.927966228}, - {1000290640, 63.929764001}, - {1000300640, 63.929141776}, - {1000310640, 63.936840366}, - {1000320640, 63.941689912}, - {1000330640, 63.95756}, - {1000340640, 63.971165}, - {1000220650, 65.005593}, - {1000230650, 64.986999}, - {1000240650, 64.969608}, - {1000250650, 64.956019749}, - {1000260650, 64.945015323}, - {1000270650, 64.936462071}, - {1000280650, 64.930084585}, - {1000290650, 64.927789476}, - {1000300650, 64.929240534}, - {1000310650, 64.932734424}, - {1000320650, 64.939368136}, - {1000330650, 64.949611}, - {1000340650, 64.964552}, - {1000350650, 64.982297}, - {1000230660, 65.993237}, - {1000240660, 65.973011}, - {1000250660, 65.960546833}, - {1000260660, 65.946249958}, - {1000270660, 65.939442943}, - {1000280660, 65.929139333}, - {1000290660, 65.928868804}, - {1000300660, 65.926033639}, - {1000310660, 65.931589766}, - {1000320660, 65.933862124}, - {1000330660, 65.944148778}, - {1000340660, 65.955276}, - {1000350660, 65.974697}, - {1000230670, 66.998128}, - {1000240670, 66.979313}, - {1000250670, 66.96395}, - {1000260670, 66.95093}, - {1000270670, 66.940609625}, - {1000280670, 66.931569413}, - {1000290670, 66.92772949}, - {1000300670, 66.927127422}, - {1000310670, 66.928202276}, - {1000320670, 66.932716999}, - {1000330670, 66.93925111}, - {1000340670, 66.949994}, - {1000350670, 66.965078}, - {1000360670, 66.983305}, - {1000240680, 67.983156}, - {1000250680, 67.968953}, - {1000260680, 67.952875}, - {1000270680, 67.944559401}, - {1000280680, 67.931868787}, - {1000290680, 67.929610887}, - {1000300680, 67.924844232}, - {1000310680, 67.927980161}, - {1000320680, 67.928095305}, - {1000330680, 67.936774127}, - {1000340680, 67.941825236}, - {1000350680, 67.958356}, - {1000360680, 67.972489}, - {1000240690, 68.989662}, - {1000250690, 68.972775}, - {1000260690, 68.957918}, - {1000270690, 68.945909}, - {1000280690, 68.935610267}, - {1000290690, 68.929429267}, - {1000300690, 68.92655036}, - {1000310690, 68.925573528}, - {1000320690, 68.927964467}, - {1000330690, 68.932246289}, - {1000340690, 68.939414845}, - {1000350690, 68.95033841}, - {1000360690, 68.965496}, - {1000240700, 69.993945}, - {1000250700, 69.978046}, - {1000260700, 69.960397}, - {1000270700, 69.9500534}, - {1000280700, 69.9364313}, - {1000290700, 69.932392078}, - {1000300700, 69.925319175}, - {1000310700, 69.926021914}, - {1000320700, 69.924248542}, - {1000330700, 69.930934642}, - {1000340700, 69.933515521}, - {1000350700, 69.944792321}, - {1000360700, 69.955877}, - {1000250710, 70.982158}, - {1000260710, 70.965722}, - {1000270710, 70.952366923}, - {1000280710, 70.940518962}, - {1000290710, 70.932676831}, - {1000300710, 70.927719578}, - {1000310710, 70.924702554}, - {1000320710, 70.92495212}, - {1000330710, 70.927113594}, - {1000340710, 70.932209431}, - {1000350710, 70.939342153}, - {1000360710, 70.950265695}, - {1000370710, 70.965335}, - {1000250720, 71.988009}, - {1000260720, 71.968599}, - {1000270720, 71.956736}, - {1000280720, 71.941785924}, - {1000290720, 71.935820306}, - {1000300720, 71.926842806}, - {1000310720, 71.926367452}, - {1000320720, 71.922075824}, - {1000330720, 71.926752291}, - {1000340720, 71.927140506}, - {1000350720, 71.936594606}, - {1000360720, 71.942092406}, - {1000370720, 71.958851}, - {1000250730, 72.992807}, - {1000260730, 72.974246}, - {1000270730, 72.959238}, - {1000280730, 72.946206681}, - {1000290730, 72.936674376}, - {1000300730, 72.92958258}, - {1000310730, 72.92517468}, - {1000320730, 72.923458954}, - {1000330730, 72.923829086}, - {1000340730, 72.926754881}, - {1000350730, 72.931673441}, - {1000360730, 72.939289193}, - {1000370730, 72.950604506}, - {1000380730, 72.9657}, - {1000260740, 73.977821}, - {1000270740, 73.963993}, - {1000280740, 73.947718}, - {1000290740, 73.93987486}, - {1000300740, 73.92940726}, - {1000310740, 73.926945725}, - {1000320740, 73.92117776}, - {1000330740, 73.923928596}, - {1000340740, 73.922475933}, - {1000350740, 73.929910279}, - {1000360740, 73.933084016}, - {1000370740, 73.944265867}, - {1000380740, 73.95617}, - {1000260750, 74.984219}, - {1000270750, 74.967192}, - {1000280750, 74.952506}, - {1000290750, 74.941523817}, - {1000300750, 74.932840244}, - {1000310750, 74.926504484}, - {1000320750, 74.92285837}, - {1000330750, 74.921594562}, - {1000340750, 74.92252287}, - {1000350750, 74.925810566}, - {1000360750, 74.930945744}, - {1000370750, 74.9385732}, - {1000380750, 74.949952767}, - {1000390750, 74.96584}, - {1000260760, 75.988631}, - {1000270760, 75.972453}, - {1000280760, 75.954707}, - {1000290760, 75.945268974}, - {1000300760, 75.933114956}, - {1000310760, 75.928827624}, - {1000320760, 75.921402725}, - {1000330760, 75.922392011}, - {1000340760, 75.919213702}, - {1000350760, 75.924541574}, - {1000360760, 75.925910743}, - {1000370760, 75.935073031}, - {1000380760, 75.94176276}, - {1000390760, 75.958937}, - {1000270770, 76.976479}, - {1000280770, 76.959903}, - {1000290770, 76.947543599}, - {1000300770, 76.936887197}, - {1000310770, 76.929154299}, - {1000320770, 76.923549843}, - {1000330770, 76.920647555}, - {1000340770, 76.91991415}, - {1000350770, 76.921379193}, - {1000360770, 76.924669999}, - {1000370770, 76.930401599}, - {1000380770, 76.937945454}, - {1000390770, 76.950146}, - {1000400770, 76.966076}, - {1000270780, 77.983553}, - {1000280780, 77.962555}, - {1000290780, 77.951916524}, - {1000300780, 77.938289204}, - {1000310780, 77.931610854}, - {1000320780, 77.922852911}, - {1000330780, 77.921827771}, - {1000340780, 77.917309244}, - {1000350780, 77.921145858}, - {1000360780, 77.920366341}, - {1000370780, 77.928141866}, - {1000380780, 77.932179979}, - {1000390780, 77.94399}, - {1000400780, 77.956146}, - {1000280790, 78.969769}, - {1000290790, 78.9544731}, - {1000300790, 78.942638067}, - {1000310790, 78.932851582}, - {1000320790, 78.925359506}, - {1000330790, 78.920948419}, - {1000340790, 78.918499252}, - {1000350790, 78.918337574}, - {1000360790, 78.920082919}, - {1000370790, 78.923990095}, - {1000380790, 78.929704692}, - {1000390790, 78.937946}, - {1000400790, 78.94979}, - {1000410790, 78.966022}, - {1000280800, 79.975051}, - {1000290800, 79.960623}, - {1000300800, 79.944552929}, - {1000310800, 79.936420773}, - {1000320800, 79.925350773}, - {1000330800, 79.92247444}, - {1000340800, 79.916521761}, - {1000350800, 79.918529784}, - {1000360800, 79.91637794}, - {1000370800, 79.922516442}, - {1000380800, 79.924517538}, - {1000390800, 79.93435475}, - {1000400800, 79.941213}, - {1000410800, 79.958754}, - {1000280810, 80.982727}, - {1000290810, 80.965743}, - {1000300810, 80.950402617}, - {1000310810, 80.938133841}, - {1000320810, 80.928832941}, - {1000330810, 80.922132288}, - {1000340810, 80.917993019}, - {1000350810, 80.916288197}, - {1000360810, 80.916589703}, - {1000370810, 80.9189939}, - {1000380810, 80.923211393}, - {1000390810, 80.929454283}, - {1000400810, 80.938245}, - {1000410810, 80.95023}, - {1000420810, 80.966226}, - {1000280820, 81.988492}, - {1000290820, 81.972378}, - {1000300820, 81.954574097}, - {1000310820, 81.943176531}, - {1000320820, 81.929774031}, - {1000330820, 81.924738731}, - {1000340820, 81.916699531}, - {1000350820, 81.916801752}, - {1000360820, 81.91348115368}, - {1000370820, 81.918209023}, - {1000380820, 81.918399845}, - {1000390820, 81.926930189}, - {1000400820, 81.931707497}, - {1000410820, 81.94438}, - {1000420820, 81.956661}, - {1000290830, 82.97811}, - {1000300830, 82.961041}, - {1000310830, 82.9471203}, - {1000320830, 82.9345391}, - {1000330830, 82.9252069}, - {1000340830, 82.919118604}, - {1000350830, 82.915175285}, - {1000360830, 82.914126516}, - {1000370830, 82.915114181}, - {1000380830, 82.917554372}, - {1000390830, 82.922484026}, - {1000400830, 82.929240926}, - {1000410830, 82.93815}, - {1000420830, 82.950252}, - {1000430830, 82.966377}, - {1000290840, 83.985271}, - {1000300840, 83.965829}, - {1000310840, 83.952663}, - {1000320840, 83.93757509}, - {1000330840, 83.92930329000001}, - {1000340840, 83.918466761}, - {1000350840, 83.916496417}, - {1000360840, 83.91149772708}, - {1000370840, 83.914375223}, - {1000380840, 83.913419118}, - {1000390840, 83.92067106}, - {1000400840, 83.923325663}, - {1000410840, 83.934305711}, - {1000420840, 83.941846}, - {1000430840, 83.959527}, - {1000300850, 84.973054}, - {1000310850, 84.957333}, - {1000320850, 84.942969658}, - {1000330850, 84.932163658}, - {1000340850, 84.922260758}, - {1000350850, 84.915645758}, - {1000360850, 84.91252726}, - {1000370850, 84.91178973604}, - {1000380850, 84.912932041}, - {1000390850, 84.916433039}, - {1000400850, 84.921443199}, - {1000410850, 84.928845836}, - {1000420850, 84.938260736}, - {1000430850, 84.950778}, - {1000440850, 84.967117}, - {1000300860, 85.978463}, - {1000310860, 85.963757}, - {1000320860, 85.946967}, - {1000330860, 85.936701532}, - {1000340860, 85.924311732}, - {1000350860, 85.918805432}, - {1000360860, 85.91061062468}, - {1000370860, 85.911167443}, - {1000380860, 85.90926072473}, - {1000390860, 85.914886095}, - {1000400860, 85.916296814}, - {1000410860, 85.925781536}, - {1000420860, 85.931174092}, - {1000430860, 85.944637}, - {1000440860, 85.957305}, - {1000310870, 86.969007}, - {1000320870, 86.953204}, - {1000330870, 86.940291716}, - {1000340870, 86.928688616}, - {1000350870, 86.920674016}, - {1000360870, 86.913354759}, - {1000370870, 86.909180529}, - {1000380870, 86.90887749454}, - {1000390870, 86.9108761}, - {1000400870, 86.914817338}, - {1000410870, 86.920692473}, - {1000420870, 86.928196198}, - {1000430870, 86.938067185}, - {1000440870, 86.950907}, - {1000310880, 87.975963}, - {1000320880, 87.957574}, - {1000330880, 87.94584}, - {1000340880, 87.93141749}, - {1000350880, 87.92408329}, - {1000360880, 87.914447879}, - {1000370880, 87.91131559}, - {1000380880, 87.905612253}, - {1000390880, 87.909501274}, - {1000400880, 87.910220715}, - {1000410880, 87.918226476}, - {1000420880, 87.921967779}, - {1000430880, 87.933794211}, - {1000440880, 87.941664}, - {1000450880, 87.960429}, - {1000320890, 88.96453}, - {1000330890, 88.950048}, - {1000340890, 88.936669058}, - {1000350890, 88.926704558}, - {1000360890, 88.917835449}, - {1000370890, 88.912278136}, - {1000380890, 88.907450808}, - {1000390890, 88.905838156}, - {1000400890, 88.908879751}, - {1000410890, 88.913444696}, - {1000420890, 88.919468149}, - {1000430890, 88.927648649}, - {1000440890, 88.937337849}, - {1000450890, 88.950992}, - {1000320900, 89.969436}, - {1000330900, 89.955995}, - {1000340900, 89.940096}, - {1000350900, 89.931292848}, - {1000360900, 89.919527929}, - {1000370900, 89.914797557}, - {1000380900, 89.90772787}, - {1000390900, 89.907141749}, - {1000400900, 89.904698755}, - {1000410900, 89.911259201}, - {1000420900, 89.91393127}, - {1000430900, 89.924073919}, - {1000440900, 89.930344378}, - {1000450900, 89.944569}, - {1000460900, 89.95737}, - {1000330910, 90.960816}, - {1000340910, 90.9457}, - {1000350910, 90.934398617}, - {1000360910, 90.923806309}, - {1000370910, 90.916537261}, - {1000380910, 90.910195942}, - {1000390910, 90.907298048}, - {1000400910, 90.905640205}, - {1000410910, 90.906990256}, - {1000420910, 90.91174519}, - {1000430910, 90.918424972}, - {1000440910, 90.92674153}, - {1000450910, 90.937123}, - {1000460910, 90.950435}, - {1000330920, 91.967386}, - {1000340920, 91.94984}, - {1000350920, 91.939631595}, - {1000360920, 91.926173092}, - {1000370920, 91.919728477}, - {1000380920, 91.911038222}, - {1000390920, 91.908945752}, - {1000400920, 91.905035336}, - {1000410920, 91.90718858}, - {1000420920, 91.906807153}, - {1000430920, 91.915269777}, - {1000440920, 91.920234373}, - {1000450920, 91.932367692}, - {1000460920, 91.941192225}, - {1000470920, 91.95971}, - {1000340930, 92.956135}, - {1000350930, 92.94322}, - {1000360930, 92.931147172}, - {1000370930, 92.922039334}, - {1000380930, 92.914024314}, - {1000390930, 92.909578434}, - {1000400930, 92.906470661}, - {1000410930, 92.90637317}, - {1000420930, 92.906808772}, - {1000430930, 92.910245147}, - {1000440930, 92.917104442}, - {1000450930, 92.925912778}, - {1000460930, 92.936680426}, - {1000470930, 92.950188}, - {1000340940, 93.96049}, - {1000350940, 93.948846}, - {1000360940, 93.934140452}, - {1000370940, 93.926394819}, - {1000380940, 93.915355641}, - {1000390940, 93.911592062}, - {1000400940, 93.906312523}, - {1000410940, 93.907279001}, - {1000420940, 93.905083586}, - {1000430940, 93.909652319}, - {1000440940, 93.91134286}, - {1000450940, 93.92173045}, - {1000460940, 93.929036286}, - {1000470940, 93.943744}, - {1000480940, 93.956586}, - {1000340950, 94.9673}, - {1000350950, 94.952925}, - {1000360950, 94.939710922}, - {1000370950, 94.929263849}, - {1000380950, 94.919358282}, - {1000390950, 94.912819697}, - {1000400950, 94.908040276}, - {1000410950, 94.90683111}, - {1000420950, 94.905837436}, - {1000430950, 94.907652281}, - {1000440950, 94.910404415}, - {1000450950, 94.915897893}, - {1000460950, 94.924888506}, - {1000470950, 94.935688}, - {1000480950, 94.949483}, - {1000350960, 95.95898}, - {1000360960, 95.943014473}, - {1000370960, 95.934133398}, - {1000380960, 95.921719045}, - {1000390960, 95.915909305}, - {1000400960, 95.908277615}, - {1000410960, 95.908101586}, - {1000420960, 95.90467477}, - {1000430960, 95.907866675}, - {1000440960, 95.90758891}, - {1000450960, 95.914451705}, - {1000460960, 95.918213739}, - {1000470960, 95.930743903}, - {1000480960, 95.940341}, - {1000490960, 95.959109}, - {1000350970, 96.963499}, - {1000360970, 96.949088782}, - {1000370970, 96.937177117}, - {1000380970, 96.926375621}, - {1000390970, 96.918286702}, - {1000400970, 96.910963802}, - {1000410970, 96.908101622}, - {1000420970, 96.906016903}, - {1000430970, 96.90636072}, - {1000440970, 96.907545776}, - {1000450970, 96.911327872}, - {1000460970, 96.916471985}, - {1000470970, 96.9238814}, - {1000480970, 96.934799343}, - {1000490970, 96.949125}, - {1000350980, 97.969887}, - {1000360980, 97.952635}, - {1000370980, 97.941632317}, - {1000380980, 97.928692636}, - {1000390980, 97.922394841}, - {1000400980, 97.912740448}, - {1000410980, 97.910332645}, - {1000420980, 97.905403609}, - {1000430980, 97.907211206}, - {1000440980, 97.905286709}, - {1000450980, 97.910707734}, - {1000460980, 97.912698335}, - {1000470980, 97.92155997}, - {1000480980, 97.927389315}, - {1000490980, 97.942129}, - {1000360990, 98.958776}, - {1000370990, 98.94511919}, - {1000380990, 98.932883604}, - {1000390990, 98.924160839}, - {1000400990, 98.916675081}, - {1000410990, 98.911609377}, - {1000420990, 98.907707299}, - {1000430990, 98.906249681}, - {1000440990, 98.905930284}, - {1000450990, 98.908121241}, - {1000460990, 98.911773073}, - {1000470990, 98.917645766}, - {1000480990, 98.924925845}, - {1000490990, 98.93411}, - {1000500990, 98.948495}, - {1000361000, 99.962995}, - {1000371000, 99.950331532}, - {1000381000, 99.93578327}, - {1000391000, 99.927727678}, - {1000401000, 99.918010499}, - {1000411000, 99.914340578}, - {1000421000, 99.907467982}, - {1000431000, 99.907652715}, - {1000441000, 99.90421046}, - {1000451000, 99.908114147}, - {1000461000, 99.908520438}, - {1000471000, 99.916115443}, - {1000481000, 99.920348829}, - {1000491000, 99.931101929}, - {1000501000, 99.938648944}, - {1000361010, 100.969318}, - {1000371010, 100.954302}, - {1000381010, 100.940606264}, - {1000391010, 100.930160817}, - {1000401010, 100.921458454}, - {1000411010, 100.915306508}, - {1000421010, 100.910337648}, - {1000431010, 100.907305271}, - {1000441010, 100.905573086}, - {1000451010, 100.906158903}, - {1000461010, 100.908284824}, - {1000471010, 100.912683951}, - {1000481010, 100.918586209}, - {1000491010, 100.926414025}, - {1000501010, 100.935259252}, - {1000371020, 101.960008}, - {1000381020, 101.944004679}, - {1000391020, 101.934328471}, - {1000401020, 101.923154181}, - {1000411020, 101.918090447}, - {1000421020, 101.910293725}, - {1000431020, 101.909207239}, - {1000441020, 101.904340312}, - {1000451020, 101.906834282}, - {1000461020, 101.905632292}, - {1000471020, 101.911704538}, - {1000481020, 101.914481797}, - {1000491020, 101.924105911}, - {1000501020, 101.930289525}, - {1000511020, 101.945142}, - {1000371030, 102.964401}, - {1000381030, 102.949243}, - {1000391030, 102.937243796}, - {1000401030, 102.927204054}, - {1000411030, 102.919453416}, - {1000421030, 102.913091954}, - {1000431030, 102.90917396}, - {1000441030, 102.906314846}, - {1000451030, 102.905494081}, - {1000461030, 102.906111074}, - {1000471030, 102.908960558}, - {1000481030, 102.913416922}, - {1000491030, 102.91987883}, - {1000501030, 102.927973}, - {1000511030, 102.939162}, - {1000371040, 103.970531}, - {1000381040, 103.953022}, - {1000391040, 103.941943}, - {1000401040, 103.929449193}, - {1000411040, 103.922907728}, - {1000421040, 103.913747443}, - {1000431040, 103.911433718}, - {1000441040, 103.905425312}, - {1000451040, 103.906645309}, - {1000461040, 103.904030393}, - {1000471040, 103.908623715}, - {1000481040, 103.909856228}, - {1000491040, 103.918214538}, - {1000501040, 103.923105195}, - {1000511040, 103.936344}, - {1000521040, 103.946723408}, - {1000381050, 104.959001}, - {1000391050, 104.945711}, - {1000401050, 104.934021832}, - {1000411050, 104.924942577}, - {1000421050, 104.91698198899999}, - {1000431050, 104.911662024}, - {1000441050, 104.907745478}, - {1000451050, 104.905687787}, - {1000461050, 104.905079479}, - {1000471050, 104.906525604}, - {1000481050, 104.909463893}, - {1000491050, 104.914502322}, - {1000501050, 104.921268421}, - {1000511050, 104.931276547}, - {1000521050, 104.943304516}, - {1000381060, 105.963177}, - {1000391060, 105.950842}, - {1000401060, 105.93693}, - {1000411060, 105.928928505}, - {1000421060, 105.918273231}, - {1000431060, 105.914356674}, - {1000441060, 105.907328181}, - {1000451060, 105.907285879}, - {1000461060, 105.903480287}, - {1000471060, 105.906663499}, - {1000481060, 105.906459791}, - {1000491060, 105.913463596}, - {1000501060, 105.916957394}, - {1000511060, 105.928637979}, - {1000521060, 105.937498521}, - {1000531060, 105.953516}, - {1000381070, 106.969672}, - {1000391070, 106.954943}, - {1000401070, 106.942007}, - {1000411070, 106.931589685}, - {1000421070, 106.92211977}, - {1000431070, 106.915458437}, - {1000441070, 106.909969837}, - {1000451070, 106.906747975}, - {1000461070, 106.905128058}, - {1000471070, 106.905091509}, - {1000481070, 106.906612049}, - {1000491070, 106.910287497}, - {1000501070, 106.915713649}, - {1000511070, 106.924150621}, - {1000521070, 106.934882}, - {1000531070, 106.946935}, - {1000391080, 107.960515}, - {1000401080, 107.945303}, - {1000411080, 107.936075604}, - {1000421080, 107.924047508}, - {1000431080, 107.918493493}, - {1000441080, 107.910185793}, - {1000451080, 107.908715304}, - {1000461080, 107.903891806}, - {1000471080, 107.905950245}, - {1000481080, 107.904183588}, - {1000491080, 107.909693654}, - {1000501080, 107.91189429}, - {1000511080, 107.922226731}, - {1000521080, 107.929380469}, - {1000531080, 107.943348}, - {1000541080, 107.954232285}, - {1000391090, 108.965131}, - {1000401090, 108.950907}, - {1000411090, 108.939141}, - {1000421090, 108.928438318}, - {1000431090, 108.920254107}, - {1000441090, 108.913323707}, - {1000451090, 108.908749555}, - {1000461090, 108.905950576}, - {1000471090, 108.904755778}, - {1000481090, 108.904986697}, - {1000491090, 108.907149679}, - {1000501090, 108.911292857}, - {1000511090, 108.918141203}, - {1000521090, 108.927304532}, - {1000531090, 108.938086022}, - {1000541090, 108.950434955}, - {1000401100, 109.954675}, - {1000411100, 109.943843}, - {1000421100, 109.930717956}, - {1000431100, 109.923741263}, - {1000441100, 109.914038501}, - {1000451100, 109.911079745}, - {1000461100, 109.905172878}, - {1000471100, 109.906110724}, - {1000481100, 109.90300747}, - {1000491100, 109.907170674}, - {1000501100, 109.907844835}, - {1000511100, 109.916854283}, - {1000521100, 109.922458102}, - {1000531100, 109.935085102}, - {1000541100, 109.944258759}, - {1000401110, 110.960837}, - {1000411110, 110.947439}, - {1000421110, 110.935651966}, - {1000431110, 110.925898966}, - {1000441110, 110.917567566}, - {1000451110, 110.911643164}, - {1000461110, 110.907690358}, - {1000471110, 110.905296827}, - {1000481110, 110.904183776}, - {1000491110, 110.905107236}, - {1000501110, 110.907741143}, - {1000511110, 110.913218187}, - {1000521110, 110.921000587}, - {1000531110, 110.930269236}, - {1000541110, 110.94147}, - {1000551110, 110.953945}, - {1000401120, 111.965196}, - {1000411120, 111.952689}, - {1000421120, 111.938293}, - {1000431120, 111.929941658}, - {1000441120, 111.918806922}, - {1000451120, 111.914405199}, - {1000461120, 111.907330557}, - {1000471120, 111.907048548}, - {1000481120, 111.902763896}, - {1000491120, 111.905538718}, - {1000501120, 111.904824894}, - {1000511120, 111.912399903}, - {1000521120, 111.916727848}, - {1000531120, 111.928004548}, - {1000541120, 111.935559068}, - {1000551120, 111.950172}, - {1000401130, 112.971723}, - {1000411130, 112.956833}, - {1000421130, 112.943478}, - {1000431130, 112.932569032}, - {1000441130, 112.922846729}, - {1000451130, 112.915440212}, - {1000461130, 112.910261912}, - {1000471130, 112.906572865}, - {1000481130, 112.904408105}, - {1000491130, 112.904060451}, - {1000501130, 112.905175857}, - {1000511130, 112.909374664}, - {1000521130, 112.915891}, - {1000531130, 112.923650062}, - {1000541130, 112.933221663}, - {1000551130, 112.944428484}, - {1000561130, 112.95737}, - {1000411140, 113.962469}, - {1000421140, 113.946666}, - {1000431140, 113.93709}, - {1000441140, 113.92461443}, - {1000451140, 113.91872168}, - {1000461140, 113.91036943}, - {1000471140, 113.908823029}, - {1000481140, 113.903364998}, - {1000491140, 113.904916405}, - {1000501140, 113.90278013}, - {1000511140, 113.909289155}, - {1000521140, 113.91208782}, - {1000531140, 113.9220189}, - {1000541140, 113.927980329}, - {1000551140, 113.941292244}, - {1000561140, 113.950718489}, - {1000411150, 114.966849}, - {1000421150, 114.952174}, - {1000431150, 114.9401}, - {1000441150, 114.929033049}, - {1000451150, 114.920311649}, - {1000461150, 114.913659333}, - {1000471150, 114.908767445}, - {1000481150, 114.905437426}, - {1000491150, 114.903878772}, - {1000501150, 114.903344695}, - {1000511150, 114.906598}, - {1000521150, 114.911902}, - {1000531150, 114.918048}, - {1000541150, 114.926293943}, - {1000551150, 114.93591}, - {1000561150, 114.947482}, - {1000411160, 115.972914}, - {1000421160, 115.955759}, - {1000431160, 115.94502}, - {1000441160, 115.931219191}, - {1000451160, 115.92406206}, - {1000461160, 115.914297872}, - {1000471160, 115.911386809}, - {1000481160, 115.90476323}, - {1000491160, 115.905259992}, - {1000501160, 115.901742825}, - {1000511160, 115.906792732}, - {1000521160, 115.908465558}, - {1000531160, 115.916885513}, - {1000541160, 115.921580955}, - {1000551160, 115.933395}, - {1000561160, 115.941621}, - {1000571160, 115.957005}, - {1000421170, 116.961686}, - {1000431170, 116.94832}, - {1000441170, 116.936135}, - {1000451170, 116.926036291}, - {1000461170, 116.917955584}, - {1000471170, 116.911774086}, - {1000481170, 116.907226039}, - {1000491170, 116.904515729}, - {1000501170, 116.902954036}, - {1000511170, 116.904841519}, - {1000521170, 116.908646227}, - {1000531170, 116.913645649}, - {1000541170, 116.920358758}, - {1000551170, 116.928616723}, - {1000561170, 116.938316403}, - {1000571170, 116.950326}, - {1000421180, 117.965249}, - {1000431180, 117.953526}, - {1000441180, 117.938808}, - {1000451180, 117.930341116}, - {1000461180, 117.919067273}, - {1000471180, 117.914595484}, - {1000481180, 117.906921956}, - {1000491180, 117.906356705}, - {1000501180, 117.90160663}, - {1000511180, 117.905532194}, - {1000521180, 117.905860104}, - {1000531180, 117.913074}, - {1000541180, 117.916178678}, - {1000551180, 117.926559517}, - {1000561180, 117.933226}, - {1000571180, 117.946731}, - {1000421190, 118.971465}, - {1000431190, 118.956876}, - {1000441190, 118.94409}, - {1000451190, 118.932556951}, - {1000461190, 118.923341138}, - {1000471190, 118.915570309}, - {1000481190, 118.909847052}, - {1000491190, 118.905851622}, - {1000501190, 118.903311266}, - {1000511190, 118.903944062}, - {1000521190, 118.906405699}, - {1000531190, 118.91006091}, - {1000541190, 118.915410641}, - {1000551190, 118.922377327}, - {1000561190, 118.930659683}, - {1000571190, 118.940934}, - {1000581190, 118.952957}, - {1000431200, 119.962426}, - {1000441200, 119.946623}, - {1000451200, 119.937069}, - {1000461200, 119.924551745}, - {1000471200, 119.918784765}, - {1000481200, 119.909868065}, - {1000491200, 119.907967489}, - {1000501200, 119.902202557}, - {1000511200, 119.905080308}, - {1000521200, 119.904065779}, - {1000531200, 119.910093729}, - {1000541200, 119.911784267}, - {1000551200, 119.920677277}, - {1000561200, 119.926044997}, - {1000571200, 119.938196}, - {1000581200, 119.946613}, - {1000431210, 120.96614}, - {1000441210, 120.952098}, - {1000451210, 120.939613}, - {1000461210, 120.928950342}, - {1000471210, 120.920125279}, - {1000481210, 120.91296366}, - {1000491210, 120.907852778}, - {1000501210, 120.904243488}, - {1000511210, 120.903811353}, - {1000521210, 120.904945065}, - {1000531210, 120.907411492}, - {1000541210, 120.911453012}, - {1000551210, 120.917227235}, - {1000561210, 120.924052286}, - {1000571210, 120.933236}, - {1000581210, 120.943435}, - {1000591210, 120.955393}, - {1000431220, 121.97176}, - {1000441220, 121.955147}, - {1000451220, 121.944305}, - {1000461220, 121.930631693}, - {1000471220, 121.923664446}, - {1000481220, 121.91345905}, - {1000491220, 121.910282458}, - {1000501220, 121.903445494}, - {1000511220, 121.905169335}, - {1000521220, 121.903044708}, - {1000531220, 121.907590094}, - {1000541220, 121.908367655}, - {1000551220, 121.916108144}, - {1000561220, 121.919904}, - {1000571220, 121.93071}, - {1000581220, 121.93787}, - {1000591220, 121.951927}, - {1000441230, 122.960762}, - {1000451230, 122.947192}, - {1000461230, 122.935126}, - {1000471230, 122.92531506}, - {1000481230, 122.91689246}, - {1000491230, 122.910435252}, - {1000501230, 122.905727065}, - {1000511230, 122.904215292}, - {1000521230, 122.904271022}, - {1000531230, 122.905589753}, - {1000541230, 122.908482235}, - {1000551230, 122.91299606}, - {1000561230, 122.91878106}, - {1000571230, 122.9263}, - {1000581230, 122.93528}, - {1000591230, 122.946076}, - {1000441240, 123.96394}, - {1000451240, 123.952002}, - {1000461240, 123.937305}, - {1000471240, 123.928899227}, - {1000481240, 123.917659772}, - {1000491240, 123.913184873}, - {1000501240, 123.905279619}, - {1000511240, 123.905937065}, - {1000521240, 123.902818341}, - {1000531240, 123.906210297}, - {1000541240, 123.905885174}, - {1000551240, 123.912247366}, - {1000561240, 123.915093627}, - {1000571240, 123.924574275}, - {1000581240, 123.93031}, - {1000591240, 123.94294}, - {1000601240, 123.951873}, - {1000441250, 124.969544}, - {1000451250, 124.955094}, - {1000461250, 124.942072}, - {1000471250, 124.930735}, - {1000481250, 124.92125759}, - {1000491250, 124.913673841}, - {1000501250, 124.90778937}, - {1000511250, 124.905254264}, - {1000521250, 124.904431178}, - {1000531250, 124.90463061}, - {1000541250, 124.90638764}, - {1000551250, 124.909725953}, - {1000561250, 124.91447184}, - {1000571250, 124.92081593099999}, - {1000581250, 124.92844}, - {1000591250, 124.937659}, - {1000601250, 124.948395}, - {1000451260, 125.960064}, - {1000461260, 125.944401}, - {1000471260, 125.934814}, - {1000481260, 125.92243029}, - {1000491260, 125.916468202}, - {1000501260, 125.907658958}, - {1000511260, 125.907253158}, - {1000521260, 125.903312144}, - {1000531260, 125.905624205}, - {1000541260, 125.904297422}, - {1000551260, 125.909445821}, - {1000561260, 125.911250202}, - {1000571260, 125.919512667}, - {1000581260, 125.923971}, - {1000591260, 125.93524}, - {1000601260, 125.942694}, - {1000611260, 125.957327}, - {1000451270, 126.963789}, - {1000461270, 126.949307}, - {1000471270, 126.937037}, - {1000481270, 126.926203291}, - {1000491270, 126.91746604}, - {1000501270, 126.910391726}, - {1000511270, 126.906925557}, - {1000521270, 126.905226993}, - {1000531270, 126.904472592}, - {1000541270, 126.905183636}, - {1000551270, 126.907417527}, - {1000561270, 126.911091272}, - {1000571270, 126.916375083}, - {1000581270, 126.922727}, - {1000591270, 126.93071}, - {1000601270, 126.939978}, - {1000611270, 126.951358}, - {1000451280, 127.970649}, - {1000461280, 127.952345}, - {1000471280, 127.941266}, - {1000481280, 127.927816778}, - {1000491280, 127.920353637}, - {1000501280, 127.910507828}, - {1000511280, 127.909146121}, - {1000521280, 127.904461237}, - {1000531280, 127.905809355}, - {1000541280, 127.90353075341}, - {1000551280, 127.907748452}, - {1000561280, 127.908352446}, - {1000571280, 127.915592123}, - {1000581280, 127.918911}, - {1000591280, 127.928791}, - {1000601280, 127.935018}, - {1000611280, 127.948234}, - {1000621280, 127.957971}, - {1000461290, 128.959334}, - {1000471290, 128.944315}, - {1000481290, 128.932235597}, - {1000491290, 128.921808534}, - {1000501290, 128.91348244}, - {1000511290, 128.909146623}, - {1000521290, 128.906596419}, - {1000531290, 128.904983643}, - {1000541290, 128.90478085742}, - {1000551290, 128.90606591}, - {1000561290, 128.908683409}, - {1000571290, 128.912695592}, - {1000581290, 128.918102}, - {1000591290, 128.925095}, - {1000601290, 128.933038}, - {1000611290, 128.942909}, - {1000621290, 128.954557}, - {1000461300, 129.964863}, - {1000471300, 129.950727}, - {1000481300, 129.934387563}, - {1000491300, 129.924952257}, - {1000501300, 129.913974531}, - {1000511300, 129.911662686}, - {1000521300, 129.906222745}, - {1000531300, 129.906670168}, - {1000541300, 129.903509346}, - {1000551300, 129.906709281}, - {1000561300, 129.906326002}, - {1000571300, 129.912369413}, - {1000581300, 129.914736}, - {1000591300, 129.92359}, - {1000601300, 129.928506}, - {1000611300, 129.940451}, - {1000621300, 129.948792}, - {1000631300, 129.964022}, - {1000461310, 130.972367}, - {1000471310, 130.956253}, - {1000481310, 130.94072774}, - {1000491310, 130.926972839}, - {1000501310, 130.917053067}, - {1000511310, 130.911989339}, - {1000521310, 130.90852221}, - {1000531310, 130.906126375}, - {1000541310, 130.90508412808}, - {1000551310, 130.905468457}, - {1000561310, 130.906946315}, - {1000571310, 130.91007}, - {1000581310, 130.914429465}, - {1000591310, 130.92023496}, - {1000601310, 130.92724802}, - {1000611310, 130.935834}, - {1000621310, 130.946022}, - {1000631310, 130.957634}, - {1000471320, 131.96307}, - {1000481320, 131.945823136}, - {1000491320, 131.932998444}, - {1000501320, 131.917823898}, - {1000511320, 131.914508013}, - {1000521320, 131.908546713}, - {1000531320, 131.907993511}, - {1000541320, 131.90415508346}, - {1000551320, 131.90643774}, - {1000561320, 131.905061231}, - {1000571320, 131.910119047}, - {1000581320, 131.911466226}, - {1000591320, 131.91924}, - {1000601320, 131.923321237}, - {1000611320, 131.93384}, - {1000621320, 131.940805}, - {1000631320, 131.954696}, - {1000471330, 132.968781}, - {1000481330, 132.952614}, - {1000491330, 132.938067}, - {1000501330, 132.923913753}, - {1000511330, 132.915272128}, - {1000521330, 132.91096333}, - {1000531330, 132.9078284}, - {1000541330, 132.905910748}, - {1000551330, 132.905451958}, - {1000561330, 132.906007443}, - {1000571330, 132.908218}, - {1000581330, 132.911520402}, - {1000591330, 132.916330558}, - {1000601330, 132.922348}, - {1000611330, 132.929782}, - {1000621330, 132.93856}, - {1000631330, 132.94929}, - {1000641330, 132.961288}, - {1000481340, 133.957638}, - {1000491340, 133.944208}, - {1000501340, 133.92868043}, - {1000511340, 133.920537334}, - {1000521340, 133.911396376}, - {1000531340, 133.90977566}, - {1000541340, 133.90539303}, - {1000551340, 133.906718501}, - {1000561340, 133.904508249}, - {1000571340, 133.908514011}, - {1000581340, 133.908928142}, - {1000591340, 133.915696729}, - {1000601340, 133.918790207}, - {1000611340, 133.928326}, - {1000621340, 133.93411}, - {1000631340, 133.946537}, - {1000641340, 133.955416}, - {1000481350, 134.964766}, - {1000491350, 134.949425}, - {1000501350, 134.934908603}, - {1000511350, 134.925184354}, - {1000521350, 134.916554715}, - {1000531350, 134.910059355}, - {1000541350, 134.907231441}, - {1000551350, 134.905976907}, - {1000561350, 134.905688447}, - {1000571350, 134.906984427}, - {1000581350, 134.909160662}, - {1000591350, 134.913111772}, - {1000601350, 134.918181318}, - {1000611350, 134.92478499999999}, - {1000621350, 134.93252}, - {1000631350, 134.94187}, - {1000641350, 134.952496}, - {1000651350, 134.964516}, - {1000491360, 135.956017}, - {1000501360, 135.939699}, - {1000511360, 135.930749009}, - {1000521360, 135.92010118}, - {1000531360, 135.914604693}, - {1000541360, 135.907214474}, - {1000551360, 135.907311431}, - {1000561360, 135.9045758}, - {1000571360, 135.907634962}, - {1000581360, 135.907129256}, - {1000591360, 135.91267747}, - {1000601360, 135.914976061}, - {1000611360, 135.923595949}, - {1000621360, 135.928275553}, - {1000631360, 135.93962}, - {1000641360, 135.9473}, - {1000651360, 135.96146}, - {1000491370, 136.961535}, - {1000501370, 136.946162}, - {1000511370, 136.935522519}, - {1000521370, 136.925599354}, - {1000531370, 136.918028178}, - {1000541370, 136.911557771}, - {1000551370, 136.907089296}, - {1000561370, 136.905827207}, - {1000571370, 136.906450438}, - {1000581370, 136.907762416}, - {1000591370, 136.910679183}, - {1000601370, 136.914563099}, - {1000611370, 136.920479519}, - {1000621370, 136.927007959}, - {1000631370, 136.935430719}, - {1000641370, 136.94502}, - {1000651370, 136.95602}, - {1000501380, 137.951143}, - {1000511380, 137.941331}, - {1000521380, 137.929472452}, - {1000531380, 137.922726392}, - {1000541380, 137.914146268}, - {1000551380, 137.911017119}, - {1000561380, 137.905247059}, - {1000571380, 137.907124041}, - {1000581380, 137.90599418}, - {1000591380, 137.910757495}, - {1000601380, 137.911950938}, - {1000611380, 137.919576119}, - {1000621380, 137.923243988}, - {1000631380, 137.933709}, - {1000641380, 137.940247}, - {1000651380, 137.953193}, - {1000661380, 137.9625}, - {1000501390, 138.957799}, - {1000511390, 138.946269}, - {1000521390, 138.935367191}, - {1000531390, 138.9264934}, - {1000541390, 138.9187922}, - {1000551390, 138.913363822}, - {1000561390, 138.908841164}, - {1000571390, 138.906362927}, - {1000581390, 138.906647029}, - {1000591390, 138.9089327}, - {1000601390, 138.911951208}, - {1000611390, 138.916799228}, - {1000621390, 138.922296631}, - {1000631390, 138.929792307}, - {1000641390, 138.93813}, - {1000651390, 138.94833}, - {1000661390, 138.959527}, - {1000501400, 139.962973}, - {1000511400, 139.952345}, - {1000521400, 139.939487057}, - {1000531400, 139.931715914}, - {1000541400, 139.921645814}, - {1000551400, 139.917283707}, - {1000561400, 139.910608231}, - {1000571400, 139.909487285}, - {1000581400, 139.905448433}, - {1000591400, 139.9090856}, - {1000601400, 139.90954613}, - {1000611400, 139.916035918}, - {1000621400, 139.918994714}, - {1000631400, 139.928087633}, - {1000641400, 139.933674}, - {1000651400, 139.945805048}, - {1000661400, 139.95402}, - {1000671400, 139.968526}, - {1000511410, 140.957552}, - {1000521410, 140.945604}, - {1000531410, 140.935666081}, - {1000541410, 140.926787181}, - {1000551410, 140.920045279}, - {1000561410, 140.914403653}, - {1000571410, 140.910971155}, - {1000581410, 140.908285991}, - {1000591410, 140.907659604}, - {1000601410, 140.90961669}, - {1000611410, 140.913555081}, - {1000621410, 140.918481545}, - {1000631410, 140.924931734}, - {1000641410, 140.932126}, - {1000651410, 140.941448}, - {1000661410, 140.95128}, - {1000671410, 140.963108}, - {1000511420, 141.963918}, - {1000521420, 141.950027}, - {1000531420, 141.941166595}, - {1000541420, 141.929973095}, - {1000551420, 141.924299514}, - {1000561420, 141.916432904}, - {1000571420, 141.91409076}, - {1000581420, 141.909250208}, - {1000591420, 141.91005164}, - {1000601420, 141.907728824}, - {1000611420, 141.912890982}, - {1000621420, 141.915209415}, - {1000631420, 141.923446719}, - {1000641420, 141.928116}, - {1000651420, 141.939280858}, - {1000661420, 141.946194}, - {1000671420, 141.96001}, - {1000681420, 141.970016}, - {1000521430, 142.956489}, - {1000531430, 142.945475}, - {1000541430, 142.93536955}, - {1000551430, 142.927347346}, - {1000561430, 142.920625149}, - {1000571430, 142.916079482}, - {1000581430, 142.912391953}, - {1000591430, 142.910822624}, - {1000601430, 142.909819815}, - {1000611430, 142.910938068}, - {1000621430, 142.914634848}, - {1000631430, 142.920298678}, - {1000641430, 142.926750678}, - {1000651430, 142.935137332}, - {1000661430, 142.943994332}, - {1000671430, 142.95486}, - {1000681430, 142.966548}, - {1000521440, 143.961116}, - {1000531440, 143.951336}, - {1000541440, 143.938945076}, - {1000551440, 143.932075402}, - {1000561440, 143.922954821}, - {1000571440, 143.919645589}, - {1000581440, 143.913652763}, - {1000591440, 143.913310682}, - {1000601440, 143.910092798}, - {1000611440, 143.912596208}, - {1000621440, 143.912006285}, - {1000631440, 143.918819481}, - {1000641440, 143.922963}, - {1000651440, 143.933045}, - {1000661440, 143.939269512}, - {1000671440, 143.952109712}, - {1000681440, 143.9607}, - {1000691440, 143.976211}, - {1000521450, 144.967783}, - {1000531450, 144.955845}, - {1000541450, 144.944719631}, - {1000551450, 144.935528927}, - {1000561450, 144.9275184}, - {1000571450, 144.921808065}, - {1000581450, 144.917265113}, - {1000591450, 144.914517987}, - {1000601450, 144.912579151}, - {1000611450, 144.912755748}, - {1000621450, 144.913417157}, - {1000631450, 144.916272659}, - {1000641450, 144.921710051}, - {1000651450, 144.928717001}, - {1000661450, 144.937473992}, - {1000671450, 144.947267392}, - {1000681450, 144.957874}, - {1000691450, 144.970389}, - {1000531460, 145.961846}, - {1000541460, 145.948518245}, - {1000551460, 145.940621867}, - {1000561460, 145.9303632}, - {1000571460, 145.925688017}, - {1000581460, 145.918812294}, - {1000591460, 145.91768763}, - {1000601460, 145.913122459}, - {1000611460, 145.91470224}, - {1000621460, 145.913046835}, - {1000631460, 145.917210852}, - {1000641460, 145.918318513}, - {1000651460, 145.927252739}, - {1000661460, 145.932844526}, - {1000671460, 145.944993503}, - {1000681460, 145.952418357}, - {1000691460, 145.966661}, - {1000531470, 146.966505}, - {1000541470, 146.954482}, - {1000551470, 146.944261512}, - {1000561470, 146.9353039}, - {1000571470, 146.9284178}, - {1000581470, 146.9226899}, - {1000591470, 146.919007438}, - {1000601470, 146.916105969}, - {1000611470, 146.915144944}, - {1000621470, 146.914904401}, - {1000631470, 146.91675244}, - {1000641470, 146.919101014}, - {1000651470, 146.92405462}, - {1000661470, 146.931082712}, - {1000671470, 146.940142293}, - {1000681470, 146.949964456}, - {1000691470, 146.961379887}, - {1000541480, 147.958508}, - {1000551480, 147.949639026}, - {1000561480, 147.938223}, - {1000571480, 147.9326794}, - {1000581480, 147.924424186}, - {1000591480, 147.922129992}, - {1000601480, 147.916899027}, - {1000611480, 147.917481091}, - {1000621480, 147.914829233}, - {1000631480, 147.918091288}, - {1000641480, 147.918121414}, - {1000651480, 147.924275476}, - {1000661480, 147.927149944}, - {1000671480, 147.937743925}, - {1000681480, 147.944735026}, - {1000691480, 147.958384026}, - {1000701480, 147.967547}, - {1000541490, 148.964573}, - {1000551490, 148.953516}, - {1000561490, 148.943284}, - {1000571490, 148.935351259}, - {1000581490, 148.9284269}, - {1000591490, 148.9237361}, - {1000601490, 148.920154583}, - {1000611490, 148.918341507}, - {1000621490, 148.917191211}, - {1000631490, 148.917936875}, - {1000641490, 148.919347666}, - {1000651490, 148.923253792}, - {1000661490, 148.927327516}, - {1000671490, 148.933820457}, - {1000681490, 148.942306}, - {1000691490, 148.952828}, - {1000701490, 148.964219}, - {1000541500, 149.968878}, - {1000551500, 149.959023}, - {1000561500, 149.9464411}, - {1000571500, 149.9395475}, - {1000581500, 149.930384032}, - {1000591500, 149.926676391}, - {1000601500, 149.920901322}, - {1000611500, 149.920990014}, - {1000621500, 149.917281993}, - {1000631500, 149.919707092}, - {1000641500, 149.918663949}, - {1000651500, 149.923664799}, - {1000661500, 149.925593068}, - {1000671500, 149.933498353}, - {1000681500, 149.937915524}, - {1000691500, 149.95009}, - {1000701500, 149.958314}, - {1000711500, 149.973407}, - {1000551510, 150.963199}, - {1000561510, 150.951755}, - {1000571510, 150.942769}, - {1000581510, 150.9342722}, - {1000591510, 150.928309066}, - {1000601510, 150.923839363}, - {1000611510, 150.921216613}, - {1000621510, 150.919938859}, - {1000631510, 150.919856606}, - {1000641510, 150.920354922}, - {1000651510, 150.92310897}, - {1000661510, 150.926191279}, - {1000671510, 150.931698176}, - {1000681510, 150.937448567}, - {1000691510, 150.945494433}, - {1000701510, 150.955402453}, - {1000711510, 150.967471}, - {1000551520, 151.968728}, - {1000561520, 151.95533}, - {1000571520, 151.947085}, - {1000581520, 151.936682}, - {1000591520, 151.9315529}, - {1000601520, 151.924691242}, - {1000611520, 151.923505185}, - {1000621520, 151.919738646}, - {1000631520, 151.92175098}, - {1000641520, 151.919798414}, - {1000651520, 151.924081855}, - {1000661520, 151.924725274}, - {1000671520, 151.931717618}, - {1000681520, 151.935050347}, - {1000691520, 151.944476}, - {1000701520, 151.950326699}, - {1000711520, 151.96412}, - {1000561530, 152.960848}, - {1000571530, 152.950553}, - {1000581530, 152.941052}, - {1000591530, 152.933903511}, - {1000601530, 152.927717868}, - {1000611530, 152.924156252}, - {1000621530, 152.922103576}, - {1000631530, 152.921236789}, - {1000641530, 152.921756945}, - {1000651530, 152.923441694}, - {1000661530, 152.925771729}, - {1000671530, 152.930206671}, - {1000681530, 152.93508635}, - {1000691530, 152.942058023}, - {1000701530, 152.949372}, - {1000711530, 152.958802248}, - {1000721530, 152.970692}, - {1000561540, 153.964659}, - {1000571540, 153.955416}, - {1000581540, 153.94394}, - {1000591540, 153.937885165}, - {1000601540, 153.929597404}, - {1000611540, 153.926712791}, - {1000621540, 153.922215756}, - {1000631540, 153.922985699}, - {1000641540, 153.920872974}, - {1000651540, 153.924683681}, - {1000661540, 153.92442892}, - {1000671540, 153.930606776}, - {1000681540, 153.932790799}, - {1000691540, 153.941570062}, - {1000701540, 153.946395696}, - {1000711540, 153.957416}, - {1000721540, 153.964863}, - {1000571550, 154.95928}, - {1000581550, 154.948706}, - {1000591550, 154.940509193}, - {1000601550, 154.933135598}, - {1000611550, 154.928136951}, - {1000621550, 154.924646645}, - {1000631550, 154.922899847}, - {1000641550, 154.922629356}, - {1000651550, 154.923509511}, - {1000661550, 154.925758049}, - {1000671550, 154.929103363}, - {1000681550, 154.93321571}, - {1000691550, 154.939209576}, - {1000701550, 154.945783216}, - {1000711550, 154.954326005}, - {1000721550, 154.963167}, - {1000731550, 154.974248}, - {1000571560, 155.964519}, - {1000581560, 155.951884}, - {1000591560, 155.9447669}, - {1000601560, 155.935370358}, - {1000611560, 155.931114059}, - {1000621560, 155.925538191}, - {1000631560, 155.924762976}, - {1000641560, 155.92213012}, - {1000651560, 155.924754209}, - {1000661560, 155.924283593}, - {1000671560, 155.929641634}, - {1000681560, 155.931065926}, - {1000691560, 155.938985746}, - {1000701560, 155.942817096}, - {1000711560, 155.953086606}, - {1000721560, 155.959399083}, - {1000731560, 155.972087}, - {1000571570, 156.968792}, - {1000581570, 156.957133}, - {1000591570, 156.9480031}, - {1000601570, 156.939351074}, - {1000611570, 156.933121298}, - {1000621570, 156.928418598}, - {1000631570, 156.925432556}, - {1000641570, 156.923967424}, - {1000651570, 156.924031888}, - {1000661570, 156.925469555}, - {1000671570, 156.928251974}, - {1000681570, 156.931922652}, - {1000691570, 156.936973}, - {1000701570, 156.94265136799999}, - {1000711570, 156.950144807}, - {1000721570, 156.958288}, - {1000731570, 156.968227445}, - {1000741570, 156.978862}, - {1000581580, 157.960773}, - {1000591580, 157.952603}, - {1000601580, 157.94220562}, - {1000611580, 157.936546948}, - {1000621580, 157.929949262}, - {1000631580, 157.927782192}, - {1000641580, 157.9241112}, - {1000651580, 157.925419942}, - {1000661580, 157.924414817}, - {1000671580, 157.92894491}, - {1000681580, 157.929893474}, - {1000691580, 157.936979525}, - {1000701580, 157.939871202}, - {1000711580, 157.94931562}, - {1000721580, 157.954801217}, - {1000731580, 157.966593}, - {1000741580, 157.974565}, - {1000581590, 158.966355}, - {1000591590, 158.956232}, - {1000601590, 158.946619085}, - {1000611590, 158.939286409}, - {1000621590, 158.93321713}, - {1000631590, 158.929099512}, - {1000641590, 158.926395822}, - {1000651590, 158.925353707}, - {1000661590, 158.925745938}, - {1000671590, 158.927718683}, - {1000681590, 158.93069079}, - {1000691590, 158.934975}, - {1000701590, 158.940060257}, - {1000711590, 158.946635615}, - {1000721590, 158.953995837}, - {1000731590, 158.963028046}, - {1000741590, 158.972696}, - {1000751590, 158.984106}, - {1000591600, 159.961138}, - {1000601600, 159.949839172}, - {1000611600, 159.943215272}, - {1000621600, 159.935337032}, - {1000631600, 159.931836982}, - {1000641600, 159.927061202}, - {1000651600, 159.927174553}, - {1000661600, 159.925203578}, - {1000671600, 159.928735538}, - {1000681600, 159.929077193}, - {1000691600, 159.935264177}, - {1000701600, 159.93755921}, - {1000711600, 159.946033}, - {1000721600, 159.950682728}, - {1000731600, 159.961541678}, - {1000741600, 159.968513946}, - {1000751600, 159.98188}, - {1000591610, 160.965121}, - {1000601610, 160.954664}, - {1000611610, 160.946229837}, - {1000621610, 160.939160062}, - {1000631610, 160.933663991}, - {1000641610, 160.929676267}, - {1000651610, 160.927576806}, - {1000661610, 160.926939425}, - {1000671610, 160.927861815}, - {1000681610, 160.93000353}, - {1000691610, 160.933549}, - {1000701610, 160.937912384}, - {1000711610, 160.943572}, - {1000721610, 160.950277927}, - {1000731610, 160.958369489}, - {1000741610, 160.967249}, - {1000751610, 160.977624313}, - {1000761610, 160.989054}, - {1000601620, 161.958121}, - {1000611620, 161.950574}, - {1000621620, 161.941621687}, - {1000631620, 161.936958329}, - {1000641620, 161.930991812}, - {1000651620, 161.9292754}, - {1000661620, 161.92680450699999}, - {1000671620, 161.929102543}, - {1000681620, 161.928787299}, - {1000691620, 161.934001211}, - {1000701620, 161.935779342}, - {1000711620, 161.943282776}, - {1000721620, 161.947215526}, - {1000731620, 161.957292907}, - {1000741620, 161.963500341}, - {1000751620, 161.975896}, - {1000761620, 161.984434}, - {1000601630, 162.963414}, - {1000611630, 162.953881}, - {1000621630, 162.945679085}, - {1000631630, 162.93926551}, - {1000641630, 162.93409664}, - {1000651630, 162.930653609}, - {1000661630, 162.928737221}, - {1000671630, 162.92874026}, - {1000681630, 162.930039908}, - {1000691630, 162.932658282}, - {1000701630, 162.936345406}, - {1000711630, 162.941179}, - {1000721630, 162.947107211}, - {1000731630, 162.954337194}, - {1000741630, 162.962524251}, - {1000751630, 162.972085434}, - {1000761630, 162.982462}, - {1000771630, 162.994299}, - {1000611640, 163.958819}, - {1000621640, 163.948550061}, - {1000631640, 163.942852943}, - {1000641640, 163.935916193}, - {1000651640, 163.933327561}, - {1000661640, 163.929180819}, - {1000671640, 163.930240548}, - {1000681640, 163.929207739}, - {1000691640, 163.933538019}, - {1000701640, 163.934500743}, - {1000711640, 163.941339}, - {1000721640, 163.944370709}, - {1000731640, 163.953534}, - {1000741640, 163.958952445}, - {1000751640, 163.970507122}, - {1000761640, 163.978073158}, - {1000771640, 163.991966}, - {1000611650, 164.96278}, - {1000621650, 164.95329}, - {1000631650, 164.94554007}, - {1000641650, 164.93931708}, - {1000651650, 164.934955198}, - {1000661650, 164.931709402}, - {1000671650, 164.930329116}, - {1000681650, 164.930733482}, - {1000691650, 164.932441843}, - {1000701650, 164.935270241}, - {1000711650, 164.939406758}, - {1000721650, 164.944567}, - {1000731650, 164.950780287}, - {1000741650, 164.958280663}, - {1000751650, 164.967085831}, - {1000761650, 164.976654}, - {1000771650, 164.987552}, - {1000781650, 164.999658}, - {1000621660, 165.956575}, - {1000631660, 165.949813}, - {1000641660, 165.941630413}, - {1000651660, 165.937939727}, - {1000661660, 165.93281281}, - {1000671660, 165.932291209}, - {1000681660, 165.930301067}, - {1000691660, 165.933562136}, - {1000701660, 165.933876439}, - {1000711660, 165.939859}, - {1000721660, 165.94218}, - {1000731660, 165.950512}, - {1000741660, 165.955031952}, - {1000751660, 165.965821216}, - {1000761660, 165.972698135}, - {1000771660, 165.985716}, - {1000781660, 165.994866}, - {1000621670, 166.962072}, - {1000631670, 166.953011}, - {1000641670, 166.945490012}, - {1000651670, 166.940007046}, - {1000661670, 166.935682415}, - {1000671670, 166.933140254}, - {1000681670, 166.932056192}, - {1000691670, 166.932857206}, - {1000701670, 166.934954069}, - {1000711670, 166.938243}, - {1000721670, 166.9426}, - {1000731670, 166.948093}, - {1000741670, 166.95481108}, - {1000751670, 166.962604}, - {1000761670, 166.971552304}, - {1000771670, 166.981671973}, - {1000781670, 166.99275}, - {1000621680, 167.966033}, - {1000631680, 167.957863}, - {1000641680, 167.948309}, - {1000651680, 167.943337074}, - {1000661680, 167.937134977}, - {1000671680, 167.935523766}, - {1000681680, 167.932378282}, - {1000691680, 167.934178457}, - {1000701680, 167.933891297}, - {1000711680, 167.938729798}, - {1000721680, 167.940568}, - {1000731680, 167.948047}, - {1000741680, 167.951805459}, - {1000751680, 167.961572607}, - {1000761680, 167.96779905}, - {1000771680, 167.979960978}, - {1000781680, 167.988180196}, - {1000791680, 168.002716}, - {1000631690, 168.961717}, - {1000641690, 168.952882}, - {1000651690, 168.945807}, - {1000661690, 168.940315231}, - {1000671690, 168.93687989}, - {1000681690, 168.934598444}, - {1000691690, 168.934218956}, - {1000701690, 168.935184208}, - {1000711690, 168.937645845}, - {1000721690, 168.941259}, - {1000731690, 168.946011}, - {1000741690, 168.951778689}, - {1000751690, 168.958765979}, - {1000761690, 168.967017521}, - {1000771690, 168.976281743}, - {1000781690, 168.986619}, - {1000791690, 168.99808}, - {1000631700, 169.96687}, - {1000641700, 169.956146}, - {1000651700, 169.949855}, - {1000661700, 169.94234}, - {1000671700, 169.939626548}, - {1000681700, 169.935471933}, - {1000691700, 169.935807093}, - {1000701700, 169.934767242}, - {1000711700, 169.93847923}, - {1000721700, 169.939609}, - {1000731700, 169.946175}, - {1000741700, 169.949231235}, - {1000751700, 169.958234844}, - {1000761700, 169.963579273}, - {1000771700, 169.975113}, - {1000781700, 169.982502087}, - {1000791700, 169.996024}, - {1000801700, 170.005814}, - {1000641710, 170.961127}, - {1000651710, 170.953011}, - {1000661710, 170.946312}, - {1000671710, 170.941472713}, - {1000681710, 170.938037372}, - {1000691710, 170.936435162}, - {1000701710, 170.936331515}, - {1000711710, 170.937918591}, - {1000721710, 170.940492}, - {1000731710, 170.944476}, - {1000741710, 170.949451}, - {1000751710, 170.955716}, - {1000761710, 170.963180402}, - {1000771710, 170.97164552}, - {1000781710, 170.981248868}, - {1000791710, 170.991881533}, - {1000801710, 171.003585}, - {1000641720, 171.964605}, - {1000651720, 171.957391}, - {1000661720, 171.948728}, - {1000671720, 171.94473}, - {1000681720, 171.939363461}, - {1000691720, 171.938406959}, - {1000701720, 171.936386654}, - {1000711720, 171.93909132}, - {1000721720, 171.939449716}, - {1000731720, 171.944895}, - {1000741720, 171.947292}, - {1000751720, 171.955376165}, - {1000761720, 171.960017309}, - {1000771720, 171.970607035}, - {1000781720, 171.977341059}, - {1000791720, 171.989996704}, - {1000801720, 171.998860581}, - {1000651730, 172.960805}, - {1000661730, 172.953043}, - {1000671730, 172.94702}, - {1000681730, 172.9424}, - {1000691730, 172.93960663}, - {1000701730, 172.938216211}, - {1000711730, 172.938935722}, - {1000721730, 172.940513}, - {1000731730, 172.94375}, - {1000741730, 172.947689}, - {1000751730, 172.953243}, - {1000761730, 172.959808387}, - {1000771730, 172.967505477}, - {1000781730, 172.976449922}, - {1000791730, 172.986224263}, - {1000801730, 172.997143}, - {1000651740, 173.965679}, - {1000661740, 173.955845}, - {1000671740, 173.950757}, - {1000681740, 173.94423}, - {1000691740, 173.942174061}, - {1000701740, 173.938867545}, - {1000711740, 173.94034284}, - {1000721740, 173.940048377}, - {1000731740, 173.944454}, - {1000741740, 173.946079}, - {1000751740, 173.953115}, - {1000761740, 173.957063192}, - {1000771740, 173.966949939}, - {1000781740, 173.972820431}, - {1000791740, 173.984908}, - {1000801740, 173.992870575}, - {1000661750, 174.960569}, - {1000671750, 174.953516}, - {1000681750, 174.94777}, - {1000691750, 174.94384231}, - {1000701750, 174.941281907}, - {1000711750, 174.940777211}, - {1000721750, 174.941511424}, - {1000731750, 174.943737}, - {1000741750, 174.946717}, - {1000751750, 174.951381}, - {1000761750, 174.956945126}, - {1000771750, 174.964149519}, - {1000781750, 174.972400593}, - {1000791750, 174.981316375}, - {1000801750, 174.991444451}, - {1000661760, 175.963918}, - {1000671760, 175.957713}, - {1000681760, 175.94994}, - {1000691760, 175.946997707}, - {1000701760, 175.942574706}, - {1000711760, 175.942691711}, - {1000721760, 175.941409797}, - {1000731760, 175.944857}, - {1000741760, 175.945634}, - {1000751760, 175.951623}, - {1000761760, 175.954770315}, - {1000771760, 175.963626261}, - {1000781760, 175.968938162}, - {1000791760, 175.980116925}, - {1000801760, 175.98734867}, - {1000811760, 176.000627731}, - {1000671770, 176.961052}, - {1000681770, 176.95399}, - {1000691770, 176.948932}, - {1000701770, 176.945263846}, - {1000711770, 176.94376357}, - {1000721770, 176.943230187}, - {1000731770, 176.94448194}, - {1000741770, 176.946643}, - {1000751770, 176.950328}, - {1000761770, 176.954957902}, - {1000771770, 176.9613015}, - {1000781770, 176.968469541}, - {1000791770, 176.976869701}, - {1000801770, 176.98628459}, - {1000811770, 176.996414252}, - {1000671780, 177.965507}, - {1000681780, 177.956779}, - {1000691780, 177.952506}, - {1000701780, 177.9466694}, - {1000711780, 177.945960065}, - {1000721780, 177.943708322}, - {1000731780, 177.94568}, - {1000741780, 177.945885791}, - {1000751780, 177.950989}, - {1000761780, 177.953253334}, - {1000771780, 177.961079395}, - {1000781780, 177.965649288}, - {1000791780, 177.976056714}, - {1000801780, 177.982484756}, - {1000811780, 177.995047}, - {1000821780, 178.003836171}, - {1000681790, 178.961267}, - {1000691790, 178.955018}, - {1000701790, 178.94993}, - {1000711790, 178.947332985}, - {1000721790, 178.945825705}, - {1000731790, 178.94593905}, - {1000741790, 178.947079378}, - {1000751790, 178.949989686}, - {1000761790, 178.953815985}, - {1000771790, 178.959117594}, - {1000781790, 178.965358742}, - {1000791790, 178.973173666}, - {1000801790, 178.981821759}, - {1000811790, 178.991122185}, - {1000821790, 179.002202492}, - {1000681800, 179.96438}, - {1000691800, 179.959023}, - {1000701800, 179.951991}, - {1000711800, 179.949890744}, - {1000721800, 179.946559537}, - {1000731800, 179.947467589}, - {1000741800, 179.946713304}, - {1000751800, 179.950791568}, - {1000761800, 179.952381665}, - {1000771800, 179.959229446}, - {1000781800, 179.96303801}, - {1000791800, 179.972489738}, - {1000801800, 179.97826018}, - {1000811800, 179.98991895}, - {1000821800, 179.997916177}, - {1000691810, 180.961954}, - {1000701810, 180.95589}, - {1000711810, 180.951908}, - {1000721810, 180.949110834}, - {1000731810, 180.947998528}, - {1000741810, 180.948218733}, - {1000751810, 180.950061507}, - {1000761810, 180.953247188}, - {1000771810, 180.957634691}, - {1000781810, 180.963089946}, - {1000791810, 180.970079102}, - {1000801810, 180.977819368}, - {1000811810, 180.986259978}, - {1000821810, 180.9966606}, - {1000691820, 181.966194}, - {1000701820, 181.958239}, - {1000711820, 181.955158}, - {1000721820, 181.950563684}, - {1000731820, 181.950154612}, - {1000741820, 181.948205636}, - {1000751820, 181.95121156}, - {1000761820, 181.952110154}, - {1000771820, 181.958076296}, - {1000781820, 181.961171605}, - {1000791820, 181.969614433}, - {1000801820, 181.974689173}, - {1000811820, 181.985692649}, - {1000821820, 181.992673537}, - {1000701830, 182.962426}, - {1000711830, 182.957363}, - {1000721830, 182.953533203}, - {1000731830, 182.95137538}, - {1000741830, 182.950224416}, - {1000751830, 182.950821306}, - {1000761830, 182.953125028}, - {1000771830, 182.956841231}, - {1000781830, 182.961595895}, - {1000791830, 182.967588106}, - {1000801830, 182.974444652}, - {1000811830, 182.982192843}, - {1000821830, 182.991862527}, - {1000701840, 183.965002}, - {1000711840, 183.96103}, - {1000721840, 183.955448507}, - {1000731840, 183.954009958}, - {1000741840, 183.95093318}, - {1000751840, 183.952528073}, - {1000761840, 183.952492919}, - {1000771840, 183.957476}, - {1000781840, 183.959921929}, - {1000791840, 183.967451523}, - {1000801840, 183.971717709}, - {1000811840, 183.981874973}, - {1000821840, 183.988135634}, - {1000831840, 184.001347}, - {1000701850, 184.969425}, - {1000711850, 184.963542}, - {1000721850, 184.958862}, - {1000731850, 184.955561317}, - {1000741850, 184.953421206}, - {1000751850, 184.95295832}, - {1000761850, 184.954045969}, - {1000771850, 184.956698}, - {1000781850, 184.960613659}, - {1000791850, 184.965798871}, - {1000801850, 184.971890696}, - {1000811850, 184.978789189}, - {1000821850, 184.98761}, - {1000831850, 184.9976}, - {1000711860, 185.96745}, - {1000721860, 185.960897}, - {1000731860, 185.958553036}, - {1000741860, 185.95436514}, - {1000751860, 185.954989172}, - {1000761860, 185.953837569}, - {1000771860, 185.957946754}, - {1000781860, 185.959350845}, - {1000791860, 185.965952703}, - {1000801860, 185.969362061}, - {1000811860, 185.978654787}, - {1000821860, 185.984239409}, - {1000831860, 185.996623169}, - {1000841860, 186.004403174}, - {1000711870, 186.970188}, - {1000721870, 186.964573}, - {1000731870, 186.960391}, - {1000741870, 186.957161249}, - {1000751870, 186.955752217}, - {1000761870, 186.955749569}, - {1000771870, 186.957542}, - {1000781870, 186.960616646}, - {1000791870, 186.964542147}, - {1000801870, 186.96981354}, - {1000811870, 186.97590474}, - {1000821870, 186.983910842}, - {1000831870, 186.993147272}, - {1000841870, 187.003031482}, - {1000711880, 187.974428}, - {1000721880, 187.966903}, - {1000731880, 187.963596}, - {1000741880, 187.958488325}, - {1000751880, 187.958113658}, - {1000761880, 187.955837292}, - {1000771880, 187.958834999}, - {1000781880, 187.959397521}, - {1000791880, 187.965247966}, - {1000801880, 187.967580738}, - {1000811880, 187.976020886}, - {1000821880, 187.980879079}, - {1000831880, 187.992276064}, - {1000841880, 187.999415586}, - {1000721890, 188.970853}, - {1000731890, 188.96569}, - {1000741890, 188.961557}, - {1000751890, 188.959227764}, - {1000761890, 188.958145949}, - {1000771890, 188.958722602}, - {1000781890, 188.960848485}, - {1000791890, 188.963948286}, - {1000801890, 188.968194776}, - {1000811890, 188.973573525}, - {1000821890, 188.980843658}, - {1000831890, 188.989195139}, - {1000841890, 188.998473425}, - {1000721900, 189.973376}, - {1000731900, 189.969168}, - {1000741900, 189.963103542}, - {1000751900, 189.961800064}, - {1000761900, 189.958445442}, - {1000771900, 189.960543374}, - {1000781900, 189.959949823}, - {1000791900, 189.964751746}, - {1000801900, 189.96632225}, - {1000811900, 189.973841771}, - {1000821900, 189.978081872}, - {1000831900, 189.988624828}, - {1000841900, 189.995101731}, - {1000731910, 190.97153}, - {1000741910, 190.966531}, - {1000751910, 190.963123322}, - {1000761910, 190.960928105}, - {1000771910, 190.960591455}, - {1000781910, 190.961676261}, - {1000791910, 190.963716452}, - {1000801910, 190.967158301}, - {1000811910, 190.971784093}, - {1000821910, 190.978216455}, - {1000831910, 190.985786972}, - {1000841910, 190.994558494}, - {1000851910, 191.004148081}, - {1000731920, 191.975201}, - {1000741920, 191.968202}, - {1000751920, 191.966088}, - {1000761920, 191.961478765}, - {1000771920, 191.962602414}, - {1000781920, 191.961042667}, - {1000791920, 191.964817615}, - {1000801920, 191.965634263}, - {1000811920, 191.972225}, - {1000821920, 191.975789598}, - {1000831920, 191.985470077}, - {1000841920, 191.991340274}, - {1000851920, 192.003140912}, - {1000731930, 192.97766}, - {1000741930, 192.971884}, - {1000751930, 192.967545}, - {1000761930, 192.964149637}, - {1000771930, 192.962923753}, - {1000781930, 192.962984546}, - {1000791930, 192.964138442}, - {1000801930, 192.966653395}, - {1000811930, 192.970501994}, - {1000821930, 192.976135914}, - {1000831930, 192.98294722}, - {1000841930, 192.991062421}, - {1000851930, 192.999927725}, - {1000861930, 193.009707973}, - {1000731940, 193.98161}, - {1000741940, 193.973795}, - {1000751940, 193.970735}, - {1000761940, 193.965179407}, - {1000771940, 193.965075703}, - {1000781940, 193.962683498}, - {1000791940, 193.965419051}, - {1000801940, 193.965449108}, - {1000811940, 193.971081408}, - {1000821940, 193.974011788}, - {1000831940, 193.982798581}, - {1000841940, 193.988186058}, - {1000851940, 193.999230816}, - {1000861940, 194.006145636}, - {1000741950, 194.977735}, - {1000751950, 194.97256}, - {1000761950, 194.968318}, - {1000771950, 194.965976898}, - {1000781950, 194.964794325}, - {1000791950, 194.965037823}, - {1000801950, 194.966705809}, - {1000811950, 194.969774052}, - {1000821950, 194.974516167}, - {1000831950, 194.980648759}, - {1000841950, 194.988065781}, - {1000851950, 194.99627448}, - {1000861950, 195.005421703}, - {1000741960, 195.979882}, - {1000751960, 195.975996}, - {1000761960, 195.969643261}, - {1000771960, 195.968399669}, - {1000781960, 195.964954648}, - {1000791960, 195.966571213}, - {1000801960, 195.965833445}, - {1000811960, 195.970481189}, - {1000821960, 195.972787552}, - {1000831960, 195.980666509}, - {1000841960, 195.985540722}, - {1000851960, 195.995799034}, - {1000861960, 196.002120431}, - {1000741970, 196.984036}, - {1000751970, 196.978153}, - {1000761970, 196.973076}, - {1000771970, 196.969657217}, - {1000781970, 196.96734303}, - {1000791970, 196.966570103}, - {1000801970, 196.967213715}, - {1000811970, 196.969560492}, - {1000821970, 196.973434737}, - {1000831970, 196.978864927}, - {1000841970, 196.985621939}, - {1000851970, 196.993177353}, - {1000861970, 197.001621446}, - {1000871970, 197.011008086}, - {1000751980, 197.98176}, - {1000761980, 197.974664}, - {1000771980, 197.972399}, - {1000781980, 197.967896718}, - {1000791980, 197.968243714}, - {1000801980, 197.966769177}, - {1000811980, 197.970446669}, - {1000821980, 197.97201545}, - {1000831980, 197.979201316}, - {1000841980, 197.983388753}, - {1000851980, 197.992797864}, - {1000861980, 197.998679197}, - {1000871980, 198.010282081}, - {1000751990, 198.984187}, - {1000761990, 198.978239}, - {1000771990, 198.973807097}, - {1000781990, 198.970597022}, - {1000791990, 198.968766573}, - {1000801990, 198.968280994}, - {1000811990, 198.969877}, - {1000821990, 198.97291262}, - {1000831990, 198.977672841}, - {1000841990, 198.983640445}, - {1000851990, 198.990527715}, - {1000861990, 198.998325436}, - {1000871990, 199.007269384}, - {1000762000, 199.980086}, - {1000772000, 199.976844}, - {1000782000, 199.971444609}, - {1000792000, 199.970756558}, - {1000802000, 199.968326941}, - {1000812000, 199.970963608}, - {1000822000, 199.971818546}, - {1000832000, 199.97813129}, - {1000842000, 199.981812355}, - {1000852000, 199.990351099}, - {1000862000, 199.995705335}, - {1000872000, 200.006584666}, - {1000762010, 200.984069}, - {1000772010, 200.978701}, - {1000782010, 200.974513305}, - {1000792010, 200.971657678}, - {1000802010, 200.970303054}, - {1000812010, 200.970820235}, - {1000822010, 200.972870431}, - {1000832010, 200.976995017}, - {1000842010, 200.982263799}, - {1000852010, 200.988417058}, - {1000862010, 200.995590511}, - {1000872010, 201.003852491}, - {1000882010, 201.012814699}, - {1000762020, 201.986548}, - {1000772020, 201.982136}, - {1000782020, 201.975639}, - {1000792020, 201.973856}, - {1000802020, 201.970643604}, - {1000812020, 201.972108874}, - {1000822020, 201.972151613}, - {1000832020, 201.977723042}, - {1000842020, 201.980738934}, - {1000852020, 201.988625686}, - {1000862020, 201.993263982}, - {1000872020, 202.003329637}, - {1000882020, 202.009742305}, - {1000762030, 202.992195}, - {1000772030, 202.984573}, - {1000782030, 202.979055}, - {1000792030, 202.975154492}, - {1000802030, 202.972872396}, - {1000812030, 202.972344098}, - {1000822030, 202.973390617}, - {1000832030, 202.976892077}, - {1000842030, 202.981416072}, - {1000852030, 202.986942904}, - {1000862030, 202.993361155}, - {1000872030, 203.000940867}, - {1000882030, 203.009233907}, - {1000772040, 203.989726}, - {1000782040, 203.981084}, - {1000792040, 203.97811}, - {1000802040, 203.973494037}, - {1000812040, 203.97386342}, - {1000822040, 203.973043506}, - {1000832040, 203.977835687}, - {1000842040, 203.980310078}, - {1000852040, 203.987251393}, - {1000862040, 203.991443729}, - {1000872040, 204.000651972}, - {1000882040, 204.006506855}, - {1000772050, 204.993988}, - {1000782050, 204.986237}, - {1000792050, 204.980064}, - {1000802050, 204.976073151}, - {1000812050, 204.974427318}, - {1000822050, 204.974481682}, - {1000832050, 204.977385182}, - {1000842050, 204.981190006}, - {1000852050, 204.986060546}, - {1000862050, 204.991723228}, - {1000872050, 204.998593854}, - {1000882050, 205.006230692}, - {1000892050, 205.015144152}, - {1000782060, 205.99008}, - {1000792060, 205.984766}, - {1000802060, 205.977513837}, - {1000812060, 205.976110108}, - {1000822060, 205.97446521}, - {1000832060, 205.978498843}, - {1000842060, 205.980473662}, - {1000852060, 205.986645768}, - {1000862060, 205.990195409}, - {1000872060, 205.998661441}, - {1000882060, 206.003827842}, - {1000892060, 206.014476477}, - {1000782070, 206.995556}, - {1000792070, 206.988577}, - {1000802070, 206.9823}, - {1000812070, 206.977418605}, - {1000822070, 206.975896821}, - {1000832070, 206.978470551}, - {1000842070, 206.981593334}, - {1000852070, 206.985799715}, - {1000862070, 206.990730224}, - {1000872070, 206.99694145}, - {1000882070, 207.00377242}, - {1000892070, 207.011965967}, - {1000782080, 207.999463}, - {1000792080, 207.993655}, - {1000802080, 207.985759}, - {1000812080, 207.982018006}, - {1000822080, 207.976652005}, - {1000832080, 207.97974206}, - {1000842080, 207.981246035}, - {1000852080, 207.986613011}, - {1000862080, 207.989634513}, - {1000872080, 207.997139082}, - {1000882080, 208.001855012}, - {1000892080, 208.011552251}, - {1000902080, 208.017915348}, - {1000792090, 208.997606}, - {1000802090, 208.990757}, - {1000812090, 208.985351713}, - {1000822090, 208.981089978}, - {1000832090, 208.980398599}, - {1000842090, 208.982430361}, - {1000852090, 208.986168701}, - {1000862090, 208.990401389}, - {1000872090, 208.995939701}, - {1000882090, 209.001994902}, - {1000892090, 209.009495375}, - {1000902090, 209.017601}, - {1000792100, 210.002877}, - {1000802100, 209.99431}, - {1000812100, 209.990072942}, - {1000822100, 209.984188381}, - {1000832100, 209.984120237}, - {1000842100, 209.982873686}, - {1000852100, 209.987147423}, - {1000862100, 209.989688862}, - {1000872100, 209.996410596}, - {1000882100, 210.000475406}, - {1000892100, 210.009408625}, - {1000902100, 210.015093515}, - {1000802110, 210.999581}, - {1000812110, 210.993475}, - {1000822110, 210.988735288}, - {1000832110, 210.987268715}, - {1000842110, 210.986653171}, - {1000852110, 210.987496226}, - {1000862110, 210.990600767}, - {1000872110, 210.995555189}, - {1000882110, 211.000893049}, - {1000892110, 211.007668846}, - {1000902110, 211.014896923}, - {1000912110, 211.023674036}, - {1000802120, 212.003242}, - {1000812120, 211.998335}, - {1000822120, 211.991895891}, - {1000832120, 211.99128503}, - {1000842120, 211.988867982}, - {1000852120, 211.990737301}, - {1000862120, 211.990703946}, - {1000872120, 211.99622542}, - {1000882120, 211.999786619}, - {1000892120, 212.007836442}, - {1000902120, 212.01300157}, - {1000912120, 212.023184819}, - {1000802130, 213.008803}, - {1000812130, 213.001915}, - {1000822130, 212.996560796}, - {1000832130, 212.99438357}, - {1000842130, 212.992857154}, - {1000852130, 212.992936593}, - {1000862130, 212.993885147}, - {1000872130, 212.99618441}, - {1000882130, 213.000370971}, - {1000892130, 213.006592665}, - {1000902130, 213.01301147}, - {1000912130, 213.021099644}, - {1000802140, 214.012636}, - {1000812140, 214.00694}, - {1000822140, 213.999803521}, - {1000832140, 213.998710909}, - {1000842140, 213.995201287}, - {1000852140, 213.996372331}, - {1000862140, 213.99536265}, - {1000872140, 213.998971193}, - {1000882140, 214.00009956}, - {1000892140, 214.0069064}, - {1000902140, 214.01148148}, - {1000912140, 214.020891055}, - {1000802150, 215.018368}, - {1000812150, 215.010768}, - {1000822150, 215.004661591}, - {1000832150, 215.001749095}, - {1000842150, 214.999418385}, - {1000852150, 214.998651002}, - {1000862150, 214.998745037}, - {1000872150, 215.000341534}, - {1000882150, 215.002718208}, - {1000892150, 215.006474061}, - {1000902150, 215.01172464}, - {1000912150, 215.019113955}, - {1000922150, 215.026719774}, - {1000802160, 216.022459}, - {1000812160, 216.015964}, - {1000822160, 216.008062}, - {1000832160, 216.006305985}, - {1000842160, 216.001913416}, - {1000852160, 216.002422643}, - {1000862160, 216.000271942}, - {1000872160, 216.003189523}, - {1000882160, 216.003533534}, - {1000892160, 216.008749101}, - {1000902160, 216.011055933}, - {1000912160, 216.019134633}, - {1000922160, 216.024762829}, - {1000812170, 217.020032}, - {1000822170, 217.013162}, - {1000832170, 217.009372}, - {1000842170, 217.006316145}, - {1000852170, 217.004717794}, - {1000862170, 217.003927632}, - {1000872170, 217.00463198}, - {1000882170, 217.006322676}, - {1000892170, 217.009342325}, - {1000902170, 217.013103443}, - {1000912170, 217.018309024}, - {1000922170, 217.02466}, - {1000812180, 218.025454}, - {1000822180, 218.016779}, - {1000832180, 218.014188}, - {1000842180, 218.008971234}, - {1000852180, 218.008695941}, - {1000862180, 218.005601123}, - {1000872180, 218.00757862}, - {1000882180, 218.007134297}, - {1000892180, 218.01164886}, - {1000902180, 218.013276248}, - {1000912180, 218.020021133}, - {1000922180, 218.023504877}, - {1000822190, 219.022136}, - {1000832190, 219.01752}, - {1000842190, 219.013614}, - {1000852190, 219.011160587}, - {1000862190, 219.009478683}, - {1000872190, 219.009250664}, - {1000882190, 219.010084715}, - {1000892190, 219.012420425}, - {1000902190, 219.015526432}, - {1000912190, 219.019949909}, - {1000922190, 219.025009233}, - {1000932190, 219.031601865}, - {1000822200, 220.025905}, - {1000832200, 220.022501}, - {1000842200, 220.016386}, - {1000852200, 220.015433}, - {1000862200, 220.011392443}, - {1000872200, 220.012326789}, - {1000882200, 220.011027542}, - {1000892200, 220.014754527}, - {1000902200, 220.015769866}, - {1000912200, 220.021769753}, - {1000922200, 220.024706}, - {1000932200, 220.03271628}, - {1000832210, 221.02598}, - {1000842210, 221.021228}, - {1000852210, 221.018017}, - {1000862210, 221.015535637}, - {1000872210, 221.014253714}, - {1000882210, 221.013917293}, - {1000892210, 221.015599721}, - {1000902210, 221.018185757}, - {1000912210, 221.021873393}, - {1000922210, 221.026323297}, - {1000932210, 221.03211}, - {1000942210, 221.038572}, - {1000832220, 222.031079}, - {1000842220, 222.02414}, - {1000852220, 222.022494}, - {1000862220, 222.017576017}, - {1000872220, 222.017582615}, - {1000882220, 222.015373371}, - {1000892220, 222.017844232}, - {1000902220, 222.01846822}, - {1000912220, 222.023687064}, - {1000922220, 222.026057957}, - {1000932220, 222.033574706}, - {1000942220, 222.037638}, - {1000832230, 223.034611}, - {1000842230, 223.02907}, - {1000852230, 223.025151}, - {1000862230, 223.021889283}, - {1000872230, 223.019734241}, - {1000882230, 223.018500648}, - {1000892230, 223.019135982}, - {1000902230, 223.020811083}, - {1000912230, 223.023980414}, - {1000922230, 223.027960754}, - {1000932230, 223.03291334}, - {1000942230, 223.038777}, - {1000952230, 223.04584}, - {1000832240, 224.039796}, - {1000842240, 224.03211}, - {1000852240, 224.029749}, - {1000862240, 224.024095803}, - {1000872240, 224.023348096}, - {1000882240, 224.020210361}, - {1000892240, 224.021722249}, - {1000902240, 224.021466137}, - {1000912240, 224.025617286}, - {1000922240, 224.027635913}, - {1000932240, 224.03438803}, - {1000942240, 224.037875}, - {1000952240, 224.046442}, - {1000842250, 225.037123}, - {1000852250, 225.032528}, - {1000862250, 225.028485572}, - {1000872250, 225.025572466}, - {1000882250, 225.023610502}, - {1000892250, 225.023228601}, - {1000902250, 225.023950975}, - {1000912250, 225.026147927}, - {1000922250, 225.02938505}, - {1000932250, 225.033943422}, - {1000942250, 225.03897}, - {1000952250, 225.045508}, - {1000842260, 226.04031}, - {1000852260, 226.037209}, - {1000862260, 226.03086138}, - {1000872260, 226.029544512}, - {1000882260, 226.025408186}, - {1000892260, 226.026096999}, - {1000902260, 226.024903699}, - {1000912260, 226.027948217}, - {1000922260, 226.029338669}, - {1000932260, 226.035230364}, - {1000942260, 226.03825}, - {1000952260, 226.04613}, - {1000842270, 227.04539}, - {1000852270, 227.040183}, - {1000862270, 227.035304393}, - {1000872270, 227.031865413}, - {1000882270, 227.029176205}, - {1000892270, 227.027750594}, - {1000902270, 227.027702546}, - {1000912270, 227.028803586}, - {1000922270, 227.031181124}, - {1000932270, 227.034975012}, - {1000942270, 227.039474}, - {1000952270, 227.045282}, - {1000852280, 228.04496}, - {1000862280, 228.037835415}, - {1000872280, 228.035839433}, - {1000882280, 228.031068574}, - {1000892280, 228.031019685}, - {1000902280, 228.028739741}, - {1000912280, 228.031050758}, - {1000922280, 228.031368959}, - {1000932280, 228.036313}, - {1000942280, 228.038763325}, - {1000952280, 228.046001}, - {1000852290, 229.048191}, - {1000862290, 229.042257272}, - {1000872290, 229.038291443}, - {1000882290, 229.034956703}, - {1000892290, 229.032947}, - {1000902290, 229.031761357}, - {1000912290, 229.032095585}, - {1000922290, 229.033505976}, - {1000932290, 229.036287269}, - {1000942290, 229.040145099}, - {1000952290, 229.045282534}, - {1000862300, 230.045271}, - {1000872300, 230.042390787}, - {1000882300, 230.037054776}, - {1000892300, 230.036327}, - {1000902300, 230.033132267}, - {1000912300, 230.034539717}, - {1000922300, 230.033940114}, - {1000932300, 230.03782806}, - {1000942300, 230.039648313}, - {1000952300, 230.046025}, - {1000862310, 231.049973}, - {1000872310, 231.045175353}, - {1000882310, 231.041027085}, - {1000892310, 231.038393}, - {1000902310, 231.036302764}, - {1000912310, 231.0358825}, - {1000922310, 231.03629218}, - {1000932310, 231.038243598}, - {1000942310, 231.041125946}, - {1000952310, 231.045529}, - {1000962310, 231.050746}, - {1000872320, 232.049461219}, - {1000882320, 232.043475267}, - {1000892320, 232.042034}, - {1000902320, 232.038053606}, - {1000912320, 232.038590205}, - {1000922320, 232.037154765}, - {1000932320, 232.040107}, - {1000942320, 232.041182133}, - {1000952320, 232.046613}, - {1000962320, 232.04974}, - {1000872330, 233.052517833}, - {1000882330, 233.04759457}, - {1000892330, 233.044346}, - {1000902330, 233.041580126}, - {1000912330, 233.040246535}, - {1000922330, 233.039634294}, - {1000932330, 233.040739421}, - {1000942330, 233.042997411}, - {1000952330, 233.046468}, - {1000962330, 233.050771485}, - {1000972330, 233.056652}, - {1000882340, 234.0503821}, - {1000892340, 234.048139}, - {1000902340, 234.043599801}, - {1000912340, 234.043305555}, - {1000922340, 234.040950296}, - {1000932340, 234.042893245}, - {1000942340, 234.043317489}, - {1000952340, 234.047731}, - {1000962340, 234.050158568}, - {1000972340, 234.057322}, - {1000882350, 235.05489}, - {1000892350, 235.05084}, - {1000902350, 235.047255}, - {1000912350, 235.045399}, - {1000922350, 235.043928117}, - {1000932350, 235.044061518}, - {1000942350, 235.045284609}, - {1000952350, 235.047906478}, - {1000962350, 235.051545}, - {1000972350, 235.056651}, - {1000892360, 236.054988}, - {1000902360, 236.049657}, - {1000912360, 236.048668}, - {1000922360, 236.04556613}, - {1000932360, 236.046568296}, - {1000942360, 236.046056661}, - {1000952360, 236.049427}, - {1000962360, 236.051372112}, - {1000972360, 236.057479}, - {1000892370, 237.057993}, - {1000902370, 237.053629}, - {1000912370, 237.051023}, - {1000922370, 237.048728309}, - {1000932370, 237.04817164}, - {1000942370, 237.048407888}, - {1000952370, 237.049995}, - {1000962370, 237.052868988}, - {1000972370, 237.057123}, - {1000982370, 237.062199272}, - {1000902380, 238.056388}, - {1000912380, 238.054637}, - {1000922380, 238.050786936}, - {1000932380, 238.050944603}, - {1000942380, 238.049558175}, - {1000952380, 238.051982531}, - {1000962380, 238.053081606}, - {1000972380, 238.058204}, - {1000982380, 238.06149}, - {1000902390, 239.060655}, - {1000912390, 239.05726}, - {1000922390, 239.054291989}, - {1000932390, 239.052937538}, - {1000942390, 239.052161596}, - {1000952390, 239.053022729}, - {1000962390, 239.054908519}, - {1000972390, 239.058239}, - {1000982390, 239.062482}, - {1000992390, 239.06831}, - {1000912400, 240.061203}, - {1000922400, 240.056592411}, - {1000932400, 240.056163778}, - {1000942400, 240.05381174}, - {1000952400, 240.055298374}, - {1000962400, 240.055528233}, - {1000972400, 240.059758}, - {1000982400, 240.062253447}, - {1000992400, 240.068949}, - {1000912410, 241.064134}, - {1000922410, 241.06033}, - {1000932410, 241.058309671}, - {1000942410, 241.056849651}, - {1000952410, 241.056827343}, - {1000962410, 241.057651218}, - {1000972410, 241.060098}, - {1000982410, 241.06369}, - {1000992410, 241.068592}, - {1001002410, 241.074311}, - {1000922420, 242.062931}, - {1000932420, 242.061639548}, - {1000942420, 242.058740979}, - {1000952420, 242.059547358}, - {1000962420, 242.058834187}, - {1000972420, 242.061999}, - {1000982420, 242.063754544}, - {1000992420, 242.069567}, - {1001002420, 242.07343}, - {1000922430, 243.067075}, - {1000932430, 243.064204}, - {1000942430, 243.062002068}, - {1000952430, 243.061379889}, - {1000962430, 243.061387329}, - {1000972430, 243.063005905}, - {1000982430, 243.065475}, - {1000992430, 243.069508}, - {1001002430, 243.074414}, - {1000932440, 244.067891}, - {1000942440, 244.064204401}, - {1000952440, 244.064282892}, - {1000962440, 244.062750622}, - {1000972440, 244.065178969}, - {1000982440, 244.065999447}, - {1000992440, 244.070881}, - {1001002440, 244.074036}, - {1001012440, 244.081157}, - {1000932450, 245.070693}, - {1000942450, 245.067824554}, - {1000952450, 245.066452827}, - {1000962450, 245.065491047}, - {1000972450, 245.066359814}, - {1000982450, 245.068046755}, - {1000992450, 245.071192}, - {1001002450, 245.075354}, - {1001012450, 245.080864}, - {1000942460, 246.070204172}, - {1000952460, 246.069774}, - {1000962460, 246.067222016}, - {1000972460, 246.0686713}, - {1000982460, 246.068803685}, - {1000992460, 246.072806474}, - {1001002460, 246.075353334}, - {1001012460, 246.081713}, - {1000942470, 247.0743}, - {1000952470, 247.072092}, - {1000962470, 247.070352678}, - {1000972470, 247.070305889}, - {1000982470, 247.070971348}, - {1000992470, 247.073621929}, - {1001002470, 247.076944}, - {1001012470, 247.08152}, - {1000952480, 248.075752}, - {1000962480, 248.072349086}, - {1000972480, 248.073141689}, - {1000982480, 248.072182905}, - {1000992480, 248.075469}, - {1001002480, 248.077185451}, - {1001012480, 248.082607}, - {1001022480, 248.086623}, - {1000952490, 249.07848}, - {1000962490, 249.075953992}, - {1000972490, 249.074983118}, - {1000982490, 249.074850428}, - {1000992490, 249.076409}, - {1001002490, 249.078926042}, - {1001012490, 249.082857155}, - {1001022490, 249.087802}, - {1000962500, 250.078357541}, - {1000972500, 250.078317195}, - {1000982500, 250.076404494}, - {1000992500, 250.078611}, - {1001002500, 250.079519765}, - {1001012500, 250.084164934}, - {1001022500, 250.087565}, - {1000962510, 251.082284988}, - {1000972510, 251.080760555}, - {1000982510, 251.079587171}, - {1000992510, 251.079991431}, - {1001002510, 251.08154513}, - {1001012510, 251.084774287}, - {1001022510, 251.088942}, - {1001032510, 251.094289}, - {1000962520, 252.08487}, - {1000972520, 252.08431}, - {1000982520, 252.081626507}, - {1000992520, 252.082979173}, - {1001002520, 252.082466019}, - {1001012520, 252.086385}, - {1001022520, 252.08896607}, - {1001032520, 252.095048}, - {1000972530, 253.08688}, - {1000982530, 253.085133723}, - {1000992530, 253.084821241}, - {1001002530, 253.085180945}, - {1001012530, 253.087143}, - {1001022530, 253.09056278}, - {1001032530, 253.09503385}, - {1001042530, 253.100528}, - {1000972540, 254.0906}, - {1000982540, 254.087323575}, - {1000992540, 254.088024337}, - {1001002540, 254.086852424}, - {1001012540, 254.08959}, - {1001022540, 254.090954211}, - {1001032540, 254.096238813}, - {1001042540, 254.100055}, - {1000982550, 255.091046}, - {1000992550, 255.090273504}, - {1001002550, 255.089963495}, - {1001012550, 255.091081702}, - {1001022550, 255.093196439}, - {1001032550, 255.096562399}, - {1001042550, 255.101267}, - {1001052550, 255.106919}, - {1000982560, 256.093442}, - {1000992560, 256.093597}, - {1001002560, 256.091771699}, - {1001012560, 256.093888}, - {1001022560, 256.094281912}, - {1001032560, 256.098494024}, - {1001042560, 256.101151464}, - {1001052560, 256.107674}, - {1000992570, 257.095979}, - {1001002570, 257.095105419}, - {1001012570, 257.095537343}, - {1001022570, 257.096884203}, - {1001032570, 257.09948}, - {1001042570, 257.102916796}, - {1001052570, 257.107520042}, - {1000992580, 258.09952}, - {1001002580, 258.097077}, - {1001012580, 258.098433634}, - {1001022580, 258.098205}, - {1001032580, 258.101753}, - {1001042580, 258.103429895}, - {1001052580, 258.108972995}, - {1001062580, 258.11304}, - {1001002590, 259.100596}, - {1001012590, 259.100445}, - {1001022590, 259.100998364}, - {1001032590, 259.1029}, - {1001042590, 259.105601}, - {1001052590, 259.109491859}, - {1001062590, 259.114353}, - {1001002600, 260.102809}, - {1001012600, 260.10365}, - {1001022600, 260.102641}, - {1001032600, 260.105504}, - {1001042600, 260.10644}, - {1001052600, 260.111297}, - {1001062600, 260.114383435}, - {1001072600, 260.121443}, - {1001012610, 261.105828}, - {1001022610, 261.105696}, - {1001032610, 261.106879}, - {1001042610, 261.108769591}, - {1001052610, 261.111979}, - {1001062610, 261.115948135}, - {1001072610, 261.121395733}, - {1001012620, 262.109144}, - {1001022620, 262.107463}, - {1001032620, 262.109615}, - {1001042620, 262.109923}, - {1001052620, 262.114067}, - {1001062620, 262.116338978}, - {1001072620, 262.122654688}, - {1001022630, 263.110714}, - {1001032630, 263.111293}, - {1001042630, 263.112461}, - {1001052630, 263.114987}, - {1001062630, 263.118299}, - {1001072630, 263.122916}, - {1001082630, 263.128479}, - {1001022640, 264.112734}, - {1001032640, 264.114198}, - {1001042640, 264.113876}, - {1001052640, 264.117297}, - {1001062640, 264.11893}, - {1001072640, 264.124486}, - {1001082640, 264.12835633}, - {1001032650, 265.116193}, - {1001042650, 265.116683}, - {1001052650, 265.1185}, - {1001062650, 265.121089}, - {1001072650, 265.124955}, - {1001082650, 265.129791744}, - {1001092650, 265.135937}, - {1001032660, 266.119874}, - {1001042660, 266.118236}, - {1001052660, 266.121032}, - {1001062660, 266.121973}, - {1001072660, 266.12679}, - {1001082660, 266.130048783}, - {1001092660, 266.137062253}, - {1001042670, 267.121787}, - {1001052670, 267.122399}, - {1001062670, 267.124323}, - {1001072670, 267.127499}, - {1001082670, 267.131678}, - {1001092670, 267.137189}, - {1001102670, 267.143726}, - {1001042680, 268.123968}, - {1001052680, 268.125669}, - {1001062680, 268.125389}, - {1001072680, 268.129584}, - {1001082680, 268.132011}, - {1001092680, 268.138649}, - {1001102680, 268.143477}, - {1001052690, 269.127911}, - {1001062690, 269.128495}, - {1001072690, 269.130411}, - {1001082690, 269.133649}, - {1001092690, 269.138809}, - {1001102690, 269.144750965}, - {1001052700, 270.131399}, - {1001062700, 270.130362}, - {1001072700, 270.133366}, - {1001082700, 270.134313}, - {1001092700, 270.140322}, - {1001102700, 270.14458662}, - {1001062710, 271.133782}, - {1001072710, 271.135115}, - {1001082710, 271.137082}, - {1001092710, 271.140741}, - {1001102710, 271.145951}, - {1001062720, 272.135825}, - {1001072720, 272.138259}, - {1001082720, 272.138492}, - {1001092720, 272.143298}, - {1001102720, 272.146091}, - {1001112720, 272.153273}, - {1001062730, 273.139475}, - {1001072730, 273.140294}, - {1001082730, 273.141458}, - {1001092730, 273.144695}, - {1001102730, 273.148455}, - {1001112730, 273.153393}, - {1001072740, 274.143599}, - {1001082740, 274.143217}, - {1001092740, 274.147343}, - {1001102740, 274.149434}, - {1001112740, 274.155247}, - {1001072750, 275.145766}, - {1001082750, 275.14653}, - {1001092750, 275.148972}, - {1001102750, 275.152085}, - {1001112750, 275.156088}, - {1001072760, 276.149169}, - {1001082760, 276.148348}, - {1001092760, 276.151705}, - {1001102760, 276.153022}, - {1001112760, 276.158226}, - {1001122760, 276.161418}, - {1001072770, 277.151477}, - {1001082770, 277.151772}, - {1001092770, 277.153525}, - {1001102770, 277.155763}, - {1001112770, 277.159322}, - {1001122770, 277.163535}, - {1001072780, 278.154988}, - {1001082780, 278.153753}, - {1001092780, 278.156487}, - {1001102780, 278.157007}, - {1001112780, 278.16159}, - {1001122780, 278.164083}, - {1001132780, 278.170725}, - {1001082790, 279.157274}, - {1001092790, 279.158439}, - {1001102790, 279.159984}, - {1001112790, 279.16288}, - {1001122790, 279.166422}, - {1001132790, 279.171187}, - {1001082800, 280.159335}, - {1001092800, 280.161579}, - {1001102800, 280.161375}, - {1001112800, 280.165204}, - {1001122800, 280.167102}, - {1001132800, 280.173098}, - {1001092810, 281.163608}, - {1001102810, 281.164545}, - {1001112810, 281.166757}, - {1001122810, 281.169563}, - {1001132810, 281.17371}, - {1001092820, 282.166888}, - {1001102820, 282.166174}, - {1001112820, 282.169343}, - {1001122820, 282.170507}, - {1001132820, 282.17577}, - {1001102830, 283.169437}, - {1001112830, 283.171101}, - {1001122830, 283.173202}, - {1001132830, 283.176666}, - {1001102840, 284.171187}, - {1001112840, 284.173882}, - {1001122840, 284.17436}, - {1001132840, 284.178843}, - {1001142840, 284.181192}, - {1001112850, 285.175771}, - {1001122850, 285.177227}, - {1001132850, 285.180106}, - {1001142850, 285.183503}, - {1001112860, 286.178756}, - {1001122860, 286.178691}, - {1001132860, 286.182456}, - {1001142860, 286.184226}, - {1001122870, 287.181826}, - {1001132870, 287.184064}, - {1001142870, 287.18672}, - {1001152870, 287.19082}, - {1001122880, 288.183501}, - {1001132880, 288.186764}, - {1001142880, 288.187781}, - {1001152880, 288.192879}, - {1001132890, 289.188461}, - {1001142890, 289.190517}, - {1001152890, 289.193971}, - {1001162890, 289.198023}, - {1001132900, 290.191429}, - {1001142900, 290.191875}, - {1001152900, 290.196235}, - {1001162900, 290.198635}, - {1001142910, 291.194848}, - {1001152910, 291.197725}, - {1001162910, 291.201014}, - {1001172910, 291.205748}, - {1001152920, 292.200323}, - {1001162920, 292.201969}, - {1001172920, 292.207861}, - {1001162930, 293.204583}, - {1001172930, 293.208727}, - {1001182930, 293.213423}, - {1001172940, 294.21084}, - {1001182940, 294.213979}, - {1001182950, 295.216178}, -}; - -} // namespace openmc diff --git a/src/bank.cpp b/src/bank.cpp index 5b12b48fd..8d00d5440 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -1,14 +1,11 @@ #include "openmc/bank.h" #include "openmc/capi.h" #include "openmc/error.h" -#include "openmc/ifp.h" #include "openmc/message_passing.h" #include "openmc/simulation.h" #include "openmc/vector.h" #include -#include -#include namespace openmc { @@ -22,8 +19,6 @@ vector source_bank; SharedArray surf_source_bank; -SharedArray collision_track_bank; - // The fission bank is allocated as a SharedArray, rather than a vector, as it // will be shared by all threads in the simulation. It will be allocated to a // fixed maximum capacity in the init_fission_bank() function. Then, Elements @@ -31,26 +26,11 @@ SharedArray collision_track_bank; // function. SharedArray fission_bank; -vector> ifp_source_delayed_group_bank; - -vector> ifp_source_lifetime_bank; - -vector> ifp_fission_delayed_group_bank; - -vector> ifp_fission_lifetime_bank; - // Each entry in this vector corresponds to the number of progeny produced // this generation for the particle located at that index. This vector is // used to efficiently sort the fission bank after each iteration. vector progeny_per_particle; -// When shared secondary bank mode is enabled, secondaries produced during -// transport are collected in the write bank. When a secondary generation is -// complete, write is moved to read for transport, and a new empty write bank -// is created. This repeats until no secondaries remain. -SharedArray shared_secondary_bank_read; -SharedArray shared_secondary_bank_write; - } // namespace simulation //============================================================================== @@ -61,15 +41,8 @@ void free_memory_bank() { simulation::source_bank.clear(); simulation::surf_source_bank.clear(); - simulation::collision_track_bank.clear(); simulation::fission_bank.clear(); simulation::progeny_per_particle.clear(); - simulation::ifp_source_delayed_group_bank.clear(); - simulation::ifp_source_lifetime_bank.clear(); - simulation::ifp_fission_delayed_group_bank.clear(); - simulation::ifp_fission_lifetime_bank.clear(); - simulation::shared_secondary_bank_read.clear(); - simulation::shared_secondary_bank_write.clear(); } void init_fission_bank(int64_t max) @@ -78,13 +51,13 @@ void init_fission_bank(int64_t max) simulation::progeny_per_particle.resize(simulation::work_per_rank); } -// Performs an O(n) sort on a fission or secondary bank, by leveraging +// Performs an O(n) sort on the fission bank, by leveraging // the parent_id and progeny_id fields of banked particles. See the following // paper for more details: // "Reproducibility and Monte Carlo Eigenvalue Calculations," F.B. Brown and // T.M. Sutton, 1992 ANS Annual Meeting, Transactions of the American Nuclear // Society, Volume 65, Page 235. -void sort_bank(SharedArray& bank, bool is_fission_bank) +void sort_fission_bank() { // Ensure we don't read off the end of the array if we ran with 0 particles if (simulation::progeny_per_particle.size() == 0) { @@ -93,211 +66,47 @@ void sort_bank(SharedArray& bank, bool is_fission_bank) // Perform exclusive scan summation to determine starting indices in fission // bank for each parent particle id - std::exclusive_scan(simulation::progeny_per_particle.begin(), - simulation::progeny_per_particle.end(), - simulation::progeny_per_particle.begin(), 0); + int64_t tmp = simulation::progeny_per_particle[0]; + simulation::progeny_per_particle[0] = 0; + for (int64_t i = 1; i < simulation::progeny_per_particle.size(); i++) { + int64_t value = simulation::progeny_per_particle[i - 1] + tmp; + tmp = simulation::progeny_per_particle[i]; + simulation::progeny_per_particle[i] = value; + } + + // TODO: C++17 introduces the exclusive_scan() function which could be + // used to replace everything above this point in this function. // We need a scratch vector to make permutation of the fission bank into // sorted order easy. Under normal usage conditions, the fission bank is // over provisioned, so we can use that as scratch space. SourceSite* sorted_bank; vector sorted_bank_holder; - vector> sorted_ifp_delayed_group_bank; - vector> sorted_ifp_lifetime_bank; // If there is not enough space, allocate a temporary vector and point to it - if (bank.size() > bank.capacity() / 2) { - sorted_bank_holder.resize(bank.size()); + if (simulation::fission_bank.size() > + simulation::fission_bank.capacity() / 2) { + sorted_bank_holder.resize(simulation::fission_bank.size()); sorted_bank = sorted_bank_holder.data(); } else { // otherwise, point sorted_bank to unused portion of the fission bank - sorted_bank = bank.data() + bank.size(); + sorted_bank = &simulation::fission_bank[simulation::fission_bank.size()]; } - if (settings::ifp_on && is_fission_bank) { - allocate_temporary_vector_ifp( - sorted_ifp_delayed_group_bank, sorted_ifp_lifetime_bank); - } - - // Use parent and progeny indices to sort bank - for (int64_t i = 0; i < bank.size(); i++) { - const auto& site = bank[i]; - if (site.parent_id < 0 || - site.parent_id >= - static_cast(simulation::progeny_per_particle.size())) { - fatal_error(fmt::format("Invalid parent_id {} for banked site (expected " - "range [0, {})).", - site.parent_id, simulation::progeny_per_particle.size())); - } - int64_t idx = - simulation::progeny_per_particle[site.parent_id] + site.progeny_id; - if (idx < 0 || idx >= bank.size()) { + // Use parent and progeny indices to sort fission bank + for (int64_t i = 0; i < simulation::fission_bank.size(); i++) { + const auto& site = simulation::fission_bank[i]; + int64_t offset = site.parent_id - 1 - simulation::work_index[mpi::rank]; + int64_t idx = simulation::progeny_per_particle[offset] + site.progeny_id; + if (idx >= simulation::fission_bank.size()) { fatal_error("Mismatch detected between sum of all particle progeny and " - "bank size during sorting."); + "shared fission bank size."); } sorted_bank[idx] = site; - if (settings::ifp_on && is_fission_bank) { - copy_ifp_data_from_fission_banks( - i, sorted_ifp_delayed_group_bank[idx], sorted_ifp_lifetime_bank[idx]); - } } // Copy sorted bank into the fission bank - std::copy(sorted_bank, sorted_bank + bank.size(), bank.data()); - if (settings::ifp_on && is_fission_bank) { - copy_ifp_data_to_fission_banks( - sorted_ifp_delayed_group_bank.data(), sorted_ifp_lifetime_bank.data()); - } -} - -// This function redistributes SourceSite particles across MPI ranks to -// achieve load balancing while preserving the global ordering of particles. -// -// GUARANTEES: -// ----------- -// 1. Global Order Preservation: After redistribution, each rank holds a -// contiguous slice of the original global ordering. For example, if the -// input across 3 ranks was: -// - Rank 0: IDs 0-4 -// - Rank 1: IDs 5-6 -// - Rank 2: IDs 7-200 -// Then after redistribution (assuming ~67 particles per rank): -// - Rank 0: IDs 0-66 (contiguous) -// - Rank 1: IDs 67-133 (contiguous) -// - Rank 2: IDs 134-200 (contiguous) -// The global ordering is always preserved - no rank will ever hold -// non-contiguous ID ranges like "0-4 and 100-200". -// -// 2. Even Load Balancing: Particles are distributed as evenly as possible. -// If total % n_procs != 0, the first 'remainder' ranks each get one extra -// particle (i.e., floor division with remainder distributed to lower -// ranks). This follows the same logic as calculate_work(). -// -// HOW IT WORKS: -// ------------- -// The algorithm uses overlap-based redistribution: -// 1. Each rank's current data occupies a range [cumulative_before[rank], -// cumulative_before[rank+1]) in the global index space. -// 2. Each rank's target data should occupy [cumulative_target[rank], -// cumulative_target[rank+1]) in the same global index space. -// 3. For each pair of (source_rank, dest_rank), we calculate the overlap -// between what source_rank currently has and what dest_rank needs. -// 4. MPI_Alltoallv transfers exactly these overlapping regions, with -// displacements ensuring data lands at the correct position in the -// receiving buffer. -// -// EDGE CASES HANDLED: -// ------------------- -// - Single rank (n_procs == 1): Returns immediately with local size, no MPI. -// - Empty total (all ranks have 0 particles): Returns 0 immediately. -// - Imbalanced input (e.g., one rank has all particles): Works correctly; -// that rank will send portions to all other ranks based on target ranges. -// - Non-divisible totals: First 'remainder' ranks get one extra particle. -int64_t synchronize_global_secondary_bank( - SharedArray& shared_secondary_bank) -{ - // Get current size of local bank - int64_t local_size = shared_secondary_bank.size(); - - if (mpi::n_procs == 1) { - return local_size; - } - -#ifdef OPENMC_MPI - // Gather all sizes to all ranks - vector all_sizes(mpi::n_procs); - MPI_Allgather(&local_size, 1, MPI_INT64_T, all_sizes.data(), 1, MPI_INT64_T, - mpi::intracomm); - - // Calculate total and check for empty case - int64_t total = 0; - for (int64_t size : all_sizes) { - total += size; - } - - // If we don't have any items to distribute, return - if (total == 0) { - return total; - } - - int64_t base_count = total / mpi::n_procs; - int64_t remainder = total % mpi::n_procs; - - // Calculate target size for each rank - // First 'remainder' ranks get base_count + 1, rest get base_count - vector target_sizes(mpi::n_procs); - for (int i = 0; i < mpi::n_procs; ++i) { - target_sizes[i] = base_count + (i < remainder ? 1 : 0); - } - - // Calculate send and receive counts in terms of SourceSite objects - // (not bytes) - vector send_counts(mpi::n_procs, 0); - vector recv_counts(mpi::n_procs, 0); - vector send_displs(mpi::n_procs, 0); - vector recv_displs(mpi::n_procs, 0); - - // Calculate cumulative positions (starting index for each rank in the - // global array) - vector cumulative_before(mpi::n_procs + 1, 0); - vector cumulative_target(mpi::n_procs + 1, 0); - for (int i = 0; i < mpi::n_procs; ++i) { - cumulative_before[i + 1] = cumulative_before[i] + all_sizes[i]; - cumulative_target[i + 1] = cumulative_target[i] + target_sizes[i]; - } - - // Determine send and receive amounts for each rank - int64_t my_start = cumulative_before[mpi::rank]; - int64_t my_end = cumulative_before[mpi::rank + 1]; - int64_t my_target_start = cumulative_target[mpi::rank]; - int64_t my_target_end = cumulative_target[mpi::rank + 1]; - - for (int r = 0; r < mpi::n_procs; ++r) { - // Send: overlap between my current range and rank r's target range - int64_t send_overlap_start = std::max(my_start, cumulative_target[r]); - int64_t send_overlap_end = std::min(my_end, cumulative_target[r + 1]); - if (send_overlap_start < send_overlap_end) { - int64_t count = send_overlap_end - send_overlap_start; - int64_t displ = send_overlap_start - my_start; - if (count > std::numeric_limits::max() || - displ > std::numeric_limits::max()) { - fatal_error("Secondary bank size exceeds MPI_Alltoallv int limit."); - } - send_counts[r] = static_cast(count); - send_displs[r] = static_cast(displ); - } - - // Recv: overlap between rank r's current range and my target range - int64_t recv_overlap_start = - std::max(cumulative_before[r], my_target_start); - int64_t recv_overlap_end = - std::min(cumulative_before[r + 1], my_target_end); - if (recv_overlap_start < recv_overlap_end) { - int64_t count = recv_overlap_end - recv_overlap_start; - int64_t displ = recv_overlap_start - my_target_start; - if (count > std::numeric_limits::max() || - displ > std::numeric_limits::max()) { - fatal_error("Secondary bank size exceeds MPI_Alltoallv int limit."); - } - recv_counts[r] = static_cast(count); - recv_displs[r] = static_cast(displ); - } - } - - // Prepare receive buffer with target size - SharedArray new_bank(target_sizes[mpi::rank]); - - // Perform all-to-all redistribution using the custom MPI type - MPI_Alltoallv(shared_secondary_bank.data(), send_counts.data(), - send_displs.data(), mpi::source_site, new_bank.data(), recv_counts.data(), - recv_displs.data(), mpi::source_site, mpi::intracomm); - - // Replace old bank with redistributed data - shared_secondary_bank = std::move(new_bank); - - return total; -#else - return local_size; -#endif + std::copy(sorted_bank, sorted_bank + simulation::fission_bank.size(), + simulation::fission_bank.data()); } //============================================================================== diff --git a/src/boundary_condition.cpp b/src/boundary_condition.cpp index d166f1247..5b842399e 100644 --- a/src/boundary_condition.cpp +++ b/src/boundary_condition.cpp @@ -6,7 +6,6 @@ #include "openmc/constants.h" #include "openmc/error.h" -#include "openmc/random_ray/random_ray.h" #include "openmc/surface.h" namespace openmc { @@ -17,18 +16,7 @@ namespace openmc { void VacuumBC::handle_particle(Particle& p, const Surface& surf) const { - // Random ray and Monte Carlo need different treatments at vacuum BCs - if (settings::solver_type == SolverType::RANDOM_RAY) { - // Reflect ray off of the surface - ReflectiveBC().handle_particle(p, surf); - - // Set ray's angular flux spectrum to vacuum conditions (zero) - RandomRay* r = static_cast(&p); - std::fill(r->angular_flux_.begin(), r->angular_flux_.end(), 0.0); - - } else { - p.cross_vacuum_bc(surf); - } + p.cross_vacuum_bc(surf); } //============================================================================== @@ -38,14 +26,8 @@ void VacuumBC::handle_particle(Particle& p, const Surface& surf) const void ReflectiveBC::handle_particle(Particle& p, const Surface& surf) const { Direction u = surf.reflect(p.r(), p.u(), &p); - - // normalize reflected u to ensure no floating point error leads to - // unnormalized directions u /= u.norm(); - // Handle the effects of the surface albedo on the particle's weight. - BoundaryCondition::handle_albedo(p, surf); - p.cross_reflective_bc(surf, u); } @@ -56,14 +38,8 @@ void ReflectiveBC::handle_particle(Particle& p, const Surface& surf) const void WhiteBC::handle_particle(Particle& p, const Surface& surf) const { Direction u = surf.diffuse_reflect(p.r(), p.u(), p.current_seed()); - - // normalize outgoing u to ensure no floating point error leads to - // unnormalized directions u /= u.norm(); - // Handle the effects of the surface albedo on the particle's weight. - BoundaryCondition::handle_albedo(p, surf); - p.cross_reflective_bc(surf, u); } @@ -135,11 +111,24 @@ TranslationalPeriodicBC::TranslationalPeriodicBC(int i_surf, int j_surf) void TranslationalPeriodicBC::handle_particle( Particle& p, const Surface& surf) const { - auto new_r = p.r() + translation_; - int new_surface = p.surface() > 0 ? j_surf_ + 1 : -(j_surf_ + 1); + // TODO: off-by-one on surface indices throughout this function. + int i_particle_surf = std::abs(p.surface()) - 1; - // Handle the effects of the surface albedo on the particle's weight. - BoundaryCondition::handle_albedo(p, surf); + // Figure out which of the two BC surfaces were struck then find the + // particle's new location and surface. + Position new_r; + int new_surface; + if (i_particle_surf == i_surf_) { + new_r = p.r() + translation_; + new_surface = p.surface() > 0 ? j_surf_ + 1 : -(j_surf_ + 1); + } else if (i_particle_surf == j_surf_) { + new_r = p.r() - translation_; + new_surface = p.surface() > 0 ? i_surf_ + 1 : -(i_surf_ + 1); + } else { + throw std::runtime_error( + "Called BoundaryCondition::handle_particle after " + "hitting a surface, but that surface is not recognized by the BC."); + } // Pass the new location and surface to the particle. p.cross_periodic_bc(surf, new_r, p.u(), new_surface); @@ -149,45 +138,63 @@ void TranslationalPeriodicBC::handle_particle( // RotationalPeriodicBC implementation //============================================================================== -RotationalPeriodicBC::RotationalPeriodicBC( - int i_surf, int j_surf, PeriodicAxis axis) - : PeriodicBC(std::abs(i_surf) - 1, std::abs(j_surf) - 1) +RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf) + : PeriodicBC(i_surf, j_surf) { Surface& surf1 {*model::surfaces[i_surf_]}; Surface& surf2 {*model::surfaces[j_surf_]}; - // below convention for right handed coordinate system - switch (axis) { - case x: - zero_axis_idx_ = 0; // x component of plane must be zero - axis_1_idx_ = 1; // y component independent - axis_2_idx_ = 2; // z component dependent - break; - case y: - zero_axis_idx_ = 1; // y component of plane must be zero - axis_1_idx_ = 2; // z component independent - axis_2_idx_ = 0; // x component dependent - break; - case z: - zero_axis_idx_ = 2; // z component of plane must be zero - axis_1_idx_ = 0; // x component independent - axis_2_idx_ = 1; // y component dependent - break; - default: - throw std::invalid_argument( - fmt::format("You've specified an axis that is not x, y, or z.")); + // Check the type of the first surface + bool surf1_is_xyplane; + if (const auto* ptr = dynamic_cast(&surf1)) { + surf1_is_xyplane = true; + } else if (const auto* ptr = dynamic_cast(&surf1)) { + surf1_is_xyplane = true; + } else if (const auto* ptr = dynamic_cast(&surf1)) { + surf1_is_xyplane = false; + } else { + throw std::invalid_argument(fmt::format( + "Surface {} is an invalid type for " + "rotational periodic BCs. Only x-planes, y-planes, or general planes " + "(that are perpendicular to z) are supported for these BCs.", + surf1.id_)); } - Direction ax = {0.0, 0.0, 0.0}; - ax[zero_axis_idx_] = 1.0; - - auto i_sign = std::copysign(1, i_surf); - auto j_sign = -std::copysign(1, j_surf); + // Check the type of the second surface + bool surf2_is_xyplane; + if (const auto* ptr = dynamic_cast(&surf2)) { + surf2_is_xyplane = true; + } else if (const auto* ptr = dynamic_cast(&surf2)) { + surf2_is_xyplane = true; + } else if (const auto* ptr = dynamic_cast(&surf2)) { + surf2_is_xyplane = false; + } else { + throw std::invalid_argument(fmt::format( + "Surface {} is an invalid type for " + "rotational periodic BCs. Only x-planes, y-planes, or general planes " + "(that are perpendicular to z) are supported for these BCs.", + surf2.id_)); + } // Compute the surface normal vectors and make sure they are perpendicular - // to the correct axis - Direction norm1 = i_sign * surf1.normal({0, 0, 0}); - Direction norm2 = j_sign * surf2.normal({0, 0, 0}); + // to the z-axis + Direction norm1 = surf1.normal({0, 0, 0}); + Direction norm2 = surf2.normal({0, 0, 0}); + if (std::abs(norm1.z) > FP_PRECISION) { + throw std::invalid_argument(fmt::format( + "Rotational periodic BCs are only " + "supported for rotations about the z-axis, but surface {} is not " + "perpendicular to the z-axis.", + surf1.id_)); + } + if (std::abs(norm2.z) > FP_PRECISION) { + throw std::invalid_argument(fmt::format( + "Rotational periodic BCs are only " + "supported for rotations about the z-axis, but surface {} is not " + "perpendicular to the z-axis.", + surf2.id_)); + } + // Make sure both surfaces intersect the origin if (std::abs(surf1.evaluate({0, 0, 0})) > FP_COINCIDENT) { throw std::invalid_argument(fmt::format( @@ -204,15 +211,15 @@ RotationalPeriodicBC::RotationalPeriodicBC( surf2.id_)); } - // Compute the signed rotation angle about the periodic axis. Note that - // (n1×n2)·a = |n1||n2|sin(θ) and n1·n2 = |n1||n2|cos(θ), where a is the axis - // of rotation. - auto c = norm1.cross(norm2); - angle_ = std::atan2(c.dot(ax), norm1.dot(norm2)); - - // If the normals point in the same general direction, the surface sense - // should change when crossing the boundary - flip_sense_ = (i_sign * j_sign > 0.0); + // Compute the BC rotation angle. Here it is assumed that both surface + // normal vectors point inwards---towards the valid geometry region. + // Consequently, the rotation angle is not the difference between the two + // normals, but is instead the difference between one normal and one + // anti-normal. (An incident ray on one surface must be an outgoing ray on + // the other surface after rotation hence the anti-normal.) + double theta1 = std::atan2(norm1.y, norm1.x); + double theta2 = std::atan2(norm2.y, norm2.x) + PI; + angle_ = theta2 - theta1; // Warn the user if the angle does not evenly divide a circle double rem = std::abs(std::remainder((2 * PI / angle_), 1.0)); @@ -227,32 +234,35 @@ RotationalPeriodicBC::RotationalPeriodicBC( void RotationalPeriodicBC::handle_particle( Particle& p, const Surface& surf) const { - int new_surface = p.surface() > 0 ? -(j_surf_ + 1) : j_surf_ + 1; - if (flip_sense_) - new_surface = -new_surface; + // TODO: off-by-one on surface indices throughout this function. + int i_particle_surf = std::abs(p.surface()) - 1; - // Rotate the particle's position and direction. + // Figure out which of the two BC surfaces were struck to figure out if a + // forward or backward rotation is required. Specify the other surface as + // the particle's new surface. + double theta; + int new_surface; + if (i_particle_surf == i_surf_) { + theta = angle_; + new_surface = p.surface() > 0 ? -(j_surf_ + 1) : j_surf_ + 1; + } else if (i_particle_surf == j_surf_) { + theta = -angle_; + new_surface = p.surface() > 0 ? -(i_surf_ + 1) : i_surf_ + 1; + } else { + throw std::runtime_error( + "Called BoundaryCondition::handle_particle after " + "hitting a surface, but that surface is not recognized by the BC."); + } + + // Rotate the particle's position and direction about the z-axis. Position r = p.r(); Direction u = p.u(); - double cos_theta = std::cos(angle_); - double sin_theta = std::sin(angle_); - - Position new_r; - new_r[zero_axis_idx_] = r[zero_axis_idx_]; - new_r[axis_1_idx_] = cos_theta * r[axis_1_idx_] - sin_theta * r[axis_2_idx_]; - new_r[axis_2_idx_] = sin_theta * r[axis_1_idx_] + cos_theta * r[axis_2_idx_]; - - Direction new_u; - new_u[zero_axis_idx_] = u[zero_axis_idx_]; - new_u[axis_1_idx_] = cos_theta * u[axis_1_idx_] - sin_theta * u[axis_2_idx_]; - new_u[axis_2_idx_] = sin_theta * u[axis_1_idx_] + cos_theta * u[axis_2_idx_]; - - // normalize new_u to ensure no floating point error leads to unnormalized - // directions - new_u /= new_u.norm(); - - // Handle the effects of the surface albedo on the particle's weight. - BoundaryCondition::handle_albedo(p, surf); + double cos_theta = std::cos(theta); + double sin_theta = std::sin(theta); + Position new_r = { + cos_theta * r.x - sin_theta * r.y, sin_theta * r.x + cos_theta * r.y, r.z}; + Direction new_u = { + cos_theta * u.x - sin_theta * u.y, sin_theta * u.x + cos_theta * u.y, u.z}; // Pass the new location, direction, and surface to the particle. p.cross_periodic_bc(surf, new_r, new_u, new_surface); diff --git a/src/bremsstrahlung.cpp b/src/bremsstrahlung.cpp index ec1088101..d22d6392a 100644 --- a/src/bremsstrahlung.cpp +++ b/src/bremsstrahlung.cpp @@ -6,7 +6,7 @@ #include "openmc/search.h" #include "openmc/settings.h" -#include "openmc/tensor.h" +#include "xtensor/xmath.hpp" namespace openmc { @@ -16,8 +16,8 @@ namespace openmc { namespace data { -tensor::Tensor ttb_e_grid; -tensor::Tensor ttb_k_grid; +xt::xtensor ttb_e_grid; +xt::xtensor ttb_k_grid; vector ttb; } // namespace data @@ -31,13 +31,13 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) if (p.material() == MATERIAL_VOID) return; - int photon = ParticleType::photon().transport_index(); + int photon = static_cast(ParticleType::photon); if (p.E() < settings::energy_cutoff[photon]) return; // Get bremsstrahlung data for this material and particle type BremsstrahlungData* mat; - if (p.type() == ParticleType::positron()) { + if (p.type() == ParticleType::positron) { mat = &model::materials[p.material()]->ttb_->positron; } else { mat = &model::materials[p.material()]->ttb_->electron; @@ -112,14 +112,8 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) std::pow(a * (c - c_l) / (std::exp(w_l) * p_l) + 1.0, 1.0 / a); if (w > settings::energy_cutoff[photon]) { - // If the energy of the secondary photon is larger than the remaining - // energy of the primary particle, adjust it to the remaining energy - if (*E_lost + w > p.E()) { - w = p.E() - *E_lost; - } - // Create secondary photon - p.create_secondary(p.wgt(), p.u(), w, ParticleType::photon()); + p.create_secondary(p.wgt(), p.u(), w, ParticleType::photon); *E_lost += w; } } diff --git a/src/cell.cpp b/src/cell.cpp index 06bc29a66..f9786ce3e 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -2,7 +2,6 @@ #include "openmc/cell.h" #include -#include #include #include #include @@ -11,6 +10,7 @@ #include #include +#include #include "openmc/capi.h" #include "openmc/constants.h" @@ -37,805 +37,74 @@ vector> cells; } // namespace model //============================================================================== -// Cell implementation +//! Convert region specification string to integer tokens. +//! +//! The characters (, ), |, and ~ count as separate tokens since they represent +//! operators. //============================================================================== -int32_t Cell::n_instances() const +vector tokenize(const std::string region_spec) { - return model::universes[universe_]->n_instances_; -} - -void Cell::set_rotation(const vector& rot) -{ - if (fill_ == C_NONE) { - fatal_error(fmt::format("Cannot apply a rotation to cell {}" - " because it is not filled with another universe", - id_)); + // Check for an empty region_spec first. + vector tokens; + if (region_spec.empty()) { + return tokens; } - if (rot.size() != 3 && rot.size() != 9) { - fatal_error(fmt::format("Non-3D rotation vector applied to cell {}", id_)); - } - - // Compute and store the inverse rotation matrix for the angles given. - rotation_.clear(); - rotation_.reserve(rot.size() == 9 ? 9 : 12); - if (rot.size() == 3) { - double phi = -rot[0] * PI / 180.0; - double theta = -rot[1] * PI / 180.0; - double psi = -rot[2] * PI / 180.0; - rotation_.push_back(std::cos(theta) * std::cos(psi)); - rotation_.push_back(-std::cos(phi) * std::sin(psi) + - std::sin(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::sin(phi) * std::sin(psi) + - std::cos(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::cos(theta) * std::sin(psi)); - rotation_.push_back(std::cos(phi) * std::cos(psi) + - std::sin(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(phi) * std::cos(psi) + - std::cos(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(theta)); - rotation_.push_back(std::sin(phi) * std::cos(theta)); - rotation_.push_back(std::cos(phi) * std::cos(theta)); - - // When user specifies angles, write them at end of vector - rotation_.push_back(rot[0]); - rotation_.push_back(rot[1]); - rotation_.push_back(rot[2]); - } else { - std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); - } -} - -double Cell::temperature(int32_t instance) const -{ - if (sqrtkT_.size() < 1) { - throw std::runtime_error {"Cell temperature has not yet been set."}; - } - - if (instance >= 0) { - double sqrtkT = sqrtkT_.size() == 1 ? sqrtkT_.at(0) : sqrtkT_.at(instance); - return sqrtkT * sqrtkT / K_BOLTZMANN; - } else { - return sqrtkT_[0] * sqrtkT_[0] / K_BOLTZMANN; - } -} - -double Cell::density_mult(int32_t instance) const -{ - if (instance >= 0) { - return density_mult_.size() == 1 ? density_mult_.at(0) - : density_mult_.at(instance); - } else { - return density_mult_[0]; - } -} - -double Cell::density(int32_t instance) const -{ - const int32_t mat_index = material(instance); - if (mat_index == MATERIAL_VOID) - return 0.0; - - return density_mult(instance) * model::materials[mat_index]->density_gpcc(); -} - -void Cell::set_temperature(double T, int32_t instance, bool set_contained) -{ - if (settings::temperature_method == TemperatureMethod::INTERPOLATION) { - if (T < (data::temperature_min - settings::temperature_tolerance)) { - throw std::runtime_error { - fmt::format("Temperature of {} K is below minimum temperature at " - "which data is available of {} K.", - T, data::temperature_min)}; - } else if (T > (data::temperature_max + settings::temperature_tolerance)) { - throw std::runtime_error { - fmt::format("Temperature of {} K is above maximum temperature at " - "which data is available of {} K.", - T, data::temperature_max)}; - } - } - - if (type_ == Fill::MATERIAL) { - if (instance >= 0) { - // If temperature vector is not big enough, resize it first - if (sqrtkT_.size() != n_instances()) - sqrtkT_.resize(n_instances(), sqrtkT_[0]); - - // Set temperature for the corresponding instance - sqrtkT_.at(instance) = std::sqrt(K_BOLTZMANN * T); - } else { - // Set temperature for all instances - for (auto& T_ : sqrtkT_) { - T_ = std::sqrt(K_BOLTZMANN * T); - } - } - } else { - if (!set_contained) { - throw std::runtime_error { - fmt::format("Attempted to set the temperature of cell {} " - "which is not filled by a material.", - id_)}; - } - - auto contained_cells = this->get_contained_cells(instance); - for (const auto& entry : contained_cells) { - auto& cell = model::cells[entry.first]; - assert(cell->type_ == Fill::MATERIAL); - auto& instances = entry.second; - for (auto instance : instances) { - cell->set_temperature(T, instance); - } - } - } -} - -void Cell::set_density(double density, int32_t instance, bool set_contained) -{ - if (type_ != Fill::MATERIAL && !set_contained) { - fatal_error( - fmt::format("Attempted to set the density multiplier of cell {} " - "which is not filled by a material.", - id_)); - } - - if (type_ == Fill::MATERIAL) { - const int32_t mat_index = material(instance); - if (mat_index == MATERIAL_VOID) - return; - - if (instance >= 0) { - // If density multiplier vector is not big enough, resize it first - if (density_mult_.size() != n_instances()) - density_mult_.resize(n_instances(), density_mult_[0]); - - // Set density multiplier for the corresponding instance - density_mult_.at(instance) = - density / model::materials[mat_index]->density_gpcc(); - } else { - // Set density multiplier for all instances - for (auto& x : density_mult_) { - x = density / model::materials[mat_index]->density_gpcc(); - } - } - } else { - auto contained_cells = this->get_contained_cells(instance); - for (const auto& entry : contained_cells) { - auto& cell = model::cells[entry.first]; - assert(cell->type_ == Fill::MATERIAL); - auto& instances = entry.second; - for (auto instance : instances) { - cell->set_density(density, instance); - } - } - } -} - -void Cell::export_properties_hdf5(hid_t group) const -{ - // Create a group for this cell. - auto cell_group = create_group(group, fmt::format("cell {}", id_)); - - // Write temperature in [K] for one or more cell instances - vector temps; - for (auto sqrtkT_val : sqrtkT_) - temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); - write_dataset(cell_group, "temperature", temps); - - // Write density for one or more cell instances - if (type_ == Fill::MATERIAL && material_.size() > 0) { - vector density; - for (int32_t i = 0; i < density_mult_.size(); ++i) - density.push_back(this->density(i)); - - write_dataset(cell_group, "density", density); - } - - close_group(cell_group); -} - -void Cell::import_properties_hdf5(hid_t group) -{ - auto cell_group = open_group(group, fmt::format("cell {}", id_)); - - // Read temperatures from file - vector temps; - read_dataset(cell_group, "temperature", temps); - - // Ensure number of temperatures makes sense - auto n_temps = temps.size(); - if (n_temps > 1 && n_temps != n_instances()) { - fatal_error(fmt::format( - "Number of temperatures for cell {} doesn't match number of instances", - id_)); - } - - // Modify temperatures for the cell - sqrtkT_.clear(); - sqrtkT_.resize(temps.size()); - for (int64_t i = 0; i < temps.size(); ++i) { - this->set_temperature(temps[i], i); - } - - // Read densities - if (object_exists(cell_group, "density")) { - vector density; - read_dataset(cell_group, "density", density); - - // Ensure number of densities makes sense - auto n_density = density.size(); - if (n_density > 1 && n_density != n_instances()) { - fatal_error(fmt::format("Number of densities for cell {} " - "doesn't match number of instances", - id_)); - } - - // Set densities. - for (int32_t i = 0; i < n_density; ++i) { - this->set_density(density[i], i); - } - } - - close_group(cell_group); -} - -void Cell::to_hdf5(hid_t cell_group) const -{ - - // Create a group for this cell. - auto group = create_group(cell_group, fmt::format("cell {}", id_)); - - if (!name_.empty()) { - write_string(group, "name", name_, false); - } - - write_dataset(group, "universe", model::universes[universe_]->id_); - - to_hdf5_inner(group); - - // Write fill information. - if (type_ == Fill::MATERIAL) { - write_dataset(group, "fill_type", "material"); - std::vector mat_ids; - for (auto i_mat : material_) { - if (i_mat != MATERIAL_VOID) { - mat_ids.push_back(model::materials[i_mat]->id_); - } else { - mat_ids.push_back(MATERIAL_VOID); - } - } - if (mat_ids.size() == 1) { - write_dataset(group, "material", mat_ids[0]); - } else { - write_dataset(group, "material", mat_ids); - } - - std::vector temps; - for (auto sqrtkT_val : sqrtkT_) - temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); - write_dataset(group, "temperature", temps); - - write_dataset(group, "density_mult", density_mult_); - - } else if (type_ == Fill::UNIVERSE) { - write_dataset(group, "fill_type", "universe"); - write_dataset(group, "fill", model::universes[fill_]->id_); - if (translation_ != Position(0, 0, 0)) { - write_dataset(group, "translation", translation_); - } - if (!rotation_.empty()) { - if (rotation_.size() == 12) { - std::array rot {rotation_[9], rotation_[10], rotation_[11]}; - write_dataset(group, "rotation", rot); - } else { - write_dataset(group, "rotation", rotation_); - } - } - - } else if (type_ == Fill::LATTICE) { - write_dataset(group, "fill_type", "lattice"); - write_dataset(group, "lattice", model::lattices[fill_]->id_); - } - - close_group(group); -} - -//============================================================================== -// XML parsing helpers for nodes -//============================================================================== - -vector parse_cell_material_xml(pugi::xml_node node, int32_t cell_id) -{ - vector mats { - get_node_array(node, "material", true)}; - if (mats.empty()) { - fatal_error(fmt::format( - "An empty material element was specified for cell {}", cell_id)); - } - vector material; - material.reserve(mats.size()); - for (const auto& mat : mats) { - if (mat == "void") { - material.push_back(MATERIAL_VOID); - } else { - material.push_back(std::stoi(mat)); - } - } - return material; -} - -vector parse_cell_temperature_xml(pugi::xml_node node, int32_t cell_id) -{ - auto temperatures = get_node_array(node, "temperature"); - if (temperatures.empty()) { - fatal_error(fmt::format( - "An empty temperature element was specified for cell {}", cell_id)); - } - for (auto T : temperatures) { - if (T < 0) { - fatal_error(fmt::format( - "Cell {} was specified with a negative temperature", cell_id)); - } - } - return temperatures; -} - -vector parse_cell_density_xml(pugi::xml_node node, int32_t cell_id) -{ - auto densities = get_node_array(node, "density"); - if (densities.empty()) { - fatal_error(fmt::format( - "An empty density element was specified for cell {}", cell_id)); - } - for (auto rho : densities) { - if (rho <= 0) { - fatal_error(fmt::format( - "Cell {} was specified with a density less than or equal to zero", - cell_id)); - } - } - return densities; -} - -//============================================================================== -// CSGCell implementation -//============================================================================== - -CSGCell::CSGCell(pugi::xml_node cell_node) -{ - if (check_for_node(cell_node, "id")) { - id_ = std::stoi(get_node_value(cell_node, "id")); - } else { - fatal_error("Must specify id of cell in geometry XML file."); - } - - if (check_for_node(cell_node, "name")) { - name_ = get_node_value(cell_node, "name"); - } - - if (check_for_node(cell_node, "universe")) { - universe_ = std::stoi(get_node_value(cell_node, "universe")); - } else { - universe_ = 0; - } - - // Make sure that either material or fill was specified, but not both. - bool fill_present = check_for_node(cell_node, "fill"); - bool material_present = check_for_node(cell_node, "material"); - if (!(fill_present || material_present)) { - fatal_error( - fmt::format("Neither material nor fill was specified for cell {}", id_)); - } - if (fill_present && material_present) { - fatal_error(fmt::format("Cell {} has both a material and a fill specified; " - "only one can be specified per cell", - id_)); - } - - if (fill_present) { - fill_ = std::stoi(get_node_value(cell_node, "fill")); - if (fill_ == universe_) { - fatal_error(fmt::format("Cell {} is filled with the same universe that " - "it is contained in.", - id_)); - } - } else { - fill_ = C_NONE; - } - - // Read the material element. There can be zero materials (filled with a - // universe), more than one material (distribmats), and some materials may - // be "void". - if (material_present) { - material_ = parse_cell_material_xml(cell_node, id_); - } - - // Read the temperature element which may be distributed like materials. - if (check_for_node(cell_node, "temperature")) { - sqrtkT_ = parse_cell_temperature_xml(cell_node, id_); - sqrtkT_.shrink_to_fit(); - - // Make sure this is a material-filled cell. - if (material_.size() == 0) { - fatal_error(fmt::format( - "Cell {} was specified with a temperature but no material. Temperature" - "specification is only valid for cells filled with a material.", - id_)); - } - - // Convert to sqrt(k*T). - for (auto& T : sqrtkT_) { - T = std::sqrt(K_BOLTZMANN * T); - } - } - - // Read the density element which can be distributed similar to temperature. - // These get assigned to the density multiplier, requiring a division by - // the material density. - // Note: calculating the actual density multiplier is deferred until materials - // are finalized. density_mult_ contains the true density in the meantime. - if (check_for_node(cell_node, "density")) { - density_mult_ = parse_cell_density_xml(cell_node, id_); - density_mult_.shrink_to_fit(); - - // Make sure this is a material-filled cell. - if (material_.size() == 0) { - fatal_error(fmt::format( - "Cell {} was specified with a density but no material. Density" - "specification is only valid for cells filled with a material.", - id_)); - } - - // Make sure this is a non-void material. - for (auto mat_id : material_) { - if (mat_id == MATERIAL_VOID) { - fatal_error(fmt::format( - "Cell {} was specified with a density, but contains a void " - "material. Density specification is only valid for cells " - "filled with a non-void material.", - id_)); - } - } - } - - // Read the region specification. - std::string region_spec; - if (check_for_node(cell_node, "region")) { - region_spec = get_node_value(cell_node, "region"); - } - - // Get a tokenized representation of the region specification and apply De - // Morgans law - Region region(region_spec, id_); - region_ = region; - - // Read the translation vector. - if (check_for_node(cell_node, "translation")) { - if (fill_ == C_NONE) { - fatal_error(fmt::format("Cannot apply a translation to cell {}" - " because it is not filled with another universe", - id_)); - } - - auto xyz {get_node_array(cell_node, "translation")}; - if (xyz.size() != 3) { - fatal_error( - fmt::format("Non-3D translation vector applied to cell {}", id_)); - } - translation_ = xyz; - } - - // Read the rotation transform. - if (check_for_node(cell_node, "rotation")) { - auto rot {get_node_array(cell_node, "rotation")}; - set_rotation(rot); - } -} - -//============================================================================== - -void CSGCell::to_hdf5_inner(hid_t group_id) const -{ - write_string(group_id, "geom_type", "csg", false); - write_string(group_id, "region", region_.str(), false); -} - -//============================================================================== - -vector::iterator CSGCell::find_left_parenthesis( - vector::iterator start, const vector& infix) -{ - // start search at zero - int parenthesis_level = 0; - auto it = start; - while (it != infix.begin()) { - // look at two tokens at a time - int32_t one = *it; - int32_t two = *(it - 1); - - // decrement parenthesis level if there are two adjacent surfaces - if (one < OP_UNION && two < OP_UNION) { - parenthesis_level--; - // increment if there are two adjacent operators - } else if (one >= OP_UNION && two >= OP_UNION) { - parenthesis_level++; - } - - // if the level gets to zero, return the position - if (parenthesis_level == 0) { - // move the iterator back one before leaving the loop - // so that all tokens in the parenthesis block are included - it--; - break; - } - - // continue loop, one token at a time - it--; - } - return it; -} - -//============================================================================== -// Region implementation -//============================================================================== - -Region::Region(std::string region_spec, int32_t cell_id) -{ - // Check if region_spec is not empty. - if (!region_spec.empty()) { - // Parse all halfspaces and operators except for intersection (whitespace). - for (int i = 0; i < region_spec.size();) { - if (region_spec[i] == '(') { - expression_.push_back(OP_LEFT_PAREN); - i++; - - } else if (region_spec[i] == ')') { - expression_.push_back(OP_RIGHT_PAREN); - i++; - - } else if (region_spec[i] == '|') { - expression_.push_back(OP_UNION); - i++; - - } else if (region_spec[i] == '~') { - expression_.push_back(OP_COMPLEMENT); - i++; - - } else if (region_spec[i] == '-' || region_spec[i] == '+' || - std::isdigit(region_spec[i])) { - // This is the start of a halfspace specification. Iterate j until we - // find the end, then push-back everything between i and j. - int j = i + 1; - while (j < region_spec.size() && std::isdigit(region_spec[j])) { - j++; - } - expression_.push_back(std::stoi(region_spec.substr(i, j - i))); - i = j; - - } else if (std::isspace(region_spec[i])) { - i++; - - } else { - auto err_msg = - fmt::format("Region specification contains invalid character, \"{}\"", - region_spec[i]); - fatal_error(err_msg); - } - } - - // Add in intersection operators where a missing operator is needed. - int i = 0; - while (i < expression_.size() - 1) { - bool left_compat { - (expression_[i] < OP_UNION) || (expression_[i] == OP_RIGHT_PAREN)}; - bool right_compat {(expression_[i + 1] < OP_UNION) || - (expression_[i + 1] == OP_LEFT_PAREN) || - (expression_[i + 1] == OP_COMPLEMENT)}; - if (left_compat && right_compat) { - expression_.insert(expression_.begin() + i + 1, OP_INTERSECTION); - } + // Parse all halfspaces and operators except for intersection (whitespace). + for (int i = 0; i < region_spec.size();) { + if (region_spec[i] == '(') { + tokens.push_back(OP_LEFT_PAREN); i++; - } - // Remove complement operators using DeMorgan's laws - auto it = std::find(expression_.begin(), expression_.end(), OP_COMPLEMENT); - while (it != expression_.end()) { - // Erase complement - expression_.erase(it); + } else if (region_spec[i] == ')') { + tokens.push_back(OP_RIGHT_PAREN); + i++; - // Define stop given left parenthesis or not - auto stop = it; - if (*it == OP_LEFT_PAREN) { - int depth = 1; - do { - stop++; - if (*stop > OP_COMPLEMENT) { - if (*stop == OP_RIGHT_PAREN) { - depth--; - } else { - depth++; - } - } - } while (depth > 0); - it++; + } else if (region_spec[i] == '|') { + tokens.push_back(OP_UNION); + i++; + + } else if (region_spec[i] == '~') { + tokens.push_back(OP_COMPLEMENT); + i++; + + } else if (region_spec[i] == '-' || region_spec[i] == '+' || + std::isdigit(region_spec[i])) { + // This is the start of a halfspace specification. Iterate j until we + // find the end, then push-back everything between i and j. + int j = i + 1; + while (j < region_spec.size() && std::isdigit(region_spec[j])) { + j++; } + tokens.push_back(std::stoi(region_spec.substr(i, j - i))); + i = j; - // apply DeMorgan's law to any surfaces/operators between these - // positions in the RPN - apply_demorgan(it, stop); - // update iterator position - it = std::find(expression_.begin(), expression_.end(), OP_COMPLEMENT); - } + } else if (std::isspace(region_spec[i])) { + i++; - // Convert user IDs to surface indices. - for (auto& r : expression_) { - if (r < OP_UNION) { - const auto& it {model::surface_map.find(abs(r))}; - if (it == model::surface_map.end()) { - throw std::runtime_error { - "Invalid surface ID " + std::to_string(abs(r)) + - " specified in region for cell " + std::to_string(cell_id) + "."}; - } - r = (r > 0) ? it->second + 1 : -(it->second + 1); - } - } - - // Check if this is a simple cell. - simple_ = true; - for (int32_t token : expression_) { - if (token == OP_UNION) { - simple_ = false; - // Ensure intersections have precedence over unions - enforce_precedence(); - break; - } - } - - // If this cell is simple, remove all the superfluous operator tokens. - if (simple_) { - for (auto it = expression_.begin(); it != expression_.end(); it++) { - if (*it == OP_INTERSECTION || *it > OP_COMPLEMENT) { - expression_.erase(it); - it--; - } - } - } - expression_.shrink_to_fit(); - - } else { - simple_ = true; - } -} - -//============================================================================== - -void Region::apply_demorgan( - vector::iterator start, vector::iterator stop) -{ - do { - if (*start < OP_UNION) { - *start *= -1; - } else if (*start == OP_UNION) { - *start = OP_INTERSECTION; - } else if (*start == OP_INTERSECTION) { - *start = OP_UNION; - } - start++; - } while (start < stop); -} - -//============================================================================== -//! Add precedence for infix regions so intersections have higher -//! precedence than unions using parentheses. -//============================================================================== - -void Region::add_parentheses(int64_t start) -{ - int32_t start_token = expression_[start]; - // Add left parenthesis and set new position to be after parenthesis - if (start_token == OP_UNION) { - start += 2; - } - expression_.insert(expression_.begin() + start - 1, OP_LEFT_PAREN); - - // Add right parenthesis - // While the start iterator is within the bounds of infix - while (start + 1 < expression_.size()) { - start++; - - // If the current token is an operator and is different than the start token - if (expression_[start] >= OP_UNION && expression_[start] != start_token) { - // Skip wrapped regions but save iterator position to check precedence and - // add right parenthesis, right parenthesis position depends on the - // operator, when the operator is a union then do not include the operator - // in the region, when the operator is an intersection then include the - // operator and next surface - if (expression_[start] == OP_LEFT_PAREN) { - int depth = 1; - do { - start++; - if (expression_[start] > OP_COMPLEMENT) { - if (expression_[start] == OP_RIGHT_PAREN) { - depth--; - } else { - depth++; - } - } - } while (depth > 0); - } else { - if (start_token == OP_UNION) { - --start; - } - expression_.insert(expression_.begin() + start, OP_RIGHT_PAREN); - return; - } + } else { + auto err_msg = + fmt::format("Region specification contains invalid character, \"{}\"", + region_spec[i]); + fatal_error(err_msg); } } - // If we get here a right parenthesis hasn't been placed - expression_.push_back(OP_RIGHT_PAREN); -} -//============================================================================== -//! Add parentheses to enforce operator precedence in region expressions -//! -//! This function ensures that intersection operators have higher precedence -//! than union operators by adding parentheses where needed. For example: -//! "1 2 | 3" becomes "(1 2) | 3" -//! "1 | 2 3" becomes "1 | (2 3)" -//! -//! The algorithm uses stacks to track the current operator type and its -//! position at each parenthesis depth level. When it encounters a different -//! operator at the same depth, it adds parentheses to group the -//! higher-precedence operations. -//============================================================================== - -void Region::enforce_precedence() -{ - // Stack tracking the operator type at each depth (0 = no operator seen yet) - vector op_stack = {0}; - - // Stack tracking where the operator sequence started at each depth - vector pos_stack = {0}; - - for (int64_t i = 0; i < expression_.size(); ++i) { - int32_t token = expression_[i]; - - if (token == OP_LEFT_PAREN) { - // Entering a new parenthesis level - push new tracking state - op_stack.push_back(0); - pos_stack.push_back(0); - continue; - } else if (token == OP_RIGHT_PAREN) { - // Exiting a parenthesis level - pop tracking state (keep at least one) - if (op_stack.size() > 1) { - op_stack.pop_back(); - pos_stack.pop_back(); - } - continue; - } - - if (token == OP_UNION || token == OP_INTERSECTION) { - if (op_stack.back() == 0) { - // First operator at this depth - record it and its position - op_stack.back() = token; - pos_stack.back() = i; - } else if (token != op_stack.back()) { - // Encountered a different operator at the same depth - need to add - // parentheses to enforce precedence. Intersection has higher - // precedence, so we parenthesize the intersection terms. - if (op_stack.back() == OP_INTERSECTION) { - add_parentheses(pos_stack.back()); - } else { - add_parentheses(i); - } - - // Restart the scan since we modified the expression - i = -1; // Will be incremented to 0 by the for loop - op_stack = {0}; - pos_stack = {0}; - } + // Add in intersection operators where a missing operator is needed. + int i = 0; + while (i < tokens.size() - 1) { + bool left_compat {(tokens[i] < OP_UNION) || (tokens[i] == OP_RIGHT_PAREN)}; + bool right_compat {(tokens[i + 1] < OP_UNION) || + (tokens[i + 1] == OP_LEFT_PAREN) || + (tokens[i + 1] == OP_COMPLEMENT)}; + if (left_compat && right_compat) { + tokens.insert(tokens.begin() + i + 1, OP_INTERSECTION); } + i++; } + + return tokens; } //============================================================================== @@ -844,12 +113,12 @@ void Region::enforce_precedence() //! This function uses the shunting-yard algorithm. //============================================================================== -vector Region::generate_postfix(int32_t cell_id) const +vector generate_rpn(int32_t cell_id, vector infix) { vector rpn; vector stack; - for (int32_t token : expression_) { + for (int32_t token : infix) { if (token < OP_UNION) { // If token is not an operator, add it to output rpn.push_back(token); @@ -915,41 +184,406 @@ vector Region::generate_postfix(int32_t cell_id) const return rpn; } +//============================================================================== +// Cell implementation //============================================================================== -std::string Region::str() const +void Cell::set_rotation(const vector& rot) { - std::stringstream region_spec {}; - if (!expression_.empty()) { - for (int32_t token : expression_) { - if (token == OP_LEFT_PAREN) { - region_spec << " ("; - } else if (token == OP_RIGHT_PAREN) { - region_spec << " )"; - } else if (token == OP_COMPLEMENT) { - region_spec << " ~"; - } else if (token == OP_INTERSECTION) { - } else if (token == OP_UNION) { - region_spec << " |"; - } else { - // Note the off-by-one indexing - auto surf_id = model::surfaces[abs(token) - 1]->id_; - region_spec << " " << ((token > 0) ? surf_id : -surf_id); + if (fill_ == C_NONE) { + fatal_error(fmt::format("Cannot apply a rotation to cell {}" + " because it is not filled with another universe", + id_)); + } + + if (rot.size() != 3 && rot.size() != 9) { + fatal_error(fmt::format("Non-3D rotation vector applied to cell {}", id_)); + } + + // Compute and store the rotation matrix. + rotation_.clear(); + rotation_.reserve(rot.size() == 9 ? 9 : 12); + if (rot.size() == 3) { + double phi = -rot[0] * PI / 180.0; + double theta = -rot[1] * PI / 180.0; + double psi = -rot[2] * PI / 180.0; + rotation_.push_back(std::cos(theta) * std::cos(psi)); + rotation_.push_back(-std::cos(phi) * std::sin(psi) + + std::sin(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::sin(phi) * std::sin(psi) + + std::cos(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::cos(theta) * std::sin(psi)); + rotation_.push_back(std::cos(phi) * std::cos(psi) + + std::sin(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(phi) * std::cos(psi) + + std::cos(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(theta)); + rotation_.push_back(std::sin(phi) * std::cos(theta)); + rotation_.push_back(std::cos(phi) * std::cos(theta)); + + // When user specifies angles, write them at end of vector + rotation_.push_back(rot[0]); + rotation_.push_back(rot[1]); + rotation_.push_back(rot[2]); + } else { + std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); + } +} + +double Cell::temperature(int32_t instance) const +{ + if (sqrtkT_.size() < 1) { + throw std::runtime_error {"Cell temperature has not yet been set."}; + } + + if (instance >= 0) { + double sqrtkT = sqrtkT_.size() == 1 ? sqrtkT_.at(0) : sqrtkT_.at(instance); + return sqrtkT * sqrtkT / K_BOLTZMANN; + } else { + return sqrtkT_[0] * sqrtkT_[0] / K_BOLTZMANN; + } +} + +void Cell::set_temperature(double T, int32_t instance, bool set_contained) +{ + if (settings::temperature_method == TemperatureMethod::INTERPOLATION) { + if (T < data::temperature_min) { + throw std::runtime_error {"Temperature is below minimum temperature at " + "which data is available."}; + } else if (T > data::temperature_max) { + throw std::runtime_error {"Temperature is above maximum temperature at " + "which data is available."}; + } + } + + if (type_ == Fill::MATERIAL) { + if (instance >= 0) { + // If temperature vector is not big enough, resize it first + if (sqrtkT_.size() != n_instances_) + sqrtkT_.resize(n_instances_, sqrtkT_[0]); + + // Set temperature for the corresponding instance + sqrtkT_.at(instance) = std::sqrt(K_BOLTZMANN * T); + } else { + // Set temperature for all instances + for (auto& T_ : sqrtkT_) { + T_ = std::sqrt(K_BOLTZMANN * T); + } + } + } else { + if (!set_contained) { + throw std::runtime_error { + fmt::format("Attempted to set the temperature of cell {} " + "which is not filled by a material.", + id_)}; + } + + auto contained_cells = this->get_contained_cells(instance); + for (const auto& entry : contained_cells) { + auto& cell = model::cells[entry.first]; + Expects(cell->type_ == Fill::MATERIAL); + auto& instances = entry.second; + for (auto instance : instances) { + cell->set_temperature(T, instance); } } } - return region_spec.str(); +} + +void Cell::export_properties_hdf5(hid_t group) const +{ + // Create a group for this cell. + auto cell_group = create_group(group, fmt::format("cell {}", id_)); + + // Write temperature in [K] for one or more cell instances + vector temps; + for (auto sqrtkT_val : sqrtkT_) + temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); + write_dataset(cell_group, "temperature", temps); + + close_group(cell_group); +} + +void Cell::import_properties_hdf5(hid_t group) +{ + auto cell_group = open_group(group, fmt::format("cell {}", id_)); + + // Read temperatures from file + vector temps; + read_dataset(cell_group, "temperature", temps); + + // Ensure number of temperatures makes sense + auto n_temps = temps.size(); + if (n_temps > 1 && n_temps != n_instances_) { + throw std::runtime_error(fmt::format( + "Number of temperatures for cell {} doesn't match number of instances", + id_)); + } + + // Modify temperatures for the cell + sqrtkT_.clear(); + sqrtkT_.resize(temps.size()); + for (gsl::index i = 0; i < temps.size(); ++i) { + this->set_temperature(temps[i], i); + } + + close_group(cell_group); +} + +void Cell::to_hdf5(hid_t cell_group) const +{ + + // Create a group for this cell. + auto group = create_group(cell_group, fmt::format("cell {}", id_)); + + if (!name_.empty()) { + write_string(group, "name", name_, false); + } + + write_dataset(group, "universe", model::universes[universe_]->id_); + + to_hdf5_inner(group); + + // Write fill information. + if (type_ == Fill::MATERIAL) { + write_dataset(group, "fill_type", "material"); + std::vector mat_ids; + for (auto i_mat : material_) { + if (i_mat != MATERIAL_VOID) { + mat_ids.push_back(model::materials[i_mat]->id_); + } else { + mat_ids.push_back(MATERIAL_VOID); + } + } + if (mat_ids.size() == 1) { + write_dataset(group, "material", mat_ids[0]); + } else { + write_dataset(group, "material", mat_ids); + } + + std::vector temps; + for (auto sqrtkT_val : sqrtkT_) + temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); + write_dataset(group, "temperature", temps); + + } else if (type_ == Fill::UNIVERSE) { + write_dataset(group, "fill_type", "universe"); + write_dataset(group, "fill", model::universes[fill_]->id_); + if (translation_ != Position(0, 0, 0)) { + write_dataset(group, "translation", translation_); + } + if (!rotation_.empty()) { + if (rotation_.size() == 12) { + std::array rot {rotation_[9], rotation_[10], rotation_[11]}; + write_dataset(group, "rotation", rot); + } else { + write_dataset(group, "rotation", rotation_); + } + } + + } else if (type_ == Fill::LATTICE) { + write_dataset(group, "fill_type", "lattice"); + write_dataset(group, "lattice", model::lattices[fill_]->id_); + } + + close_group(group); +} + +//============================================================================== +// CSGCell implementation +//============================================================================== + +// default constructor +CSGCell::CSGCell() +{ + geom_type_ = GeometryType::CSG; +} + +CSGCell::CSGCell(pugi::xml_node cell_node) +{ + geom_type_ = GeometryType::CSG; + + if (check_for_node(cell_node, "id")) { + id_ = std::stoi(get_node_value(cell_node, "id")); + } else { + fatal_error("Must specify id of cell in geometry XML file."); + } + + if (check_for_node(cell_node, "name")) { + name_ = get_node_value(cell_node, "name"); + } + + if (check_for_node(cell_node, "universe")) { + universe_ = std::stoi(get_node_value(cell_node, "universe")); + } else { + universe_ = 0; + } + + // Make sure that either material or fill was specified, but not both. + bool fill_present = check_for_node(cell_node, "fill"); + bool material_present = check_for_node(cell_node, "material"); + if (!(fill_present || material_present)) { + fatal_error( + fmt::format("Neither material nor fill was specified for cell {}", id_)); + } + if (fill_present && material_present) { + fatal_error(fmt::format("Cell {} has both a material and a fill specified; " + "only one can be specified per cell", + id_)); + } + + if (fill_present) { + fill_ = std::stoi(get_node_value(cell_node, "fill")); + if (fill_ == universe_) { + fatal_error(fmt::format("Cell {} is filled with the same universe that" + "it is contained in.", + id_)); + } + } else { + fill_ = C_NONE; + } + + // Read the material element. There can be zero materials (filled with a + // universe), more than one material (distribmats), and some materials may + // be "void". + if (material_present) { + vector mats { + get_node_array(cell_node, "material", true)}; + if (mats.size() > 0) { + material_.reserve(mats.size()); + for (std::string mat : mats) { + if (mat.compare("void") == 0) { + material_.push_back(MATERIAL_VOID); + } else { + material_.push_back(std::stoi(mat)); + } + } + } else { + fatal_error(fmt::format( + "An empty material element was specified for cell {}", id_)); + } + } + + // Read the temperature element which may be distributed like materials. + if (check_for_node(cell_node, "temperature")) { + sqrtkT_ = get_node_array(cell_node, "temperature"); + sqrtkT_.shrink_to_fit(); + + // Make sure this is a material-filled cell. + if (material_.size() == 0) { + fatal_error(fmt::format( + "Cell {} was specified with a temperature but no material. Temperature" + "specification is only valid for cells filled with a material.", + id_)); + } + + // Make sure all temperatures are non-negative. + for (auto T : sqrtkT_) { + if (T < 0) { + fatal_error(fmt::format( + "Cell {} was specified with a negative temperature", id_)); + } + } + + // Convert to sqrt(k*T). + for (auto& T : sqrtkT_) { + T = std::sqrt(K_BOLTZMANN * T); + } + } + + // Read the region specification. + std::string region_spec; + if (check_for_node(cell_node, "region")) { + region_spec = get_node_value(cell_node, "region"); + } + + // Get a tokenized representation of the region specification. + region_ = tokenize(region_spec); + region_.shrink_to_fit(); + + // Convert user IDs to surface indices. + for (auto& r : region_) { + if (r < OP_UNION) { + const auto& it {model::surface_map.find(abs(r))}; + if (it == model::surface_map.end()) { + throw std::runtime_error { + "Invalid surface ID " + std::to_string(abs(r)) + + " specified in region for cell " + std::to_string(id_) + "."}; + } + r = (r > 0) ? it->second + 1 : -(it->second + 1); + } + } + + // Convert the infix region spec to RPN. + rpn_ = generate_rpn(id_, region_); + + // Check if this is a simple cell. + simple_ = true; + for (int32_t token : rpn_) { + if ((token == OP_COMPLEMENT) || (token == OP_UNION)) { + simple_ = false; + break; + } + } + + // If this cell is simple, remove all the superfluous operator tokens. + if (simple_) { + size_t i0 = 0; + size_t i1 = 0; + while (i1 < rpn_.size()) { + if (rpn_[i1] < OP_UNION) { + rpn_[i0] = rpn_[i1]; + ++i0; + } + ++i1; + } + rpn_.resize(i0); + } + rpn_.shrink_to_fit(); + + // Read the translation vector. + if (check_for_node(cell_node, "translation")) { + if (fill_ == C_NONE) { + fatal_error(fmt::format("Cannot apply a translation to cell {}" + " because it is not filled with another universe", + id_)); + } + + auto xyz {get_node_array(cell_node, "translation")}; + if (xyz.size() != 3) { + fatal_error( + fmt::format("Non-3D translation vector applied to cell {}", id_)); + } + translation_ = xyz; + } + + // Read the rotation transform. + if (check_for_node(cell_node, "rotation")) { + auto rot {get_node_array(cell_node, "rotation")}; + set_rotation(rot); + } } //============================================================================== -std::pair Region::distance( - Position r, Direction u, int32_t on_surface) const +bool CSGCell::contains(Position r, Direction u, int32_t on_surface) const +{ + if (simple_) { + return contains_simple(r, u, on_surface); + } else { + return contains_complex(r, u, on_surface); + } +} + +//============================================================================== + +std::pair CSGCell::distance( + Position r, Direction u, int32_t on_surface, Particle* p) const { double min_dist {INFTY}; int32_t i_surf {std::numeric_limits::max()}; - for (int32_t token : expression_) { + for (int32_t token : rpn_) { // Ignore this token if it corresponds to an operator rather than a region. if (token >= OP_UNION) continue; @@ -973,20 +607,144 @@ std::pair Region::distance( //============================================================================== -bool Region::contains(Position r, Direction u, int32_t on_surface) const +void CSGCell::to_hdf5_inner(hid_t group_id) const { - if (simple_) { - return contains_simple(r, u, on_surface); - } else { - return contains_complex(r, u, on_surface); + + write_string(group_id, "geom_type", "csg", false); + + // Write the region specification. + if (!region_.empty()) { + std::stringstream region_spec {}; + for (int32_t token : region_) { + if (token == OP_LEFT_PAREN) { + region_spec << " ("; + } else if (token == OP_RIGHT_PAREN) { + region_spec << " )"; + } else if (token == OP_COMPLEMENT) { + region_spec << " ~"; + } else if (token == OP_INTERSECTION) { + } else if (token == OP_UNION) { + region_spec << " |"; + } else { + // Note the off-by-one indexing + auto surf_id = model::surfaces[abs(token) - 1]->id_; + region_spec << " " << ((token > 0) ? surf_id : -surf_id); + } + } + write_string(group_id, "region", region_spec.str(), false); } } +BoundingBox CSGCell::bounding_box_simple() const +{ + BoundingBox bbox; + for (int32_t token : rpn_) { + bbox &= model::surfaces[abs(token) - 1]->bounding_box(token > 0); + } + return bbox; +} + +void CSGCell::apply_demorgan( + vector::iterator start, vector::iterator stop) +{ + while (start < stop) { + if (*start < OP_UNION) { + *start *= -1; + } else if (*start == OP_UNION) { + *start = OP_INTERSECTION; + } else if (*start == OP_INTERSECTION) { + *start = OP_UNION; + } + start++; + } +} + +vector::iterator CSGCell::find_left_parenthesis( + vector::iterator start, const vector& rpn) +{ + // start search at zero + int parenthesis_level = 0; + auto it = start; + while (it != rpn.begin()) { + // look at two tokens at a time + int32_t one = *it; + int32_t two = *(it - 1); + + // decrement parenthesis level if there are two adjacent surfaces + if (one < OP_UNION && two < OP_UNION) { + parenthesis_level--; + // increment if there are two adjacent operators + } else if (one >= OP_UNION && two >= OP_UNION) { + parenthesis_level++; + } + + // if the level gets to zero, return the position + if (parenthesis_level == 0) { + // move the iterator back one before leaving the loop + // so that all tokens in the parenthesis block are included + it--; + break; + } + + // continue loop, one token at a time + it--; + } + return it; +} + +void CSGCell::remove_complement_ops(vector& rpn) +{ + auto it = std::find(rpn.begin(), rpn.end(), OP_COMPLEMENT); + while (it != rpn.end()) { + // find the opening parenthesis (if any) + auto left = find_left_parenthesis(it, rpn); + vector tmp(left, it + 1); + + // apply DeMorgan's law to any surfaces/operators between these + // positions in the RPN + apply_demorgan(left, it); + // remove complement operator + rpn.erase(it); + // update iterator position + it = std::find(rpn.begin(), rpn.end(), OP_COMPLEMENT); + } +} + +BoundingBox CSGCell::bounding_box_complex(vector rpn) +{ + // remove complements by adjusting surface signs and operators + remove_complement_ops(rpn); + + vector stack(rpn.size()); + int i_stack = -1; + + for (auto& token : rpn) { + if (token == OP_UNION) { + stack[i_stack - 1] = stack[i_stack - 1] | stack[i_stack]; + i_stack--; + } else if (token == OP_INTERSECTION) { + stack[i_stack - 1] = stack[i_stack - 1] & stack[i_stack]; + i_stack--; + } else { + i_stack++; + stack[i_stack] = model::surfaces[abs(token) - 1]->bounding_box(token > 0); + } + } + + Ensures(i_stack == 0); + return stack.front(); +} + +BoundingBox CSGCell::bounding_box() const +{ + return simple_ ? bounding_box_simple() : bounding_box_complex(rpn_); +} + //============================================================================== -bool Region::contains_simple(Position r, Direction u, int32_t on_surface) const +bool CSGCell::contains_simple(Position r, Direction u, int32_t on_surface) const { - for (int32_t token : expression_) { + for (int32_t token : rpn_) { // Assume that no tokens are operators. Evaluate the sense of particle with // respect to the surface and see if the token matches the sense. If the // particle's surface attribute is set and matches the token, that @@ -1007,133 +765,55 @@ bool Region::contains_simple(Position r, Direction u, int32_t on_surface) const //============================================================================== -bool Region::contains_complex(Position r, Direction u, int32_t on_surface) const +bool CSGCell::contains_complex( + Position r, Direction u, int32_t on_surface) const { - bool in_cell = true; - int total_depth = 0; + // Make a stack of booleans. We don't know how big it needs to be, but we do + // know that rpn.size() is an upper-bound. + vector stack(rpn_.size()); + int i_stack = -1; - // For each token - for (auto it = expression_.begin(); it != expression_.end(); it++) { - int32_t token = *it; - - // If the token is a surface evaluate the sense - // If the token is a union or intersection check to - // short circuit - if (token < OP_UNION) { + for (int32_t token : rpn_) { + // If the token is a binary operator (intersection/union), apply it to + // the last two items on the stack. If the token is a unary operator + // (complement), apply it to the last item on the stack. + if (token == OP_UNION) { + stack[i_stack - 1] = stack[i_stack - 1] || stack[i_stack]; + i_stack--; + } else if (token == OP_INTERSECTION) { + stack[i_stack - 1] = stack[i_stack - 1] && stack[i_stack]; + i_stack--; + } else if (token == OP_COMPLEMENT) { + stack[i_stack] = !stack[i_stack]; + } else { + // If the token is not an operator, evaluate the sense of particle with + // respect to the surface and see if the token matches the sense. If the + // particle's surface attribute is set and matches the token, that + // overrides the determination based on sense(). + i_stack++; if (token == on_surface) { - in_cell = true; + stack[i_stack] = true; } else if (-token == on_surface) { - in_cell = false; + stack[i_stack] = false; } else { // Note the off-by-one indexing bool sense = model::surfaces[abs(token) - 1]->sense(r, u); - in_cell = (sense == (token > 0)); + stack[i_stack] = (sense == (token > 0)); } - } else if ((token == OP_UNION && in_cell == true) || - (token == OP_INTERSECTION && in_cell == false)) { - // If the total depth is zero return - if (total_depth == 0) { - return in_cell; - } - - total_depth--; - - // While the iterator is within the bounds of the vector - int depth = 1; - do { - // Get next token - it++; - int32_t next_token = *it; - - // If the token is an a parenthesis - if (next_token > OP_COMPLEMENT) { - // Adjust depth accordingly - if (next_token == OP_RIGHT_PAREN) { - depth--; - } else { - depth++; - } - } - } while (depth > 0); - } else if (token == OP_LEFT_PAREN) { - total_depth++; - } else if (token == OP_RIGHT_PAREN) { - total_depth--; } } - return in_cell; -} -//============================================================================== - -BoundingBox Region::bounding_box(int32_t cell_id) const -{ - if (simple_) { - return bounding_box_simple(); + if (i_stack == 0) { + // The one remaining bool on the stack indicates whether the particle is + // in the cell. + return stack[i_stack]; } else { - auto postfix = generate_postfix(cell_id); - return bounding_box_complex(postfix); + // This case occurs if there is no region specification since i_stack will + // still be -1. + return true; } } -//============================================================================== - -BoundingBox Region::bounding_box_simple() const -{ - BoundingBox bbox; - for (int32_t token : expression_) { - bbox &= model::surfaces[abs(token) - 1]->bounding_box(token > 0); - } - return bbox; -} - -//============================================================================== - -BoundingBox Region::bounding_box_complex(vector postfix) const -{ - vector stack(postfix.size()); - int i_stack = -1; - - for (auto& token : postfix) { - if (token == OP_UNION) { - stack[i_stack - 1] = stack[i_stack - 1] | stack[i_stack]; - i_stack--; - } else if (token == OP_INTERSECTION) { - stack[i_stack - 1] = stack[i_stack - 1] & stack[i_stack]; - i_stack--; - } else { - i_stack++; - stack[i_stack] = model::surfaces[abs(token) - 1]->bounding_box(token > 0); - } - } - - assert(i_stack == 0); - return stack.front(); -} - -//============================================================================== - -vector Region::surfaces() const -{ - if (simple_) { - return expression_; - } - - vector surfaces = expression_; - - auto it = std::find_if(surfaces.begin(), surfaces.end(), - [&](const auto& value) { return value >= OP_UNION; }); - - while (it != surfaces.end()) { - surfaces.erase(it); - - it = std::find_if(surfaces.begin(), surfaces.end(), - [&](const auto& value) { return value >= OP_UNION; }); - } - - return surfaces; -} - //============================================================================== // Non-method functions //============================================================================== @@ -1180,41 +860,19 @@ void read_cells(pugi::xml_node node) void populate_universes() { - // Used to map universe index to the index of an implicit complement cell for - // DAGMC universes - std::unordered_map implicit_comp_cells; - // Populate the Universe vector and map. - for (int index_cell = 0; index_cell < model::cells.size(); index_cell++) { - int32_t uid = model::cells[index_cell]->universe_; + for (int i = 0; i < model::cells.size(); i++) { + int32_t uid = model::cells[i]->universe_; auto it = model::universe_map.find(uid); if (it == model::universe_map.end()) { model::universes.push_back(make_unique()); model::universes.back()->id_ = uid; - model::universes.back()->cells_.push_back(index_cell); + model::universes.back()->cells_.push_back(i); model::universe_map[uid] = model::universes.size() - 1; } else { -#ifdef OPENMC_DAGMC_ENABLED - // Skip implicit complement cells for now - Universe* univ = model::universes[it->second].get(); - DAGUniverse* dag_univ = dynamic_cast(univ); - if (dag_univ && (dag_univ->implicit_complement_idx() == index_cell)) { - implicit_comp_cells[it->second] = index_cell; - continue; - } -#endif - - model::universes[it->second]->cells_.push_back(index_cell); + model::universes[it->second]->cells_.push_back(i); } } - - // Add DAGUniverse implicit complement cells last - for (const auto& it : implicit_comp_cells) { - int index_univ = it.first; - int index_cell = it.second; - model::universes[index_univ]->cells_.push_back(index_cell); - } - model::universes.shrink_to_fit(); } @@ -1293,24 +951,6 @@ extern "C" int openmc_cell_set_temperature( return 0; } -extern "C" int openmc_cell_set_density( - int32_t index, double density, const int32_t* instance, bool set_contained) -{ - if (index < 0 || index >= model::cells.size()) { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - int32_t instance_index = instance ? *instance : -1; - try { - model::cells[index]->set_density(density, instance_index, set_contained); - } catch (const std::exception& e) { - set_errmsg(e.what()); - return OPENMC_E_UNASSIGNED; - } - return 0; -} - extern "C" int openmc_cell_get_temperature( int32_t index, const int32_t* instance, double* T) { @@ -1329,36 +969,6 @@ extern "C" int openmc_cell_get_temperature( return 0; } -extern "C" int openmc_cell_get_density( - int32_t index, const int32_t* instance, double* density) -{ - if (index < 0 || index >= model::cells.size()) { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - int32_t instance_index = instance ? *instance : -1; - try { - if (model::cells[index]->type_ != Fill::MATERIAL) { - fatal_error( - fmt::format("Cell {}, instance {} is not filled with a material.", - model::cells[index]->id_, instance_index)); - } - - int32_t mat_index = model::cells[index]->material(instance_index); - if (mat_index == MATERIAL_VOID) { - *density = 0.0; - } else { - *density = model::cells[index]->density_mult(instance_index) * - model::materials[mat_index]->density_gpcc(); - } - } catch (const std::exception& e) { - set_errmsg(e.what()); - return OPENMC_E_UNASSIGNED; - } - return 0; -} - //! Get the bounding box of a cell extern "C" int openmc_cell_bounding_box( const int32_t index, double* llc, double* urc) @@ -1370,14 +980,14 @@ extern "C" int openmc_cell_bounding_box( bbox = c->bounding_box(); // set lower left corner values - llc[0] = bbox.min.x; - llc[1] = bbox.min.y; - llc[2] = bbox.min.z; + llc[0] = bbox.xmin; + llc[1] = bbox.ymin; + llc[2] = bbox.zmin; // set upper right corner values - urc[0] = bbox.max.x; - urc[1] = bbox.max.y; - urc[2] = bbox.max.z; + urc[0] = bbox.xmax; + urc[1] = bbox.ymax; + urc[2] = bbox.zmax; return 0; } @@ -1427,8 +1037,8 @@ struct ParentCell { lattice_index < other.lattice_index); } - int64_t cell_index; - int64_t lattice_index; + gsl::index cell_index; + gsl::index lattice_index; }; //! Structure used to insert ParentCell into hashed STL data structures @@ -1480,9 +1090,6 @@ struct ParentCellStack { //! compute an instance for the provided distribcell index int32_t compute_instance(int32_t distribcell_index) const { - if (distribcell_index == C_NONE) - return 0; - int32_t instance = 0; for (const auto& parent_cell : this->parent_cells_) { auto& cell = model::cells[parent_cell.cell_index]; @@ -1508,11 +1115,10 @@ struct ParentCellStack { }; vector Cell::find_parent_cells( - int32_t instance, const Position& r) const -{ + int32_t instance, const Position& r) const { // create a temporary particle - GeometryState dummy_particle {}; + Particle dummy_particle {}; dummy_particle.r() = r; dummy_particle.u() = {0., 0., 1.}; @@ -1520,8 +1126,7 @@ vector Cell::find_parent_cells( } vector Cell::find_parent_cells( - int32_t instance, GeometryState& p) const -{ + int32_t instance, Particle& p) const { // look up the particle's location exhaustive_find_cell(p); const auto& coords = p.coord(); @@ -1531,10 +1136,9 @@ vector Cell::find_parent_cells( bool cell_found = false; for (auto it = coords.begin(); it != coords.end(); it++) { const auto& coord = *it; - const auto& cell = model::cells[coord.cell()]; - // if the cell at this level matches the current cell, stop adding to the - // stack - if (coord.cell() == model::cell_map[this->id_]) { + const auto& cell = model::cells[coord.cell]; + // if the cell at this level matches the current cell, stop adding to the stack + if (coord.cell == model::cell_map[this->id_]) { cell_found = true; break; } @@ -1544,17 +1148,15 @@ vector Cell::find_parent_cells( int lattice_idx = C_NONE; if (cell->type_ == Fill::LATTICE) { const auto& next_coord = *(it + 1); - lattice_idx = model::lattices[next_coord.lattice()]->get_flat_index( - next_coord.lattice_index()); + lattice_idx = model::lattices[next_coord.lattice]->get_flat_index(next_coord.lattice_i); } - stack.push(coord.universe(), {coord.cell(), lattice_idx}); + stack.push(coord.universe, {coord.cell, lattice_idx}); } // if this loop finished because the cell was found and // the instance matches the one requested in the call // we have the correct path and can return the stack - if (cell_found && - stack.compute_instance(this->distribcell_index_) == instance) { + if (cell_found && stack.compute_instance(this->distribcell_index_) == instance) { return stack.parent_cells(); } @@ -1562,7 +1164,9 @@ vector Cell::find_parent_cells( return exhaustive_find_parent_cells(instance); } -vector Cell::exhaustive_find_parent_cells(int32_t instance) const + +vector Cell::exhaustive_find_parent_cells( + int32_t instance) const { ParentCellStack stack; // start with this cell's universe @@ -1835,7 +1439,7 @@ extern "C" int openmc_cell_get_num_instances( set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } - *num_instances = model::cells[index]->n_instances(); + *num_instances = model::cells[index]->n_instances_; return 0; } diff --git a/src/chain.cpp b/src/chain.cpp deleted file mode 100644 index 3915c016c..000000000 --- a/src/chain.cpp +++ /dev/null @@ -1,131 +0,0 @@ -//! \file chain.cpp -//! \brief Depletion chain and associated information - -#include "openmc/chain.h" - -#include // for getenv -#include // for make_unique -#include // for stod - -#include -#include - -#include "openmc/distribution.h" // for distribution_from_xml -#include "openmc/error.h" -#include "openmc/reaction.h" -#include "openmc/xml_interface.h" // for get_node_value - -namespace openmc { - -//============================================================================== -// ChainNuclide implementation -//============================================================================== - -ChainNuclide::ChainNuclide(pugi::xml_node node) -{ - name_ = get_node_value(node, "name"); - if (check_for_node(node, "half_life")) { - half_life_ = std::stod(get_node_value(node, "half_life")); - } - if (check_for_node(node, "decay_energy")) { - decay_energy_ = std::stod(get_node_value(node, "decay_energy")); - } - - // Read reactions to store MT -> product map - for (pugi::xml_node reaction_node : node.children("reaction")) { - std::string rx_name = get_node_value(reaction_node, "type"); - if (!reaction_node.attribute("target")) - continue; - std::string rx_target = get_node_value(reaction_node, "target"); - double branching_ratio = 1.0; - if (reaction_node.attribute("branching_ratio")) { - branching_ratio = - std::stod(get_node_value(reaction_node, "branching_ratio")); - } - int mt = reaction_mt(rx_name); - reaction_products_[mt].push_back({rx_target, branching_ratio}); - } - - for (pugi::xml_node source_node : node.children("source")) { - auto particle = get_node_value(source_node, "particle"); - if (particle == "photon") { - photon_energy_ = distribution_from_xml(source_node); - break; - } - } - - // Set entry in mapping - data::chain_nuclide_map[name_] = data::chain_nuclides.size(); -} - -ChainNuclide::~ChainNuclide() -{ - data::chain_nuclide_map.erase(name_); -} - -//============================================================================== -// DecayPhotonAngleEnergy implementation -//============================================================================== - -void DecayPhotonAngleEnergy::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - E_out = photon_energy_->sample(seed).first; - mu = Uniform(-1., 1.).sample(seed).first; -} - -double DecayPhotonAngleEnergy::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - E_out = photon_energy_->sample(seed).first; - return 0.5; -} - -//============================================================================== -// Global variables -//============================================================================== - -namespace data { - -std::unordered_map chain_nuclide_map; -vector> chain_nuclides; - -} // namespace data - -//============================================================================== -// Non-member functions -//============================================================================== - -void read_chain_file_xml() -{ - free_memory_chain(); - - char* chain_file_path = std::getenv("OPENMC_CHAIN_FILE"); - if (!chain_file_path) { - return; - } - - write_message(5, "Reading chain file: {}...", chain_file_path); - - pugi::xml_document doc; - auto result = doc.load_file(chain_file_path); - if (!result) { - fatal_error( - fmt::format("Error processing chain file: {}", chain_file_path)); - } - - // Get root element - pugi::xml_node root = doc.document_element(); - - for (auto node : root.children("nuclide")) { - data::chain_nuclides.push_back(std::make_unique(node)); - } -} - -void free_memory_chain() -{ - data::chain_nuclides.clear(); - data::chain_nuclide_map.clear(); -} - -} // namespace openmc diff --git a/src/cmfd_solver.cpp b/src/cmfd_solver.cpp index 714a5bf3a..943042f67 100644 --- a/src/cmfd_solver.cpp +++ b/src/cmfd_solver.cpp @@ -5,7 +5,7 @@ #ifdef _OPENMP #include #endif -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include "openmc/bank.h" #include "openmc/capi.h" @@ -36,7 +36,7 @@ double spectral; int nx, ny, nz, ng; -tensor::Tensor indexmap; +xt::xtensor indexmap; int use_all_threads; @@ -79,14 +79,15 @@ int get_cmfd_energy_bin(const double E) // COUNT_BANK_SITES bins fission sites according to CMFD mesh and energy //============================================================================== -tensor::Tensor count_bank_sites( - tensor::Tensor& bins, bool* outside) +xt::xtensor count_bank_sites( + xt::xtensor& bins, bool* outside) { // Determine shape of array for counts std::size_t cnt_size = cmfd::nx * cmfd::ny * cmfd::nz * cmfd::ng; + vector cnt_shape = {cnt_size}; // Create array of zeros - tensor::Tensor cnt = tensor::zeros({cnt_size}); + xt::xarray cnt {cnt_shape, 0.0}; bool outside_ = false; auto bank_size = simulation::source_bank.size(); @@ -112,22 +113,29 @@ tensor::Tensor count_bank_sites( bins[i] = mesh_bin * cmfd::ng + energy_bin; } + // Create copy of count data. Since ownership will be acquired by xtensor, + // std::allocator must be used to avoid Valgrind mismatched free() / delete + // warnings. int total = cnt.size(); - tensor::Tensor counts = tensor::zeros({cnt_size}); + double* cnt_reduced = std::allocator {}.allocate(total); #ifdef OPENMC_MPI // collect values from all processors MPI_Reduce( - cnt.data(), counts.data(), total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); + cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); // Check if there were sites outside the mesh for any processor MPI_Reduce(&outside_, outside, 1, MPI_C_BOOL, MPI_LOR, 0, mpi::intracomm); #else - std::copy(cnt.data(), cnt.data() + total, counts.data()); + std::copy(cnt.data(), cnt.data() + total, cnt_reduced); *outside = outside_; #endif + // Adapt reduced values in array back into an xarray + auto arr = xt::adapt(cnt_reduced, total, xt::acquire_ownership(), cnt_shape); + xt::xarray counts = arr; + return counts; } @@ -143,19 +151,19 @@ extern "C" void openmc_cmfd_reweight( std::size_t src_size = cmfd::nx * cmfd::ny * cmfd::nz * cmfd::ng; // count bank sites for CMFD mesh, store bins in bank_bins for reweighting - tensor::Tensor bank_bins = tensor::zeros({bank_size}); + xt::xtensor bank_bins({bank_size}, 0); bool sites_outside; - tensor::Tensor sourcecounts = + xt::xtensor sourcecounts = count_bank_sites(bank_bins, &sites_outside); // Compute CMFD weightfactors - tensor::Tensor weightfactors = tensor::ones({src_size}); + xt::xtensor weightfactors = xt::xtensor({src_size}, 1.); if (mpi::master) { if (sites_outside) { fatal_error("Source sites outside of the CMFD mesh"); } - double norm = sourcecounts.sum() / cmfd::norm; + double norm = xt::sum(sourcecounts)() / cmfd::norm; for (int i = 0; i < src_size; i++) { if (sourcecounts[i] > 0 && cmfd_src[i] > 0) { weightfactors[i] = cmfd_src[i] * norm / sourcecounts[i]; @@ -553,7 +561,7 @@ void free_memory_cmfd() cmfd::indices.clear(); cmfd::egrid.clear(); - // Resize tensors to be empty + // Resize xtensors to be empty cmfd::indexmap.resize({0}); // Set pointers to null diff --git a/src/collision_track.cpp b/src/collision_track.cpp deleted file mode 100644 index 2e749007f..000000000 --- a/src/collision_track.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "openmc/collision_track.h" - -#include -#include - -#include - -#include "openmc/bank.h" -#include "openmc/bank_io.h" -#include "openmc/cell.h" -#include "openmc/constants.h" -#include "openmc/error.h" -#include "openmc/file_utils.h" -#include "openmc/hdf5_interface.h" -#include "openmc/material.h" -#include "openmc/mcpl_interface.h" -#include "openmc/message_passing.h" -#include "openmc/nuclide.h" -#include "openmc/output.h" -#include "openmc/particle.h" -#include "openmc/settings.h" -#include "openmc/simulation.h" -#include "openmc/universe.h" - -#ifdef OPENMC_MPI -#include -#endif - -namespace openmc { - -namespace { - -hid_t h5_collision_track_banktype() -{ - hid_t postype = H5Tcreate(H5T_COMPOUND, sizeof(Position)); - H5Tinsert(postype, "x", HOFFSET(Position, x), H5T_NATIVE_DOUBLE); - H5Tinsert(postype, "y", HOFFSET(Position, y), H5T_NATIVE_DOUBLE); - H5Tinsert(postype, "z", HOFFSET(Position, z), H5T_NATIVE_DOUBLE); - - hid_t banktype = H5Tcreate(H5T_COMPOUND, sizeof(CollisionTrackSite)); - - H5Tinsert(banktype, "r", HOFFSET(CollisionTrackSite, r), postype); - H5Tinsert(banktype, "u", HOFFSET(CollisionTrackSite, u), postype); - H5Tinsert(banktype, "E", HOFFSET(CollisionTrackSite, E), H5T_NATIVE_DOUBLE); - H5Tinsert(banktype, "dE", HOFFSET(CollisionTrackSite, dE), H5T_NATIVE_DOUBLE); - H5Tinsert( - banktype, "time", HOFFSET(CollisionTrackSite, time), H5T_NATIVE_DOUBLE); - H5Tinsert( - banktype, "wgt", HOFFSET(CollisionTrackSite, wgt), H5T_NATIVE_DOUBLE); - H5Tinsert(banktype, "event_mt", HOFFSET(CollisionTrackSite, event_mt), - H5T_NATIVE_INT); - H5Tinsert(banktype, "delayed_group", - HOFFSET(CollisionTrackSite, delayed_group), H5T_NATIVE_INT); - H5Tinsert( - banktype, "cell_id", HOFFSET(CollisionTrackSite, cell_id), H5T_NATIVE_INT); - H5Tinsert(banktype, "nuclide_id", HOFFSET(CollisionTrackSite, nuclide_id), - H5T_NATIVE_INT); - H5Tinsert(banktype, "material_id", HOFFSET(CollisionTrackSite, material_id), - H5T_NATIVE_INT); - H5Tinsert(banktype, "universe_id", HOFFSET(CollisionTrackSite, universe_id), - H5T_NATIVE_INT); - H5Tinsert(banktype, "n_collision", HOFFSET(CollisionTrackSite, n_collision), - H5T_NATIVE_INT); - H5Tinsert(banktype, "particle", HOFFSET(CollisionTrackSite, particle), - H5T_NATIVE_INT); - H5Tinsert(banktype, "parent_id", HOFFSET(CollisionTrackSite, parent_id), - H5T_NATIVE_INT64); - H5Tinsert(banktype, "progeny_id", HOFFSET(CollisionTrackSite, progeny_id), - H5T_NATIVE_INT64); - H5Tclose(postype); - return banktype; -} - -void write_collision_track_bank(hid_t group_id, - openmc::span collision_track_bank, - const openmc::vector& bank_index) -{ - hid_t banktype = h5_collision_track_banktype(); -#ifdef OPENMC_MPI - write_bank_dataset("collision_track_bank", group_id, collision_track_bank, - bank_index, banktype, banktype, mpi::collision_track_site); -#else - write_bank_dataset("collision_track_bank", group_id, collision_track_bank, - bank_index, banktype, banktype); -#endif - - H5Tclose(banktype); -} - -void write_h5_collision_track(const char* filename, - openmc::span collision_track_bank, - const openmc::vector& bank_index) -{ -#ifdef PHDF5 - bool parallel = true; -#else - bool parallel = false; -#endif - - if (!filename) - fatal_error("write_h5_collision_track filename needs a nonempty name."); - - std::string filename_(filename); - const auto extension = get_file_extension(filename_); - if (extension.empty()) { - filename_.append(".h5"); - } else if (extension != "h5") { - warning("write_h5_collision_track was passed a file extension differing " - "from .h5, but an hdf5 file will be written."); - } - - hid_t file_id; - if (mpi::master || parallel) { - file_id = file_open(filename_.c_str(), 'w', true); - - // Write filetype and version info - write_attribute(file_id, "filetype", "collision_track"); - write_attribute(file_id, "version", VERSION_COLLISION_TRACK); - } - - write_collision_track_bank(file_id, collision_track_bank, bank_index); - - if (mpi::master || parallel) - file_close(file_id); -} - -} // namespace - -bool should_record_event(int id_cell, int mt_event, const std::string& nuclide, - int id_universe, int id_material, double energy_loss) -{ - auto matches_filter = [](const auto& filter_set, const auto& value) { - return filter_set.empty() || filter_set.count(value) > 0; - }; - - const auto& cfg = settings::collision_track_config; - return simulation::current_batch > settings::n_inactive && - !simulation::collision_track_bank.full() && - matches_filter(cfg.cell_ids, id_cell) && - matches_filter(cfg.mt_numbers, mt_event) && - matches_filter(cfg.universe_ids, id_universe) && - matches_filter(cfg.material_ids, id_material) && - matches_filter(cfg.nuclides, nuclide) && - (cfg.deposited_energy_threshold == 0 || - cfg.deposited_energy_threshold < energy_loss); -} - -void collision_track_reserve_bank() -{ - simulation::collision_track_bank.reserve( - settings::collision_track_config.max_collisions); -} - -void collision_track_flush_bank() -{ - const auto& cfg = settings::collision_track_config; - if (simulation::ct_current_file > cfg.max_files) - return; - - bool last_batch = (simulation::current_batch == settings::n_batches); - if (!simulation::collision_track_bank.full() && !last_batch) - return; - - auto size = simulation::collision_track_bank.size(); - if (size == 0 && !last_batch) - return; - - auto collision_track_work_index = mpi::calculate_parallel_index_vector(size); - openmc::span collisiontrackbankspan( - simulation::collision_track_bank.begin(), size); - - std::string ext = cfg.mcpl_write ? "mcpl" : "h5"; - auto filename = fmt::format("{}collision_track.{}.{}", settings::path_output, - simulation::ct_current_file, ext); - - if (cfg.max_files == 1 || (simulation::ct_current_file == 1 && last_batch)) { - filename = settings::path_output + "collision_track." + ext; - } - write_message("Creating {}...", filename, 4); - - if (cfg.mcpl_write) { - write_mcpl_collision_track( - filename.c_str(), collisiontrackbankspan, collision_track_work_index); - } else { - write_h5_collision_track( - filename.c_str(), collisiontrackbankspan, collision_track_work_index); - } - - simulation::collision_track_bank.clear(); - if (!last_batch && cfg.max_files >= 1) { - collision_track_reserve_bank(); - } - ++simulation::ct_current_file; -} - -void collision_track_record(Particle& particle) -{ - int cell_index = particle.lowest_coord().cell(); - if (cell_index == C_NONE) - return; - - int cell_id = model::cells[cell_index]->id_; - std::string nuclide {}; - int nuclide_id = 0; - if (particle.event_nuclide() != NUCLIDE_NONE) { - const auto* nuclide_ptr = data::nuclides[particle.event_nuclide()].get(); - nuclide = nuclide_ptr->name_; - nuclide_id = nuclide_ptr->particle_type().pdg_number(); - } - int universe_id = model::universes[particle.lowest_coord().universe()]->id_; - double delta_E = particle.E_last() - particle.E(); - int material_index = particle.material(); - if (material_index == C_NONE) - return; - - int material_id = model::materials[material_index]->id_; - - if (!should_record_event(cell_id, particle.event_mt(), nuclide, universe_id, - material_id, delta_E)) - return; - - CollisionTrackSite site; - site.r = particle.r(); - site.u = particle.u(); - site.E = particle.E_last(); - site.dE = delta_E; - site.time = particle.time(); - site.wgt = particle.wgt(); - site.event_mt = particle.event_mt(); - site.delayed_group = particle.delayed_group(); - site.cell_id = cell_id; - site.nuclide_id = nuclide_id; - site.material_id = material_id; - site.universe_id = universe_id; - site.n_collision = particle.n_collision(); - site.particle = particle.type(); - site.parent_id = particle.id(); - site.progeny_id = particle.n_progeny(); - simulation::collision_track_bank.thread_safe_append(site); -} - -} // namespace openmc diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index ec9da5b8a..afb0a1f36 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -23,7 +23,6 @@ #include "pugixml.hpp" #include // for getenv -#include #include namespace openmc { @@ -105,11 +104,6 @@ void read_cross_sections_xml() auto root = doc.document_element(); - read_cross_sections_xml(root); -} - -void read_cross_sections_xml(pugi::xml_node root) -{ // Find cross_sections.xml file -- the first place to look is the // materials.xml file. If no file is found there, then we check the // OPENMC_CROSS_SECTIONS environment variable @@ -254,7 +248,7 @@ void read_ce_cross_sections(const vector>& nuc_temps, if (settings::photon_transport && settings::electron_treatment == ElectronTreatment::TTB) { // Take logarithm of energies since they are log-log interpolated - data::ttb_e_grid = tensor::log(data::ttb_e_grid); + data::ttb_e_grid = xt::log(data::ttb_e_grid); } // Show minimum/maximum temperature @@ -283,15 +277,10 @@ void read_ce_cross_sections(const vector>& nuc_temps, void read_ce_cross_sections_xml() { // Check if cross_sections.xml exists - std::filesystem::path filename(settings::path_cross_sections); - if (!std::filesystem::exists(filename)) { - fatal_error( - "Cross sections XML file '" + filename.string() + "' does not exist."); - } - - if (std::filesystem::is_directory(filename)) { - fatal_error("OPENMC_CROSS_SECTIONS is set to a directory. " - "It should be set to an XML file."); + const auto& filename = settings::path_cross_sections; + if (!file_exists(filename)) { + // Could not find cross_sections.xml file + fatal_error("Cross sections XML file '" + filename + "' does not exist."); } write_message("Reading cross sections XML file...", 5); @@ -311,10 +300,15 @@ void read_ce_cross_sections_xml() } else { // If no directory is listed in cross_sections.xml, by default select the // directory in which the cross_sections.xml file resides - if (filename.has_parent_path()) { - directory = filename.parent_path().string(); - } else { + + // TODO: Use std::filesystem functionality when C++17 is adopted + auto pos = filename.rfind("/"); + if (pos == std::string::npos) { + // No '\\' found, so the file must be in the same directory as + // materials.xml directory = settings::path_input; + } else { + directory = filename.substr(0, pos); } } diff --git a/src/dagmc.cpp b/src/dagmc.cpp index a5cc71b52..0e04869fd 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -1,7 +1,5 @@ #include "openmc/dagmc.h" -#include - #include "openmc/constants.h" #include "openmc/container_util.h" #include "openmc/error.h" @@ -13,34 +11,27 @@ #include "openmc/settings.h" #include "openmc/string_utils.h" -#ifdef OPENMC_UWUW_ENABLED +#ifdef DAGMC #include "uwuw.hpp" #endif #include #include -#include #include #include #include namespace openmc { -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC const bool DAGMC_ENABLED = true; #else const bool DAGMC_ENABLED = false; #endif -#ifdef OPENMC_UWUW_ENABLED -const bool UWUW_ENABLED = true; -#else -const bool UWUW_ENABLED = false; -#endif - } // namespace openmc -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC namespace openmc { @@ -50,10 +41,6 @@ namespace openmc { DAGUniverse::DAGUniverse(pugi::xml_node node) { - MaterialOverrides material_overrides; - TemperatureOverrides temperature_overrides; - DensityOverrides density_overrides; - if (check_for_node(node, "id")) { id_ = std::stoi(get_node_value(node, "id")); } else { @@ -62,9 +49,8 @@ DAGUniverse::DAGUniverse(pugi::xml_node node) if (check_for_node(node, "filename")) { filename_ = get_node_value(node, "filename"); - if (!starts_with(filename_, "/")) { - std::filesystem::path d(dir_name(settings::path_input)); - filename_ = (d / filename_).string(); + if (!file_exists(filename_)) { + fatal_error(fmt::format("DAGMC file '{}' could not be found", filename_)); } } else { fatal_error("Must specify a file for the DAGMC universe"); @@ -80,77 +66,7 @@ DAGUniverse::DAGUniverse(pugi::xml_node node) adjust_material_ids_ = get_node_value_bool(node, "auto_mat_ids"); } - // Get material assignment overrides from nested DAGMC cell elements. - if (node.child("cell")) { - for (pugi::xml_node cell_node : node.children("cell")) { - if (!check_for_node(cell_node, "id")) { - fatal_error( - "Must specify id for each DAGMC cell override in ."); - } - - int32_t cell_id = std::stoi(get_node_value(cell_node, "id")); - - if (check_for_node(cell_node, "region")) { - fatal_error(fmt::format( - "DAGMC cell {} override cannot specify a region.", cell_id)); - } - if (check_for_node(cell_node, "fill")) { - fatal_error(fmt::format( - "DAGMC cell {} override currently only supports material fills.", - cell_id)); - } - if (check_for_node(cell_node, "universe")) { - fatal_error(fmt::format( - "DAGMC cell {} override cannot specify a universe.", cell_id)); - } - if (check_for_node(cell_node, "translation") || - check_for_node(cell_node, "rotation")) { - fatal_error(fmt::format( - "DAGMC cell {} override does not support translation or rotation.", - cell_id)); - } - if (!check_for_node(cell_node, "material")) { - fatal_error(fmt::format( - "DAGMC cell {} override must specify material.", cell_id)); - } - - auto inserted = material_overrides.emplace( - cell_id, parse_cell_material_xml(cell_node, cell_id)); - if (!inserted.second) { - fatal_error(fmt::format( - "Duplicate DAGMC cell override specified for cell {}", cell_id)); - } - - if (check_for_node(cell_node, "temperature")) { - temperature_overrides.emplace( - cell_id, parse_cell_temperature_xml(cell_node, cell_id)); - } - - if (check_for_node(cell_node, "density")) { - density_overrides.emplace( - cell_id, parse_cell_density_xml(cell_node, cell_id)); - } - } - } else if (check_for_node(node, "material_overrides")) { - if (node.child("cell")) { - fatal_error("DAGMCUniverse cannot specify both and " - " sub-elements. Use elements only."); - } - warning("DAGMCUniverse is deprecated. Use nested " - " elements under instead."); - for (pugi::xml_node co : - node.child("material_overrides").children("cell_override")) { - int32_t cell_id = std::stoi(get_node_value(co, "id")); - std::istringstream iss(co.child("material_ids").text().get()); - vector mats; - for (std::string s; iss >> s;) { - mats.push_back(s == "void" ? MATERIAL_VOID : std::stoi(s)); - } - material_overrides.emplace(cell_id, mats); - } - } - - initialize(material_overrides, temperature_overrides, density_overrides); + initialize(); } DAGUniverse::DAGUniverse( @@ -167,12 +83,10 @@ DAGUniverse::DAGUniverse(std::shared_ptr dagmc_ptr, : dagmc_instance_(dagmc_ptr), filename_(filename), adjust_geometry_ids_(auto_geom_ids), adjust_material_ids_(auto_mat_ids) { - MaterialOverrides material_overrides; - TemperatureOverrides temperature_overrides; - DensityOverrides density_overrides; set_id(); init_metadata(); - init_geometry(material_overrides, temperature_overrides, density_overrides); + read_uwuw_materials(); + init_geometry(); } void DAGUniverse::set_id() @@ -191,25 +105,15 @@ void DAGUniverse::set_id() void DAGUniverse::initialize() { - MaterialOverrides material_overrides; - TemperatureOverrides temperature_overrides; - initialize(material_overrides, temperature_overrides); -} - -void DAGUniverse::initialize(const MaterialOverrides& material_overrides, - const TemperatureOverrides& temperature_overrides, - const DensityOverrides& density_overrides) -{ -#ifdef OPENMC_UWUW_ENABLED - // read uwuw materials from the .h5m file if present - read_uwuw_materials(); -#endif + geom_type() = GeometryType::DAG; init_dagmc(); init_metadata(); - init_geometry(material_overrides, temperature_overrides, density_overrides); + read_uwuw_materials(); + + init_geometry(); } void DAGUniverse::init_dagmc() @@ -219,6 +123,7 @@ void DAGUniverse::init_dagmc() dagmc_instance_ = std::make_shared(); // load the DAGMC geometry + filename_ = settings::path_input + filename_; if (!file_exists(filename_)) { fatal_error("Geometry DAGMC file '" + filename_ + "' does not exist!"); } @@ -245,9 +150,7 @@ void DAGUniverse::init_metadata() MB_CHK_ERR_CONT(rval); } -void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, - const TemperatureOverrides& temperature_overrides, - const DensityOverrides& density_overrides) +void DAGUniverse::init_geometry() { moab::ErrorCode rval; @@ -273,21 +176,17 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, : dagmc_instance_->id_by_index(3, c->dag_index()); c->universe_ = this->id_; c->fill_ = C_NONE; // no fill, single universe - if (dagmc_instance_->is_implicit_complement(vol_handle)) { - c->name_ = "implicit complement"; - } auto in_map = model::cell_map.find(c->id_); if (in_map == model::cell_map.end()) { model::cell_map[c->id_] = model::cells.size(); } else { warning(fmt::format("DAGMC Cell IDs: {}", dagmc_ids_for_dim(3))); - fatal_error(fmt::format( - "DAGMC Universe {} contains a cell with ID {}, which " - "already exists elsewhere in the geometry. Setting auto_geom_ids " - "to True when initiating the DAGMC Universe may " - "resolve this issue", - this->id_, c->id_)); + fatal_error(fmt::format("Cell ID {} exists in both DAGMC Universe {} " + "and the CSG geometry. Setting auto_geom_ids " + "to True when initiating the DAGMC Universe may " + "resolve this issue", + c->id_, this->id_)); } // --- Materials --- @@ -304,68 +203,28 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, if (mat_str == "graveyard") { graveyard = vol_handle; } - if (material_overrides.count(c->id_)) { - override_assign_material(c, material_overrides); - } else if (mat_str == "void" || mat_str == "vacuum" || - mat_str == "graveyard") { + + // material void checks + if (mat_str == "void" || mat_str == "vacuum" || mat_str == "graveyard") { c->material_.push_back(MATERIAL_VOID); - } else if (uses_uwuw()) { - uwuw_assign_material(vol_handle, c); } else { - legacy_assign_material(mat_str, c); - } - - if (temperature_overrides.count(c->id_)) { - if (c->material_.empty() || c->material_[0] == MATERIAL_VOID) { - fatal_error(fmt::format("DAGMC cell {} was specified with a " - "temperature but no non-void material.", - c->id_)); - } - - c->sqrtkT_.clear(); - const auto& temp_overrides = temperature_overrides.at(c->id_); - c->sqrtkT_.reserve(temp_overrides.size()); - for (auto T : temp_overrides) { - c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T)); - } - - if (settings::verbosity >= 10) { - std::stringstream override_values; - for (size_t i = 0; i < temp_overrides.size(); ++i) { - if (i > 0) { - override_values << " "; - } - override_values << temp_overrides[i]; + if (uses_uwuw()) { + // lookup material in uwuw if present + std::string uwuw_mat = + dmd_ptr->volume_material_property_data_eh[vol_handle]; + if (uwuw_->material_library.count(uwuw_mat) != 0) { + // Note: material numbers are set by UWUW + int mat_number = uwuw_->material_library.get_material(uwuw_mat) + .metadata["mat_number"] + .asInt(); + c->material_.push_back(mat_number); + } else { + fatal_error(fmt::format("Material with value '{}' not found in the " + "UWUW material library", + mat_str)); } - auto msg = fmt::format("Overriding DAGMC cell {} property " - "'temperature [K]' with value(s): {}", - c->id_, override_values.str()); - write_message(msg, 10); - } - } - - if (density_overrides.count(c->id_)) { - if (c->material_.empty() || c->material_[0] == MATERIAL_VOID) { - fatal_error(fmt::format("DAGMC cell {} was specified with a density " - "but no non-void material.", - c->id_)); - } - // density_mult_ holds the true density until materials are finalized, - // at which point it is converted to a proper multiplier (same as CSG). - c->density_mult_ = density_overrides.at(c->id_); - - if (settings::verbosity >= 10) { - const auto& dens = density_overrides.at(c->id_); - std::stringstream override_values; - for (size_t i = 0; i < dens.size(); ++i) { - if (i > 0) - override_values << " "; - override_values << dens[i]; - } - write_message(fmt::format("Overriding DAGMC cell {} property " - "'density [g/cm³]' with value(s): {}", - c->id_, override_values.str()), - 10); + } else { + legacy_assign_material(mat_str, c); } } @@ -378,21 +237,18 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, continue; } - // assign cell temperature if not explicitly overridden - if (c->sqrtkT_.empty()) { - const auto& mat = - model::materials[model::material_map.at(c->material_[0])]; - if (dagmc_instance_->has_prop(vol_handle, "temp")) { - rval = dagmc_instance_->prop_value(vol_handle, "temp", temp_value); - MB_CHK_ERR_CONT(rval); - double temp = std::stod(temp_value); - c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp)); - } else if (mat->temperature() > 0.0) { - c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature())); - } else { - c->sqrtkT_.push_back( - std::sqrt(K_BOLTZMANN * settings::temperature_default)); - } + // assign cell temperature + const auto& mat = model::materials[model::material_map.at(c->material_[0])]; + if (dagmc_instance_->has_prop(vol_handle, "temp")) { + rval = dagmc_instance_->prop_value(vol_handle, "temp", temp_value); + MB_CHK_ERR_CONT(rval); + double temp = std::stod(temp_value); + c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp)); + } else if (mat->temperature() > 0.0) { + c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature())); + } else { + c->sqrtkT_.push_back( + std::sqrt(K_BOLTZMANN * settings::temperature_default)); } model::cells.emplace_back(std::move(c)); @@ -424,12 +280,6 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, s->id_ = adjust_geometry_ids_ ? next_surf_id++ : dagmc_instance_->id_by_index(2, i + 1); - // set surface source attribute if needed - if (contains(settings::source_write_surf_id, s->id_) || - settings::source_write_surf_id.empty()) { - s->surf_source_ = true; - } - // set BCs std::string bc_value = dmd_ptr->get_surface_property("boundary", surf_handle); @@ -438,10 +288,10 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, bc_value == "transmission") { // set to transmission by default (nullptr) } else if (bc_value == "vacuum") { - s->bc_ = make_unique(); + s->bc_ = std::make_shared(); } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { - s->bc_ = make_unique(); + s->bc_ = std::make_shared(); } else if (bc_value == "periodic") { fatal_error("Periodic boundary condition not supported in DAGMC."); } else { @@ -459,7 +309,7 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, // if this surface belongs to the graveyard if (graveyard && parent_vols.find(graveyard) != parent_vols.end()) { // set graveyard surface BC's to vacuum - s->bc_ = make_unique(); + s->bc_ = std::make_shared(); } // add to global array and map @@ -478,20 +328,6 @@ void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides, } // end surface loop } -int32_t DAGUniverse::cell_index(moab::EntityHandle vol) const -{ - // return the index of the volume in the DAGMC instance and then - // adjust by the offset into the model cells for this DAGMC universe - return dagmc_ptr()->index_by_handle(vol) + cell_idx_offset_; -} - -int32_t DAGUniverse::surface_index(moab::EntityHandle surf) const -{ - // return the index of the surface in the DAGMC instance and then - // adjust by the offset into the model cells for this DAGMC universe - return dagmc_ptr()->index_by_handle(surf) + surf_idx_offset_; -} - std::string DAGUniverse::dagmc_ids_for_dim(int dim) const { // generate a vector of ids @@ -553,13 +389,13 @@ int32_t DAGUniverse::implicit_complement_idx() const return cell_idx_offset_ + dagmc_instance_->index_by_handle(ic) - 1; } -bool DAGUniverse::find_cell(GeometryState& p) const +bool DAGUniverse::find_cell(Particle& p) const { // if the particle isn't in any of the other DagMC // cells, place it in the implicit complement bool found = Universe::find_cell(p); if (!found && model::universe_map[this->id_] != model::root_universe) { - p.lowest_coord().cell() = implicit_complement_idx(); + p.coord(p.n_coord() - 1).cell = implicit_complement_idx(); found = true; } return found; @@ -585,16 +421,11 @@ void DAGUniverse::to_hdf5(hid_t universes_group) const bool DAGUniverse::uses_uwuw() const { -#ifdef OPENMC_UWUW_ENABLED return uwuw_ && !uwuw_->material_library.empty(); -#else - return false; -#endif // OPENMC_UWUW_ENABLED } std::string DAGUniverse::get_uwuw_materials_xml() const { -#ifdef OPENMC_UWUW_ENABLED if (!uses_uwuw()) { throw std::runtime_error("This DAGMC Universe does not use UWUW materials"); } @@ -612,14 +443,10 @@ std::string DAGUniverse::get_uwuw_materials_xml() const ss << ""; return ss.str(); -#else - fatal_error("DAGMC was not configured with UWUW."); -#endif // OPENMC_UWUW_ENABLED } void DAGUniverse::write_uwuw_materials_xml(const std::string& outfile) const { -#ifdef OPENMC_UWUW_ENABLED if (!uses_uwuw()) { throw std::runtime_error( "This DAGMC universe does not use UWUW materials."); @@ -630,9 +457,6 @@ void DAGUniverse::write_uwuw_materials_xml(const std::string& outfile) const std::ofstream mats_xml(outfile); mats_xml << xml_str; mats_xml.close(); -#else - fatal_error("DAGMC was not configured with UWUW."); -#endif // OPENMC_UWUW_ENABLED } void DAGUniverse::legacy_assign_material( @@ -662,21 +486,13 @@ void DAGUniverse::legacy_assign_material( // if no material was set using a name, assign by id if (!mat_found_by_name) { - bool found_by_id = true; try { auto id = std::stoi(mat_string); - if (model::material_map.find(id) == model::material_map.end()) - found_by_id = false; c->material_.emplace_back(id); } catch (const std::invalid_argument&) { - found_by_id = false; + fatal_error(fmt::format( + "No material '{}' found for volume (cell) {}", mat_string, c->id_)); } - - // report failure for failed int conversion or missing material - if (!found_by_id) - fatal_error( - fmt::format("Material with name/ID '{}' not found for volume (cell) {}", - mat_string, c->id_)); } if (settings::verbosity >= 10) { @@ -694,7 +510,6 @@ void DAGUniverse::legacy_assign_material( void DAGUniverse::read_uwuw_materials() { -#ifdef OPENMC_UWUW_ENABLED // If no filename was provided, don't read UWUW materials if (filename_ == "") return; @@ -732,71 +547,6 @@ void DAGUniverse::read_uwuw_materials() for (pugi::xml_node material_node : root.children("material")) { model::materials.push_back(std::make_unique(material_node)); } -#else - fatal_error("DAGMC was not configured with UWUW."); -#endif // OPENMC_UWUW_ENABLED -} - -void DAGUniverse::uwuw_assign_material( - moab::EntityHandle vol_handle, std::unique_ptr& c) const -{ -#ifdef OPENMC_UWUW_ENABLED - // lookup material in uwuw if present - std::string uwuw_mat = dmd_ptr->volume_material_property_data_eh[vol_handle]; - if (uwuw_->material_library.count(uwuw_mat) != 0) { - // Note: material numbers are set by UWUW - int mat_number = uwuw_->material_library.get_material(uwuw_mat) - .metadata["mat_number"] - .asInt(); - c->material_.push_back(mat_number); - } else { - fatal_error(fmt::format("Material with value '{}' not found in the " - "UWUW material library", - uwuw_mat)); - } -#else - fatal_error("DAGMC was not configured with UWUW."); -#endif // OPENMC_UWUW_ENABLED -} - -void DAGUniverse::override_assign_material(std::unique_ptr& c, - const MaterialOverrides& material_overrides) const -{ - // if Cell ID matches an override key, use it to override the material - // assignment else if UWUW is used, get the material assignment from the DAGMC - // metadata - // Notify User that an override is being applied on a DAGMCCell - write_message(fmt::format("Applying override for DAGMCCell {}", c->id_), 8); - - const auto& mat_overrides = material_overrides.at(c->id_); - if (settings::verbosity >= 10) { - std::stringstream override_values; - for (size_t i = 0; i < mat_overrides.size(); ++i) { - if (i > 0) { - override_values << " "; - } - if (mat_overrides[i] == MATERIAL_VOID) { - override_values << "void"; - } else { - override_values << mat_overrides[i]; - } - } - auto msg = fmt::format("Overriding DAGMC cell {} property 'material' " - "with value(s): {}", - c->id_, override_values.str()); - write_message(msg, 10); - } - - // Override the material assignment for each cell instance using the legacy - // assignement - for (auto mat_id : mat_overrides) { - if (mat_id != MATERIAL_VOID && - model::material_map.find(mat_id) == model::material_map.end()) { - fatal_error(fmt::format( - "Material with ID '{}' not found for DAGMC cell {}", mat_id, c->id_)); - } - c->material_.push_back(mat_id); - } } //============================================================================== @@ -804,63 +554,57 @@ void DAGUniverse::override_assign_material(std::unique_ptr& c, //============================================================================== DAGCell::DAGCell(std::shared_ptr dag_ptr, int32_t dag_idx) - : Cell {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) {}; + : Cell {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) +{ + geom_type_ = GeometryType::DAG; + simple_ = true; +}; std::pair DAGCell::distance( - Position r, Direction u, int32_t on_surface, GeometryState* p) const + Position r, Direction u, int32_t on_surface, Particle* p) const { + Expects(p); // if we've changed direction or we're not on a surface, // reset the history and update last direction if (u != p->last_dir()) { p->last_dir() = u; p->history().reset(); } - if (on_surface == SURFACE_NONE) { + if (on_surface == 0) { p->history().reset(); } - const auto& univ = model::universes[p->lowest_coord().universe()]; + const auto& univ = model::universes[p->coord(p->n_coord() - 1).universe]; DAGUniverse* dag_univ = static_cast(univ.get()); if (!dag_univ) fatal_error("DAGMC call made for particle in a non-DAGMC universe"); - // initialize to lost particle conditions - int surf_idx = -1; - double dist = INFINITY; - + moab::ErrorCode rval; moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); moab::EntityHandle hit_surf; - - // create the ray + double dist; double pnt[3] = {r.x, r.y, r.z}; double dir[3] = {u.x, u.y, u.z}; - MB_CHK_ERR_CONT( - dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history())); + rval = dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history()); + MB_CHK_ERR_CONT(rval); + int surf_idx; if (hit_surf != 0) { surf_idx = dag_univ->surf_idx_offset_ + dagmc_ptr_->index_by_handle(hit_surf); - } else if (!dagmc_ptr_->is_implicit_complement(vol) || - is_root_universe(dag_univ->id_)) { - // surface boundary conditions are ignored for projection plotting, meaning - // that the particle may move through the graveyard (bounding) volume and - // into the implicit complement on the other side where no intersection will - // be found. Treating this as a lost particle is problematic when plotting. - // Instead, the infinite distance and invalid surface index are returned. - if (settings::run_mode == RunMode::PLOTTING) - return {INFTY, -1}; - - // the particle should be marked as lost immediately if an intersection - // isn't found in a volume that is not the implicit complement. In the case - // that the DAGMC model is the root universe of the geometry, even a missing - // intersection in the implicit complement should trigger this condition. - std::string material_id = - p->material() == MATERIAL_VOID - ? "-1 (VOID)" - : std::to_string(model::materials[p->material()]->id()); - p->mark_as_lost(fmt::format( - "No intersection found with DAGMC cell {}, filled with material {}", id_, - material_id)); + } else { + // indicate that particle is lost + surf_idx = -1; + dist = INFINITY; + if (!dagmc_ptr_->is_implicit_complement(vol) || + model::universe_map[dag_univ->id_] == model::root_universe) { + std::string material_id = p->material() == MATERIAL_VOID + ? "-1 (VOID)" + : std::to_string(model::materials[p->material()]->id()); + p->mark_as_lost( + fmt::format("No intersection found with DAGMC cell {}, material {}", + id_, material_id)); + } } return {dist, surf_idx}; @@ -879,11 +623,6 @@ bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const return result; } -moab::EntityHandle DAGCell::mesh_handle() const -{ - return dagmc_ptr()->entity_by_index(3, dag_index()); -} - void DAGCell::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "geom_type", "dagmc", false); @@ -896,7 +635,7 @@ BoundingBox DAGCell::bounding_box() const double min[3], max[3]; rval = dagmc_ptr_->getobb(vol, min, max); MB_CHK_ERR_CONT(rval); - return {{min[0], min[1], min[2]}, {max[0], max[1], max[2]}}; + return {min[0], max[0], min[1], max[1], min[2], max[2]}; } //============================================================================== @@ -905,12 +644,9 @@ BoundingBox DAGCell::bounding_box() const DAGSurface::DAGSurface(std::shared_ptr dag_ptr, int32_t dag_idx) : Surface {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) -{} // empty constructor - -moab::EntityHandle DAGSurface::mesh_handle() const { - return dagmc_ptr()->entity_by_index(2, dag_index()); -} + geom_type_ = GeometryType::DAG; +} // empty constructor double DAGSurface::evaluate(Position r) const { @@ -943,15 +679,18 @@ Direction DAGSurface::normal(Position r) const return dir; } -Direction DAGSurface::reflect(Position r, Direction u, GeometryState* p) const +Direction DAGSurface::reflect(Position r, Direction u, Particle* p) const { - assert(p); + Expects(p); + p->history().reset_to_last_intersection(); + moab::ErrorCode rval; + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); double pnt[3] = {r.x, r.y, r.z}; double dir[3]; - moab::ErrorCode rval = - dagmc_ptr_->get_angle(mesh_handle(), pnt, dir, &p->history()); + rval = dagmc_ptr_->get_angle(surf, pnt, dir, &p->history()); MB_CHK_ERR_CONT(rval); - return u.reflect(dir); + p->last_dir() = u.reflect(dir); + return p->last_dir(); } //============================================================================== @@ -982,58 +721,19 @@ void check_dagmc_root_univ() } } -int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ) +int32_t next_cell( + DAGUniverse* dag_univ, DAGCell* cur_cell, DAGSurface* surf_xed) { - auto surfp = dynamic_cast(model::surfaces[surf].get()); - auto cellp = dynamic_cast(model::cells[curr_cell].get()); - auto univp = static_cast(model::universes[univ].get()); - - moab::EntityHandle surf_handle = surfp->mesh_handle(); - moab::EntityHandle curr_vol = cellp->mesh_handle(); + moab::EntityHandle surf = + surf_xed->dagmc_ptr()->entity_by_index(2, surf_xed->dag_index()); + moab::EntityHandle vol = + cur_cell->dagmc_ptr()->entity_by_index(3, cur_cell->dag_index()); moab::EntityHandle new_vol; - moab::ErrorCode rval = - cellp->dagmc_ptr()->next_vol(surf_handle, curr_vol, new_vol); - if (rval != moab::MB_SUCCESS) - return -1; + cur_cell->dagmc_ptr()->next_vol(surf, vol, new_vol); - return univp->cell_index(new_vol); -} - -extern "C" int openmc_dagmc_universe_get_cell_ids( - int32_t univ_id, int32_t* ids, size_t* n) -{ - // make sure the universe id is a DAGMC Universe - const auto& univ = model::universes[model::universe_map[univ_id]]; - if (univ->geom_type() != GeometryType::DAG) { - set_errmsg(fmt::format("Universe {} is not a DAGMC Universe", univ_id)); - return OPENMC_E_INVALID_TYPE; - } - - std::vector dag_cell_ids; - for (const auto& cell_index : univ->cells_) { - const auto& cell = model::cells[cell_index]; - if (cell->geom_type() == GeometryType::CSG) { - set_errmsg(fmt::format("Cell {} is not a DAGMC Cell", cell->id_)); - return OPENMC_E_INVALID_TYPE; - } - dag_cell_ids.push_back(cell->id_); - } - std::copy(dag_cell_ids.begin(), dag_cell_ids.end(), ids); - *n = dag_cell_ids.size(); - return 0; -} - -extern "C" int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n) -{ - // make sure the universe id is a DAGMC Universe - const auto& univ = model::universes[model::universe_map[univ_id]]; - if (univ->geom_type() != GeometryType::DAG) { - set_errmsg(fmt::format("Universe {} is not a DAGMC universe", univ_id)); - return OPENMC_E_INVALID_TYPE; - } - *n = univ->cells_.size(); - return 0; + return cur_cell->dagmc_ptr()->index_by_handle(new_vol) + + dag_univ->cell_idx_offset_; } } // namespace openmc @@ -1042,19 +742,6 @@ extern "C" int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n) namespace openmc { -extern "C" int openmc_dagmc_universe_get_cell_ids( - int32_t univ_id, int32_t* ids, size_t* n) -{ - set_errmsg("OpenMC was not configured with DAGMC"); - return OPENMC_E_UNASSIGNED; -}; - -extern "C" int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n) -{ - set_errmsg("OpenMC was not configured with DAGMC"); - return OPENMC_E_UNASSIGNED; -}; - void read_dagmc_universes(pugi::xml_node node) { if (check_for_node(node, "dagmc_universe")) { @@ -1062,11 +749,8 @@ void read_dagmc_universes(pugi::xml_node node) "with DAGMC"); } }; - void check_dagmc_root_univ() {}; -int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ); - } // namespace openmc -#endif // OPENMC_DAGMC_ENABLED +#endif // DAGMC diff --git a/src/distribution.cpp b/src/distribution.cpp index cbdd13127..901852e0f 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -1,190 +1,22 @@ #include "openmc/distribution.h" #include // for copy -#include #include // for sqrt, floor, max #include // for back_inserter #include // for accumulate #include // for runtime_error #include // for string, stod -#include -#include "openmc/chain.h" -#include "openmc/constants.h" +#include + #include "openmc/error.h" #include "openmc/math_functions.h" #include "openmc/random_dist.h" #include "openmc/random_lcg.h" #include "openmc/xml_interface.h" -namespace { -std::unordered_set decay_spectrum_missing_chain_nuclides; -} - namespace openmc { -//============================================================================== -// Helper function for computing importance weights from biased sampling -//============================================================================== - -vector compute_importance_weights( - const vector& p, const vector& b) -{ - std::size_t n = p.size(); - - // Normalize original probabilities - double sum_p = std::accumulate(p.begin(), p.end(), 0.0); - vector p_norm(n); - for (std::size_t i = 0; i < n; ++i) { - p_norm[i] = p[i] / sum_p; - } - - // Normalize bias probabilities - double sum_b = std::accumulate(b.begin(), b.end(), 0.0); - vector b_norm(n); - for (std::size_t i = 0; i < n; ++i) { - b_norm[i] = b[i] / sum_b; - } - - // Compute importance weights - vector weights(n); - for (std::size_t i = 0; i < n; ++i) { - weights[i] = (b_norm[i] == 0.0) ? INFTY : p_norm[i] / b_norm[i]; - } - return weights; -} - -std::pair Distribution::sample(uint64_t* seed) const -{ - if (bias_) { - // Sample from the bias distribution and compute importance weight - double val = bias_->sample_unbiased(seed); - double wgt = this->evaluate(val) / bias_->evaluate(val); - return {val, wgt}; - } else { - // Unbiased sampling: return sampled value with weight 1.0 - double val = sample_unbiased(seed); - return {val, 1.0}; - } -} - -// PDF evaluation not supported for all distribution types -double Distribution::evaluate(double x) const -{ - throw std::runtime_error( - "PDF evaluation not implemented for this distribution type."); -} - -void Distribution::read_bias_from_xml(pugi::xml_node node) -{ - if (check_for_node(node, "bias")) { - pugi::xml_node bias_node = node.child("bias"); - - if (check_for_node(bias_node, "bias")) { - openmc::fatal_error( - "Distribution has a bias distribution with its own bias distribution. " - "Please ensure bias distributions do not have their own bias."); - } - - UPtrDist bias = distribution_from_xml(bias_node); - this->set_bias(std::move(bias)); - } -} - -//============================================================================== -// DiscreteIndex implementation -//============================================================================== - -DiscreteIndex::DiscreteIndex(pugi::xml_node node) -{ - auto params = get_node_array(node, "parameters"); - std::size_t n = params.size() / 2; - - assign({params.data() + n, n}); -} - -DiscreteIndex::DiscreteIndex(span p) -{ - assign(p); -} - -void DiscreteIndex::assign(span p) -{ - prob_.assign(p.begin(), p.end()); - this->init_alias(); -} - -void DiscreteIndex::init_alias() -{ - normalize(); - - // The initialization and sampling method is based on Vose - // (DOI: 10.1109/32.92917) - // Vectors for large and small probabilities based on 1/n - vector large; - vector small; - - size_t n = prob_.size(); - - // Set and allocate memory - alias_.assign(n, 0); - - // Fill large and small vectors based on 1/n - for (size_t i = 0; i < n; i++) { - prob_[i] *= n; - if (prob_[i] > 1.0) { - large.push_back(i); - } else { - small.push_back(i); - } - } - - while (!large.empty() && !small.empty()) { - int j = small.back(); - int k = large.back(); - - // Remove last element of small - small.pop_back(); - - // Update probability and alias based on Vose's algorithm - prob_[k] += prob_[j] - 1.0; - alias_[j] = k; - - // Move large index to small vector, if it is no longer large - if (prob_[k] < 1.0) { - small.push_back(k); - large.pop_back(); - } - } -} - -size_t DiscreteIndex::sample(uint64_t* seed) const -{ - // Alias sampling of discrete distribution - size_t n = prob_.size(); - if (n > 1) { - size_t u = prn(seed) * n; - if (prn(seed) < prob_[u]) { - return u; - } else { - return alias_[u]; - } - } else { - return 0; - } -} - -void DiscreteIndex::normalize() -{ - // Renormalize density function so that it sums to unity. Note that we save - // the integral of the distribution so that if it is used as part of another - // distribution (e.g., Mixture), we know its relative strength. - integral_ = std::accumulate(prob_.begin(), prob_.end(), 0.0); - for (auto& p_i : prob_) { - p_i /= integral_; - } -} - //============================================================================== // Discrete implementation //============================================================================== @@ -192,52 +24,44 @@ void DiscreteIndex::normalize() Discrete::Discrete(pugi::xml_node node) { auto params = get_node_array(node, "parameters"); - std::size_t n = params.size() / 2; - // First half is x values, second half is probabilities - x_.assign(params.begin(), params.begin() + n); - const double* p = params.data() + n; + std::size_t n = params.size(); + std::copy(params.begin(), params.begin() + n / 2, std::back_inserter(x_)); + std::copy(params.begin() + n / 2, params.end(), std::back_inserter(p_)); - // Check for bias - if (check_for_node(node, "bias")) { - // Get bias probabilities - auto bias_params = get_node_array(node, "bias"); - if (bias_params.size() != n) { - openmc::fatal_error( - "Size mismatch: Attempted to bias Discrete distribution with " + - std::to_string(n) + " probability entries using a bias with " + - std::to_string(bias_params.size()) + - " entries. Please ensure distributions have the same size."); + normalize(); +} + +Discrete::Discrete(const double* x, const double* p, int n) + : x_ {x, x + n}, p_ {p, p + n} +{ + normalize(); +} + +double Discrete::sample(uint64_t* seed) const +{ + int n = x_.size(); + if (n > 1) { + double xi = prn(seed); + double c = 0.0; + for (int i = 0; i < n; ++i) { + c += p_[i]; + if (xi < c) + return x_[i]; } - - // Compute importance weights - vector p_vec(p, p + n); - weight_ = compute_importance_weights(p_vec, bias_params); - - // Initialize DiscreteIndex with bias probabilities for sampling - di_.assign(bias_params); + throw std::runtime_error {"Error when sampling probability mass function."}; } else { - // Unbiased case: weight_ stays empty - di_.assign({p, n}); + return x_[0]; } } -Discrete::Discrete(const double* x, const double* p, size_t n) : di_({p, n}) +void Discrete::normalize() { - x_.assign(x, x + n); -} - -std::pair Discrete::sample(uint64_t* seed) const -{ - size_t idx = di_.sample(seed); - double wgt = weight_.empty() ? 1.0 : weight_[idx]; - return {x_[idx], wgt}; -} - -double Discrete::sample_unbiased(uint64_t* seed) const -{ - size_t idx = di_.sample(seed); - return x_[idx]; + // Renormalize density function so that it sums to unity + double norm = std::accumulate(p_.begin(), p_.end(), 0.0); + for (auto& p_i : p_) { + p_i /= norm; + } } //============================================================================== @@ -254,26 +78,13 @@ Uniform::Uniform(pugi::xml_node node) a_ = params.at(0); b_ = params.at(1); - - read_bias_from_xml(node); } -double Uniform::sample_unbiased(uint64_t* seed) const +double Uniform::sample(uint64_t* seed) const { return a_ + prn(seed) * (b_ - a_); } -double Uniform::evaluate(double x) const -{ - if (x <= a()) { - return 0.0; - } else if (x >= b()) { - return 0.0; - } else { - return 1 / (b() - a()); - } -} - //============================================================================== // PowerLaw implementation //============================================================================== @@ -293,24 +104,9 @@ PowerLaw::PowerLaw(pugi::xml_node node) offset_ = std::pow(a, n + 1); span_ = std::pow(b, n + 1) - offset_; ninv_ = 1 / (n + 1); - - read_bias_from_xml(node); } -double PowerLaw::evaluate(double x) const -{ - if (x <= a()) { - return 0.0; - } else if (x >= b()) { - return 0.0; - } else { - int pwr = n() + 1; - double norm = pwr / span_; - return norm * std::pow(std::fabs(x), n()); - } -} - -double PowerLaw::sample_unbiased(uint64_t* seed) const +double PowerLaw::sample(uint64_t* seed) const { return std::pow(offset_ + prn(seed) * span_, ninv_); } @@ -322,21 +118,13 @@ double PowerLaw::sample_unbiased(uint64_t* seed) const Maxwell::Maxwell(pugi::xml_node node) { theta_ = std::stod(get_node_value(node, "parameters")); - - read_bias_from_xml(node); } -double Maxwell::sample_unbiased(uint64_t* seed) const +double Maxwell::sample(uint64_t* seed) const { return maxwell_spectrum(theta_, seed); } -double Maxwell::evaluate(double x) const -{ - double c = (2.0 / SQRT_PI) * std::pow(theta_, -1.5); - return c * std::sqrt(x) * std::exp(-x / theta_); -} - //============================================================================== // Watt implementation //============================================================================== @@ -350,111 +138,52 @@ Watt::Watt(pugi::xml_node node) a_ = params.at(0); b_ = params.at(1); - - read_bias_from_xml(node); } -double Watt::sample_unbiased(uint64_t* seed) const +double Watt::sample(uint64_t* seed) const { return watt_spectrum(a_, b_, seed); } -double Watt::evaluate(double x) const -{ - double c = - 2.0 / (std::sqrt(PI * b_) * std::pow(a_, 1.5) * std::exp(a_ * b_ / 4.0)); - return c * std::exp(-x / a_) * std::sinh(std::sqrt(b_ * x)); -} - //============================================================================== // Normal implementation //============================================================================== - -Normal::Normal(double mean_value, double std_dev, double lower, double upper) - : mean_value_ {mean_value}, std_dev_ {std_dev}, lower_ {lower}, upper_ {upper} -{ - compute_normalization(); -} - Normal::Normal(pugi::xml_node node) { auto params = get_node_array(node, "parameters"); - if (params.size() != 2 && params.size() != 4) { + if (params.size() != 2) { openmc::fatal_error("Normal energy distribution must have two " - "parameters (mean, std_dev) or four parameters " - "(mean, std_dev, lower, upper) specified."); + "parameters specified."); } mean_value_ = params.at(0); std_dev_ = params.at(1); - - // Optional truncation bounds - if (params.size() == 4) { - lower_ = params.at(2); - upper_ = params.at(3); - } else { - lower_ = -INFTY; - upper_ = INFTY; - } - - compute_normalization(); - read_bias_from_xml(node); } -void Normal::compute_normalization() +double Normal::sample(uint64_t* seed) const { - // Validate bounds - if (lower_ >= upper_) { - openmc::fatal_error( - "Normal distribution lower bound must be less than upper bound."); - } - - // Check if truncation bounds are finite - is_truncated_ = (lower_ > -INFTY || upper_ < INFTY); - - if (is_truncated_) { - double alpha = (lower_ - mean_value_) / std_dev_; - double beta = (upper_ - mean_value_) / std_dev_; - double cdf_diff = standard_normal_cdf(beta) - standard_normal_cdf(alpha); - - if (cdf_diff <= 0.0) { - openmc::fatal_error( - "Normal distribution truncation bounds exclude entire distribution."); - } - norm_factor_ = 1.0 / cdf_diff; - } else { - norm_factor_ = 1.0; - } + return normal_variate(mean_value_, std_dev_, seed); } -double Normal::sample_unbiased(uint64_t* seed) const +//============================================================================== +// Muir implementation +//============================================================================== +Muir::Muir(pugi::xml_node node) { - if (!is_truncated_) { - return normal_variate(mean_value_, std_dev_, seed); + auto params = get_node_array(node, "parameters"); + if (params.size() != 3) { + openmc::fatal_error("Muir energy distribution must have three " + "parameters specified."); } - // Rejection sampling for truncated normal - double x; - do { - x = normal_variate(mean_value_, std_dev_, seed); - } while (x < lower_ || x > upper_); - return x; + e0_ = params.at(0); + m_rat_ = params.at(1); + kt_ = params.at(2); } -double Normal::evaluate(double x) const +double Muir::sample(uint64_t* seed) const { - // Return 0 outside truncation bounds - if (x < lower_ || x > upper_) { - return 0.0; - } - - // Standard normal PDF value - double pdf = (1.0 / (std::sqrt(2.0 * PI) * std_dev_)) * - std::exp(-std::pow((x - mean_value_), 2.0) / - (2.0 * std::pow(std_dev_, 2.0))); - - // Apply normalization for truncation - return pdf * norm_factor_; + return muir_spectrum(e0_, m_rat_, kt_, seed); } //============================================================================== @@ -469,30 +198,20 @@ Tabular::Tabular(pugi::xml_node node) interp_ = Interpolation::histogram; } else if (temp == "linear-linear") { interp_ = Interpolation::lin_lin; - } else if (temp == "log-linear") { - interp_ = Interpolation::log_lin; - } else if (temp == "log-log") { - interp_ = Interpolation::log_log; } else { openmc::fatal_error( - "Unsupported interpolation type for distribution: " + temp); + "Unknown interpolation type for distribution: " + temp); } } else { interp_ = Interpolation::histogram; } - // Read and initialize tabular distribution. If number of parameters is odd, - // add an extra zero for the 'p' array. + // Read and initialize tabular distribution auto params = get_node_array(node, "parameters"); - if (params.size() % 2 != 0) { - params.push_back(0.0); - } std::size_t n = params.size() / 2; const double* x = params.data(); const double* p = x + n; init(x, p, n); - - read_bias_from_xml(node); } Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp, @@ -509,6 +228,13 @@ void Tabular::init( std::copy(x, x + n, std::back_inserter(x_)); std::copy(p, p + n, std::back_inserter(p_)); + // Check interpolation parameter + if (interp_ != Interpolation::histogram && + interp_ != Interpolation::lin_lin) { + openmc::fatal_error("Only histogram and linear-linear interpolation " + "for tabular distribution is supported."); + } + // Calculate cumulative distribution function if (c) { std::copy(c, c + n, std::back_inserter(c_)); @@ -520,41 +246,31 @@ void Tabular::init( c_[i] = c_[i - 1] + p_[i - 1] * (x_[i] - x_[i - 1]); } else if (interp_ == Interpolation::lin_lin) { c_[i] = c_[i - 1] + 0.5 * (p_[i - 1] + p_[i]) * (x_[i] - x_[i - 1]); - } else if (interp_ == Interpolation::log_lin) { - double m = std::log(p_[i] / p_[i - 1]) / (x_[i] - x_[i - 1]); - c_[i] = c_[i - 1] + p_[i - 1] * (x_[i] - x_[i - 1]) * - exprel(m * (x_[i] - x_[i - 1])); - } else if (interp_ == Interpolation::log_log) { - double m = std::log((x_[i] * p_[i]) / (x_[i - 1] * p_[i - 1])) / - std::log(x_[i] / x_[i - 1]); - c_[i] = c_[i - 1] + x_[i - 1] * p_[i - 1] * - std::log(x_[i] / x_[i - 1]) * - exprel(m * std::log(x_[i] / x_[i - 1])); - } else { - UNREACHABLE(); } } } - // Normalize density and distribution functions. Note that we save the - // integral of the distribution so that if it is used as part of another - // distribution (e.g., Mixture), we know its relative strength. - integral_ = c_[n - 1]; + // Normalize density and distribution functions for (int i = 0; i < n; ++i) { - p_[i] = p_[i] / integral_; - c_[i] = c_[i] / integral_; + p_[i] = p_[i] / c_[n - 1]; + c_[i] = c_[i] / c_[n - 1]; } } -double Tabular::sample_unbiased(uint64_t* seed) const +double Tabular::sample(uint64_t* seed) const { // Sample value of CDF double c = prn(seed); // Find first CDF bin which is above the sampled value - auto c_iter = std::lower_bound(c_.begin() + 1, c_.end(), c); - int i = std::distance(c_.begin(), c_iter) - 1; - double c_i = c_[i]; + double c_i = c_[0]; + int i; + std::size_t n = c_.size(); + for (i = 0; i < n - 1; ++i) { + if (c <= c_[i + 1]) + break; + c_i = c_[i + 1]; + } // Determine bounding PDF values double x_i = x_[i]; @@ -567,7 +283,7 @@ double Tabular::sample_unbiased(uint64_t* seed) const } else { return x_i; } - } else if (interp_ == Interpolation::lin_lin) { + } else { // Linear-linear interpolation double x_i1 = x_[i + 1]; double p_i1 = p_[i + 1]; @@ -580,52 +296,6 @@ double Tabular::sample_unbiased(uint64_t* seed) const (std::sqrt(std::max(0.0, p_i * p_i + 2 * m * (c - c_i))) - p_i) / m; } - } else if (interp_ == Interpolation::log_lin) { - // Log-linear interpolation - double x_i1 = x_[i + 1]; - double p_i1 = p_[i + 1]; - - double m = std::log(p_i1 / p_i) / (x_i1 - x_i); - double f = (c - c_i) / p_i; - return x_i + f * log1prel(m * f); - } else if (interp_ == Interpolation::log_log) { - // Log-Log interpolation - double x_i1 = x_[i + 1]; - double p_i1 = p_[i + 1]; - - double m = std::log((x_i1 * p_i1) / (x_i * p_i)) / std::log(x_i1 / x_i); - double f = (c - c_i) / (p_i * x_i); - return x_i * std::exp(f * log1prel(m * f)); - } else { - UNREACHABLE(); - } -} - -double Tabular::evaluate(double x) const -{ - int i; - - if (interp_ == Interpolation::histogram) { - i = std::upper_bound(x_.begin(), x_.end(), x) - x_.begin() - 1; - if (i < 0 || i >= static_cast(p_.size())) { - return 0.0; - } else { - return p_[i]; - } - } else { - i = std::lower_bound(x_.begin(), x_.end(), x) - x_.begin() - 1; - - if (i < 0 || i >= static_cast(p_.size()) - 1) { - return 0.0; - } else { - double x0 = x_[i]; - double x1 = x_[i + 1]; - double p0 = p_[i]; - double p1 = p_[i + 1]; - - double t = (x - x0) / (x1 - x0); - return (1 - t) * p0 + t * p1; - } } } @@ -633,7 +303,7 @@ double Tabular::evaluate(double x) const // Equiprobable implementation //============================================================================== -double Equiprobable::sample_unbiased(uint64_t* seed) const +double Equiprobable::sample(uint64_t* seed) const { std::size_t n = x_.size(); @@ -645,88 +315,46 @@ double Equiprobable::sample_unbiased(uint64_t* seed) const return xl + ((n - 1) * r - i) * (xr - xl); } -double Equiprobable::evaluate(double x) const -{ - double x_min = *std::min_element(x_.begin(), x_.end()); - double x_max = *std::max_element(x_.begin(), x_.end()); - - if (x < x_min || x > x_max) { - return 0.0; - } else { - return 1.0 / (x_max - x_min); - } -} - //============================================================================== // Mixture implementation //============================================================================== Mixture::Mixture(pugi::xml_node node) { - vector probabilities; - - // First pass: collect distributions and their probabilities + double cumsum = 0.0; for (pugi::xml_node pair : node.children("pair")) { // Check that required data exists - if (!pair.attribute("probability")) - fatal_error("Mixture pair element does not have probability."); - if (!pair.child("dist")) - fatal_error("Mixture pair element does not have a distribution."); + if (!pair.attribute("probability")) fatal_error("Mixture pair element does not have probability."); + if (!pair.child("dist")) fatal_error("Mixture pair element does not have a distribution."); - // Get probability and distribution - double p = std::stod(pair.attribute("probability").value()); - auto dist = distribution_from_xml(pair.child("dist")); + // cummulative sum of probybilities + cumsum += std::stod(pair.attribute("probability").value()); - // Weight probability by the distribution's integral - double weighted_prob = p * dist->integral(); - probabilities.push_back(weighted_prob); - distribution_.push_back(std::move(dist)); + // Save cummulative probybility and distrubution + distribution_.push_back( + std::make_pair(cumsum, distribution_from_xml(pair.child("dist")))); } - // Save sum of weighted probabilities - integral_ = std::accumulate(probabilities.begin(), probabilities.end(), 0.0); - - std::size_t n = probabilities.size(); - - // Check for bias - if (check_for_node(node, "bias")) { - // Get bias probabilities - auto bias_params = get_node_array(node, "bias"); - if (bias_params.size() != n) { - openmc::fatal_error( - "Size mismatch: Attempted to bias Mixture distribution with " + - std::to_string(n) + " components using a bias with " + - std::to_string(bias_params.size()) + - " entries. Please ensure distributions have the same size."); - } - - // Compute importance weights - weight_ = compute_importance_weights(probabilities, bias_params); - - // Initialize DiscreteIndex with bias probabilities for sampling - di_.assign(bias_params); - } else { - // Unbiased case: weight_ stays empty - di_.assign(probabilities); + // Normalize cummulative probabilities to 1 + for (auto& pair : distribution_) { + pair.first /= cumsum; } } -std::pair Mixture::sample(uint64_t* seed) const +double Mixture::sample(uint64_t* seed) const { - size_t idx = di_.sample(seed); + // Sample value of CDF + const double p = prn(seed); + + // find matching distribution + const auto it = std::lower_bound(distribution_.cbegin(), distribution_.cend(), + p, [](const DistPair& pair, double p) { return pair.first < p; }); + + // This should not happen. Catch it + Ensures(it != distribution_.cend()); // Sample the chosen distribution - auto [val, sub_wgt] = distribution_[idx]->sample(seed); - - // Multiply by component selection weight - double mix_wgt = weight_.empty() ? 1.0 : weight_[idx]; - return {val, mix_wgt * sub_wgt}; -} - -double Mixture::sample_unbiased(uint64_t* seed) const -{ - size_t idx = di_.sample(seed); - return distribution_[idx]->sample(seed).first; + return it->second->sample(seed); } //============================================================================== @@ -753,138 +381,18 @@ UPtrDist distribution_from_xml(pugi::xml_node node) dist = UPtrDist {new Watt(node)}; } else if (type == "normal") { dist = UPtrDist {new Normal(node)}; + } else if (type == "muir") { + dist = UPtrDist {new Muir(node)}; } else if (type == "discrete") { dist = UPtrDist {new Discrete(node)}; } else if (type == "tabular") { dist = UPtrDist {new Tabular(node)}; } else if (type == "mixture") { dist = UPtrDist {new Mixture(node)}; - } else if (type == "decay_spectrum") { - dist = UPtrDist {new DecaySpectrum(node)}; - } else if (type == "muir") { - openmc::fatal_error( - "'muir' distributions are now specified using the openmc.stats.muir() " - "function in Python. Please regenerate your XML files."); } else { openmc::fatal_error("Invalid distribution type: " + type); } return dist; } -//============================================================================== -// DecaySpectrum implementation -//============================================================================== - -DecaySpectrum::DecaySpectrum(pugi::xml_node node) -{ - // Read the region volume [cm^3] needed for absolute emission rate - if (!check_for_node(node, "volume")) - fatal_error("DecaySpectrum: 'volume' attribute is required."); - double volume = std::stod(get_node_value(node, "volume")); - - // Read nuclide names and atom densities from XML - vector nuclide_indices; - vector atoms; - auto names = get_node_array(node, "nuclides"); - auto densities = get_node_array(node, "parameters"); - if (names.size() != densities.size()) { - fatal_error("DecaySpectrum nuclides and parameters must have the same " - "length."); - } - - for (size_t i = 0; i < names.size(); ++i) { - const auto& name = names[i]; - double density = densities[i]; - - // Look up nuclide in the depletion chain - auto it = data::chain_nuclide_map.find(name); - if (it == data::chain_nuclide_map.end()) { - if (decay_spectrum_missing_chain_nuclides.insert(name).second) { - warning("Nuclide '" + name + - "' appears in a DecaySpectrum source but is not present in " - "the depletion chain; it will be ignored."); - } - continue; - } - - int nuclide_index = it->second; - const auto& chain_nuc = data::chain_nuclides[nuclide_index]; - const Distribution* photon_dist = chain_nuc->photon_energy(); - if (!photon_dist) - continue; - - // Skip non-positive densities and warn if negative - if (density <= 0.0) { - if (density < 0.0) { - warning("Nuclide '" + name + - "' has a negative density in a DecaySpectrum source; it will " - "be ignored."); - } - continue; - } - - // atoms = density [atom/b-cm] * 1e24 [b/cm^2] * volume [cm^3] - double atoms_i = density * 1.0e24 * volume; - - nuclide_indices.push_back(nuclide_index); - atoms.push_back(atoms_i); - } - - init(std::move(nuclide_indices), atoms); -} - -void DecaySpectrum::init( - vector nuclide_indices, const vector& atoms) -{ - if (nuclide_indices.size() != atoms.size()) { - fatal_error("DecaySpectrum nuclide index and atoms arrays must have " - "the same length."); - } - - vector probs; - probs.reserve(nuclide_indices.size()); - for (size_t i = 0; i < nuclide_indices.size(); ++i) { - // Distribution integral is in [photons/s/atom]; multiplying by atoms gives - // the total emission rate [photons/s] for this nuclide. - const auto* dist = - data::chain_nuclides[nuclide_indices[i]]->photon_energy(); - probs.push_back(atoms[i] * dist->integral()); - } - - nuclide_indices_ = std::move(nuclide_indices); - integral_ = std::accumulate(probs.begin(), probs.end(), 0.0); - if (nuclide_indices_.empty() || integral_ <= 0.0) { - fatal_error("DecaySpectrum source did not resolve any nuclides with decay " - "photon spectra and positive atom densities. Ensure " - "OPENMC_CHAIN_FILE is set and matches the nuclides in the " - "source definition."); - } - di_.assign(probs); -} - -DecaySpectrum::Sample DecaySpectrum::sample_with_parent(uint64_t* seed) const -{ - size_t idx = di_.sample(seed); - int parent_nuclide = nuclide_indices_[idx]; - const auto* dist = data::chain_nuclides[parent_nuclide]->photon_energy(); - auto [energy, weight] = dist->sample(seed); - return {energy, weight, parent_nuclide}; -} - -std::pair DecaySpectrum::sample(uint64_t* seed) const -{ - auto sample = sample_with_parent(seed); - return {sample.energy, sample.weight}; -} - -double DecaySpectrum::integral() const -{ - return integral_; -} - -double DecaySpectrum::sample_unbiased(uint64_t* seed) const -{ - return sample_with_parent(seed).energy; -} - } // namespace openmc diff --git a/src/distribution_angle.cpp b/src/distribution_angle.cpp index ecb5961f6..5e92b794a 100644 --- a/src/distribution_angle.cpp +++ b/src/distribution_angle.cpp @@ -2,11 +2,11 @@ #include // for abs, copysign -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" +#include "xtensor/xview.hpp" #include "openmc/endf.h" #include "openmc/hdf5_interface.h" -#include "openmc/math_functions.h" #include "openmc/random_lcg.h" #include "openmc/search.h" #include "openmc/vector.h" // for vector @@ -29,7 +29,7 @@ AngleDistribution::AngleDistribution(hid_t group) hid_t dset = open_dataset(group, "mu"); read_attribute(dset, "offsets", offsets); read_attribute(dset, "interpolation", interp); - tensor::Tensor temp; + xt::xarray temp; read_dataset(dset, temp); close_dataset(dset); @@ -40,13 +40,13 @@ AngleDistribution::AngleDistribution(hid_t group) if (i < n_energy - 1) { n = offsets[i + 1] - j; } else { - n = temp.shape(1) - j; + n = temp.shape()[1] - j; } // Create and initialize tabular distribution - tensor::View xs = temp.slice(0, tensor::range(j, j + n)); - tensor::View ps = temp.slice(1, tensor::range(j, j + n)); - tensor::View cs = temp.slice(2, tensor::range(j, j + n)); + auto xs = xt::view(temp, 0, xt::range(j, j + n)); + auto ps = xt::view(temp, 1, xt::range(j, j + n)); + auto cs = xt::view(temp, 2, xt::range(j, j + n)); vector x {xs.begin(), xs.end()}; vector p {ps.begin(), ps.end()}; vector c {cs.begin(), cs.end()}; @@ -64,17 +64,30 @@ AngleDistribution::AngleDistribution(hid_t group) double AngleDistribution::sample(double E, uint64_t* seed) const { - // Find energy bin and calculate interpolation factor + // Determine number of incoming energies + auto n = energy_.size(); + + // Find energy bin and calculate interpolation factor -- if the energy is + // outside the range of the tabulated energies, choose the first or last bins int i; double r; - get_energy_index(energy_, E, i, r); + if (E < energy_[0]) { + i = 0; + r = 0.0; + } else if (E > energy_[n - 1]) { + i = n - 2; + r = 1.0; + } else { + i = lower_bound_index(energy_.begin(), energy_.end(), E); + r = (E - energy_[i]) / (energy_[i + 1] - energy_[i]); + } // Sample between the ith and (i+1)th bin if (r > prn(seed)) ++i; // Sample i-th distribution - double mu = distribution_[i]->sample(seed).first; + double mu = distribution_[i]->sample(seed); // Make sure mu is in range [-1,1] and return if (std::abs(mu) > 1.0) @@ -82,19 +95,4 @@ double AngleDistribution::sample(double E, uint64_t* seed) const return mu; } -double AngleDistribution::evaluate(double E, double mu) const -{ - // Find energy bin and calculate interpolation factor - int i; - double r; - get_energy_index(energy_, E, i, r); - - double pdf = 0.0; - if (r > 0.0) - pdf += r * distribution_[i + 1]->evaluate(mu); - if (r < 1.0) - pdf += (1.0 - r) * distribution_[i]->evaluate(mu); - return pdf; -} - } // namespace openmc diff --git a/src/distribution_energy.cpp b/src/distribution_energy.cpp index 2f8e6cf1a..a4a5ce9e1 100644 --- a/src/distribution_energy.cpp +++ b/src/distribution_energy.cpp @@ -4,7 +4,7 @@ #include // for size_t #include // for back_inserter -#include "openmc/tensor.h" +#include "xtensor/xview.hpp" #include "openmc/endf.h" #include "openmc/hdf5_interface.h" @@ -60,11 +60,11 @@ ContinuousTabular::ContinuousTabular(hid_t group) hid_t dset = open_dataset(group, "energy"); // Get interpolation parameters - tensor::Tensor temp; + xt::xarray temp; read_attribute(dset, "interpolation", temp); - tensor::View temp_b = temp.slice(0); // breakpoints - tensor::View temp_i = temp.slice(1); // interpolation parameters + auto temp_b = xt::view(temp, 0); // view of breakpoints + auto temp_i = xt::view(temp, 1); // view of interpolation parameters std::copy(temp_b.begin(), temp_b.end(), std::back_inserter(breakpoints_)); for (const auto i : temp_i) @@ -85,7 +85,7 @@ ContinuousTabular::ContinuousTabular(hid_t group) read_attribute(dset, "interpolation", interp); read_attribute(dset, "n_discrete_lines", n_discrete); - tensor::Tensor eout; + xt::xarray eout; read_dataset(dset, eout); close_dataset(dset); @@ -96,7 +96,7 @@ ContinuousTabular::ContinuousTabular(hid_t group) if (i < n_energy - 1) { n = offsets[i + 1] - j; } else { - n = eout.shape(1) - j; + n = eout.shape()[1] - j; } // Assign interpolation scheme and number of discrete lines @@ -105,15 +105,15 @@ ContinuousTabular::ContinuousTabular(hid_t group) d.n_discrete = n_discrete[i]; // Copy data - d.e_out = eout.slice(0, tensor::range(j, j + n)); - d.p = eout.slice(1, tensor::range(j, j + n)); + d.e_out = xt::view(eout, 0, xt::range(j, j + n)); + d.p = xt::view(eout, 1, xt::range(j, j + n)); // To get answers that match ACE data, for now we still use the tabulated // CDF values that were passed through to the HDF5 library. At a later // time, we can remove the CDF values from the HDF5 library and // reconstruct them using the PDF if (true) { - d.c = eout.slice(2, tensor::range(j, j + n)); + d.c = xt::view(eout, 2, xt::range(j, j + n)); } else { // Calculate cumulative distribution function -- discrete portion for (int k = 0; k < d.n_discrete; ++k) { diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index 47785649b..0735f0994 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -1,6 +1,6 @@ #include "openmc/distribution_multi.h" -#include // for move, clamp +#include // for move #include // for sqrt, sin, cos, max #include "openmc/constants.h" @@ -12,25 +12,6 @@ namespace openmc { -unique_ptr UnitSphereDistribution::create( - pugi::xml_node node) -{ - // Check for type of angular distribution - std::string type; - if (check_for_node(node, "type")) - type = get_node_value(node, "type", true, true); - if (type == "isotropic") { - return UPtrAngle {new Isotropic(node)}; - } else if (type == "monodirectional") { - return UPtrAngle {new Monodirectional(node)}; - } else if (type == "mu-phi") { - return UPtrAngle {new PolarAzimuthal(node)}; - } else { - fatal_error(fmt::format( - "Invalid angular distribution for external source: {}", type)); - } -} - //============================================================================== // UnitSphereDistribution implementation //============================================================================== @@ -44,7 +25,6 @@ UnitSphereDistribution::UnitSphereDistribution(pugi::xml_node node) fatal_error("Angular distribution reference direction must have " "three parameters specified."); u_ref_ = Direction(u_ref.data()); - u_ref_ /= u_ref_.norm(); } } @@ -59,16 +39,6 @@ PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) PolarAzimuthal::PolarAzimuthal(pugi::xml_node node) : UnitSphereDistribution {node} { - // Read reference directional unit vector - if (check_for_node(node, "reference_vwu")) { - auto v_ref = get_node_array(node, "reference_vwu"); - if (v_ref.size() != 3) - fatal_error("Angular distribution reference v direction must have " - "three parameters specified."); - v_ref_ = Direction(v_ref.data()); - v_ref_ /= v_ref_.norm(); - } - w_ref_ = u_ref_.cross(v_ref_); if (check_for_node(node, "mu")) { pugi::xml_node node_dist = node.child("mu"); mu_ = distribution_from_xml(node_dist); @@ -84,79 +54,23 @@ PolarAzimuthal::PolarAzimuthal(pugi::xml_node node) } } -std::pair PolarAzimuthal::sample(uint64_t* seed) const -{ - return sample_impl(seed, false); -} - -std::pair PolarAzimuthal::sample_as_bias( - uint64_t* seed) const -{ - return sample_impl(seed, true); -} - -std::pair PolarAzimuthal::sample_impl( - uint64_t* seed, bool return_pdf) const +Direction PolarAzimuthal::sample(uint64_t* seed) const { // Sample cosine of polar angle - auto [mu, mu_wgt] = mu_->sample(seed); + double mu = mu_->sample(seed); + if (mu == 1.0) + return u_ref_; // Sample azimuthal angle - auto [phi, phi_wgt] = phi_->sample(seed); + double phi = phi_->sample(seed); - // Compute either the PDF value or the importance weight - double weight = - return_pdf ? (mu_->evaluate(mu) * phi_->evaluate(phi)) : (mu_wgt * phi_wgt); - - if (mu == 1.0) - return {u_ref_, weight}; - if (mu == -1.0) - return {-u_ref_, weight}; - - double f = std::sqrt(1 - mu * mu); - return {mu * u_ref_ + f * std::cos(phi) * v_ref_ + f * std::sin(phi) * w_ref_, - weight}; -} - -double PolarAzimuthal::evaluate(Direction u) const -{ - double mu = std::clamp(u.dot(u_ref_), -1.0, 1.0); - double phi = 0.0; - double sin_theta_sq = std::max(0.0, 1.0 - mu * mu); - if (sin_theta_sq > 0.0) { - double sin_theta = std::sqrt(sin_theta_sq); - double cos_phi = u.dot(v_ref_) / sin_theta; - double sin_phi = u.dot(w_ref_) / sin_theta; - phi = std::atan2(sin_phi, cos_phi); - if (phi < 0.0) - phi += 2.0 * PI; - } - return mu_->evaluate(mu) * phi_->evaluate(phi); + return rotate_angle(u_ref_, mu, &phi, seed); } //============================================================================== // Isotropic implementation //============================================================================== -Isotropic::Isotropic(pugi::xml_node node) : UnitSphereDistribution {node} -{ - if (check_for_node(node, "bias")) { - pugi::xml_node bias_node = node.child("bias"); - std::string bias_type = get_node_value(bias_node, "type", true, true); - if (bias_type != "mu-phi") { - openmc::fatal_error( - "Isotropic distributions may only be biased by a PolarAzimuthal."); - } - auto bias = std::make_unique(bias_node); - if (bias->mu()->bias() || bias->phi()->bias()) { - openmc::fatal_error( - "Attempted to bias Isotropic distribution with a biased PolarAzimuthal " - "distribution. Please ensure bias distributions are unbiased."); - } - this->set_bias(std::move(bias)); - } -} - Direction isotropic_direction(uint64_t* seed) { double phi = uniform_distribution(0., 2.0 * PI, seed); @@ -165,28 +79,18 @@ Direction isotropic_direction(uint64_t* seed) std::sqrt(1.0 - mu * mu) * std::sin(phi)}; } -std::pair Isotropic::sample(uint64_t* seed) const +Direction Isotropic::sample(uint64_t* seed) const { - if (bias()) { - auto [val, eval] = bias()->sample_as_bias(seed); - return {val, 1.0 / (4.0 * PI * eval)}; - } else { - return {isotropic_direction(seed), 1.0}; - } -} - -double Isotropic::evaluate(Direction u) const -{ - return 1.0 / (4.0 * PI); + return isotropic_direction(seed); } //============================================================================== // Monodirectional implementation //============================================================================== -std::pair Monodirectional::sample(uint64_t* seed) const +Direction Monodirectional::sample(uint64_t* seed) const { - return {u_ref_, 1.0}; + return u_ref_; } } // namespace openmc diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp index 5a3452422..a06f84d80 100644 --- a/src/distribution_spatial.cpp +++ b/src/distribution_spatial.cpp @@ -1,45 +1,11 @@ #include "openmc/distribution_spatial.h" #include "openmc/error.h" -#include "openmc/mesh.h" #include "openmc/random_lcg.h" -#include "openmc/search.h" #include "openmc/xml_interface.h" namespace openmc { -//============================================================================== -// SpatialDistribution implementation -//============================================================================== - -unique_ptr SpatialDistribution::create(pugi::xml_node node) -{ - // Check for type of spatial distribution and read - std::string type; - if (check_for_node(node, "type")) - type = get_node_value(node, "type", true, true); - if (type == "cartesian") { - return UPtrSpace {new CartesianIndependent(node)}; - } else if (type == "cylindrical") { - return UPtrSpace {new CylindricalIndependent(node)}; - } else if (type == "spherical") { - return UPtrSpace {new SphericalIndependent(node)}; - } else if (type == "mesh") { - return UPtrSpace {new MeshSpatial(node)}; - } else if (type == "cloud") { - return UPtrSpace {new PointCloud(node)}; - } else if (type == "box") { - return UPtrSpace {new SpatialBox(node)}; - } else if (type == "fission") { - return UPtrSpace {new SpatialBox(node, true)}; - } else if (type == "point") { - return UPtrSpace {new SpatialPoint(node)}; - } else { - fatal_error(fmt::format( - "Invalid spatial distribution for external source: {}", type)); - } -} - //============================================================================== // CartesianIndependent implementation //============================================================================== @@ -80,13 +46,9 @@ CartesianIndependent::CartesianIndependent(pugi::xml_node node) } } -std::pair CartesianIndependent::sample(uint64_t* seed) const +Position CartesianIndependent::sample(uint64_t* seed) const { - auto [x_val, x_wgt] = x_->sample(seed); - auto [y_val, y_wgt] = y_->sample(seed); - auto [z_val, z_wgt] = z_->sample(seed); - Position xi {x_val, y_val, z_val}; - return {xi, x_wgt * y_wgt * z_wgt}; + return {x_->sample(seed), y_->sample(seed), z_->sample(seed)}; } //============================================================================== @@ -141,51 +103,16 @@ CylindricalIndependent::CylindricalIndependent(pugi::xml_node node) // If no coordinates were specified, default to (0, 0, 0) origin_ = {0.0, 0.0, 0.0}; } - - // Read cylinder z_dir - if (check_for_node(node, "z_dir")) { - auto z_dir = get_node_array(node, "z_dir"); - if (z_dir.size() == 3) { - z_dir_ = z_dir; - z_dir_ /= z_dir_.norm(); - } else { - fatal_error("z_dir for cylindrical source distribution must be length 3"); - } - } else { - // If no z_dir was specified, default to (0, 0, 1) - z_dir_ = {0.0, 0.0, 1.0}; - } - - // Read cylinder r_dir - if (check_for_node(node, "r_dir")) { - auto r_dir = get_node_array(node, "r_dir"); - if (r_dir.size() == 3) { - r_dir_ = r_dir; - r_dir_ /= r_dir_.norm(); - } else { - fatal_error("r_dir for cylindrical source distribution must be length 3"); - } - } else { - // If no r_dir was specified, default to (1, 0, 0) - r_dir_ = {1.0, 0.0, 0.0}; - } - - if (r_dir_.dot(z_dir_) > 1e-12) - fatal_error("r_dir must be perpendicular to z_dir"); - - auto phi_dir = z_dir_.cross(r_dir_); - phi_dir /= phi_dir.norm(); - phi_dir_ = phi_dir; } -std::pair CylindricalIndependent::sample(uint64_t* seed) const +Position CylindricalIndependent::sample(uint64_t* seed) const { - auto [r, r_wgt] = r_->sample(seed); - auto [phi, phi_wgt] = phi_->sample(seed); - auto [z, z_wgt] = z_->sample(seed); - Position xi = - r * (cos(phi) * r_dir_ + sin(phi) * phi_dir_) + z * z_dir_ + origin_; - return {xi, r_wgt * phi_wgt * z_wgt}; + double r = r_->sample(seed); + double phi = phi_->sample(seed); + double x = r * cos(phi) + origin_.x; + double y = r * sin(phi) + origin_.y; + double z = z_->sample(seed) + origin_.z; + return {x, y, z}; } //============================================================================== @@ -210,8 +137,7 @@ SphericalIndependent::SphericalIndependent(pugi::xml_node node) pugi::xml_node node_dist = node.child("cos_theta"); cos_theta_ = distribution_from_xml(node_dist); } else { - // If no distribution was specified, default to a single point at - // cos_theta=0 + // If no distribution was specified, default to a single point at cos_theta=0 double x[] {0.0}; double p[] {1.0}; cos_theta_ = make_unique(x, p, 1); @@ -242,206 +168,16 @@ SphericalIndependent::SphericalIndependent(pugi::xml_node node) } } -std::pair SphericalIndependent::sample(uint64_t* seed) const +Position SphericalIndependent::sample(uint64_t* seed) const { - auto [r, r_wgt] = r_->sample(seed); - auto [cos_theta, cos_theta_wgt] = cos_theta_->sample(seed); - auto [phi, phi_wgt] = phi_->sample(seed); + double r = r_->sample(seed); + double cos_theta = cos_theta_->sample(seed); + double phi = phi_->sample(seed); // sin(theta) by sin**2 + cos**2 = 1 double x = r * std::sqrt(1 - cos_theta * cos_theta) * cos(phi) + origin_.x; double y = r * std::sqrt(1 - cos_theta * cos_theta) * sin(phi) + origin_.y; double z = r * cos_theta + origin_.z; - Position xi {x, y, z}; - return {xi, r_wgt * cos_theta_wgt * phi_wgt}; -} - -//============================================================================== -// MeshSpatial implementation -//============================================================================== - -MeshSpatial::MeshSpatial(pugi::xml_node node) -{ - - auto spatial_type = get_node_value(node, "type", true, true); - if (spatial_type != "mesh") { - fatal_error( - fmt::format("Incorrect spatial type '{}' for a MeshSpatial distribution", - spatial_type)); - } - - // No in-tet distributions implemented, could include distributions for the - // barycentric coords Read in unstructured mesh from mesh_id value - int32_t mesh_id = std::stoi(get_node_value(node, "mesh_id")); - // Get pointer to spatial distribution - mesh_idx_ = model::mesh_map.at(mesh_id); - - const auto mesh_ptr = model::meshes.at(mesh_idx_).get(); - - check_element_types(); - - size_t n_bins = this->n_sources(); - std::vector strengths(n_bins, 1.0); - - // Create cdfs for sampling for an element over a mesh - // Volume scheme is weighted by the volume of each tet - // File scheme is weighted by an array given in the xml file - if (check_for_node(node, "strengths")) { - strengths = get_node_array(node, "strengths"); - if (strengths.size() != n_bins) { - fatal_error( - fmt::format("Number of entries in the source strengths array {} does " - "not match the number of entities in mesh {} ({}).", - strengths.size(), mesh_id, n_bins)); - } - } - - if (get_node_value_bool(node, "volume_normalized")) { - for (int i = 0; i < n_bins; i++) { - strengths[i] *= this->mesh()->volume(i); - } - } - - elem_idx_dist_.assign(strengths); - - if (check_for_node(node, "bias")) { - pugi::xml_node bias_node = node.child("bias"); - - if (check_for_node(bias_node, "strengths")) { - std::vector bias_strengths(n_bins, 1.0); - bias_strengths = get_node_array(node, "strengths"); - - if (bias_strengths.size() != n_bins) { - fatal_error( - fmt::format("Number of entries in the bias strengths array {} does " - "not match the number of entities in mesh {} ({}).", - bias_strengths.size(), mesh_id, n_bins)); - } - - if (get_node_value_bool(node, "volume_normalized")) { - for (int i = 0; i < n_bins; i++) { - bias_strengths[i] *= this->mesh()->volume(i); - } - } - - // Compute importance weights - weight_ = compute_importance_weights(strengths, bias_strengths); - - // Re-initialize DiscreteIndex with bias strengths for sampling - elem_idx_dist_.assign(bias_strengths); - } else { - fatal_error(fmt::format( - "Bias node for mesh {} found without strengths array.", mesh_id)); - } - } -} - -MeshSpatial::MeshSpatial(int32_t mesh_idx, span strengths) - : mesh_idx_(mesh_idx) -{ - check_element_types(); - elem_idx_dist_.assign(strengths); -} - -void MeshSpatial::check_element_types() const -{ - const auto umesh_ptr = dynamic_cast(this->mesh()); - if (umesh_ptr) { - // ensure that the unstructured mesh contains only linear tets - for (int bin = 0; bin < umesh_ptr->n_bins(); bin++) { - if (umesh_ptr->element_type(bin) != ElementType::LINEAR_TET) { - fatal_error( - "Mesh specified for source must contain only linear tetrahedra."); - } - } - } -} - -int32_t MeshSpatial::sample_element_index(uint64_t* seed) const -{ - return elem_idx_dist_.sample(seed); -} - -std::pair MeshSpatial::sample_mesh(uint64_t* seed) const -{ - // Sample the CDF defined in initialization above - int32_t elem_idx = this->sample_element_index(seed); - return {elem_idx, mesh()->sample_element(elem_idx, seed)}; -} - -std::pair MeshSpatial::sample(uint64_t* seed) const -{ - auto [elem_idx, u] = this->sample_mesh(seed); - double wgt = weight_.empty() ? 1.0 : weight_[elem_idx]; - return {u, wgt}; -} - -//============================================================================== -// PointCloud implementation -//============================================================================== - -PointCloud::PointCloud(pugi::xml_node node) -{ - if (check_for_node(node, "coords")) { - point_cloud_ = get_node_position_array(node, "coords"); - } else { - fatal_error("No coordinates were provided for the PointCloud " - "spatial distribution"); - } - - std::vector strengths; - - if (check_for_node(node, "strengths")) - strengths = get_node_array(node, "strengths"); - else - strengths.resize(point_cloud_.size(), 1.0); - - if (strengths.size() != point_cloud_.size()) { - fatal_error( - fmt::format("Number of entries for the strengths array {} does " - "not match the number of spatial points provided {}.", - strengths.size(), point_cloud_.size())); - } - - point_idx_dist_.assign(strengths); - - if (check_for_node(node, "bias")) { - pugi::xml_node bias_node = node.child("bias"); - - if (check_for_node(bias_node, "strengths")) { - std::vector bias_strengths(point_cloud_.size(), 1.0); - bias_strengths = get_node_array(node, "strengths"); - - if (bias_strengths.size() != point_cloud_.size()) { - fatal_error( - fmt::format("Number of entries in the bias strengths array {} does " - "not match the number of spatial points provided {}.", - bias_strengths.size(), point_cloud_.size())); - } - - // Compute importance weights - weight_ = compute_importance_weights(strengths, bias_strengths); - - // Re-initialize DiscreteIndex with bias strengths for sampling - point_idx_dist_.assign(bias_strengths); - } else { - fatal_error( - fmt::format("Bias node for PointCloud found without strengths array.")); - } - } -} - -PointCloud::PointCloud( - std::vector point_cloud, span strengths) -{ - point_cloud_.assign(point_cloud.begin(), point_cloud.end()); - point_idx_dist_.assign(strengths); -} - -std::pair PointCloud::sample(uint64_t* seed) const -{ - int32_t index = point_idx_dist_.sample(seed); - double wgt = weight_.empty() ? 1.0 : weight_[index]; - return {point_cloud_[index], wgt}; + return {x, y, z}; } //============================================================================== @@ -461,15 +197,10 @@ SpatialBox::SpatialBox(pugi::xml_node node, bool fission) upper_right_ = Position {params[3], params[4], params[5]}; } -SpatialBox::SpatialBox(Position lower_left, Position upper_right, bool fission) - : lower_left_(lower_left), upper_right_(upper_right), - only_fissionable_(fission) -{} - -std::pair SpatialBox::sample(uint64_t* seed) const +Position SpatialBox::sample(uint64_t* seed) const { Position xi {prn(seed), prn(seed), prn(seed)}; - return {lower_left_ + xi * (upper_right_ - lower_left_), 1.0}; + return lower_left_ + xi * (upper_right_ - lower_left_); } //============================================================================== @@ -488,9 +219,9 @@ SpatialPoint::SpatialPoint(pugi::xml_node node) r_ = Position {params.data()}; } -std::pair SpatialPoint::sample(uint64_t* seed) const +Position SpatialPoint::sample(uint64_t* seed) const { - return {r_, 1.0}; + return r_; } } // namespace openmc diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index bc8dcc9ea..5584210a1 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -1,6 +1,9 @@ #include "openmc/eigenvalue.h" -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xtensor.hpp" +#include "xtensor/xview.hpp" #include "openmc/array.h" #include "openmc/bank.h" @@ -8,7 +11,6 @@ #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/hdf5_interface.h" -#include "openmc/ifp.h" #include "openmc/math_functions.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" @@ -36,7 +38,7 @@ namespace simulation { double keff_generation; array k_sum; vector entropy; -tensor::Tensor source_frac; +xt::xtensor source_frac; } // namespace simulation @@ -55,28 +57,16 @@ void calculate_generation_keff() double keff_reduced; #ifdef OPENMC_MPI - if (settings::solver_type != SolverType::RANDOM_RAY) { - // Combine values across all processors - MPI_Allreduce(&simulation::keff_generation, &keff_reduced, 1, MPI_DOUBLE, - MPI_SUM, mpi::intracomm); - } else { - // If using random ray, MPI parallelism is provided by domain replication. - // As such, all fluxes will be reduced at the end of each transport sweep, - // such that all ranks have identical scalar flux vectors, and will all - // independently compute the same value of k. Thus, there is no need to - // perform any additional MPI reduction here. - keff_reduced = simulation::keff_generation; - } + // Combine values across all processors + MPI_Allreduce(&simulation::keff_generation, &keff_reduced, 1, MPI_DOUBLE, + MPI_SUM, mpi::intracomm); #else keff_reduced = simulation::keff_generation; #endif // Normalize single batch estimate of k // TODO: This should be normalized by total_weight, not by n_particles - if (settings::solver_type != SolverType::RANDOM_RAY) { - keff_reduced /= settings::n_particles; - } - + keff_reduced /= settings::n_particles; simulation::k_generation.push_back(keff_reduced); } @@ -124,54 +114,54 @@ void synchronize_bank() "No fission sites banked on MPI rank " + std::to_string(mpi::rank)); } - simulation::time_bank_sample.start(); + // Make sure all processors start at the same point for random sampling. Then + // skip ahead in the sequence using the starting index in the 'global' + // fission bank for each processor. - // Allocate temporary source bank -- we don't really know how many fission - // sites were created, so overallocate by a factor of 3 - int64_t index_temp = 0; + int64_t id = simulation::total_gen + overall_generation(); + uint64_t seed = init_seed(id, STREAM_TRACKING); + advance_prn_seed(start, &seed); - vector temp_sites(3 * simulation::work_per_rank); + // Determine how many fission sites we need to sample from the source bank + // and the probability for selecting a site. - // Temporary banks for IFP - vector> temp_delayed_groups; - vector> temp_lifetimes; - if (settings::ifp_on) { - resize_ifp_data( - temp_delayed_groups, temp_lifetimes, 3 * simulation::work_per_rank); + int64_t sites_needed; + if (total < settings::n_particles) { + sites_needed = settings::n_particles % total; + } else { + sites_needed = settings::n_particles; } + double p_sample = static_cast(sites_needed) / total; + + simulation::time_bank_sample.start(); // ========================================================================== // SAMPLE N_PARTICLES FROM FISSION BANK AND PLACE IN TEMP_SITES - // We use Uniform Combing method to exactly get the targeted particle size - // [https://doi.org/10.1080/00295639.2022.2091906] + // Allocate temporary source bank -- we don't really know how many fission + // sites were created, so overallocate by a factor of 3 + int64_t index_temp = 0; + vector temp_sites(3 * simulation::work_per_rank); - // Make sure all processors use the same random number seed. - int64_t id = simulation::total_gen + overall_generation(); - uint64_t seed = init_seed(id, STREAM_TRACKING); + for (int64_t i = 0; i < simulation::fission_bank.size(); i++) { + const auto& site = simulation::fission_bank[i]; - // Comb specification - double teeth_distance = static_cast(total) / settings::n_particles; - double teeth_offset = prn(&seed) * teeth_distance; - - // First and last hitting tooth - int64_t end = start + simulation::fission_bank.size(); - int64_t tooth_start = std::ceil((start - teeth_offset) / teeth_distance); - int64_t tooth_end = std::floor((end - teeth_offset) / teeth_distance) + 1; - - // Locally comb particles in fission_bank - double tooth = tooth_start * teeth_distance + teeth_offset; - for (int64_t i = tooth_start; i < tooth_end; i++) { - int64_t idx = std::floor(tooth) - start; - temp_sites[index_temp] = simulation::fission_bank[idx]; - if (settings::ifp_on) { - copy_ifp_data_from_fission_banks( - idx, temp_delayed_groups[index_temp], temp_lifetimes[index_temp]); + // If there are less than n_particles particles banked, automatically add + // int(n_particles/total) sites to temp_sites. For example, if you need + // 1000 and 300 were banked, this would add 3 source sites per banked site + // and the remaining 100 would be randomly sampled. + if (total < settings::n_particles) { + for (int64_t j = 1; j <= settings::n_particles / total; ++j) { + temp_sites[index_temp] = site; + ++index_temp; + } } - ++index_temp; - // Next tooth - tooth += teeth_distance; + // Randomly sample sites needed + if (prn(&seed) < p_sample) { + temp_sites[index_temp] = site; + ++index_temp; + } } // At this point, the sampling of source sites is done and now we need to @@ -186,17 +176,40 @@ void synchronize_bank() MPI_Exscan(&index_temp, &start, 1, MPI_INT64_T, MPI_SUM, mpi::intracomm); finish = start + index_temp; - // TODO: protect for MPI_Exscan at rank 0 - // Allocate space for bank_position if this hasn't been done yet - std::vector bank_position(mpi::n_procs); - MPI_Allgather(&start, 1, MPI_INT64_T, bank_position.data(), 1, MPI_INT64_T, - mpi::intracomm); + int64_t bank_position[mpi::n_procs]; + MPI_Allgather( + &start, 1, MPI_INT64_T, bank_position, 1, MPI_INT64_T, mpi::intracomm); #else start = 0; finish = index_temp; #endif + // Now that the sampling is complete, we need to ensure that we have exactly + // n_particles source sites. The way this is done in a reproducible manner is + // to adjust only the source sites on the last processor. + + if (mpi::rank == mpi::n_procs - 1) { + if (finish > settings::n_particles) { + // If we have extra sites sampled, we will simply discard the extra + // ones on the last processor + index_temp = settings::n_particles - start; + + } else if (finish < settings::n_particles) { + // If we have too few sites, repeat sites from the very end of the + // fission bank + sites_needed = settings::n_particles - finish; + for (int i = 0; i < sites_needed; ++i) { + int i_bank = simulation::fission_bank.size() - sites_needed + i; + temp_sites[index_temp] = simulation::fission_bank[i_bank]; + ++index_temp; + } + } + + // the last processor should not be sending sites to right + finish = simulation::work_index[mpi::rank + 1]; + } + simulation::time_bank_sample.stop(); simulation::time_bank_sendrecv.start(); @@ -204,32 +217,15 @@ void synchronize_bank() // ========================================================================== // SEND BANK SITES TO NEIGHBORS - // IFP number of generation - int ifp_n_generation; - if (settings::ifp_on) { - broadcast_ifp_n_generation( - ifp_n_generation, temp_delayed_groups, temp_lifetimes); - } - int64_t index_local = 0; vector requests; - // IFP send buffers - vector send_delayed_groups; - vector send_lifetimes; - if (start < settings::n_particles) { // Determine the index of the processor which has the first part of the // source_bank for the local processor int neighbor = upper_bound_index( simulation::work_index.begin(), simulation::work_index.end(), start); - // Resize IFP send buffers - if (settings::ifp_on && mpi::n_procs > 1) { - resize_ifp_data(send_delayed_groups, send_lifetimes, - ifp_n_generation * 3 * simulation::work_per_rank); - } - while (start < finish) { // Determine the number of sites to send int64_t n = @@ -242,16 +238,6 @@ void synchronize_bank() MPI_Isend(&temp_sites[index_local], static_cast(n), mpi::source_site, neighbor, mpi::rank, mpi::intracomm, &requests.back()); - - if (settings::ifp_on) { - // Send IFP data - if (is_beta_effective_or_both()) - send_ifp_info(index_local, n, ifp_n_generation, neighbor, requests, - temp_delayed_groups, send_delayed_groups); - if (is_generation_time_or_both()) - send_ifp_info(index_local, n, ifp_n_generation, neighbor, requests, - temp_lifetimes, send_lifetimes); - } } // Increment all indices @@ -273,11 +259,6 @@ void synchronize_bank() start = simulation::work_index[mpi::rank]; index_local = 0; - // IFP receive buffers - vector recv_delayed_groups; - vector recv_lifetimes; - vector deserialization_info; - // Determine what process has the source sites that will need to be stored at // the beginning of this processor's source bank. @@ -286,13 +267,7 @@ void synchronize_bank() neighbor = mpi::n_procs - 1; } else { neighbor = - upper_bound_index(bank_position.begin(), bank_position.end(), start); - } - - // Resize IFP receive buffers - if (settings::ifp_on && mpi::n_procs > 1) { - resize_ifp_data(recv_delayed_groups, recv_lifetimes, - ifp_n_generation * simulation::work_per_rank); + upper_bound_index(bank_position, bank_position + mpi::n_procs, start); } while (start < simulation::work_index[mpi::rank + 1]) { @@ -314,28 +289,13 @@ void synchronize_bank() MPI_Irecv(&simulation::source_bank[index_local], static_cast(n), mpi::source_site, neighbor, neighbor, mpi::intracomm, &requests.back()); - if (settings::ifp_on) { - // Receive IFP data - if (is_beta_effective_or_both()) - receive_ifp_data(index_local, n, ifp_n_generation, neighbor, requests, - recv_delayed_groups, deserialization_info); - if (is_generation_time_or_both()) - receive_ifp_data(index_local, n, ifp_n_generation, neighbor, requests, - recv_lifetimes, deserialization_info); - } - } else { - // If the source sites are on this processor, we can simply copy them + // If the source sites are on this procesor, we can simply copy them // from the temp_sites bank index_temp = start - bank_position[mpi::rank]; std::copy(&temp_sites[index_temp], &temp_sites[index_temp + n], &simulation::source_bank[index_local]); - - if (settings::ifp_on) { - copy_partial_ifp_data_to_source_banks( - index_temp, n, index_local, temp_delayed_groups, temp_lifetimes); - } } // Increment all indices @@ -351,21 +311,9 @@ void synchronize_bank() int n_request = requests.size(); MPI_Waitall(n_request, requests.data(), MPI_STATUSES_IGNORE); - if (settings::ifp_on) { - if (is_beta_effective_or_both()) - deserialize_ifp_info(ifp_n_generation, recv_delayed_groups, - simulation::ifp_source_delayed_group_bank, deserialization_info); - if (is_generation_time_or_both()) - deserialize_ifp_info(ifp_n_generation, recv_lifetimes, - simulation::ifp_source_lifetime_bank, deserialization_info); - } - #else std::copy(temp_sites.data(), temp_sites.data() + settings::n_particles, simulation::source_bank.begin()); - if (settings::ifp_on) { - copy_complete_ifp_data_to_source_banks(temp_delayed_groups, temp_lifetimes); - } #endif simulation::time_bank_sendrecv.stop(); @@ -411,16 +359,6 @@ void calculate_average_keff() t_value * std::sqrt( (simulation::k_sum[1] / n - std::pow(simulation::keff, 2)) / (n - 1)); - - // In some cases (such as an infinite medium problem), random ray - // may estimate k exactly and in an unvarying manner between iterations. - // In this case, the floating point roundoff between the division and the - // power operations may cause an extremely small negative value to occur - // inside the sqrt operation, leading to NaN. If this occurs, we check for - // it and set the std dev to zero. - if (!std::isfinite(simulation::keff_std)) { - simulation::keff_std = 0.0; - } } } } @@ -432,8 +370,7 @@ int openmc_get_keff(double* k_combined) // Special case for n <=3. Notice that at the end, // there is a N-3 term in a denominator. - if (simulation::n_realizations <= 3 || - settings::solver_type == SolverType::RANDOM_RAY) { + if (simulation::n_realizations <= 3) { k_combined[0] = simulation::keff; k_combined[1] = simulation::keff_std; if (simulation::n_realizations <= 1) { @@ -449,7 +386,7 @@ int openmc_get_keff(double* k_combined) const auto& gt = simulation::global_tallies; array kv {}; - tensor::Tensor cov = tensor::zeros({3, 3}); + xt::xtensor cov = xt::zeros({3, 3}); kv[0] = gt(GlobalTally::K_COLLISION, TallyResult::SUM) / n; kv[1] = gt(GlobalTally::K_ABSORPTION, TallyResult::SUM) / n; kv[2] = gt(GlobalTally::K_TRACKLENGTH, TallyResult::SUM) / n; @@ -588,7 +525,7 @@ void shannon_entropy() { // Get source weight in each mesh bin bool sites_outside; - tensor::Tensor p = + xt::xtensor p = simulation::entropy_mesh->count_sites(simulation::fission_bank.data(), simulation::fission_bank.size(), &sites_outside); @@ -600,13 +537,13 @@ void shannon_entropy() if (mpi::master) { // Normalize to total weight of bank sites - p /= p.sum(); + p /= xt::sum(p); // Sum values to obtain Shannon entropy double H = 0.0; for (auto p_i : p) { if (p_i > 0.0) { - H -= p_i * std::log2(p_i); + H -= p_i * std::log(p_i) / std::log(2.0); } } @@ -624,7 +561,7 @@ void ufs_count_sites() std::size_t n = simulation::ufs_mesh->n_bins(); double vol_frac = simulation::ufs_mesh->volume_frac_; - simulation::source_frac = tensor::Tensor({n}, vol_frac); + simulation::source_frac = xt::xtensor({n}, vol_frac); } else { // count number of source sites in each ufs mesh cell @@ -646,7 +583,7 @@ void ufs_count_sites() #endif // Normalize to total weight to get fraction of source in each cell - double total = simulation::source_frac.sum(); + double total = xt::sum(simulation::source_frac)(); simulation::source_frac /= total; // Since the total starting weight is not equal to n_particles, we need to diff --git a/src/endf.cpp b/src/endf.cpp index 8a9c5e48a..c0c1d2e7e 100644 --- a/src/endf.cpp +++ b/src/endf.cpp @@ -5,7 +5,8 @@ #include // for back_inserter #include // for runtime_error -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" +#include "xtensor/xview.hpp" #include "openmc/array.h" #include "openmc/constants.h" @@ -87,83 +88,6 @@ bool is_inelastic_scatter(int mt) } } -bool mt_matches(int event_mt, int target_mt) -{ - // Direct match - if (event_mt == target_mt) - return true; - - // Check if event_mt is a component of target_mt summation reaction - switch (target_mt) { - case TOTAL_XS: - return event_mt == ELASTIC || mt_matches(event_mt, N_NONELASTIC); - - case N_NONELASTIC: { - static constexpr int components[] = {4, 5, 11, 16, 17, 22, 23, 24, 25, 27, - 28, 29, 30, 32, 33, 34, 35, 36, 37, 41, 42, 44, 45, 152, 153, 154, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, - 188, 189, 190, 194, 195, 196, 198, 199, 200}; - for (int mt : components) { - if (mt_matches(event_mt, mt)) - return true; - } - return false; - } - - case N_LEVEL: - // Inelastic scattering levels - return event_mt >= 50 && event_mt <= N_NC; - - case N_2N: - // (n,2n) to excited states - return event_mt >= N_2N0 && event_mt <= N_2NC; - - case N_FISSION: - return is_fission(event_mt); - - case 27: - return is_fission(event_mt) || is_disappearance(event_mt); - - case N_DISAPPEAR: { - return is_disappearance(event_mt); - } - - case N_P: - // (n,p) to excited states - return event_mt >= N_P0 && event_mt <= N_PC; - - case N_D: - // (n,d) to excited states - return event_mt >= N_D0 && event_mt <= N_DC; - - case N_T: - // (n,t) to excited states - return event_mt >= N_T0 && event_mt <= N_TC; - - case N_3HE: - // (n,3He) to excited states - return event_mt >= N_3HE0 && event_mt <= N_3HEC; - - case N_A: - // (n,alpha) to excited states - return event_mt >= N_A0 && event_mt <= N_AC; - - case 501: - return event_mt == 502 || event_mt == 504 || mt_matches(event_mt, 516) || - mt_matches(event_mt, 522); - - case PAIR_PROD: - return event_mt == PAIR_PROD_ELEC || event_mt == PAIR_PROD_NUC; - - case PHOTOELECTRIC: - return event_mt >= 534 && event_mt < 573; - - default: - return false; - } -} - unique_ptr read_function(hid_t group, const char* name) { hid_t obj_id = open_object(group, name); @@ -229,11 +153,11 @@ Tabulated1D::Tabulated1D(hid_t dset) for (const auto i : int_temp) int_.push_back(int2interp(i)); - tensor::Tensor arr; + xt::xarray arr; read_dataset(dset, arr); - tensor::View xs = arr.slice(0); - tensor::View ys = arr.slice(1); + auto xs = xt::view(arr, 0); + auto ys = xt::view(arr, 1); std::copy(xs.begin(), xs.end(), std::back_inserter(x_)); std::copy(ys.begin(), ys.end(), std::back_inserter(y_)); @@ -305,12 +229,12 @@ double Tabulated1D::operator()(double x) const CoherentElasticXS::CoherentElasticXS(hid_t dset) { // Read 2D array from dataset - tensor::Tensor arr; + xt::xarray arr; read_dataset(dset, arr); // Get views for Bragg edges and structure factors - tensor::View E = arr.slice(0); - tensor::View s = arr.slice(1); + auto E = xt::view(arr, 0); + auto s = xt::view(arr, 1); // Copy Bragg edges and partial sums of structure factors std::copy(E.begin(), E.end(), std::back_inserter(bragg_edges_)); diff --git a/src/error.cpp b/src/error.cpp index f99f5935f..566950a97 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -110,26 +110,23 @@ void write_message(const std::string& message, int level) void fatal_error(const std::string& message, int err) { -#pragma omp critical(FatalError) - { #ifdef _POSIX_VERSION - // Make output red if user is in a terminal - if (isatty(STDERR_FILENO)) { - std::cerr << "\033[0;31m"; - } -#endif - - // Write error message - std::cerr << " ERROR: "; - output(message, std::cerr, 8); - -#ifdef _POSIX_VERSION - // Reset color for terminal - if (isatty(STDERR_FILENO)) { - std::cerr << "\033[0m"; - } -#endif + // Make output red if user is in a terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0;31m"; } +#endif + + // Write error message + std::cerr << " ERROR: "; + output(message, std::cerr, 8); + +#ifdef _POSIX_VERSION + // Reset color for terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0m"; + } +#endif #ifdef OPENMC_MPI MPI_Abort(mpi::intracomm, err); diff --git a/src/event.cpp b/src/event.cpp index 2d436bb9d..1db5c99d7 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -1,9 +1,5 @@ #include "openmc/event.h" - -#include "openmc/bank.h" -#include "openmc/error.h" #include "openmc/material.h" -#include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/timer.h" @@ -55,7 +51,7 @@ void dispatch_xs_event(int64_t buffer_idx) { Particle& p = simulation::particles[buffer_idx]; if (p.material() == MATERIAL_VOID || - !model::materials[p.material()]->fissionable()) { + !model::materials[p.material()]->fissionable_) { simulation::calculate_nonfuel_xs_queue.thread_safe_append({p, buffer_idx}); } else { simulation::calculate_fuel_xs_queue.thread_safe_append({p, buffer_idx}); @@ -67,8 +63,7 @@ void process_init_events(int64_t n_particles, int64_t source_offset) simulation::time_event_init.start(); #pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < n_particles; i++) { - initialize_particle_track( - simulation::particles[i], source_offset + i + 1, false); + initialize_history(simulation::particles[i], source_offset + i + 1); dispatch_xs_event(i); } simulation::time_event_init.stop(); @@ -78,17 +73,17 @@ void process_calculate_xs_events(SharedArray& queue) { simulation::time_event_calculate_xs.start(); - // TODO: If using C++17, we could perform a parallel sort of the queue by - // particle type, material type, and then energy, in order to improve cache - // locality and reduce thread divergence on GPU. However, the parallel - // algorithms typically require linking against an additional library (Intel - // TBB). Prior to C++17, std::sort is a serial only operation, which in this - // case makes it too slow to be practical for most test problems. + // TODO: If using C++17, perform a parallel sort of the queue + // by particle type, material type, and then energy, in order to + // improve cache locality and reduce thread divergence on GPU. Prior + // to C++17, std::sort is a serial only operation, which in this case + // makes it too slow to be practical for most test problems. // // std::sort(std::execution::par_unseq, queue.data(), queue.data() + // queue.size()); int64_t offset = simulation::advance_particle_queue.size(); + ; #pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < queue.size(); i++) { @@ -117,9 +112,7 @@ void process_advance_particle_events() int64_t buffer_idx = simulation::advance_particle_queue[i].idx; Particle& p = simulation::particles[buffer_idx]; p.event_advance(); - if (!p.alive()) - continue; - if (p.collision_distance() > p.boundary().distance()) { + if (p.collision_distance() > p.boundary().distance) { simulation::surface_crossing_queue.thread_safe_append({p, buffer_idx}); } else { simulation::collision_queue.thread_safe_append({p, buffer_idx}); @@ -140,7 +133,7 @@ void process_surface_crossing_events() int64_t buffer_idx = simulation::surface_crossing_queue[i].idx; Particle& p = simulation::particles[buffer_idx]; p.event_cross_surface(); - p.event_check_limit_and_revive(); + p.event_revive_from_secondary(); if (p.alive()) dispatch_xs_event(buffer_idx); } @@ -159,7 +152,7 @@ void process_collision_events() int64_t buffer_idx = simulation::collision_queue[i].idx; Particle& p = simulation::particles[buffer_idx]; p.event_collide(); - p.event_check_limit_and_revive(); + p.event_revive_from_secondary(); if (p.alive()) dispatch_xs_event(buffer_idx); } @@ -180,45 +173,4 @@ void process_death_events(int64_t n_particles) simulation::time_event_death.stop(); } -void process_transport_events() -{ - while (true) { - int64_t max = std::max({simulation::calculate_fuel_xs_queue.size(), - simulation::calculate_nonfuel_xs_queue.size(), - simulation::advance_particle_queue.size(), - simulation::surface_crossing_queue.size(), - simulation::collision_queue.size()}); - - if (max == 0) { - break; - } else if (max == simulation::calculate_fuel_xs_queue.size()) { - process_calculate_xs_events(simulation::calculate_fuel_xs_queue); - } else if (max == simulation::calculate_nonfuel_xs_queue.size()) { - process_calculate_xs_events(simulation::calculate_nonfuel_xs_queue); - } else if (max == simulation::advance_particle_queue.size()) { - process_advance_particle_events(); - } else if (max == simulation::surface_crossing_queue.size()) { - process_surface_crossing_events(); - } else if (max == simulation::collision_queue.size()) { - process_collision_events(); - } - } -} - -void process_init_secondary_events(int64_t n_particles, int64_t offset, - const SharedArray& shared_secondary_bank) -{ - simulation::time_event_init.start(); -#pragma omp parallel for schedule(runtime) - for (int64_t i = 0; i < n_particles; i++) { - initialize_particle_track(simulation::particles[i], offset + i + 1, true); - const SourceSite& site = shared_secondary_bank[offset + i]; - simulation::particles[i].event_revive_from_secondary(site); - if (simulation::particles[i].alive()) { - dispatch_xs_event(i); - } - } - simulation::time_event_init.stop(); -} - } // namespace openmc diff --git a/src/external/quartic_solver.cpp b/src/external/quartic_solver.cpp index 71bdb25c3..0b280e83c 100644 --- a/src/external/quartic_solver.cpp +++ b/src/external/quartic_solver.cpp @@ -1,4 +1,3 @@ -#define _USE_MATH_DEFINES // to make M_PI declared in Intel and MSVC compilers #include #include #include diff --git a/src/file_utils.cpp b/src/file_utils.cpp deleted file mode 100644 index 517f82d15..000000000 --- a/src/file_utils.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "openmc/file_utils.h" - -#include - -namespace openmc { - -bool dir_exists(const std::string& path) -{ - std::filesystem::path d(path); - return std::filesystem::is_directory(d); -} - -bool file_exists(const std::string& filename) -{ - std::filesystem::path p(filename); - if (!std::filesystem::exists(p)) { - return false; - } - if (std::filesystem::is_directory(p)) { - return false; - } - return true; -} - -std::string dir_name(const std::string& filename) -{ - std::filesystem::path p(filename); - return (p.parent_path()).string(); -} - -std::string get_file_extension(const std::string& filename) -{ - std::filesystem::path p(filename); - auto ext = p.extension(); - if (!ext.empty()) { - // path::extension includes the period - return ext.string().substr(1); - } - return ""; -} - -} // namespace openmc diff --git a/src/finalize.cpp b/src/finalize.cpp index fd891d9dd..0c2c62310 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -2,9 +2,7 @@ #include "openmc/bank.h" #include "openmc/capi.h" -#include "openmc/chain.h" #include "openmc/cmfd_solver.h" -#include "openmc/collision_track.h" #include "openmc/constants.h" #include "openmc/cross_sections.h" #include "openmc/dagmc.h" @@ -15,12 +13,10 @@ #include "openmc/material.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" -#include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/photon.h" #include "openmc/plot.h" #include "openmc/random_lcg.h" -#include "openmc/random_ray/random_ray_simulation.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/source.h" @@ -31,7 +27,7 @@ #include "openmc/volume_calc.h" #include "openmc/weight_windows.h" -#include "openmc/tensor.h" +#include "xtensor/xview.hpp" namespace openmc { @@ -45,7 +41,6 @@ void free_memory() free_memory_photon(); free_memory_settings(); free_memory_thermal(); - free_memory_chain(); library_clear(); nuclides_clear(); free_memory_source(); @@ -68,9 +63,6 @@ using namespace openmc; int openmc_finalize() { - if (simulation::initialized) - openmc_simulation_finalize(); - // Clear results openmc_reset(); @@ -80,44 +72,27 @@ int openmc_finalize() // Reset global variables settings::assume_separate = false; settings::check_overlaps = false; - settings::collision_track_config = CollisionTrackConfig {}; settings::confidence_intervals = false; settings::create_fission_neutrons = true; - settings::create_delayed_neutrons = true; settings::electron_treatment = ElectronTreatment::LED; settings::delayed_photon_scaling = true; settings::energy_cutoff = {0.0, 1000.0, 0.0, 0.0}; - settings::time_cutoff = {INFTY, INFTY, INFTY, INFTY}; settings::entropy_on = false; settings::event_based = false; - settings::free_gas_threshold = 400.0; settings::gen_per_batch = 1; settings::legendre_to_tabular = true; settings::legendre_to_tabular_points = -1; settings::material_cell_offsets = true; - settings::max_lost_particles = 10; - settings::max_order = 0; settings::max_particles_in_flight = 100000; - settings::max_secondaries = 10000; - settings::max_particle_events = 1'000'000; - settings::max_history_splits = 10'000'000; + settings::max_splits = 1000; settings::max_tracks = 1000; - settings::max_write_lost_particles = -1; - settings::n_log_bins = 8000; settings::n_inactive = 0; settings::n_particles = -1; settings::output_summary = true; settings::output_tallies = true; settings::particle_restart_run = false; - settings::path_cross_sections.clear(); - settings::path_input.clear(); - settings::path_output.clear(); - settings::path_particle_restart.clear(); - settings::path_sourcepoint.clear(); - settings::path_statepoint.clear(); settings::photon_transport = false; settings::reduce_tallies = true; - settings::rel_max_lost_particles = 1.0e-6; settings::res_scat_on = false; settings::res_scat_method = ResScatMethod::rvs; settings::res_scat_energy_min = 0.01; @@ -125,83 +100,62 @@ int openmc_finalize() settings::restart_run = false; settings::run_CE = true; settings::run_mode = RunMode::UNSET; - settings::surface_grazing_cutoff = 0.001; - settings::surface_grazing_ratio = 0.5; - settings::solver_type = SolverType::MONTE_CARLO; settings::source_latest = false; - settings::source_rejection_fraction = 0.05; settings::source_separate = false; settings::source_write = true; - settings::ssw_cell_id = C_NONE; - settings::ssw_cell_type = SSWCellType::None; - settings::ssw_max_particles = 0; - settings::ssw_max_files = 1; settings::survival_biasing = false; settings::temperature_default = 293.6; settings::temperature_method = TemperatureMethod::NEAREST; settings::temperature_multipole = false; settings::temperature_range = {0.0, 0.0}; settings::temperature_tolerance = 10.0; - settings::properties_file.clear(); settings::trigger_on = false; settings::trigger_predict = false; settings::trigger_batch_interval = 1; - settings::uniform_source_sampling = false; settings::ufs_on = false; settings::urr_ptables_on = true; - settings::use_decay_photons = false; - settings::use_shared_secondary_bank = false; - settings::verbosity = -1; + settings::verbosity = 7; settings::weight_cutoff = 0.25; settings::weight_survive = 1.0; - settings::weight_windows_file.clear(); settings::weight_windows_on = false; settings::write_all_tracks = false; settings::write_initial_source = false; simulation::keff = 1.0; simulation::need_depletion_rx = false; - simulation::ssw_current_file = 1; simulation::total_gen = 0; simulation::entropy_mesh = nullptr; simulation::ufs_mesh = nullptr; - data::energy_max = {INFTY, INFTY, INFTY, INFTY}; - data::energy_min = {0.0, 0.0, 0.0, 0.0}; + data::energy_max = {INFTY, INFTY}; + data::energy_min = {0.0, 0.0}; data::temperature_min = 0.0; data::temperature_max = INFTY; - data::mg = {}; model::root_universe = -1; model::plotter_seed = 1; openmc::openmc_set_seed(DEFAULT_SEED); - openmc::openmc_set_stride(DEFAULT_STRIDE); // Deallocate arrays free_memory(); -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH settings::libmesh_init.reset(); #endif // Free all MPI types #ifdef OPENMC_MPI - if (mpi::source_site != MPI_DATATYPE_NULL) { + if (mpi::source_site != MPI_DATATYPE_NULL) MPI_Type_free(&mpi::source_site); - } - if (mpi::collision_track_site != MPI_DATATYPE_NULL) { - MPI_Type_free(&mpi::collision_track_site); - } #endif - openmc_finalize_random_ray(); - return 0; } int openmc_reset() { + model::universe_cell_counts.clear(); model::universe_level_counts.clear(); for (auto& t : model::tallies) { @@ -210,7 +164,7 @@ int openmc_reset() // Reset global tallies simulation::n_realizations = 0; - simulation::global_tallies.fill(0.0); + xt::view(simulation::global_tallies, xt::all()) = 0.0; simulation::k_col_abs = 0.0; simulation::k_col_tra = 0.0; @@ -221,7 +175,6 @@ int openmc_reset() settings::cmfd_run = false; simulation::n_lost_particles = 0; - simulation::simulation_tracks_completed = 0; return 0; } @@ -244,6 +197,5 @@ int openmc_hard_reset() // Reset the random number generator state openmc::openmc_set_seed(DEFAULT_SEED); - openmc::openmc_set_stride(DEFAULT_STRIDE); return 0; } diff --git a/src/geometry.cpp b/src/geometry.cpp index bf654f4f9..216650ff1 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -26,69 +26,44 @@ int n_coord_levels; vector overlap_check_count; -vector overlap_keys; -std::unordered_map overlap_key_index; - } // namespace model //============================================================================== // Non-member functions //============================================================================== -int check_cell_overlap(GeometryState& p, bool error) +bool check_cell_overlap(Particle& p, bool error) { int n_coord = p.n_coord(); - // If no overlap found, return a nonphysical index - int overlap_index = -1; - // Loop through each coordinate level for (int j = 0; j < n_coord; j++) { - Universe& univ = *model::universes[p.coord(j).universe()]; + Universe& univ = *model::universes[p.coord(j).universe]; // Loop through each cell on this level for (auto index_cell : univ.cells_) { Cell& c = *model::cells[index_cell]; - if (c.contains(p.coord(j).r(), p.coord(j).u(), p.surface())) { -#pragma omp atomic - ++model::overlap_check_count[index_cell]; - if (index_cell != p.coord(j).cell()) { + if (c.contains(p.coord(j).r, p.coord(j).u, p.surface())) { + if (index_cell != p.coord(j).cell) { if (error) { fatal_error( fmt::format("Overlapping cells detected: {}, {} on universe {}", - c.id_, model::cells[p.coord(j).cell()]->id_, univ.id_)); + c.id_, model::cells[p.coord(j).cell]->id_, univ.id_)); } - - // With no fatal error (plotter is calling), now adds overlaps and - // ensures order does not matter when making overlap key - int cell_a = model::cells[index_cell]->id_; - int cell_b = model::cells[p.coord(j).cell()]->id_; - int a = std::min(cell_a, cell_b); - int b = std::max(cell_a, cell_b); - OverlapKey key {univ.id_, a, b}; -#pragma omp critical(overlap_key_update) - { - auto it = model::overlap_key_index.find(key); - if (it != model::overlap_key_index.end()) { - overlap_index = it->second; // already exists, reuse index - } else { - int idx = int(model::overlap_keys.size()); - model::overlap_keys.push_back(key); - model::overlap_key_index[key] = idx; - overlap_index = idx; - } - } - break; + return true; } +#pragma omp atomic + ++model::overlap_check_count[index_cell]; } } } - return overlap_index; + + return false; } //============================================================================== -int cell_instance_at_level(const GeometryState& p, int level) +int cell_instance_at_level(const Particle& p, int level) { // throw error if the requested level is too deep for the geometry if (level > model::n_coord_levels) { @@ -98,7 +73,7 @@ int cell_instance_at_level(const GeometryState& p, int level) } // determine the cell instance - Cell& c {*model::cells[p.coord(level).cell()]}; + Cell& c {*model::cells[p.coord(level).cell]}; // quick exit if this cell doesn't have distribcell instances if (c.distribcell_index_ == C_NONE) @@ -107,13 +82,13 @@ int cell_instance_at_level(const GeometryState& p, int level) // compute the cell's instance int instance = 0; for (int i = 0; i < level; i++) { - const auto& c_i {*model::cells[p.coord(i).cell()]}; + const auto& c_i {*model::cells[p.coord(i).cell]}; if (c_i.type_ == Fill::UNIVERSE) { instance += c_i.offset_[c.distribcell_index_]; } else if (c_i.type_ == Fill::LATTICE) { instance += c_i.offset_[c.distribcell_index_]; - auto& lat {*model::lattices[p.coord(i + 1).lattice()]}; - const auto& i_xyz {p.coord(i + 1).lattice_index()}; + auto& lat {*model::lattices[p.coord(i + 1).lattice]}; + const auto& i_xyz {p.coord(i + 1).lattice_i}; if (lat.are_valid_indices(i_xyz)) { instance += lat.offset(c.distribcell_index_, i_xyz); } @@ -124,8 +99,7 @@ int cell_instance_at_level(const GeometryState& p, int level) //============================================================================== -bool find_cell_inner( - GeometryState& p, const NeighborList* neighbor_list, bool verbose) +bool find_cell_inner(Particle& p, const NeighborList* neighbor_list) { // Find which cell of this universe the particle is in. Use the neighbor list // to shorten the search if one was provided. @@ -136,7 +110,7 @@ bool find_cell_inner( i_cell = *it; // Make sure the search cell is in the same universe. - int i_universe = p.lowest_coord().universe(); + int i_universe = p.coord(p.n_coord() - 1).universe; if (model::cells[i_cell]->universe_ != i_universe) continue; @@ -145,7 +119,7 @@ bool find_cell_inner( Direction u {p.u_local()}; auto surf = p.surface(); if (model::cells[i_cell]->contains(r, u, surf)) { - p.lowest_coord().cell() = i_cell; + p.coord(p.n_coord() - 1).cell = i_cell; found = true; break; } @@ -171,7 +145,7 @@ bool find_cell_inner( // code below this conditional, we set i_cell back to C_NONE to indicate // that. if (i_cell == C_NONE) { - int i_universe = p.lowest_coord().universe(); + int i_universe = p.coord(p.n_coord() - 1).universe; const auto& univ {model::universes[i_universe]}; found = univ->find_cell(p); } @@ -179,10 +153,10 @@ bool find_cell_inner( if (!found) { return found; } - i_cell = p.lowest_coord().cell(); + i_cell = p.coord(p.n_coord() - 1).cell; // Announce the cell that the particle is entering. - if (found && verbose) { + if (found && (settings::verbosity >= 10 || p.trace())) { auto msg = fmt::format(" Entering cell {}", model::cells[i_cell]->id_); write_message(msg, 1); } @@ -197,13 +171,19 @@ bool find_cell_inner( p.cell_instance() = cell_instance_at_level(p, p.n_coord() - 1); } - // Set the material, temperature and density multiplier. + // Set the material and temperature. p.material_last() = p.material(); - p.material() = c.material(p.cell_instance()); + if (c.material_.size() > 1) { + p.material() = c.material_[p.cell_instance()]; + } else { + p.material() = c.material_[0]; + } p.sqrtkT_last() = p.sqrtkT(); - p.sqrtkT() = c.sqrtkT(p.cell_instance()); - p.density_mult_last() = p.density_mult(); - p.density_mult() = c.density_mult(p.cell_instance()); + if (c.sqrtkT_.size() > 1) { + p.sqrtkT() = c.sqrtkT_[p.cell_instance()]; + } else { + p.sqrtkT() = c.sqrtkT_[0]; + } return true; @@ -213,14 +193,14 @@ bool find_cell_inner( // Set the lower coordinate level universe. auto& coord {p.coord(p.n_coord())}; - coord.universe() = c.fill_; + coord.universe = c.fill_; // Set the position and direction. - coord.r() = p.r_local(); - coord.u() = p.u_local(); + coord.r = p.r_local(); + coord.u = p.u_local(); // Apply translation. - coord.r() -= c.translation_; + coord.r -= c.translation_; // Apply rotation. if (!c.rotation_.empty()) { @@ -235,11 +215,11 @@ bool find_cell_inner( // Set the position and direction. auto& coord {p.coord(p.n_coord())}; - coord.r() = p.r_local(); - coord.u() = p.u_local(); + coord.r = p.r_local(); + coord.u = p.u_local(); // Apply translation. - coord.r() -= c.translation_; + coord.r -= c.translation_; // Apply rotation. if (!c.rotation_.empty()) { @@ -247,25 +227,26 @@ bool find_cell_inner( } // Determine lattice indices. - auto& i_xyz {coord.lattice_index()}; - lat.get_indices(coord.r(), coord.u(), i_xyz); + auto& i_xyz {coord.lattice_i}; + lat.get_indices(coord.r, coord.u, i_xyz); // Get local position in appropriate lattice cell - coord.r() = lat.get_local_position(coord.r(), i_xyz); + coord.r = lat.get_local_position(coord.r, i_xyz); // Set lattice indices. - coord.lattice() = c.fill_; + coord.lattice = c.fill_; // Set the lower coordinate level universe. if (lat.are_valid_indices(i_xyz)) { - coord.universe() = lat[i_xyz]; + coord.universe = lat[i_xyz]; } else { if (lat.outer_ != NO_OUTER_UNIVERSE) { - coord.universe() = lat.outer_; + coord.universe = lat.outer_; } else { - p.mark_as_lost(fmt::format( - "Particle {} left lattice {}, but it has no outer definition.", + warning(fmt::format("Particle {} is outside lattice {} but the " + "lattice has no defined outer universe.", p.id(), lat.id_)); + return false; } } } @@ -278,7 +259,7 @@ bool find_cell_inner( //============================================================================== -bool neighbor_list_find_cell(GeometryState& p, bool verbose) +bool neighbor_list_find_cell(Particle& p) { // Reset all the deeper coordinate levels. @@ -288,29 +269,29 @@ bool neighbor_list_find_cell(GeometryState& p, bool verbose) // Get the cell this particle was in previously. auto coord_lvl = p.n_coord() - 1; - auto i_cell = p.coord(coord_lvl).cell(); + auto i_cell = p.coord(coord_lvl).cell; Cell& c {*model::cells[i_cell]}; // Search for the particle in that cell's neighbor list. Return if we // found the particle. - bool found = find_cell_inner(p, &c.neighbors_, verbose); + bool found = find_cell_inner(p, &c.neighbors_); if (found) return found; // The particle could not be found in the neighbor list. Try searching all // cells in this universe, and update the neighbor list if we find a new // neighboring cell. - found = find_cell_inner(p, nullptr, verbose); + found = find_cell_inner(p, nullptr); if (found) - c.neighbors_.push_back(p.coord(coord_lvl).cell()); + c.neighbors_.push_back(p.coord(coord_lvl).cell); return found; } -bool exhaustive_find_cell(GeometryState& p, bool verbose) +bool exhaustive_find_cell(Particle& p) { - int i_universe = p.lowest_coord().universe(); + int i_universe = p.coord(p.n_coord() - 1).universe; if (i_universe == C_NONE) { - p.coord(0).universe() = model::root_universe; + p.coord(0).universe = model::root_universe; p.n_coord() = 1; i_universe = model::root_universe; } @@ -318,53 +299,52 @@ bool exhaustive_find_cell(GeometryState& p, bool verbose) for (int i = p.n_coord(); i < model::n_coord_levels; i++) { p.coord(i).reset(); } - return find_cell_inner(p, nullptr, verbose); + return find_cell_inner(p, nullptr); } //============================================================================== -void cross_lattice(GeometryState& p, const BoundaryInfo& boundary, bool verbose) +void cross_lattice(Particle& p, const BoundaryInfo& boundary) { - auto& coord {p.lowest_coord()}; - auto& lat {*model::lattices[coord.lattice()]}; + auto& coord {p.coord(p.n_coord() - 1)}; + auto& lat {*model::lattices[coord.lattice]}; - if (verbose) { + if (settings::verbosity >= 10 || p.trace()) { write_message( fmt::format(" Crossing lattice {}. Current position ({},{},{}). r={}", - lat.id_, coord.lattice_index()[0], coord.lattice_index()[1], - coord.lattice_index()[2], p.r()), + lat.id_, coord.lattice_i[0], coord.lattice_i[1], coord.lattice_i[2], + p.r()), 1); } // Set the lattice indices. - coord.lattice_index()[0] += boundary.lattice_translation()[0]; - coord.lattice_index()[1] += boundary.lattice_translation()[1]; - coord.lattice_index()[2] += boundary.lattice_translation()[2]; + coord.lattice_i[0] += boundary.lattice_translation[0]; + coord.lattice_i[1] += boundary.lattice_translation[1]; + coord.lattice_i[2] += boundary.lattice_translation[2]; // Set the new coordinate position. const auto& upper_coord {p.coord(p.n_coord() - 2)}; - const auto& cell {model::cells[upper_coord.cell()]}; - Position r = upper_coord.r(); + const auto& cell {model::cells[upper_coord.cell]}; + Position r = upper_coord.r; r -= cell->translation_; if (!cell->rotation_.empty()) { r = r.rotate(cell->rotation_); } - p.r_local() = lat.get_local_position(r, coord.lattice_index()); + p.r_local() = lat.get_local_position(r, coord.lattice_i); - if (!lat.are_valid_indices(coord.lattice_index())) { + if (!lat.are_valid_indices(coord.lattice_i)) { // The particle is outside the lattice. Search for it from the base coords. p.n_coord() = 1; bool found = exhaustive_find_cell(p); - - if (!found) { - p.mark_as_lost(fmt::format("Particle {} could not be located after " - "crossing a boundary of lattice {}", - p.id(), lat.id_)); + if (!found && p.alive()) { + p.mark_as_lost(fmt::format("Could not locate particle {} after " + "crossing a lattice boundary", + p.id())); } } else { // Find cell in next lattice element. - p.lowest_coord().universe() = lat[coord.lattice_index()]; + p.coord(p.n_coord() - 1).universe = lat[coord.lattice_i]; bool found = exhaustive_find_cell(p); if (!found) { @@ -372,10 +352,10 @@ void cross_lattice(GeometryState& p, const BoundaryInfo& boundary, bool verbose) // this case, search for it from the base coords. p.n_coord() = 1; bool found = exhaustive_find_cell(p); - if (!found) { - p.mark_as_lost(fmt::format("Particle {} could not be located after " - "crossing a boundary of lattice {}", - p.id(), lat.id_)); + if (!found && p.alive()) { + p.mark_as_lost(fmt::format("Could not locate particle {} after " + "crossing a lattice boundary", + p.id())); } } } @@ -383,7 +363,7 @@ void cross_lattice(GeometryState& p, const BoundaryInfo& boundary, bool verbose) //============================================================================== -BoundaryInfo distance_to_boundary(GeometryState& p) +BoundaryInfo distance_to_boundary(Particle& p) { BoundaryInfo info; double d_lat = INFINITY; @@ -394,9 +374,9 @@ BoundaryInfo distance_to_boundary(GeometryState& p) // Loop over each coordinate level. for (int i = 0; i < p.n_coord(); i++) { const auto& coord {p.coord(i)}; - const Position& r {coord.r()}; - const Direction& u {coord.u()}; - Cell& c {*model::cells[coord.cell()]}; + const Position& r {coord.r}; + const Direction& u {coord.u}; + Cell& c {*model::cells[coord.cell]}; // Find the oncoming surface in this cell and the distance to it. auto surface_distance = c.distance(r, u, p.surface(), &p); @@ -404,73 +384,71 @@ BoundaryInfo distance_to_boundary(GeometryState& p) level_surf_cross = surface_distance.second; // Find the distance to the next lattice tile crossing. - if (coord.lattice() != C_NONE) { - auto& lat {*model::lattices[coord.lattice()]}; + if (coord.lattice != C_NONE) { + auto& lat {*model::lattices[coord.lattice]}; // TODO: refactor so both lattice use the same position argument (which // also means the lat.type attribute can be removed) std::pair> lattice_distance; switch (lat.type_) { case LatticeType::rect: - lattice_distance = lat.distance(r, u, coord.lattice_index()); + lattice_distance = lat.distance(r, u, coord.lattice_i); break; case LatticeType::hex: - auto& cell_above {model::cells[p.coord(i - 1).cell()]}; - Position r_hex {p.coord(i - 1).r()}; + auto& cell_above {model::cells[p.coord(i - 1).cell]}; + Position r_hex {p.coord(i - 1).r}; r_hex -= cell_above->translation_; - if (coord.rotated()) { + if (coord.rotated) { r_hex = r_hex.rotate(cell_above->rotation_); } - r_hex.z = coord.r().z; - lattice_distance = lat.distance(r_hex, u, coord.lattice_index()); + r_hex.z = coord.r.z; + lattice_distance = lat.distance(r_hex, u, coord.lattice_i); break; } d_lat = lattice_distance.first; level_lat_trans = lattice_distance.second; if (d_lat < 0) { - p.mark_as_lost(fmt::format("Particle {} had a negative distance " - "to a lattice boundary.", - p.id())); + p.mark_as_lost(fmt::format( + "Particle {} had a negative distance to a lattice boundary", p.id())); } } // If the boundary on this coordinate level is coincident with a boundary on // a higher level then we need to make sure that the higher level boundary // is selected. This logic must consider floating point precision. - double& d = info.distance(); + double& d = info.distance; if (d_surf < d_lat - FP_COINCIDENT) { if (d == INFINITY || (d - d_surf) / d >= FP_REL_PRECISION) { - // Update closest distance d = d_surf; // If the cell is not simple, it is possible that both the negative and // positive half-space were given in the region specification. Thus, we // have to explicitly check which half-space the particle would be // traveling into if the surface is crossed - if (c.is_simple() || d == INFTY) { - info.surface() = level_surf_cross; + if (c.simple_) { + info.surface_index = level_surf_cross; } else { Position r_hit = r + d_surf * u; Surface& surf {*model::surfaces[std::abs(level_surf_cross) - 1]}; Direction norm = surf.normal(r_hit); if (u.dot(norm) > 0) { - info.surface() = std::abs(level_surf_cross); + info.surface_index = std::abs(level_surf_cross); } else { - info.surface() = -std::abs(level_surf_cross); + info.surface_index = -std::abs(level_surf_cross); } } - info.lattice_translation()[0] = 0; - info.lattice_translation()[1] = 0; - info.lattice_translation()[2] = 0; - info.coord_level() = i + 1; + info.lattice_translation[0] = 0; + info.lattice_translation[1] = 0; + info.lattice_translation[2] = 0; + info.coord_level = i + 1; } } else { if (d == INFINITY || (d - d_lat) / d >= FP_REL_PRECISION) { d = d_lat; - info.surface() = SURFACE_NONE; - info.lattice_translation() = level_lat_trans; - info.coord_level() = i + 1; + info.surface_index = 0; + info.lattice_translation = level_lat_trans; + info.coord_level = i + 1; } } } @@ -484,19 +462,18 @@ BoundaryInfo distance_to_boundary(GeometryState& p) extern "C" int openmc_find_cell( const double* xyz, int32_t* index, int32_t* instance) { - GeometryState geom_state; + Particle p; - geom_state.r() = Position {xyz}; - geom_state.u() = {0.0, 0.0, 1.0}; + p.r() = Position {xyz}; + p.u() = {0.0, 0.0, 1.0}; - if (!exhaustive_find_cell(geom_state)) { - set_errmsg( - fmt::format("Could not find cell at position {}.", geom_state.r())); + if (!exhaustive_find_cell(p)) { + set_errmsg(fmt::format("Could not find cell at position {}.", p.r())); return OPENMC_E_GEOMETRY; } - *index = geom_state.lowest_coord().cell(); - *instance = geom_state.cell_instance(); + *index = p.coord(p.n_coord() - 1).cell; + *instance = p.cell_instance(); return 0; } @@ -505,14 +482,14 @@ extern "C" int openmc_global_bounding_box(double* llc, double* urc) auto bbox = model::universes.at(model::root_universe)->bounding_box(); // set lower left corner values - llc[0] = bbox.min.x; - llc[1] = bbox.min.y; - llc[2] = bbox.min.z; + llc[0] = bbox.xmin; + llc[1] = bbox.ymin; + llc[2] = bbox.zmin; // set upper right corner values - urc[0] = bbox.max.x; - urc[1] = bbox.max.y; - urc[2] = bbox.max.z; + urc[0] = bbox.xmax; + urc[1] = bbox.ymax; + urc[2] = bbox.zmax; return 0; } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index a740740c1..ddce2469b 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -25,9 +25,21 @@ namespace openmc { namespace model { +std::unordered_map> + universe_cell_counts; std::unordered_map universe_level_counts; } // namespace model +// adds the cell counts of universe b to universe a +void update_universe_cell_count(int32_t a, int32_t b) +{ + auto& universe_a_counts = model::universe_cell_counts[a]; + const auto& universe_b_counts = model::universe_cell_counts[b]; + for (const auto& it : universe_b_counts) { + universe_a_counts[it.first] += it.second; + } +} + void read_geometry_xml() { // Display output message @@ -49,19 +61,9 @@ void read_geometry_xml() // Get root element pugi::xml_node root = doc.document_element(); - read_geometry_xml(root); -} - -void read_geometry_xml(pugi::xml_node root) -{ // Read surfaces, cells, lattice - std::set> periodic_pairs; - std::unordered_map albedo_map; - std::unordered_map periodic_sense_map; - - read_surfaces(root, periodic_pairs, albedo_map, periodic_sense_map); + read_surfaces(root); read_cells(root); - prepare_boundary_conditions(periodic_pairs, albedo_map, periodic_sense_map); read_lattices(root); // Check to make sure a boundary condition was applied to at least one @@ -74,8 +76,7 @@ void read_geometry_xml(pugi::xml_node root) } } - if (settings::run_mode != RunMode::PLOTTING && - settings::run_mode != RunMode::VOLUME && !boundary_exists) { + if (settings::run_mode != RunMode::PLOTTING && !boundary_exists) { fatal_error("No boundary conditions were applied to any surfaces!"); } @@ -153,8 +154,9 @@ void partition_universes() // Collect the set of surfaces in this universe. std::unordered_set surf_inds; for (auto i_cell : univ->cells_) { - for (auto token : model::cells[i_cell]->surfaces()) { - surf_inds.insert(std::abs(token) - 1); + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) + surf_inds.insert(std::abs(token) - 1); } } @@ -200,24 +202,6 @@ void assign_temperatures() //============================================================================== -void finalize_cell_densities() -{ - for (auto& c : model::cells) { - // Convert to density multipliers. - if (!c->density_mult_.empty()) { - for (int32_t instance = 0; instance < c->density_mult_.size(); - ++instance) { - c->density_mult_[instance] /= - model::materials[c->material(instance)]->density_gpcc(); - } - } else { - c->density_mult_ = {1.0}; - } - } -} - -//============================================================================== - void get_temperatures( vector>& nuc_temps, vector>& thermal_temps) { @@ -274,7 +258,7 @@ void finalize_geometry() { // Perform some final operations to set up the geometry adjust_indices(); - count_universe_instances(); + count_cell_instances(model::root_universe); partition_universes(); // Assign temperatures to cells that don't have temperatures already assigned @@ -355,7 +339,7 @@ void prepare_distribcell(const std::vector* user_distribcells) // By default, add material cells to the list of distributed cells if (settings::material_cell_offsets) { - for (int64_t i = 0; i < model::cells.size(); ++i) { + for (gsl::index i = 0; i < model::cells.size(); ++i) { if (model::cells[i]->type_ == Fill::MATERIAL) distribcells.insert(i); } @@ -367,49 +351,35 @@ void prepare_distribcell(const std::vector* user_distribcells) Cell& c {*model::cells[i]}; if (c.material_.size() > 1) { - if (c.material_.size() != c.n_instances()) { + if (c.material_.size() != c.n_instances_) { fatal_error(fmt::format( "Cell {} was specified with {} materials but has {} distributed " "instances. The number of materials must equal one or the number " "of instances.", - c.id_, c.material_.size(), c.n_instances())); + c.id_, c.material_.size(), c.n_instances_)); } } if (c.sqrtkT_.size() > 1) { - if (c.sqrtkT_.size() != c.n_instances()) { + if (c.sqrtkT_.size() != c.n_instances_) { fatal_error(fmt::format( "Cell {} was specified with {} temperatures but has {} distributed " "instances. The number of temperatures must equal one or the number " "of instances.", - c.id_, c.sqrtkT_.size(), c.n_instances())); - } - } - - if (c.density_mult_.size() > 1) { - if (c.density_mult_.size() != c.n_instances()) { - fatal_error(fmt::format("Cell {} was specified with {} density " - "multipliers but has {} distributed " - "instances. The number of density multipliers " - "must equal one or the number " - "of instances.", - c.id_, c.density_mult_.size(), c.n_instances())); + c.id_, c.sqrtkT_.size(), c.n_instances_)); } } } // Search through universes for material cells and assign each one a - // distribcell array index according to the containing universe. + // unique distribcell array index. + int distribcell_index = 0; vector target_univ_ids; for (const auto& u : model::universes) { for (auto idx : u->cells_) { if (distribcells.find(idx) != distribcells.end()) { - if (!contains(target_univ_ids, u->id_)) { - target_univ_ids.push_back(u->id_); - } - model::cells[idx]->distribcell_index_ = - std::find(target_univ_ids.begin(), target_univ_ids.end(), u->id_) - - target_univ_ids.begin(); + model::cells[idx]->distribcell_index_ = distribcell_index++; + target_univ_ids.push_back(u->id_); } } } @@ -444,7 +414,8 @@ void prepare_distribcell(const std::vector* user_distribcells) } else if (c.type_ == Fill::LATTICE) { c.offset_[map] = offset; Lattice& lat = *model::lattices[c.fill_]; - offset += lat.fill_offset_table(target_univ_id, map, univ_count_memo); + offset += + lat.fill_offset_table(offset, target_univ_id, map, univ_count_memo); } } } @@ -453,12 +424,32 @@ void prepare_distribcell(const std::vector* user_distribcells) //============================================================================== -void count_universe_instances() +void count_cell_instances(int32_t univ_indx) { - for (auto& univ : model::universes) { - std::unordered_map univ_count_memo; - univ->n_instances_ = count_universe_instances( - model::root_universe, univ->id_, univ_count_memo); + const auto univ_counts = model::universe_cell_counts.find(univ_indx); + if (univ_counts != model::universe_cell_counts.end()) { + for (const auto& it : univ_counts->second) { + model::cells[it.first]->n_instances_ += it.second; + } + } else { + for (int32_t cell_indx : model::universes[univ_indx]->cells_) { + Cell& c = *model::cells[cell_indx]; + ++c.n_instances_; + model::universe_cell_counts[univ_indx][cell_indx] += 1; + + if (c.type_ == Fill::UNIVERSE) { + // This cell contains another universe. Recurse into that universe. + count_cell_instances(c.fill_); + update_universe_cell_count(univ_indx, c.fill_); + } else if (c.type_ == Fill::LATTICE) { + // This cell contains a lattice. Recurse into the lattice universes. + Lattice& lat = *model::lattices[c.fill_]; + for (auto it = lat.begin(); it != lat.end(); ++it) { + count_cell_instances(*it); + update_universe_cell_count(univ_indx, *it); + } + } + } } } @@ -532,11 +523,13 @@ std::string distribcell_path_inner(int32_t target_cell, int32_t map, // Material cells don't contain other cells so ignore them. if (c.type_ != Fill::MATERIAL) { - int32_t temp_offset = offset + c.offset_[map]; - if (c.type_ == Fill::LATTICE) { + int32_t temp_offset; + if (c.type_ == Fill::UNIVERSE) { + temp_offset = offset + c.offset_[map]; + } else { Lattice& lat = *model::lattices[c.fill_]; int32_t indx = lat.universes_.size() * map + lat.begin().indx_; - temp_offset += lat.offsets_[indx]; + temp_offset = offset + lat.offsets_[indx]; } // The desired cell is the first cell that gives an offset smaller or @@ -546,15 +539,6 @@ std::string distribcell_path_inner(int32_t target_cell, int32_t map, } } - // if we get through the loop without finding an appropriate entry, throw - // an error - if (cell_it == search_univ.cells_.crend()) { - fatal_error( - fmt::format("Failed to generate a text label for distribcell with ID {}." - "The current label is: '{}'", - model::cells[target_cell]->id_, path.str())); - } - // Add the cell to the path string. Cell& c = *model::cells[*cell_it]; path << "c" << c.id_ << "->"; @@ -571,7 +555,7 @@ std::string distribcell_path_inner(int32_t target_cell, int32_t map, path << "l" << lat.id_; for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) { int32_t indx = lat.universes_.size() * map + it.indx_; - int32_t temp_offset = offset + lat.offsets_[indx] + c.offset_[map]; + int32_t temp_offset = offset + lat.offsets_[indx]; if (temp_offset <= target_offset) { offset = temp_offset; path << "(" << lat.index_to_string(it.indx_) << ")->"; @@ -622,11 +606,6 @@ int maximum_levels(int32_t univ) return levels_below; } -bool is_root_universe(int32_t univ_id) -{ - return model::universe_map[univ_id] == model::root_universe; -} - //============================================================================== void free_memory_geometry() diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 00c6a4399..27b750b93 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -4,7 +4,8 @@ #include #include -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" +#include "xtensor/xtensor.hpp" #include #include "hdf5.h" @@ -91,7 +92,7 @@ void get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims) H5Aclose(attr); } -hid_t create_group(hid_t parent_id, const char* name) +hid_t create_group(hid_t parent_id, char const* name) { hid_t out = H5Gcreate(parent_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (out < 0) { @@ -224,7 +225,8 @@ void get_name(hid_t obj_id, std::string& name) { size_t size = 1 + H5Iget_name(obj_id, nullptr, 0); name.resize(size); - H5Iget_name(obj_id, name.data(), size); + // TODO: switch to name.data() when using C++17 + H5Iget_name(obj_id, &name[0], size); } int get_num_datasets(hid_t group_id) @@ -465,19 +467,22 @@ void read_dataset_lowlevel(hid_t obj_id, const char* name, hid_t mem_type_id, } template<> -void read_dataset( - hid_t dset, tensor::Tensor>& tensor, bool indep) +void read_dataset(hid_t dset, xt::xarray>& arr, bool indep) { // Get shape of dataset vector shape = object_shape(dset); - // Resize tensor and read data directly - vector tshape(shape.begin(), shape.end()); - tensor.resize(tshape); + // Allocate new array to read data into + std::size_t size = 1; + for (const auto x : shape) + size *= x; + vector> buffer(size); - // Read data from dataset - read_complex(dset, nullptr, - reinterpret_cast*>(tensor.data()), indep); + // Read data from attribute + read_complex(dset, nullptr, buffer.data(), indep); + + // Adapt into xarray + arr = xt::adapt(buffer, shape); } void read_double(hid_t obj_id, const char* name, double* buffer, bool indep) @@ -532,14 +537,14 @@ void read_complex( H5Tclose(complex_id); } -void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - hsize_t n_results, double* results) +void read_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) { // Create dataspace for hyperslab in memory constexpr int ndim = 3; - hsize_t dims[ndim] {n_filter, n_score, n_results}; + hsize_t dims[ndim] {n_filter, n_score, 3}; hsize_t start[ndim] {0, 0, 1}; - hsize_t count[ndim] {n_filter, n_score, n_results - 1}; + hsize_t count[ndim] {n_filter, n_score, 2}; hid_t memspace = H5Screate_simple(ndim, dims, nullptr); H5Sselect_hyperslab(memspace, H5S_SELECT_SET, start, nullptr, count, nullptr); @@ -682,15 +687,15 @@ void write_string( group_id, 0, nullptr, buffer.length(), name, buffer.c_str(), indep); } -void write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - hsize_t n_results, const double* results) +void write_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, const double* results) { // Set dimensions of sum/sum_sq hyperslab to store constexpr int ndim = 3; - hsize_t count[ndim] {n_filter, n_score, n_results - 1}; + hsize_t count[ndim] {n_filter, n_score, 2}; // Set dimensions of results array - hsize_t dims[ndim] {n_filter, n_score, n_results}; + hsize_t dims[ndim] {n_filter, n_score, 3}; hsize_t start[ndim] {0, 0, 1}; hid_t memspace = H5Screate_simple(ndim, dims, nullptr); H5Sselect_hyperslab(memspace, H5S_SELECT_SET, start, nullptr, count, nullptr); diff --git a/src/ifp.cpp b/src/ifp.cpp deleted file mode 100644 index f0f98b8ef..000000000 --- a/src/ifp.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "openmc/ifp.h" - -#include "openmc/bank.h" -#include "openmc/message_passing.h" -#include "openmc/particle.h" -#include "openmc/particle_data.h" -#include "openmc/settings.h" -#include "openmc/simulation.h" -#include "openmc/vector.h" - -namespace openmc { - -bool is_beta_effective_or_both() -{ - if (settings::ifp_parameter == IFPParameter::BetaEffective || - settings::ifp_parameter == IFPParameter::Both) { - return true; - } - return false; -} - -bool is_generation_time_or_both() -{ - if (settings::ifp_parameter == IFPParameter::GenerationTime || - settings::ifp_parameter == IFPParameter::Both) { - return true; - } - return false; -} - -void ifp(const Particle& p, int64_t idx) -{ - if (is_beta_effective_or_both()) { - const auto& delayed_groups = - simulation::ifp_source_delayed_group_bank[p.current_work()]; - simulation::ifp_fission_delayed_group_bank[idx] = - _ifp(p.delayed_group(), delayed_groups); - } - if (is_generation_time_or_both()) { - const auto& lifetimes = - simulation::ifp_source_lifetime_bank[p.current_work()]; - simulation::ifp_fission_lifetime_bank[idx] = _ifp(p.lifetime(), lifetimes); - } -} - -void resize_simulation_ifp_banks() -{ - resize_ifp_data(simulation::ifp_source_delayed_group_bank, - simulation::ifp_source_lifetime_bank, simulation::work_per_rank); - resize_ifp_data(simulation::ifp_fission_delayed_group_bank, - simulation::ifp_fission_lifetime_bank, 3 * simulation::work_per_rank); -} - -void copy_ifp_data_from_fission_banks( - int i_bank, vector& delayed_groups, vector& lifetimes) -{ - if (is_beta_effective_or_both()) { - delayed_groups = simulation::ifp_fission_delayed_group_bank[i_bank]; - } - if (is_generation_time_or_both()) { - lifetimes = simulation::ifp_fission_lifetime_bank[i_bank]; - } -} - -#ifdef OPENMC_MPI -void broadcast_ifp_n_generation(int& n_generation, - const vector>& delayed_groups, - const vector>& lifetimes) -{ - if (mpi::rank == 0) { - if (is_beta_effective_or_both()) { - n_generation = static_cast(delayed_groups[0].size()); - } else { - n_generation = static_cast(lifetimes[0].size()); - } - } - MPI_Bcast(&n_generation, 1, MPI_INT, 0, mpi::intracomm); -} - -void copy_partial_ifp_data_to_source_banks(int64_t idx, int n, int64_t i_bank, - const vector>& delayed_groups, - const vector>& lifetimes) -{ - if (is_beta_effective_or_both()) { - std::copy(&delayed_groups[idx], &delayed_groups[idx + n], - &simulation::ifp_source_delayed_group_bank[i_bank]); - } - if (is_generation_time_or_both()) { - std::copy(&lifetimes[idx], &lifetimes[idx + n], - &simulation::ifp_source_lifetime_bank[i_bank]); - } -} -#endif - -void copy_complete_ifp_data_to_source_banks( - const vector>& delayed_groups, - const vector>& lifetimes) -{ - if (is_beta_effective_or_both()) { - std::copy(delayed_groups.data(), - delayed_groups.data() + settings::n_particles, - simulation::ifp_source_delayed_group_bank.begin()); - } - if (is_generation_time_or_both()) { - std::copy(lifetimes.data(), lifetimes.data() + settings::n_particles, - simulation::ifp_source_lifetime_bank.begin()); - } -} - -void allocate_temporary_vector_ifp( - vector>& delayed_groups, vector>& lifetimes) -{ - if (is_beta_effective_or_both()) { - delayed_groups.resize(simulation::fission_bank.size()); - } - if (is_generation_time_or_both()) { - lifetimes.resize(simulation::fission_bank.size()); - } -} - -void copy_ifp_data_to_fission_banks(const vector* const delayed_groups_ptr, - const vector* lifetimes_ptr) -{ - if (is_beta_effective_or_both()) { - std::copy(delayed_groups_ptr, - delayed_groups_ptr + simulation::fission_bank.size(), - simulation::ifp_fission_delayed_group_bank.data()); - } - if (is_generation_time_or_both()) { - std::copy(lifetimes_ptr, lifetimes_ptr + simulation::fission_bank.size(), - simulation::ifp_fission_lifetime_bank.data()); - } -} - -} // namespace openmc diff --git a/src/initialize.cpp b/src/initialize.cpp index 78b414f78..9c20a1f3c 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -1,6 +1,5 @@ #include "openmc/initialize.h" -#include #include #include // for getenv #include @@ -12,11 +11,9 @@ #include #include "openmc/capi.h" -#include "openmc/chain.h" #include "openmc/constants.h" #include "openmc/cross_sections.h" #include "openmc/error.h" -#include "openmc/file_utils.h" #include "openmc/geometry_aux.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" @@ -24,7 +21,6 @@ #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" -#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/plot.h" #include "openmc/random_lcg.h" @@ -36,9 +32,8 @@ #include "openmc/thermal.h" #include "openmc/timer.h" #include "openmc/vector.h" -#include "openmc/weight_windows.h" -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH #include "libmesh/libmesh.h" #endif @@ -64,8 +59,14 @@ int openmc_init(int argc, char* argv[], const void* intracomm) if (err) return err; -#ifdef OPENMC_LIBMESH_ENABLED - const int n_threads = num_threads(); +#ifdef LIBMESH + +#ifdef _OPENMP + int n_threads = omp_get_max_threads(); +#else + int n_threads = 1; +#endif + // initialize libMesh if it hasn't been initialized already // (if initialized externally, the libmesh_init object needs to be provided // also) @@ -99,36 +100,12 @@ int openmc_init(int argc, char* argv[], const void* intracomm) } #endif - // Initialize random number generator -- if the user specifies a seed and/or - // stride, it will be re-initialized later + // Initialize random number generator -- if the user specifies a seed, it + // will be re-initialized later openmc::openmc_set_seed(DEFAULT_SEED); - openmc::openmc_set_stride(DEFAULT_STRIDE); - - // Copy previous locale and set locale to C. This is a workaround for an issue - // whereby when openmc_init is called from the plotter, the Qt application - // framework first calls std::setlocale, which affects how pugixml reads - // floating point numbers due to a bug: - // https://github.com/zeux/pugixml/issues/469 - std::string prev_locale = std::setlocale(LC_ALL, nullptr); - if (std::setlocale(LC_ALL, "C") == NULL) { - fatal_error("Cannot set locale to C."); - } // Read XML input files - if (!read_model_xml()) - read_separate_xml_files(); - - if (!settings::properties_file.empty()) { - openmc_properties_import(settings::properties_file.c_str()); - } - - // Reset locale to previous state - if (std::setlocale(LC_ALL, prev_locale.c_str()) == NULL) { - fatal_error("Cannot reset locale."); - } - - // Write some initial output under the header if needed - initial_output(); + read_input_xml(); // Check for particle restart run if (settings::particle_restart_run) @@ -161,7 +138,7 @@ void initialize_mpi(MPI_Comm intracomm) // Create bank datatype SourceSite b; - MPI_Aint disp[14]; + MPI_Aint disp[10]; MPI_Get_address(&b.r, &disp[0]); MPI_Get_address(&b.u, &disp[1]); MPI_Get_address(&b.E, &disp[2]); @@ -170,70 +147,17 @@ void initialize_mpi(MPI_Comm intracomm) MPI_Get_address(&b.delayed_group, &disp[5]); MPI_Get_address(&b.surf_id, &disp[6]); MPI_Get_address(&b.particle, &disp[7]); - MPI_Get_address(&b.parent_nuclide, &disp[8]); - MPI_Get_address(&b.parent_id, &disp[9]); - MPI_Get_address(&b.progeny_id, &disp[10]); - MPI_Get_address(&b.wgt_born, &disp[11]); - MPI_Get_address(&b.wgt_ww_born, &disp[12]); - MPI_Get_address(&b.n_split, &disp[13]); - for (int i = 13; i >= 0; --i) { + MPI_Get_address(&b.parent_id, &disp[8]); + MPI_Get_address(&b.progeny_id, &disp[9]); + for (int i = 9; i >= 0; --i) { disp[i] -= disp[0]; } - // Block counts for each field - int blocks[] = {3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - - // Types for each field - MPI_Datatype types[] = { - MPI_DOUBLE, // r (3 doubles) - MPI_DOUBLE, // u (3 doubles) - MPI_DOUBLE, // E - MPI_DOUBLE, // time - MPI_DOUBLE, // wgt - MPI_INT, // delayed_group - MPI_INT, // surf_id - MPI_INT, // particle (enum) - MPI_INT, // parent_nuclide - MPI_INT64_T, // parent_id - MPI_INT64_T, // progeny_id - MPI_DOUBLE, // wgt_born - MPI_DOUBLE, // wgt_ww_born - MPI_INT64_T // n_split - }; - - MPI_Type_create_struct(14, blocks, disp, types, &mpi::source_site); + int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1}; + MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, + MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG}; + MPI_Type_create_struct(10, blocks, disp, types, &mpi::source_site); MPI_Type_commit(&mpi::source_site); - - CollisionTrackSite bc; - MPI_Aint dispc[16]; - MPI_Get_address(&bc.r, &dispc[0]); // double - MPI_Get_address(&bc.u, &dispc[1]); // double - MPI_Get_address(&bc.E, &dispc[2]); // double - MPI_Get_address(&bc.dE, &dispc[3]); // double - MPI_Get_address(&bc.time, &dispc[4]); // double - MPI_Get_address(&bc.wgt, &dispc[5]); // double - MPI_Get_address(&bc.event_mt, &dispc[6]); // int - MPI_Get_address(&bc.delayed_group, &dispc[7]); // int - MPI_Get_address(&bc.cell_id, &dispc[8]); // int - MPI_Get_address(&bc.nuclide_id, &dispc[9]); // int - MPI_Get_address(&bc.material_id, &dispc[10]); // int - MPI_Get_address(&bc.universe_id, &dispc[11]); // int - MPI_Get_address(&bc.n_collision, &dispc[12]); // int - MPI_Get_address(&bc.particle, &dispc[13]); // int - MPI_Get_address(&bc.parent_id, &dispc[14]); // int64_t - MPI_Get_address(&bc.progeny_id, &dispc[15]); // int64_t - for (int i = 15; i >= 0; --i) { - dispc[i] -= dispc[0]; - } - - int blocksc[] = {3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - MPI_Datatype typesc[] = {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, MPI_INT, MPI_INT64_T, MPI_INT64_T}; - - MPI_Type_create_struct( - 16, blocksc, dispc, typesc, &mpi::collision_track_site); - MPI_Type_commit(&mpi::collision_track_site); } #endif // OPENMC_MPI @@ -251,19 +175,12 @@ int parse_command_line(int argc, char* argv[]) i += 1; settings::n_particles = std::stoll(argv[i]); - } else if (arg == "-q" || arg == "--verbosity") { - i += 1; - settings::verbosity = std::stoi(argv[i]); - if (settings::verbosity > 10 || settings::verbosity < 1) { - auto msg = fmt::format("Invalid verbosity: {}.", settings::verbosity); - strcpy(openmc_err_msg, msg.c_str()); - return OPENMC_E_INVALID_ARGUMENT; - } - } else if (arg == "-e" || arg == "--event") { settings::event_based = true; + } else if (arg == "-r" || arg == "--restart") { i += 1; + // Check what type of file this is hid_t file_id = file_open(argv[i], 'r', true); std::string filetype; @@ -273,7 +190,6 @@ int parse_command_line(int argc, char* argv[]) // Set path and flag for type of run if (filetype == "statepoint") { settings::path_statepoint = argv[i]; - settings::path_statepoint_c = settings::path_statepoint.c_str(); settings::restart_run = true; } else if (filetype == "particle restart") { settings::path_particle_restart = argv[i]; @@ -321,11 +237,6 @@ int parse_command_line(int argc, char* argv[]) settings::run_mode = RunMode::VOLUME; } else if (arg == "-s" || arg == "--threads") { // Read number of threads - if (i + 1 >= argc) { - std::string msg {"Number of threads not specified."}; - strcpy(openmc_err_msg, msg.c_str()); - return OPENMC_E_INVALID_ARGUMENT; - } i += 1; #ifdef _OPENMP @@ -349,7 +260,6 @@ int parse_command_line(int argc, char* argv[]) } else if (arg == "-v" || arg == "--version") { print_version(); - print_build_info(); return OPENMC_E_UNASSIGNED; } else if (arg == "-t" || arg == "--track") { @@ -369,17 +279,8 @@ int parse_command_line(int argc, char* argv[]) if (argc > 1 && last_flag < argc - 1) { settings::path_input = std::string(argv[last_flag + 1]); - // check that the path is either a valid directory or file - if (!dir_exists(settings::path_input) && - !file_exists(settings::path_input)) { - fatal_error(fmt::format( - "The path specified to the OpenMC executable '{}' does not exist.", - settings::path_input)); - } - // Add slash at end of directory if it isn't there - if (!ends_with(settings::path_input, "/") && - dir_exists(settings::path_input)) { + if (!ends_with(settings::path_input, "/")) { settings::path_input += "/"; } } @@ -387,154 +288,10 @@ int parse_command_line(int argc, char* argv[]) return 0; } -// TODO: Pulse-height tallies require per-history scoring across the full -// particle tree (parent + all descendants). The shared secondary bank -// transports each secondary as an independent Particle, breaking this -// assumption. A proper fix would defer pulse-height scoring: save -// (root_source_id, cell, pht_storage) per particle, then aggregate by -// root_source_id after all secondary generations complete before scoring -// into the histogram. For now, disable shared secondary when pulse-height -// tallies are present. -static void check_pulse_height_compatibility() +void read_input_xml() { - if (settings::use_shared_secondary_bank) { - for (const auto& t : model::tallies) { - if (t->type_ == TallyType::PULSE_HEIGHT) { - settings::use_shared_secondary_bank = false; - warning("Pulse-height tallies are not yet compatible with the shared " - "secondary bank. Disabling shared secondary bank."); - break; - } - } - } -} - -bool read_model_xml() -{ - std::string model_filename = settings::path_input; - - // if the current filename is a directory, append the default model filename - if (model_filename.empty() || dir_exists(model_filename)) - model_filename += "model.xml"; - - // if this file doesn't exist, stop here - if (!file_exists(model_filename)) - return false; - - // try to process the path input as an XML file - pugi::xml_document doc; - if (!doc.load_file(model_filename.c_str())) { - fatal_error(fmt::format( - "Error reading from single XML input file '{}'", model_filename)); - } - - pugi::xml_node root = doc.document_element(); - - // Read settings - if (!check_for_node(root, "settings")) { - fatal_error("No node present in the model.xml file."); - } - auto settings_root = root.child("settings"); - - // Verbosity - if (check_for_node(settings_root, "verbosity") && settings::verbosity == -1) { - settings::verbosity = std::stoi(get_node_value(settings_root, "verbosity")); - } else if (settings::verbosity == -1) { - settings::verbosity = 7; - } - - // To this point, we haven't displayed any output since we didn't know what - // the verbosity is. Now that we checked for it, show the title if necessary - if (mpi::master) { - if (settings::verbosity >= 2) - title(); - } - - write_message( - fmt::format("Reading model XML file '{}' ...", model_filename), 5); - - // Read chain data before settings so DecaySpectrum source distributions can - // resolve nuclides while sources are constructed. - read_chain_file_xml(); - - read_settings_xml(settings_root); - - // If other XML files are present, display warning - // that they will be ignored - auto other_inputs = {"materials.xml", "geometry.xml", "settings.xml", - "tallies.xml", "plots.xml"}; - for (const auto& input : other_inputs) { - if (file_exists(settings::path_input + input)) { - warning((fmt::format("Other XML file input(s) are present. These files " - "may be ignored in favor of the {} file.", - model_filename))); - break; - } - } - - // Read materials and cross sections - if (!check_for_node(root, "materials")) { - fatal_error(fmt::format( - "No node present in the {} file.", model_filename)); - } - - if (settings::run_mode != RunMode::PLOTTING) { - read_cross_sections_xml(root.child("materials")); - } - read_materials_xml(root.child("materials")); - - // Read geometry - if (!check_for_node(root, "geometry")) { - fatal_error(fmt::format( - "No node present in the {} file.", model_filename)); - } - read_geometry_xml(root.child("geometry")); - - // Final geometry setup and assign temperatures - finalize_geometry(); - - // Finalize cross sections having assigned temperatures - finalize_cross_sections(); - - // Compute cell density multipliers now that material densities - // have been finalized (from geometry_aux.h) - finalize_cell_densities(); - - if (check_for_node(root, "tallies")) - read_tallies_xml(root.child("tallies")); - - check_pulse_height_compatibility(); - - // Initialize distribcell_filters - prepare_distribcell(); - - if (check_for_node(root, "plots")) { - read_plots_xml(root.child("plots")); - } else { - // When no element is present in the model.xml file, check for a - // regular plots.xml file - std::string filename = settings::path_input + "plots.xml"; - if (file_exists(filename)) { - read_plots_xml(); - } - } - - finalize_variance_reduction(); - - return true; -} - -void read_separate_xml_files() -{ - // Read chain data before settings so DecaySpectrum source distributions can - // resolve nuclides while sources are constructed. - read_chain_file_xml(); - read_settings_xml(); - if (settings::run_mode != RunMode::PLOTTING) { - read_cross_sections_xml(); - } - + read_cross_sections_xml(); read_materials_xml(); read_geometry_xml(); @@ -544,27 +301,14 @@ void read_separate_xml_files() // Finalize cross sections having assigned temperatures finalize_cross_sections(); - // Compute cell density multipliers now that material densities - // have been finalized (from geometry_aux.h) - finalize_cell_densities(); - read_tallies_xml(); - check_pulse_height_compatibility(); - // Initialize distribcell_filters prepare_distribcell(); // Read the plots.xml regardless of plot mode in case plots are requested // via the API read_plots_xml(); - - finalize_variance_reduction(); -} - -void initial_output() -{ - // write initial output if (settings::run_mode == RunMode::PLOTTING) { // Read plots.xml if it exists if (mpi::master && settings::verbosity >= 5) diff --git a/src/lattice.cpp b/src/lattice.cpp index 9e56c58e8..fa2e2828e 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -10,7 +10,6 @@ #include "openmc/geometry.h" #include "openmc/geometry_aux.h" #include "openmc/hdf5_interface.h" -#include "openmc/math_functions.h" #include "openmc/string_utils.h" #include "openmc/vector.h" #include "openmc/xml_interface.h" @@ -59,11 +58,6 @@ LatticeIter Lattice::end() return LatticeIter(*this, universes_.size()); } -int32_t& Lattice::back() -{ - return universes_.back(); -} - ReverseLatticeIter Lattice::rbegin() { return ReverseLatticeIter(*this, universes_.size() - 1); @@ -104,28 +98,25 @@ void Lattice::adjust_indices() //============================================================================== -int32_t Lattice::fill_offset_table(int32_t target_univ_id, int map, - std::unordered_map& univ_count_memo) +int32_t Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, + int map, std::unordered_map& univ_count_memo) { // If the offsets have already been determined for this "map", don't bother // recalculating all of them and just return the total offset. Note that the // offsets_ array doesn't actually include the offset accounting for the last // universe, so we get the before-last offset for the given map and then // explicitly add the count for the last universe. - if (offsets_[map * universes_.size() + this->begin().indx_] != C_NONE) { - int last_offset = - offsets_[(map + 1) * universes_.size() - this->begin().indx_ - 1]; - int last_univ = this->back(); + if (offsets_[map * universes_.size()] != C_NONE) { + int last_offset = offsets_[(map + 1) * universes_.size() - 1]; + int last_univ = universes_.back(); return last_offset + count_universe_instances(last_univ, target_univ_id, univ_count_memo); } - int32_t offset = 0; for (LatticeIter it = begin(); it != end(); ++it) { offsets_[map * universes_.size() + it.indx_] = offset; offset += count_universe_instances(*it, target_univ_id, univ_count_memo); } - return offset; } @@ -234,14 +225,14 @@ RectLattice::RectLattice(pugi::xml_node lat_node) : Lattice {lat_node} //============================================================================== -const int32_t& RectLattice::operator[](const array& i_xyz) +int32_t const& RectLattice::operator[](array const& i_xyz) { return universes_[get_flat_index(i_xyz)]; } //============================================================================== -bool RectLattice::are_valid_indices(const array& i_xyz) const +bool RectLattice::are_valid_indices(array const& i_xyz) const { return ((i_xyz[0] >= 0) && (i_xyz[0] < n_cells_[0]) && (i_xyz[1] >= 0) && (i_xyz[1] < n_cells_[1]) && (i_xyz[2] >= 0) && @@ -262,32 +253,46 @@ std::pair> RectLattice::distance( double x0 {copysign(0.5 * pitch_[0], u.x)}; double y0 {copysign(0.5 * pitch_[1], u.y)}; - // Evaluate the distance to each oncoming edge independently. Comparing these - // distances directly (rather than reconstructing the crossing position) - // avoids the floating-point cancellation that occurs for large pitches. - double dx = u.x != 0.0 ? (x0 - x) / u.x : INFTY; - double dy = u.y != 0.0 ? (y0 - y) / u.y : INFTY; - double dz = INFTY; - if (is_3d_) { - double z0 {copysign(0.5 * pitch_[2], u.z)}; - dz = u.z != 0.0 ? (z0 - z) / u.z : INFTY; + // Left and right sides + double d {INFTY}; + array lattice_trans; + if ((std::abs(x - x0) > FP_PRECISION) && u.x != 0) { + d = (x0 - x) / u.x; + if (u.x > 0) { + lattice_trans = {1, 0, 0}; + } else { + lattice_trans = {-1, 0, 0}; + } } - // The distance to the nearest lattice boundary is the smallest axial - // distance. - double d = std::min({dx, dy, dz}); + // Front and back sides + if ((std::abs(y - y0) > FP_PRECISION) && u.y != 0) { + double this_d = (y0 - y) / u.y; + if (this_d < d) { + d = this_d; + if (u.y > 0) { + lattice_trans = {0, 1, 0}; + } else { + lattice_trans = {0, -1, 0}; + } + } + } - // Determine which lattice boundaries are being crossed. The axis attaining - // the minimum is exactly equal to d, so at least one translation is always - // set for a finite crossing; a near-equal second axis indicates a corner - // crossing. - array lattice_trans = {0, 0, 0}; - if (isclose(d, dx, FP_COINCIDENT, FP_PRECISION)) - lattice_trans[0] = copysign(1, u.x); - if (isclose(d, dy, FP_COINCIDENT, FP_PRECISION)) - lattice_trans[1] = copysign(1, u.y); - if (is_3d_ && isclose(d, dz, FP_COINCIDENT, FP_PRECISION)) - lattice_trans[2] = copysign(1, u.z); + // Top and bottom sides + if (is_3d_) { + double z0 {copysign(0.5 * pitch_[2], u.z)}; + if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) { + double this_d = (z0 - z) / u.z; + if (this_d < d) { + d = this_d; + if (u.z > 0) { + lattice_trans = {0, 0, 1}; + } else { + lattice_trans = {0, 0, -1}; + } + } + } + } return {d, lattice_trans}; } @@ -349,27 +354,7 @@ Position RectLattice::get_local_position( //============================================================================== -Direction RectLattice::get_normal( - const array& i_xyz, bool& is_valid) const -{ - is_valid = false; - Direction dir = {0.0, 0.0, 0.0}; - if ((std::abs(i_xyz[0]) == 1) && (i_xyz[1] == 0) && (i_xyz[2] == 0)) { - is_valid = true; - dir[0] = std::copysign(1.0, i_xyz[0]); - } else if ((i_xyz[0] == 0) && (std::abs(i_xyz[1]) == 1) && (i_xyz[2] == 0)) { - is_valid = true; - dir[1] = std::copysign(1.0, i_xyz[1]); - } else if ((i_xyz[0] == 0) && (i_xyz[1] == 0) && (std::abs(i_xyz[2]) == 1)) { - is_valid = true; - dir[2] = std::copysign(1.0, i_xyz[2]); - } - return dir; -} - -//============================================================================== - -int32_t& RectLattice::offset(int map, const array& i_xyz) +int32_t& RectLattice::offset(int map, array const& i_xyz) { return offsets_[n_cells_[0] * n_cells_[1] * n_cells_[2] * map + n_cells_[0] * n_cells_[1] * i_xyz[2] + @@ -691,19 +676,13 @@ void HexLattice::fill_lattice_y(const vector& univ_words) //============================================================================== -const int32_t& HexLattice::operator[](const array& i_xyz) +int32_t const& HexLattice::operator[](array const& i_xyz) { return universes_[get_flat_index(i_xyz)]; } //============================================================================== -// The HexLattice iterators need their own versions b/c the universes array is -// "square", meaning that it is allocated with entries that are intentionally -// left empty. As such, the iterator indices need to skip the empty entries to -// get cell instances and geometry paths correct. See the image in the Theory -// and Methodology section on "Hexagonal Lattice Indexing" for a visual of where -// the empty positions are. LatticeIter HexLattice::begin() { return LatticeIter(*this, n_rings_ - 1); @@ -714,24 +693,9 @@ ReverseLatticeIter HexLattice::rbegin() return ReverseLatticeIter(*this, universes_.size() - n_rings_); } -int32_t& HexLattice::back() -{ - return universes_[universes_.size() - n_rings_]; -} - -LatticeIter HexLattice::end() -{ - return LatticeIter(*this, universes_.size() - n_rings_ + 1); -} - -ReverseLatticeIter HexLattice::rend() -{ - return ReverseLatticeIter(*this, n_rings_ - 2); -} - //============================================================================== -bool HexLattice::are_valid_indices(const array& i_xyz) const +bool HexLattice::are_valid_indices(array const& i_xyz) const { // Check if (x, alpha, z) indices are valid, accounting for number of rings return ((i_xyz[0] >= 0) && (i_xyz[1] >= 0) && (i_xyz[2] >= 0) && @@ -1015,91 +979,6 @@ Position HexLattice::get_local_position( //============================================================================== -Direction HexLattice::get_normal( - const array& i_xyz, bool& is_valid) const -{ - // Short description of the direction vectors used here. The beta, gamma, and - // delta vectors point towards the flat sides of each hexagonal tile. - // Y - orientation: - // basis0 = (1, 0) - // basis1 = (-1/sqrt(3), 1) = +120 degrees from basis0 - // beta = (sqrt(3)/2, 1/2) = +30 degrees from basis0 - // gamma = (sqrt(3)/2, -1/2) = -60 degrees from beta - // delta = (0, 1) = +60 degrees from beta - // X - orientation: - // basis0 = (1/sqrt(3), -1) - // basis1 = (0, 1) = +120 degrees from basis0 - // beta = (1, 0) = +30 degrees from basis0 - // gamma = (1/2, -sqrt(3)/2) = -60 degrees from beta - // delta = (1/2, sqrt(3)/2) = +60 degrees from beta - - is_valid = false; - Direction dir = {0.0, 0.0, 0.0}; - if ((i_xyz[0] == 0) && (i_xyz[1] == 0) && (std::abs(i_xyz[2]) == 1)) { - is_valid = true; - dir[2] = std::copysign(1.0, i_xyz[2]); - } else if ((i_xyz[2] == 0) && - std::max({std::abs(i_xyz[0]), std::abs(i_xyz[1]), - std::abs(i_xyz[0] + i_xyz[1])}) == 1) { - is_valid = true; - // beta direction - if ((i_xyz[0] == 1) && (i_xyz[1] == 0)) { - if (orientation_ == Orientation::y) { - dir[0] = 0.5 * std::sqrt(3.0); - dir[1] = 0.5; - } else { - dir[0] = 1.0; - dir[1] = 0.0; - } - } else if ((i_xyz[0] == -1) && (i_xyz[1] == 0)) { - if (orientation_ == Orientation::y) { - dir[0] = -0.5 * std::sqrt(3.0); - dir[1] = -0.5; - } else { - dir[0] = -1.0; - dir[1] = 0.0; - } - // gamma direction - } else if ((i_xyz[0] == 1) && (i_xyz[1] == -1)) { - if (orientation_ == Orientation::y) { - dir[0] = 0.5 * std::sqrt(3.0); - dir[1] = -0.5; - } else { - dir[0] = 0.5; - dir[1] = -0.5 * std::sqrt(3.0); - } - } else if ((i_xyz[0] == -1) && (i_xyz[1] == 1)) { - if (orientation_ == Orientation::y) { - dir[0] = -0.5 * std::sqrt(3.0); - dir[1] = 0.5; - } else { - dir[0] = -0.5; - dir[1] = 0.5 * std::sqrt(3.0); - } - // delta direction - } else if ((i_xyz[0] == 0) && (i_xyz[1] == 1)) { - if (orientation_ == Orientation::y) { - dir[0] = 0.0; - dir[1] = 1.0; - } else { - dir[0] = 0.5; - dir[1] = 0.5 * std::sqrt(3.0); - } - } else if ((i_xyz[0] == 0) && (i_xyz[1] == -1)) { - if (orientation_ == Orientation::y) { - dir[0] = 0.0; - dir[1] = -1.0; - } else { - dir[0] = -0.5; - dir[1] = -0.5 * std::sqrt(3.0); - } - } - } - return dir; -} - -//============================================================================== - bool HexLattice::is_valid_index(int indx) const { int nx {2 * n_rings_ - 1}; @@ -1113,7 +992,7 @@ bool HexLattice::is_valid_index(int indx) const //============================================================================== -int32_t& HexLattice::offset(int map, const array& i_xyz) +int32_t& HexLattice::offset(int map, array const& i_xyz) { int nx {2 * n_rings_ - 1}; int ny {2 * n_rings_ - 1}; diff --git a/src/main.cpp b/src/main.cpp index 88251ac72..02a850ead 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,6 @@ #include "openmc/error.h" #include "openmc/message_passing.h" #include "openmc/particle_restart.h" -#include "openmc/random_ray/random_ray_simulation.h" #include "openmc/settings.h" int main(int argc, char* argv[]) @@ -32,15 +31,7 @@ int main(int argc, char* argv[]) switch (settings::run_mode) { case RunMode::FIXED_SOURCE: case RunMode::EIGENVALUE: - switch (settings::solver_type) { - case SolverType::MONTE_CARLO: - err = openmc_run(); - break; - case SolverType::RANDOM_RAY: - openmc_run_random_ray(); - err = 0; - break; - } + err = openmc_run(); break; case RunMode::PLOTTING: err = openmc_plot_geometry(); diff --git a/src/material.cpp b/src/material.cpp index 21b11b8b9..30dfa5ed5 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1,14 +1,15 @@ #include "openmc/material.h" #include // for min, max, sort, fill -#include #include #include #include #include #include -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xoperation.hpp" +#include "xtensor/xview.hpp" #include "openmc/capi.h" #include "openmc/container_util.h" @@ -59,13 +60,6 @@ Material::Material(pugi::xml_node node) name_ = get_node_value(node, "name"); } - if (check_for_node(node, "cfg")) { - auto cfg = get_node_value(node, "cfg"); - write_message( - 5, "NCrystal config string for material #{}: '{}'", this->id(), cfg); - ncrystal_mat_ = NCrystalMat(cfg); - } - if (check_for_node(node, "depletable")) { depletable_ = get_node_value_bool(node, "depletable"); } @@ -214,7 +208,7 @@ Material::Material(pugi::xml_node node) // allocate arrays in Material object auto n = names.size(); nuclide_.reserve(n); - atom_density_ = tensor::Tensor({n}); + atom_density_ = xt::empty({n}); if (settings::photon_transport) element_.reserve(n); @@ -223,13 +217,11 @@ Material::Material(pugi::xml_node node) // Check that this nuclide is listed in the nuclear data library // (cross_sections.xml for CE and the MGXS HDF5 for MG) - if (settings::run_mode != RunMode::PLOTTING) { - LibraryKey key {Library::Type::neutron, name}; - if (data::library_map.find(key) == data::library_map.end()) { - fatal_error("Could not find nuclide " + name + - " in the " - "nuclear data library."); - } + LibraryKey key {Library::Type::neutron, name}; + if (data::library_map.find(key) == data::library_map.end()) { + fatal_error("Could not find nuclide " + name + + " in the " + "nuclear data library."); } // If this nuclide hasn't been encountered yet, we need to add its name @@ -248,12 +240,10 @@ Material::Material(pugi::xml_node node) std::string element = to_element(name); // Make sure photon cross section data is available - if (settings::run_mode != RunMode::PLOTTING) { - LibraryKey key {Library::Type::photon, element}; - if (data::library_map.find(key) == data::library_map.end()) { - fatal_error( - "Could not find element " + element + " in cross_sections.xml."); - } + LibraryKey key {Library::Type::photon, element}; + if (data::library_map.find(key) == data::library_map.end()) { + fatal_error( + "Could not find element " + element + " in cross_sections.xml."); } if (data::element_map.find(element) == data::element_map.end()) { @@ -288,14 +278,14 @@ Material::Material(pugi::xml_node node) // Check to make sure either all atom percents or all weight percents are // given - if (!((atom_density_ >= 0.0).all() || (atom_density_ <= 0.0).all())) { + if (!(xt::all(atom_density_ >= 0.0) || xt::all(atom_density_ <= 0.0))) { fatal_error( "Cannot mix atom and weight percents in material " + std::to_string(id_)); } // Determine density if it is a sum value if (sum_density) - density_ = atom_density_.sum(); + density_ = xt::sum(atom_density_)(); if (check_for_node(node, "temperature")) { temperature_ = std::stod(get_node_value(node, "temperature")); @@ -327,12 +317,10 @@ Material::Material(pugi::xml_node node) // Check that the thermal scattering table is listed in the // cross_sections.xml file - if (settings::run_mode != RunMode::PLOTTING) { - LibraryKey key {Library::Type::thermal, name}; - if (data::library_map.find(key) == data::library_map.end()) { - fatal_error("Could not find thermal scattering data " + name + - " in cross_sections.xml file."); - } + LibraryKey key {Library::Type::thermal, name}; + if (data::library_map.find(key) == data::library_map.end()) { + fatal_error("Could not find thermal scattering data " + name + + " in cross_sections.xml file."); } // Determine index of thermal scattering data in global @@ -358,35 +346,6 @@ Material::~Material() model::material_map.erase(id_); } -Material& Material::clone() -{ - std::unique_ptr mat = std::make_unique(); - - // set all other parameters to whatever the calling Material has - mat->name_ = name_; - mat->nuclide_ = nuclide_; - mat->element_ = element_; - mat->ncrystal_mat_ = ncrystal_mat_.clone(); - mat->atom_density_ = atom_density_; - mat->density_ = density_; - mat->density_gpcc_ = density_gpcc_; - mat->volume_ = volume_; - mat->fissionable() = fissionable_; - mat->depletable() = depletable_; - mat->p0_ = p0_; - mat->mat_nuclide_index_ = mat_nuclide_index_; - mat->thermal_tables_ = thermal_tables_; - mat->temperature_ = temperature_; - - if (ttb_) - mat->ttb_ = std::make_unique(*ttb_); - - mat->index_ = model::materials.size(); - mat->set_id(C_NONE); - model::materials.push_back(std::move(mat)); - return *model::materials.back(); -} - void Material::finalize() { // Set fissionable if any nuclide is fissionable @@ -408,8 +367,8 @@ void Material::finalize() this->init_thermal(); } - // Normalize density - this->normalize_density(); +// Normalize density +this->normalize_density(); } void Material::normalize_density() @@ -433,7 +392,7 @@ void Material::normalize_density() // determine normalized atom percents. if given atom percents, this is // straightforward. if given weight percents, the value is w/awr and is // divided by sum(w/awr) - atom_density_ /= atom_density_.sum(); + atom_density_ /= xt::sum(atom_density_)(); // Change density in g/cm^3 to atom/b-cm. Since all values are now in // atom percent, the sum needs to be re-evaluated as 1/sum(x*awr) @@ -452,15 +411,12 @@ void Material::normalize_density() // Calculate nuclide atom densities atom_density_ *= density_; - // Calculate density in [g/cm^3] and charge density in [e/b-cm] + // Calculate density in g/cm^3. density_gpcc_ = 0.0; - charge_density_ = 0.0; for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; double awr = settings::run_CE ? data::nuclides[i_nuc]->awr_ : 1.0; - int z = settings::run_CE ? data::nuclides[i_nuc]->Z_ : 0.0; density_gpcc_ += atom_density_(i) * awr * MASS_NEUTRON / N_AVOGADRO; - charge_density_ += atom_density_(i) * z; } } @@ -639,14 +595,14 @@ void Material::init_bremsstrahlung() bool positron = (particle == 1); // Allocate arrays for TTB data - ttb->pdf = tensor::zeros({n_e, n_e}); - ttb->cdf = tensor::zeros({n_e, n_e}); - ttb->yield = tensor::zeros({n_e}); + ttb->pdf = xt::zeros({n_e, n_e}); + ttb->cdf = xt::zeros({n_e, n_e}); + ttb->yield = xt::empty({n_e}); // Allocate temporary arrays - auto stopping_power_collision = tensor::zeros({n_e}); - auto stopping_power_radiative = tensor::zeros({n_e}); - auto dcs = tensor::zeros({n_e, n_k}); + xt::xtensor stopping_power_collision({n_e}, 0.0); + xt::xtensor stopping_power_radiative({n_e}, 0.0); + xt::xtensor dcs({n_e, n_k}, 0.0); double Z_eq_sq = 0.0; double sum_density = 0.0; @@ -696,18 +652,18 @@ void Material::init_bremsstrahlung() 1.0595e-3 * std::pow(t, 5) + 7.0568e-5 * std::pow(t, 6) - 1.808e-6 * std::pow(t, 7)); stopping_power_radiative(i) *= r; - tensor::View dcs_i = dcs.slice(i); + auto dcs_i = xt::view(dcs, i, xt::all()); dcs_i *= r; } } // Total material stopping power - tensor::Tensor stopping_power = + xt::xtensor stopping_power = stopping_power_collision + stopping_power_radiative; // Loop over photon energies - auto f = tensor::zeros({n_e}); - auto z = tensor::zeros({n_e}); + xt::xtensor f({n_e}, 0.0); + xt::xtensor z({n_e}, 0.0); for (int i = 0; i < n_e - 1; ++i) { double w = data::ttb_e_grid(i); @@ -778,15 +734,14 @@ void Material::init_bremsstrahlung() // Loop over photon energies double c = 0.0; for (int i = 0; i < j; ++i) { - // Integrate the CDF from the PDF using the fact that the PDF is linear - // in log-log space + // Integrate the CDF from the PDF using the trapezoidal rule in log-log + // space double w_l = std::log(data::ttb_e_grid(i)); double w_r = std::log(data::ttb_e_grid(i + 1)); double x_l = std::log(ttb->pdf(j, i)); double x_r = std::log(ttb->pdf(j, i + 1)); - double beta = (x_r - x_l) / (w_r - w_l); - double a = beta + 1.0; - c += std::exp(w_l + x_l) / a * std::expm1(a * (w_r - w_l)); + + c += 0.5 * (w_r - w_l) * (std::exp(w_l + x_l) + std::exp(w_r + x_r)); ttb->cdf(j, i + 1) = c; } @@ -795,8 +750,7 @@ void Material::init_bremsstrahlung() } // Use logarithm of number yield since it is log-log interpolated - ttb->yield = - tensor::where(ttb->yield > 0.0, tensor::log(ttb->yield), -500.0); + ttb->yield = xt::where(ttb->yield > 0.0, xt::log(ttb->yield), -500.0); } } @@ -818,9 +772,9 @@ void Material::calculate_xs(Particle& p) const p.macro_xs().fission = 0.0; p.macro_xs().nu_fission = 0.0; - if (p.type().is_neutron()) { + if (p.type() == ParticleType::neutron) { this->calculate_neutron_xs(p); - } else if (p.type().is_photon()) { + } else if (p.type() == ParticleType::photon) { this->calculate_photon_xs(p); } } @@ -828,7 +782,7 @@ void Material::calculate_xs(Particle& p) const void Material::calculate_neutron_xs(Particle& p) const { // Find energy index on energy grid - int neutron = ParticleType::neutron().transport_index(); + int neutron = static_cast(ParticleType::neutron); int i_grid = std::log(p.E() / data::energy_min[neutron]) / simulation::log_spacing; @@ -838,12 +792,6 @@ void Material::calculate_neutron_xs(Particle& p) const // Initialize position in i_sab_nuclides int j = 0; - // Calculate NCrystal cross section - double ncrystal_xs = -1.0; - if (ncrystal_mat_ && p.E() < NCRYSTAL_MAX_ENERGY) { - ncrystal_xs = ncrystal_mat_.xs(p); - } - // Add contribution from each nuclide in material for (int i = 0; i < nuclide_.size(); ++i) { // ====================================================================== @@ -878,18 +826,21 @@ void Material::calculate_neutron_xs(Particle& p) const // ====================================================================== // CALCULATE MICROSCOPIC CROSS SECTION - // Get nuclide index + // Determine microscopic cross sections for this nuclide int i_nuclide = nuclide_[i]; - // Update microscopic cross section for this nuclide - p.update_neutron_xs(i_nuclide, i_grid, i_sab, sab_frac, ncrystal_xs); - auto& micro = p.neutron_xs(i_nuclide); + // Calculate microscopic cross section for this nuclide + const auto& micro {p.neutron_xs(i_nuclide)}; + if (p.E() != micro.last_E || p.sqrtkT() != micro.last_sqrtkT || + i_sab != micro.index_sab || sab_frac != micro.sab_frac) { + data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, p); + } // ====================================================================== // ADD TO MACROSCOPIC CROSS SECTION // Copy atom density of nuclide in material - double atom_density = this->atom_density(i, p.density_mult()); + double atom_density = atom_density_(i); // Add contributions to cross sections p.macro_xs().total += atom_density * micro.total; @@ -924,7 +875,7 @@ void Material::calculate_photon_xs(Particle& p) const // ADD TO MACROSCOPIC CROSS SECTION // Copy atom density of nuclide in material - double atom_density = this->atom_density(i, p.density_mult()); + double atom_density = atom_density_(i); // Add contributions to material macroscopic cross sections p.macro_xs().total += atom_density * micro.total; @@ -937,7 +888,7 @@ void Material::calculate_photon_xs(Particle& p) const void Material::set_id(int32_t id) { - assert(id >= 0 || id == C_NONE); + Expects(id >= 0 || id == C_NONE); // Clear entry in material map if an ID was already assigned before if (id_ != C_NONE) { @@ -965,9 +916,9 @@ void Material::set_id(int32_t id) model::material_map[id] = index_; } -void Material::set_density(double density, const std::string& units) +void Material::set_density(double density, gsl::cstring_span units) { - assert(density >= 0.0); + Expects(density >= 0.0); if (nuclide_.empty()) { throw std::runtime_error {"No nuclides exist in material yet."}; @@ -978,21 +929,18 @@ void Material::set_density(double density, const std::string& units) density_ = density; // Determine normalized atom percents - double sum_percent = atom_density_.sum(); + double sum_percent = xt::sum(atom_density_)(); atom_density_ /= sum_percent; // Recalculate nuclide atom densities based on given density atom_density_ *= density; - // Calculate density in g/cm^3 and charge density in [e/b-cm] + // Calculate density in g/cm^3. density_gpcc_ = 0.0; - charge_density_ = 0.0; for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; double awr = data::nuclides[i_nuc]->awr_; - int z = settings::run_CE ? data::nuclides[i_nuc]->Z_ : 0.0; density_gpcc_ += atom_density_(i) * awr * MASS_NEUTRON / N_AVOGADRO; - charge_density_ += atom_density_(i) * z; } } else if (units == "g/cm3" || units == "g/cc") { // Determine factor by which to change densities @@ -1003,7 +951,6 @@ void Material::set_density(double density, const std::string& units) density_gpcc_ = density; density_ *= f; atom_density_ *= f; - charge_density_ *= f; } else { throw std::invalid_argument { "Invalid units '" + std::string(units.data()) + "' specified."}; @@ -1014,18 +961,18 @@ void Material::set_densities( const vector& name, const vector& density) { auto n = name.size(); - assert(n > 0); - assert(n == density.size()); + Expects(n > 0); + Expects(n == density.size()); if (n != nuclide_.size()) { nuclide_.resize(n); - atom_density_ = tensor::zeros({n}); + atom_density_ = xt::zeros({n}); if (settings::photon_transport) element_.resize(n); } double sum_density = 0.0; - for (int64_t i = 0; i < n; ++i) { + for (gsl::index i = 0; i < n; ++i) { const auto& nuc {name[i]}; if (data::nuclide_map.find(nuc) == data::nuclide_map.end()) { int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); @@ -1034,7 +981,7 @@ void Material::set_densities( } nuclide_[i] = data::nuclide_map.at(nuc); - assert(density[i] > 0.0); + Expects(density[i] > 0.0); atom_density_(i) = density[i]; sum_density += density[i]; @@ -1076,7 +1023,7 @@ void Material::to_hdf5(hid_t group) const { hid_t material_group = create_group(group, "material " + std::to_string(id_)); - write_attribute(material_group, "depletable", static_cast(depletable())); + write_attribute(material_group, "depletable", static_cast(depletable_)); if (volume_ > 0.0) { write_attribute(material_group, "volume", volume_); } @@ -1180,8 +1127,8 @@ void Material::add_nuclide(const std::string& name, double density) auto n = nuclide_.size(); // Create copy of atom_density_ array with one extra entry - tensor::Tensor atom_density = tensor::zeros({n}); - atom_density.slice(tensor::range(0, n - 1)) = atom_density_; + xt::xtensor atom_density = xt::zeros({n}); + xt::view(atom_density, xt::range(0, n - 1)) = atom_density_; atom_density(n - 1) = density; atom_density_ = atom_density; @@ -1334,12 +1281,6 @@ void read_materials_xml() // Loop over XML material elements and populate the array. pugi::xml_node root = doc.document_element(); - - read_materials_xml(root); -} - -void read_materials_xml(pugi::xml_node root) -{ for (pugi::xml_node material_node : root.children("material")) { model::materials.push_back(make_unique(material_node)); } @@ -1558,30 +1499,6 @@ extern "C" int openmc_material_set_volume(int32_t index, double volume) } } -extern "C" int openmc_material_get_depletable(int32_t index, bool* depletable) -{ - if (index < 0 || index >= model::materials.size()) { - set_errmsg("Index in materials array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - *depletable = model::materials[index]->depletable(); - - return 0; -} - -extern "C" int openmc_material_set_depletable(int32_t index, bool depletable) -{ - if (index < 0 || index >= model::materials.size()) { - set_errmsg("Index in materials array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - model::materials[index]->depletable() = depletable; - - return 0; -} - extern "C" int openmc_extend_materials( int32_t n, int32_t* index_start, int32_t* index_end) { diff --git a/src/math_functions.cpp b/src/math_functions.cpp index ddacc2bd9..ba1c6c3db 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -1,7 +1,5 @@ #include "openmc/math_functions.h" -#include // for numeric_limits - #include "openmc/external/Faddeeva.hh" #include "openmc/constants.h" @@ -97,13 +95,6 @@ double t_percentile(double p, int df) return t; } -double standard_normal_cdf(double z) -{ - // Use the complementary error function to compute the standard normal CDF - // Phi(z) = 0.5 * (1 + erf(z / sqrt(2))) = 0.5 * erfc(-z / sqrt(2)) - return 0.5 * std::erfc(-z / std::sqrt(2.0)); -} - void calc_pn_c(int n, double x, double pnx[]) { pnx[0] = 1.; @@ -659,7 +650,7 @@ void calc_zn(int n, double rho, double phi, double zn[]) // =========================================================================== // Determine vector of sin(n*phi) and cos(n*phi). This takes advantage of the // following recurrence relations so that only a single sin/cos have to be - // evaluated (https://mathworld.wolfram.com/Multiple-AngleFormulas.html) + // evaluated (http://mathworld.wolfram.com/Multiple-AngleFormulas.html) // // sin(nx) = 2 cos(x) sin((n-1)x) - sin((n-2)x) // cos(nx) = 2 cos(x) cos((n-1)x) - cos((n-2)x) @@ -928,85 +919,4 @@ std::complex w_derivative(std::complex z, int order) } } -double exprel(double x) -{ - if (std::abs(x) < 1e-16) - return 1.0; - else { - return std::expm1(x) / x; - } -} - -double log1prel(double x) -{ - if (std::abs(x) < 1e-16) - return 1.0; - else { - return std::log1p(x) / x; - } -} - -double cyl_bessel_j(int n, double x) -{ - // Handle negative arguments via the parity relation - // J_n(-x) = (-1)^n J_n(x); std::cyl_bessel_j has a domain error for x < 0. - double sign = 1.0; - if (x < 0.0) { - x = -x; - if (n % 2 == 1) - sign = -1.0; - } - -#if defined(__cpp_lib_math_special_functions) && \ - __cpp_lib_math_special_functions >= 201603L - return sign * std::cyl_bessel_j(static_cast(n), x); -#else - // Ascending power series (e.g., Abramowitz & Stegun eq. 9.1.10): - // J_n(x) = sum_{m=0}^inf (-1)^m / (m! (m+n)!) * (x/2)^(2m+n) - // The term ratio is -(x/2)^2 / (m*(m+n)), so for |x| <= 2 the series - // converges to machine precision within ~20 terms. - double half_x = 0.5 * x; - - // First term: (x/2)^n / n! - double term = 1.0; - for (int k = 1; k <= n; ++k) { - term *= half_x / k; - } - - double sum = term; - double neg_half_x_sq = -half_x * half_x; - for (int m = 1; m <= 50; ++m) { - term *= neg_half_x_sq / (m * (m + n)); - sum += term; - if (std::abs(term) <= - std::numeric_limits::epsilon() * std::abs(sum)) - break; - } - return sign * sum; -#endif -} - -// Helper function to get index and interpolation function on an incident energy -// grid -void get_energy_index( - const vector& energies, double E, int& i, double& f) -{ - // Get index and interpolation factor for linear-linear energy grid - i = 0; - f = 0.0; - if (E >= energies.front()) { - i = lower_bound_index(energies.begin(), energies.end(), E); - if (i + 1 < energies.size()) - f = (E - energies[i]) / (energies[i + 1] - energies[i]); - } -} - -// Return true if two floating-point values are approximately equal within a -// combined relative and absolute tolerance. -bool isclose(double a, double b, double rel_tol, double abs_tol) -{ - return std::abs(a - b) <= - std::max(rel_tol * std::max(std::abs(a), std::abs(b)), abs_tol); -} - } // namespace openmc diff --git a/src/mcpl_interface.cpp b/src/mcpl_interface.cpp deleted file mode 100644 index 30c41ec5a..000000000 --- a/src/mcpl_interface.cpp +++ /dev/null @@ -1,646 +0,0 @@ -#include "openmc/mcpl_interface.h" - -#include "openmc/bank.h" -#include "openmc/error.h" -#include "openmc/file_utils.h" -#include "openmc/message_passing.h" -#include "openmc/settings.h" -#include "openmc/simulation.h" -#include "openmc/state_point.h" -#include "openmc/vector.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#else -#include -#endif - -// WARNING: These declarations MUST EXACTLY MATCH the structure and function -// signatures of the libmcpl being loaded at runtime. Any discrepancy will -// likely lead to crashes or incorrect behavior. This is a maintenance risk. -// MCPL 2.2.0 - -#pragma pack(push, 1) -struct mcpl_particle_repr_t { - double ekin; - double polarisation[3]; - double position[3]; - double direction[3]; - double time; - double weight; - int32_t pdgcode; - uint32_t userflags; -}; -#pragma pack(pop) - -// Opaque struct definitions replicating the MCPL C-API to ensure ABI -// compatibility without including mcpl.h. These must be kept in sync. -struct mcpl_file_t { - void* internal; -}; -struct mcpl_outfile_t { - void* internal; -}; - -// Function pointer types for the dynamically loaded MCPL library -using mcpl_open_file_fpt = mcpl_file_t* (*)(const char* filename); -using mcpl_hdr_nparticles_fpt = uint64_t (*)(mcpl_file_t* file_handle); -using mcpl_read_fpt = const mcpl_particle_repr_t* (*)(mcpl_file_t* file_handle); -using mcpl_close_file_fpt = void (*)(mcpl_file_t* file_handle); - -using mcpl_hdr_add_data_fpt = void (*)(mcpl_outfile_t* file_handle, - const char* key, uint32_t datalength, const char* data); -using mcpl_create_outfile_fpt = mcpl_outfile_t* (*)(const char* filename); -using mcpl_hdr_set_srcname_fpt = void (*)( - mcpl_outfile_t* outfile_handle, const char* srcname); -using mcpl_add_particle_fpt = void (*)( - mcpl_outfile_t* outfile_handle, const mcpl_particle_repr_t* particle); -using mcpl_close_outfile_fpt = void (*)(mcpl_outfile_t* outfile_handle); -using mcpl_hdr_add_stat_sum_fpt = void (*)( - mcpl_outfile_t* outfile_handle, const char* key, double value); - -namespace openmc { - -#ifdef _WIN32 -using LibraryHandleType = HMODULE; -#else -using LibraryHandleType = void*; -#endif - -std::string get_last_library_error() -{ -#ifdef _WIN32 - DWORD error_code = GetLastError(); - if (error_code == 0) - return "No error reported by system."; // More accurate than "No error." - LPSTR message_buffer = nullptr; - size_t size = - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&message_buffer, 0, NULL); - std::string message(message_buffer, size); - LocalFree(message_buffer); - while ( - !message.empty() && (message.back() == '\n' || message.back() == '\r')) { - message.pop_back(); - } - return message; -#else - const char* err = dlerror(); - return err ? std::string(err) : "No error reported by dlerror."; -#endif -} - -struct McplApi { - mcpl_open_file_fpt open_file; - mcpl_hdr_nparticles_fpt hdr_nparticles; - mcpl_read_fpt read; - mcpl_close_file_fpt close_file; - mcpl_create_outfile_fpt create_outfile; - mcpl_hdr_set_srcname_fpt hdr_set_srcname; - mcpl_hdr_add_data_fpt hdr_add_data; - mcpl_add_particle_fpt add_particle; - mcpl_close_outfile_fpt close_outfile; - mcpl_hdr_add_stat_sum_fpt hdr_add_stat_sum; - - explicit McplApi(LibraryHandleType lib_handle) - { - if (!lib_handle) - throw std::runtime_error( - "MCPL library handle is null during API binding."); - - auto load_symbol_platform = [lib_handle](const char* name) { - void* sym = nullptr; -#ifdef _WIN32 - sym = (void*)GetProcAddress(lib_handle, name); -#else - sym = dlsym(lib_handle, name); -#endif - if (!sym) { - throw std::runtime_error( - fmt::format("Failed to load MCPL symbol '{}': {}", name, - get_last_library_error())); - } - return sym; - }; - - open_file = reinterpret_cast( - load_symbol_platform("mcpl_open_file")); - hdr_nparticles = reinterpret_cast( - load_symbol_platform("mcpl_hdr_nparticles")); - read = reinterpret_cast(load_symbol_platform("mcpl_read")); - close_file = reinterpret_cast( - load_symbol_platform("mcpl_close_file")); - create_outfile = reinterpret_cast( - load_symbol_platform("mcpl_create_outfile")); - hdr_set_srcname = reinterpret_cast( - load_symbol_platform("mcpl_hdr_set_srcname")); - add_particle = reinterpret_cast( - load_symbol_platform("mcpl_add_particle")); - close_outfile = reinterpret_cast( - load_symbol_platform("mcpl_close_outfile")); - - // Try to load mcpl_hdr_add_data (available in MCPL >= 2.1.0) - // Set to nullptr if not available for graceful fallback - try { - hdr_add_data = reinterpret_cast( - load_symbol_platform("mcpl_hdr_add_data")); - } catch (const std::runtime_error&) { - hdr_add_data = nullptr; - } - - // Try to load mcpl_hdr_add_stat_sum (available in MCPL >= 2.1.0) - // Set to nullptr if not available for graceful fallback - try { - hdr_add_stat_sum = reinterpret_cast( - load_symbol_platform("mcpl_hdr_add_stat_sum")); - } catch (const std::runtime_error&) { - hdr_add_stat_sum = nullptr; - } - } -}; - -static LibraryHandleType g_mcpl_lib_handle = nullptr; -static std::unique_ptr g_mcpl_api; -static bool g_mcpl_init_attempted = false; -static bool g_mcpl_successfully_loaded = false; -static std::string g_mcpl_load_error_msg; -static std::once_flag g_mcpl_init_flag; - -void append_error(std::string& existing_msg, const std::string& new_error) -{ - if (!existing_msg.empty()) { - existing_msg += "; "; - } - existing_msg += new_error; -} - -void initialize_mcpl_interface_impl() -{ - g_mcpl_init_attempted = true; - g_mcpl_load_error_msg.clear(); - - // Try mcpl-config - if (!g_mcpl_lib_handle) { - FILE* pipe = nullptr; -#ifdef _WIN32 - pipe = _popen("mcpl-config --show libpath", "r"); -#else - pipe = popen("mcpl-config --show libpath 2>/dev/null", "r"); -#endif - if (pipe) { - char buffer[512]; - if (fgets(buffer, sizeof(buffer), pipe) != nullptr) { - std::string shlibpath = buffer; - // Remove trailing whitespace - while (!shlibpath.empty() && - std::isspace(static_cast(shlibpath.back()))) { - shlibpath.pop_back(); - } - - if (!shlibpath.empty()) { -#ifdef _WIN32 - g_mcpl_lib_handle = LoadLibraryA(shlibpath.c_str()); -#else - g_mcpl_lib_handle = dlopen(shlibpath.c_str(), RTLD_LAZY); -#endif - if (!g_mcpl_lib_handle) { - append_error( - g_mcpl_load_error_msg, fmt::format("From mcpl-config ({}): {}", - shlibpath, get_last_library_error())); - } - } - } -#ifdef _WIN32 - _pclose(pipe); -#else - pclose(pipe); -#endif - } else { // pipe failed to open - append_error(g_mcpl_load_error_msg, - "mcpl-config command not found or failed to execute"); - } - } - - // Try standard library names - if (!g_mcpl_lib_handle) { -#ifdef _WIN32 - const char* standard_names[] = {"mcpl.dll", "libmcpl.dll"}; -#else - const char* standard_names[] = {"libmcpl.so", "libmcpl.dylib"}; -#endif - for (const char* name : standard_names) { -#ifdef _WIN32 - g_mcpl_lib_handle = LoadLibraryA(name); -#else - g_mcpl_lib_handle = dlopen(name, RTLD_LAZY); -#endif - if (g_mcpl_lib_handle) - break; - } - if (!g_mcpl_lib_handle) { - append_error( - g_mcpl_load_error_msg, fmt::format("Using standard names (e.g. {}): {}", - standard_names[0], get_last_library_error())); - } - } - - if (!g_mcpl_lib_handle) { - if (mpi::master) { - warning(fmt::format("MCPL library could not be loaded. MCPL-dependent " - "features will be unavailable. Load attempts: {}", - g_mcpl_load_error_msg.empty() - ? "No specific error during load attempts." - : g_mcpl_load_error_msg)); - } - g_mcpl_successfully_loaded = false; - return; - } - - try { - g_mcpl_api = std::make_unique(g_mcpl_lib_handle); - g_mcpl_successfully_loaded = true; - // Do not call dlclose/FreeLibrary at exit. Leaking the handle is safer - // and standard practice for libraries used for the application's lifetime. - } catch (const std::runtime_error& e) { - append_error(g_mcpl_load_error_msg, - fmt::format( - "MCPL library loaded, but failed to bind symbols: {}", e.what())); - if (mpi::master) { - warning(g_mcpl_load_error_msg); - } -#ifdef _WIN32 - FreeLibrary(g_mcpl_lib_handle); -#else - dlclose(g_mcpl_lib_handle); -#endif - g_mcpl_lib_handle = nullptr; - g_mcpl_successfully_loaded = false; - } -} - -void initialize_mcpl_interface_if_needed() -{ - std::call_once(g_mcpl_init_flag, initialize_mcpl_interface_impl); -} - -bool is_mcpl_interface_available() -{ - initialize_mcpl_interface_if_needed(); - return g_mcpl_successfully_loaded; -} - -inline void ensure_mcpl_ready_or_fatal() -{ - initialize_mcpl_interface_if_needed(); - if (!g_mcpl_successfully_loaded) { - fatal_error("MCPL functionality is required, but the MCPL library is not " - "available or failed to initialize. Please ensure MCPL is " - "installed and its library can be found (e.g., via PATH on " - "Windows, LD_LIBRARY_PATH on Linux, or DYLD_LIBRARY_PATH on " - "macOS). You can often install MCPL with 'pip install mcpl' or " - "'conda install mcpl'."); - } -} - -SourceSite mcpl_particle_to_site(const mcpl_particle_repr_t* particle_repr) -{ - SourceSite site; - site.particle = ParticleType {particle_repr->pdgcode}; - - // Copy position and direction - site.r.x = particle_repr->position[0]; - site.r.y = particle_repr->position[1]; - site.r.z = particle_repr->position[2]; - site.u.x = particle_repr->direction[0]; - site.u.y = particle_repr->direction[1]; - site.u.z = particle_repr->direction[2]; - // MCPL stores kinetic energy in [MeV], time in [ms] - site.E = particle_repr->ekin * 1e6; - site.time = particle_repr->time * 1e-3; - site.wgt = particle_repr->weight; - return site; -} - -vector mcpl_source_sites(std::string path) -{ - ensure_mcpl_ready_or_fatal(); - vector sites; - - mcpl_file_t* mcpl_file = g_mcpl_api->open_file(path.c_str()); - if (!mcpl_file) { - fatal_error(fmt::format("MCPL: Could not open file '{}'. It might be " - "missing, inaccessible, or not a valid MCPL file.", - path)); - } - - size_t n_particles_in_file = g_mcpl_api->hdr_nparticles(mcpl_file); - if (n_particles_in_file > 0) { - sites.reserve(n_particles_in_file); - } - - for (size_t i = 0; i < n_particles_in_file; ++i) { - const mcpl_particle_repr_t* p_repr = g_mcpl_api->read(mcpl_file); - if (!p_repr) { - warning(fmt::format("MCPL: Read error or unexpected end of file '{}' " - "after reading {} of {} expected particles.", - path, sites.size(), n_particles_in_file)); - break; - } - sites.push_back(mcpl_particle_to_site(p_repr)); - } - - g_mcpl_api->close_file(mcpl_file); - - if (sites.empty()) { - if (n_particles_in_file > 0) { - fatal_error(fmt::format( - "MCPL file '{}' contained {} particles, but no particles could be " - "read.", - path, n_particles_in_file)); - } else { - fatal_error(fmt::format( - "MCPL file '{}' is empty or contains no particle data.", path)); - } - } - return sites; -} - -void write_mcpl_source_bank_internal(mcpl_outfile_t* file_id, - span local_source_bank, - const vector& bank_index_all_ranks) -{ - if (mpi::master) { - if (!file_id) { - fatal_error("MCPL: Internal error - master rank called " - "write_mcpl_source_bank_internal with null file_id."); - } - vector receive_buffer; - - for (int rank_idx = 0; rank_idx < mpi::n_procs; ++rank_idx) { - size_t num_sites_on_rank = static_cast( - bank_index_all_ranks[rank_idx + 1] - bank_index_all_ranks[rank_idx]); - if (num_sites_on_rank == 0) - continue; - - span sites_to_write; -#ifdef OPENMC_MPI - if (rank_idx == mpi::rank) { - sites_to_write = openmc::span( - local_source_bank.data(), num_sites_on_rank); - } else { - if (receive_buffer.size() < num_sites_on_rank) { - receive_buffer.resize(num_sites_on_rank); - } - MPI_Recv(receive_buffer.data(), num_sites_on_rank, mpi::source_site, - rank_idx, rank_idx, mpi::intracomm, MPI_STATUS_IGNORE); - sites_to_write = openmc::span( - receive_buffer.data(), num_sites_on_rank); - } -#else - sites_to_write = openmc::span( - local_source_bank.data(), num_sites_on_rank); -#endif - for (const auto& site : sites_to_write) { - mcpl_particle_repr_t p_repr {}; - p_repr.position[0] = site.r.x; - p_repr.position[1] = site.r.y; - p_repr.position[2] = site.r.z; - p_repr.direction[0] = site.u.x; - p_repr.direction[1] = site.u.y; - p_repr.direction[2] = site.u.z; - p_repr.ekin = site.E * 1e-6; - p_repr.time = site.time * 1e3; - p_repr.weight = site.wgt; - p_repr.pdgcode = site.particle.pdg_number(); - g_mcpl_api->add_particle(file_id, &p_repr); - } - } - } else { -#ifdef OPENMC_MPI - if (!local_source_bank.empty()) { - MPI_Send(local_source_bank.data(), local_source_bank.size(), - mpi::source_site, 0, mpi::rank, mpi::intracomm); - } -#endif - } -} - -void write_mcpl_source_point(const char* filename, span source_bank, - const vector& bank_index) -{ - ensure_mcpl_ready_or_fatal(); - - std::string filename_(filename); - const auto extension = get_file_extension(filename_); - if (extension.empty()) { - filename_.append(".mcpl"); - } else if (extension != "mcpl") { - warning(fmt::format("Specified filename '{}' has an extension '.{}', but " - "an MCPL file (.mcpl) will be written using this name.", - filename, extension)); - } - - mcpl_outfile_t* file_id = nullptr; - - if (mpi::master) { - file_id = g_mcpl_api->create_outfile(filename_.c_str()); - if (!file_id) { - fatal_error(fmt::format( - "MCPL: Failed to create output file '{}'. Check permissions and path.", - filename_)); - } - std::string src_line; - if (VERSION_DEV) { - src_line = fmt::format("OpenMC {}.{}.{}-dev{}", VERSION_MAJOR, - VERSION_MINOR, VERSION_RELEASE, VERSION_COMMIT_COUNT); - } else { - src_line = fmt::format( - "OpenMC {}.{}.{}", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE); - } - g_mcpl_api->hdr_set_srcname(file_id, src_line.c_str()); - - // Initialize stat:sum with -1 to indicate incomplete file (issue #3514) - // This follows MCPL >= 2.1.0 convention for tracking simulation statistics - // The -1 value indicates "not available" if file creation is interrupted - if (g_mcpl_api->hdr_add_stat_sum) { - // Using key "openmc_np1" following tkittel's recommendation - // Initial value of -1 prevents misleading values in case of crashes - g_mcpl_api->hdr_add_stat_sum(file_id, "openmc_np1", -1.0); - } - } - - write_mcpl_source_bank_internal(file_id, source_bank, bank_index); - - if (mpi::master) { - if (file_id) { - // Update stat:sum with actual particle count before closing (issue #3514) - // This represents the original number of source particles in the - // simulation (not the number of particles in the file) - if (g_mcpl_api->hdr_add_stat_sum) { - // Calculate total source particles from active batches - // Per issue #3514: this should be the original number of source - // particles, not the number written to the file - int64_t total_source_particles = - static_cast(settings::n_batches - settings::n_inactive) * - settings::gen_per_batch * settings::n_particles; - // Update with actual count - this overwrites the initial -1 value - g_mcpl_api->hdr_add_stat_sum( - file_id, "openmc_np1", static_cast(total_source_particles)); - } - - g_mcpl_api->close_outfile(file_id); - } - } -} - -// Collision track feature with MCPL -void write_mcpl_collision_track_internal(mcpl_outfile_t* file_id, - span collision_track_bank, - const vector& bank_index_all_ranks) -{ - if (mpi::master) { - if (!file_id) { - fatal_error("MCPL: Internal error - master rank called " - "write_mcpl_source_bank_internal with null file_id."); - } - vector receive_buffer; - vector all_sites; - all_sites.reserve(static_cast(bank_index_all_ranks.back())); - vector all_blobs; - all_blobs.reserve(static_cast(bank_index_all_ranks.back())); - - for (int rank_idx = 0; rank_idx < mpi::n_procs; ++rank_idx) { - size_t num_sites_on_rank = static_cast( - bank_index_all_ranks[rank_idx + 1] - bank_index_all_ranks[rank_idx]); - if (num_sites_on_rank == 0) - continue; - - span sites_to_process; -#ifdef OPENMC_MPI - if (rank_idx == mpi::rank) { - sites_to_process = openmc::span( - collision_track_bank.data(), num_sites_on_rank); - } else { - receive_buffer.resize(num_sites_on_rank); - MPI_Recv(receive_buffer.data(), num_sites_on_rank, - mpi::collision_track_site, rank_idx, rank_idx, mpi::intracomm, - MPI_STATUS_IGNORE); - sites_to_process = openmc::span( - receive_buffer.data(), num_sites_on_rank); - } -#else - sites_to_process = openmc::span( - collision_track_bank.data(), num_sites_on_rank); -#endif - - for (const auto& site : sites_to_process) { - std::ostringstream custom_data_stream; - custom_data_stream << " dE : " << site.dE - << " ; event_mt : " << site.event_mt - << " ; delayed_group : " << site.delayed_group - << " ; cell_id : " << site.cell_id - << " ; nuclide_id : " << site.nuclide_id - << " ; material_id : " << site.material_id - << " ; universe_id : " << site.universe_id - << " ; n_collision : " << site.n_collision - << " ; parent_id : " << site.parent_id - << " ; progeny_id : " << site.progeny_id; - - all_blobs.push_back(custom_data_stream.str()); - all_sites.push_back(site); - } - } - - for (size_t idx = 0; idx < all_blobs.size(); ++idx) { - const auto& blob = all_blobs[idx]; - std::string key = "blob_" + std::to_string(idx); - g_mcpl_api->hdr_add_data(file_id, key.c_str(), blob.size(), blob.c_str()); - } - - for (const auto& site : all_sites) { - mcpl_particle_repr_t p_repr {}; - p_repr.position[0] = site.r.x; - p_repr.position[1] = site.r.y; - p_repr.position[2] = site.r.z; - p_repr.direction[0] = site.u.x; - p_repr.direction[1] = site.u.y; - p_repr.direction[2] = site.u.z; - p_repr.ekin = site.E * 1e-6; - p_repr.time = site.time * 1e3; - p_repr.weight = site.wgt; - p_repr.pdgcode = site.particle.pdg_number(); - g_mcpl_api->add_particle(file_id, &p_repr); - } - } else { -#ifdef OPENMC_MPI - if (!collision_track_bank.empty()) { - MPI_Send(collision_track_bank.data(), collision_track_bank.size(), - mpi::collision_track_site, 0, mpi::rank, mpi::intracomm); - } -#endif - } -} - -void write_mcpl_collision_track(const char* filename, - span collision_track_bank, - const vector& bank_index) -{ - ensure_mcpl_ready_or_fatal(); - - std::string filename_(filename); - const auto extension = get_file_extension(filename_); - if (extension.empty()) { - filename_.append(".mcpl"); - } else if (extension != "mcpl") { - warning(fmt::format("Specified filename '{}' has an extension '.{}', but " - "an MCPL file (.mcpl) will be written using this name.", - filename, extension)); - } - - mcpl_outfile_t* file_id = nullptr; - - if (mpi::master) { - file_id = g_mcpl_api->create_outfile(filename_.c_str()); - if (!file_id) { - fatal_error(fmt::format( - "MCPL: Failed to create output file '{}'. Check permissions and path.", - filename_)); - } - std::string src_line; - if (VERSION_DEV) { - src_line = fmt::format("OpenMC {}.{}.{}-dev{}", VERSION_MAJOR, - VERSION_MINOR, VERSION_RELEASE, VERSION_COMMIT_COUNT); - } else { - src_line = fmt::format( - "OpenMC {}.{}.{}", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE); - } - - g_mcpl_api->hdr_set_srcname(file_id, src_line.c_str()); - } - write_mcpl_collision_track_internal( - file_id, collision_track_bank, bank_index); - - if (mpi::master) { - if (file_id) { - g_mcpl_api->close_outfile(file_id); - } - } -} - -} // namespace openmc diff --git a/src/mesh.cpp b/src/mesh.cpp index b05560d2a..55fbc8e29 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,23 +1,22 @@ #include "openmc/mesh.h" #include // for copy, equal, min, min_element -#include -#include // for ceil -#include // for size_t -#include // for uint64_t -#include // for memcpy -#include -#include // for accumulate +#include // for ceil +#include // for size_t +#include #include -#ifdef _MSC_VER -#include // for _InterlockedCompareExchange -#endif - #ifdef OPENMC_MPI #include "mpi.h" #endif - -#include "openmc/tensor.h" +#ifdef _OPENMP +#include +#endif +#include "xtensor/xbuilder.hpp" +#include "xtensor/xeval.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xtensor.hpp" +#include "xtensor/xview.hpp" #include // for fmt #include "openmc/capi.h" @@ -25,34 +24,19 @@ #include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" -#include "openmc/geometry.h" #include "openmc/hdf5_interface.h" -#include "openmc/material.h" #include "openmc/memory.h" #include "openmc/message_passing.h" -#include "openmc/openmp_interface.h" -#include "openmc/output.h" -#include "openmc/particle_data.h" -#include "openmc/plot.h" -#include "openmc/random_dist.h" #include "openmc/search.h" #include "openmc/settings.h" -#include "openmc/string_utils.h" #include "openmc/tallies/filter.h" #include "openmc/tallies/tally.h" -#include "openmc/timer.h" -#include "openmc/volume_calc.h" #include "openmc/xml_interface.h" -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH #include "libmesh/mesh_modification.h" #include "libmesh/mesh_tools.h" #include "libmesh/numeric_vector.h" -#include "libmesh/replicated_mesh.h" -#endif - -#ifdef OPENMC_DAGMC_ENABLED -#include "moab/FileOptions.hpp" #endif namespace openmc { @@ -61,16 +45,12 @@ namespace openmc { // Global variables //============================================================================== -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH const bool LIBMESH_ENABLED = true; #else const bool LIBMESH_ENABLED = false; #endif -// Value used to indicate an empty slot in the hash table. We use -2 because -// the value -1 is used to indicate a void material. -constexpr int32_t EMPTY = -2; - namespace model { std::unordered_map mesh_map; @@ -78,7 +58,7 @@ vector> meshes; } // namespace model -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH namespace settings { unique_ptr libmesh_init; const libMesh::Parallel::Communicator* libmesh_comm {nullptr}; @@ -112,281 +92,19 @@ inline bool check_intersection_point(double x1, double x0, double y1, double y0, return false; } -//! Atomic compare-and-swap for signed 32-bit integer -// -//! \param[in,out] ptr Pointer to value to update -//! \param[in,out] expected Value to compare to -//! \param[in] desired If comparison is successful, value to update to -//! \return True if the comparison was successful and the value was updated -inline bool atomic_cas_int32(int32_t* ptr, int32_t& expected, int32_t desired) -{ -#if defined(__GNUC__) || defined(__clang__) - // For gcc/clang, use the __atomic_compare_exchange_n intrinsic - return __atomic_compare_exchange_n( - ptr, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - -#elif defined(_MSC_VER) - // For MSVC, use the _InterlockedCompareExchange intrinsic - int32_t old_val = - _InterlockedCompareExchange(reinterpret_cast(ptr), - static_cast(desired), static_cast(expected)); - return (old_val == expected); - -#else -#error "No compare-and-swap implementation available for this compiler." -#endif -} - -// Helper function equivalent to std::bit_cast in C++20 -template -inline To bit_cast_value(const From& value) -{ - To out; - std::memcpy(&out, &value, sizeof(To)); - return out; -} - -inline void atomic_update_double(double* ptr, double value, bool is_min) -{ -#if defined(__GNUC__) || defined(__clang__) - using may_alias_uint64_t [[gnu::may_alias]] = uint64_t; - auto* bits_ptr = reinterpret_cast(ptr); - uint64_t current_bits = __atomic_load_n(bits_ptr, __ATOMIC_SEQ_CST); - double current = bit_cast_value(current_bits); - while (is_min ? (value < current) : (value > current)) { - uint64_t desired_bits = bit_cast_value(value); - uint64_t expected_bits = current_bits; - if (__atomic_compare_exchange_n(bits_ptr, &expected_bits, desired_bits, - false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { - return; - } - current_bits = expected_bits; - current = bit_cast_value(current_bits); - } - -#elif defined(_MSC_VER) - auto* bits_ptr = reinterpret_cast(ptr); - long long current_bits = *bits_ptr; - double current = bit_cast_value(current_bits); - while (is_min ? (value < current) : (value > current)) { - long long desired_bits = bit_cast_value(value); - long long old_bits = - _InterlockedCompareExchange64(bits_ptr, desired_bits, current_bits); - if (old_bits == current_bits) { - return; - } - current_bits = old_bits; - current = bit_cast_value(current_bits); - } - -#else -#error "No compare-and-swap implementation available for this compiler." -#endif -} - -inline void atomic_max_double(double* ptr, double value) -{ - atomic_update_double(ptr, value, false); -} - -inline void atomic_min_double(double* ptr, double value) -{ - atomic_update_double(ptr, value, true); -} - -namespace detail { - -//============================================================================== -// MaterialVolumes implementation -//============================================================================== - -void MaterialVolumes::add_volume( - int index_elem, int index_material, double volume, const BoundingBox* bbox) -{ - // This method handles adding elements to the materials hash table, - // implementing open addressing with linear probing. Consistency across - // multiple threads is handled by with an atomic compare-and-swap operation. - // Ideally, we would use #pragma omp atomic compare, but it was introduced in - // OpenMP 5.1 and is not widely supported yet. - - // Loop for linear probing - for (int attempt = 0; attempt < table_size_; ++attempt) { - // Determine slot to check, making sure it is positive - int slot = (index_material + attempt) % table_size_; - if (slot < 0) - slot += table_size_; - int32_t* slot_ptr = &this->materials(index_elem, slot); - - // Non-atomic read of current material - int32_t current_val = *slot_ptr; - - // Found the desired material; accumulate volume and bbox - if (current_val == index_material) { -#pragma omp atomic - this->volumes(index_elem, slot) += volume; - if (bbox) { - atomic_min_double(&this->bboxes(index_elem, slot, 0), bbox->min.x); - atomic_min_double(&this->bboxes(index_elem, slot, 1), bbox->min.y); - atomic_min_double(&this->bboxes(index_elem, slot, 2), bbox->min.z); - atomic_max_double(&this->bboxes(index_elem, slot, 3), bbox->max.x); - atomic_max_double(&this->bboxes(index_elem, slot, 4), bbox->max.y); - atomic_max_double(&this->bboxes(index_elem, slot, 5), bbox->max.z); - } - return; - } - - // Slot appears to be empty; attempt to claim - if (current_val == EMPTY) { - // Attempt compare-and-swap from EMPTY to index_material - int32_t expected_val = EMPTY; - bool claimed_slot = - atomic_cas_int32(slot_ptr, expected_val, index_material); - - // If we claimed the slot or another thread claimed it but the same - // material was inserted, proceed to accumulate - if (claimed_slot || (expected_val == index_material)) { -#pragma omp atomic - this->volumes(index_elem, slot) += volume; - if (bbox) { - atomic_min_double(&this->bboxes(index_elem, slot, 0), bbox->min.x); - atomic_min_double(&this->bboxes(index_elem, slot, 1), bbox->min.y); - atomic_min_double(&this->bboxes(index_elem, slot, 2), bbox->min.z); - atomic_max_double(&this->bboxes(index_elem, slot, 3), bbox->max.x); - atomic_max_double(&this->bboxes(index_elem, slot, 4), bbox->max.y); - atomic_max_double(&this->bboxes(index_elem, slot, 5), bbox->max.z); - } - return; - } - } - } - - // If table is full, set a flag that can be checked later - table_full_ = true; -} - -void MaterialVolumes::add_volume_unsafe( - int index_elem, int index_material, double volume, const BoundingBox* bbox) -{ - // Linear probe - for (int attempt = 0; attempt < table_size_; ++attempt) { - // Determine slot to check, making sure it is positive - int slot = (index_material + attempt) % table_size_; - if (slot < 0) - slot += table_size_; - - // Read current material - int32_t current_val = this->materials(index_elem, slot); - - // Found the desired material; accumulate volume and bbox - if (current_val == index_material) { - this->volumes(index_elem, slot) += volume; - if (bbox) { - this->bboxes(index_elem, slot, 0) = - std::min(this->bboxes(index_elem, slot, 0), bbox->min.x); - this->bboxes(index_elem, slot, 1) = - std::min(this->bboxes(index_elem, slot, 1), bbox->min.y); - this->bboxes(index_elem, slot, 2) = - std::min(this->bboxes(index_elem, slot, 2), bbox->min.z); - this->bboxes(index_elem, slot, 3) = - std::max(this->bboxes(index_elem, slot, 3), bbox->max.x); - this->bboxes(index_elem, slot, 4) = - std::max(this->bboxes(index_elem, slot, 4), bbox->max.y); - this->bboxes(index_elem, slot, 5) = - std::max(this->bboxes(index_elem, slot, 5), bbox->max.z); - } - return; - } - - // Claim empty slot - if (current_val == EMPTY) { - this->materials(index_elem, slot) = index_material; - this->volumes(index_elem, slot) += volume; - if (bbox) { - this->bboxes(index_elem, slot, 0) = - std::min(this->bboxes(index_elem, slot, 0), bbox->min.x); - this->bboxes(index_elem, slot, 1) = - std::min(this->bboxes(index_elem, slot, 1), bbox->min.y); - this->bboxes(index_elem, slot, 2) = - std::min(this->bboxes(index_elem, slot, 2), bbox->min.z); - this->bboxes(index_elem, slot, 3) = - std::max(this->bboxes(index_elem, slot, 3), bbox->max.x); - this->bboxes(index_elem, slot, 4) = - std::max(this->bboxes(index_elem, slot, 4), bbox->max.y); - this->bboxes(index_elem, slot, 5) = - std::max(this->bboxes(index_elem, slot, 5), bbox->max.z); - } - return; - } - } - - // If table is full, set a flag that can be checked later - table_full_ = true; -} - -} // namespace detail - //============================================================================== // Mesh implementation //============================================================================== -template -const std::unique_ptr& Mesh::create( - T dataset, const std::string& mesh_type, const std::string& mesh_library) -{ - // Determine mesh type. Add to model vector and map - if (mesh_type == RegularMesh::mesh_type) { - model::meshes.push_back(make_unique(dataset)); - } else if (mesh_type == RectilinearMesh::mesh_type) { - model::meshes.push_back(make_unique(dataset)); - } else if (mesh_type == CylindricalMesh::mesh_type) { - model::meshes.push_back(make_unique(dataset)); - } else if (mesh_type == SphericalMesh::mesh_type) { - model::meshes.push_back(make_unique(dataset)); -#ifdef OPENMC_DAGMC_ENABLED - } else if (mesh_type == UnstructuredMesh::mesh_type && - mesh_library == MOABMesh::mesh_lib_type) { - model::meshes.push_back(make_unique(dataset)); -#endif -#ifdef OPENMC_LIBMESH_ENABLED - } else if (mesh_type == UnstructuredMesh::mesh_type && - mesh_library == LibMesh::mesh_lib_type) { - model::meshes.push_back(make_unique(dataset)); -#endif - } else if (mesh_type == UnstructuredMesh::mesh_type) { - fatal_error("Unstructured mesh support is not enabled or the mesh " - "library is invalid."); - } else { - fatal_error(fmt::format("Invalid mesh type: {}", mesh_type)); - } - - // Map ID to position in vector - model::mesh_map[model::meshes.back()->id_] = model::meshes.size() - 1; - - return model::meshes.back(); -} - Mesh::Mesh(pugi::xml_node node) { // Read mesh id id_ = std::stoi(get_node_value(node, "id")); - if (check_for_node(node, "name")) - name_ = get_node_value(node, "name"); -} - -Mesh::Mesh(hid_t group) -{ - // Read mesh ID - read_attribute(group, "id", id_); - - // Read mesh name - if (object_exists(group, "name")) { - read_dataset(group, "name", name_); - } } void Mesh::set_id(int32_t id) { - assert(id >= 0 || id == C_NONE); + Expects(id >= 0 || id == C_NONE); // Clear entry in mesh map in case one was already assigned if (id_ != C_NONE) { @@ -411,343 +129,7 @@ void Mesh::set_id(int32_t id) // Update ID and entry in the mesh map id_ = id; - - // find the index of this mesh in the model::meshes vector - // (search in reverse because this mesh was likely just added to the vector) - auto it = std::find_if(model::meshes.rbegin(), model::meshes.rend(), - [this](const std::unique_ptr& mesh) { return mesh.get() == this; }); - - model::mesh_map[id] = std::distance(model::meshes.begin(), it.base()) - 1; -} - -vector Mesh::volumes() const -{ - vector volumes(n_bins()); - for (int i = 0; i < n_bins(); i++) { - volumes[i] = this->volume(i); - } - return volumes; -} - -void Mesh::material_volumes(int nx, int ny, int nz, int table_size, - int32_t* materials, double* volumes) const -{ - this->material_volumes(nx, ny, nz, table_size, materials, volumes, nullptr); -} - -void Mesh::material_volumes(int nx, int ny, int nz, int table_size, - int32_t* materials, double* volumes, double* bboxes) const -{ - if (mpi::master) { - header("MESH MATERIAL VOLUMES CALCULATION", 7); - } - write_message(7, "Number of mesh elements = {}", n_bins()); - write_message(7, "Number of rays (x) = {}", nx); - write_message(7, "Number of rays (y) = {}", ny); - write_message(7, "Number of rays (z) = {}", nz); - int64_t n_total = static_cast(nx) * ny + - static_cast(ny) * nz + - static_cast(nx) * nz; - write_message(7, "Total number of rays = {}", n_total); - write_message(7, "Table size per mesh element = {}", table_size); - - Timer timer; - timer.start(); - - // Create object for keeping track of materials/volumes - detail::MaterialVolumes result(materials, volumes, bboxes, table_size); - bool compute_bboxes = bboxes != nullptr; - - // Determine bounding box - auto bbox = this->bounding_box(); - - std::array n_rays = {nx, ny, nz}; - - // Determine effective width of rays - Position width = bbox.max - bbox.min; - width.x = (nx > 0) ? width.x / nx : 0.0; - width.y = (ny > 0) ? width.y / ny : 0.0; - width.z = (nz > 0) ? width.z / nz : 0.0; - - // Set flag for mesh being contained within model - bool out_of_model = false; - -#pragma omp parallel - { - // Preallocate vector for mesh indices and length fractions and particle - vector bins; - vector length_fractions; - Particle p; - - SourceSite site; - site.E = 1.0; - site.particle = ParticleType::neutron(); - - for (int axis = 0; axis < 3; ++axis) { - // Set starting position and direction - site.r = {0.0, 0.0, 0.0}; - site.r[axis] = bbox.min[axis]; - site.u = {0.0, 0.0, 0.0}; - site.u[axis] = 1.0; - - // Determine width of rays and number of rays in other directions - int ax1 = (axis + 1) % 3; - int ax2 = (axis + 2) % 3; - double min1 = bbox.min[ax1]; - double min2 = bbox.min[ax2]; - double d1 = width[ax1]; - double d2 = width[ax2]; - int n1 = n_rays[ax1]; - int n2 = n_rays[ax2]; - if (n1 == 0 || n2 == 0) { - continue; - } - - // Divide rays in first direction over MPI processes by computing starting - // and ending indices - int min_work = n1 / mpi::n_procs; - int remainder = n1 % mpi::n_procs; - int n1_local = (mpi::rank < remainder) ? min_work + 1 : min_work; - int i1_start = mpi::rank * min_work + std::min(mpi::rank, remainder); - int i1_end = i1_start + n1_local; - - // Loop over rays on face of bounding box -#pragma omp for collapse(2) - for (int i1 = i1_start; i1 < i1_end; ++i1) { - for (int i2 = 0; i2 < n2; ++i2) { - site.r[ax1] = min1 + (i1 + 0.5) * d1; - site.r[ax2] = min2 + (i2 + 0.5) * d2; - - p.from_source(&site); - - // Determine particle's location - if (!exhaustive_find_cell(p)) { - out_of_model = true; - continue; - } - - // Set birth cell attribute - if (p.cell_born() == C_NONE) - p.cell_born() = p.lowest_coord().cell(); - - // Initialize last cells from current cell - for (int j = 0; j < p.n_coord(); ++j) { - p.cell_last(j) = p.coord(j).cell(); - } - p.n_coord_last() = p.n_coord(); - - while (true) { - // Ray trace from r_start to r_end - Position r0 = p.r(); - double max_distance = bbox.max[axis] - r0[axis]; - - // Find the distance to the nearest boundary - BoundaryInfo boundary = distance_to_boundary(p); - - // Advance particle forward - double distance = std::min(boundary.distance(), max_distance); - p.move_distance(distance); - - // Determine what mesh elements were crossed by particle - bins.clear(); - length_fractions.clear(); - this->bins_crossed(r0, p.r(), p.u(), bins, length_fractions); - - // Add volumes to any mesh elements that were crossed - int i_material = p.material(); - if (i_material != C_NONE) { - i_material = model::materials[i_material]->id(); - } - double cumulative_frac = 0.0; - for (int i_bin = 0; i_bin < bins.size(); i_bin++) { - int mesh_index = bins[i_bin]; - double length = distance * length_fractions[i_bin]; - double volume = length * d1 * d2; - - if (compute_bboxes) { - double axis_start = r0[axis] + distance * cumulative_frac; - double axis_end = axis_start + length; - cumulative_frac += length_fractions[i_bin]; - - Position contrib_min = site.r; - Position contrib_max = site.r; - - contrib_min[ax1] = site.r[ax1] - 0.5 * d1; - contrib_max[ax1] = site.r[ax1] + 0.5 * d1; - contrib_min[ax2] = site.r[ax2] - 0.5 * d2; - contrib_max[ax2] = site.r[ax2] + 0.5 * d2; - contrib_min[axis] = std::min(axis_start, axis_end); - contrib_max[axis] = std::max(axis_start, axis_end); - - BoundingBox contrib_bbox {contrib_min, contrib_max}; - contrib_bbox &= bbox; - - result.add_volume( - mesh_index, i_material, volume, &contrib_bbox); - } else { - // Add volume to result - result.add_volume(mesh_index, i_material, volume); - } - } - - if (distance == max_distance) - break; - - // cross next geometric surface - for (int j = 0; j < p.n_coord(); ++j) { - p.cell_last(j) = p.coord(j).cell(); - } - p.n_coord_last() = p.n_coord(); - - // Set surface that particle is on and adjust coordinate levels - p.surface() = boundary.surface(); - p.n_coord() = boundary.coord_level(); - - if (boundary.lattice_translation()[0] != 0 || - boundary.lattice_translation()[1] != 0 || - boundary.lattice_translation()[2] != 0) { - // Particle crosses lattice boundary - cross_lattice(p, boundary); - } else { - // Particle crosses surface - const auto& surf {model::surfaces[p.surface_index()].get()}; - p.cross_surface(*surf); - } - } - } - } - } - } - - // Check for errors - if (out_of_model) { - throw std::runtime_error("Mesh not fully contained in geometry."); - } else if (result.table_full()) { - throw std::runtime_error("Maximum number of materials for mesh material " - "volume calculation insufficient."); - } - - // Compute time for raytracing - double t_raytrace = timer.elapsed(); - -#ifdef OPENMC_MPI - // Combine results from multiple MPI processes - if (mpi::n_procs > 1) { - int total = this->n_bins() * table_size; - int total_bbox = total * 6; - if (mpi::master) { - // Allocate temporary buffer for receiving data - vector mats(total); - vector vols(total); - vector recv_bboxes; - if (compute_bboxes) { - recv_bboxes.resize(total_bbox); - } - - for (int i = 1; i < mpi::n_procs; ++i) { - // Receive material indices and volumes from process i - MPI_Recv(mats.data(), total, MPI_INT32_T, i, i, mpi::intracomm, - MPI_STATUS_IGNORE); - MPI_Recv(vols.data(), total, MPI_DOUBLE, i, i, mpi::intracomm, - MPI_STATUS_IGNORE); - if (compute_bboxes) { - MPI_Recv(recv_bboxes.data(), total_bbox, MPI_DOUBLE, i, i, - mpi::intracomm, MPI_STATUS_IGNORE); - } - - // Combine with existing results; we can call thread unsafe version of - // add_volume because each thread is operating on a different element -#pragma omp for - for (int index_elem = 0; index_elem < n_bins(); ++index_elem) { - for (int k = 0; k < table_size; ++k) { - int index = index_elem * table_size + k; - if (mats[index] != EMPTY) { - if (compute_bboxes) { - int bbox_index = index * 6; - BoundingBox slot_bbox { - {recv_bboxes[bbox_index + 0], recv_bboxes[bbox_index + 1], - recv_bboxes[bbox_index + 2]}, - {recv_bboxes[bbox_index + 3], recv_bboxes[bbox_index + 4], - recv_bboxes[bbox_index + 5]}}; - result.add_volume_unsafe( - index_elem, mats[index], vols[index], &slot_bbox); - } else { - result.add_volume_unsafe(index_elem, mats[index], vols[index]); - } - } - } - } - } - } else { - // Send material indices and volumes to process 0 - MPI_Send(materials, total, MPI_INT32_T, 0, mpi::rank, mpi::intracomm); - MPI_Send(volumes, total, MPI_DOUBLE, 0, mpi::rank, mpi::intracomm); - if (compute_bboxes) { - MPI_Send(bboxes, total_bbox, MPI_DOUBLE, 0, mpi::rank, mpi::intracomm); - } - } - } - - // Report time for MPI communication - double t_mpi = timer.elapsed() - t_raytrace; -#else - double t_mpi = 0.0; -#endif - - // Normalize based on known volumes of elements - for (int i = 0; i < this->n_bins(); ++i) { - // Estimated total volume in element i - double volume = 0.0; - for (int j = 0; j < table_size; ++j) { - volume += result.volumes(i, j); - } - // Renormalize volumes based on known volume of element i - double norm = this->volume(i) / volume; - for (int j = 0; j < table_size; ++j) { - result.volumes(i, j) *= norm; - } - } - - // Get total time and normalization time - timer.stop(); - double t_total = timer.elapsed(); - double t_norm = t_total - t_raytrace - t_mpi; - - // Show timing statistics - if (settings::verbosity < 7 || !mpi::master) - return; - header("Timing Statistics", 7); - fmt::print(" Total time elapsed = {:.4e} seconds\n", t_total); - fmt::print(" Ray tracing = {:.4e} seconds\n", t_raytrace); - fmt::print(" MPI communication = {:.4e} seconds\n", t_mpi); - fmt::print(" Normalization = {:.4e} seconds\n", t_norm); - fmt::print(" Calculation rate = {:.4e} rays/seconds\n", - n_total / t_raytrace); - fmt::print(" Calculation rate (per thread) = {:.4e} rays/seconds\n", - n_total / (t_raytrace * mpi::n_procs * num_threads())); - std::fflush(stdout); -} - -void Mesh::to_hdf5(hid_t group) const -{ - // Create group for mesh - std::string group_name = fmt::format("mesh {}", id_); - hid_t mesh_group = create_group(group, group_name.c_str()); - - // Write mesh type - write_dataset(mesh_group, "type", this->get_mesh_type()); - - // Write mesh ID - write_attribute(mesh_group, "id", id_); - - // Write mesh name - write_dataset(mesh_group, "name", name_); - - // Write mesh data - this->to_hdf5_inner(mesh_group); - - // Close group - close_group(mesh_group); + model::mesh_map[id] = model::meshes.size() - 1; } //============================================================================== @@ -767,26 +149,11 @@ std::string StructuredMesh::bin_label(int bin) const } } -tensor::Tensor StructuredMesh::get_shape_tensor() const +xt::xtensor StructuredMesh::get_x_shape() const { - return tensor::Tensor(shape_.data(), static_cast(n_dimension_)); -} - -Position StructuredMesh::sample_element( - const MeshIndex& ijk, uint64_t* seed) const -{ - // lookup the lower/upper bounds for the mesh element - double x_min = negative_grid_boundary(ijk, 0); - double x_max = positive_grid_boundary(ijk, 0); - - double y_min = (n_dimension_ >= 2) ? negative_grid_boundary(ijk, 1) : 0.0; - double y_max = (n_dimension_ >= 2) ? positive_grid_boundary(ijk, 1) : 0.0; - - double z_min = (n_dimension_ == 3) ? negative_grid_boundary(ijk, 2) : 0.0; - double z_max = (n_dimension_ == 3) ? positive_grid_boundary(ijk, 2) : 0.0; - - return {x_min + (x_max - x_min) * prn(seed), - y_min + (y_max - y_min) * prn(seed), z_min + (z_max - z_min) * prn(seed)}; + // because method is const, shape_ is const as well and can't be adapted + auto tmp_shape = shape_; + return xt::adapt(tmp_shape, {n_dimension_}); } //============================================================================== @@ -795,7 +162,6 @@ Position StructuredMesh::sample_element( UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) { - n_dimension_ = 3; // check the mesh type if (check_for_node(node, "type")) { @@ -808,6 +174,7 @@ UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) // check if a length unit multiplier was specified if (check_for_node(node, "length_multiplier")) { length_multiplier_ = std::stod(get_node_value(node, "length_multiplier")); + specified_length_multiplier_ = true; } // get the filename of the unstructured mesh to load @@ -821,10 +188,6 @@ UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) "No filename supplied for unstructured mesh with ID: {}", id_)); } - if (check_for_node(node, "options")) { - options_ = get_node_value(node, "options"); - } - // check if mesh tally data should be written with // statepoint files if (check_for_node(node, "output")) { @@ -832,98 +195,6 @@ UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) } } -UnstructuredMesh::UnstructuredMesh(hid_t group) : Mesh(group) -{ - n_dimension_ = 3; - - // check the mesh type - if (object_exists(group, "type")) { - std::string temp; - read_dataset(group, "type", temp); - if (temp != mesh_type) { - fatal_error(fmt::format("Invalid mesh type: {}", temp)); - } - } - - // check if a length unit multiplier was specified - if (object_exists(group, "length_multiplier")) { - read_dataset(group, "length_multiplier", length_multiplier_); - } - - // get the filename of the unstructured mesh to load - if (object_exists(group, "filename")) { - read_dataset(group, "filename", filename_); - if (!file_exists(filename_)) { - fatal_error("Mesh file '" + filename_ + "' does not exist!"); - } - } else { - fatal_error(fmt::format( - "No filename supplied for unstructured mesh with ID: {}", id_)); - } - - if (attribute_exists(group, "options")) { - read_attribute(group, "options", options_); - } - - // check if mesh tally data should be written with - // statepoint files - if (attribute_exists(group, "output")) { - read_attribute(group, "output", output_); - } -} - -void UnstructuredMesh::determine_bounds() -{ - double xmin = INFTY; - double ymin = INFTY; - double zmin = INFTY; - double xmax = -INFTY; - double ymax = -INFTY; - double zmax = -INFTY; - int n = this->n_vertices(); - for (int i = 0; i < n; ++i) { - auto v = this->vertex(i); - xmin = std::min(v.x, xmin); - ymin = std::min(v.y, ymin); - zmin = std::min(v.z, zmin); - xmax = std::max(v.x, xmax); - ymax = std::max(v.y, ymax); - zmax = std::max(v.z, zmax); - } - lower_left_ = {xmin, ymin, zmin}; - upper_right_ = {xmax, ymax, zmax}; -} - -Position UnstructuredMesh::sample_tet( - std::array coords, uint64_t* seed) const -{ - // Uniform distribution - double s = prn(seed); - double t = prn(seed); - double u = prn(seed); - - // From PyNE implementation of moab tet sampling C. Rocchini & P. Cignoni - // (2000) Generating Random Points in a Tetrahedron, Journal of Graphics - // Tools, 5:4, 9-12, DOI: 10.1080/10867651.2000.10487528 - if (s + t > 1) { - s = 1.0 - s; - t = 1.0 - t; - } - if (s + t + u > 1) { - if (t + u > 1) { - double old_t = t; - t = 1.0 - u; - u = 1.0 - s - old_t; - } else if (t + u <= 1) { - double old_s = s; - s = 1.0 - t - u; - u = old_s + t + u - 1; - } - } - return s * (coords[1] - coords[0]) + t * (coords[2] - coords[0]) + - u * (coords[3] - coords[0]) + coords[0]; -} - const std::string UnstructuredMesh::mesh_type = "unstructured"; std::string UnstructuredMesh::get_mesh_type() const @@ -942,23 +213,22 @@ std::string UnstructuredMesh::bin_label(int bin) const return fmt::format("Mesh Index ({})", bin); }; -void UnstructuredMesh::to_hdf5_inner(hid_t mesh_group) const +void UnstructuredMesh::to_hdf5(hid_t group) const { + hid_t mesh_group = create_group(group, fmt::format("mesh {}", id_)); + + write_dataset(mesh_group, "type", mesh_type); write_dataset(mesh_group, "filename", filename_); write_dataset(mesh_group, "library", this->library()); - if (!options_.empty()) { - write_attribute(mesh_group, "options", options_); - } - if (length_multiplier_ > 0.0) + if (specified_length_multiplier_) write_dataset(mesh_group, "length_multiplier", length_multiplier_); // write vertex coordinates - tensor::Tensor vertices( - {static_cast(this->n_vertices()), static_cast(3)}); + xt::xtensor vertices({static_cast(this->n_vertices()), 3}); for (int i = 0; i < this->n_vertices(); i++) { auto v = this->vertex(i); - vertices.slice(i) = {v.x, v.y, v.z}; + xt::view(vertices, i, xt::all()) = xt::xarray({v.x, v.y, v.z}); } write_dataset(mesh_group, "vertices", vertices); @@ -966,10 +236,8 @@ void UnstructuredMesh::to_hdf5_inner(hid_t mesh_group) const // write element types and connectivity vector volumes; - tensor::Tensor connectivity( - {static_cast(this->n_bins()), static_cast(8)}); - tensor::Tensor elem_types( - {static_cast(this->n_bins()), static_cast(1)}); + xt::xtensor connectivity ({static_cast(this->n_bins()), 8}); + xt::xtensor elem_types ({static_cast(this->n_bins()), 1}); for (int i = 0; i < this->n_bins(); i++) { auto conn = this->connectivity(i); @@ -977,18 +245,18 @@ void UnstructuredMesh::to_hdf5_inner(hid_t mesh_group) const // write linear tet element if (conn.size() == 4) { - elem_types.slice(i) = static_cast(ElementType::LINEAR_TET); - connectivity.slice(i) = { - conn[0], conn[1], conn[2], conn[3], -1, -1, -1, -1}; - // write linear hex element + xt::view(elem_types, i, xt::all()) = static_cast(ElementType::LINEAR_TET); + xt::view(connectivity, i, xt::all()) = xt::xarray({conn[0], conn[1], conn[2], conn[3], + -1, -1, -1, -1}); + // write linear hex element } else if (conn.size() == 8) { - elem_types.slice(i) = static_cast(ElementType::LINEAR_HEX); - connectivity.slice(i) = { - conn[0], conn[1], conn[2], conn[3], conn[4], conn[5], conn[6], conn[7]}; + xt::view(elem_types, i, xt::all()) = static_cast(ElementType::LINEAR_HEX); + xt::view(connectivity, i, xt::all()) = xt::xarray({conn[0], conn[1], conn[2], conn[3], + conn[4], conn[5], conn[6], conn[7]}); } else { num_elem_skipped++; - elem_types.slice(i) = static_cast(ElementType::UNSUPPORTED); - connectivity.slice(i) = -1; + xt::view(elem_types, i, xt::all()) = static_cast(ElementType::UNSUPPORTED); + xt::view(connectivity, i, xt::all()) = -1; } } @@ -1003,23 +271,16 @@ void UnstructuredMesh::to_hdf5_inner(hid_t mesh_group) const write_dataset(mesh_group, "volumes", volumes); write_dataset(mesh_group, "connectivity", connectivity); write_dataset(mesh_group, "element_types", elem_types); + + close_group(mesh_group); } void UnstructuredMesh::set_length_multiplier(double length_multiplier) { length_multiplier_ = length_multiplier; -} -ElementType UnstructuredMesh::element_type(int bin) const -{ - auto conn = connectivity(bin); - - if (conn.size() == 4) - return ElementType::LINEAR_TET; - else if (conn.size() == 8) - return ElementType::LINEAR_HEX; - else - return ElementType::UNSUPPORTED; + if (length_multiplier_ != 1.0) + specified_length_multiplier_ = true; } StructuredMesh::MeshIndex StructuredMesh::get_indices( @@ -1080,29 +341,16 @@ int StructuredMesh::get_bin(Position r) const int StructuredMesh::n_bins() const { - // Bin indices are stored as 32-bit ints in the tally system. - int64_t n = 1; - for (int i = 0; i < n_dimension_; ++i) - n *= shape_[i]; - if (n > std::numeric_limits::max()) { - fatal_error(fmt::format( - "Mesh {} has too many bins ({}) for 32-bit tally indexing", id_, n)); - } - return static_cast(n); + return std::accumulate( + shape_.begin(), shape_.begin() + n_dimension_, 1, std::multiplies<>()); } int StructuredMesh::n_surface_bins() const { - // Surface bin indices are stored as 32-bit ints in the tally system. - int64_t n = static_cast(n_bins()) * 4 * n_dimension_; - if (n > std::numeric_limits::max()) { - fatal_error(fmt::format( - "Mesh {} has too many surface bins ({}) for tally indexing", id_, n)); - } - return static_cast(n); + return 4 * n_dimension_ * n_bins(); } -tensor::Tensor StructuredMesh::count_sites( +xt::xtensor StructuredMesh::count_sites( const SourceSite* bank, int64_t length, bool* outside) const { // Determine shape of array for counts @@ -1110,7 +358,7 @@ tensor::Tensor StructuredMesh::count_sites( vector shape = {m}; // Create array of zeros - auto cnt = tensor::zeros(shape); + xt::xarray cnt {shape, 0.0}; bool outside_ = false; for (int64_t i = 0; i < length; i++) { @@ -1129,35 +377,42 @@ tensor::Tensor StructuredMesh::count_sites( cnt(mesh_bin) += site.wgt; } - // Create reduced count data - auto counts = tensor::zeros(shape); + // Create copy of count data. Since ownership will be acquired by xtensor, + // std::allocator must be used to avoid Valgrind mismatched free() / delete + // warnings. int total = cnt.size(); + double* cnt_reduced = std::allocator {}.allocate(total); #ifdef OPENMC_MPI // collect values from all processors MPI_Reduce( - cnt.data(), counts.data(), total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); + cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); // Check if there were sites outside the mesh for any processor if (outside) { MPI_Reduce(&outside_, outside, 1, MPI_C_BOOL, MPI_LOR, 0, mpi::intracomm); } #else - std::copy(cnt.data(), cnt.data() + total, counts.data()); + std::copy(cnt.data(), cnt.data() + total, cnt_reduced); if (outside) *outside = outside_; #endif + // Adapt reduced values in array back into an xarray + auto arr = xt::adapt(cnt_reduced, total, xt::acquire_ownership(), shape); + xt::xarray counts = arr; + return counts; } // raytrace through the mesh. The template class T will do the tallying. -// A modern optimizing compiler can recognize the noop method of T and -// eliminate that call entirely. +// A modern optimizing compiler can recognize the noop method of T and eleminate +// that call entirely. template void StructuredMesh::raytrace_mesh( Position r0, Position r1, const Direction& u, T tally) const { + // TODO: when c++-17 is available, use "if constexpr ()" to compile-time // enable/disable tally calls for now, T template type needs to provide both // surface and track methods, which might be empty. modern optimizing @@ -1166,14 +421,9 @@ void StructuredMesh::raytrace_mesh( // Compute the length of the entire track. double total_distance = (r1 - r0).norm(); - if (total_distance == 0.0 && settings::solver_type != SolverType::RANDOM_RAY) + if (total_distance == 0.0) return; - // keep a copy of the original global position to pass to get_indices, - // which performs its own transformation to local coordinates - Position global_r = r0; - Position local_r = local_coords(r0); - const int n = n_dimension_; // Flag if position is inside the mesh @@ -1184,7 +434,7 @@ void StructuredMesh::raytrace_mesh( // Calculate index of current cell. Offset the position a tiny bit in // direction of flight - MeshIndex ijk = get_indices(global_r + TINY_BIT * u, in_mesh); + MeshIndex ijk = get_indices(r0 + TINY_BIT * u, in_mesh); // if track is very short, assume that it is completely inside one cell. // Only the current cell will score and no surfaces @@ -1198,7 +448,7 @@ void StructuredMesh::raytrace_mesh( // Calculate initial distances to next surfaces in all three dimensions std::array distances; for (int k = 0; k < n; ++k) { - distances[k] = distance_to_grid_boundary(ijk, k, local_r, u, 0.0); + distances[k] = distance_to_grid_boundary(ijk, k, r0, u, 0.0); } // Loop until r = r1 is eventually reached @@ -1220,30 +470,28 @@ void StructuredMesh::raytrace_mesh( if (traveled_distance >= total_distance) return; - // If we have not reached r1, we have hit a surface. Tally outward - // current + // If we have not reached r1, we have hit a surface. Tally outward current tally.surface(ijk, k, distances[k].max_surface, false); // Update cell and calculate distance to next surface in k-direction. // The two other directions are still valid! ijk[k] = distances[k].next_index; distances[k] = - distance_to_grid_boundary(ijk, k, local_r, u, traveled_distance); + distance_to_grid_boundary(ijk, k, r0, u, traveled_distance); // Check if we have left the interior of the mesh in_mesh = ((ijk[k] >= 1) && (ijk[k] <= shape_[k])); - // If we are still inside the mesh, tally inward current for the next - // cell + // If we are still inside the mesh, tally inward current for the next cell if (in_mesh) tally.surface(ijk, k, !distances[k].max_surface, true); } else { // not inside mesh - // For all directions outside the mesh, find the distance that we need - // to travel to reach the next surface. Use the largest distance, as - // only this will cross all outer surfaces. - int k_max {-1}; + // For all directions outside the mesh, find the distance that we need to + // travel to reach the next surface. Use the largest distance, as only + // this will cross all outer surfaces. + int k_max {0}; for (int k = 0; k < n; ++k) { if ((ijk[k] < 1 || ijk[k] > shape_[k]) && (distances[k].distance > traveled_distance)) { @@ -1251,25 +499,20 @@ void StructuredMesh::raytrace_mesh( k_max = k; } } - // Assure some distance is traveled - if (k_max == -1) { - traveled_distance += TINY_BIT; - } // If r1 is not inside the mesh, exit here if (traveled_distance >= total_distance) return; - // Calculate the new cell index and update all distances to next - // surfaces. - ijk = get_indices(global_r + (traveled_distance + TINY_BIT) * u, in_mesh); + // Calculate the new cell index and update all distances to next surfaces. + ijk = get_indices(r0 + (traveled_distance + TINY_BIT) * u, in_mesh); for (int k = 0; k < n; ++k) { distances[k] = - distance_to_grid_boundary(ijk, k, local_r, u, traveled_distance); + distance_to_grid_boundary(ijk, k, r0, u, traveled_distance); } // If inside the mesh, Tally inward current - if (in_mesh && k_max >= 0) + if (in_mesh) tally.surface(ijk, k_max, !distances[k_max].max_surface, true); } } @@ -1338,72 +581,6 @@ void StructuredMesh::surface_bins_crossed( // RegularMesh implementation //============================================================================== -int RegularMesh::set_grid() -{ - tensor::Tensor shape(shape_.data(), static_cast(n_dimension_)); - - // Check that dimensions are all greater than zero - if ((shape <= 0).any()) { - set_errmsg("All entries for a regular mesh dimensions " - "must be positive."); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Make sure lower_left and dimension match - if (lower_left_.size() != n_dimension_) { - set_errmsg("Number of entries in lower_left must be the same " - "as the regular mesh dimensions."); - return OPENMC_E_INVALID_ARGUMENT; - } - if (width_.size() > 0) { - - // Check to ensure width has same dimensions - if (width_.size() != n_dimension_) { - set_errmsg("Number of entries on width must be the same as " - "the regular mesh dimensions."); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Check for negative widths - if ((width_ < 0.0).any()) { - set_errmsg("Cannot have a negative width on a regular mesh."); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Set width and upper right coordinate - upper_right_ = lower_left_ + shape * width_; - - } else if (upper_right_.size() > 0) { - - // Check to ensure upper_right_ has same dimensions - if (upper_right_.size() != n_dimension_) { - set_errmsg("Number of entries on upper_right must be the " - "same as the regular mesh dimensions."); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Check that upper-right is above lower-left - if ((upper_right_ < lower_left_).any()) { - set_errmsg( - "The upper_right coordinates of a regular mesh must be greater than " - "the lower_left coordinates."); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Set width - width_ = (upper_right_ - lower_left_) / shape; - } - - // Set material volumes - volume_frac_ = 1.0 / shape.prod(); - - element_volume_ = 1.0; - for (int i = 0; i < n_dimension_; i++) { - element_volume_ *= width_[i]; - } - return 0; -} - RegularMesh::RegularMesh(pugi::xml_node node) : StructuredMesh {node} { // Determine number of dimensions for mesh @@ -1411,76 +588,80 @@ RegularMesh::RegularMesh(pugi::xml_node node) : StructuredMesh {node} fatal_error("Must specify on a regular mesh."); } - tensor::Tensor shape = get_node_tensor(node, "dimension"); + xt::xtensor shape = get_node_xarray(node, "dimension"); int n = n_dimension_ = shape.size(); if (n != 1 && n != 2 && n != 3) { fatal_error("Mesh must be one, two, or three dimensions."); } std::copy(shape.begin(), shape.end(), shape_.begin()); + // Check that dimensions are all greater than zero + if (xt::any(shape <= 0)) { + fatal_error("All entries on the element for a tally " + "mesh must be positive."); + } + // Check for lower-left coordinates if (check_for_node(node, "lower_left")) { // Read mesh lower-left corner location - lower_left_ = get_node_tensor(node, "lower_left"); + lower_left_ = get_node_xarray(node, "lower_left"); } else { fatal_error("Must specify on a mesh."); } + // Make sure lower_left and dimension match + if (shape.size() != lower_left_.size()) { + fatal_error("Number of entries on must be the same " + "as the number of entries on ."); + } + if (check_for_node(node, "width")) { // Make sure one of upper-right or width were specified if (check_for_node(node, "upper_right")) { fatal_error("Cannot specify both and on a mesh."); } - width_ = get_node_tensor(node, "width"); + width_ = get_node_xarray(node, "width"); + + // Check to ensure width has same dimensions + auto n = width_.size(); + if (n != lower_left_.size()) { + fatal_error("Number of entries on must be the same as " + "the number of entries on ."); + } + + // Check for negative widths + if (xt::any(width_ < 0.0)) { + fatal_error("Cannot have a negative on a tally mesh."); + } + + // Set width and upper right coordinate + upper_right_ = xt::eval(lower_left_ + shape * width_); } else if (check_for_node(node, "upper_right")) { + upper_right_ = get_node_xarray(node, "upper_right"); - upper_right_ = get_node_tensor(node, "upper_right"); + // Check to ensure width has same dimensions + auto n = upper_right_.size(); + if (n != lower_left_.size()) { + fatal_error("Number of entries on must be the " + "same as the number of entries on ."); + } + // Check that upper-right is above lower-left + if (xt::any(upper_right_ < lower_left_)) { + fatal_error("The coordinates must be greater than " + "the coordinates on a tally mesh."); + } + + // Set width + width_ = xt::eval((upper_right_ - lower_left_) / shape); } else { fatal_error("Must specify either or on a mesh."); } - if (int err = set_grid()) { - fatal_error(openmc_err_msg); - } -} - -RegularMesh::RegularMesh(hid_t group) : StructuredMesh {group} -{ - // Determine number of dimensions for mesh - if (!object_exists(group, "dimension")) { - fatal_error("Must specify on a regular mesh."); - } - - tensor::Tensor shape; - read_dataset(group, "dimension", shape); - int n = n_dimension_ = shape.size(); - if (n != 1 && n != 2 && n != 3) { - fatal_error("Mesh must be one, two, or three dimensions."); - } - std::copy(shape.begin(), shape.end(), shape_.begin()); - - // Check for lower-left coordinates - if (object_exists(group, "lower_left")) { - // Read mesh lower-left corner location - read_dataset(group, "lower_left", lower_left_); - } else { - fatal_error("Must specify lower_left dataset on a mesh."); - } - - if (object_exists(group, "upper_right")) { - - read_dataset(group, "upper_right", upper_right_); - - } else { - fatal_error("Must specify either upper_right dataset on a mesh."); - } - - if (int err = set_grid()) { - fatal_error(openmc_err_msg); - } + // Set volume fraction + volume_frac_ = 1.0 / xt::prod(shape)(); } int RegularMesh::get_index_in_direction(double r, int i) const @@ -1522,7 +703,6 @@ StructuredMesh::MeshDistance RegularMesh::distance_to_grid_boundary( d.next_index--; d.distance = (negative_grid_boundary(ijk, i) - r0[i]) / u[i]; } - return d; } @@ -1567,15 +747,20 @@ std::pair, vector> RegularMesh::plot( return {axis_lines[0], axis_lines[1]}; } -void RegularMesh::to_hdf5_inner(hid_t mesh_group) const +void RegularMesh::to_hdf5(hid_t group) const { - write_dataset(mesh_group, "dimension", get_shape_tensor()); + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", "regular"); + write_dataset(mesh_group, "dimension", get_x_shape()); write_dataset(mesh_group, "lower_left", lower_left_); write_dataset(mesh_group, "upper_right", upper_right_); write_dataset(mesh_group, "width", width_); + + close_group(mesh_group); } -tensor::Tensor RegularMesh::count_sites( +xt::xtensor RegularMesh::count_sites( const SourceSite* bank, int64_t length, bool* outside) const { // Determine shape of array for counts @@ -1583,7 +768,7 @@ tensor::Tensor RegularMesh::count_sites( vector shape = {m}; // Create array of zeros - auto cnt = tensor::zeros(shape); + xt::xarray cnt {shape, 0.0}; bool outside_ = false; for (int64_t i = 0; i < length; i++) { @@ -1602,31 +787,32 @@ tensor::Tensor RegularMesh::count_sites( cnt(mesh_bin) += site.wgt; } - // Create reduced count data - auto counts = tensor::zeros(shape); + // Create copy of count data. Since ownership will be acquired by xtensor, + // std::allocator must be used to avoid Valgrind mismatched free() / delete + // warnings. int total = cnt.size(); + double* cnt_reduced = std::allocator {}.allocate(total); #ifdef OPENMC_MPI // collect values from all processors MPI_Reduce( - cnt.data(), counts.data(), total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); + cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); // Check if there were sites outside the mesh for any processor if (outside) { MPI_Reduce(&outside_, outside, 1, MPI_C_BOOL, MPI_LOR, 0, mpi::intracomm); } #else - std::copy(cnt.data(), cnt.data() + total, counts.data()); + std::copy(cnt.data(), cnt.data() + total, cnt_reduced); if (outside) *outside = outside_; #endif - return counts; -} + // Adapt reduced values in array back into an xarray + auto arr = xt::adapt(cnt_reduced, total, xt::acquire_ownership(), shape); + xt::xarray counts = arr; -double RegularMesh::volume(const MeshIndex& ijk) const -{ - return element_volume_; + return counts; } //============================================================================== @@ -1646,19 +832,6 @@ RectilinearMesh::RectilinearMesh(pugi::xml_node node) : StructuredMesh {node} } } -RectilinearMesh::RectilinearMesh(hid_t group) : StructuredMesh {group} -{ - n_dimension_ = 3; - - read_dataset(group, "x_grid", grid_[0]); - read_dataset(group, "y_grid", grid_[1]); - read_dataset(group, "z_grid", grid_[2]); - - if (int err = set_grid()) { - fatal_error(openmc_err_msg); - } -} - const std::string RectilinearMesh::mesh_type = "rectilinear"; std::string RectilinearMesh::get_mesh_type() const @@ -1759,48 +932,29 @@ std::pair, vector> RectilinearMesh::plot( return {axis_lines[0], axis_lines[1]}; } -void RectilinearMesh::to_hdf5_inner(hid_t mesh_group) const +void RectilinearMesh::to_hdf5(hid_t group) const { + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", "rectilinear"); write_dataset(mesh_group, "x_grid", grid_[0]); write_dataset(mesh_group, "y_grid", grid_[1]); write_dataset(mesh_group, "z_grid", grid_[2]); -} -double RectilinearMesh::volume(const MeshIndex& ijk) const -{ - double vol {1.0}; - - for (int i = 0; i < n_dimension_; i++) { - vol *= grid_[i][ijk[i]] - grid_[i][ijk[i] - 1]; - } - return vol; + close_group(mesh_group); } //============================================================================== // CylindricalMesh implementation //============================================================================== -CylindricalMesh::CylindricalMesh(pugi::xml_node node) - : PeriodicStructuredMesh {node} +CylindricalMesh::CylindricalMesh(pugi::xml_node node) : StructuredMesh {node} { n_dimension_ = 3; + grid_[0] = get_node_array(node, "r_grid"); grid_[1] = get_node_array(node, "phi_grid"); grid_[2] = get_node_array(node, "z_grid"); - origin_ = get_node_position(node, "origin"); - - if (int err = set_grid()) { - fatal_error(openmc_err_msg); - } -} - -CylindricalMesh::CylindricalMesh(hid_t group) : PeriodicStructuredMesh {group} -{ - n_dimension_ = 3; - read_dataset(group, "r_grid", grid_[0]); - read_dataset(group, "phi_grid", grid_[1]); - read_dataset(group, "z_grid", grid_[2]); - read_dataset(group, "origin", origin_); if (int err = set_grid()) { fatal_error(openmc_err_msg); @@ -1817,18 +971,16 @@ std::string CylindricalMesh::get_mesh_type() const StructuredMesh::MeshIndex CylindricalMesh::get_indices( Position r, bool& in_mesh) const { - r = local_coords(r); - Position mapped_r; + mapped_r[0] = std::hypot(r.x, r.y); mapped_r[2] = r[2]; - if (mapped_r[0] < FP_PRECISION) { mapped_r[1] = 0.0; } else { mapped_r[1] = std::atan2(r.y, r.x); if (mapped_r[1] < 0) - mapped_r[1] += 2 * PI; + mapped_r[1] += 2 * M_PI; } MeshIndex idx = StructuredMesh::get_indices(mapped_r, in_mesh); @@ -1838,30 +990,6 @@ StructuredMesh::MeshIndex CylindricalMesh::get_indices( return idx; } -Position CylindricalMesh::sample_element( - const MeshIndex& ijk, uint64_t* seed) const -{ - double r_min = this->r(ijk[0] - 1); - double r_max = this->r(ijk[0]); - - double phi_min = this->phi(ijk[1] - 1); - double phi_max = this->phi(ijk[1]); - - double z_min = this->z(ijk[2] - 1); - double z_max = this->z(ijk[2]); - - double r_min_sq = r_min * r_min; - double r_max_sq = r_max * r_max; - double r = std::sqrt(uniform_distribution(r_min_sq, r_max_sq, seed)); - double phi = uniform_distribution(phi_min, phi_max, seed); - double z = uniform_distribution(z_min, z_max, seed); - - double x = r * std::cos(phi); - double y = r * std::sin(phi); - - return origin_ + Position(x, y, z); -} - double CylindricalMesh::find_r_crossing( const Position& r, const Direction& u, double l, int shell) const { @@ -1874,9 +1002,6 @@ double CylindricalMesh::find_r_crossing( // s^2 * (u^2 + v^2) + 2*s*(u*x+v*y) + x^2+y^2-r0^2 = 0 const double r0 = grid_[0][shell]; - if (r0 == 0.0) - return INFTY; - const double denominator = u.x * u.x + u.y * u.y; // Direction of flight is in z-direction. Will never intersect r. @@ -1887,19 +1012,14 @@ double CylindricalMesh::find_r_crossing( const double inv_denominator = 1.0 / denominator; const double p = (u.x * r.x + u.y * r.y) * inv_denominator; - double R = std::sqrt(r.x * r.x + r.y * r.y); - double D = p * p - (R - r0) * (R + r0) * inv_denominator; + double D = p * p + (r0 * r0 - r.x * r.x - r.y * r.y) * inv_denominator; if (D < 0.0) return INFTY; D = std::sqrt(D); - // Particle is already on the shell surface; avoid spurious crossing - if (std::abs(R - r0) <= RADIAL_MESH_TOL * (1.0 + std::abs(r0))) - return INFTY; - - // Check -p - D first because it is always smaller as -p + D + // the solution -p - D is always smaller as -p + D : Check this one first if (-p - D > l) return -p - D; if (-p + D > l) @@ -1966,6 +1086,7 @@ StructuredMesh::MeshDistance CylindricalMesh::distance_to_grid_boundary( const MeshIndex& ijk, int i, const Position& r0, const Direction& u, double l) const { + if (i == 0) { return std::min( @@ -2022,10 +1143,8 @@ int CylindricalMesh::set_grid() full_phi_ = (grid_[1].front() == 0.0) && (grid_[1].back() == 2.0 * PI); - lower_left_ = {origin_[0] - grid_[0].back(), origin_[1] - grid_[0].back(), - origin_[2] + grid_[2].front()}; - upper_right_ = {origin_[0] + grid_[0].back(), origin_[1] + grid_[0].back(), - origin_[2] + grid_[2].back()}; + lower_left_ = {grid_[0].front(), grid_[1].front(), grid_[2].front()}; + upper_right_ = {grid_[0].back(), grid_[1].back(), grid_[2].back()}; return 0; } @@ -2045,55 +1164,29 @@ std::pair, vector> CylindricalMesh::plot( return {axis_lines[0], axis_lines[1]}; } -void CylindricalMesh::to_hdf5_inner(hid_t mesh_group) const +void CylindricalMesh::to_hdf5(hid_t group) const { + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", "cylindrical"); write_dataset(mesh_group, "r_grid", grid_[0]); write_dataset(mesh_group, "phi_grid", grid_[1]); write_dataset(mesh_group, "z_grid", grid_[2]); - write_dataset(mesh_group, "origin", origin_); -} -double CylindricalMesh::volume(const MeshIndex& ijk) const -{ - double r_i = grid_[0][ijk[0] - 1]; - double r_o = grid_[0][ijk[0]]; - - double phi_i = grid_[1][ijk[1] - 1]; - double phi_o = grid_[1][ijk[1]]; - - double z_i = grid_[2][ijk[2] - 1]; - double z_o = grid_[2][ijk[2]]; - - return 0.5 * (r_o * r_o - r_i * r_i) * (phi_o - phi_i) * (z_o - z_i); + close_group(mesh_group); } //============================================================================== // SphericalMesh implementation //============================================================================== -SphericalMesh::SphericalMesh(pugi::xml_node node) - : PeriodicStructuredMesh {node} +SphericalMesh::SphericalMesh(pugi::xml_node node) : StructuredMesh {node} { n_dimension_ = 3; grid_[0] = get_node_array(node, "r_grid"); grid_[1] = get_node_array(node, "theta_grid"); grid_[2] = get_node_array(node, "phi_grid"); - origin_ = get_node_position(node, "origin"); - - if (int err = set_grid()) { - fatal_error(openmc_err_msg); - } -} - -SphericalMesh::SphericalMesh(hid_t group) : PeriodicStructuredMesh {group} -{ - n_dimension_ = 3; - - read_dataset(group, "r_grid", grid_[0]); - read_dataset(group, "theta_grid", grid_[1]); - read_dataset(group, "phi_grid", grid_[2]); - read_dataset(group, "origin", origin_); if (int err = set_grid()) { fatal_error(openmc_err_msg); @@ -2110,11 +1203,9 @@ std::string SphericalMesh::get_mesh_type() const StructuredMesh::MeshIndex SphericalMesh::get_indices( Position r, bool& in_mesh) const { - r = local_coords(r); - Position mapped_r; - mapped_r[0] = r.norm(); + mapped_r[0] = r.norm(); if (mapped_r[0] < FP_PRECISION) { mapped_r[1] = 0.0; mapped_r[2] = 0.0; @@ -2122,7 +1213,7 @@ StructuredMesh::MeshIndex SphericalMesh::get_indices( mapped_r[1] = std::acos(r.z / mapped_r.x); mapped_r[2] = std::atan2(r.y, r.x); if (mapped_r[2] < 0) - mapped_r[2] += 2 * PI; + mapped_r[2] += 2 * M_PI; } MeshIndex idx = StructuredMesh::get_indices(mapped_r, in_mesh); @@ -2133,34 +1224,6 @@ StructuredMesh::MeshIndex SphericalMesh::get_indices( return idx; } -Position SphericalMesh::sample_element( - const MeshIndex& ijk, uint64_t* seed) const -{ - double r_min = this->r(ijk[0] - 1); - double r_max = this->r(ijk[0]); - - double theta_min = this->theta(ijk[1] - 1); - double theta_max = this->theta(ijk[1]); - - double phi_min = this->phi(ijk[2] - 1); - double phi_max = this->phi(ijk[2]); - - double cos_theta = - uniform_distribution(std::cos(theta_min), std::cos(theta_max), seed); - double sin_theta = std::sin(std::acos(cos_theta)); - double phi = uniform_distribution(phi_min, phi_max, seed); - double r_min_cub = std::pow(r_min, 3); - double r_max_cub = std::pow(r_max, 3); - // might be faster to do rejection here? - double r = std::cbrt(uniform_distribution(r_min_cub, r_max_cub, seed)); - - double x = r * std::cos(phi) * sin_theta; - double y = r * std::sin(phi) * sin_theta; - double z = r * cos_theta; - - return origin_ + Position(x, y, z); -} - double SphericalMesh::find_r_crossing( const Position& r, const Direction& u, double l, int shell) const { @@ -2170,19 +1233,12 @@ double SphericalMesh::find_r_crossing( // solve |r+s*u| = r0 // |r+s*u| = |r| + 2*s*r*u + s^2 (|u|==1 !) const double r0 = grid_[0][shell]; - if (r0 == 0.0) - return INFTY; const double p = r.dot(u); - double R = r.norm(); - double D = p * p - (R - r0) * (R + r0); - - // Particle is already on the shell surface; avoid spurious crossing - if (std::abs(R - r0) <= RADIAL_MESH_TOL * (1.0 + std::abs(r0))) - return INFTY; + double D = p * p - r.dot(r) + r0 * r0; if (D >= 0.0) { D = std::sqrt(D); - // Check -p - D first because it is always smaller as -p + D + // the solution -p - D is always smaller as -p + D : Check this one first if (-p - D > l) return -p - D; if (-p + D > l) @@ -2216,8 +1272,7 @@ double SphericalMesh::find_theta_crossing( const double b = r.dot(u) * cos_t_2 - r.z * u.z; const double c = r.dot(r) * cos_t_2 - r.z * r.z; - // if factor of s^2 is zero, direction of flight is parallel to theta - // surface + // if factor of s^2 is zero, direction of flight is parallel to theta surface if (std::abs(a) < FP_PRECISION) { // if b vanishes, direction of flight is within theta surface and crossing // is not possible @@ -2225,8 +1280,7 @@ double SphericalMesh::find_theta_crossing( return INFTY; const double s = -0.5 * c / b; - // Check if solution is in positive direction of flight and has correct - // sign + // Check if solution is in positive direction of flight and has correct sign if ((s > l) && (std::signbit(r.z + s * u.z) == sgn)) return s; @@ -2352,9 +1406,8 @@ int SphericalMesh::set_grid() full_theta_ = (grid_[1].front() == 0.0) && (grid_[1].back() == PI); full_phi_ = (grid_[2].front() == 0.0) && (grid_[2].back() == 2 * PI); - double r = grid_[0].back(); - lower_left_ = {origin_[0] - r, origin_[1] - r, origin_[2] - r}; - upper_right_ = {origin_[0] + r, origin_[1] + r, origin_[2] + r}; + lower_left_ = {grid_[0].front(), grid_[1].front(), grid_[2].front()}; + upper_right_ = {grid_[0].back(), grid_[1].back(), grid_[2].back()}; return 0; } @@ -2374,27 +1427,16 @@ std::pair, vector> SphericalMesh::plot( return {axis_lines[0], axis_lines[1]}; } -void SphericalMesh::to_hdf5_inner(hid_t mesh_group) const +void SphericalMesh::to_hdf5(hid_t group) const { + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", SphericalMesh::mesh_type); write_dataset(mesh_group, "r_grid", grid_[0]); write_dataset(mesh_group, "theta_grid", grid_[1]); write_dataset(mesh_group, "phi_grid", grid_[2]); - write_dataset(mesh_group, "origin", origin_); -} -double SphericalMesh::volume(const MeshIndex& ijk) const -{ - double r_i = grid_[0][ijk[0] - 1]; - double r_o = grid_[0][ijk[0]]; - - double theta_i = grid_[1][ijk[1] - 1]; - double theta_o = grid_[1][ijk[1]]; - - double phi_i = grid_[2][ijk[2] - 1]; - double phi_o = grid_[2][ijk[2]]; - - return (1.0 / 3.0) * (r_o * r_o * r_o - r_i * r_i * r_i) * - (std::cos(theta_i) - std::cos(theta_o)) * (phi_o - phi_i); + close_group(mesh_group); } //============================================================================== @@ -2481,14 +1523,14 @@ extern "C" int openmc_add_unstructured_mesh( std::string mesh_file(filename); bool valid_lib = false; -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC if (lib_name == MOABMesh::mesh_lib_type) { model::meshes.push_back(std::move(make_unique(mesh_file))); valid_lib = true; } #endif -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH if (lib_name == LibMesh::mesh_lib_type) { model::meshes.push_back(std::move(make_unique(mesh_file))); valid_lib = true; @@ -2540,124 +1582,6 @@ extern "C" int openmc_mesh_set_id(int32_t index, int32_t id) return 0; } -//! Get the number of elements in a mesh -extern "C" int openmc_mesh_get_n_elements(int32_t index, size_t* n) -{ - if (int err = check_mesh(index)) - return err; - *n = model::meshes[index]->n_bins(); - return 0; -} - -//! Get the volume of each element in the mesh -extern "C" int openmc_mesh_get_volumes(int32_t index, double* volumes) -{ - if (int err = check_mesh(index)) - return err; - for (int i = 0; i < model::meshes[index]->n_bins(); ++i) { - volumes[i] = model::meshes[index]->volume(i); - } - return 0; -} - -//! Get the bounding box of a mesh -extern "C" int openmc_mesh_bounding_box(int32_t index, double* ll, double* ur) -{ - if (int err = check_mesh(index)) - return err; - - BoundingBox bbox = model::meshes[index]->bounding_box(); - - // set lower left corner values - ll[0] = bbox.min.x; - ll[1] = bbox.min.y; - ll[2] = bbox.min.z; - - // set upper right corner values - ur[0] = bbox.max.x; - ur[1] = bbox.max.y; - ur[2] = bbox.max.z; - return 0; -} - -extern "C" int openmc_mesh_material_volumes(int32_t index, int nx, int ny, - int nz, int table_size, int32_t* materials, double* volumes, double* bboxes) -{ - if (int err = check_mesh(index)) - return err; - - try { - model::meshes[index]->material_volumes( - nx, ny, nz, table_size, materials, volumes, bboxes); - } catch (const std::exception& e) { - set_errmsg(e.what()); - if (starts_with(e.what(), "Mesh")) { - return OPENMC_E_GEOMETRY; - } else { - return OPENMC_E_ALLOCATE; - } - } - - return 0; -} - -extern "C" int openmc_mesh_get_plot_bins(int32_t index, Position origin, - Position width, int basis, int* pixels, int32_t* data) -{ - if (int err = check_mesh(index)) - return err; - const auto& mesh = model::meshes[index].get(); - - int pixel_width = pixels[0]; - int pixel_height = pixels[1]; - - // get pixel size - double in_pixel = (width[0]) / static_cast(pixel_width); - double out_pixel = (width[1]) / static_cast(pixel_height); - - // setup basis indices and initial position centered on pixel - int in_i, out_i; - Position xyz = origin; - enum class PlotBasis { xy = 1, xz = 2, yz = 3 }; - PlotBasis basis_enum = static_cast(basis); - switch (basis_enum) { - case PlotBasis::xy: - in_i = 0; - out_i = 1; - break; - case PlotBasis::xz: - in_i = 0; - out_i = 2; - break; - case PlotBasis::yz: - in_i = 1; - out_i = 2; - break; - default: - UNREACHABLE(); - } - - // set initial position - xyz[in_i] = origin[in_i] - width[0] / 2. + in_pixel / 2.; - xyz[out_i] = origin[out_i] + width[1] / 2. - out_pixel / 2.; - -#pragma omp parallel - { - Position r = xyz; - -#pragma omp for - for (int y = 0; y < pixel_height; y++) { - r[out_i] = xyz[out_i] - out_pixel * y; - for (int x = 0; x < pixel_width; x++) { - r[in_i] = xyz[in_i] + in_pixel * x; - data[pixel_width * y + x] = mesh->get_bin(r); - } - } - } - - return 0; -} - //! Get the dimension of a regular mesh extern "C" int openmc_regular_mesh_get_dimension( int32_t index, int** dims, int* n) @@ -2692,7 +1616,7 @@ extern "C" int openmc_regular_mesh_get_params( return err; RegularMesh* m = dynamic_cast(model::meshes[index].get()); - if (m->lower_left_.empty()) { + if (m->lower_left_.dimension() == 0) { set_errmsg("Mesh parameters have not been set."); return OPENMC_E_ALLOCATE; } @@ -2712,39 +1636,24 @@ extern "C" int openmc_regular_mesh_set_params( return err; RegularMesh* m = dynamic_cast(model::meshes[index].get()); - if (m->n_dimension_ == -1) { - set_errmsg("Need to set mesh dimension before setting parameters."); - return OPENMC_E_UNASSIGNED; - } - vector shape = {static_cast(n)}; if (ll && ur) { - m->lower_left_ = tensor::Tensor(ll, n); - m->upper_right_ = tensor::Tensor(ur, n); - m->width_ = (m->upper_right_ - m->lower_left_) / m->get_shape_tensor(); + m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape); + m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape); + m->width_ = (m->upper_right_ - m->lower_left_) / m->get_x_shape(); } else if (ll && width) { - m->lower_left_ = tensor::Tensor(ll, n); - m->width_ = tensor::Tensor(width, n); - m->upper_right_ = m->lower_left_ + m->get_shape_tensor() * m->width_; + m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape); + m->width_ = xt::adapt(width, n, xt::no_ownership(), shape); + m->upper_right_ = m->lower_left_ + m->get_x_shape() * m->width_; } else if (ur && width) { - m->upper_right_ = tensor::Tensor(ur, n); - m->width_ = tensor::Tensor(width, n); - m->lower_left_ = m->upper_right_ - m->get_shape_tensor() * m->width_; + m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape); + m->width_ = xt::adapt(width, n, xt::no_ownership(), shape); + m->lower_left_ = m->upper_right_ - m->get_x_shape() * m->width_; } else { set_errmsg("At least two parameters must be specified."); return OPENMC_E_INVALID_ARGUMENT; } - // Set material volumes - - // TODO: incorporate this into method in RegularMesh that can be called from - // here and from constructor - m->volume_frac_ = 1.0 / m->get_shape_tensor().prod(); - m->element_volume_ = 1.0; - for (int i = 0; i < m->n_dimension_; i++) { - m->element_volume_ *= m->width_[i]; - } - return 0; } @@ -2788,7 +1697,7 @@ int openmc_structured_mesh_get_grid_impl(int32_t index, double** grid_x, return err; C* m = dynamic_cast(model::meshes[index].get()); - if (m->lower_left_.empty()) { + if (m->lower_left_.dimension() == 0) { set_errmsg("Mesh parameters have not been set."); return OPENMC_E_ALLOCATE; } @@ -2856,7 +1765,7 @@ extern "C" int openmc_spherical_mesh_set_grid(int32_t index, index, grid_x, nx, grid_y, ny, grid_z, nz); } -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC const std::string MOABMesh::mesh_lib_type = "moab"; @@ -2865,15 +1774,8 @@ MOABMesh::MOABMesh(pugi::xml_node node) : UnstructuredMesh(node) initialize(); } -MOABMesh::MOABMesh(hid_t group) : UnstructuredMesh(group) -{ - initialize(); -} - MOABMesh::MOABMesh(const std::string& filename, double length_multiplier) - : UnstructuredMesh() { - n_dimension_ = 3; filename_ = filename; set_length_multiplier(length_multiplier); initialize(); @@ -2917,6 +1819,7 @@ void MOABMesh::initialize() fatal_error("Failed to get all vertex handles"); } + // make an entity set for all tetrahedra // this is used for convenience later in output rval = mbi_->create_meshset(moab::MESHSET_SET, tetset_); @@ -2929,7 +1832,7 @@ void MOABMesh::initialize() fatal_error("Failed to add tetrahedra to an entity set."); } - if (length_multiplier_ > 0.0) { + if (specified_length_multiplier_) { // get the connectivity of all tets moab::Range adj; rval = mbi_->get_adjacencies(ehs_, 0, true, adj, moab::Interface::UNION); @@ -2957,16 +1860,6 @@ void MOABMesh::initialize() } } - // Determine bounds of mesh - this->determine_bounds(); -} - -void MOABMesh::prepare_for_point_location() -{ - // if the KDTree has already been constructed, do nothing - if (kdtree_) - return; - // build acceleration data structures compute_barycentric_data(ehs_); build_kdtree(ehs_); @@ -2992,7 +1885,6 @@ void MOABMesh::build_kdtree(const moab::Range& all_tets) { moab::Range all_tris; int adj_dim = 2; - write_message("Getting tet adjacencies...", 7); moab::ErrorCode rval = mbi_->get_adjacencies( all_tets, adj_dim, true, all_tris, moab::Interface::UNION); if (rval != moab::MB_SUCCESS) { @@ -3011,21 +1903,10 @@ void MOABMesh::build_kdtree(const moab::Range& all_tets) all_tets_and_tris.merge(all_tris); // create a kd-tree instance - write_message( - 7, "Building adaptive k-d tree for tet mesh with ID {}...", id_); kdtree_ = make_unique(mbi_.get()); - // Determine what options to use - std::ostringstream options_stream; - if (options_.empty()) { - options_stream << "MAX_DEPTH=20;PLANE_SET=2;"; - } else { - options_stream << options_; - } - moab::FileOptions file_opts(options_stream.str().c_str()); - - // Build the k-d tree - rval = kdtree_->build_tree(all_tets_and_tris, &kdtree_root_, &file_opts); + // build the tree + rval = kdtree_->build_tree(all_tets_and_tris, &kdtree_root_); if (rval != moab::MB_SUCCESS) { fatal_error("Failed to construct KDTree for the " "unstructured mesh file: " + @@ -3041,8 +1922,7 @@ void MOABMesh::intersect_track(const moab::CartVect& start, moab::ErrorCode rval; vector tris; // get all intersections with triangles in the tet mesh - // (distances are relative to the start point, not the previous - // intersection) + // (distances are relative to the start point, not the previous intersection) rval = kdtree_->ray_intersect_triangles(kdtree_root_, FP_COINCIDENT, dir.array(), start.array(), tris, hits, 0, track_len); if (rval != moab::MB_SUCCESS) { @@ -3169,35 +2049,6 @@ std::string MOABMesh::library() const return mesh_lib_type; } -// Sample position within a tet for MOAB type tets -Position MOABMesh::sample_element(int32_t bin, uint64_t* seed) const -{ - - moab::EntityHandle tet_ent = get_ent_handle_from_bin(bin); - - // Get vertex coordinates for MOAB tet - const moab::EntityHandle* conn1; - int conn1_size; - moab::ErrorCode rval = mbi_->get_connectivity(tet_ent, conn1, conn1_size); - if (rval != moab::MB_SUCCESS || conn1_size != 4) { - fatal_error(fmt::format( - "Failed to get tet connectivity or connectivity size ({}) is invalid.", - conn1_size)); - } - moab::CartVect p[4]; - rval = mbi_->get_coords(conn1, conn1_size, p[0].array()); - if (rval != moab::MB_SUCCESS) { - fatal_error("Failed to get tet coords"); - } - - std::array tet_verts; - for (int i = 0; i < 4; i++) { - tet_verts[i] = {p[i][0], p[i][1], p[i][2]}; - } - // Samples position within tet using Barycentric stuff - return this->sample_tet(tet_verts, seed); -} - double MOABMesh::tet_volume(moab::EntityHandle tet) const { vector conn; @@ -3318,12 +2169,10 @@ std::pair, vector> MOABMesh::plot( return {}; } -int MOABMesh::get_vert_idx_from_handle(moab::EntityHandle vert) const -{ +int MOABMesh::get_vert_idx_from_handle(moab::EntityHandle vert) const { int idx = vert - verts_[0]; if (idx >= n_vertices()) { - fatal_error( - fmt::format("Invalid vertex idx {} (# vertices {})", idx, n_vertices())); + fatal_error(fmt::format("Invalid vertex idx {} (# vertices {})", idx, n_vertices())); } return idx; } @@ -3395,13 +2244,11 @@ Position MOABMesh::centroid(int bin) const return {centroid[0], centroid[1], centroid[2]}; } -int MOABMesh::n_vertices() const -{ +int MOABMesh::n_vertices() const { return verts_.size(); } -Position MOABMesh::vertex(int id) const -{ +Position MOABMesh::vertex(int id) const { moab::ErrorCode rval; @@ -3416,8 +2263,7 @@ Position MOABMesh::vertex(int id) const return {coords[0], coords[1], coords[2]}; } -std::vector MOABMesh::connectivity(int bin) const -{ +std::vector MOABMesh::connectivity(int bin) const { moab::ErrorCode rval; auto tet = get_ent_handle_from_bin(bin); @@ -3565,36 +2411,21 @@ void MOABMesh::write(const std::string& base_filename) const #endif -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH const std::string LibMesh::mesh_lib_type = "libmesh"; LibMesh::LibMesh(pugi::xml_node node) : UnstructuredMesh(node) { - // filename_ and length_multiplier_ will already be set by the - // UnstructuredMesh constructor - set_mesh_pointer_from_filename(filename_); - set_length_multiplier(length_multiplier_); - initialize(); -} - -LibMesh::LibMesh(hid_t group) : UnstructuredMesh(group) -{ - // filename_ and length_multiplier_ will already be set by the - // UnstructuredMesh constructor + // filename_ and length_multiplier_ will already be set by the UnstructuredMesh constructor set_mesh_pointer_from_filename(filename_); set_length_multiplier(length_multiplier_); initialize(); } // create the mesh from a pointer to a libMesh Mesh -LibMesh::LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier) +LibMesh::LibMesh(libMesh::MeshBase & input_mesh, double length_multiplier) { - if (!input_mesh.is_replicated()) { - fatal_error("At present LibMesh tallies require a replicated mesh. Please " - "ensure 'input_mesh' is a libMesh::ReplicatedMesh."); - } - m_ = &input_mesh; set_length_multiplier(length_multiplier); initialize(); @@ -3603,7 +2434,6 @@ LibMesh::LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier) // create the mesh from an input file LibMesh::LibMesh(const std::string& filename, double length_multiplier) { - n_dimension_ = 3; set_mesh_pointer_from_filename(filename); set_length_multiplier(length_multiplier); initialize(); @@ -3612,32 +2442,25 @@ LibMesh::LibMesh(const std::string& filename, double length_multiplier) void LibMesh::set_mesh_pointer_from_filename(const std::string& filename) { filename_ = filename; - unique_m_ = - make_unique(*settings::libmesh_comm, n_dimension_); + unique_m_ = make_unique(*settings::libmesh_comm, n_dimension_); m_ = unique_m_.get(); m_->read(filename_); } -// build a libMesh equation system for storing values -void LibMesh::build_eqn_sys() -{ - eq_system_name_ = fmt::format("mesh_{}_system", id_); - equation_systems_ = make_unique(*m_); - libMesh::ExplicitSystem& eq_sys = - equation_systems_->add_system(eq_system_name_); -} - // intialize from mesh file void LibMesh::initialize() { if (!settings::libmesh_comm) { - fatal_error("Attempting to use an unstructured mesh without a libMesh " - "communicator."); + fatal_error( + "Attempting to use an unstructured mesh without a libMesh communicator."); } // assuming that unstructured meshes used in OpenMC are 3D n_dimension_ = 3; + if (specified_length_multiplier_) { + libMesh::MeshTools::Modification::scale(*m_, length_multiplier_); + } // if OpenMC is managing the libMesh::MeshBase instance, prepare the mesh. // Otherwise assume that it is prepared by its owning application if (unique_m_) { @@ -3651,7 +2474,20 @@ void LibMesh::initialize() filename_)); } - for (int i = 0; i < num_threads(); i++) { + // create an equation system for storing values + eq_system_name_ = fmt::format("mesh_{}_system", id_); + + equation_systems_ = make_unique(*m_); + libMesh::ExplicitSystem& eq_sys = + equation_systems_->add_system(eq_system_name_); + +#ifdef _OPENMP + int n_threads = omp_get_max_threads(); +#else + int n_threads = 1; +#endif + + for (int i = 0; i < n_threads; i++) { pl_.emplace_back(m_->sub_point_locator()); pl_.back()->set_contains_point_tol(FP_COINCIDENT); pl_.back()->enable_out_of_mesh_mode(); @@ -3663,47 +2499,13 @@ void LibMesh::initialize() // bounding box for the mesh for quick rejection checks bbox_ = libMesh::MeshTools::create_bounding_box(*m_); - libMesh::Point ll = bbox_.min(); - libMesh::Point ur = bbox_.max(); - if (length_multiplier_ > 0.0) { - lower_left_ = {length_multiplier_ * ll(0), length_multiplier_ * ll(1), - length_multiplier_ * ll(2)}; - upper_right_ = {length_multiplier_ * ur(0), length_multiplier_ * ur(1), - length_multiplier_ * ur(2)}; - } else { - lower_left_ = {ll(0), ll(1), ll(2)}; - upper_right_ = {ur(0), ur(1), ur(2)}; - } -} - -// Sample position within a tet for LibMesh type tets -Position LibMesh::sample_element(int32_t bin, uint64_t* seed) const -{ - const auto& elem = get_element_from_bin(bin); - // Get tet vertex coordinates from LibMesh - std::array tet_verts; - for (int i = 0; i < elem.n_nodes(); i++) { - const auto& node_ref = elem.node_ref(i); - tet_verts[i] = {node_ref(0), node_ref(1), node_ref(2)}; - } - // Samples position within tet using Barycentric coordinates - Position sampled_position = this->sample_tet(tet_verts, seed); - if (length_multiplier_ > 0.0) { - return length_multiplier_ * sampled_position; - } else { - return sampled_position; - } } Position LibMesh::centroid(int bin) const { const auto& elem = this->get_element_from_bin(bin); - auto centroid = elem.vertex_average(); - if (length_multiplier_ > 0.0) { - return length_multiplier_ * Position(centroid(0), centroid(1), centroid(2)); - } else { - return {centroid(0), centroid(1), centroid(2)}; - } + auto centroid = elem.centroid(); + return {centroid(0), centroid(1), centroid(2)}; } int LibMesh::n_vertices() const @@ -3713,12 +2515,8 @@ int LibMesh::n_vertices() const Position LibMesh::vertex(int vertex_id) const { - const auto& node_ref = m_->node_ref(vertex_id); - if (length_multiplier_ > 0.0) { - return length_multiplier_ * Position(node_ref(0), node_ref(1), node_ref(2)); - } else { - return {node_ref(0), node_ref(1), node_ref(2)}; - } + const auto node_ref = m_->node_ref(vertex_id); + return {node_ref(0), node_ref(1), node_ref(2)}; } std::vector LibMesh::connectivity(int elem_id) const @@ -3761,10 +2559,6 @@ int LibMesh::n_surface_bins() const void LibMesh::add_score(const std::string& var_name) { - if (!equation_systems_) { - build_eqn_sys(); - } - // check if this is a new variable std::string value_name = var_name + "_mean"; if (!variable_map_.count(value_name)) { @@ -3786,20 +2580,14 @@ void LibMesh::add_score(const std::string& var_name) void LibMesh::remove_scores() { - if (equation_systems_) { - auto& eqn_sys = equation_systems_->get_system(eq_system_name_); - eqn_sys.clear(); - variable_map_.clear(); - } + auto& eqn_sys = equation_systems_->get_system(eq_system_name_); + eqn_sys.clear(); + variable_map_.clear(); } void LibMesh::set_score_data(const std::string& var_name, const vector& values, const vector& std_dev) { - if (!equation_systems_) { - build_eqn_sys(); - } - auto& eqn_sys = equation_systems_->get_system(eq_system_name_); if (!eqn_sys.is_initialized()) { @@ -3817,22 +2605,18 @@ void LibMesh::set_score_data(const std::string& var_name, for (auto it = m_->local_elements_begin(); it != m_->local_elements_end(); it++) { - if (!(*it)->active()) { - continue; - } - auto bin = get_bin_from_element(*it); // set value vector value_dof_indices; dof_map.dof_indices(*it, value_dof_indices, value_num); - assert(value_dof_indices.size() == 1); + Ensures(value_dof_indices.size() == 1); eqn_sys.solution->set(value_dof_indices[0], values.at(bin)); // set std dev vector std_dev_dof_indices; dof_map.dof_indices(*it, std_dev_dof_indices, std_dev_num); - assert(std_dev_dof_indices.size() == 1); + Ensures(std_dev_dof_indices.size() == 1); eqn_sys.solution->set(std_dev_dof_indices[0], std_dev.at(bin)); } } @@ -3859,17 +2643,18 @@ int LibMesh::get_bin(Position r) const // look-up a tet using the point locator libMesh::Point p(r.x, r.y, r.z); - if (length_multiplier_ > 0.0) { - // Scale the point down - p /= length_multiplier_; - } - // quick rejection check if (!bbox_.contains_point(p)) { return -1; } - const auto& point_locator = pl_.at(thread_num()); +#ifdef _OPENMP + int thread_num = omp_get_thread_num(); +#else + int thread_num = 0; +#endif + + const auto& point_locator = pl_.at(thread_num); const auto elem_ptr = (*point_locator)(p); return elem_ptr ? get_bin_from_element(elem_ptr) : -1; @@ -3897,100 +2682,10 @@ const libMesh::Elem& LibMesh::get_element_from_bin(int bin) const double LibMesh::volume(int bin) const { - return this->get_element_from_bin(bin).volume() * length_multiplier_ * - length_multiplier_ * length_multiplier_; + return m_->elem_ref(bin).volume(); } -AdaptiveLibMesh::AdaptiveLibMesh(libMesh::MeshBase& input_mesh, - double length_multiplier, - const std::set& block_ids) - : LibMesh(input_mesh, length_multiplier), block_ids_(block_ids), - block_restrict_(!block_ids_.empty()), - num_active_( - block_restrict_ - ? std::distance(m_->active_subdomain_set_elements_begin(block_ids_), - m_->active_subdomain_set_elements_end(block_ids_)) - : m_->n_active_elem()) -{ - // if the mesh is adaptive elements aren't guaranteed by libMesh to be - // contiguous in ID space, so we need to map from bin indices (defined over - // active elements) to global dof ids - bin_to_elem_map_.reserve(num_active_); - elem_to_bin_map_.resize(m_->n_elem(), -1); - auto begin = block_restrict_ - ? m_->active_subdomain_set_elements_begin(block_ids_) - : m_->active_elements_begin(); - auto end = block_restrict_ ? m_->active_subdomain_set_elements_end(block_ids_) - : m_->active_elements_end(); - for (const auto& elem : libMesh::as_range(begin, end)) { - bin_to_elem_map_.push_back(elem->id()); - elem_to_bin_map_[elem->id()] = bin_to_elem_map_.size() - 1; - } -} - -int AdaptiveLibMesh::n_bins() const -{ - return num_active_; -} - -void AdaptiveLibMesh::add_score(const std::string& var_name) -{ - warning(fmt::format( - "Exodus output cannot be provided as unstructured mesh {} is adaptive.", - this->id_)); -} - -void AdaptiveLibMesh::set_score_data(const std::string& var_name, - const vector& values, const vector& std_dev) -{ - warning(fmt::format( - "Exodus output cannot be provided as unstructured mesh {} is adaptive.", - this->id_)); -} - -void AdaptiveLibMesh::write(const std::string& filename) const -{ - warning(fmt::format( - "Exodus output cannot be provided as unstructured mesh {} is adaptive.", - this->id_)); -} - -int AdaptiveLibMesh::get_bin(Position r) const -{ - // look-up a tet using the point locator - libMesh::Point p(r.x, r.y, r.z); - - if (length_multiplier_ > 0.0) { - // Scale the point down - p /= length_multiplier_; - } - - // quick rejection check - if (!bbox_.contains_point(p)) { - return -1; - } - - const auto& point_locator = pl_.at(thread_num()); - - const auto elem_ptr = (*point_locator)(p, &block_ids_); - return elem_ptr ? get_bin_from_element(elem_ptr) : -1; -} - -int AdaptiveLibMesh::get_bin_from_element(const libMesh::Elem* elem) const -{ - int bin = elem_to_bin_map_[elem->id()]; - if (bin >= n_bins() || bin < 0) { - fatal_error(fmt::format("Invalid bin: {}", bin)); - } - return bin; -} - -const libMesh::Elem& AdaptiveLibMesh::get_element_from_bin(int bin) const -{ - return m_->elem_ref(bin_to_elem_map_.at(bin)); -} - -#endif // OPENMC_LIBMESH_ENABLED +#endif // LIBMESH //============================================================================== // Non-member functions @@ -4004,8 +2699,8 @@ void read_meshes(pugi::xml_node root) // Check to make sure multiple meshes in the same file don't share IDs int id = std::stoi(get_node_value(node, "id")); if (contains(mesh_ids, id)) { - fatal_error(fmt::format("Two or more meshes use the same unique ID " - "'{}' in the same input file", + fatal_error(fmt::format( + "Two or more meshes use the same unique ID '{}' in the same input file", id)); } mesh_ids.insert(id); @@ -4030,51 +2725,34 @@ void read_meshes(pugi::xml_node root) mesh_lib = get_node_value(node, "library", true, true); } - Mesh::create(node, mesh_type, mesh_lib); - } -} - -void read_meshes(hid_t group) -{ - std::unordered_set mesh_ids; - - std::vector ids; - read_attribute(group, "ids", ids); - - for (auto id : ids) { - - // Check to make sure multiple meshes in the same file don't share IDs - if (contains(mesh_ids, id)) { - fatal_error(fmt::format("Two or more meshes use the same unique ID " - "'{}' in the same HDF5 input file", - id)); - } - mesh_ids.insert(id); - - // If we've already read a mesh with the same ID in a *different* file, - // assume it is the same here - if (model::mesh_map.find(id) != model::mesh_map.end()) { - warning(fmt::format("Mesh with ID={} appears in multiple files.", id)); - continue; - } - - std::string name = fmt::format("mesh {}", id); - hid_t mesh_group = open_group(group, name.c_str()); - - std::string mesh_type; - if (object_exists(mesh_group, "type")) { - read_dataset(mesh_group, "type", mesh_type); + // Read mesh and add to vector + if (mesh_type == RegularMesh::mesh_type) { + model::meshes.push_back(make_unique(node)); + } else if (mesh_type == RectilinearMesh::mesh_type) { + model::meshes.push_back(make_unique(node)); + } else if (mesh_type == CylindricalMesh::mesh_type) { + model::meshes.push_back(make_unique(node)); + } else if (mesh_type == SphericalMesh::mesh_type) { + model::meshes.push_back(make_unique(node)); +#ifdef DAGMC + } else if (mesh_type == UnstructuredMesh::mesh_type && + mesh_lib == MOABMesh::mesh_lib_type) { + model::meshes.push_back(make_unique(node)); +#endif +#ifdef LIBMESH + } else if (mesh_type == UnstructuredMesh::mesh_type && + mesh_lib == LibMesh::mesh_lib_type) { + model::meshes.push_back(make_unique(node)); +#endif + } else if (mesh_type == UnstructuredMesh::mesh_type) { + fatal_error("Unstructured mesh support is not enabled or the mesh " + "library is invalid."); } else { - mesh_type = "regular"; + fatal_error("Invalid mesh type: " + mesh_type); } - // determine the mesh library to use - std::string mesh_lib; - if (object_exists(mesh_group, "library")) { - read_dataset(mesh_group, "library", mesh_lib); - } - - Mesh::create(mesh_group, mesh_type, mesh_lib); + // Map ID to position in vector + model::mesh_map[model::meshes.back()->id_] = model::meshes.size() - 1; } } diff --git a/src/message_passing.cpp b/src/message_passing.cpp index cf6113ed6..f87782083 100644 --- a/src/message_passing.cpp +++ b/src/message_passing.cpp @@ -10,7 +10,6 @@ bool master {true}; #ifdef OPENMC_MPI MPI_Comm intracomm {MPI_COMM_NULL}; MPI_Datatype source_site {MPI_DATATYPE_NULL}; -MPI_Datatype collision_track_site {MPI_DATATYPE_NULL}; #endif extern "C" bool openmc_master() @@ -18,35 +17,6 @@ extern "C" bool openmc_master() return mpi::master; } -vector calculate_parallel_index_vector(int64_t size) -{ - vector result; - result.resize(n_procs + 1); - result[0] = 0; - -#ifdef OPENMC_MPI - - // Populate the result with cumulative sum of the number of - // surface source banks per process - int64_t scan_total; - MPI_Scan(&size, &scan_total, 1, MPI_INT64_T, MPI_SUM, intracomm); - MPI_Allgather( - &scan_total, 1, MPI_INT64_T, result.data() + 1, 1, MPI_INT64_T, intracomm); -#else - result[1] = size; -#endif - - return result; -} - -#ifdef OPENMC_MPI -// Specializations of the MPITypeMap template struct -template<> -const MPI_Datatype MPITypeMap::mpi_type = MPI_INT; -template<> -const MPI_Datatype MPITypeMap::mpi_type = MPI_DOUBLE; -#endif - } // namespace mpi } // namespace openmc diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 1dc090ab9..472beda35 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -5,13 +5,19 @@ #include #include -#include "openmc/tensor.h" +#ifdef _OPENMP +#include +#endif + +#include "xtensor/xadapt.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xview.hpp" #include #include "openmc/error.h" #include "openmc/math_functions.h" #include "openmc/mgxs_interface.h" -#include "openmc/nuclide.h" #include "openmc/random_lcg.h" #include "openmc/settings.h" #include "openmc/string_utils.h" @@ -30,7 +36,8 @@ void Mgxs::init(const std::string& in_name, double in_awr, // Set the metadata name = in_name; awr = in_awr; - kTs = tensor::Tensor(in_kTs.data(), in_kTs.size()); + // TODO: Remove adapt when in_KTs is an xtensor + kTs = xt::adapt(in_kTs); fissionable = in_fissionable; scatter_format = in_scatter_format; xs.resize(in_kTs.size()); @@ -39,6 +46,15 @@ void Mgxs::init(const std::string& in_name, double in_awr, n_azi = in_azimuthal.size(); polar = in_polar; azimuthal = in_azimuthal; + + // Set the cross section index cache +#ifdef _OPENMP + int n_threads = omp_get_max_threads(); +#else + int n_threads = 1; +#endif + cache.resize(n_threads); + // vector.resize() will value-initialize the members of cache[:] } //============================================================================== @@ -69,25 +85,18 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, } get_datasets(kT_group, dset_names); vector shape = {num_temps}; - tensor::Tensor temps_available(shape); + xt::xarray available_temps(shape); for (int i = 0; i < num_temps; i++) { - read_double(kT_group, dset_names[i], &temps_available[i], true); + read_double(kT_group, dset_names[i], &available_temps[i], true); // convert eV to Kelvin - temps_available[i] = std::round(temps_available[i] / K_BOLTZMANN); + available_temps[i] /= K_BOLTZMANN; // Done with dset_names, so delete it delete[] dset_names[i]; } delete[] dset_names; - std::sort(temps_available.begin(), temps_available.end()); - - // Set the global upper and lower interpolation bounds to avoid errors - // involving C-API functions. - data::temperature_min = - std::min(data::temperature_min, temps_available.front()); - data::temperature_max = - std::max(data::temperature_max, temps_available.back()); + std::sort(available_temps.begin(), available_temps.end()); // If only one temperature is available, lets just use nearest temperature // interpolation @@ -103,22 +112,17 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, case TemperatureMethod::NEAREST: // Determine actual temperatures to read for (const auto& T : temperature) { - // Determine the closest temperature value - auto i_closest = tensor::abs(temps_available - T).argmin(); - - double temp_actual = temps_available[i_closest]; + auto i_closest = xt::argmin(xt::abs(available_temps - T))[0]; + double temp_actual = available_temps[i_closest]; if (std::fabs(temp_actual - T) < settings::temperature_tolerance) { if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) == temps_to_read.end()) { temps_to_read.push_back(std::round(temp_actual)); } } else { - fatal_error(fmt::format( - "MGXS library does not contain cross sections " - "for {} at or near {} K. Available temperatures " - "are {} K. Consider making use of openmc.Settings.temperature " - "to specify how intermediate temperatures are treated.", - in_name, std::round(T), concatenate(temps_available))); + fatal_error(fmt::format("MGXS library does not contain cross sections " + "for {} at or near {} K.", + in_name, std::round(T))); } } break; @@ -131,16 +135,16 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, in_name + " at temperatures that bound " + std::to_string(std::round(temperature[i]))); } - if ((temps_available[j] <= temperature[i]) && - (temperature[i] < temps_available[j + 1])) { + if ((available_temps[j] <= temperature[i]) && + (temperature[i] < available_temps[j + 1])) { if (std::find(temps_to_read.begin(), temps_to_read.end(), - temps_available[j]) == temps_to_read.end()) { - temps_to_read.push_back(temps_available[j]); + std::round(available_temps[j])) == temps_to_read.end()) { + temps_to_read.push_back(std::round((int)available_temps[j])); } if (std::find(temps_to_read.begin(), temps_to_read.end(), - temps_available[j + 1]) == temps_to_read.end()) { - temps_to_read.push_back(temps_available[j + 1]); + std::round(available_temps[j + 1])) == temps_to_read.end()) { + temps_to_read.push_back(std::round((int)available_temps[j + 1])); } break; } @@ -339,7 +343,7 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, for (int m = 0; m < micros.size(); m++) { switch (settings::temperature_method) { case TemperatureMethod::NEAREST: { - micro_t[m] = tensor::abs(micros[m]->kTs - temp_desired).argmin(); + micro_t[m] = xt::argmin(xt::abs(micros[m]->kTs - temp_desired))[0]; auto temp_actual = micros[m]->kTs[micro_t[m]]; if (std::abs(temp_actual - temp_desired) >= @@ -352,7 +356,7 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, case TemperatureMethod::INTERPOLATION: // Get a list of bounding temperatures for each actual temperature // present in the model - for (int k = 0; k < micros[m]->kTs.shape(0) - 1; k++) { + for (int k = 0; k < micros[m]->kTs.shape()[0] - 1; k++) { if ((micros[m]->kTs[k] <= temp_desired) && (temp_desired < micros[m]->kTs[k + 1])) { micro_t[m] = k; @@ -365,7 +369,7 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, } } } // end switch - } // end microscopic temperature loop + } // end microscopic temperature loop // Now combine the microscopic data at each relevant temperature // We will do this by treating the multiple temperatures of a nuclide as @@ -421,10 +425,18 @@ void Mgxs::combine(const vector& micros, const vector& scalars, //============================================================================== -double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, - const int* dg, int t, int a) +double Mgxs::get_xs( + MgxsType xstype, int gin, const int* gout, const double* mu, const int* dg) { - XsData* xs_t = &xs[t]; + // This method assumes that the temperature and angle indices are set +#ifdef _OPENMP + int tid = omp_get_thread_num(); + XsData* xs_t = &xs[cache[tid].t]; + int a = cache[tid].a; +#else + XsData* xs_t = &xs[cache[0].t]; + int a = cache[0].a; +#endif double val; switch (xstype) { case MgxsType::TOTAL: @@ -458,7 +470,7 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, val = xs_t->delayed_nu_fission(a, *dg, gin); } else { val = 0.; - for (int d = 0; d < xs_t->delayed_nu_fission.shape(1); d++) { + for (int d = 0; d < xs_t->delayed_nu_fission.shape()[1]; d++) { val += xs_t->delayed_nu_fission(a, d, gin); } } @@ -473,7 +485,7 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, } else { // provide an outgoing group-wise sum val = 0.; - for (int g = 0; g < xs_t->chi_prompt.shape(2); g++) { + for (int g = 0; g < xs_t->chi_prompt.shape()[2]; g++) { val += xs_t->chi_prompt(a, gin, g); } } @@ -492,13 +504,13 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, } else { if (dg != nullptr) { val = 0.; - for (int g = 0; g < xs_t->delayed_nu_fission.shape(2); g++) { + for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { val += xs_t->delayed_nu_fission(a, *dg, gin, g); } } else { val = 0.; - for (int g = 0; g < xs_t->delayed_nu_fission.shape(2); g++) { - for (int d = 0; d < xs_t->delayed_nu_fission.shape(3); d++) { + for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { + for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) { val += xs_t->delayed_nu_fission(a, d, gin, g); } } @@ -510,8 +522,6 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, break; case MgxsType::INVERSE_VELOCITY: val = xs_t->inverse_velocity(a, gin); - if (!(val > 0)) - val = data::mg.default_inverse_velocity_[gin]; break; case MgxsType::DECAY_RATE: if (dg != nullptr) { @@ -528,14 +538,19 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, //============================================================================== -void Mgxs::sample_fission_energy( - int gin, int& dg, int& gout, uint64_t* seed, int t, int a) +void Mgxs::sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed) { - XsData* xs_t = &xs[t]; - double nu_fission = xs_t->nu_fission(a, gin); + // This method assumes that the temperature and angle indices are set +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + XsData* xs_t = &xs[cache[tid].t]; + double nu_fission = xs_t->nu_fission(cache[tid].a, gin); // Find the probability of having a prompt neutron - double prob_prompt = xs_t->prompt_nu_fission(a, gin); + double prob_prompt = xs_t->prompt_nu_fission(cache[tid].a, gin); // sample random numbers double xi_pd = prn(seed) * nu_fission; @@ -551,7 +566,7 @@ void Mgxs::sample_fission_energy( // sample the outgoing energy group double prob_gout = 0.; for (gout = 0; gout < num_groups; ++gout) { - prob_gout += xs_t->chi_prompt(a, gin, gout); + prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout); if (xi_gout < prob_gout) break; } @@ -561,7 +576,7 @@ void Mgxs::sample_fission_energy( // get the delayed group for (dg = 0; dg < num_delayed_groups; ++dg) { - prob_prompt += xs_t->delayed_nu_fission(a, dg, gin); + prob_prompt += xs_t->delayed_nu_fission(cache[tid].a, dg, gin); if (xi_pd < prob_prompt) break; } @@ -572,7 +587,7 @@ void Mgxs::sample_fission_energy( // sample the outgoing energy group double prob_gout = 0.; for (gout = 0; gout < num_groups; ++gout) { - prob_gout += xs_t->chi_delayed(a, dg, gin, gout); + prob_gout += xs_t->chi_delayed(cache[tid].a, dg, gin, gout); if (xi_gout < prob_gout) break; } @@ -582,41 +597,35 @@ void Mgxs::sample_fission_energy( //============================================================================== void Mgxs::sample_scatter( - int gin, int& gout, double& mu, double& wgt, uint64_t* seed, int t, int a) + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) { + // This method assumes that the temperature and angle indices are set // Sample the data - xs[t].scatter[a]->sample(gin, gout, mu, wgt, seed); +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + xs[cache[tid].t].scatter[cache[tid].a]->sample(gin, gout, mu, wgt, seed); } //============================================================================== void Mgxs::calculate_xs(Particle& p) { - // If the material is different, then we need to do a full lookup - if (p.material() != p.mg_xs_cache().material) { - set_temperature_index(p); - set_angle_index(p); - p.mg_xs_cache().material = p.material(); - } else { - // If material is the same, but temperature is different, need to - // find the new temperature index - if (p.sqrtkT() != p.mg_xs_cache().sqrtkT) { - set_temperature_index(p); - } - // If the material is the same, but angle is different, need to - // find the new angle index - if (p.u_local() != p.mg_xs_cache().u) { - set_angle_index(p); - } - } - int temperature = p.mg_xs_cache().t; - int angle = p.mg_xs_cache().a; - p.macro_xs().total = xs[temperature].total(angle, p.g()) * p.density_mult(); - p.macro_xs().absorption = - xs[temperature].absorption(angle, p.g()) * p.density_mult(); + // Set our indices +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + set_temperature_index(p.sqrtkT()); + set_angle_index(p.u_local()); + XsData* xs_t = &xs[cache[tid].t]; + p.macro_xs().total = xs_t->total(cache[tid].a, p.g()); + p.macro_xs().absorption = xs_t->absorption(cache[tid].a, p.g()); p.macro_xs().nu_fission = - fissionable ? xs[temperature].nu_fission(angle, p.g()) * p.density_mult() - : 0.; + fissionable ? xs_t->nu_fission(cache[tid].a, p.g()) : 0.; } //============================================================================== @@ -634,26 +643,32 @@ bool Mgxs::equiv(const Mgxs& that) //============================================================================== -int Mgxs::get_temperature_index(double sqrtkT) const +void Mgxs::set_temperature_index(double sqrtkT) { - return tensor::abs(kTs - sqrtkT * sqrtkT).argmin(); + // See if we need to find the new index +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + if (sqrtkT != cache[tid].sqrtkT) { + cache[tid].t = xt::argmin(xt::abs(kTs - sqrtkT * sqrtkT))[0]; + cache[tid].sqrtkT = sqrtkT; + } } //============================================================================== -void Mgxs::set_temperature_index(Particle& p) +void Mgxs::set_angle_index(Direction u) { - p.mg_xs_cache().t = get_temperature_index(p.sqrtkT()); - p.mg_xs_cache().sqrtkT = p.sqrtkT(); -} - -//============================================================================== - -int Mgxs::get_angle_index(const Direction& u) const -{ - if (is_isotropic) { - return 0; - } else { + // See if we need to find the new index +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + if (!is_isotropic && ((u.x != cache[tid].u) || (u.y != cache[tid].v) || + (u.z != cache[tid].w))) { // convert direction to polar and azimuthal angles double my_pol = std::acos(u.z); double my_azi = std::atan2(u.y, u.x); @@ -664,18 +679,12 @@ int Mgxs::get_angle_index(const Direction& u) const delta_angle = 2. * PI / n_azi; int a = std::floor((my_azi + PI) / delta_angle); - return n_azi * p + a; - } -} + cache[tid].a = n_azi * p + a; -//============================================================================== - -void Mgxs::set_angle_index(Particle& p) -{ - // See if we need to find the new index - if (!is_isotropic) { - p.mg_xs_cache().a = get_angle_index(p.u_local()); - p.mg_xs_cache().u = p.u_local(); + // store this direction as the last one used + cache[tid].u = u.x; + cache[tid].v = u.y; + cache[tid].w = u.z; } } diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 865c56580..77085d57c 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -15,7 +15,6 @@ #include "openmc/material.h" #include "openmc/math_functions.h" #include "openmc/nuclide.h" -#include "openmc/search.h" #include "openmc/settings.h" namespace openmc { @@ -146,7 +145,7 @@ void MgxsInterface::create_macro_xs() num_energy_groups_, num_delayed_groups_); } else { // Preserve the ordering of materials by including a blank entry - macro_xs_.emplace_back(false); + macro_xs_.emplace_back(); } } } @@ -169,13 +168,13 @@ vector> MgxsInterface::get_mat_kTs() continue; // Get temperature of cell (rounding to nearest integer) - for (int k = 0; k < cell->sqrtkT_.size(); ++k) { - double kT = cell->sqrtkT_[k] * cell->sqrtkT_[k]; + double sqrtkT = + cell->sqrtkT_.size() == 1 ? cell->sqrtkT_[j] : cell->sqrtkT_[0]; + double kT = sqrtkT * sqrtkT; - // Add temperature if it hasn't already been added - if (!contains(kTs[i_material], kT)) { - kTs[i_material].push_back(kT); - } + // Add temperature if it hasn't already been added + if (!contains(kTs[i_material], kT)) { + kTs[i_material].push_back(kT); } } } @@ -184,15 +183,6 @@ vector> MgxsInterface::get_mat_kTs() //============================================================================== -int MgxsInterface::get_group_index(double E) -{ - int g = - lower_bound_index(rev_energy_bins_.begin(), rev_energy_bins_.end(), E); - return num_energy_groups_ - g - 1.; -} - -//============================================================================== - void MgxsInterface::read_header(const std::string& path_cross_sections) { // Save name of HDF5 file to be read to struct data @@ -237,19 +227,6 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) "library file!"); } - // Calculate approximate default inverse velocity data - for (int i = 0; i < energy_bins_.size() - 1; ++i) { - double e_min = std::max(energy_bins_[i + 1], 1e-5); - double e_max = energy_bins_[i]; - double alpha = 1.0 / (C_LIGHT * std::log(e_max / e_min)); - double k_max = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_max); - double k_min = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_min); - double inv_v = - alpha * (2.0 * (std::atanh(1.0 / k_max) - std::atanh(1.0 / k_min)) - - (k_max - k_min)); - default_inverse_velocity_.push_back(inv_v); - } - // Close MGXS HDF5 file file_close(file_id); } @@ -257,7 +234,7 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) void put_mgxs_header_data_to_globals() { // Get the minimum and maximum energies - int neutron = ParticleType::neutron().transport_index(); + int neutron = static_cast(ParticleType::neutron); data::energy_min[neutron] = data::mg.energy_bins_.back(); data::energy_max[neutron] = data::mg.energy_bins_.front(); @@ -307,7 +284,7 @@ void mark_fissionable_mgxs_materials() for (const auto& mat : model::materials) { for (int i_nuc : mat->nuclide_) { if (data::mg.nuclides_[i_nuc].fissionable) { - mat->fissionable() = true; + mat->fissionable_ = true; } } } diff --git a/src/ncrystal_interface.cpp b/src/ncrystal_interface.cpp deleted file mode 100644 index 935d2b885..000000000 --- a/src/ncrystal_interface.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "openmc/ncrystal_interface.h" - -#include "openmc/error.h" -#include "openmc/material.h" -#include "openmc/random_lcg.h" - -namespace openmc { - -//============================================================================== -// NCrystalMat implementation -//============================================================================== - -NCrystalMat::NCrystalMat(const std::string& cfg) : cfg_(cfg), proc_(cfg.c_str()) -{} - -double NCrystalMat::xs(const Particle& p) const -{ - // Calculate scattering XS per atom with NCrystal, only once per material - double neutron_state[4] = {p.E(), p.u().x, p.u().y, p.u().z}; - return proc_.cross_section(neutron_state); -} - -void NCrystalMat::scatter(Particle& p) const -{ - // Scatter with NCrystal, using the OpenMC RNG stream: - uint64_t* seed = p.current_seed(); - std::function rng = [&seed]() { return prn(seed); }; - double neutron_state[4] = {p.E(), p.u().x, p.u().y, p.u().z}; - proc_.scatter(rng, neutron_state); - // Modify attributes of particle - p.E() = neutron_state[0]; - Direction u_old {p.u()}; - p.u() = Direction(neutron_state[1], neutron_state[2], neutron_state[3]); - p.mu() = u_old.dot(p.u()); - p.event_mt() = ELASTIC; -} - -//============================================================================== -// Functions -//============================================================================== - -void ncrystal_update_micro(double xs, NuclideMicroXS& micro) -{ - if (micro.thermal > 0 || micro.thermal_elastic > 0) { - fatal_error("S(a,b) treatment and NCrystal are not compatible."); - } - // remove free atom cross section - // and replace it by scattering cross section per atom from NCrystal - micro.total = micro.total - micro.elastic + xs; - micro.elastic = xs; -} - -} // namespace openmc diff --git a/src/ncrystal_load.cpp b/src/ncrystal_load.cpp deleted file mode 100644 index b69f3a27f..000000000 --- a/src/ncrystal_load.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "openmc/ncrystal_load.h" - -#include // for isspace -#include // for strtoul -#include // for shared_ptr -#include // for mutex, lock_guard -#include - -#include -#include // for popen, pclose - -#include "openmc/error.h" - -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include // for LoadLibrary, GetProcAddress -#else -#include // for dlopen, dlsym, dlerror -#endif - -namespace openmc { -namespace { - -struct NCrystalConfig { - std::string shlibpath; - unsigned long intversion = 0; - std::string symbol_namespace; -}; - -NCrystalConfig query_ncrystal_config() -{ -#ifdef _WIN32 - FILE* pipe = _popen("ncrystal-config --show " - "intversion shlibpath namespace", - "r"); -#else - FILE* pipe = popen("ncrystal-config --show " - "intversion shlibpath namespace 2>/dev/null", - "r"); -#endif - if (!pipe) - return {}; // failure - auto readLine = [pipe](std::string& tgt) -> bool { - // Read line and discard trailing whitespace (including newline chars). - char buffer[4096]; - if (fgets(buffer, sizeof(buffer), pipe) == NULL) - return false; - tgt = buffer; - while (!tgt.empty() && std::isspace(tgt.back())) - tgt.pop_back(); - return true; - }; - auto parseIntVersion = [](const std::string& s) { - char* str_end = nullptr; - unsigned long v = std::strtoul(s.c_str(), &str_end, 10); - return (v >= 2002000 && v < 999999999 && str_end == s.c_str() + s.size()) - ? v - : 0; - }; - - NCrystalConfig res; - if (!readLine(res.shlibpath) || - !(res.intversion = parseIntVersion(res.shlibpath)) || - !readLine(res.shlibpath) || res.shlibpath.empty() || - !readLine(res.symbol_namespace)) { - res.intversion = 0; // failure - } - -#ifdef _WIN32 - auto returnCode = _pclose(pipe); -#else - auto returnCode = pclose(pipe); -#endif - if (returnCode == 0 && res.intversion >= 2002000) - return res; - return {}; // failure -} - -struct NCrystalAPIDB { - std::mutex mtx; - std::shared_ptr api; - using FctSignature = void* (*)(int); - FctSignature ncrystal_access_virtapi_fct = nullptr; -}; - -void* load_virtapi_raw(unsigned interface_id, NCrystalAPIDB& db) -{ - if (!db.ncrystal_access_virtapi_fct) { - auto cfg = query_ncrystal_config(); - if (!(cfg.intversion >= 4001000)) { - // This is the most likely error message people will see: - fatal_error("Could not locate a functioning and recent enough" - " NCrystal installation (required since geometry" - " contains NCrystal materials)."); - } -#ifdef _WIN32 - auto handle = LoadLibrary(cfg.shlibpath.c_str()); -#else - dlerror(); // clear previous errors - void* handle = dlopen(cfg.shlibpath.c_str(), RTLD_LOCAL | RTLD_LAZY); -#endif - if (!handle) - fatal_error("Loading of the NCrystal library failed"); - - std::string symbol = - fmt::format("ncrystal{}_access_virtual_api", cfg.symbol_namespace); - -#ifdef _WIN32 - void* addr = (void*)(intptr_t)GetProcAddress(handle, symbol.c_str()); - if (!addr) - fatal_error("GetProcAddress(" - "ncrystal_access_virtual_api) failed"); -#else - dlerror(); // clear previous errors - void* addr = dlsym(handle, symbol.c_str()); - if (!addr) - fatal_error("dlsym(ncrystal_access_virtual_api) failed"); -#endif - db.ncrystal_access_virtapi_fct = - reinterpret_cast(addr); - } - - void* result = (*db.ncrystal_access_virtapi_fct)(interface_id); - if (!result) - fatal_error("NCrystal installation does not support required interface."); - - return result; -} - -NCrystalAPIDB& get_ncrystal_api_db() -{ - static NCrystalAPIDB db; - return db; -} -} // namespace - -std::shared_ptr load_ncrystal_api() -{ - auto& db = get_ncrystal_api_db(); - std::lock_guard lock(db.mtx); - if (!db.api) { - void* raw_api = load_virtapi_raw(NCrystalAPI::interface_id, db); - if (!raw_api) - fatal_error("Problems loading NCrystal."); - db.api = *reinterpret_cast*>(raw_api); - } - return db.api; -} -} // namespace openmc diff --git a/src/nuclide.cpp b/src/nuclide.cpp index 17d6e952c..564e27d44 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -17,11 +17,11 @@ #include -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xview.hpp" #include // for sort, min_element -#include -#include // for to_string, stoi +#include // for to_string, stoi namespace openmc { @@ -30,8 +30,8 @@ namespace openmc { //============================================================================== namespace data { -array energy_min {0.0, 0.0, 0.0, 0.0}; -array energy_max {INFTY, INFTY, INFTY, INFTY}; +array energy_min {0.0, 0.0}; +array energy_max {INFTY, INFTY}; double temperature_min {INFTY}; double temperature_max {0.0}; std::unordered_map nuclide_map; @@ -62,23 +62,6 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) read_attribute(group, "metastable", metastable_); read_attribute(group, "atomic_weight_ratio", awr_); - if (settings::run_mode == RunMode::VOLUME) { - // Determine whether nuclide is fissionable and then exit - int mt; - hid_t rxs_group = open_group(group, "reactions"); - for (auto name : group_names(rxs_group)) { - if (starts_with(name, "reaction_")) { - hid_t rx_group = open_group(rxs_group, name.c_str()); - read_attribute(rx_group, "mt", mt); - if (is_fission(mt)) { - fissionable_ = true; - break; - } - } - } - return; - } - // Determine temperatures available hid_t kT_group = open_group(group, "kTs"); auto dset_names = dataset_names(kT_group); @@ -86,7 +69,7 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) for (const auto& name : dset_names) { double T; read_dataset(kT_group, name.c_str(), T); - temps_available.push_back(std::round(T / K_BOLTZMANN)); + temps_available.push_back(T / K_BOLTZMANN); } std::sort(temps_available.begin(), temps_available.end()); @@ -158,12 +141,9 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) } } } else { - fatal_error(fmt::format( - "Nuclear data library does not contain cross sections " - "for {} at or near {} K. Available temperatures " - "are {} K. Consider making use of openmc.Settings.temperature " - "to specify how intermediate temperatures are treated.", - name_, std::to_string(T_desired), concatenate(temps_available))); + fatal_error( + "Nuclear data library does not contain cross sections for " + name_ + + " at or near " + std::to_string(T_desired) + " K."); } } break; @@ -176,8 +156,8 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) for (int j = 0; j < temps_available.size() - 1; ++j) { if (temps_available[j] <= T_desired && T_desired < temps_available[j + 1]) { - int T_j = temps_available[j]; - int T_j1 = temps_available[j + 1]; + int T_j = std::round(temps_available[j]); + int T_j1 = std::round(temps_available[j + 1]); if (!contains(temps_to_read, T_j)) { temps_to_read.push_back(T_j); } @@ -189,22 +169,6 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) } if (!found_pair) { - // If no pairs found, check if the desired temperature falls just - // outside of data - if (std::abs(T_desired - temps_available.front()) <= - settings::temperature_tolerance) { - if (!contains(temps_to_read, temps_available.front())) { - temps_to_read.push_back(temps_available.front()); - } - continue; - } - if (std::abs(T_desired - temps_available.back()) <= - settings::temperature_tolerance) { - if (!contains(temps_to_read, temps_available.back())) { - temps_to_read.push_back(temps_available.back()); - } - continue; - } fatal_error( "Nuclear data library does not contain cross sections for " + name_ + " at temperatures that bound " + std::to_string(T_desired) + " K."); @@ -247,8 +211,7 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) for (auto name : group_names(rxs_group)) { if (starts_with(name, "reaction_")) { hid_t rx_group = open_group(rxs_group, name.c_str()); - reactions_.push_back( - make_unique(rx_group, temps_to_read, name_)); + reactions_.push_back(make_unique(rx_group, temps_to_read)); // Check for 0K elastic scattering const auto& rx = reactions_.back(); @@ -360,7 +323,8 @@ void Nuclide::create_derived( { for (const auto& grid : grid_) { // Allocate and initialize cross section - xs_.push_back(tensor::zeros({grid.energy.size(), 5})); + array shape {grid.energy.size(), 5}; + xs_.emplace_back(shape, 0.0); } reaction_index_.fill(C_NONE); @@ -373,15 +337,16 @@ void Nuclide::create_derived( for (int t = 0; t < kTs_.size(); ++t) { int j = rx->xs_[t].threshold; int n = rx->xs_[t].value.size(); - auto xs = tensor::Tensor( - rx->xs_[t].value.data(), rx->xs_[t].value.size()); + auto xs = xt::adapt(rx->xs_[t].value); + for (const auto& p : rx->products_) { - if (p.particle_.is_photon()) { + if (p.particle_ == ParticleType::photon) { + auto pprod = xt::view(xs_[t], xt::range(j, j + n), XS_PHOTON_PROD); for (int k = 0; k < n; ++k) { double E = grid_[t].energy[k + j]; - // For fission, artificially increase the photon yield to - // account for delayed photons + // For fission, artificially increase the photon yield to account + // for delayed photons double f = 1.0; if (settings::delayed_photon_scaling) { if (is_fission(rx->mt_)) { @@ -393,7 +358,7 @@ void Nuclide::create_derived( } } - xs_[t](j + k, XS_PHOTON_PROD) += f * xs[k] * (*p.yield_)(E); + pprod[k] += f * xs[k] * (*p.yield_)(E); } } } @@ -403,17 +368,20 @@ void Nuclide::create_derived( continue; // Add contribution to total cross section - xs_[t].slice(tensor::range(j, j + n), XS_TOTAL) += xs; + auto total = xt::view(xs_[t], xt::range(j, j + n), XS_TOTAL); + total += xs; // Add contribution to absorption cross section + auto absorption = xt::view(xs_[t], xt::range(j, j + n), XS_ABSORPTION); if (is_disappearance(rx->mt_)) { - xs_[t].slice(tensor::range(j, j + n), XS_ABSORPTION) += xs; + absorption += xs; } if (is_fission(rx->mt_)) { fissionable_ = true; - xs_[t].slice(tensor::range(j, j + n), XS_FISSION) += xs; - xs_[t].slice(tensor::range(j, j + n), XS_ABSORPTION) += xs; + auto fission = xt::view(xs_[t], xt::range(j, j + n), XS_FISSION); + fission += xs; + absorption += xs; // Keep track of fission reactions if (t == 0) { @@ -464,8 +432,8 @@ void Nuclide::create_derived( } } } else { - // Otherwise, assume that any that have 0 K elastic scattering data - // are resonant + // Otherwise, assume that any that have 0 K elastic scattering data are + // resonant resonant_ = !energy_0K_.empty(); } @@ -487,7 +455,7 @@ void Nuclide::create_derived( xs_cdf_sum += (std::sqrt(E[i]) * xs[i] + std::sqrt(E[i + 1]) * xs[i + 1]) / 2.0 * (E[i + 1] - E[i]); - xs_cdf_[i + 1] = xs_cdf_sum; + xs_cdf_[i+1] = xs_cdf_sum; } } } @@ -495,7 +463,7 @@ void Nuclide::create_derived( void Nuclide::init_grid() { - int neutron = ParticleType::neutron().transport_index(); + int neutron = static_cast(ParticleType::neutron); double E_min = data::energy_min[neutron]; double E_max = data::energy_max[neutron]; int M = settings::n_log_bins; @@ -504,7 +472,7 @@ void Nuclide::init_grid() double spacing = std::log(E_max / E_min) / M; // Create equally log-spaced energy grid - auto umesh = tensor::linspace(0.0, M * spacing, M + 1); + auto umesh = xt::linspace(0.0, M * spacing, M + 1); for (auto& grid : grid_) { // Resize array for storing grid indices @@ -535,7 +503,7 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const case EmissionMode::prompt: return (*fission_rx_[0]->products_[0].yield_)(E); case EmissionMode::delayed: - if (n_precursor_ > 0 && settings::create_delayed_neutrons) { + if (n_precursor_ > 0) { auto rx = fission_rx_[0]; if (group >= 1 && group < rx->products_.size()) { // If delayed group specified, determine yield immediately @@ -546,7 +514,7 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const for (int i = 1; i < rx->products_.size(); ++i) { // Skip any non-neutron products const auto& product = rx->products_[i]; - if (!product.particle_.is_neutron()) + if (product.particle_ != ParticleType::neutron) continue; // Evaluate yield @@ -560,7 +528,7 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const return 0.0; } case EmissionMode::total: - if (total_nu_ && settings::create_delayed_neutrons) { + if (total_nu_) { return (*total_nu_)(E); } else { return (*fission_rx_[0]->products_[0].yield_)(E); @@ -646,23 +614,16 @@ void Nuclide::calculate_xs( } } - /* - * index_temp, index_grid, and interp_factor are used only in the - * following places: - * 1. physics.cpp - scatter - For inelastic scatter. - * 2. physics.cpp - sample_fission - For partial fissions. - * 3. tallies/tally_scoring.cpp - score_general - - * For tallying on MTxxx reactions. - * 4. nuclide.cpp - calculate_urr_xs - For unresolved purposes. - * It is worth noting that none of these occur in the resolved resonance - * range, so the value here does not matter. index_temp is set to -1 to - * force a segfault in case a developer messes up and tries to use it with - * multipole. - * - * However, a segfault is not necessarily guaranteed with an out-of-bounds - * access, so this technique should be replaced by something more robust - * in the future. - */ + // Ensure these values are set + // Note, the only time either is used is in one of 4 places: + // 1. physics.cpp - scatter - For inelastic scatter. + // 2. physics.cpp - sample_fission - For partial fissions. + // 3. tally.F90 - score_general - For tallying on MTxxx reactions. + // 4. nuclide.cpp - calculate_urr_xs - For unresolved purposes. + // It is worth noting that none of these occur in the resolved + // resonance range, so the value here does not matter. index_temp is + // set to -1 to force a segfault in case a developer messes up and tries + // to use it with multipole. micro.index_temp = -1; micro.index_grid = -1; micro.interp_factor = 0.0; @@ -685,16 +646,6 @@ void Nuclide::calculate_xs( } break; case TemperatureMethod::INTERPOLATION: - // If current kT outside of the bounds of available, snap to the bound - if (kT < kTs_.front()) { - i_temp = 0; - break; - } - if (kT > kTs_.back()) { - i_temp = kTs_.size() - 1; - break; - } - // Find temperatures that bound the actual temperature for (i_temp = 0; i_temp < kTs_.size() - 1; ++i_temp) { if (kTs_[i_temp] <= kT && kT < kTs_[i_temp + 1]) @@ -776,8 +727,8 @@ void Nuclide::calculate_xs( } for (int j = 0; j < DEPLETION_RX.size(); ++j) { - // If reaction is present and energy is greater than threshold, set - // the reaction xs appropriately + // If reaction is present and energy is greater than threshold, set the + // reaction xs appropriately int i_rx = reaction_index_[DEPLETION_RX[j]]; if (i_rx >= 0) { const auto& rx = reactions_[i_rx]; @@ -814,9 +765,9 @@ void Nuclide::calculate_xs( // Initialize URR probability table treatment to false micro.use_ptable = false; - // If there is S(a,b) data for this nuclide, we need to set the - // sab_scatter and sab_elastic cross sections and correct the total and - // elastic cross sections. + // If there is S(a,b) data for this nuclide, we need to set the sab_scatter + // and sab_elastic cross sections and correct the total and elastic cross + // sections. if (i_sab >= 0) this->calculate_sab_xs(i_sab, sab_frac, p); @@ -880,8 +831,9 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const // This guarantees the randomness and, at the same time, makes sure we // reuse random numbers for the same nuclide at different temperatures, // therefore preserving correlation of temperature in probability tables. - double r = - future_prn(static_cast(index_), p.seeds(STREAM_URR_PTABLE)); + p.stream() = STREAM_URR_PTABLE; + double r = future_prn(static_cast(index_), *p.current_seed()); + p.stream() = STREAM_TRACKING; // Warning: this assumes row-major order of cdf_values_ int i_low = upper_bound_index(&urr.cdf_values_(i_energy, 0), @@ -979,8 +931,8 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const } // Set elastic, absorption, fission, total, and capture x/s. Note that the - // total x/s is calculated as a sum of partials instead of the - // table-provided value + // total x/s is calculated as a sum of partials instead of the table-provided + // value micro.elastic = elastic; micro.absorption = capture + fission; micro.fission = fission; @@ -995,19 +947,19 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const } } -std::pair Nuclide::find_temperature(double T) const +std::pair Nuclide::find_temperature(double T) const { - assert(T >= 0.0); + Expects(T >= 0.0); // Determine temperature index - int64_t i_temp = 0; + gsl::index i_temp = 0; double f = 0.0; double kT = K_BOLTZMANN * T; - int64_t n = kTs_.size(); + gsl::index n = kTs_.size(); switch (settings::temperature_method) { case TemperatureMethod::NEAREST: { double max_diff = INFTY; - for (int64_t t = 0; t < n; ++t) { + for (gsl::index t = 0; t < n; ++t) { double diff = std::abs(kTs_[t] - kT); if (diff < max_diff) { i_temp = t; @@ -1017,15 +969,6 @@ std::pair Nuclide::find_temperature(double T) const } break; case TemperatureMethod::INTERPOLATION: - // If current kT outside of the bounds of available, snap to the bound - if (kT < kTs_.front()) { - i_temp = 0; - break; - } - if (kT > kTs_.back()) { - i_temp = kTs_.size() - 1; - break; - } // Find temperatures that bound the actual temperature while (kTs_[i_temp + 1] < kT && i_temp + 1 < n - 1) ++i_temp; @@ -1034,17 +977,17 @@ std::pair Nuclide::find_temperature(double T) const f = (kT - kTs_[i_temp]) / (kTs_[i_temp + 1] - kTs_[i_temp]); } - assert(i_temp >= 0 && i_temp < n); + Ensures(i_temp >= 0 && i_temp < n); return {i_temp, f}; } double Nuclide::collapse_rate(int MT, double temperature, - span energy, span flux) const + gsl::span energy, gsl::span flux) const { - assert(MT > 0); - assert(energy.size() > 0); - assert(energy.size() == flux.size() + 1); + Expects(MT > 0); + Expects(energy.size() > 0); + Expects(energy.size() == flux.size() + 1); int i_rx = reaction_index_[MT]; if (i_rx < 0) @@ -1052,7 +995,7 @@ double Nuclide::collapse_rate(int MT, double temperature, const auto& rx = reactions_[i_rx]; // Determine temperature index - int64_t i_temp; + gsl::index i_temp; double f; std::tie(i_temp, f) = this->find_temperature(temperature); @@ -1108,7 +1051,7 @@ extern "C" size_t nuclides_size() extern "C" int openmc_load_nuclide(const char* name, const double* temps, int n) { if (data::nuclide_map.find(name) == data::nuclide_map.end() || - data::nuclide_map.at(name) >= data::nuclides.size()) { + data::nuclide_map.at(name) >= data::elements.size()) { LibraryKey key {Library::Type::neutron, name}; const auto& it = data::library_map.find(key); if (it == data::library_map.end()) { @@ -1209,6 +1152,7 @@ extern "C" int openmc_nuclide_collapse_rate(int index, int MT, *xs = data::nuclides[index]->collapse_rate( MT, temperature, {energy, energy + n + 1}, {flux, flux + n}); } catch (const std::out_of_range& e) { + fmt::print("Caught error\n"); set_errmsg(e.what()); return OPENMC_E_OUT_OF_BOUNDS; } diff --git a/src/output.cpp b/src/output.cpp index 04a8caa60..56fea4db9 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1,8 +1,8 @@ #include "openmc/output.h" #include // for transform, max -#include // for stdout #include // for strlen +#include // for stdout #include // for time, localtime #include #include // for setw, setprecision, put_time @@ -17,7 +17,7 @@ #ifdef _OPENMP #include #endif -#include "openmc/tensor.h" +#include "xtensor/xview.hpp" #include "openmc/capi.h" #include "openmc/cell.h" @@ -31,7 +31,6 @@ #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/plot.h" -#include "openmc/random_ray/flat_source_domain.h" #include "openmc/reaction.h" #include "openmc/settings.h" #include "openmc/simulation.h" @@ -44,12 +43,6 @@ namespace openmc { -#ifdef OPENMC_ENABLE_STRICT_FP -const bool STRICT_FP_ENABLED = true; -#else -const bool STRICT_FP_ENABLED = false; -#endif - //============================================================================== void title() @@ -81,12 +74,13 @@ void title() // Write version information fmt::print( " | The OpenMC Monte Carlo Code\n" - " Copyright | 2011-2026 MIT, UChicago Argonne LLC, and contributors\n" + " Copyright | 2011-2022 MIT, UChicago Argonne LLC, and contributors\n" " License | https://docs.openmc.org/en/latest/license.html\n" - " Version | {}.{}.{}{}{}\n", - VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE, VERSION_DEV ? "-dev" : "", - VERSION_COMMIT_COUNT); - fmt::print(" Commit Hash | {}\n", VERSION_COMMIT_HASH); + " Version | {}.{}.{}{}\n", + VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE, VERSION_DEV ? "-dev" : ""); +#ifdef GIT_SHA1 + fmt::print(" Git SHA1 | {}\n", GIT_SHA1); +#endif // Write the date and time fmt::print(" Date/Time | {}\n", time_stamp()); @@ -140,10 +134,9 @@ void header(const char* msg, int level) auto out = header(msg); // Print header based on verbosity level. - if (settings::verbosity >= level) { + if (settings::verbosity >= level) fmt::print("\n{}\n\n", out); std::fflush(stdout); - } } //============================================================================== @@ -161,21 +154,21 @@ std::string time_stamp() void print_particle(Particle& p) { // Display particle type and ID. - switch (p.type().pdg_number()) { - case PDG_NEUTRON: + switch (p.type()) { + case ParticleType::neutron: fmt::print("Neutron "); break; - case PDG_PHOTON: + case ParticleType::photon: fmt::print("Photon "); break; - case PDG_ELECTRON: + case ParticleType::electron: fmt::print("Electron "); break; - case PDG_POSITRON: + case ParticleType::positron: fmt::print("Positron "); break; default: - fmt::print("Particle {} ", p.type().str()); + fmt::print("Unknown Particle "); } fmt::print("{}\n", p.id()); @@ -183,32 +176,31 @@ void print_particle(Particle& p) for (auto i = 0; i < p.n_coord(); i++) { fmt::print(" Level {}\n", i); - if (p.coord(i).cell() != C_NONE) { - const Cell& c {*model::cells[p.coord(i).cell()]}; + if (p.coord(i).cell != C_NONE) { + const Cell& c {*model::cells[p.coord(i).cell]}; fmt::print(" Cell = {}\n", c.id_); } - if (p.coord(i).universe() != C_NONE) { - const Universe& u {*model::universes[p.coord(i).universe()]}; + if (p.coord(i).universe != C_NONE) { + const Universe& u {*model::universes[p.coord(i).universe]}; fmt::print(" Universe = {}\n", u.id_); } - if (p.coord(i).lattice() != C_NONE) { - const Lattice& lat {*model::lattices[p.coord(i).lattice()]}; + if (p.coord(i).lattice != C_NONE) { + const Lattice& lat {*model::lattices[p.coord(i).lattice]}; fmt::print(" Lattice = {}\n", lat.id_); - fmt::print(" Lattice position = ({},{},{})\n", - p.coord(i).lattice_index()[0], p.coord(i).lattice_index()[1], - p.coord(i).lattice_index()[2]); + fmt::print(" Lattice position = ({},{},{})\n", p.coord(i).lattice_i[0], + p.coord(i).lattice_i[1], p.coord(i).lattice_i[2]); } - fmt::print(" r = {}\n", p.coord(i).r()); - fmt::print(" u = {}\n", p.coord(i).u()); + fmt::print(" r = {}\n", p.coord(i).r); + fmt::print(" u = {}\n", p.coord(i).u); } // Display miscellaneous info. - if (p.surface() != SURFACE_NONE) { + if (p.surface() != 0) { // Surfaces identifiers are >= 1, but indices are >= 0 so we need -1 - const Surface& surf {*model::surfaces[p.surface_index()]}; + const Surface& surf {*model::surfaces[std::abs(p.surface()) - 1]}; fmt::print(" Surface = {}\n", (p.surface() > 0) ? surf.id_ : -surf.id_); } fmt::print(" Weight = {}\n", p.wgt()); @@ -228,11 +220,56 @@ void print_plot() if (settings::verbosity < 5) return; - for (const auto& pl : model::plots) { - fmt::print("Plot ID: {}\n", pl->id()); - fmt::print("Plot file: {}\n", pl->path_plot()); - fmt::print("Universe depth: {}\n", pl->level()); - pl->print_info(); // prints type-specific plot info + for (auto pl : model::plots) { + // Plot id + fmt::print("Plot ID: {}\n", pl.id_); + // Plot filename + fmt::print("Plot file: {}\n", pl.path_plot_); + // Plot level + fmt::print("Universe depth: {}\n", pl.level_); + + // Plot type + if (PlotType::slice == pl.type_) { + fmt::print("Plot Type: Slice\n"); + } else if (PlotType::voxel == pl.type_) { + fmt::print("Plot Type: Voxel\n"); + } + + // Plot parameters + fmt::print( + "Origin: {} {} {}\n", pl.origin_[0], pl.origin_[1], pl.origin_[2]); + + if (PlotType::slice == pl.type_) { + fmt::print("Width: {:4} {:4}\n", pl.width_[0], pl.width_[1]); + } else if (PlotType::voxel == pl.type_) { + fmt::print( + "Width: {:4} {:4} {:4}\n", pl.width_[0], pl.width_[1], pl.width_[2]); + } + + if (PlotColorBy::cells == pl.color_by_) { + fmt::print("Coloring: Cells\n"); + } else if (PlotColorBy::mats == pl.color_by_) { + fmt::print("Coloring: Materials\n"); + } + + if (PlotType::slice == pl.type_) { + switch (pl.basis_) { + case PlotBasis::xy: + fmt::print("Basis: XY\n"); + break; + case PlotBasis::xz: + fmt::print("Basis: XZ\n"); + break; + case PlotBasis::yz: + fmt::print("Basis: YZ\n"); + break; + } + fmt::print("Pixels: {} {}\n", pl.pixels_[0], pl.pixels_[1]); + } else if (PlotType::voxel == pl.type_) { + fmt::print( + "Voxels: {} {} {}\n", pl.pixels_[0], pl.pixels_[1], pl.pixels_[2]); + } + fmt::print("\n"); } } @@ -275,7 +312,7 @@ void print_usage() { if (mpi::master) { fmt::print( - "Usage: openmc [options] [path]\n\n" + "Usage: openmc [options] [directory]\n\n" "Options:\n" " -c, --volume Run in stochastic volume calculation mode\n" " -g, --geometry-debug Run with geometry debugging on\n" @@ -287,7 +324,6 @@ void print_usage() " -t, --track Write tracks for all particles (up to " "max_tracks)\n" " -e, --event Run using event-based parallelism\n" - " -q, --verbosity Output verbosity\n" " -v, --version Show version information\n" " -h, --help Show this message\n"); } @@ -298,10 +334,12 @@ void print_usage() void print_version() { if (mpi::master) { - fmt::print("OpenMC version {}.{}.{}{}{}\n", VERSION_MAJOR, VERSION_MINOR, - VERSION_RELEASE, VERSION_DEV ? "-dev" : "", VERSION_COMMIT_COUNT); - fmt::print("Commit hash: {}\n", VERSION_COMMIT_HASH); - fmt::print("Copyright (c) 2011-2026 MIT, UChicago Argonne LLC, and " + fmt::print("OpenMC version {}.{}.{}\n", VERSION_MAJOR, VERSION_MINOR, + VERSION_RELEASE); +#ifdef GIT_SHA1 + fmt::print("Git SHA1: {}\n", GIT_SHA1); +#endif + fmt::print("Copyright (c) 2011-2022 MIT, UChicago Argonne LLC, and " "contributors\nMIT/X license at " "\n"); } @@ -309,71 +347,6 @@ void print_version() //============================================================================== -void print_build_info() -{ - const std::string n("no"); - const std::string y("yes"); - - std::string mpi(n); - std::string phdf5(n); - std::string dagmc(n); - std::string libmesh(n); - std::string png(n); - std::string profiling(n); - std::string coverage(n); - std::string uwuw(n); - std::string strict_fp(n); - -#ifdef PHDF5 - phdf5 = y; -#endif -#ifdef OPENMC_MPI - mpi = y; -#endif -#ifdef OPENMC_DAGMC_ENABLED - dagmc = y; -#endif -#ifdef OPENMC_LIBMESH_ENABLED - libmesh = y; -#endif -#ifdef USE_LIBPNG - png = y; -#endif -#ifdef PROFILINGBUILD - profiling = y; -#endif -#ifdef COVERAGEBUILD - coverage = y; -#endif -#ifdef OPENMC_UWUW_ENABLED - uwuw = y; -#endif -#ifdef OPENMC_ENABLE_STRICT_FP - strict_fp = y; -#endif - - // Wraps macro variables in quotes -#define STRINGIFY(x) STRINGIFY2(x) -#define STRINGIFY2(x) #x - - if (mpi::master) { - fmt::print("Build type: {}\n", STRINGIFY(BUILD_TYPE)); - fmt::print("Compiler ID: {} {}\n", STRINGIFY(COMPILER_ID), - STRINGIFY(COMPILER_VERSION)); - fmt::print("MPI enabled: {}\n", mpi); - fmt::print("Parallel HDF5 enabled: {}\n", phdf5); - fmt::print("PNG support: {}\n", png); - fmt::print("DAGMC support: {}\n", dagmc); - fmt::print("libMesh support: {}\n", libmesh); - fmt::print("Coverage testing: {}\n", coverage); - fmt::print("Profiling flags: {}\n", profiling); - fmt::print("UWUW support: {}\n", uwuw); - fmt::print("Strict FP: {}\n", strict_fp); - } -} - -//============================================================================== - void print_columns() { if (settings::entropy_on) { @@ -415,7 +388,7 @@ void print_generation() //============================================================================== -void show_time(const char* label, double secs, int indent_level) +void show_time(const char* label, double secs, int indent_level = 0) { int width = 33 - indent_level * 2; fmt::print("{0:{1}} {2:<{3}} = {4:>10.4e} seconds\n", "", 2 * indent_level, @@ -501,14 +474,6 @@ void print_runtime() show_rate("Calculation Rate (inactive)", speed_inactive); } show_rate("Calculation Rate (active)", speed_active); - - // Display track rate when weight windows are enabled - if (settings::weight_windows_on) { - double speed_tracks = - simulation::simulation_tracks_completed / time_active.elapsed(); - fmt::print( - " {:<33} = {:.6} tracks/second\n", "Track Rate (active)", speed_tracks); - } } //============================================================================== @@ -608,10 +573,6 @@ const std::unordered_map score_names = { {SCORE_FISS_Q_PROMPT, "Prompt fission power"}, {SCORE_FISS_Q_RECOV, "Recoverable fission power"}, {SCORE_CURRENT, "Current"}, - {SCORE_PULSE_HEIGHT, "pulse-height"}, - {SCORE_IFP_TIME_NUM, "IFP lifetime numerator"}, - {SCORE_IFP_BETA_NUM, "IFP delayed fraction numerator"}, - {SCORE_IFP_DENOM, "IFP common denominator"}, }; //! Create an ASCII output file showing all tally results. @@ -621,15 +582,8 @@ void write_tallies() if (model::tallies.empty()) return; - // Tag tallies.out written during the forward solve of an adjoint run - const char* forward = - (FlatSourceDomain::solve_ == RandomRaySolve::FORWARD_FOR_ADJOINT) - ? "forward." - : ""; - // Set filename for tallies_out - std::string filename = - fmt::format("{}tallies.{}out", settings::path_output, forward); + std::string filename = fmt::format("{}tallies.out", settings::path_output); // Open the tallies.out file. std::ofstream tallies_out; diff --git a/src/particle.cpp b/src/particle.cpp index 10e8f213d..cb959e14d 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -8,18 +8,15 @@ #include "openmc/bank.h" #include "openmc/capi.h" #include "openmc/cell.h" -#include "openmc/collision_track.h" #include "openmc/constants.h" #include "openmc/dagmc.h" #include "openmc/error.h" #include "openmc/geometry.h" #include "openmc/hdf5_interface.h" -#include "openmc/lattice.h" #include "openmc/material.h" #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" -#include "openmc/particle_data.h" #include "openmc/photon.h" #include "openmc/physics.h" #include "openmc/physics_mg.h" @@ -32,131 +29,69 @@ #include "openmc/tallies/tally.h" #include "openmc/tallies/tally_scoring.h" #include "openmc/track_output.h" -#include "openmc/weight_windows.h" -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC #include "DagMC.hpp" #endif namespace openmc { -//============================================================================== -// Particle implementation -//============================================================================== - double Particle::speed() const { - if (settings::run_CE) { - // Determine mass in eV/c^2 - double mass = this->mass(); - - // Equivalent to C * sqrt(1-(m/(m+E))^2) without problem at E<E() * (this->E() + 2 * mass)) / - (this->E() + mass); - } else { - auto mat = this->material(); - if (mat == MATERIAL_VOID) - return 1.0 / data::mg.default_inverse_velocity_[this->g()]; - auto& macro_xs = data::mg.macro_xs_[mat]; - int macro_t = this->mg_xs_cache().t; - int macro_a = macro_xs.get_angle_index(this->u()); - return 1.0 / macro_xs.get_xs( - MgxsType::INVERSE_VELOCITY, this->g(), macro_t, macro_a); + // Determine mass in eV/c^2 + double mass; + switch (this->type()) { + case ParticleType::neutron: + mass = MASS_NEUTRON_EV; + break; + case ParticleType::photon: + mass = 0.0; + break; + case ParticleType::electron: + case ParticleType::positron: + mass = MASS_ELECTRON_EV; + break; } + + // Calculate inverse of Lorentz factor + const double inv_gamma = mass / (this->E() + mass); + + // Calculate speed via v = c * sqrt(1 - γ^-2) + return C_LIGHT * std::sqrt(1 - inv_gamma * inv_gamma); } -double Particle::mass() const -{ - switch (type().pdg_number()) { - case PDG_NEUTRON: - return MASS_NEUTRON_EV; - case PDG_ELECTRON: - case PDG_POSITRON: - return MASS_ELECTRON_EV; - default: - return this->type().mass() * AMU_EV; - } -} - -bool Particle::create_secondary( +void Particle::create_secondary( double wgt, Direction u, double E, ParticleType type) { // If energy is below cutoff for this particle, don't create secondary // particle - int idx = type.transport_index(); - if (idx == C_NONE) { - return false; - } - if (E < settings::energy_cutoff[idx]) { - return false; + if (E < settings::energy_cutoff[static_cast(type)]) { + return; } - // Increment number of secondaries created (for ParticleProductionFilter) - n_secondaries()++; + secondary_bank().emplace_back(); - SourceSite bank; + auto& bank {secondary_bank().back()}; bank.particle = type; bank.wgt = wgt; bank.r = r(); bank.u = u; bank.E = settings::run_CE ? E : g(); bank.time = time(); - bank_second_E() += bank.E; - bank.parent_id = current_work(); - if (settings::use_shared_secondary_bank) { - bank.progeny_id = n_progeny()++; - } - bank.wgt_born = wgt_born(); - bank.wgt_ww_born = wgt_ww_born(); - bank.n_split = n_split(); - local_secondary_bank().emplace_back(bank); - return true; -} - -void Particle::split(double wgt) -{ - SourceSite bank; - bank.particle = type(); - bank.wgt = wgt; - bank.r = r(); - bank.u = u(); - bank.E = settings::run_CE ? E() : g(); - bank.time = time(); - - // Convert signed index to a signed surface ID - if (surface() == SURFACE_NONE) { - bank.surf_id = SURFACE_NONE; - } else { - int surf_id = model::surfaces[surface_index()]->id_; - bank.surf_id = (surface() > 0) ? surf_id : -surf_id; - } - - bank.wgt_born = wgt_born(); - bank.wgt_ww_born = wgt_ww_born(); - bank.n_split = n_split(); - bank.parent_id = current_work(); - if (settings::use_shared_secondary_bank) { - bank.progeny_id = n_progeny()++; - } - - local_secondary_bank().emplace_back(bank); + n_bank_second() += 1; } void Particle::from_source(const SourceSite* src) { // Reset some attributes clear(); - surface() = SURFACE_NONE; + surface() = 0; cell_born() = C_NONE; material() = C_NONE; n_collision() = 0; fission() = false; zero_flux_derivs(); - lifetime() = 0.0; -#ifdef OPENMC_DAGMC_ENABLED - history().reset(); -#endif // Copy attributes from source bank site type() = src->particle; @@ -164,7 +99,6 @@ void Particle::from_source(const SourceSite* src) wgt_last() = src->wgt; r() = src->r; u() = src->u; - r_born() = src->r; r_last_current() = src->r; r_last() = src->r; u_last() = src->u; @@ -179,18 +113,6 @@ void Particle::from_source(const SourceSite* src) E_last() = E(); time() = src->time; time_last() = src->time; - parent_nuclide() = src->parent_nuclide; - delayed_group() = src->delayed_group; - - // Convert signed surface ID to signed index - if (src->surf_id != SURFACE_NONE) { - int index_plus_one = model::surface_map[std::abs(src->surf_id)] + 1; - surface() = (src->surf_id > 0) ? index_plus_one : -index_plus_one; - } - - wgt_born() = src->wgt_born; - wgt_ww_born() = src->wgt_ww_born; - n_split() = src->n_split; } void Particle::event_calculate_xs() @@ -213,7 +135,7 @@ void Particle::event_calculate_xs() // If the cell hasn't been determined based on the particle's location, // initiate a search for the current cell. This generally happens at the // beginning of the history and again for any secondary particles - if (lowest_coord().cell() == C_NONE) { + if (coord(n_coord() - 1).cell == C_NONE) { if (!exhaustive_find_cell(*this)) { mark_as_lost( "Could not find the cell containing particle " + std::to_string(id())); @@ -222,13 +144,7 @@ void Particle::event_calculate_xs() // Set birth cell attribute if (cell_born() == C_NONE) - cell_born() = lowest_coord().cell(); - - // Initialize last cells from current cell - for (int j = 0; j < n_coord(); ++j) { - cell_last(j) = coord(j).cell(); - } - n_coord_last() = n_coord(); + cell_born() = coord(n_coord() - 1).cell; } // Write particle track. @@ -241,8 +157,7 @@ void Particle::event_calculate_xs() // Calculate microscopic and macroscopic cross sections if (material() != MATERIAL_VOID) { if (settings::run_CE) { - if (material() != material_last() || sqrtkT() != sqrtkT_last() || - density_mult() != density_mult_last()) { + if (material() != material_last() || sqrtkT() != sqrtkT_last()) { // If the material is the same as the last material and the // temperature hasn't changed, we don't need to lookup cross // sections again. @@ -271,34 +186,22 @@ void Particle::event_advance() boundary() = distance_to_boundary(*this); // Sample a distance to collision - if (type() == ParticleType::electron() || - type() == ParticleType::positron()) { - collision_distance() = material() == MATERIAL_VOID ? INFINITY : 0.0; + if (type() == ParticleType::electron || type() == ParticleType::positron) { + collision_distance() = 0.0; } else if (macro_xs().total == 0.0) { collision_distance() = INFINITY; } else { collision_distance() = -std::log(prn(current_seed())) / macro_xs().total; } - double speed = this->speed(); - double time_cutoff = settings::time_cutoff[type().transport_index()]; - double distance_cutoff = - (time_cutoff < INFTY) ? (time_cutoff - time()) * speed : INFTY; - - // Select smaller of the three distances - double distance = - std::min({boundary().distance(), collision_distance(), distance_cutoff}); + // Select smaller of the two distances + double distance = std::min(boundary().distance, collision_distance()); // Advance particle in space and time - this->move_distance(distance); - double dt = distance / speed; - this->time() += dt; - this->lifetime() += dt; - - // Score timed track-length tallies - if (!model::active_timed_tracklength_tallies.empty()) { - score_timed_tracklength_tally(*this, distance); + for (int j = 0; j < n_coord(); ++j) { + coord(j).r += distance * coord(j).u; } + this->time() += distance / this->speed(); // Score track-length tallies if (!model::active_tracklength_tallies.empty()) { @@ -306,7 +209,8 @@ void Particle::event_advance() } // Score track-length estimate of k-eff - if (settings::run_mode == RunMode::EIGENVALUE && type().is_neutron()) { + if (settings::run_mode == RunMode::EIGENVALUE && + type() == ParticleType::neutron) { keff_tally_tracklength() += wgt() * distance * macro_xs().nu_fission; } @@ -314,80 +218,42 @@ void Particle::event_advance() if (!model::active_tallies.empty()) { score_track_derivative(*this, distance); } - - // Set particle weight to zero if it hit the time boundary - if (distance == distance_cutoff) { - wgt() = 0.0; - } } void Particle::event_cross_surface() { + // Set surface that particle is on and adjust coordinate levels + surface() = boundary().surface_index; + n_coord() = boundary().coord_level; + // Saving previous cell data for (int j = 0; j < n_coord(); ++j) { - cell_last(j) = coord(j).cell(); + cell_last(j) = coord(j).cell; } n_coord_last() = n_coord(); - // Set surface that particle is on and adjust coordinate levels - surface() = boundary().surface(); - n_coord() = boundary().coord_level(); - - if (boundary().lattice_translation()[0] != 0 || - boundary().lattice_translation()[1] != 0 || - boundary().lattice_translation()[2] != 0) { + if (boundary().lattice_translation[0] != 0 || + boundary().lattice_translation[1] != 0 || + boundary().lattice_translation[2] != 0) { // Particle crosses lattice boundary - - int i_lattice = coord(boundary().coord_level() - 1).lattice(); - bool verbose = settings::verbosity >= 10 || trace(); - cross_lattice(*this, boundary(), verbose); + cross_lattice(*this, boundary()); event() = TallyEvent::LATTICE; - - // Score cell to cell partial currents - if (!model::active_surface_tallies.empty()) { - auto& lat {*model::lattices[i_lattice]}; - bool is_valid; - Direction normal = - lat.get_normal(boundary().lattice_translation(), is_valid); - if (is_valid) { - normal /= normal.norm(); - score_surface_tally(*this, model::active_surface_tallies, normal); - } - } - } else { - - const auto& surf {*model::surfaces[surface_index()].get()}; - // Particle crosses surface - // If BC, add particle to surface source before crossing surface - if (surf.surf_source_ && surf.bc_) { - add_surf_source_to_bank(*this, surf); - } - this->cross_surface(surf); - // If no BC, add particle to surface source after crossing surface - if (surf.surf_source_ && !surf.bc_) { - add_surf_source_to_bank(*this, surf); - } - if (settings::weight_window_checkpoint_surface) { - apply_weight_windows(*this); - } + cross_surface(); event() = TallyEvent::SURFACE; - - // Score cell to cell partial currents - if (!model::active_surface_tallies.empty()) { - Direction normal = surf.normal(r()); - normal /= normal.norm(); - score_surface_tally(*this, model::active_surface_tallies, normal); - } + } + // Score cell to cell partial currents + if (!model::active_surface_tallies.empty()) { + score_surface_tally(*this, model::active_surface_tallies); } } void Particle::event_collide() { - // Score collision estimate of keff - if (settings::run_mode == RunMode::EIGENVALUE && type().is_neutron()) { + if (settings::run_mode == RunMode::EIGENVALUE && + type() == ParticleType::neutron) { keff_tally_collision() += wgt() * macro_xs().nu_fission / macro_xs().total; } @@ -396,10 +262,10 @@ void Particle::event_collide() // pre-collision direction to figure out what mesh surfaces were crossed if (!model::active_meshsurf_tallies.empty()) - score_meshsurface_tally(*this, model::active_meshsurf_tallies); + score_surface_tally(*this, model::active_meshsurf_tallies); // Clear surface component - surface() = SURFACE_NONE; + surface() = 0; if (settings::run_CE) { collision(*this); @@ -407,11 +273,6 @@ void Particle::event_collide() collision_mg(*this); } - // Collision track feature to recording particle interaction - if (settings::collision_track) { - collision_track_record(*this); - } - // Score collision estimator tallies -- this is done after a collision // has occurred rather than before because we need information on the // outgoing energy for any tallies with an outgoing energy filter @@ -425,19 +286,10 @@ void Particle::event_collide() } } - if (!model::active_pulse_height_tallies.empty() && type().is_photon()) { - pht_collision_energy(); - } - // Reset banked weight during collision n_bank() = 0; - bank_second_E() = 0.0; + n_bank_second() = 0; wgt_bank() = 0.0; - - // Clear number of secondaries in this collision. This is - // distinct from the number of created neutrons n_bank() above! - n_secondaries() = 0; - zero_delayed_bank(); // Reset fission logical @@ -453,14 +305,14 @@ void Particle::event_collide() // Set all directions to base level -- right now, after a collision, only // the base level directions are changed for (int j = 0; j < n_coord() - 1; ++j) { - if (coord(j + 1).rotated()) { + if (coord(j + 1).rotated) { // If next level is rotated, apply rotation matrix - const auto& m {model::cells[coord(j).cell()]->rotation_}; - const auto& u {coord(j).u()}; - coord(j + 1).u() = u.rotate(m); + const auto& m {model::cells[coord(j).cell]->rotation_}; + const auto& u {coord(j).u}; + coord(j + 1).u = u.rotate(m); } else { // Otherwise, copy this level's direction - coord(j + 1).u() = coord(j).u(); + coord(j + 1).u = coord(j).u; } } @@ -468,116 +320,62 @@ void Particle::event_collide() if (!model::active_tallies.empty()) score_collision_derivative(*this); -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC history().reset(); #endif } -void Particle::event_revive_from_secondary(const SourceSite& site) -{ - // Write final position for the previous track (skip if this is a freshly - // constructed particle with no prior track, e.g., Phase 2 of shared - // secondary transport) - if (write_track() && n_event() > 0) { - write_particle_track(*this); - } - - from_source(&site); - - n_event() = 0; - if (!settings::use_shared_secondary_bank) { - n_tracks()++; - } - bank_second_E() = 0.0; - - // Subtract secondary particle energy from interim pulse-height results. - // In shared secondary mode, this subtraction was already done on the parent - // particle during create_secondary(), so skip it here. - if (!settings::use_shared_secondary_bank && - !model::active_pulse_height_tallies.empty() && this->type().is_photon()) { - // Since the birth cell of the particle has not been set we - // have to determine it before the energy of the secondary particle can be - // removed from the pulse-height of this cell. - if (lowest_coord().cell() == C_NONE) { - bool verbose = settings::verbosity >= 10 || trace(); - if (!exhaustive_find_cell(*this, verbose)) { - mark_as_lost("Could not find the cell containing particle " + - std::to_string(id())); - return; - } - // Set birth cell attribute - if (cell_born() == C_NONE) - cell_born() = lowest_coord().cell(); - - // Initialize last cells from current cell - for (int j = 0; j < n_coord(); ++j) { - cell_last(j) = coord(j).cell(); - } - n_coord_last() = n_coord(); - } - pht_secondary_particles(); - } - - // Enter new particle in particle track file - if (write_track()) - add_particle_track(*this); -} - -void Particle::event_check_limit_and_revive() +void Particle::event_revive_from_secondary() { // If particle has too many events, display warning and kill it - n_event()++; - if (n_event() == settings::max_particle_events) { + ++n_event(); + if (n_event() == MAX_EVENTS) { warning("Particle " + std::to_string(id()) + " underwent maximum number of events."); wgt() = 0.0; } - // In non-shared-secondary mode, revive from local secondary bank - if (!alive() && !settings::use_shared_secondary_bank && - !local_secondary_bank().empty()) { - SourceSite& site = local_secondary_bank().back(); - event_revive_from_secondary(site); - local_secondary_bank().pop_back(); + // Check for secondary particles if this particle is dead + if (!alive()) { + // Write final position for this particle + if (write_track()) { + write_particle_track(*this); + } + + // If no secondary particles, break out of event loop + if (secondary_bank().empty()) + return; + + from_source(&secondary_bank().back()); + secondary_bank().pop_back(); + n_event() = 0; + + // Enter new particle in particle track file + if (write_track()) + add_particle_track(*this); } } void Particle::event_death() { -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC history().reset(); #endif // Finish particle track output. if (write_track()) { - write_particle_track(*this); finalize_particle_track(*this); } - // Contribute tally reduction variables to global accumulator - const auto k_absorption = keff_tally_absorption(); - const auto k_collision = keff_tally_collision(); - const auto k_tracklength = keff_tally_tracklength(); - const auto leakage = keff_tally_leakage(); - - if (settings::run_mode == RunMode::EIGENVALUE) { - if (k_absorption != 0.0) { +// Contribute tally reduction variables to global accumulator #pragma omp atomic - global_tally_absorption += k_absorption; - } - if (k_collision != 0.0) { + global_tally_absorption += keff_tally_absorption(); #pragma omp atomic - global_tally_collision += k_collision; - } - if (k_tracklength != 0.0) { + global_tally_collision += keff_tally_collision(); #pragma omp atomic - global_tally_tracklength += k_tracklength; - } - } - if (leakage != 0.0) { + global_tally_tracklength += keff_tally_tracklength(); #pragma omp atomic - global_tally_leakage += leakage; - } + global_tally_leakage += keff_tally_leakage(); // Reset particle tallies once accumulated keff_tally_absorption() = 0.0; @@ -585,118 +383,84 @@ void Particle::event_death() keff_tally_tracklength() = 0.0; keff_tally_leakage() = 0.0; - if (!model::active_pulse_height_tallies.empty()) { - score_pulse_height_tally(*this, model::active_pulse_height_tallies); - } - - // Accumulate track count for this particle history - if (!settings::use_shared_secondary_bank) { -#pragma omp atomic - simulation::simulation_tracks_completed += n_tracks(); - } - // Record the number of progeny created by this particle. // This data will be used to efficiently sort the fission bank. - if (settings::run_mode == RunMode::EIGENVALUE || - settings::use_shared_secondary_bank) { - simulation::progeny_per_particle[current_work()] = n_progeny(); + if (settings::run_mode == RunMode::EIGENVALUE) { + int64_t offset = id() - 1 - simulation::work_index[mpi::rank]; + simulation::progeny_per_particle[offset] = n_progeny(); } } -void Particle::pht_collision_energy() +void Particle::cross_surface() { - // Adds the energy particles lose in a collision to the pulse-height - - // determine index of cell in pulse_height_cells - auto it = std::find(model::pulse_height_cells.begin(), - model::pulse_height_cells.end(), lowest_coord().cell()); - - if (it != model::pulse_height_cells.end()) { - int index = std::distance(model::pulse_height_cells.begin(), it); - pht_storage()[index] += E_last() - E(); - - // If the energy of the particle is below the cutoff, it will not be sampled - // so its energy is added to the pulse-height in the cell - int photon = ParticleType::photon().transport_index(); - if (E() < settings::energy_cutoff[photon]) { - pht_storage()[index] += E(); - } - } -} - -void Particle::pht_secondary_particles() -{ - // Removes the energy of secondary produced particles from the pulse-height - - // determine index of cell in pulse_height_cells - auto it = std::find(model::pulse_height_cells.begin(), - model::pulse_height_cells.end(), cell_born()); - - if (it != model::pulse_height_cells.end()) { - int index = std::distance(model::pulse_height_cells.begin(), it); - pht_storage()[index] -= E(); - } -} - -void Particle::cross_surface(const Surface& surf) -{ - + int i_surface = std::abs(surface()); + // TODO: off-by-one + const auto& surf {model::surfaces[i_surface - 1].get()}; if (settings::verbosity >= 10 || trace()) { - write_message(1, " Crossing surface {}", surf.id_); + write_message(1, " Crossing surface {}", surf->id_); + } + + if (surf->surf_source_ && simulation::current_batch == settings::n_batches) { + SourceSite site; + site.r = r(); + site.u = u(); + site.E = E(); + site.time = time(); + site.wgt = wgt(); + site.delayed_group = delayed_group(); + site.surf_id = surf->id_; + site.particle = type(); + site.parent_id = id(); + site.progeny_id = n_progeny(); + int64_t idx = simulation::surf_source_bank.thread_safe_append(site); } // if we're crossing a CSG surface, make sure the DAG history is reset -#ifdef OPENMC_DAGMC_ENABLED - if (surf.geom_type() == GeometryType::CSG) +#ifdef DAGMC + if (surf->geom_type_ == GeometryType::CSG) history().reset(); #endif // Handle any applicable boundary conditions. - if (surf.bc_ && settings::run_mode != RunMode::PLOTTING && - settings::run_mode != RunMode::VOLUME) { - surf.bc_->handle_particle(*this, surf); + if (surf->bc_ && settings::run_mode != RunMode::PLOTTING) { + surf->bc_->handle_particle(*this, *surf); return; } // ========================================================================== // SEARCH NEIGHBOR LISTS FOR NEXT CELL -#ifdef OPENMC_DAGMC_ENABLED +#ifdef DAGMC // in DAGMC, we know what the next cell should be - if (surf.geom_type() == GeometryType::DAG) { - int32_t i_cell = next_cell(surface_index(), cell_last(n_coord() - 1), - lowest_coord().universe()) - - 1; - // save material, temperature, and density multiplier + if (surf->geom_type_ == GeometryType::DAG) { + auto surfp = dynamic_cast(surf); + auto cellp = + dynamic_cast(model::cells[cell_last(n_coord() - 1)].get()); + auto univp = static_cast( + model::universes[coord(n_coord() - 1).universe].get()); + // determine the next cell for this crossing + int32_t i_cell = next_cell(univp, cellp, surfp) - 1; + // save material and temp material_last() = material(); sqrtkT_last() = sqrtkT(); - density_mult_last() = density_mult(); // set new cell value - lowest_coord().cell() = i_cell; - auto& cell = model::cells[i_cell]; - + coord(n_coord() - 1).cell = i_cell; cell_instance() = 0; - if (cell->distribcell_index_ >= 0) - cell_instance() = cell_instance_at_level(*this, n_coord() - 1); - - material() = cell->material(cell_instance()); - sqrtkT() = cell->sqrtkT(cell_instance()); - density_mult() = cell->density_mult(cell_instance()); + material() = model::cells[i_cell]->material_[0]; + sqrtkT() = model::cells[i_cell]->sqrtkT_[0]; return; } #endif - bool verbose = settings::verbosity >= 10 || trace(); - if (neighbor_list_find_cell(*this, verbose)) { + if (neighbor_list_find_cell(*this)) return; - } // ========================================================================== // COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS // Remove lower coordinate levels n_coord() = 1; - bool found = exhaustive_find_cell(*this, verbose); + bool found = exhaustive_find_cell(*this); if (settings::run_mode != RunMode::PLOTTING && (!found)) { // If a cell is still not found, there are two possible causes: 1) there is @@ -704,16 +468,16 @@ void Particle::cross_surface(const Surface& surf) // the particle is really traveling tangent to a surface, if we move it // forward a tiny bit it should fix the problem. - surface() = SURFACE_NONE; + surface() = 0; n_coord() = 1; r() += TINY_BIT * u(); // Couldn't find next cell anywhere! This probably means there is an actual // undefined region in the geometry. - if (!exhaustive_find_cell(*this, verbose)) { + if (!exhaustive_find_cell(*this)) { mark_as_lost("After particle " + std::to_string(id()) + - " crossed surface " + std::to_string(surf.id_) + + " crossed surface " + std::to_string(surf->id_) + " it could not be located in any cell and it did not leak."); return; } @@ -731,7 +495,7 @@ void Particle::cross_vacuum_bc(const Surface& surf) // physically moving the particle forward slightly r() += TINY_BIT * u(); - score_meshsurface_tally(*this, model::active_meshsurf_tallies); + score_surface_tally(*this, model::active_meshsurf_tallies); } // Score to global leakage tally @@ -763,15 +527,13 @@ void Particle::cross_reflective_bc(const Surface& surf, Direction new_u) // with a mesh boundary if (!model::active_surface_tallies.empty()) { - Direction normal = surf.normal(r()); - normal /= normal.norm(); - score_surface_tally(*this, model::active_surface_tallies, normal); + score_surface_tally(*this, model::active_surface_tallies); } if (!model::active_meshsurf_tallies.empty()) { Position r {this->r()}; this->r() -= TINY_BIT * u(); - score_meshsurface_tally(*this, model::active_meshsurf_tallies); + score_surface_tally(*this, model::active_meshsurf_tallies); this->r() = r; } @@ -779,7 +541,7 @@ void Particle::cross_reflective_bc(const Surface& surf, Direction new_u) u() = new_u; // Reassign particle's cell and surface - coord(0).cell() = cell_last(0); + coord(0).cell = cell_last(n_coord_last() - 1); surface() = -surface(); // If a reflective surface is coincident with a lattice or universe @@ -787,10 +549,9 @@ void Particle::cross_reflective_bc(const Surface& surf, Direction new_u) // the lower universes. // (unless we're using a dagmc model, which has exactly one universe) n_coord() = 1; - if (surf.geom_type() != GeometryType::DAG && - !neighbor_list_find_cell(*this)) { - mark_as_lost("Couldn't find particle after reflecting from surface " + - std::to_string(surf.id_) + "."); + if (surf.geom_type_ != GeometryType::DAG && !neighbor_list_find_cell(*this)) { + this->mark_as_lost("Couldn't find particle after reflecting from surface " + + std::to_string(surf.id_) + "."); return; } @@ -821,7 +582,7 @@ void Particle::cross_periodic_bc( if (!model::active_meshsurf_tallies.empty()) { Position r {this->r()}; this->r() -= TINY_BIT * u(); - score_meshsurface_tally(*this, model::active_meshsurf_tallies); + score_surface_tally(*this, model::active_meshsurf_tallies); this->r() = r; } @@ -838,7 +599,9 @@ void Particle::cross_periodic_bc( if (!neighbor_list_find_cell(*this)) { mark_as_lost("Couldn't find particle after hitting periodic " "boundary on surface " + - std::to_string(surf.id_) + "."); + std::to_string(surf.id_) + + ". The normal vector " + "of one periodic surface may need to be reversed."); return; } @@ -855,10 +618,8 @@ void Particle::mark_as_lost(const char* message) { // Print warning and write lost particle file warning(message); - if (settings::max_write_lost_particles < 0 || - simulation::n_lost_particles < settings::max_write_lost_particles) { - write_restart(); - } + write_restart(); + // Increment number of lost particles wgt() = 0.0; #pragma omp atomic @@ -918,143 +679,64 @@ void Particle::write_restart() const break; } write_dataset(file_id, "id", id()); - write_dataset(file_id, "type", type().pdg_number()); + write_dataset(file_id, "type", static_cast(type())); - // Get source site data for the particle that got lost int64_t i = current_work(); - SourceSite site; if (settings::run_mode == RunMode::EIGENVALUE) { - site = simulation::source_bank[i]; - } else if (settings::run_mode == RunMode::FIXED_SOURCE && - settings::use_shared_secondary_bank && - i < simulation::shared_secondary_bank_read.size()) { - site = simulation::shared_secondary_bank_read[i]; + // take source data from primary bank for eigenvalue simulation + write_dataset(file_id, "weight", simulation::source_bank[i - 1].wgt); + write_dataset(file_id, "energy", simulation::source_bank[i - 1].E); + write_dataset(file_id, "xyz", simulation::source_bank[i - 1].r); + write_dataset(file_id, "uvw", simulation::source_bank[i - 1].u); + write_dataset(file_id, "time", simulation::source_bank[i - 1].time); } else if (settings::run_mode == RunMode::FIXED_SOURCE) { - // Re-sample using the same seed used to generate the source particle. - // current_work() is 0-indexed, compute_particle_id expects 1-indexed. - int64_t id = compute_transport_seed(compute_particle_id(i + 1)); + // re-sample using rng random number seed used to generate source particle + int64_t id = (simulation::total_gen + overall_generation() - 1) * + settings::n_particles + + simulation::work_index[mpi::rank] + i; uint64_t seed = init_seed(id, STREAM_SOURCE); - site = sample_external_source(&seed); + // re-sample source site + auto site = sample_external_source(&seed); + write_dataset(file_id, "weight", site.wgt); + write_dataset(file_id, "energy", site.E); + write_dataset(file_id, "xyz", site.r); + write_dataset(file_id, "uvw", site.u); + write_dataset(file_id, "time", site.time); } - write_dataset(file_id, "weight", site.wgt); - write_dataset(file_id, "energy", site.E); - write_dataset(file_id, "xyz", site.r); - write_dataset(file_id, "uvw", site.u); - write_dataset(file_id, "time", site.time); // Close file file_close(file_id); } // #pragma omp critical } -void Particle::update_neutron_xs( - int i_nuclide, int i_grid, int i_sab, double sab_frac, double ncrystal_xs) +std::string particle_type_to_str(ParticleType type) { - // Get microscopic cross section cache - auto& micro = this->neutron_xs(i_nuclide); - - // If the cache doesn't match, recalculate micro xs - if (this->E() != micro.last_E || this->sqrtkT() != micro.last_sqrtkT || - i_sab != micro.index_sab || sab_frac != micro.sab_frac || - ncrystal_xs != micro.ncrystal_xs) { - data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, *this); - - // If NCrystal is being used, update micro cross section cache - micro.ncrystal_xs = ncrystal_xs; - if (ncrystal_xs >= 0.0) { - data::nuclides[i_nuclide]->calculate_elastic_xs(*this); - ncrystal_update_micro(ncrystal_xs, micro); - } + switch (type) { + case ParticleType::neutron: + return "neutron"; + case ParticleType::photon: + return "photon"; + case ParticleType::electron: + return "electron"; + case ParticleType::positron: + return "positron"; } + UNREACHABLE(); } -//============================================================================== -// Non-method functions -//============================================================================== -void add_surf_source_to_bank(Particle& p, const Surface& surf) +ParticleType str_to_particle_type(std::string str) { - if (simulation::current_batch <= settings::n_inactive || - simulation::surf_source_bank.full()) { - return; + if (str == "neutron") { + return ParticleType::neutron; + } else if (str == "photon") { + return ParticleType::photon; + } else if (str == "electron") { + return ParticleType::electron; + } else if (str == "positron") { + return ParticleType::positron; + } else { + throw std::invalid_argument {fmt::format("Invalid particle name: {}", str)}; } - - // If a cell/cellfrom/cellto parameter is defined - if (settings::ssw_cell_id != C_NONE) { - - // Retrieve cell index and storage type - int cell_idx = model::cell_map[settings::ssw_cell_id]; - - if (surf.bc_) { - // Leave if cellto with vacuum boundary condition - if (surf.bc_->type() == "vacuum" && - settings::ssw_cell_type == SSWCellType::To) { - return; - } - - // Leave if other boundary condition than vacuum - if (surf.bc_->type() != "vacuum") { - return; - } - } - - // Check if the cell of interest has been exited - bool exited = false; - for (int i = 0; i < p.n_coord_last(); ++i) { - if (p.cell_last(i) == cell_idx) { - exited = true; - } - } - - // Check if the cell of interest has been entered - bool entered = false; - for (int i = 0; i < p.n_coord(); ++i) { - if (p.coord(i).cell() == cell_idx) { - entered = true; - } - } - - // Vacuum boundary conditions: return if cell is not exited - if (surf.bc_) { - if (surf.bc_->type() == "vacuum" && !exited) { - return; - } - } else { - - // If we both enter and exit the cell of interest - if (entered && exited) { - return; - } - - // If we did not enter nor exit the cell of interest - if (!entered && !exited) { - return; - } - - // If cellfrom and the cell before crossing is not the cell of - // interest - if (settings::ssw_cell_type == SSWCellType::From && !exited) { - return; - } - - // If cellto and the cell after crossing is not the cell of interest - if (settings::ssw_cell_type == SSWCellType::To && !entered) { - return; - } - } - } - - SourceSite site; - site.r = p.r(); - site.u = p.u(); - site.E = p.E(); - site.time = p.time(); - site.wgt = p.wgt(); - site.delayed_group = p.delayed_group(); - site.surf_id = surf.id_; - site.particle = p.type(); - site.parent_id = p.id(); - site.progeny_id = p.n_progeny(); - int64_t idx = simulation::surf_source_bank.thread_safe_append(site); } } // namespace openmc diff --git a/src/particle_data.cpp b/src/particle_data.cpp index 370ca12e4..a2be72084 100644 --- a/src/particle_data.cpp +++ b/src/particle_data.cpp @@ -1,9 +1,6 @@ #include "openmc/particle_data.h" -#include - #include "openmc/cell.h" -#include "openmc/error.h" #include "openmc/geometry.h" #include "openmc/material.h" #include "openmc/nuclide.h" @@ -15,83 +12,31 @@ namespace openmc { -void GeometryState::mark_as_lost(const char* message) -{ - fatal_error(message); -} - -void GeometryState::mark_as_lost(const std::string& message) -{ - mark_as_lost(message.c_str()); -} - -void GeometryState::mark_as_lost(const std::stringstream& message) -{ - mark_as_lost(message.str()); -} - void LocalCoord::rotate(const vector& rotation) { - r_ = r_.rotate(rotation); - u_ = u_.rotate(rotation); - rotated_ = true; + r = r.rotate(rotation); + u = u.rotate(rotation); + rotated = true; } void LocalCoord::reset() { - cell_ = C_NONE; - universe_ = C_NONE; - lattice_ = C_NONE; - lattice_index_[0] = 0; - lattice_index_[1] = 0; - lattice_index_[2] = 0; - rotated_ = false; + cell = C_NONE; + universe = C_NONE; + lattice = C_NONE; + lattice_i[0] = 0; + lattice_i[1] = 0; + lattice_i[2] = 0; + rotated = false; } -GeometryState::GeometryState() +ParticleData::ParticleData() { // Create and clear coordinate levels coord_.resize(model::n_coord_levels); cell_last_.resize(model::n_coord_levels); clear(); -} -void GeometryState::advance_to_boundary_from_void() -{ - auto root_coord = this->coord(0); - const auto& root_universe = model::universes[model::root_universe]; - boundary().reset(); - - for (auto c_i : root_universe->cells_) { - auto dist = - model::cells.at(c_i)->distance(root_coord.r(), root_coord.u(), 0, this); - if (dist.first < boundary().distance()) { - boundary().distance() = dist.first; - boundary().surface() = dist.second; - } - } - - // if no intersection or near-infinite intersection, reset - // boundary information - if (boundary().distance() > 1e300) { - boundary().distance() = INFTY; - boundary().surface() = SURFACE_NONE; - return; - } - - // move the particle up to (and just past) the boundary - move_distance(boundary().distance() + TINY_BIT); -} - -void GeometryState::move_distance(double length) -{ - for (int j = 0; j < n_coord(); ++j) { - coord(j).r() += length * coord(j).u(); - } -} - -ParticleData::ParticleData() -{ zero_delayed_bank(); // Every particle starts with no accumulated flux derivative. Note that in @@ -108,11 +53,6 @@ ParticleData::ParticleData() // Create microscopic cross section caches neutron_xs_.resize(data::nuclides.size()); photon_xs_.resize(data::elements.size()); - - // Creates the pulse-height storage for the particle - if (!model::pulse_height_cells.empty()) { - pht_storage_.resize(model::pulse_height_cells.size(), 0.0); - } } TrackState ParticleData::get_track_state() const @@ -123,7 +63,7 @@ TrackState ParticleData::get_track_state() const state.E = this->E(); state.time = this->time(); state.wgt = this->wgt(); - state.cell_id = model::cells[this->lowest_coord().cell()]->id_; + state.cell_id = model::cells[this->lowest_coord().cell]->id_; state.cell_instance = this->cell_instance(); if (this->material() != MATERIAL_VOID) { state.material_id = model::materials[material()]->id_; diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index c226d51ec..32d187dd8 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -1,7 +1,6 @@ #include "openmc/particle_restart.h" #include "openmc/array.h" -#include "openmc/bank.h" #include "openmc/constants.h" #include "openmc/hdf5_interface.h" #include "openmc/mgxs_interface.h" @@ -32,16 +31,6 @@ void read_particle_restart(Particle& p, RunMode& previous_run_mode) hid_t file_id = file_open(settings::path_particle_restart, 'r'); // Read data from file - bool legacy_particle_codes = true; - if (attribute_exists(file_id, "version")) { - array version; - read_attribute(file_id, "version", version); - if (version[0] > VERSION_PARTICLE_RESTART[0] || - (version[0] == VERSION_PARTICLE_RESTART[0] && version[1] >= 1)) { - legacy_particle_codes = false; - } - } - read_dataset(file_id, "current_batch", simulation::current_batch); read_dataset(file_id, "generations_per_batch", settings::gen_per_batch); read_dataset(file_id, "current_generation", simulation::current_gen); @@ -56,8 +45,7 @@ void read_particle_restart(Particle& p, RunMode& previous_run_mode) read_dataset(file_id, "id", p.id()); int type; read_dataset(file_id, "type", type); - p.type() = legacy_particle_codes ? legacy_particle_index_to_type(type) - : ParticleType {type}; + p.type() = static_cast(type); read_dataset(file_id, "weight", p.wgt()); read_dataset(file_id, "energy", p.E()); read_dataset(file_id, "xyz", p.r()); @@ -99,24 +87,26 @@ void run_particle_restart() read_particle_restart(p, previous_run_mode); // write track if that was requested on command line - if (settings::write_all_tracks) { - open_track_file(); + if (settings::write_all_tracks) p.write_track() = true; - } // Set all tallies to 0 for now (just tracking errors) model::tallies.clear(); - // Allocate progeny_per_particle if needed for shared secondary mode - // (event_death() writes to this array). Set current_work to 0 since we - // only have one particle being restarted. - if (settings::use_shared_secondary_bank) { - p.current_work() = 0; - simulation::progeny_per_particle.resize(1, 0); - } - // Compute random number seed - int64_t particle_seed = compute_transport_seed(p.id()); + int64_t particle_seed; + switch (previous_run_mode) { + case RunMode::EIGENVALUE: + case RunMode::FIXED_SOURCE: + particle_seed = (simulation::total_gen + overall_generation() - 1) * + settings::n_particles + + p.id(); + break; + default: + throw std::runtime_error { + "Unexpected run mode: " + + std::to_string(static_cast(previous_run_mode))}; + } init_particle_seeds(particle_seed, p.seeds()); // Force calculation of cross-sections by setting last energy to zero @@ -133,10 +123,6 @@ void run_particle_restart() // Write output if particle made it print_particle(p); - - if (settings::write_all_tracks) { - close_track_file(); - } } } // namespace openmc diff --git a/src/particle_type.cpp b/src/particle_type.cpp deleted file mode 100644 index fe8f9fe2a..000000000 --- a/src/particle_type.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include "openmc/particle_type.h" - -#include -#include -#include - -#include "openmc/string_utils.h" - -namespace openmc { -namespace { - -constexpr const char* ATOMIC_SYMBOL[] = {"", "H", "He", "Li", "Be", "B", "C", - "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", - "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", - "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", - "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", - "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", - "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", - "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", - "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", - "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og"}; - -constexpr int MAX_Z = - static_cast(sizeof(ATOMIC_SYMBOL) / sizeof(ATOMIC_SYMBOL[0])) - 1; - -bool is_integer_string(const std::string& s) -{ - if (s.empty()) - return false; - size_t i = 0; - if (s[0] == '-' || s[0] == '+') { - if (s.size() == 1) - return false; - i = 1; - } - for (; i < s.size(); ++i) { - if (!std::isdigit(static_cast(s[i]))) - return false; - } - return true; -} - -int atomic_number_from_symbol(std::string_view symbol) -{ - for (int z = 1; z <= MAX_Z; ++z) { - if (symbol == ATOMIC_SYMBOL[z]) { - return z; - } - } - return 0; -} - -bool parse_gnds_nuclide(std::string_view name, int& Z, int& A, int& m) -{ - if (name.empty()) - return false; - - size_t pos = 0; - if (!std::isupper(static_cast(name[pos]))) - return false; - - std::string symbol; - symbol += name[pos++]; - if (pos < name.size() && - std::islower(static_cast(name[pos]))) { - symbol += name[pos++]; - } - - if (pos >= name.size() || - !std::isdigit(static_cast(name[pos]))) { - return false; - } - - size_t a_start = pos; - while ( - pos < name.size() && std::isdigit(static_cast(name[pos]))) { - ++pos; - } - A = std::stoi(std::string {name.substr(a_start, pos - a_start)}); - if (A <= 0 || A > 999) - return false; - - m = 0; - if (pos < name.size()) { - if (name[pos] != '_' || pos + 2 >= name.size() || name[pos + 1] != 'm') { - return false; - } - pos += 2; - size_t m_start = pos; - while (pos < name.size() && - std::isdigit(static_cast(name[pos]))) { - ++pos; - } - if (m_start == pos) - return false; - m = std::stoi(std::string {name.substr(m_start, pos - m_start)}); - if (m < 0 || m > 9) - return false; - } - - if (pos != name.size()) - return false; - - Z = atomic_number_from_symbol(symbol); - return Z != 0; -} - -// Helper to convert nuclear PDG number to nuclide name -std::string nuclide_name_from_pdg(int32_t pdg) -{ - int32_t code = pdg; - int m = code % 10; - int A = (code / 10) % 1000; - int Z = (code / 10000) % 1000; - - if (Z <= 0 || Z > MAX_Z || A <= 0 || A > 999) { - throw std::invalid_argument { - "Invalid nuclear PDG number: " + std::to_string(pdg)}; - } - - std::string name = ATOMIC_SYMBOL[Z] + std::to_string(A); - if (m > 0) { - name += "_m" + std::to_string(m); - } - return name; -} - -} // namespace - -//============================================================================== -// ParticleType member function implementations -//============================================================================== - -ParticleType::ParticleType(std::string_view str) -{ - std::string s {str}; - strtrim(s); - if (s.empty()) { - throw std::invalid_argument {"Particle string is empty."}; - } - - std::string lower = s; - to_lower(lower); - - // Check for pdg: prefix - if (starts_with(lower, "pdg:")) { - std::string value_str = lower.substr(4); - if (!is_integer_string(value_str)) { - throw std::invalid_argument {"Invalid PDG number: " + value_str}; - } - pdg_number_ = std::stoi(value_str); - return; - } - - // Check for known particle names - if (lower == "neutron" || lower == "n") { - pdg_number_ = PDG_NEUTRON; - return; - } - if (lower == "photon" || lower == "gamma") { - pdg_number_ = PDG_PHOTON; - return; - } - if (lower == "electron") { - pdg_number_ = PDG_ELECTRON; - return; - } - if (lower == "positron") { - pdg_number_ = PDG_POSITRON; - return; - } - if (lower == "proton" || lower == "p" || lower == "h1") { - pdg_number_ = PDG_PROTON; - return; - } - if (lower == "deuteron" || lower == "d" || lower == "h2") { - pdg_number_ = PDG_DEUTERON; - return; - } - if (lower == "triton" || lower == "t" || lower == "h3") { - pdg_number_ = PDG_TRITON; - return; - } - if (lower == "alpha" || lower == "he4") { - pdg_number_ = PDG_ALPHA; - return; - } - - // Check for integer string - if (is_integer_string(s)) { - pdg_number_ = std::stoi(s); - return; - } - - // Try to parse as GNDS nuclide name - int Z = 0; - int A = 0; - int m = 0; - if (!parse_gnds_nuclide(s, Z, A, m)) { - throw std::invalid_argument {"Invalid nuclide name: " + s}; - } - pdg_number_ = 1000000000 + Z * 10000 + A * 10 + m; -} - -std::string ParticleType::str() const -{ - if (pdg_number_ == PDG_NEUTRON) - return "neutron"; - if (pdg_number_ == PDG_PHOTON) - return "photon"; - if (pdg_number_ == PDG_ELECTRON) - return "electron"; - if (pdg_number_ == PDG_POSITRON) - return "positron"; - if (pdg_number_ == PDG_PROTON) - return "proton"; - - if (is_nucleus()) { - return nuclide_name_from_pdg(pdg_number_); - } - - return "pdg:" + std::to_string(pdg_number_); -} - -//============================================================================== -// Free function implementations -//============================================================================== - -ParticleType legacy_particle_index_to_type(int index) -{ - switch (index) { - case 0: - return ParticleType {PDG_NEUTRON}; - case 1: - return ParticleType {PDG_PHOTON}; - case 2: - return ParticleType {PDG_ELECTRON}; - case 3: - return ParticleType {PDG_POSITRON}; - default: - throw std::invalid_argument { - "Invalid legacy particle index: " + std::to_string(index)}; - } -} - -} // namespace openmc diff --git a/src/photon.cpp b/src/photon.cpp index 6bbdc928f..2f9bc5e3d 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -13,7 +13,11 @@ #include "openmc/search.h" #include "openmc/settings.h" -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xoperation.hpp" +#include "xtensor/xslice.hpp" +#include "xtensor/xview.hpp" #include #include @@ -29,7 +33,7 @@ constexpr int PhotonInteraction::MAX_STACK_SIZE; namespace data { -tensor::Tensor compton_profile_pz; +xt::xtensor compton_profile_pz; std::unordered_map element_map; vector> elements; @@ -42,6 +46,8 @@ vector> elements; PhotonInteraction::PhotonInteraction(hid_t group) { + using namespace xt::placeholders; + // Set index of element in global vector index_ = data::elements.size(); @@ -85,13 +91,9 @@ PhotonInteraction::PhotonInteraction(hid_t group) close_group(rgroup); // Read pair production - if (object_exists(group, "pair_production_electron")) { - rgroup = open_group(group, "pair_production_electron"); - read_dataset(rgroup, "xs", pair_production_electron_); - close_group(rgroup); - } else { - pair_production_electron_ = tensor::zeros_like(energy_); - } + rgroup = open_group(group, "pair_production_electron"); + read_dataset(rgroup, "xs", pair_production_electron_); + close_group(rgroup); // Read pair production if (object_exists(group, "pair_production_nuclear")) { @@ -99,7 +101,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) read_dataset(rgroup, "xs", pair_production_nuclear_); close_group(rgroup); } else { - pair_production_nuclear_ = tensor::zeros_like(energy_); + pair_production_nuclear_ = xt::zeros_like(energy_); } // Read photoelectric @@ -113,7 +115,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) read_dataset(rgroup, "xs", heating_); close_group(rgroup); } else { - heating_ = tensor::zeros_like(energy_); + heating_ = xt::zeros_like(energy_); } // Read subshell photoionization cross section and atomic relaxation data @@ -127,7 +129,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) } shells_.resize(n_shell); - cross_sections_ = tensor::zeros({energy_.size(), n_shell}); + cross_sections_ = xt::zeros({energy_.size(), n_shell}); // Create mapping from designator to index std::unordered_map shell_map; @@ -152,28 +154,23 @@ PhotonInteraction::PhotonInteraction(hid_t group) // TODO: Move to ElectronSubshell constructor + // Read binding energy and number of electrons hid_t tgroup = open_group(rgroup, designator.c_str()); - - // Read binding energy if atomic relaxation data is present - if (attribute_exists(tgroup, "binding_energy")) { - has_atomic_relaxation_ = true; - read_attribute(tgroup, "binding_energy", shell.binding_energy); - } + read_attribute(tgroup, "binding_energy", shell.binding_energy); + read_attribute(tgroup, "num_electrons", shell.n_electrons); // Read subshell cross section - tensor::Tensor xs; + xt::xtensor xs; dset = open_dataset(tgroup, "xs"); read_attribute(dset, "threshold_idx", shell.threshold); close_dataset(dset); read_dataset(tgroup, "xs", xs); auto cross_section = - cross_sections_.slice(tensor::range(static_cast(shell.threshold), - cross_sections_.shape(0)), - i); - cross_section = tensor::where(xs > 0, tensor::log(xs), 0); + xt::view(cross_sections_, xt::range(shell.threshold, _), i); + cross_section = xt::where(xs > 0, xt::log(xs), 0); - if (settings::atomic_relaxation && object_exists(tgroup, "transitions")) { + if (object_exists(tgroup, "transitions")) { // Determine dimensions of transitions dset = open_dataset(tgroup, "transitions"); auto dims = object_shape(dset); @@ -181,12 +178,11 @@ PhotonInteraction::PhotonInteraction(hid_t group) int n_transition = dims[0]; if (n_transition > 0) { - tensor::Tensor matrix; + xt::xtensor matrix; read_dataset(tgroup, "transitions", matrix); // Transition probability normalization - double norm = - tensor::Tensor(matrix.slice(tensor::all, 3)).sum(); + double norm = xt::sum(xt::col(matrix, 3))(); shell.transitions.resize(n_transition); for (int j = 0; j < n_transition; ++j) { @@ -205,8 +201,9 @@ PhotonInteraction::PhotonInteraction(hid_t group) // Check the maximum size of the atomic relaxation stack auto max_size = this->calc_max_stack_size(); if (max_size > MAX_STACK_SIZE && mpi::master) { - warning(fmt::format("The subshell vacancy stack in atomic relaxation can " - "grow up to {}, but the stack size limit is set to {}.", + warning(fmt::format( + "The subshell vacancy stack in atomic relaxation can grow up to {}, but " + "the stack size limit is set to {}.", max_size, MAX_STACK_SIZE)); } @@ -215,7 +212,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) // Read electron shell PDF and binding energies read_dataset(rgroup, "num_electrons", electron_pdf_); - electron_pdf_ /= electron_pdf_.sum(); + electron_pdf_ /= xt::sum(electron_pdf_); read_dataset(rgroup, "binding_energy", binding_energy_); // Read Compton profiles @@ -227,33 +224,10 @@ PhotonInteraction::PhotonInteraction(hid_t group) } close_group(rgroup); - // Map Compton subshell data to atomic relaxation data by finding the - // subshell with the equivalent binding energy - if (settings::atomic_relaxation && has_atomic_relaxation_) { - auto is_close = [](double a, double b) { - return std::abs(a - b) / a < FP_REL_PRECISION; - }; - subshell_map_ = tensor::Tensor(binding_energy_.shape(), -1); - for (int i = 0; i < binding_energy_.size(); ++i) { - double E_b = binding_energy_[i]; - if (i < n_shell && is_close(E_b, shells_[i].binding_energy)) { - subshell_map_[i] = i; - } else { - for (int j = 0; j < n_shell; ++j) { - if (is_close(E_b, shells_[j].binding_energy)) { - subshell_map_[i] = j; - break; - } - } - } - } - } - // Create Compton profile CDF auto n_profile = data::compton_profile_pz.size(); - auto n_shell_compton = profile_pdf_.shape(0); - profile_cdf_ = tensor::Tensor({n_shell_compton, n_profile}); - for (int i = 0; i < n_shell_compton; ++i) { + profile_cdf_ = xt::empty({n_shell, n_profile}); + for (int i = 0; i < profile_pdf_.shape(0); ++i) { double c = 0.0; profile_cdf_(i, 0) = 0.0; for (int j = 0; j < n_profile - 1; ++j) { @@ -271,11 +245,11 @@ PhotonInteraction::PhotonInteraction(hid_t group) // Read bremsstrahlung scaled DCS rgroup = open_group(group, "bremsstrahlung"); read_dataset(rgroup, "dcs", dcs_); - auto n_e = dcs_.shape(0); - auto n_k = dcs_.shape(1); + auto n_e = dcs_.shape()[0]; + auto n_k = dcs_.shape()[1]; // Get energy grids used for bremsstrahlung DCS and for stopping powers - tensor::Tensor electron_energy; + xt::xtensor electron_energy; read_dataset(rgroup, "electron_energy", electron_energy); if (data::ttb_k_grid.size() == 0) { read_dataset(rgroup, "photon_energy", data::ttb_k_grid); @@ -288,7 +262,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) close_group(rgroup); // Truncate the bremsstrahlung data at the cutoff energy - int photon = ParticleType::photon().transport_index(); + int photon = static_cast(ParticleType::photon); const auto& E {electron_energy}; double cutoff = settings::energy_cutoff[photon]; if (cutoff > E(0)) { @@ -300,12 +274,12 @@ PhotonInteraction::PhotonInteraction(hid_t group) (std::log(E(i_grid + 1)) - std::log(E(i_grid))); // Interpolate bremsstrahlung DCS at the cutoff energy and truncate - tensor::Tensor dcs({n_e - i_grid, n_k}); + xt::xtensor dcs({n_e - i_grid, n_k}); for (int i = 0; i < n_k; ++i) { double y = std::exp( std::log(dcs_(i_grid, i)) + f * (std::log(dcs_(i_grid + 1, i)) - std::log(dcs_(i_grid, i)))); - tensor::View col_i = dcs.slice(tensor::all, i); + auto col_i = xt::view(dcs, xt::all(), i); col_i(0) = y; for (int j = i_grid + 1; j < n_e; ++j) { col_i(j - i_grid) = dcs_(j, i); @@ -313,11 +287,9 @@ PhotonInteraction::PhotonInteraction(hid_t group) } dcs_ = dcs; - tensor::Tensor frst({static_cast(1)}); - frst(0) = cutoff; - tensor::Tensor rest(electron_energy.slice( - tensor::range(i_grid + 1, electron_energy.size()))); - electron_energy = tensor::concatenate(frst, rest); + xt::xtensor frst {cutoff}; + electron_energy = xt::concatenate(xt::xtuple( + frst, xt::view(electron_energy, xt::range(i_grid + 1, n_e)))); } // Set incident particle energy grid @@ -326,8 +298,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) } // Calculate the radiative stopping power - stopping_power_radiative_ = - tensor::Tensor({data::ttb_e_grid.size()}); + stopping_power_radiative_ = xt::empty({data::ttb_e_grid.size()}); for (int i = 0; i < data::ttb_e_grid.size(); ++i) { // Integrate over reduced photon energy double c = 0.0; @@ -347,20 +318,15 @@ PhotonInteraction::PhotonInteraction(hid_t group) } // Take logarithm of energies and cross sections since they are log-log - // interpolated. Note that cross section libraries converted from ACE files - // represent zero as exp(-500) to avoid log-log interpolation errors. For - // values below exp(-499) we store the log as -900, for which exp(-900) - // evaluates to zero. - double limit = std::exp(-499.0); - energy_ = tensor::log(energy_); - coherent_ = tensor::where(coherent_ > limit, tensor::log(coherent_), -900.0); - incoherent_ = - tensor::where(incoherent_ > limit, tensor::log(incoherent_), -900.0); - photoelectric_total_ = tensor::where( - photoelectric_total_ > limit, tensor::log(photoelectric_total_), -900.0); - pair_production_total_ = tensor::where(pair_production_total_ > limit, - tensor::log(pair_production_total_), -900.0); - heating_ = tensor::where(heating_ > limit, tensor::log(heating_), -900.0); + // interpolated + energy_ = xt::log(energy_); + coherent_ = xt::where(coherent_ > 0.0, xt::log(coherent_), -500.0); + incoherent_ = xt::where(incoherent_ > 0.0, xt::log(incoherent_), -500.0); + photoelectric_total_ = xt::where( + photoelectric_total_ > 0.0, xt::log(photoelectric_total_), -500.0); + pair_production_total_ = xt::where( + pair_production_total_ > 0.0, xt::log(pair_production_total_), -500.0); + heating_ = xt::where(heating_ > 0.0, xt::log(heating_), -500.0); } PhotonInteraction::~PhotonInteraction() @@ -511,7 +477,7 @@ void PhotonInteraction::compton_doppler( c = prn(seed) * c_max; // Determine pz corresponding to sampled cdf value - tensor::View cdf_shell = profile_cdf_.slice(shell); + auto cdf_shell = xt::view(profile_cdf_, shell, xt::all()); int i = lower_bound_index(cdf_shell.cbegin(), cdf_shell.cend(), c); double pz_l = data::compton_profile_pz(i); double pz_r = data::compton_profile_pz(i + 1); @@ -607,8 +573,8 @@ void PhotonInteraction::calculate_xs(Particle& p) const // Calculate microscopic photoelectric cross section xs.photoelectric = 0.0; - tensor::View xs_lower = cross_sections_.slice(i_grid); - tensor::View xs_upper = cross_sections_.slice(i_grid + 1); + const auto& xs_lower = xt::row(cross_sections_, i_grid); + const auto& xs_upper = xt::row(cross_sections_, i_grid + 1); for (int i = 0; i < xs_upper.size(); ++i) if (xs_lower(i) != 0) @@ -783,11 +749,6 @@ void PhotonInteraction::pair_production(double alpha, double* E_electron, void PhotonInteraction::atomic_relaxation(int i_shell, Particle& p) const { - // Return if no atomic relaxation data is present or if the binding energy is - // larger than the incident particle energy - if (!has_atomic_relaxation_ || shells_[i_shell].binding_energy > p.E()) - return; - // Stack for unprocessed holes left by transitioning electrons int n_holes = 0; array holes; @@ -804,7 +765,7 @@ void PhotonInteraction::atomic_relaxation(int i_shell, Particle& p) const if (shell.transitions.empty()) { Direction u = isotropic_direction(p.current_seed()); double E = shell.binding_energy; - p.create_secondary(p.wgt(), u, E, ParticleType::photon()); + p.create_secondary(p.wgt(), u, E, ParticleType::photon); continue; } @@ -832,13 +793,12 @@ void PhotonInteraction::atomic_relaxation(int i_shell, Particle& p) const holes[n_holes++] = transition.secondary_subshell; // Create auger electron - p.create_secondary( - p.wgt(), u, transition.energy, ParticleType::electron()); + p.create_secondary(p.wgt(), u, transition.energy, ParticleType::electron); } else { // Radiative transition -- get X-ray energy // Create fluorescent photon - p.create_secondary(p.wgt(), u, transition.energy, ParticleType::photon()); + p.create_secondary(p.wgt(), u, transition.energy, ParticleType::photon); } } } diff --git a/src/physics.cpp b/src/physics.cpp index 4a8b4d368..bcdcf7ecf 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -2,17 +2,14 @@ #include "openmc/bank.h" #include "openmc/bremsstrahlung.h" -#include "openmc/chain.h" #include "openmc/constants.h" #include "openmc/distribution_multi.h" #include "openmc/eigenvalue.h" #include "openmc/endf.h" #include "openmc/error.h" -#include "openmc/ifp.h" #include "openmc/material.h" #include "openmc/math_functions.h" #include "openmc/message_passing.h" -#include "openmc/ncrystal_interface.h" #include "openmc/nuclide.h" #include "openmc/photon.h" #include "openmc/physics_common.h" @@ -30,9 +27,9 @@ #include -#include "openmc/tensor.h" #include // for max, min, max_element #include // for sqrt, exp, log, abs, copysign +#include namespace openmc { @@ -44,41 +41,32 @@ void collision(Particle& p) { // Add to collision counter for particle ++(p.n_collision()); - p.secondary_bank_index() = p.local_secondary_bank().size(); // Sample reaction for the material the particle is in - switch (p.type().pdg_number()) { - case PDG_NEUTRON: + switch (p.type()) { + case ParticleType::neutron: sample_neutron_reaction(p); + if (settings::weight_windows_on) { + apply_weight_windows(p); + } break; - case PDG_PHOTON: + case ParticleType::photon: sample_photon_reaction(p); + if (settings::weight_windows_on) { + apply_weight_windows(p); + } break; - case PDG_ELECTRON: + case ParticleType::electron: sample_electron_reaction(p); break; - case PDG_POSITRON: + case ParticleType::positron: sample_positron_reaction(p); break; - default: - fatal_error("Unsupported particle PDG for collision sampling."); - } - - if (settings::weight_windows_on) { - auto [ww_found, ww] = search_weight_window(p); - if (!ww_found && p.type() == ParticleType::neutron()) { - // if the weight window is not valid, apply russian roulette for neutrons - // (regardless of weight window collision checkpoint setting) - apply_russian_roulette(p); - } else if (settings::weight_window_checkpoint_collision) { - // if collision checkpointing is on, apply weight window - apply_weight_window(p, ww); - } } // Kill particle if energy falls below cutoff - int type = p.type().transport_index(); - if (type != C_NONE && p.E() < settings::energy_cutoff[type]) { + int type = static_cast(p.type()); + if (p.E() < settings::energy_cutoff[type]) { p.wgt() = 0.0; } @@ -87,11 +75,11 @@ void collision(Particle& p) std::string msg; if (p.event() == TallyEvent::KILL) { msg = fmt::format(" Killed. Energy = {} eV.", p.E()); - } else if (p.type().is_neutron()) { + } else if (p.type() == ParticleType::neutron) { msg = fmt::format(" {} with {}. Energy = {} eV.", reaction_name(p.event_mt()), data::nuclides[p.event_nuclide()]->name_, p.E()); - } else if (p.type().is_photon()) { + } else if (p.type() == ParticleType::photon) { msg = fmt::format(" {} with {}. Energy = {} eV.", reaction_name(p.event_mt()), to_element(data::nuclides[p.event_nuclide()]->name_), p.E()); @@ -117,7 +105,7 @@ void sample_neutron_reaction(Particle& p) const auto& nuc {data::nuclides[i_nuclide]}; - if (nuc->fissionable_ && p.neutron_xs(i_nuclide).fission > 0.0) { + if (nuc->fissionable_) { auto& rx = sample_fission(i_nuclide, p); if (settings::run_mode == RunMode::EIGENVALUE) { create_fission_sites(p, i_nuclide, rx); @@ -127,15 +115,13 @@ void sample_neutron_reaction(Particle& p) // Make sure particle population doesn't grow out of control for // subcritical multiplication problems. - if (p.local_secondary_bank().size() >= settings::max_secondaries && - !settings::use_shared_secondary_bank) { + if (p.secondary_bank().size() >= 10000) { fatal_error( "The secondary particle bank appears to be growing without " "bound. You are likely running a subcritical multiplication problem " "with k-effective close to or greater than one."); } } - p.event_mt() = rx.mt_; } // Create secondary photons @@ -154,21 +140,21 @@ void sample_neutron_reaction(Particle& p) // Sample a scattering reaction and determine the secondary energy of the // exiting neutron - const auto& ncrystal_mat = model::materials[p.material()]->ncrystal_mat(); - if (ncrystal_mat && p.E() < NCRYSTAL_MAX_ENERGY) { - ncrystal_mat.scatter(p); - } else { - scatter(p, i_nuclide); - } + scatter(p, i_nuclide); // Advance URR seed stream 'N' times after energy changes if (p.E() != p.E_last()) { - advance_prn_seed(data::nuclides.size(), &p.seeds(STREAM_URR_PTABLE)); + p.stream() = STREAM_URR_PTABLE; + advance_prn_seed(data::nuclides.size(), p.current_seed()); + p.stream() = STREAM_TRACKING; } - // Play russian roulette if there are no weight windows - if (!settings::weight_windows_on) - apply_russian_roulette(p); + // Play russian roulette if survival biasing is turned on + if (settings::survival_biasing) { + if (p.wgt() < settings::weight_cutoff) { + russian_roulette(p, settings::weight_survive); + } + } } void create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) @@ -212,25 +198,15 @@ void create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) // Initialize fission site object with particle data SourceSite site; site.r = p.r(); - site.particle = ParticleType::neutron(); + site.particle = ParticleType::neutron; site.time = p.time(); site.wgt = 1. / weight; + site.parent_id = p.id(); + site.progeny_id = p.n_progeny()++; site.surf_id = 0; // Sample delayed group and angle/energy for fission reaction - sample_fission_neutron(i_nuclide, rx, &site, p); - - // Reject site if it exceeds time cutoff - if (site.delayed_group > 0) { - double t_cutoff = settings::time_cutoff[site.particle.transport_index()]; - if (site.time > t_cutoff) { - continue; - } - } - - // Set parent and progeny IDs - site.parent_id = p.current_work(); - site.progeny_id = p.n_progeny()++; + sample_fission_neutron(i_nuclide, rx, p.E(), &site, p.current_seed()); // Store fission site in bank if (use_fission_bank) { @@ -249,28 +225,24 @@ void create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) // Break out of loop as no more sites can be added to fission bank break; } - // Iterated Fission Probability (IFP) method - if (settings::ifp_on) { - ifp(p, idx); - } } else { - site.wgt_born = p.wgt_born(); - site.wgt_ww_born = p.wgt_ww_born(); - site.n_split = p.n_split(); - p.local_secondary_bank().push_back(site); - p.n_secondaries()++; + p.secondary_bank().push_back(site); } + // Set the delayed group on the particle as well + p.delayed_group() = site.delayed_group; + // Increment the number of neutrons born delayed - if (site.delayed_group > 0) { - nu_d[site.delayed_group - 1]++; + if (p.delayed_group() > 0) { + nu_d[p.delayed_group() - 1]++; } // Write fission particles to nuBank - NuBank& nu_bank_entry = p.nu_bank().emplace_back(); - nu_bank_entry.wgt = site.wgt; - nu_bank_entry.E = site.E; - nu_bank_entry.delayed_group = site.delayed_group; + p.nu_bank().emplace_back(); + NuBank* nu_bank_entry = &p.nu_bank().back(); + nu_bank_entry->wgt = site.wgt; + nu_bank_entry->E = site.E; + nu_bank_entry->delayed_group = site.delayed_group; } // If shared fission bank was full, and no fissions could be added, @@ -297,7 +269,7 @@ void sample_photon_reaction(Particle& p) // Kill photon if below energy cutoff -- an extra check is made here because // photons with energy below the cutoff may have been produced by neutrons // reactions or atomic relaxation - int photon = ParticleType::photon().transport_index(); + int photon = static_cast(ParticleType::photon); if (p.E() < settings::energy_cutoff[photon]) { p.E() = 0.0; p.wgt() = 0.0; @@ -320,8 +292,8 @@ void sample_photon_reaction(Particle& p) // Coherent (Rayleigh) scattering prob += micro.coherent; if (prob > cutoff) { - p.mu() = element.rayleigh_scatter(alpha, p.current_seed()); - p.u() = rotate_angle(p.u(), p.mu(), nullptr, p.current_seed()); + double mu = element.rayleigh_scatter(alpha, p.current_seed()); + p.u() = rotate_angle(p.u(), mu, nullptr, p.current_seed()); p.event() = TallyEvent::SCATTER; p.event_mt() = COHERENT; return; @@ -330,10 +302,10 @@ void sample_photon_reaction(Particle& p) // Incoherent (Compton) scattering prob += micro.incoherent; if (prob > cutoff) { - double alpha_out; + double alpha_out, mu; int i_shell; element.compton_scatter( - alpha, true, &alpha_out, &p.mu(), &i_shell, p.current_seed()); + alpha, true, &alpha_out, &mu, &i_shell, p.current_seed()); // Determine binding energy of shell. The binding energy is 0.0 if // doppler broadening is not used. @@ -347,26 +319,25 @@ void sample_photon_reaction(Particle& p) // Create Compton electron double phi = uniform_distribution(0., 2.0 * PI, p.current_seed()); double E_electron = (alpha - alpha_out) * MASS_ELECTRON_EV - e_b; - int electron = ParticleType::electron().transport_index(); + int electron = static_cast(ParticleType::electron); if (E_electron >= settings::energy_cutoff[electron]) { - double mu_electron = (alpha - alpha_out * p.mu()) / + double mu_electron = (alpha - alpha_out * mu) / std::sqrt(alpha * alpha + alpha_out * alpha_out - - 2.0 * alpha * alpha_out * p.mu()); + 2.0 * alpha * alpha_out * mu); Direction u = rotate_angle(p.u(), mu_electron, &phi, p.current_seed()); - p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron()); + p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron); } - // Allow electrons to fill orbital and produce Auger electrons and - // fluorescent photons. Since Compton subshell data does not match atomic - // relaxation data, use the mapping between the data to find the subshell - if (settings::atomic_relaxation && element.has_atomic_relaxation_ && - i_shell >= 0 && element.subshell_map_[i_shell] >= 0) { - element.atomic_relaxation(element.subshell_map_[i_shell], p); + // TODO: Compton subshell data does not match atomic relaxation data + // Allow electrons to fill orbital and produce auger electrons + // and fluorescent photons + if (i_shell >= 0) { + element.atomic_relaxation(i_shell, p); } phi += PI; p.E() = alpha_out * MASS_ELECTRON_EV; - p.u() = rotate_angle(p.u(), p.mu(), &phi, p.current_seed()); + p.u() = rotate_angle(p.u(), mu, &phi, p.current_seed()); p.event() = TallyEvent::SCATTER; p.event_mt() = INCOHERENT; return; @@ -380,9 +351,8 @@ void sample_photon_reaction(Particle& p) // cross sections int i_grid = micro.index_grid; double f = micro.interp_factor; - tensor::View xs_lower = element.cross_sections_.slice(i_grid); - tensor::View xs_upper = - element.cross_sections_.slice(i_grid + 1); + const auto& xs_lower = xt::row(element.cross_sections_, i_grid); + const auto& xs_upper = xt::row(element.cross_sections_, i_grid + 1); for (int i_shell = 0; i_shell < element.shells_.size(); ++i_shell) { const auto& shell {element.shells_[i_shell]}; @@ -396,14 +366,7 @@ void sample_photon_reaction(Particle& p) xs_lower(i_shell) + f * (xs_upper(i_shell) - xs_lower(i_shell))); if (prob > cutoff) { - // Determine binding energy based on whether atomic relaxation data is - // present (if not, use value from Compton profile data) - double binding_energy = element.has_atomic_relaxation_ - ? shell.binding_energy - : element.binding_energy_[i_shell]; - - // Determine energy of secondary electron - double E_electron = p.E() - binding_energy; + double E_electron = p.E() - shell.binding_energy; // Sample mu using non-relativistic Sauter distribution. // See Eqns 3.19 and 3.20 in "Implementing a photon physics @@ -428,13 +391,11 @@ void sample_photon_reaction(Particle& p) u.z = std::sqrt(1.0 - mu * mu) * std::sin(phi); // Create secondary electron - p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron()); + p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron); // Allow electrons to fill orbital and produce auger electrons // and fluorescent photons - if (settings::atomic_relaxation) { - element.atomic_relaxation(i_shell, p); - } + element.atomic_relaxation(i_shell, p); p.event() = TallyEvent::ABSORB; p.event_mt() = 533 + shell.index_subshell; p.wgt() = 0.0; @@ -455,11 +416,12 @@ void sample_photon_reaction(Particle& p) // Create secondary electron Direction u = rotate_angle(p.u(), mu_electron, nullptr, p.current_seed()); - p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron()); + p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron); // Create secondary positron u = rotate_angle(p.u(), mu_positron, nullptr, p.current_seed()); - p.create_secondary(p.wgt(), u, E_positron, ParticleType::positron()); + p.create_secondary(p.wgt(), u, E_positron, ParticleType::positron); + p.event() = TallyEvent::ABSORB; p.event_mt() = PAIR_PROD; p.wgt() = 0.0; @@ -494,8 +456,8 @@ void sample_positron_reaction(Particle& p) Direction u = isotropic_direction(p.current_seed()); // Create annihilation photon pair traveling in opposite directions - p.create_secondary(p.wgt(), u, MASS_ELECTRON_EV, ParticleType::photon()); - p.create_secondary(p.wgt(), -u, MASS_ELECTRON_EV, ParticleType::photon()); + p.create_secondary(p.wgt(), u, MASS_ELECTRON_EV, ParticleType::photon); + p.create_secondary(p.wgt(), -u, MASS_ELECTRON_EV, ParticleType::photon); p.E() = 0.0; p.wgt() = 0.0; @@ -515,7 +477,7 @@ int sample_nuclide(Particle& p) for (int i = 0; i < n; ++i) { // Get atom density int i_nuclide = mat->nuclide_[i]; - double atom_density = mat->atom_density(i, p.density_mult()); + double atom_density = mat->atom_density_[i]; // Increment probability to compare to cutoff prob += atom_density * p.neutron_xs(i_nuclide).total; @@ -540,7 +502,7 @@ int sample_element(Particle& p) for (int i = 0; i < mat->element_.size(); ++i) { // Find atom density int i_element = mat->element_[i]; - double atom_density = mat->atom_density(i, p.density_mult()); + double atom_density = mat->atom_density_[i]; // Determine microscopic cross section double sigma = atom_density * p.photon_xs(i_element).total; @@ -620,7 +582,7 @@ void sample_photon_product( continue; for (int j = 0; j < rx->products_.size(); ++j) { - if (rx->products_[j].particle_.is_photon()) { + if (rx->products_[j].particle_ == ParticleType::photon) { // For fission, artificially increase the photon yield to account // for delayed photons double f = 1.0; @@ -675,9 +637,7 @@ void absorption(Particle& p, int i_nuclide) p.wgt() = 0.0; p.event() = TallyEvent::ABSORB; - if (!p.fission()) { - p.event_mt() = N_DISAPPEAR; - } + p.event_mt() = N_DISAPPEAR; } } } @@ -732,10 +692,17 @@ void scatter(Particle& p, int i_nuclide) // ======================================================================= // INELASTIC SCATTERING - int n = nuc->index_inelastic_scatter_.size(); + int j = 0; int i = 0; - for (int j = 0; j < n && prob < cutoff; ++j) { + while (prob < cutoff) { i = nuc->index_inelastic_scatter_[j]; + ++j; + + // Check to make sure inelastic scattering reaction sampled + if (i >= nuc->reactions_.size()) { + p.write_restart(); + fatal_error("Did not sample any reaction for nuclide " + nuc->name_); + } // add to cumulative probability prob += nuc->reactions_[i]->xs(micro); @@ -865,7 +832,7 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, // otherwise, use free gas model } else { - if (E >= settings::free_gas_threshold * kT && nuc.awr_ > 1.0) { + if (E >= FREE_GAS_THRESHOLD * kT && nuc.awr_ > 1.0) { return {}; } else { sampling_method = ResScatMethod::cxs; @@ -1051,13 +1018,9 @@ Direction sample_cxs_target_velocity( return vt * rotate_angle(u, mu, nullptr, seed); } -void sample_fission_neutron( - int i_nuclide, const Reaction& rx, SourceSite* site, Particle& p) +void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, + SourceSite* site, uint64_t* seed) { - // Get attributes of particle - double E_in = p.E(); - uint64_t* seed = p.current_seed(); - // Determine total nu, delayed nu, and delayed neutron fraction const auto& nuc {data::nuclides[i_nuclide]}; double nu_t = nuc->nu(E_in, Nuclide::EmissionMode::total); @@ -1090,10 +1053,6 @@ void sample_fission_neutron( // set the delayed group for the particle born from fission site->delayed_group = group; - // Sample time of emission based on decay constant of precursor - double decay_rate = rx.products_[site->delayed_group].decay_rate_; - site->time -= std::log(prn(p.current_seed())) / decay_rate; - } else { // ==================================================================== // PROMPT NEUTRON SAMPLED @@ -1109,7 +1068,7 @@ void sample_fission_neutron( rx.products_[site->delayed_group].sample(E_in, site->E, mu, seed); // resample if energy is greater than maximum neutron energy - int neutron = ParticleType::neutron().transport_index(); + constexpr int neutron = static_cast(ParticleType::neutron); if (site->E < data::energy_max[neutron]) break; @@ -1124,7 +1083,9 @@ void sample_fission_neutron( } // Sample azimuthal angle uniformly in [0, 2*pi) and assign angle - site->u = rotate_angle(p.u(), mu, nullptr, seed); + // TODO: account for dependence on incident neutron? + Direction ref(1., 0., 0.); + site->u = rotate_angle(ref, mu, nullptr, seed); } void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p) @@ -1166,10 +1127,10 @@ void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p) // evaluate yield double yield = (*rx.products_[0].yield_)(E_in); - if (std::floor(yield) == yield && yield > 0) { + if (std::floor(yield) == yield) { // If yield is integral, create exactly that many secondary particles for (int i = 0; i < static_cast(std::round(yield)) - 1; ++i) { - p.create_secondary(p.wgt(), p.u(), p.E(), ParticleType::neutron()); + p.create_secondary(p.wgt(), p.u(), p.E(), ParticleType::neutron); } } else { // Otherwise, change weight of particle based on yield @@ -1182,21 +1143,9 @@ void sample_secondary_photons(Particle& p, int i_nuclide) // Sample the number of photons produced double y_t = p.neutron_xs(i_nuclide).photon_prod / p.neutron_xs(i_nuclide).total; - double photon_wgt = p.wgt(); - int y = 1; - - if (settings::use_decay_photons) { - // For decay photons, sample a single photon and modify the weight - if (y_t <= 0.0) - return; - photon_wgt *= y_t; - } else { - // For prompt photons, sample an integral number of photons with weight - // equal to the neutron's weight - y = static_cast(y_t); - if (prn(p.current_seed()) <= y_t - y) - ++y; - } + int y = static_cast(y_t); + if (prn(p.current_seed()) <= y_t - y) + ++y; // Sample each secondary photon for (int i = 0; i < y; ++i) { @@ -1219,30 +1168,15 @@ void sample_secondary_photons(Particle& p, int i_nuclide) // release and deposition. See D. P. Griesheimer, S. J. Douglass, and M. H. // Stedry, "Self-consistent energy normalization for quasistatic reactor // calculations", Proc. PHYSOR, Cambridge, UK, Mar 29-Apr 2, 2020. - double wgt = photon_wgt; + double wgt; if (settings::run_mode == RunMode::EIGENVALUE && !is_fission(rx->mt_)) { - wgt *= simulation::keff; + wgt = simulation::keff * p.wgt(); + } else { + wgt = p.wgt(); } // Create the secondary photon - bool created_photon = p.create_secondary(wgt, u, E, ParticleType::photon()); - - // Pre-add photon energy to pht_storage so pht_secondary_particles() - // subtraction results in net zero - if (created_photon && !model::active_pulse_height_tallies.empty()) { - auto it = std::find(model::pulse_height_cells.begin(), - model::pulse_height_cells.end(), p.lowest_coord().cell()); - if (it != model::pulse_height_cells.end()) { - int index = std::distance(model::pulse_height_cells.begin(), it); - p.pht_storage()[index] += E; - } - } - - // Tag secondary particle with parent nuclide - if (created_photon && settings::use_decay_photons) { - p.local_secondary_bank().back().parent_nuclide = - rx->products_[i_product].parent_nuclide_; - } + p.create_secondary(wgt, u, E, ParticleType::photon); } } diff --git a/src/physics_common.cpp b/src/physics_common.cpp index 10760ce2d..e25ae6b97 100644 --- a/src/physics_common.cpp +++ b/src/physics_common.cpp @@ -18,20 +18,4 @@ void russian_roulette(Particle& p, double weight_survive) } } -void apply_russian_roulette(Particle& p) -{ - // Exit if survival biasing is turned off - if (!settings::survival_biasing) - return; - - // if survival normalization is on, use normalized weight cutoff and - // normalized weight survive - if (settings::survival_normalization) { - if (p.wgt() < settings::weight_cutoff * p.wgt_born()) { - russian_roulette(p, settings::weight_survive * p.wgt_born()); - } - } else if (p.wgt() < settings::weight_cutoff) { - russian_roulette(p, settings::weight_survive); - } -} } // namespace openmc diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index 212ba765c..ab1fdef02 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -2,7 +2,7 @@ #include -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" #include #include "openmc/bank.h" @@ -19,7 +19,6 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/tallies/tally.h" -#include "openmc/weight_windows.h" namespace openmc { @@ -27,23 +26,10 @@ void collision_mg(Particle& p) { // Add to the collision counter for the particle p.n_collision()++; - p.secondary_bank_index() = p.local_secondary_bank().size(); // Sample the reaction type sample_reaction(p); - if (settings::weight_windows_on) { - auto [ww_found, ww] = search_weight_window(p); - if (!ww_found && p.type() == ParticleType::neutron()) { - // if the weight window is not valid, apply russian roulette - // (regardless of weight window collision checkpoint setting) - apply_russian_roulette(p); - } else if (settings::weight_window_checkpoint_collision) { - // if collision checkpointing is on, apply weight window - apply_weight_window(p, ww); - } - } - // Display information about collision if ((settings::verbosity >= 10) || p.trace()) { write_message(fmt::format(" Energy Group = {}", p.g()), 1); @@ -57,7 +43,7 @@ void sample_reaction(Particle& p) // change when sampling fission sites. The following block handles all // absorption (including fission) - if (model::materials[p.material()]->fissionable()) { + if (model::materials[p.material()]->fissionable_) { if (settings::run_mode == RunMode::EIGENVALUE || (settings::run_mode == RunMode::FIXED_SOURCE && settings::create_fission_neutrons)) { @@ -76,15 +62,18 @@ void sample_reaction(Particle& p) // Sample a scattering event to determine the energy of the exiting neutron scatter(p); - // Play russian roulette if there are no weight windows - if (!settings::weight_windows_on) - apply_russian_roulette(p); + // Play Russian roulette if survival biasing is turned on + if (settings::survival_biasing) { + if (p.wgt() < settings::weight_cutoff) { + russian_roulette(p, settings::weight_survive); + } + } } void scatter(Particle& p) { - data::mg.macro_xs_[p.material()].sample_scatter(p.g_last(), p.g(), p.mu(), - p.wgt(), p.current_seed(), p.mg_xs_cache().t, p.mg_xs_cache().a); + data::mg.macro_xs_[p.material()].sample_scatter( + p.g_last(), p.g(), p.mu(), p.wgt(), p.current_seed()); // Rotate the angle p.u() = rotate_angle(p.u(), p.mu(), nullptr, p.current_seed()); @@ -137,9 +126,10 @@ void create_fission_sites(Particle& p) // Initialize fission site object with particle data SourceSite site; site.r = p.r(); - site.particle = ParticleType::neutron(); - site.time = p.time(); + site.particle = ParticleType::neutron; site.wgt = 1. / weight; + site.parent_id = p.id(); + site.progeny_id = p.n_progeny()++; // Sample the cosine of the angle, assuming fission neutrons are emitted // isotropically @@ -155,7 +145,7 @@ void create_fission_sites(Particle& p) int dg; int gout; data::mg.macro_xs_[p.material()].sample_fission_energy( - p.g(), dg, gout, p.current_seed(), p.mg_xs_cache().t, p.mg_xs_cache().a); + p.g(), dg, gout, p.current_seed()); // Store the energy and delayed groups on the fission bank site.E = gout; @@ -164,24 +154,6 @@ void create_fission_sites(Particle& p) // of the code, 0 is prompt. site.delayed_group = dg + 1; - // If delayed product production, sample time of emission - if (dg != -1) { - auto& macro_xs = data::mg.macro_xs_[p.material()]; - double decay_rate = - macro_xs.get_xs(MgxsType::DECAY_RATE, 0, nullptr, nullptr, &dg, 0, 0); - site.time -= std::log(prn(p.current_seed())) / decay_rate; - - // Reject site if it exceeds time cutoff - double t_cutoff = settings::time_cutoff[site.particle.transport_index()]; - if (site.time > t_cutoff) { - continue; - } - } - - // Set parent and progeny ID - site.parent_id = p.current_work(); - site.progeny_id = p.n_progeny()++; - // Store fission site in bank if (use_fission_bank) { int64_t idx = simulation::fission_bank.thread_safe_append(site); @@ -200,11 +172,7 @@ void create_fission_sites(Particle& p) break; } } else { - site.wgt_born = p.wgt_born(); - site.wgt_ww_born = p.wgt_ww_born(); - site.n_split = p.n_split(); - p.local_secondary_bank().push_back(site); - p.n_secondaries()++; + p.secondary_bank().push_back(site); } // Set the delayed group on the particle as well @@ -216,10 +184,11 @@ void create_fission_sites(Particle& p) } // Write fission particles to nuBank - NuBank& nu_bank_entry = p.nu_bank().emplace_back(); - nu_bank_entry.wgt = site.wgt; - nu_bank_entry.E = site.E; - nu_bank_entry.delayed_group = site.delayed_group; + p.nu_bank().emplace_back(); + NuBank* nu_bank_entry = &p.nu_bank().back(); + nu_bank_entry->wgt = site.wgt; + nu_bank_entry->E = site.E; + nu_bank_entry->delayed_group = site.delayed_group; } // If shared fission bank was full, and no fissions could be added, diff --git a/src/plot.cpp b/src/plot.cpp index 5c4eb9460..b012ed131 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -1,22 +1,19 @@ #include "openmc/plot.h" #include -#include #include #include #include -#include "openmc/tensor.h" +#include "xtensor/xview.hpp" +#include "xtensor/xmanipulation.hpp" #include #include #ifdef USE_LIBPNG #include #endif -#include "openmc/cell.h" #include "openmc/constants.h" -#include "openmc/container_util.h" -#include "openmc/dagmc.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/geometry.h" @@ -24,7 +21,6 @@ #include "openmc/material.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" -#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/particle.h" #include "openmc/progress_bar.h" @@ -32,7 +28,6 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/string_utils.h" -#include "openmc/tallies/filter.h" namespace openmc { @@ -44,123 +39,55 @@ constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level constexpr int32_t NOT_FOUND {-2}; constexpr int32_t OVERLAP {-3}; -IdData::IdData(size_t h_res, size_t v_res, bool /*include_filter*/) - : data_({v_res, h_res, 3}, NOT_FOUND) +IdData::IdData(size_t h_res, size_t v_res) : data_({v_res, h_res, 3}, NOT_FOUND) {} -void IdData::set_value(size_t y, size_t x, const Particle& p, int level, - Filter* /*filter*/, FilterMatch* /*match*/) +void IdData::set_value(size_t y, size_t x, const Particle& p, int level) { // set cell data if (p.n_coord() <= level) { data_(y, x, 0) = NOT_FOUND; data_(y, x, 1) = NOT_FOUND; } else { - data_(y, x, 0) = model::cells.at(p.coord(level).cell())->id_; + data_(y, x, 0) = model::cells.at(p.coord(level).cell)->id_; data_(y, x, 1) = level == p.n_coord() - 1 ? p.cell_instance() : cell_instance_at_level(p, level); } // set material data - Cell* c = model::cells.at(p.lowest_coord().cell()).get(); + Cell* c = model::cells.at(p.coord(p.n_coord() - 1).cell).get(); if (p.material() == MATERIAL_VOID) { data_(y, x, 2) = MATERIAL_VOID; + return; } else if (c->type_ == Fill::MATERIAL) { Material* m = model::materials.at(p.material()).get(); data_(y, x, 2) = m->id_; } } -void IdData::set_overlap(size_t y, size_t x, int /*overlap_idx*/) +void IdData::set_overlap(size_t y, size_t x) { - for (size_t k = 0; k < data_.shape(2); ++k) - data_(y, x, k) = OVERLAP; + xt::view(data_, y, x, xt::all()) = OVERLAP; } -PropertyData::PropertyData(size_t h_res, size_t v_res, bool /*include_filter*/) +PropertyData::PropertyData(size_t h_res, size_t v_res) : data_({v_res, h_res, 2}, NOT_FOUND) {} -void PropertyData::set_value(size_t y, size_t x, const Particle& p, int level, - Filter* /*filter*/, FilterMatch* /*match*/) +void PropertyData::set_value(size_t y, size_t x, const Particle& p, int level) { - Cell* c = model::cells.at(p.lowest_coord().cell()).get(); + Cell* c = model::cells.at(p.coord(p.n_coord() - 1).cell).get(); data_(y, x, 0) = (p.sqrtkT() * p.sqrtkT()) / K_BOLTZMANN; - data_(y, x, 1) = c->density(p.cell_instance()); -} - -void PropertyData::set_overlap(size_t y, size_t x, int /*overlap_idx*/) -{ - data_(y, x) = OVERLAP; -} - -//============================================================================== -// RasterData implementation -//============================================================================== - -RasterData::RasterData(size_t h_res, size_t v_res, bool include_filter) - : id_data_({v_res, h_res, include_filter ? 4u : 3u}, NOT_FOUND), - property_data_({v_res, h_res, 2}, static_cast(NOT_FOUND)), - include_filter_(include_filter) -{} - -void RasterData::set_value(size_t y, size_t x, const Particle& p, int level, - Filter* filter, FilterMatch* match) -{ - // set cell data - if (p.n_coord() <= level) { - id_data_(y, x, 0) = NOT_FOUND; - id_data_(y, x, 1) = NOT_FOUND; - } else { - id_data_(y, x, 0) = model::cells.at(p.coord(level).cell())->id_; - id_data_(y, x, 1) = level == p.n_coord() - 1 - ? p.cell_instance() - : cell_instance_at_level(p, level); - } - - // set material data - Cell* c = model::cells.at(p.lowest_coord().cell()).get(); - if (p.material() == MATERIAL_VOID) { - id_data_(y, x, 2) = MATERIAL_VOID; - } else if (c->type_ == Fill::MATERIAL) { - Material* m = model::materials.at(p.material()).get(); - id_data_(y, x, 2) = m->id_; - } - - // set filter index (only if filter is being used) - if (include_filter_ && filter) { - filter->get_all_bins(p, TallyEstimator::COLLISION, *match); - if (match->bins_.empty()) { - id_data_(y, x, 3) = -1; - } else { - id_data_(y, x, 3) = match->bins_[0]; - } - match->bins_.clear(); - match->weights_.clear(); - } - - // set temperature (in K) - property_data_(y, x, 0) = (p.sqrtkT() * p.sqrtkT()) / K_BOLTZMANN; - - // set density (g/cm³) if (c->type_ != Fill::UNIVERSE && p.material() != MATERIAL_VOID) { Material* m = model::materials.at(p.material()).get(); - property_data_(y, x, 1) = c->density(p.cell_instance()); + data_(y, x, 1) = m->density_gpcc_; } } -void RasterData::set_overlap(size_t y, size_t x, int overlap_idx) +void PropertyData::set_overlap(size_t y, size_t x) { - // Set cell, instance, and material to OVERLAP, but preserve filter bin for - // tally plotting. Cell encodes the overlap index as a negative number so that - // it can be used to look up overlap information in the plotter. - id_data_(y, x, 0) = OVERLAP - overlap_idx - 1; - id_data_(y, x, 1) = OVERLAP; - id_data_(y, x, 2) = OVERLAP; - - property_data_(y, x, 0) = OVERLAP; - property_data_(y, x, 1) = OVERLAP; + data_(y, x) = OVERLAP; } //============================================================================== @@ -170,7 +97,7 @@ void RasterData::set_overlap(size_t y, size_t x, int overlap_idx) namespace model { std::unordered_map plot_map; -vector> plots; +vector plots; uint64_t plotter_seed = 1; } // namespace model @@ -183,76 +110,20 @@ extern "C" int openmc_plot_geometry() { for (auto& pl : model::plots) { - write_message(5, "Processing plot {}: {}...", pl->id(), pl->path_plot()); - pl->create_output(); + write_message(5, "Processing plot {}: {}...", pl.id_, pl.path_plot_); + + if (PlotType::slice == pl.type_) { + // create 2D image + create_image(pl); + } else if (PlotType::voxel == pl.type_) { + // create voxel file for 3D viewing + create_voxel(pl); + } } return 0; } -void PlottableInterface::write_image(const ImageData& data) const -{ -#ifdef USE_LIBPNG - output_png(path_plot(), data); -#else - output_ppm(path_plot(), data); -#endif -} - -void Plot::create_output() const -{ - if (PlotType::slice == type_) { - // create 2D image - ImageData image = create_image(); - write_image(image); - } else if (PlotType::voxel == type_) { - // create voxel file for 3D viewing - create_voxel(); - } -} - -void Plot::print_info() const -{ - // Plot type - if (PlotType::slice == type_) { - fmt::print("Plot Type: Slice\n"); - } else if (PlotType::voxel == type_) { - fmt::print("Plot Type: Voxel\n"); - } - - // Plot parameters - fmt::print("Origin: {} {} {}\n", origin_[0], origin_[1], origin_[2]); - - if (PlotType::slice == type_) { - fmt::print("Width: {:4} {:4}\n", width_[0], width_[1]); - } else if (PlotType::voxel == type_) { - fmt::print("Width: {:4} {:4} {:4}\n", width_[0], width_[1], width_[2]); - } - - if (PlotColorBy::cells == color_by_) { - fmt::print("Coloring: Cells\n"); - } else if (PlotColorBy::mats == color_by_) { - fmt::print("Coloring: Materials\n"); - } - - if (PlotType::slice == type_) { - switch (basis_) { - case PlotBasis::xy: - fmt::print("Basis: XY\n"); - break; - case PlotBasis::xz: - fmt::print("Basis: XZ\n"); - break; - case PlotBasis::yz: - fmt::print("Basis: YZ\n"); - break; - } - fmt::print("Pixels: {} {}\n", pixels()[0], pixels()[1]); - } else if (PlotType::voxel == type_) { - fmt::print("Voxels: {} {} {}\n", pixels()[0], pixels()[1], pixels()[2]); - } -} - void read_plots_xml() { // Check if plots.xml exists; this is only necessary when the plot runmode is @@ -270,39 +141,9 @@ void read_plots_xml() doc.load_file(filename.c_str()); pugi::xml_node root = doc.document_element(); - - read_plots_xml(root); -} - -void read_plots_xml(pugi::xml_node root) -{ for (auto node : root.children("plot")) { - std::string plot_desc = ""; - if (check_for_node(node, "id")) { - plot_desc = get_node_value(node, "id", true); - } - - if (check_for_node(node, "type")) { - std::string type_str = get_node_value(node, "type", true); - if (type_str == "slice") { - model::plots.emplace_back( - std::make_unique(node, Plot::PlotType::slice)); - } else if (type_str == "voxel") { - model::plots.emplace_back( - std::make_unique(node, Plot::PlotType::voxel)); - } else if (type_str == "wireframe_raytrace") { - model::plots.emplace_back( - std::make_unique(node)); - } else if (type_str == "solid_raytrace") { - model::plots.emplace_back(std::make_unique(node)); - } else { - fatal_error(fmt::format( - "Unsupported plot type '{}' in plot {}", type_str, plot_desc)); - } - model::plot_map[model::plots.back()->id()] = model::plots.size() - 1; - } else { - fatal_error(fmt::format("Must specify plot type in plot {}", plot_desc)); - } + model::plots.emplace_back(node); + model::plot_map[model::plots.back().id_] = model::plots.size() - 1; } } @@ -312,99 +153,95 @@ void free_memory_plot() model::plot_map.clear(); } -// creates an image based on user input from a plots.xml +//============================================================================== +// CREATE_IMAGE creates an image based on user input from a plots.xml // specification in the PNG/PPM format -ImageData Plot::create_image() const -{ - size_t width = pixels()[0]; - size_t height = pixels()[1]; +//============================================================================== - ImageData data({width, height}, not_found_); +void create_image(Plot const& pl) +{ + + size_t width = pl.pixels_[0]; + size_t height = pl.pixels_[1]; + + ImageData data({width, height}, pl.not_found_); // generate ids for the plot - auto ids = get_map(); + auto ids = pl.get_map(); // assign colors for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { - int idx = color_by_ == PlotColorBy::cells ? 0 : 2; + int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 2; auto id = ids.data_(y, x, idx); // no setting needed if not found if (id == NOT_FOUND) { continue; } if (id == OVERLAP) { - data(x, y) = overlap_color_; + data(x, y) = pl.overlap_color_; continue; } - if (PlotColorBy::cells == color_by_) { - data(x, y) = colors_[model::cell_map[id]]; - } else if (PlotColorBy::mats == color_by_) { + if (PlotColorBy::cells == pl.color_by_) { + data(x, y) = pl.colors_[model::cell_map[id]]; + } else if (PlotColorBy::mats == pl.color_by_) { if (id == MATERIAL_VOID) { data(x, y) = WHITE; continue; } - data(x, y) = colors_[model::material_map[id]]; + data(x, y) = pl.colors_[model::material_map[id]]; } // color_by if-else - } - } + } // x for loop + } // y for loop // draw mesh lines if present - if (index_meshlines_mesh_ >= 0) { - draw_mesh_lines(data); + if (pl.index_meshlines_mesh_ >= 0) { + draw_mesh_lines(pl, data); } - return data; +// create image file +#ifdef USE_LIBPNG + output_png(pl, data); +#else + output_ppm(pl, data); +#endif } -void PlottableInterface::set_id(pugi::xml_node plot_node) +void Plot::set_id(pugi::xml_node plot_node) { - int id {C_NONE}; + // Copy data into plots if (check_for_node(plot_node, "id")) { - id = std::stoi(get_node_value(plot_node, "id")); + id_ = std::stoi(get_node_value(plot_node, "id")); + } else { + fatal_error("Must specify plot id in plots XML file."); } - try { - set_id(id); - } catch (const std::runtime_error& e) { - fatal_error(e.what()); + // Check to make sure 'id' hasn't been used + if (model::plot_map.find(id_) != model::plot_map.end()) { + fatal_error( + fmt::format("Two or more plots use the same unique ID: {}", id_)); } } -void PlottableInterface::set_id(int id) +void Plot::set_type(pugi::xml_node plot_node) { - if (id < 0 && id != C_NONE) { - throw std::runtime_error {fmt::format("Invalid plot ID: {}", id)}; - } - - if (id == C_NONE) { - id = 1; - for (const auto& p : model::plots) { - id = std::max(id, p->id() + 1); + // Copy plot type + // Default is slice + type_ = PlotType::slice; + // check type specified on plot node + if (check_for_node(plot_node, "type")) { + std::string type_str = get_node_value(plot_node, "type", true); + // set type using node value + if (type_str == "slice") { + type_ = PlotType::slice; + } else if (type_str == "voxel") { + type_ = PlotType::voxel; + } else { + // if we're here, something is wrong + fatal_error( + fmt::format("Unsupported plot type '{}' in plot {}", type_str, id_)); } } - - if (id_ == id) - return; - - // Check to make sure this ID doesn't already exist - if (model::plot_map.find(id) != model::plot_map.end()) { - throw std::runtime_error { - fmt::format("Two or more plots use the same unique ID: {}", id)}; - } - - id_ = id; -} - -// Checks if png or ppm is already present -bool file_extension_present( - const std::string& filename, const std::string& extension) -{ - std::string file_extension_if_present = - filename.substr(filename.find_last_of(".") + 1); - if (file_extension_if_present == extension) - return true; - return false; } void Plot::set_output_path(pugi::xml_node plot_node) @@ -415,27 +252,19 @@ void Plot::set_output_path(pugi::xml_node plot_node) if (check_for_node(plot_node, "filename")) { filename = get_node_value(plot_node, "filename"); } else { - filename = fmt::format("plot_{}", id()); - } - const std::string dir_if_present = - filename.substr(0, filename.find_last_of("/") + 1); - if (dir_if_present.size() > 0 && !dir_exists(dir_if_present)) { - fatal_error(fmt::format("Directory '{}' does not exist!", dir_if_present)); + filename = fmt::format("plot_{}", id_); } // add appropriate file extension to name switch (type_) { case PlotType::slice: #ifdef USE_LIBPNG - if (!file_extension_present(filename, "png")) - filename.append(".png"); + filename.append(".png"); #else - if (!file_extension_present(filename, "ppm")) - filename.append(".ppm"); + filename.append(".ppm"); #endif break; case PlotType::voxel: - if (!file_extension_present(filename, "h5")) - filename.append(".h5"); + filename.append(".h5"); break; } @@ -445,33 +274,38 @@ void Plot::set_output_path(pugi::xml_node plot_node) vector pxls = get_node_array(plot_node, "pixels"); if (PlotType::slice == type_) { if (pxls.size() == 2) { - pixels()[0] = pxls[0]; - pixels()[1] = pxls[1]; + pixels_[0] = pxls[0]; + pixels_[1] = pxls[1]; } else { fatal_error( - fmt::format(" must be length 2 in slice plot {}", id())); + fmt::format(" must be length 2 in slice plot {}", id_)); } } else if (PlotType::voxel == type_) { if (pxls.size() == 3) { - pixels()[0] = pxls[0]; - pixels()[1] = pxls[1]; - pixels()[2] = pxls[2]; + pixels_[0] = pxls[0]; + pixels_[1] = pxls[1]; + pixels_[2] = pxls[2]; } else { fatal_error( - fmt::format(" must be length 3 in voxel plot {}", id())); + fmt::format(" must be length 3 in voxel plot {}", id_)); } } } -void PlottableInterface::set_bg_color(pugi::xml_node plot_node) +void Plot::set_bg_color(pugi::xml_node plot_node) { // Copy plot background color if (check_for_node(plot_node, "background")) { vector bg_rgb = get_node_array(plot_node, "background"); + if (PlotType::voxel == type_) { + if (mpi::master) { + warning(fmt::format("Background color ignored in voxel plot {}", id_)); + } + } if (bg_rgb.size() == 3) { not_found_ = bg_rgb; } else { - fatal_error(fmt::format("Bad background RGB in plot {}", id())); + fatal_error(fmt::format("Bad background RGB in plot {}", id_)); } } } @@ -492,7 +326,7 @@ void Plot::set_basis(pugi::xml_node plot_node) basis_ = PlotBasis::yz; } else { fatal_error( - fmt::format("Unsupported plot basis '{}' in plot {}", pl_basis, id())); + fmt::format("Unsupported plot basis '{}' in plot {}", pl_basis, id_)); } } } @@ -504,7 +338,7 @@ void Plot::set_origin(pugi::xml_node plot_node) if (pl_origin.size() == 3) { origin_ = pl_origin; } else { - fatal_error(fmt::format("Origin must be length 3 in plot {}", id())); + fatal_error(fmt::format("Origin must be length 3 in plot {}", id_)); } } @@ -516,25 +350,9 @@ void Plot::set_width(pugi::xml_node plot_node) if (pl_width.size() == 2) { width_.x = pl_width[0]; width_.y = pl_width[1]; - switch (basis_) { - case PlotBasis::xy: - u_span_ = {width_.x, 0.0, 0.0}; - v_span_ = {0.0, width_.y, 0.0}; - break; - case PlotBasis::xz: - u_span_ = {width_.x, 0.0, 0.0}; - v_span_ = {0.0, 0.0, width_.y}; - break; - case PlotBasis::yz: - u_span_ = {0.0, width_.x, 0.0}; - v_span_ = {0.0, 0.0, width_.y}; - break; - default: - UNREACHABLE(); - } } else { fatal_error( - fmt::format(" must be length 2 in slice plot {}", id())); + fmt::format(" must be length 2 in slice plot {}", id_)); } } else if (PlotType::voxel == type_) { if (pl_width.size() == 3) { @@ -542,48 +360,40 @@ void Plot::set_width(pugi::xml_node plot_node) width_ = pl_width; } else { fatal_error( - fmt::format(" must be length 3 in voxel plot {}", id())); + fmt::format(" must be length 3 in voxel plot {}", id_)); } } } -void PlottableInterface::set_universe(pugi::xml_node plot_node) +void Plot::set_universe(pugi::xml_node plot_node) { // Copy plot universe level if (check_for_node(plot_node, "level")) { level_ = std::stoi(get_node_value(plot_node, "level")); if (level_ < 0) { - fatal_error(fmt::format("Bad universe level in plot {}", id())); + fatal_error(fmt::format("Bad universe level in plot {}", id_)); } } else { level_ = PLOT_LEVEL_LOWEST; } } -void PlottableInterface::set_color_by(pugi::xml_node plot_node) +void Plot::set_default_colors(pugi::xml_node plot_node) { - // Copy plot color type + // Copy plot color type and initialize all colors randomly std::string pl_color_by = "cell"; if (check_for_node(plot_node, "color_by")) { pl_color_by = get_node_value(plot_node, "color_by", true); } if ("cell" == pl_color_by) { color_by_ = PlotColorBy::cells; + colors_.resize(model::cells.size()); } else if ("material" == pl_color_by) { color_by_ = PlotColorBy::mats; + colors_.resize(model::materials.size()); } else { fatal_error(fmt::format( - "Unsupported plot color type '{}' in plot {}", pl_color_by, id())); - } -} - -void PlottableInterface::set_default_colors() -{ - // Copy plot color type and initialize all colors randomly - if (PlotColorBy::cells == color_by_) { - colors_.resize(model::cells.size()); - } else if (PlotColorBy::mats == color_by_) { - colors_.resize(model::materials.size()); + "Unsupported plot color type '{}' in plot {}", pl_color_by, id_)); } for (auto& c : colors_) { @@ -595,21 +405,28 @@ void PlottableInterface::set_default_colors() } } -void PlottableInterface::set_user_colors(pugi::xml_node plot_node) +void Plot::set_user_colors(pugi::xml_node plot_node) { + if (!plot_node.select_nodes("color").empty() && PlotType::voxel == type_) { + if (mpi::master) { + warning( + fmt::format("Color specifications ignored in voxel plot {}", id_)); + } + } + for (auto cn : plot_node.children("color")) { // Make sure 3 values are specified for RGB vector user_rgb = get_node_array(cn, "rgb"); if (user_rgb.size() != 3) { - fatal_error(fmt::format("Bad RGB in plot {}", id())); + fatal_error(fmt::format("Bad RGB in plot {}", id_)); } // Ensure that there is an id for this color specification int col_id; if (check_for_node(cn, "id")) { col_id = std::stoi(get_node_value(cn, "id")); } else { - fatal_error(fmt::format( - "Must specify id for color specification in plot {}", id())); + fatal_error( + fmt::format("Must specify id for color specification in plot {}", id_)); } // Add RGB if (PlotColorBy::cells == color_by_) { @@ -618,7 +435,7 @@ void PlottableInterface::set_user_colors(pugi::xml_node plot_node) colors_[col_id] = user_rgb; } else { warning(fmt::format( - "Could not find cell {} specified in plot {}", col_id, id())); + "Could not find cell {} specified in plot {}", col_id, id_)); } } else if (PlotColorBy::mats == color_by_) { if (model::material_map.find(col_id) != model::material_map.end()) { @@ -626,7 +443,7 @@ void PlottableInterface::set_user_colors(pugi::xml_node plot_node) colors_[col_id] = user_rgb; } else { warning(fmt::format( - "Could not find material {} specified in plot {}", col_id, id())); + "Could not find material {} specified in plot {}", col_id, id_)); } } } // color node loop @@ -639,7 +456,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) if (!mesh_line_nodes.empty()) { if (PlotType::voxel == type_) { - warning(fmt::format("Meshlines ignored in voxel plot {}", id())); + warning(fmt::format("Meshlines ignored in voxel plot {}", id_)); } if (mesh_line_nodes.size() == 1) { @@ -653,7 +470,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) } else { fatal_error(fmt::format( "Must specify a meshtype for meshlines specification in plot {}", - id())); + id_)); } // Ensure that there is a linewidth for this meshlines specification @@ -664,7 +481,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) } else { fatal_error(fmt::format( "Must specify a linewidth for meshlines specification in plot {}", - id())); + id_)); } // Check for color @@ -673,7 +490,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) vector ml_rgb = get_node_array(meshlines_node, "color"); if (ml_rgb.size() != 3) { fatal_error( - fmt::format("Bad RGB for meshlines color in plot {}", id())); + fmt::format("Bad RGB for meshlines color in plot {}", id_)); } meshlines_color_ = ml_rgb; } @@ -681,8 +498,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) // Set mesh based on type if ("ufs" == meshtype) { if (!simulation::ufs_mesh) { - fatal_error( - fmt::format("No UFS mesh for meshlines on plot {}", id())); + fatal_error(fmt::format("No UFS mesh for meshlines on plot {}", id_)); } else { for (int i = 0; i < model::meshes.size(); ++i) { if (const auto* m = @@ -698,7 +514,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) } else if ("entropy" == meshtype) { if (!simulation::entropy_mesh) { fatal_error( - fmt::format("No entropy mesh for meshlines on plot {}", id())); + fmt::format("No entropy mesh for meshlines on plot {}", id_)); } else { for (int i = 0; i < model::meshes.size(); ++i) { if (const auto* m = @@ -720,7 +536,7 @@ void Plot::set_meshlines(pugi::xml_node plot_node) std::stringstream err_msg; fatal_error(fmt::format("Must specify a mesh id for meshlines tally " "mesh specification in plot {}", - id())); + id_)); } // find the tally index int idx; @@ -728,24 +544,30 @@ void Plot::set_meshlines(pugi::xml_node plot_node) if (err != 0) { fatal_error(fmt::format("Could not find mesh {} specified in " "meshlines for plot {}", - tally_mesh_id, id())); + tally_mesh_id, id_)); } index_meshlines_mesh_ = idx; } else { - fatal_error(fmt::format("Invalid type for meshlines on plot {}", id())); + fatal_error(fmt::format("Invalid type for meshlines on plot {}", id_)); } } else { - fatal_error(fmt::format("Mutliple meshlines specified in plot {}", id())); + fatal_error(fmt::format("Mutliple meshlines specified in plot {}", id_)); } } } -void PlottableInterface::set_mask(pugi::xml_node plot_node) +void Plot::set_mask(pugi::xml_node plot_node) { // Deal with masks pugi::xpath_node_set mask_nodes = plot_node.select_nodes("mask"); if (!mask_nodes.empty()) { + if (PlotType::voxel == type_) { + if (mpi::master) { + warning(fmt::format("Mask ignored in voxel plot {}", id_)); + } + } + if (mask_nodes.size() == 1) { // Get pointer to mask pugi::xml_node mask_node = mask_nodes[0].node(); @@ -754,7 +576,7 @@ void PlottableInterface::set_mask(pugi::xml_node plot_node) vector iarray = get_node_array(mask_node, "components"); if (iarray.size() == 0) { fatal_error( - fmt::format("Missing in mask of plot {}", id())); + fmt::format("Missing in mask of plot {}", id_)); } // First we need to change the user-specified identifiers to indices @@ -766,7 +588,7 @@ void PlottableInterface::set_mask(pugi::xml_node plot_node) } else { fatal_error(fmt::format("Could not find cell {} specified in the " "mask in plot {}", - col_id, id())); + col_id, id_)); } } else if (PlotColorBy::mats == color_by_) { if (model::material_map.find(col_id) != model::material_map.end()) { @@ -774,14 +596,14 @@ void PlottableInterface::set_mask(pugi::xml_node plot_node) } else { fatal_error(fmt::format("Could not find material {} specified in " "the mask in plot {}", - col_id, id())); + col_id, id_)); } } } // Alter colors based on mask information for (int j = 0; j < colors_.size(); j++) { - if (contains(iarray, j)) { + if (std::find(iarray.begin(), iarray.end(), j) == iarray.end()) { if (check_for_node(mask_node, "background")) { vector bg_rgb = get_node_array(mask_node, "background"); colors_[j] = bg_rgb; @@ -792,12 +614,12 @@ void PlottableInterface::set_mask(pugi::xml_node plot_node) } } else { - fatal_error(fmt::format("Mutliple masks specified in plot {}", id())); + fatal_error(fmt::format("Mutliple masks specified in plot {}", id_)); } } } -void PlottableInterface::set_overlap_color(pugi::xml_node plot_node) +void Plot::set_overlap_color(pugi::xml_node plot_node) { color_overlaps_ = false; if (check_for_node(plot_node, "show_overlaps")) { @@ -807,13 +629,13 @@ void PlottableInterface::set_overlap_color(pugi::xml_node plot_node) if (!color_overlaps_) { warning(fmt::format( "Overlap color specified in plot {} but overlaps won't be shown.", - id())); + id_)); } vector olap_clr = get_node_array(plot_node, "overlap_color"); if (olap_clr.size() == 3) { overlap_color_ = olap_clr; } else { - fatal_error(fmt::format("Bad overlap RGB in plot {}", id())); + fatal_error(fmt::format("Bad overlap RGB in plot {}", id_)); } } } @@ -826,38 +648,32 @@ void PlottableInterface::set_overlap_color(pugi::xml_node plot_node) } } -PlottableInterface::PlottableInterface(pugi::xml_node plot_node) +Plot::Plot(pugi::xml_node plot_node) + : index_meshlines_mesh_ {-1}, overlap_color_ {RED} { set_id(plot_node); - set_bg_color(plot_node); - set_universe(plot_node); - set_color_by(plot_node); - set_default_colors(); - set_user_colors(plot_node); - set_mask(plot_node); - set_overlap_color(plot_node); -} - -Plot::Plot(pugi::xml_node plot_node, PlotType type) - : PlottableInterface(plot_node), type_(type), index_meshlines_mesh_ {-1} -{ + set_type(plot_node); set_output_path(plot_node); + set_bg_color(plot_node); set_basis(plot_node); set_origin(plot_node); set_width(plot_node); + set_universe(plot_node); + set_default_colors(plot_node); + set_user_colors(plot_node); set_meshlines(plot_node); - slice_level_ = level_; // Copy level employed in SlicePlotBase::get_map - show_overlaps_ = color_overlaps_; -} + set_mask(plot_node); + set_overlap_color(plot_node); +} // End Plot constructor //============================================================================== // OUTPUT_PPM writes out a previously generated image to a PPM file //============================================================================== -void output_ppm(const std::string& filename, const ImageData& data) +void output_ppm(Plot const& pl, const ImageData& data) { // Open PPM file for writing - std::string fname = filename; + std::string fname = pl.path_plot_; fname = strtrim(fname); std::ofstream of; @@ -865,14 +681,14 @@ void output_ppm(const std::string& filename, const ImageData& data) // Write header of << "P6\n"; - of << data.shape(0) << " " << data.shape(1) << "\n"; + of << pl.pixels_[0] << " " << pl.pixels_[1] << "\n"; of << "255\n"; of.close(); of.open(fname, std::ios::binary | std::ios::app); // Write color for each pixel - for (int y = 0; y < data.shape(1); y++) { - for (int x = 0; x < data.shape(0); x++) { + for (int y = 0; y < pl.pixels_[1]; y++) { + for (int x = 0; x < pl.pixels_[0]; x++) { RGBColor rgb = data(x, y); of << rgb.red << rgb.green << rgb.blue; } @@ -885,10 +701,10 @@ void output_ppm(const std::string& filename, const ImageData& data) //============================================================================== #ifdef USE_LIBPNG -void output_png(const std::string& filename, const ImageData& data) +void output_png(Plot const& pl, const ImageData& data) { // Open PNG file for writing - std::string fname = filename; + std::string fname = pl.path_plot_; fname = strtrim(fname); auto fp = std::fopen(fname.c_str(), "wb"); @@ -904,8 +720,8 @@ void output_png(const std::string& filename, const ImageData& data) png_init_io(png_ptr, fp); // Write header (8 bit colour depth) - int width = data.shape(0); - int height = data.shape(1); + int width = pl.pixels_[0]; + int height = pl.pixels_[1]; png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); @@ -938,84 +754,68 @@ void output_png(const std::string& filename, const ImageData& data) // DRAW_MESH_LINES draws mesh line boundaries on an image //============================================================================== -void Plot::draw_mesh_lines(ImageData& data) const +void draw_mesh_lines(Plot const& pl, ImageData& data) { RGBColor rgb; - rgb = meshlines_color_; + rgb = pl.meshlines_color_; int ax1, ax2; - Position expected_u {}; - Position expected_v {}; - switch (basis_) { + switch (pl.basis_) { case PlotBasis::xy: ax1 = 0; ax2 = 1; - expected_u = {width_[0], 0.0, 0.0}; - expected_v = {0.0, width_[1], 0.0}; break; case PlotBasis::xz: ax1 = 0; ax2 = 2; - expected_u = {width_[0], 0.0, 0.0}; - expected_v = {0.0, 0.0, width_[1]}; break; case PlotBasis::yz: ax1 = 1; ax2 = 2; - expected_u = {0.0, width_[0], 0.0}; - expected_v = {0.0, 0.0, width_[1]}; break; default: UNREACHABLE(); } - // Meshlines rely on axis-aligned indexing in global coordinates. - constexpr double rel_tol {1e-12}; - double span_tol = rel_tol * (1.0 + u_span_.norm() + v_span_.norm()); - if ((u_span_ - expected_u).norm() > span_tol || - (v_span_ - expected_v).norm() > span_tol) { - fatal_error("Meshlines are only supported for axis-aligned slice plots."); - } + Position ll_plot {pl.origin_}; + Position ur_plot {pl.origin_}; - Position ll_plot {origin_}; - Position ur_plot {origin_}; - - ll_plot[ax1] -= width_[0] / 2.; - ll_plot[ax2] -= width_[1] / 2.; - ur_plot[ax1] += width_[0] / 2.; - ur_plot[ax2] += width_[1] / 2.; + ll_plot[ax1] -= pl.width_[0] / 2.; + ll_plot[ax2] -= pl.width_[1] / 2.; + ur_plot[ax1] += pl.width_[0] / 2.; + ur_plot[ax2] += pl.width_[1] / 2.; Position width = ur_plot - ll_plot; // Find the (axis-aligned) lines of the mesh that intersect this plot. auto axis_lines = - model::meshes[index_meshlines_mesh_]->plot(ll_plot, ur_plot); + model::meshes[pl.index_meshlines_mesh_]->plot(ll_plot, ur_plot); // Find the bounds along the second axis (accounting for low-D meshes). int ax2_min, ax2_max; if (axis_lines.second.size() > 0) { double frac = (axis_lines.second.back() - ll_plot[ax2]) / width[ax2]; - ax2_min = (1.0 - frac) * pixels()[1]; + ax2_min = (1.0 - frac) * pl.pixels_[1]; if (ax2_min < 0) ax2_min = 0; frac = (axis_lines.second.front() - ll_plot[ax2]) / width[ax2]; - ax2_max = (1.0 - frac) * pixels()[1]; - if (ax2_max > pixels()[1]) - ax2_max = pixels()[1]; + ax2_max = (1.0 - frac) * pl.pixels_[1]; + if (ax2_max > pl.pixels_[1]) + ax2_max = pl.pixels_[1]; } else { ax2_min = 0; - ax2_max = pixels()[1]; + ax2_max = pl.pixels_[1]; } // Iterate across the first axis and draw lines. for (auto ax1_val : axis_lines.first) { double frac = (ax1_val - ll_plot[ax1]) / width[ax1]; - int ax1_ind = frac * pixels()[0]; + int ax1_ind = frac * pl.pixels_[0]; for (int ax2_ind = ax2_min; ax2_ind < ax2_max; ++ax2_ind) { - for (int plus = 0; plus <= meshlines_width_; plus++) { - if (ax1_ind + plus >= 0 && ax1_ind + plus < pixels()[0]) + for (int plus = 0; plus <= pl.meshlines_width_; plus++) { + if (ax1_ind + plus >= 0 && ax1_ind + plus < pl.pixels_[0]) data(ax1_ind + plus, ax2_ind) = rgb; - if (ax1_ind - plus >= 0 && ax1_ind - plus < pixels()[0]) + if (ax1_ind - plus >= 0 && ax1_ind - plus < pl.pixels_[0]) data(ax1_ind - plus, ax2_ind) = rgb; } } @@ -1025,57 +825,60 @@ void Plot::draw_mesh_lines(ImageData& data) const int ax1_min, ax1_max; if (axis_lines.first.size() > 0) { double frac = (axis_lines.first.front() - ll_plot[ax1]) / width[ax1]; - ax1_min = frac * pixels()[0]; + ax1_min = frac * pl.pixels_[0]; if (ax1_min < 0) ax1_min = 0; frac = (axis_lines.first.back() - ll_plot[ax1]) / width[ax1]; - ax1_max = frac * pixels()[0]; - if (ax1_max > pixels()[0]) - ax1_max = pixels()[0]; + ax1_max = frac * pl.pixels_[0]; + if (ax1_max > pl.pixels_[0]) + ax1_max = pl.pixels_[0]; } else { ax1_min = 0; - ax1_max = pixels()[0]; + ax1_max = pl.pixels_[0]; } // Iterate across the second axis and draw lines. for (auto ax2_val : axis_lines.second) { double frac = (ax2_val - ll_plot[ax2]) / width[ax2]; - int ax2_ind = (1.0 - frac) * pixels()[1]; + int ax2_ind = (1.0 - frac) * pl.pixels_[1]; for (int ax1_ind = ax1_min; ax1_ind < ax1_max; ++ax1_ind) { - for (int plus = 0; plus <= meshlines_width_; plus++) { - if (ax2_ind + plus >= 0 && ax2_ind + plus < pixels()[1]) + for (int plus = 0; plus <= pl.meshlines_width_; plus++) { + if (ax2_ind + plus >= 0 && ax2_ind + plus < pl.pixels_[1]) data(ax1_ind, ax2_ind + plus) = rgb; - if (ax2_ind - plus >= 0 && ax2_ind - plus < pixels()[1]) + if (ax2_ind - plus >= 0 && ax2_ind - plus < pl.pixels_[1]) data(ax1_ind, ax2_ind - plus) = rgb; } } } } -/* outputs a binary file that can be input into silomesh for 3D geometry - * visualization. It works the same way as create_image by dragging a particle - * across the geometry for the specified number of voxels. The first 3 int's in - * the binary are the number of x, y, and z voxels. The next 3 double's are - * the widths of the voxels in the x, y, and z directions. The next 3 double's - * are the x, y, and z coordinates of the lower left point. Finally the binary - * is filled with entries of four int's each. Each 'row' in the binary contains - * four int's: 3 for x,y,z position and 1 for cell or material id. For 1 - * million voxels this produces a file of approximately 15MB. - */ -void Plot::create_voxel() const +//============================================================================== +// CREATE_VOXEL outputs a binary file that can be input into silomesh for 3D +// geometry visualization. It works the same way as create_image by dragging a +// particle across the geometry for the specified number of voxels. The first 3 +// int's in the binary are the number of x, y, and z voxels. The next 3 +// double's are the widths of the voxels in the x, y, and z directions. The +// next 3 double's are the x, y, and z coordinates of the lower left +// point. Finally the binary is filled with entries of four int's each. Each +// 'row' in the binary contains four int's: 3 for x,y,z position and 1 for +// cell or material id. For 1 million voxels this produces a file of +// approximately 15MB. +// ============================================================================= + +void create_voxel(Plot const& pl) { // compute voxel widths in each direction array vox; - vox[0] = width_[0] / static_cast(pixels()[0]); - vox[1] = width_[1] / static_cast(pixels()[1]); - vox[2] = width_[2] / static_cast(pixels()[2]); + vox[0] = pl.width_[0] / (double)pl.pixels_[0]; + vox[1] = pl.width_[1] / (double)pl.pixels_[1]; + vox[2] = pl.width_[2] / (double)pl.pixels_[2]; // initial particle position - Position ll = origin_ - width_ / 2.; + Position ll = pl.origin_ - pl.width_ / 2.; // Open binary plot file for writing std::ofstream of; - std::string fname = std::string(path_plot_); + std::string fname = std::string(pl.path_plot_); fname = strtrim(fname); hid_t file_id = file_open(fname, 'w'); @@ -1090,30 +893,34 @@ void Plot::create_voxel() const // Write current date and time write_attribute(file_id, "date_and_time", time_stamp().c_str()); - array h5_pixels; - std::copy(pixels().begin(), pixels().end(), h5_pixels.begin()); - write_attribute(file_id, "num_voxels", h5_pixels); + array pixels; + std::copy(pl.pixels_.begin(), pl.pixels_.end(), pixels.begin()); + write_attribute(file_id, "num_voxels", pixels); write_attribute(file_id, "voxel_width", vox); write_attribute(file_id, "lower_left", ll); // Create dataset for voxel data -- note that the dimensions are reversed // since we want the order in the file to be z, y, x hsize_t dims[3]; - dims[0] = pixels()[2]; - dims[1] = pixels()[1]; - dims[2] = pixels()[0]; + dims[0] = pl.pixels_[2]; + dims[1] = pl.pixels_[1]; + dims[2] = pl.pixels_[0]; hid_t dspace, dset, memspace; voxel_init(file_id, &(dims[0]), &dspace, &dset, &memspace); - SlicePlotBase pltbase; - pltbase.origin_ = origin_; - pltbase.u_span_ = {width_.x, 0.0, 0.0}; - pltbase.v_span_ = {0.0, width_.y, 0.0}; - pltbase.pixels() = pixels(); - pltbase.show_overlaps_ = color_overlaps_; + PlotBase pltbase; + pltbase.width_ = pl.width_; + pltbase.origin_ = pl.origin_; + pltbase.basis_ = PlotBasis::xy; + pltbase.pixels_ = pl.pixels_; + pltbase.level_ = -1; // all universes for voxel files + pltbase.color_overlaps_ = pl.color_overlaps_; ProgressBar pb; - for (int z = 0; z < pixels()[2]; z++) { + for (int z = 0; z < pl.pixels_[2]; z++) { + // update progress bar + pb.set_value(100. * (double)z / (double)(pl.pixels_[2] - 1)); + // update z coordinate pltbase.origin_.z = ll.z + z * vox[2]; @@ -1121,22 +928,13 @@ void Plot::create_voxel() const IdData ids = pltbase.get_map(); // select only cell/material ID data and flip the y-axis - int idx = color_by_ == PlotColorBy::cells ? 0 : 2; - // Extract 2D slice at index idx from 3D data - size_t rows = ids.data_.shape(0); - size_t cols = ids.data_.shape(1); - tensor::Tensor data_slice({rows, cols}); - for (size_t r = 0; r < rows; ++r) - for (size_t c = 0; c < cols; ++c) - data_slice(r, c) = ids.data_(r, c, idx); - tensor::Tensor data_flipped = data_slice.flip(0); + int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 2; + xt::xtensor data_slice = + xt::view(ids.data_, xt::all(), xt::all(), idx); + xt::xtensor data_flipped = xt::flip(data_slice, 0); // Write to HDF5 dataset voxel_write_slice(z, dspace, dset, memspace, data_flipped.data()); - - // update progress bar - pb.set_value( - 100. * static_cast(z + 1) / static_cast((pixels()[2]))); } voxel_finalize(dspace, dset, memspace); @@ -1182,730 +980,16 @@ RGBColor random_color(void) int(prn(&model::plotter_seed) * 255), int(prn(&model::plotter_seed) * 255)}; } -RayTracePlot::RayTracePlot(pugi::xml_node node) : PlottableInterface(node) -{ - set_look_at(node); - set_camera_position(node); - set_field_of_view(node); - set_pixels(node); - set_orthographic_width(node); - set_output_path(node); - - if (check_for_node(node, "orthographic_width") && - check_for_node(node, "field_of_view")) - fatal_error("orthographic_width and field_of_view are mutually exclusive " - "parameters."); -} - -void RayTracePlot::update_view() -{ - // Get centerline vector for camera-to-model. We create vectors around this - // that form a pixel array, and then trace rays along that. - auto up = up_ / up_.norm(); - Direction looking_direction = look_at_ - camera_position_; - looking_direction /= looking_direction.norm(); - if (std::abs(std::abs(looking_direction.dot(up)) - 1.0) < 1e-9) - fatal_error("Up vector cannot align with vector between camera position " - "and look_at!"); - Direction cam_yaxis = looking_direction.cross(up); - cam_yaxis /= cam_yaxis.norm(); - Direction cam_zaxis = cam_yaxis.cross(looking_direction); - cam_zaxis /= cam_zaxis.norm(); - - // Cache the camera-to-model matrix - camera_to_model_ = {looking_direction.x, cam_yaxis.x, cam_zaxis.x, - looking_direction.y, cam_yaxis.y, cam_zaxis.y, looking_direction.z, - cam_yaxis.z, cam_zaxis.z}; -} - -WireframeRayTracePlot::WireframeRayTracePlot(pugi::xml_node node) - : RayTracePlot(node) -{ - set_opacities(node); - set_wireframe_thickness(node); - set_wireframe_ids(node); - set_wireframe_color(node); - update_view(); -} - -void WireframeRayTracePlot::set_wireframe_color(pugi::xml_node plot_node) -{ - // Copy plot wireframe color - if (check_for_node(plot_node, "wireframe_color")) { - vector w_rgb = get_node_array(plot_node, "wireframe_color"); - if (w_rgb.size() == 3) { - wireframe_color_ = w_rgb; - } else { - fatal_error(fmt::format("Bad wireframe RGB in plot {}", id())); - } - } -} - -void RayTracePlot::set_output_path(pugi::xml_node node) -{ - // Set output file path - std::string filename; - - if (check_for_node(node, "filename")) { - filename = get_node_value(node, "filename"); - } else { - filename = fmt::format("plot_{}", id()); - } - -#ifdef USE_LIBPNG - if (!file_extension_present(filename, "png")) - filename.append(".png"); -#else - if (!file_extension_present(filename, "ppm")) - filename.append(".ppm"); -#endif - path_plot_ = filename; -} - -bool WireframeRayTracePlot::trackstack_equivalent( - const std::vector& track1, - const std::vector& track2) const -{ - if (wireframe_ids_.empty()) { - // Draw wireframe for all surfaces/cells/materials - if (track1.size() != track2.size()) - return false; - for (int i = 0; i < track1.size(); ++i) { - if (track1[i].id != track2[i].id || - track1[i].surface_index != track2[i].surface_index) { - return false; - } - } - return true; - } else { - // This runs in O(nm) where n is the intersection stack size - // and m is the number of IDs we are wireframing. A simpler - // algorithm can likely be found. - for (const int id : wireframe_ids_) { - int t1_i = 0; - int t2_i = 0; - - // Advance to first instance of the ID - while (t1_i < track1.size() && t2_i < track2.size()) { - while (t1_i < track1.size() && track1[t1_i].id != id) - t1_i++; - while (t2_i < track2.size() && track2[t2_i].id != id) - t2_i++; - - // This one is really important! - if ((t1_i == track1.size() && t2_i != track2.size()) || - (t1_i != track1.size() && t2_i == track2.size())) - return false; - if (t1_i == track1.size() && t2_i == track2.size()) - break; - // Check if surface different - if (track1[t1_i].surface_index != track2[t2_i].surface_index) - return false; - - // Pretty sure this should not be used: - // if (t2_i != track2.size() - 1 && - // t1_i != track1.size() - 1 && - // track1[t1_i+1].id != track2[t2_i+1].id) return false; - if (t2_i != 0 && t1_i != 0 && - track1[t1_i - 1].surface_index != track2[t2_i - 1].surface_index) - return false; - - // Check if neighboring cells are different - // if (track1[t1_i ? t1_i - 1 : 0].id != track2[t2_i ? t2_i - 1 : 0].id) - // return false; if (track1[t1_i < track1.size() - 1 ? t1_i + 1 : t1_i - // ].id != - // track2[t2_i < track2.size() - 1 ? t2_i + 1 : t2_i].id) return - // false; - t1_i++, t2_i++; - } - } - return true; - } -} - -std::pair RayTracePlot::get_pixel_ray( - int horiz, int vert) const -{ - // Compute field of view in radians - constexpr double DEGREE_TO_RADIAN = PI / 180.0; - double horiz_fov_radians = horizontal_field_of_view_ * DEGREE_TO_RADIAN; - double p0 = static_cast(pixels()[0]); - double p1 = static_cast(pixels()[1]); - double vert_fov_radians = horiz_fov_radians * p1 / p0; - - // focal_plane_dist can be changed to alter the perspective distortion - // effect. This is in units of cm. This seems to look good most of the - // time. TODO let this variable be set through XML. - constexpr double focal_plane_dist = 10.0; - const double dx = 2.0 * focal_plane_dist * std::tan(0.5 * horiz_fov_radians); - const double dy = p1 / p0 * dx; - - std::pair result; - - // Generate the starting position/direction of the ray - if (orthographic_width_ == C_NONE) { // perspective projection - Direction camera_local_vec; - camera_local_vec.x = focal_plane_dist; - camera_local_vec.y = -0.5 * dx + horiz * dx / p0; - camera_local_vec.z = 0.5 * dy - vert * dy / p1; - camera_local_vec /= camera_local_vec.norm(); - - result.first = camera_position_; - result.second = camera_local_vec.rotate(camera_to_model_); - } else { // orthographic projection - - double x_pix_coord = (static_cast(horiz) - p0 / 2.0) / p0; - double y_pix_coord = (static_cast(vert) - p1 / 2.0) / p1; - - result.first = camera_position_ + - camera_y_axis() * x_pix_coord * orthographic_width_ + - camera_z_axis() * y_pix_coord * orthographic_width_; - result.second = camera_x_axis(); - } - - return result; -} - -ImageData WireframeRayTracePlot::create_image() const -{ - size_t width = pixels()[0]; - size_t height = pixels()[1]; - ImageData data({width, height}, not_found_); - - // This array marks where the initial wireframe was drawn. We convolve it with - // a filter that gets adjusted with the wireframe thickness in order to - // thicken the lines. - tensor::Tensor wireframe_initial( - {static_cast(width), static_cast(height)}, 0); - - /* Holds all of the track segments for the current rendered line of pixels. - * old_segments holds a copy of this_line_segments from the previous line. - * By holding both we can check if the cell/material intersection stack - * differs from the left or upper neighbor. This allows a robustly drawn - * wireframe. If only checking the left pixel (which requires substantially - * less memory), the wireframe tends to be spotty and be disconnected for - * surface edges oriented horizontally in the rendering. - * - * Note that a vector of vectors is required rather than a 2-tensor, - * since the stack size varies within each column. - */ - const int n_threads = num_threads(); - std::vector>> this_line_segments( - n_threads); - for (int t = 0; t < n_threads; ++t) { - this_line_segments[t].resize(pixels()[0]); - } - - // The last thread writes to this, and the first thread reads from it. - std::vector> old_segments(pixels()[0]); - -#pragma omp parallel - { - const int n_threads = num_threads(); - const int tid = thread_num(); - - int vert = tid; - for (int iter = 0; iter <= pixels()[1] / n_threads; iter++) { - - // Save bottom line of current work chunk to compare against later. This - // used to be inside the below if block, but it causes a spurious line to - // be drawn at the bottom of the image. Not sure why, but moving it here - // fixes things. - if (tid == n_threads - 1) - old_segments = this_line_segments[n_threads - 1]; - - if (vert < pixels()[1]) { - - for (int horiz = 0; horiz < pixels()[0]; ++horiz) { - - // RayTracePlot implements camera ray generation - std::pair ru = get_pixel_ray(horiz, vert); - - this_line_segments[tid][horiz].clear(); - ProjectionRay ray( - ru.first, ru.second, *this, this_line_segments[tid][horiz]); - - ray.trace(); - - // Now color the pixel based on what we have intersected... - // Loops backwards over intersections. - Position current_color( - not_found_.red, not_found_.green, not_found_.blue); - const auto& segments = this_line_segments[tid][horiz]; - - // There must be at least two cell intersections to color, front and - // back of the cell. Maybe an infinitely thick cell could be present - // with no back, but why would you want to color that? It's easier to - // just skip that edge case and not even color it. - if (segments.size() <= 1) - continue; - - for (int i = segments.size() - 2; i >= 0; --i) { - int colormap_idx = segments[i].id; - RGBColor seg_color = colors_[colormap_idx]; - Position seg_color_vec( - seg_color.red, seg_color.green, seg_color.blue); - double mixing = - std::exp(-xs_[colormap_idx] * - (segments[i + 1].length - segments[i].length)); - current_color = - current_color * mixing + (1.0 - mixing) * seg_color_vec; - } - - // save result converting from double-precision color coordinates to - // byte-sized - RGBColor result; - result.red = static_cast(current_color.x); - result.green = static_cast(current_color.y); - result.blue = static_cast(current_color.z); - data(horiz, vert) = result; - - // Check to draw wireframe in horizontal direction. No inter-thread - // comm. - if (horiz > 0) { - if (!trackstack_equivalent(this_line_segments[tid][horiz], - this_line_segments[tid][horiz - 1])) { - wireframe_initial(horiz, vert) = 1; - } - } - } - } // end "if" vert in correct range - - // We require a barrier before comparing vertical neighbors' intersection - // stacks. i.e. all threads must be done with their line. -#pragma omp barrier - - // Now that the horizontal line has finished rendering, we can fill in - // wireframe entries that require comparison among all the threads. Hence - // the omp barrier being used. It has to be OUTSIDE any if blocks! - if (vert < pixels()[1]) { - // Loop over horizontal pixels, checking intersection stack of upper - // neighbor - - const std::vector>* top_cmp = nullptr; - if (tid == 0) - top_cmp = &old_segments; - else - top_cmp = &this_line_segments[tid - 1]; - - for (int horiz = 0; horiz < pixels()[0]; ++horiz) { - if (!trackstack_equivalent( - this_line_segments[tid][horiz], (*top_cmp)[horiz])) { - wireframe_initial(horiz, vert) = 1; - } - } - } - - // We need another barrier to ensure threads don't proceed to modify their - // intersection stacks on that horizontal line while others are - // potentially still working on the above. -#pragma omp barrier - vert += n_threads; - } - } // end omp parallel - - // Now thicken the wireframe lines and apply them to our image - for (int vert = 0; vert < pixels()[1]; ++vert) { - for (int horiz = 0; horiz < pixels()[0]; ++horiz) { - if (wireframe_initial(horiz, vert)) { - if (wireframe_thickness_ == 1) - data(horiz, vert) = wireframe_color_; - for (int i = -wireframe_thickness_ / 2; i < wireframe_thickness_ / 2; - ++i) - for (int j = -wireframe_thickness_ / 2; j < wireframe_thickness_ / 2; - ++j) - if (i * i + j * j < wireframe_thickness_ * wireframe_thickness_) { - - // Check if wireframe pixel is out of bounds - int w_i = std::max(std::min(horiz + i, pixels()[0] - 1), 0); - int w_j = std::max(std::min(vert + j, pixels()[1] - 1), 0); - data(w_i, w_j) = wireframe_color_; - } - } - } - } - - return data; -} - -void WireframeRayTracePlot::create_output() const -{ - ImageData data = create_image(); - write_image(data); -} - -void RayTracePlot::print_info() const -{ - fmt::print("Camera position: {} {} {}\n", camera_position_.x, - camera_position_.y, camera_position_.z); - fmt::print("Look at: {} {} {}\n", look_at_.x, look_at_.y, look_at_.z); - fmt::print( - "Horizontal field of view: {} degrees\n", horizontal_field_of_view_); - fmt::print("Pixels: {} {}\n", pixels()[0], pixels()[1]); -} - -void WireframeRayTracePlot::print_info() const -{ - fmt::print("Plot Type: Wireframe ray-traced\n"); - RayTracePlot::print_info(); -} - -void WireframeRayTracePlot::set_opacities(pugi::xml_node node) -{ - xs_.resize(colors_.size(), 1e6); // set to large value for opaque by default - - for (auto cn : node.children("color")) { - // Make sure 3 values are specified for RGB - double user_xs = std::stod(get_node_value(cn, "xs")); - int col_id = std::stoi(get_node_value(cn, "id")); - - // Add RGB - if (PlotColorBy::cells == color_by_) { - if (model::cell_map.find(col_id) != model::cell_map.end()) { - col_id = model::cell_map[col_id]; - xs_[col_id] = user_xs; - } else { - warning(fmt::format( - "Could not find cell {} specified in plot {}", col_id, id())); - } - } else if (PlotColorBy::mats == color_by_) { - if (model::material_map.find(col_id) != model::material_map.end()) { - col_id = model::material_map[col_id]; - xs_[col_id] = user_xs; - } else { - warning(fmt::format( - "Could not find material {} specified in plot {}", col_id, id())); - } - } - } -} - -void RayTracePlot::set_orthographic_width(pugi::xml_node node) -{ - if (check_for_node(node, "orthographic_width")) { - double orthographic_width = - std::stod(get_node_value(node, "orthographic_width", true)); - if (orthographic_width < 0.0) - fatal_error("Requires positive orthographic_width"); - orthographic_width_ = orthographic_width; - } -} - -void WireframeRayTracePlot::set_wireframe_thickness(pugi::xml_node node) -{ - if (check_for_node(node, "wireframe_thickness")) { - int wireframe_thickness = - std::stoi(get_node_value(node, "wireframe_thickness", true)); - if (wireframe_thickness < 0) - fatal_error("Requires non-negative wireframe thickness"); - wireframe_thickness_ = wireframe_thickness; - } -} - -void WireframeRayTracePlot::set_wireframe_ids(pugi::xml_node node) -{ - if (check_for_node(node, "wireframe_ids")) { - wireframe_ids_ = get_node_array(node, "wireframe_ids"); - // It is read in as actual ID values, but we have to convert to indices in - // mat/cell array - for (auto& x : wireframe_ids_) - x = color_by_ == PlotColorBy::mats ? model::material_map[x] - : model::cell_map[x]; - } - // We make sure the list is sorted in order to later use - // std::binary_search. - std::sort(wireframe_ids_.begin(), wireframe_ids_.end()); -} - -void RayTracePlot::set_pixels(pugi::xml_node node) -{ - vector pxls = get_node_array(node, "pixels"); - if (pxls.size() != 2) - fatal_error( - fmt::format(" must be length 2 in projection plot {}", id())); - pixels()[0] = pxls[0]; - pixels()[1] = pxls[1]; -} - -void RayTracePlot::set_camera_position(pugi::xml_node node) -{ - vector camera_pos = get_node_array(node, "camera_position"); - if (camera_pos.size() != 3) { - fatal_error(fmt::format( - "camera_position element must have three floating point values")); - } - camera_position_.x = camera_pos[0]; - camera_position_.y = camera_pos[1]; - camera_position_.z = camera_pos[2]; -} - -void RayTracePlot::set_look_at(pugi::xml_node node) -{ - vector look_at = get_node_array(node, "look_at"); - if (look_at.size() != 3) { - fatal_error("look_at element must have three floating point values"); - } - look_at_.x = look_at[0]; - look_at_.y = look_at[1]; - look_at_.z = look_at[2]; -} - -void RayTracePlot::set_field_of_view(pugi::xml_node node) -{ - // Defaults to 70 degree horizontal field of view (see .h file) - if (check_for_node(node, "horizontal_field_of_view")) { - double fov = - std::stod(get_node_value(node, "horizontal_field_of_view", true)); - if (fov < 180.0 && fov > 0.0) { - horizontal_field_of_view_ = fov; - } else { - fatal_error(fmt::format("Horizontal field of view for plot {} " - "out-of-range. Must be in (0, 180) degrees.", - id())); - } - } -} - -SolidRayTracePlot::SolidRayTracePlot(pugi::xml_node node) : RayTracePlot(node) -{ - set_opaque_ids(node); - set_diffuse_fraction(node); - set_light_position(node); - update_view(); -} - -void SolidRayTracePlot::print_info() const -{ - fmt::print("Plot Type: Solid ray-traced\n"); - RayTracePlot::print_info(); -} - -ImageData SolidRayTracePlot::create_image() const -{ - size_t width = pixels()[0]; - size_t height = pixels()[1]; - ImageData data({width, height}, not_found_); - -#pragma omp parallel for schedule(dynamic) collapse(2) - for (int horiz = 0; horiz < pixels()[0]; ++horiz) { - for (int vert = 0; vert < pixels()[1]; ++vert) { - // RayTracePlot implements camera ray generation - std::pair ru = get_pixel_ray(horiz, vert); - PhongRay ray(ru.first, ru.second, *this); - ray.trace(); - data(horiz, vert) = ray.result_color(); - } - } - - return data; -} - -void SolidRayTracePlot::create_output() const -{ - ImageData data = create_image(); - write_image(data); -} - -void SolidRayTracePlot::set_opaque_ids(pugi::xml_node node) -{ - if (check_for_node(node, "opaque_ids")) { - auto opaque_ids_tmp = get_node_array(node, "opaque_ids"); - - // It is read in as actual ID values, but we have to convert to indices in - // mat/cell array - for (auto& x : opaque_ids_tmp) - x = color_by_ == PlotColorBy::mats ? model::material_map[x] - : model::cell_map[x]; - - opaque_ids_.insert(opaque_ids_tmp.begin(), opaque_ids_tmp.end()); - } -} - -void SolidRayTracePlot::set_light_position(pugi::xml_node node) -{ - if (check_for_node(node, "light_position")) { - auto light_pos_tmp = get_node_array(node, "light_position"); - - if (light_pos_tmp.size() != 3) - fatal_error("Light position must be given as 3D coordinates"); - - light_location_.x = light_pos_tmp[0]; - light_location_.y = light_pos_tmp[1]; - light_location_.z = light_pos_tmp[2]; - } else { - light_location_ = camera_position(); - } -} - -void SolidRayTracePlot::set_diffuse_fraction(pugi::xml_node node) -{ - if (check_for_node(node, "diffuse_fraction")) { - diffuse_fraction_ = std::stod(get_node_value(node, "diffuse_fraction")); - if (diffuse_fraction_ < 0.0 || diffuse_fraction_ > 1.0) { - fatal_error("Must have 0 <= diffuse fraction <= 1"); - } - } -} - -void ProjectionRay::on_intersection() -{ - // This records a tuple with the following info - // - // 1) ID (material or cell depending on color_by_) - // 2) Distance traveled by the ray through that ID - // 3) Index of the intersected surface (starting from 1) - - line_segments_.emplace_back( - plot_.color_by_ == PlottableInterface::PlotColorBy::mats - ? material() - : lowest_coord().cell(), - traversal_distance_, boundary().surface_index()); -} - -void PhongRay::on_intersection() -{ - // Check if we hit an opaque material or cell - int hit_id = plot_.color_by_ == PlottableInterface::PlotColorBy::mats - ? material() - : lowest_coord().cell(); - - // If we are reflected and have advanced beyond the camera, - // the ray is done. This is checked here because we should - // kill the ray even if the material is not opaque. - if (reflected_ && (r() - plot_.camera_position()).dot(u()) >= 0.0) { - stop(); - return; - } - - // Anything that's not opaque has zero impact on the plot. - if (plot_.opaque_ids_.find(hit_id) == plot_.opaque_ids_.end()) - return; - - if (!reflected_) { - // reflect the particle and set the color to be colored by - // the normal or the diffuse lighting contribution - reflected_ = true; - result_color_ = plot_.colors_[hit_id]; - // The ray has been advanced slightly past the boundary. Use an - // approximation to the actual hit point for stable normal/lighting. - Position r_hit = r() - TINY_BIT * u(); - Direction to_light = plot_.light_location_ - r_hit; - to_light /= to_light.norm(); - - // TODO - // Not sure what can cause a surface token to be invalid here, although it - // sometimes happens for a few pixels. It's very very rare, so proceed by - // coloring the pixel with the overlap color. It seems to happen only for a - // few pixels on the outer boundary of a hex lattice. - // - // We cannot detect it in the outer loop, and it only matters here, so - // that's why the error handling is a little different than for a lost - // ray. - if (surface() == 0) { - result_color_ = plot_.overlap_color_; - stop(); - return; - } - - // Get surface pointer - const auto& surf = model::surfaces.at(surface_index()); - - // The crossed surface may be on a higher coordinate level than the - // innermost local coordinates, so we check the surface's coordinate level - // to find the appropriate coordinate level to use for the normal - // calculation - int surf_level = boundary().coord_level() - 1; - // ensure surface level is within bounds of current coordinate stack - surf_level = std::max(0, std::min(surf_level, n_coord() - 1)); - - Position r_hit_level = - coord(surf_level).r() - TINY_BIT * coord(surf_level).u(); - Direction normal = surf->normal(r_hit_level); - normal /= normal.norm(); - - // Need to apply rotations to find the normal vector in - // the base level universe's coordinate system. - for (int lev = surf_level - 1; lev >= 0; --lev) { - if (coord(lev + 1).rotated()) { - const Cell& c {*model::cells[coord(lev).cell()]}; - normal = normal.inverse_rotate(c.rotation_); - } - } - - // use the normal opposed to the ray direction - if (normal.dot(u()) > 0.0) { - normal *= -1.0; - } - - // Facing away from the light means no lighting - double dotprod = normal.dot(to_light); - dotprod = std::max(0.0, dotprod); - - double modulation = - plot_.diffuse_fraction_ + (1.0 - plot_.diffuse_fraction_) * dotprod; - result_color_ *= modulation; - - // Now point the particle to the camera. We now begin - // checking to see if it's occluded by another surface - u() = to_light; - - orig_hit_id_ = hit_id; - - // OpenMC native CSG and DAGMC surfaces have some slight differences - // in how they interpret particles that are sitting on a surface. - // I don't know exactly why, but this makes everything work beautifully. - if (surf->geom_type() == GeometryType::DAG) { - surface() = 0; - } else { - surface() = -surface(); // go to other side - } - - // Must fully restart coordinate search. Why? Not sure. - clear(); - - // Note this could likely be faster if we cached the previous - // cell we were in before the reflection. This is the easiest - // way to fully initialize all the sub-universe coordinates and - // directions though. - bool found = exhaustive_find_cell(*this); - if (!found) { - fatal_error("Lost particle after reflection."); - } - - // Must recalculate distance to boundary due to the - // direction change - compute_distance(); - - } else { - // If it's not facing the light, we color with the diffuse contribution, so - // next we check if we're going to occlude the last reflected surface. if - // so, color by the diffuse contribution instead - - if (orig_hit_id_ == -1) - fatal_error("somehow a ray got reflected but not original ID set?"); - - result_color_ = plot_.colors_[orig_hit_id_]; - result_color_ *= plot_.diffuse_fraction_; - stop(); - } -} - extern "C" int openmc_id_map(const void* plot, int32_t* data_out) { - static bool warned {false}; - if (!warned) { - warning("openmc_id_map is deprecated and will be removed in a future " - "release. Use openmc_slice_data."); - warned = true; - } - auto plt = reinterpret_cast(plot); + auto plt = reinterpret_cast(plot); if (!plt) { set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; } - if (plt->show_overlaps_ && model::overlap_check_count.size() == 0) { + if (plt->color_overlaps_ && model::overlap_check_count.size() == 0) { model::overlap_check_count.resize(model::cells.size()); } @@ -1919,20 +1003,14 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) extern "C" int openmc_property_map(const void* plot, double* data_out) { - static bool warned {false}; - if (!warned) { - warning("openmc_property_map is deprecated and will be removed in a future " - "release. Use openmc_slice_data."); - warned = true; - } - auto plt = reinterpret_cast(plot); + auto plt = reinterpret_cast(plot); if (!plt) { - set_errmsg("Invalid slice pointer passed to openmc_property_map"); + set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; } - if (plt->show_overlaps_ && model::overlap_check_count.size() == 0) { + if (plt->color_overlaps_ && model::overlap_check_count.size() == 0) { model::overlap_check_count.resize(model::cells.size()); } @@ -1944,678 +1022,4 @@ extern "C" int openmc_property_map(const void* plot, double* data_out) return 0; } -extern "C" int openmc_slice_data(const double origin[3], const double u_span[3], - const double v_span[3], const size_t pixels[2], bool color_overlaps, - int level, int32_t filter_index, int32_t* geom_data, double* property_data) -{ - // Validate span vectors - Direction u_span_pos {u_span[0], u_span[1], u_span[2]}; - Direction v_span_pos {v_span[0], v_span[1], v_span[2]}; - double u_norm = u_span_pos.norm(); - double v_norm = v_span_pos.norm(); - if (u_norm == 0.0 || v_norm == 0.0) { - set_errmsg("Slice span vectors must be non-zero."); - return OPENMC_E_INVALID_ARGUMENT; - } - - constexpr double ORTHO_REL_TOL = 1e-10; - double dot = u_span_pos.dot(v_span_pos); - if (std::abs(dot) > ORTHO_REL_TOL * u_norm * v_norm) { - set_errmsg("Slice span vectors must be orthogonal."); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Validate filter index if provided - if (filter_index >= 0) { - if (int err = verify_filter(filter_index)) - return err; - } - - // Initialize overlap check vector if needed - if (color_overlaps && model::overlap_check_count.size() == 0) { - model::overlap_check_count.resize(model::cells.size()); - } - - try { - // Create a temporary SlicePlotBase object to reuse get_map logic - SlicePlotBase plot_params; - plot_params.origin_ = Position {origin[0], origin[1], origin[2]}; - plot_params.u_span_ = u_span_pos; - plot_params.v_span_ = v_span_pos; - plot_params.pixels_[0] = pixels[0]; - plot_params.pixels_[1] = pixels[1]; - plot_params.show_overlaps_ = color_overlaps; - plot_params.slice_level_ = level; - - // Clear overlap data structures on new slice call - model::overlap_keys.clear(); - model::overlap_key_index.clear(); - - // Use get_map to generate data - auto data = plot_params.get_map(filter_index); - std::copy(data.id_data_.begin(), data.id_data_.end(), geom_data); - - // Copy property data if requested - if (property_data != nullptr) { - std::copy( - data.property_data_.begin(), data.property_data_.end(), property_data); - } - } catch (const std::exception& e) { - set_errmsg(e.what()); - return OPENMC_E_UNASSIGNED; - } - - return 0; -} - -// Gets the number of overlaps that we need data for -extern "C" int openmc_slice_data_overlap_count(size_t* count) -{ - if (!count) { - set_errmsg("Null pointer passed for overlap count."); - return OPENMC_E_INVALID_ARGUMENT; - } - *count = model::overlap_keys.size(); - - return 0; -} - -// Plotter pre-allocates array size based on what is returned with -// overlap_count; populates an array of size 3*count -extern "C" int openmc_slice_data_overlap_info( - size_t count, int32_t* overlap_info) -{ - for (size_t i = 0; i < count; ++i) { - overlap_info[i * 3] = model::overlap_keys[i].universe_id; - overlap_info[i * 3 + 1] = model::overlap_keys[i].cell1_id; - overlap_info[i * 3 + 2] = model::overlap_keys[i].cell2_id; - } - - return 0; -} - -extern "C" int openmc_get_plot_index(int32_t id, int32_t* index) -{ - auto it = model::plot_map.find(id); - if (it == model::plot_map.end()) { - set_errmsg("No plot exists with ID=" + std::to_string(id) + "."); - return OPENMC_E_INVALID_ID; - } - - *index = it->second; - return 0; -} - -extern "C" int openmc_plot_get_id(int32_t index, int32_t* id) -{ - if (index < 0 || index >= model::plots.size()) { - set_errmsg("Index in plots array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - *id = model::plots[index]->id(); - return 0; -} - -extern "C" int openmc_plot_set_id(int32_t index, int32_t id) -{ - if (index < 0 || index >= model::plots.size()) { - set_errmsg("Index in plots array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - if (id < 0 && id != C_NONE) { - set_errmsg("Invalid plot ID."); - return OPENMC_E_INVALID_ARGUMENT; - } - - auto* plot = model::plots[index].get(); - int32_t old_id = plot->id(); - if (id == old_id) - return 0; - - model::plot_map.erase(old_id); - try { - plot->set_id(id); - } catch (const std::runtime_error& e) { - model::plot_map[old_id] = index; - set_errmsg(e.what()); - return OPENMC_E_INVALID_ID; - } - model::plot_map[plot->id()] = index; - return 0; -} - -extern "C" size_t openmc_plots_size() -{ - return model::plots.size(); -} - -int map_phong_domain_id( - const SolidRayTracePlot* plot, int32_t id, int32_t* index_out) -{ - if (!plot || !index_out) { - set_errmsg("Invalid plot pointer passed to map_phong_domain_id"); - return OPENMC_E_INVALID_ARGUMENT; - } - - if (plot->color_by_ == PlottableInterface::PlotColorBy::mats) { - auto it = model::material_map.find(id); - if (it == model::material_map.end()) { - set_errmsg("Invalid material ID for SolidRayTracePlot"); - return OPENMC_E_INVALID_ID; - } - *index_out = it->second; - return 0; - } - - if (plot->color_by_ == PlottableInterface::PlotColorBy::cells) { - auto it = model::cell_map.find(id); - if (it == model::cell_map.end()) { - set_errmsg("Invalid cell ID for SolidRayTracePlot"); - return OPENMC_E_INVALID_ID; - } - *index_out = it->second; - return 0; - } - - set_errmsg("Unsupported color_by for SolidRayTracePlot"); - return OPENMC_E_INVALID_TYPE; -} - -int get_solidraytrace_plot_by_index(int32_t index, SolidRayTracePlot** plot) -{ - if (!plot) { - set_errmsg("Null output pointer passed to get_solidraytrace_plot_by_index"); - return OPENMC_E_INVALID_ARGUMENT; - } - - if (index < 0 || index >= model::plots.size()) { - set_errmsg("Index in plots array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - - auto* plottable = model::plots[index].get(); - auto* solid_plot = dynamic_cast(plottable); - if (!solid_plot) { - set_errmsg("Plot at index=" + std::to_string(index) + - " is not a solid raytrace plot."); - return OPENMC_E_INVALID_TYPE; - } - - *plot = solid_plot; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_create(int32_t* index) -{ - if (!index) { - set_errmsg( - "Null output pointer passed to openmc_solidraytrace_plot_create"); - return OPENMC_E_INVALID_ARGUMENT; - } - - try { - auto new_plot = std::make_unique(); - new_plot->set_id(); - int32_t new_plot_id = new_plot->id(); -#ifdef USE_LIBPNG - new_plot->path_plot() = fmt::format("plot_{}.png", new_plot_id); -#else - new_plot->path_plot() = fmt::format("plot_{}.ppm", new_plot_id); -#endif - int32_t new_plot_index = model::plots.size(); - model::plots.emplace_back(std::move(new_plot)); - model::plot_map[new_plot_id] = new_plot_index; - *index = new_plot_index; - } catch (const std::exception& e) { - set_errmsg(e.what()); - return OPENMC_E_ALLOCATE; - } - - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_pixels( - int32_t index, int32_t* width, int32_t* height) -{ - if (!width || !height) { - set_errmsg( - "Invalid arguments passed to openmc_solidraytrace_plot_get_pixels"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - *width = plt->pixels()[0]; - *height = plt->pixels()[1]; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_pixels( - int32_t index, int32_t width, int32_t height) -{ - if (width <= 0 || height <= 0) { - set_errmsg( - "Invalid arguments passed to openmc_solidraytrace_plot_set_pixels"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->pixels()[0] = width; - plt->pixels()[1] = height; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_color_by( - int32_t index, int32_t* color_by) -{ - if (!color_by) { - set_errmsg( - "Invalid arguments passed to openmc_solidraytrace_plot_get_color_by"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - if (plt->color_by_ == PlottableInterface::PlotColorBy::mats) { - *color_by = 0; - } else if (plt->color_by_ == PlottableInterface::PlotColorBy::cells) { - *color_by = 1; - } else { - set_errmsg("Unsupported color_by for SolidRayTracePlot"); - return OPENMC_E_INVALID_TYPE; - } - - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_color_by( - int32_t index, int32_t color_by) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - if (color_by == 0) { - plt->color_by_ = PlottableInterface::PlotColorBy::mats; - } else if (color_by == 1) { - plt->color_by_ = PlottableInterface::PlotColorBy::cells; - } else { - set_errmsg("Invalid color_by value for SolidRayTracePlot"); - return OPENMC_E_INVALID_ARGUMENT; - } - - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_default_colors(int32_t index) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->set_default_colors(); - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_all_opaque(int32_t index) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->opaque_ids().clear(); - if (plt->color_by_ == PlottableInterface::PlotColorBy::mats) { - for (int32_t i = 0; i < model::materials.size(); ++i) { - plt->opaque_ids().insert(i); - } - return 0; - } - - if (plt->color_by_ == PlottableInterface::PlotColorBy::cells) { - for (int32_t i = 0; i < model::cells.size(); ++i) { - plt->opaque_ids().insert(i); - } - return 0; - } - - set_errmsg("Unsupported color_by for SolidRayTracePlot"); - return OPENMC_E_INVALID_TYPE; -} - -extern "C" int openmc_solidraytrace_plot_set_opaque( - int32_t index, int32_t id, bool visible) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - int32_t domain_index = -1; - err = map_phong_domain_id(plt, id, &domain_index); - if (err) - return err; - - if (visible) { - plt->opaque_ids().insert(domain_index); - } else { - plt->opaque_ids().erase(domain_index); - } - - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_color( - int32_t index, int32_t id, uint8_t r, uint8_t g, uint8_t b) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - int32_t domain_index = -1; - err = map_phong_domain_id(plt, id, &domain_index); - if (err) - return err; - - if (domain_index < 0 || - static_cast(domain_index) >= plt->colors_.size()) { - set_errmsg("Color index out of range for SolidRayTracePlot"); - return OPENMC_E_OUT_OF_BOUNDS; - } - - plt->colors_[domain_index] = RGBColor(r, g, b); - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_camera_position( - int32_t index, double* x, double* y, double* z) -{ - if (!x || !y || !z) { - set_errmsg("Invalid arguments passed to " - "openmc_solidraytrace_plot_get_camera_position"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - const auto& camera_position = plt->camera_position(); - *x = camera_position.x; - *y = camera_position.y; - *z = camera_position.z; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_camera_position( - int32_t index, double x, double y, double z) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->camera_position() = {x, y, z}; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_look_at( - int32_t index, double* x, double* y, double* z) -{ - if (!x || !y || !z) { - set_errmsg( - "Invalid arguments passed to openmc_solidraytrace_plot_get_look_at"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - const auto& look_at = plt->look_at(); - *x = look_at.x; - *y = look_at.y; - *z = look_at.z; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_look_at( - int32_t index, double x, double y, double z) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->look_at() = {x, y, z}; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_up( - int32_t index, double* x, double* y, double* z) -{ - if (!x || !y || !z) { - set_errmsg("Invalid arguments passed to openmc_solidraytrace_plot_get_up"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - const auto& up = plt->up(); - *x = up.x; - *y = up.y; - *z = up.z; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_up( - int32_t index, double x, double y, double z) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->up() = {x, y, z}; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_light_position( - int32_t index, double* x, double* y, double* z) -{ - if (!x || !y || !z) { - set_errmsg("Invalid arguments passed to " - "openmc_solidraytrace_plot_get_light_position"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - const auto& light_position = plt->light_location(); - *x = light_position.x; - *y = light_position.y; - *z = light_position.z; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_light_position( - int32_t index, double x, double y, double z) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->light_location() = {x, y, z}; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_fov(int32_t index, double* fov) -{ - if (!fov) { - set_errmsg("Invalid arguments passed to openmc_solidraytrace_plot_get_fov"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - *fov = plt->horizontal_field_of_view(); - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_fov(int32_t index, double fov) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->horizontal_field_of_view() = fov; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_update_view(int32_t index) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - plt->update_view(); - return 0; -} - -extern "C" int openmc_solidraytrace_plot_create_image( - int32_t index, uint8_t* data_out, int32_t width, int32_t height) -{ - if (!data_out || width <= 0 || height <= 0) { - set_errmsg( - "Invalid arguments passed to openmc_solidraytrace_plot_create_image"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - if (plt->pixels()[0] != width || plt->pixels()[1] != height) { - set_errmsg( - "Requested image size does not match SolidRayTracePlot pixel settings"); - return OPENMC_E_INVALID_SIZE; - } - - ImageData data = plt->create_image(); - if (static_cast(data.shape()[0]) != width || - static_cast(data.shape()[1]) != height) { - set_errmsg("Unexpected image size from SolidRayTracePlot create_image"); - return OPENMC_E_INVALID_SIZE; - } - - for (int32_t y = 0; y < height; ++y) { - for (int32_t x = 0; x < width; ++x) { - const auto& color = data(x, y); - size_t idx = (static_cast(y) * width + x) * 3; - data_out[idx + 0] = color.red; - data_out[idx + 1] = color.green; - data_out[idx + 2] = color.blue; - } - } - - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_color( - int32_t index, int32_t id, uint8_t* r, uint8_t* g, uint8_t* b) -{ - if (!r || !g || !b) { - set_errmsg( - "Invalid arguments passed to openmc_solidraytrace_plot_get_color"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - int32_t domain_index = -1; - err = map_phong_domain_id(plt, id, &domain_index); - if (err) - return err; - - if (domain_index < 0 || - static_cast(domain_index) >= plt->colors_.size()) { - set_errmsg("Color index out of range for SolidRayTracePlot"); - return OPENMC_E_OUT_OF_BOUNDS; - } - - const auto& color = plt->colors_[domain_index]; - *r = color.red; - *g = color.green; - *b = color.blue; - return 0; -} - -extern "C" int openmc_solidraytrace_plot_get_diffuse_fraction( - int32_t index, double* diffuse_fraction) -{ - if (!diffuse_fraction) { - set_errmsg("Invalid arguments passed to " - "openmc_solidraytrace_plot_get_diffuse_fraction"); - return OPENMC_E_INVALID_ARGUMENT; - } - - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - *diffuse_fraction = plt->diffuse_fraction(); - return 0; -} - -extern "C" int openmc_solidraytrace_plot_set_diffuse_fraction( - int32_t index, double diffuse_fraction) -{ - SolidRayTracePlot* plt = nullptr; - int err = get_solidraytrace_plot_by_index(index, &plt); - if (err) - return err; - - if (diffuse_fraction < 0.0 || diffuse_fraction > 1.0) { - set_errmsg("Diffuse fraction must be between 0 and 1"); - return OPENMC_E_INVALID_ARGUMENT; - } - - plt->diffuse_fraction() = diffuse_fraction; - return 0; -} - } // namespace openmc diff --git a/src/position.cpp b/src/position.cpp index 0361e99a0..5b3613b28 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -75,6 +75,13 @@ Position Position::operator-() const return {-x, -y, -z}; } +Position Position::rotate(const vector& rotation) const +{ + return {x * rotation[0] + y * rotation[1] + z * rotation[2], + x * rotation[3] + y * rotation[4] + z * rotation[5], + x * rotation[6] + y * rotation[7] + z * rotation[8]}; +} + std::ostream& operator<<(std::ostream& os, Position r) { os << "(" << r.x << ", " << r.y << ", " << r.z << ")"; diff --git a/src/random_dist.cpp b/src/random_dist.cpp index b05b76f99..c8d2380c3 100644 --- a/src/random_dist.cpp +++ b/src/random_dist.cpp @@ -12,11 +12,6 @@ double uniform_distribution(double a, double b, uint64_t* seed) return a + (b - a) * prn(seed); } -int64_t uniform_int_distribution(int64_t a, int64_t b, uint64_t* seed) -{ - return a + static_cast(prn(seed) * (b - a + 1)); -} - double maxwell_spectrum(double T, uint64_t* seed) { // Set the random numbers @@ -51,4 +46,11 @@ double normal_variate(double mean, double standard_deviation, uint64_t* seed) return mean + standard_deviation * z * x; } +double muir_spectrum(double e0, double m_rat, double kt, uint64_t* seed) +{ + // https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-05411-MS + double sigma = std::sqrt(4. * e0 * kt / m_rat); + return normal_variate(e0, sigma, seed); +} + } // namespace openmc diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index f2a81fc1c..581d69617 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -10,54 +10,14 @@ int64_t master_seed {1}; // LCG parameters constexpr uint64_t prn_mult {6364136223846793005ULL}; // multiplication constexpr uint64_t prn_add {1442695040888963407ULL}; // additive factor, c -uint64_t prn_stride {DEFAULT_STRIDE}; // stride between particles - -namespace { - -struct SkipAheadCoefficients { - uint64_t multiplier; - uint64_t increment; -}; - -SkipAheadCoefficients future_seed_coefficients(uint64_t n) -{ - // The algorithm here to determine the parameters used to skip ahead is - // described in F. Brown, "Random Number Generation with Arbitrary Stride," - // Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in - // O(log2(N)) operations instead of O(N). Basically, it computes parameters G - // and C which can then be used to find x_N = G*x_0 + C mod 2^M. - - // Initialize constants - uint64_t g {prn_mult}; - uint64_t c {prn_add}; - uint64_t g_new {1}; - uint64_t c_new {0}; - - while (n > 0) { - // Check if the least significant bit is 1. - if (n & 1) { - g_new *= g; - c_new = c_new * g + c; - } - c *= (g + 1); - g *= g; - - // Move bits right, dropping least significant bit. - n >>= 1; - } - - return {g_new, c_new}; -} - -} // namespace +constexpr uint64_t prn_stride {152917LL}; // stride between particles //============================================================================== // PRN //============================================================================== // 64 bit implementation of the PCG-RXS-M-XS 64-bit state / 64-bit output -// geneator Adapted from: https://github.com/imneme/pcg-c, in particular -// https://github.com/imneme/pcg-c/blob/83252d9c23df9c82ecb42210afed61a7b42402d7/include/pcg_variants.h#L188-L192 +// geneator Adapted from: https://github.com/imneme/pcg-c // @techreport{oneill:pcg2014, // title = "PCG: A Family of Simple Fast Space-Efficient Statistically Good // Algorithms for Random Number Generation", author = "Melissa E. O'Neill", @@ -108,10 +68,9 @@ uint64_t init_seed(int64_t id, int offset) void init_particle_seeds(int64_t id, uint64_t* seeds) { - auto [multiplier, increment] = - future_seed_coefficients(static_cast(id) * prn_stride); for (int i = 0; i < N_STREAMS; i++) { - seeds[i] = multiplier * (master_seed + i) + increment; + seeds[i] = + future_seed(static_cast(id) * prn_stride, master_seed + i); } } @@ -130,9 +89,33 @@ void advance_prn_seed(int64_t n, uint64_t* seed) uint64_t future_seed(uint64_t n, uint64_t seed) { + // The algorithm here to determine the parameters used to skip ahead is + // described in F. Brown, "Random Number Generation with Arbitrary Stride," + // Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in + // O(log2(N)) operations instead of O(N). Basically, it computes parameters G + // and C which can then be used to find x_N = G*x_0 + C mod 2^M. + + // Initialize constants + uint64_t g {prn_mult}; + uint64_t c {prn_add}; + uint64_t g_new {1}; + uint64_t c_new {0}; + + while (n > 0) { + // Check if the least significant bit is 1. + if (n & 1) { + g_new *= g; + c_new = c_new * g + c; + } + c *= (g + 1); + g *= g; + + // Move bits right, dropping least significant bit. + n >>= 1; + } + // With G and C, we can now find the new seed. - auto [multiplier, increment] = future_seed_coefficients(n); - return multiplier * seed + increment; + return g_new * seed + c_new; } //============================================================================== @@ -149,14 +132,4 @@ extern "C" void openmc_set_seed(int64_t new_seed) master_seed = new_seed; } -extern "C" uint64_t openmc_get_stride() -{ - return prn_stride; -} - -extern "C" void openmc_set_stride(uint64_t new_stride) -{ - prn_stride = new_stride; -} - } // namespace openmc diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp deleted file mode 100644 index 83128fdaa..000000000 --- a/src/random_ray/flat_source_domain.cpp +++ /dev/null @@ -1,1852 +0,0 @@ -#include "openmc/random_ray/flat_source_domain.h" - -#include "openmc/cell.h" -#include "openmc/constants.h" -#include "openmc/eigenvalue.h" -#include "openmc/geometry.h" -#include "openmc/material.h" -#include "openmc/message_passing.h" -#include "openmc/mgxs_interface.h" -#include "openmc/output.h" -#include "openmc/plot.h" -#include "openmc/random_ray/random_ray.h" -#include "openmc/simulation.h" -#include "openmc/tallies/filter.h" -#include "openmc/tallies/tally.h" -#include "openmc/tallies/tally_scoring.h" -#include "openmc/timer.h" -#include "openmc/weight_windows.h" - -#include -#include - -namespace openmc { - -//============================================================================== -// FlatSourceDomain implementation -//============================================================================== - -// Static Variable Declarations -RandomRayVolumeEstimator FlatSourceDomain::volume_estimator_ { - RandomRayVolumeEstimator::HYBRID}; -bool FlatSourceDomain::volume_normalized_flux_tallies_ {false}; -bool FlatSourceDomain::adjoint_requested_ {false}; -RandomRaySolve FlatSourceDomain::solve_ {RandomRaySolve::FORWARD}; -bool FlatSourceDomain::fw_cadis_local_ {false}; -double FlatSourceDomain::diagonal_stabilization_rho_ {1.0}; -std::unordered_map>> - FlatSourceDomain::mesh_domain_map_; -std::vector FlatSourceDomain::fw_cadis_local_targets_; - -FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) -{ - // Count the number of source regions, compute the cell offset - // indices, and store the material type The reason for the offsets is that - // some cell types may not have material fills, and therefore do not - // produce FSRs. Thus, we cannot index into the global arrays directly - int base_source_regions = 0; - for (const auto& c : model::cells) { - if (c->type_ != Fill::MATERIAL) { - source_region_offsets_.push_back(-1); - } else { - source_region_offsets_.push_back(base_source_regions); - base_source_regions += c->n_instances(); - } - } - - // Initialize source regions. - bool is_linear = RandomRay::source_shape_ != RandomRaySourceShape::FLAT; - source_regions_ = SourceRegionContainer(negroups_, is_linear); - - // Initialize tally volumes - if (volume_normalized_flux_tallies_) { - tally_volumes_.resize(model::tallies.size()); - for (int i = 0; i < model::tallies.size(); i++) { - // Get the shape of the 3D result tensor - auto shape = model::tallies[i]->results().shape(); - - // Create a new 2D tensor with the same size as the first - // two dimensions of the 3D tensor - tally_volumes_[i] = tensor::Tensor({shape[0], shape[1]}); - } - } - - // Compute simulation domain volume based on ray source - auto* is = dynamic_cast(RandomRay::ray_source_.get()); - SpatialDistribution* space_dist = is->space(); - SpatialBox* sb = dynamic_cast(space_dist); - Position dims = sb->upper_right() - sb->lower_left(); - simulation_volume_ = dims.x * dims.y * dims.z; -} - -void FlatSourceDomain::batch_reset() -{ -// Reset scalar fluxes and iteration volume tallies to zero -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - source_regions_.volume(sr) = 0.0; - source_regions_.volume_sq(sr) = 0.0; - } - -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - source_regions_.scalar_flux_new(se) = 0.0; - } -} - -void FlatSourceDomain::accumulate_iteration_flux() -{ -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - source_regions_.scalar_flux_final(se) += - source_regions_.scalar_flux_new(se); - } -} - -void FlatSourceDomain::update_single_neutron_source(SourceRegionHandle& srh) -{ - // Reset all source regions to zero (important for void regions) - for (int g = 0; g < negroups_; g++) { - srh.source(g) = 0.0; - } - - // Add scattering + fission source - int material = srh.material(); - int temp = srh.temperature_idx(); - double density_mult = srh.density_mult(); - if (material != MATERIAL_VOID) { - double inverse_k_eff = 1.0 / k_eff_; - const int material_offset = (material * ntemperature_ + temp) * negroups_; - const int scatter_offset = - (material * ntemperature_ + temp) * negroups_ * negroups_; - for (int g_out = 0; g_out < negroups_; g_out++) { - double sigma_t = sigma_t_[material_offset + g_out] * density_mult; - double scatter_source = 0.0; - double fission_source = 0.0; - - for (int g_in = 0; g_in < negroups_; g_in++) { - double scalar_flux = srh.scalar_flux_old(g_in); - double sigma_s = - sigma_s_[scatter_offset + g_out * negroups_ + g_in] * density_mult; - double nu_sigma_f = nu_sigma_f_[material_offset + g_in] * density_mult; - double chi = chi_[material_offset + g_out]; - - scatter_source += sigma_s * scalar_flux; - if (settings::create_fission_neutrons) { - fission_source += nu_sigma_f * scalar_flux * chi; - } - } - srh.source(g_out) = - (scatter_source + fission_source * inverse_k_eff) / sigma_t; - } - } - - // Add external source if in fixed source mode - if (settings::run_mode == RunMode::FIXED_SOURCE) { - for (int g = 0; g < negroups_; g++) { - srh.source(g) += srh.external_source(g); - } - } -} - -// Compute new estimate of scattering + fission sources in each source region -// based on the flux estimate from the previous iteration. -void FlatSourceDomain::update_all_neutron_sources() -{ - simulation::time_update_src.start(); - -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - SourceRegionHandle srh = source_regions_.get_source_region_handle(sr); - update_single_neutron_source(srh); - } - - simulation::time_update_src.stop(); -} - -// Normalizes flux and updates simulation-averaged volume estimate -void FlatSourceDomain::normalize_scalar_flux_and_volumes( - double total_active_distance_per_iteration) -{ - double normalization_factor = 1.0 / total_active_distance_per_iteration; - double volume_normalization_factor = - 1.0 / (total_active_distance_per_iteration * simulation::current_batch); - -// Normalize scalar flux to total distance travelled by all rays this -// iteration -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - source_regions_.scalar_flux_new(se) *= normalization_factor; - } - -// Accumulate cell-wise ray length tallies collected this iteration, then -// update the simulation-averaged cell-wise volume estimates -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - source_regions_.volume_t(sr) += source_regions_.volume(sr); - source_regions_.volume_sq_t(sr) += source_regions_.volume_sq(sr); - source_regions_.volume_naive(sr) = - source_regions_.volume(sr) * normalization_factor; - source_regions_.volume_sq(sr) = - source_regions_.volume_sq_t(sr) / source_regions_.volume_t(sr); - source_regions_.volume(sr) = - source_regions_.volume_t(sr) * volume_normalization_factor; - } -} - -void FlatSourceDomain::set_flux_to_flux_plus_source( - int64_t sr, double volume, int g) -{ - int material = source_regions_.material(sr); - int temp = source_regions_.temperature_idx(sr); - if (material == MATERIAL_VOID) { - source_regions_.scalar_flux_new(sr, g) /= volume; - if (settings::run_mode == RunMode::FIXED_SOURCE) { - source_regions_.scalar_flux_new(sr, g) += - 0.5f * source_regions_.external_source(sr, g) * - source_regions_.volume_sq(sr); - } - } else { - double sigma_t = - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - source_regions_.density_mult(sr); - source_regions_.scalar_flux_new(sr, g) /= (sigma_t * volume); - source_regions_.scalar_flux_new(sr, g) += source_regions_.source(sr, g); - } -} - -void FlatSourceDomain::set_flux_to_old_flux(int64_t sr, int g) -{ - source_regions_.scalar_flux_new(sr, g) = - source_regions_.scalar_flux_old(sr, g); -} - -void FlatSourceDomain::set_flux_to_source(int64_t sr, int g) -{ - source_regions_.scalar_flux_new(sr, g) = source_regions_.source(sr, g); -} - -// Combine transport flux contributions and flat source contributions from the -// previous iteration to generate this iteration's estimate of scalar flux. -int64_t FlatSourceDomain::add_source_to_scalar_flux() -{ - int64_t n_hits = 0; - double inverse_batch = 1.0 / simulation::current_batch; - -#pragma omp parallel for reduction(+ : n_hits) - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - - double volume_simulation_avg = source_regions_.volume(sr); - double volume_iteration = source_regions_.volume_naive(sr); - - // Increment the number of hits if cell was hit this iteration - if (volume_iteration) { - n_hits++; - } - - // Set the SR to small status if its expected number of hits - // per iteration is less than 1.5 - if (source_regions_.n_hits(sr) * inverse_batch < MIN_HITS_PER_BATCH) { - source_regions_.is_small(sr) = 1; - } else { - source_regions_.is_small(sr) = 0; - } - - // The volume treatment depends on the volume estimator type - // and whether or not an external source is present in the cell. - double volume; - switch (volume_estimator_) { - case RandomRayVolumeEstimator::NAIVE: - volume = volume_iteration; - break; - case RandomRayVolumeEstimator::SIMULATION_AVERAGED: - volume = volume_simulation_avg; - break; - case RandomRayVolumeEstimator::HYBRID: - if (source_regions_.external_source_present(sr) || - source_regions_.is_small(sr)) { - volume = volume_iteration; - } else { - volume = volume_simulation_avg; - } - break; - default: - fatal_error("Invalid volume estimator type"); - } - - for (int g = 0; g < negroups_; g++) { - // There are three scenarios we need to consider: - if (volume_iteration > 0.0) { - // 1. If the FSR was hit this iteration, then the new flux is equal to - // the flat source from the previous iteration plus the contributions - // from rays passing through the source region (computed during the - // transport sweep) - set_flux_to_flux_plus_source(sr, volume, g); - } else if (volume_simulation_avg > 0.0) { - // 2. If the FSR was not hit this iteration, but has been hit some - // previous iteration, then we need to make a choice about what - // to do. Naively we will usually want to set the flux to be equal - // to the reduced source. However, in fixed source problems where - // there is a strong external source present in the cell, and where - // the cell has a very low cross section, this approximation will - // cause a huge upward bias in the flux estimate of the cell (in these - // conditions, the flux estimate can be orders of magnitude too large). - // Thus, to avoid this bias, if any external source is present - // in the cell we will use the previous iteration's flux estimate. This - // injects a small degree of correlation into the simulation, but this - // is going to be trivial when the miss rate is a few percent or less. - if (source_regions_.external_source_present(sr)) { - set_flux_to_old_flux(sr, g); - } else { - set_flux_to_source(sr, g); - } - } - // Halt if NaN implosion is detected - if (!std::isfinite(source_regions_.scalar_flux_new(sr, g))) { - fatal_error("A source region scalar flux is not finite. " - "This indicates a numerical instability in the " - "simulation. Consider increasing ray density or adjusting " - "the source region mesh."); - } - } - } - - // Return the number of source regions that were hit this iteration - return n_hits; -} - -// Generates new estimate of k_eff based on the differences between this -// iteration's estimate of the scalar flux and the last iteration's estimate. -void FlatSourceDomain::compute_k_eff() -{ - double fission_rate_old = 0; - double fission_rate_new = 0; - - // Vector for gathering fission source terms for Shannon entropy calculation - vector p(n_source_regions(), 0.0f); - -#pragma omp parallel for reduction(+ : fission_rate_old, fission_rate_new) - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - - // If simulation averaged volume is zero, don't include this cell - double volume = source_regions_.volume(sr); - if (volume == 0.0) { - continue; - } - - int material = source_regions_.material(sr); - int temp = source_regions_.temperature_idx(sr); - if (material == MATERIAL_VOID) { - continue; - } - - double sr_fission_source_old = 0; - double sr_fission_source_new = 0; - - for (int g = 0; g < negroups_; g++) { - double nu_sigma_f = - nu_sigma_f_[(material * ntemperature_ + temp) * negroups_ + g] * - source_regions_.density_mult(sr); - sr_fission_source_old += - nu_sigma_f * source_regions_.scalar_flux_old(sr, g); - sr_fission_source_new += - nu_sigma_f * source_regions_.scalar_flux_new(sr, g); - } - - // Compute total fission rates in FSR - sr_fission_source_old *= volume; - sr_fission_source_new *= volume; - - // Accumulate totals - fission_rate_old += sr_fission_source_old; - fission_rate_new += sr_fission_source_new; - - // Store total fission rate in the FSR for Shannon calculation - p[sr] = sr_fission_source_new; - } - - double k_eff_new = k_eff_ * (fission_rate_new / fission_rate_old); - - double H = 0.0; - // defining an inverse sum for better performance - double inverse_sum = 1 / fission_rate_new; - -#pragma omp parallel for reduction(+ : H) - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - // Only if FSR has non-negative and non-zero fission source - if (p[sr] > 0.0f) { - // Normalize to total weight of bank sites. p_i for better performance - float p_i = p[sr] * inverse_sum; - // Sum values to obtain Shannon entropy. - H -= p_i * std::log2(p_i); - } - } - - // Adds entropy value to shared entropy vector in openmc namespace. - simulation::entropy.push_back(H); - - fission_rate_ = fission_rate_new; - k_eff_ = k_eff_new; -} - -// This function is responsible for generating a mapping between random -// ray flat source regions (cell instances) and tally bins. The mapping -// takes the form of a "TallyTask" object, which accounts for one single -// score being applied to a single tally. Thus, a single source region -// may have anywhere from zero to many tally tasks associated with it --- -// meaning that the global "tally_task" data structure is in 2D. The outer -// dimension corresponds to the source element (i.e., each entry corresponds -// to a specific energy group within a specific source region), and the -// inner dimension corresponds to the tallying task itself. Mechanically, -// the mapping between FSRs and spatial filters is done by considering -// the location of a single known ray midpoint that passed through the -// FSR. I.e., during transport, the first ray to pass through a given FSR -// will write down its midpoint for use with this function. This is a cheap -// and easy way of mapping FSRs to spatial tally filters, but comes with -// the downside of adding the restriction that spatial tally filters must -// share boundaries with the physical geometry of the simulation (so as -// not to subdivide any FSR). It is acceptable for a spatial tally region -// to contain multiple FSRs, but not the other way around. - -// TODO: In future work, it would be preferable to offer a more general -// (but perhaps slightly more expensive) option for handling arbitrary -// spatial tallies that would be allowed to subdivide FSRs. - -// Besides generating the mapping structure, this function also keeps track -// of whether or not all flat source regions have been hit yet. This is -// required, as there is no guarantee that all flat source regions will -// be hit every iteration, such that in the first few iterations some FSRs -// may not have a known position within them yet to facilitate mapping to -// spatial tally filters. However, after several iterations, if all FSRs -// have been hit and have had a tally map generated, then this status will -// be passed back to the caller to alert them that this function doesn't -// need to be called for the remainder of the simulation. - -// It takes as an argument the starting index in the source region array, -// and it will operate from that index until the end of the array. This -// is useful as it can be called for both explicit user source regions or -// when a source region mesh is overlaid. - -void FlatSourceDomain::convert_source_regions_to_tallies(int64_t start_sr_id) -{ - openmc::simulation::time_tallies.start(); - - // Tracks if we've generated a mapping yet for all source regions. - bool all_source_regions_mapped = true; - -// Attempt to generate mapping for all source regions -#pragma omp parallel for - for (int64_t sr = start_sr_id; sr < n_source_regions(); sr++) { - - // If this source region has not been hit by a ray yet, then - // we aren't going to be able to map it, so skip it. - if (!source_regions_.position_recorded(sr)) { - all_source_regions_mapped = false; - continue; - } - - // A particle located at the recorded midpoint of a ray - // crossing through this source region is used to estabilish - // the spatial location of the source region - Particle p; - p.r() = source_regions_.position(sr); - p.r_last() = source_regions_.position(sr); - p.u() = {1.0, 0.0, 0.0}; - bool found = exhaustive_find_cell(p); - - // Loop over energy groups (so as to support energy filters) - for (int g = 0; g < negroups_; g++) { - - // Set particle to the current energy - p.g() = g; - p.g_last() = g; - p.E() = data::mg.energy_bin_avg_[p.g()]; - p.E_last() = p.E(); - - int64_t source_element = sr * negroups_ + g; - - // If this task has already been populated, we don't need to do - // it again. - if (source_regions_.tally_task(sr, g).size() > 0) { - continue; - } - - // Loop over all active tallies. This logic is essentially identical - // to what happens when scanning for applicable tallies during - // MC transport. - for (int i_tally = 0; i_tally < model::tallies.size(); i_tally++) { - Tally& tally {*model::tallies[i_tally]}; - - // Initialize an iterator over valid filter bin combinations. - // If there are no valid combinations, use a continue statement - // to ensure we skip the assume_separate break below. - auto filter_iter = FilterBinIter(tally, p); - auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) - continue; - - // Loop over filter bins. - for (; filter_iter != end; ++filter_iter) { - auto filter_index = filter_iter.index_; - auto filter_weight = filter_iter.weight_; - - // Loop over scores - for (int score = 0; score < tally.scores_.size(); score++) { - auto score_bin = tally.scores_[score]; - // If a valid tally, filter, and score combination has been found, - // then add it to the list of tally tasks for this source element. - TallyTask task(i_tally, filter_index, score, score_bin); - source_regions_.tally_task(sr, g).push_back(task); - - // Also add this task to the list of volume tasks for this source - // region. - source_regions_.volume_task(sr).insert(task); - } - } - } - // Reset all the filter matches for the next tally event. - for (auto& match : p.filter_matches()) - match.bins_present_ = false; - } - } - openmc::simulation::time_tallies.stop(); - - mapped_all_tallies_ = all_source_regions_mapped; -} - -// Set the volume accumulators to zero for all tallies -void FlatSourceDomain::reset_tally_volumes() -{ - if (volume_normalized_flux_tallies_) { -#pragma omp parallel for - for (int i = 0; i < tally_volumes_.size(); i++) { - auto& tensor = tally_volumes_[i]; - tensor.fill(0.0); // Set all elements of the tensor to 0.0 - } - } -} - -// In fixed source mode, due to the way that volumetric fixed sources are -// converted and applied as volumetric sources in one or more source regions, -// we need to perform an additional normalization step to ensure that the -// reported scalar fluxes are in units per source neutron. This allows for -// direct comparison of reported tallies to Monte Carlo flux results. -// This factor needs to be computed at each iteration, as it is based on the -// volume estimate of each FSR, which improves over the course of the -// simulation -double FlatSourceDomain::compute_fixed_source_normalization_factor() const -{ - // Eigenvalue mode normalization - if (settings::run_mode == RunMode::EIGENVALUE) { - // Normalize fluxes by total number of fission neutrons produced. This - // ensures consistent scaling of the eigenvector such that its magnitude is - // comparable to the eigenvector produced by the Monte Carlo solver. - // Multiplying by the eigenvalue is unintuitive, but it is necessary. - // If the eigenvalue is 1.2, per starting source neutron, you will - // generate 1.2 neutrons. Thus if we normalize to generating only ONE - // neutron in total for the whole domain, then we don't actually have enough - // flux to generate the required 1.2 neutrons. We only know the flux - // required to generate 1 neutron (which would have required less than one - // starting neutron). Thus, you have to scale the flux up by the eigenvalue - // such that 1.2 neutrons are generated, so as to be consistent with the - // bookkeeping in MC which is all done per starting source neutron (not per - // neutron produced). - return k_eff_ / (fission_rate_ * simulation_volume_); - } - - // If we are in adjoint mode of a fixed source problem, the external - // source is already normalized, such that all resulting fluxes are - // also normalized. - if (solve_ == RandomRaySolve::ADJOINT) { - return 1.0; - } - - // Fixed source mode normalization - - // Step 1 is to sum over all source regions and energy groups to get the - // total external source strength in the simulation. - double simulation_external_source_strength = 0.0; -#pragma omp parallel for reduction(+ : simulation_external_source_strength) - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - int material = source_regions_.material(sr); - int temp = source_regions_.temperature_idx(sr); - double volume = source_regions_.volume(sr) * simulation_volume_; - for (int g = 0; g < negroups_; g++) { - // For non-void regions, we store the external source pre-divided by - // sigma_t. We need to multiply non-void regions back up by sigma_t - // to get the total source strength in the expected units. - double sigma_t = 1.0; - if (material != MATERIAL_VOID) { - sigma_t = sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - source_regions_.density_mult(sr); - } - simulation_external_source_strength += - source_regions_.external_source(sr, g) * sigma_t * volume; - } - } - - // Step 2 is to determine the total user-specified external source strength - double user_external_source_strength = 0.0; - for (auto& ext_source : model::external_sources) { - user_external_source_strength += ext_source->strength(); - } - - // The correction factor is the ratio of the user-specified external source - // strength to the simulation external source strength. - double source_normalization_factor = - user_external_source_strength / simulation_external_source_strength; - - return source_normalization_factor; -} - -// Tallying in random ray is not done directly during transport, rather, -// it is done only once after each power iteration. This is made possible -// by way of a mapping data structure that relates spatial source regions -// (FSRs) to tally/filter/score combinations. The mechanism by which the -// mapping is done (and the limitations incurred) is documented in the -// "convert_source_regions_to_tallies()" function comments above. The present -// tally function simply traverses the mapping data structure and executes -// the scoring operations to OpenMC's native tally result arrays. - -void FlatSourceDomain::random_ray_tally() -{ - openmc::simulation::time_tallies.start(); - - // Reset our tally volumes to zero - reset_tally_volumes(); - - double source_normalization_factor = - compute_fixed_source_normalization_factor(); - -// We loop over all source regions and energy groups. For each -// element, we check if there are any scores needed and apply -// them. -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - // The fsr.volume_ is the unitless fractional simulation averaged volume - // (i.e., it is the FSR's fraction of the overall simulation volume). The - // simulation_volume_ is the total 3D physical volume in cm^3 of the - // entire global simulation domain (as defined by the ray source box). - // Thus, the FSR's true 3D spatial volume in cm^3 is found by multiplying - // its fraction of the total volume by the total volume. Not important in - // eigenvalue solves, but useful in fixed source solves for returning the - // flux shape with a magnitude that makes sense relative to the fixed - // source strength. - double volume = source_regions_.volume(sr) * simulation_volume_; - - double material = source_regions_.material(sr); - int temp = source_regions_.temperature_idx(sr); - double density_mult = source_regions_.density_mult(sr); - for (int g = 0; g < negroups_; g++) { - double flux = - source_regions_.scalar_flux_new(sr, g) * source_normalization_factor; - - // Determine numerical score value - for (auto& task : source_regions_.tally_task(sr, g)) { - double score = 0.0; - switch (task.score_type) { - - case SCORE_FLUX: - score = flux * volume; - break; - - case SCORE_TOTAL: - if (material != MATERIAL_VOID) { - score = - flux * volume * - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - density_mult; - } - break; - - case SCORE_FISSION: - if (material != MATERIAL_VOID) { - score = - flux * volume * - sigma_f_[(material * ntemperature_ + temp) * negroups_ + g] * - density_mult; - } - break; - - case SCORE_NU_FISSION: - if (material != MATERIAL_VOID) { - score = - flux * volume * - nu_sigma_f_[(material * ntemperature_ + temp) * negroups_ + g] * - density_mult; - } - break; - - case SCORE_EVENTS: - score = 1.0; - break; - - case SCORE_KAPPA_FISSION: - score = - flux * volume * - kappa_fission_[(material * ntemperature_ + temp) * negroups_ + g] * - density_mult; - break; - - default: - fatal_error("Invalid score specified in tallies.xml. Only flux, " - "total, fission, nu-fission, kappa-fission, and events " - "are supported in random ray mode."); - break; - } - // Apply score to the appropriate tally bin - Tally& tally {*model::tallies[task.tally_idx]}; -#pragma omp atomic - tally.results_(task.filter_idx, task.score_idx, TallyResult::VALUE) += - score; - } - } - - // For flux tallies, the total volume of the spatial region is needed - // for normalizing the flux. We store this volume in a separate tensor. - // We only contribute to each volume tally bin once per FSR. - if (volume_normalized_flux_tallies_) { - for (const auto& task : source_regions_.volume_task(sr)) { - if (task.score_type == SCORE_FLUX) { -#pragma omp atomic - tally_volumes_[task.tally_idx](task.filter_idx, task.score_idx) += - volume; - } - } - } - } // end FSR loop - - // Normalize any flux scores by the total volume of the FSRs scoring to that - // bin. To do this, we loop over all tallies, and then all filter bins, - // and then scores. For each score, we check the tally data structure to - // see what index that score corresponds to. If that score is a flux score, - // then we divide it by volume. - if (volume_normalized_flux_tallies_) { - for (int i = 0; i < model::tallies.size(); i++) { - Tally& tally {*model::tallies[i]}; -#pragma omp parallel for - for (int64_t bin = 0; bin < tally.n_filter_bins(); bin++) { - for (int score_idx = 0; score_idx < tally.n_scores(); score_idx++) { - auto score_type = tally.scores_[score_idx]; - if (score_type == SCORE_FLUX) { - double vol = tally_volumes_[i](bin, score_idx); - if (vol > 0.0) { - tally.results_(bin, score_idx, TallyResult::VALUE) /= vol; - } - } - } - } - } - } - - openmc::simulation::time_tallies.stop(); -} - -double FlatSourceDomain::evaluate_flux_at_point( - Position r, int64_t sr, int g) const -{ - return source_regions_.scalar_flux_final(sr, g) / - (settings::n_batches - settings::n_inactive); -} - -// Outputs all basic material, FSR ID, multigroup flux, and -// fission source data to .vtk file that can be directly -// loaded and displayed by Paraview. Note that .vtk binary -// files require big endian byte ordering, so endianness -// is checked and flipped if necessary. -void FlatSourceDomain::output_to_vtk() const -{ - // Rename .h5 plot filename(s) to .vtk filenames - for (int p = 0; p < model::plots.size(); p++) { - PlottableInterface* plot = model::plots[p].get(); - plot->path_plot() = - plot->path_plot().substr(0, plot->path_plot().find_last_of('.')) + ".vtk"; - } - - // Print header information - print_plot(); - - // Outer loop over plots - for (int plt = 0; plt < model::plots.size(); plt++) { - - // Get handle to OpenMC plot object and extract params - Plot* openmc_plot = dynamic_cast(model::plots[plt].get()); - - // Random ray plots only support voxel plots - if (!openmc_plot) { - warning(fmt::format("Plot {} is invalid plot type -- only voxel plotting " - "is allowed in random ray mode.", - plt)); - continue; - } else if (openmc_plot->type_ != Plot::PlotType::voxel) { - warning(fmt::format("Plot {} is invalid plot type -- only voxel plotting " - "is allowed in random ray mode.", - plt)); - continue; - } - - int Nx = openmc_plot->pixels_[0]; - int Ny = openmc_plot->pixels_[1]; - int Nz = openmc_plot->pixels_[2]; - Position origin = openmc_plot->origin_; - Position width = openmc_plot->width_; - Position ll = origin - width / 2.0; - double x_delta = width.x / Nx; - double y_delta = width.y / Ny; - double z_delta = width.z / Nz; - std::string filename = openmc_plot->path_plot(); - - // Tag plots written during the forward solve of an adjoint run - if (solve_ == RandomRaySolve::FORWARD_FOR_ADJOINT) { - auto dot = filename.find_last_of('.'); - filename = filename.substr(0, dot) + ".forward" + filename.substr(dot); - } - - // Perform sanity checks on file size - uint64_t bytes = Nx * Ny * Nz * (negroups_ + 1 + 1 + 1) * sizeof(float); - write_message(5, "Processing plot {}: {}... (Estimated size is {} MB)", - openmc_plot->id(), filename, bytes / 1.0e6); - if (bytes / 1.0e9 > 1.0) { - warning("Voxel plot specification is very large (>1 GB). Plotting may be " - "slow."); - } else if (bytes / 1.0e9 > 100.0) { - fatal_error("Voxel plot specification is too large (>100 GB). Exiting."); - } - - // Relate voxel spatial locations to random ray source regions - vector voxel_indices(Nx * Ny * Nz); - vector voxel_positions(Nx * Ny * Nz); - vector weight_windows(Nx * Ny * Nz); - float min_weight = 1e20; -#pragma omp parallel for collapse(3) reduction(min : min_weight) - for (int z = 0; z < Nz; z++) { - for (int y = 0; y < Ny; y++) { - for (int x = 0; x < Nx; x++) { - Position sample; - sample.z = ll.z + z_delta / 2.0 + z * z_delta; - sample.y = ll.y + y_delta / 2.0 + y * y_delta; - sample.x = ll.x + x_delta / 2.0 + x * x_delta; - Particle p; - p.r() = sample; - p.r_last() = sample; - p.E() = 1.0; - p.E_last() = 1.0; - p.u() = {1.0, 0.0, 0.0}; - - bool found = exhaustive_find_cell(p); - if (!found) { - voxel_indices[z * Ny * Nx + y * Nx + x] = -1; - voxel_positions[z * Ny * Nx + y * Nx + x] = sample; - weight_windows[z * Ny * Nx + y * Nx + x] = 0.0; - continue; - } - - SourceRegionKey sr_key = lookup_source_region_key(p); - int64_t sr = -1; - auto it = source_region_map_.find(sr_key); - if (it != source_region_map_.end()) { - sr = it->second; - } - - voxel_indices[z * Ny * Nx + y * Nx + x] = sr; - voxel_positions[z * Ny * Nx + y * Nx + x] = sample; - - if (variance_reduction::weight_windows.size() == 1) { - auto [ww_found, ww] = - variance_reduction::weight_windows[0]->get_weight_window(p); - float weight = ww.lower_weight; - weight_windows[z * Ny * Nx + y * Nx + x] = weight; - if (weight < min_weight) - min_weight = weight; - } - } - } - } - - double source_normalization_factor = - compute_fixed_source_normalization_factor(); - - // Open file for writing - std::FILE* plot = std::fopen(filename.c_str(), "wb"); - - // Write vtk metadata - std::fprintf(plot, "# vtk DataFile Version 2.0\n"); - std::fprintf(plot, "Dataset File\n"); - std::fprintf(plot, "BINARY\n"); - std::fprintf(plot, "DATASET STRUCTURED_POINTS\n"); - std::fprintf(plot, "DIMENSIONS %d %d %d\n", Nx, Ny, Nz); - std::fprintf(plot, "ORIGIN %lf %lf %lf\n", ll.x, ll.y, ll.z); - std::fprintf(plot, "SPACING %lf %lf %lf\n", x_delta, y_delta, z_delta); - std::fprintf(plot, "POINT_DATA %d\n", Nx * Ny * Nz); - - int64_t num_neg = 0; - int64_t num_samples = 0; - float min_flux = 0.0; - float max_flux = -1.0e20; - // Plot multigroup flux data - for (int g = 0; g < negroups_; g++) { - std::fprintf(plot, "SCALARS flux_group_%d float\n", g); - std::fprintf(plot, "LOOKUP_TABLE default\n"); - for (int i = 0; i < Nx * Ny * Nz; i++) { - int64_t fsr = voxel_indices[i]; - int64_t source_element = fsr * negroups_ + g; - float flux = 0; - if (fsr >= 0) { - flux = evaluate_flux_at_point(voxel_positions[i], fsr, g); - if (flux < 0.0) - flux = FlatSourceDomain::evaluate_flux_at_point( - voxel_positions[i], fsr, g); - } - if (flux < 0.0) { - num_neg++; - if (flux < min_flux) { - min_flux = flux; - } - } - if (flux > max_flux) - max_flux = flux; - num_samples++; - flux = convert_to_big_endian(flux); - std::fwrite(&flux, sizeof(float), 1, plot); - } - } - - // Slightly negative fluxes can be normal when sampling corners of linear - // source regions. However, very common and high magnitude negative fluxes - // may indicate numerical instability. - if (num_neg > 0) { - warning(fmt::format("{} plot samples ({:.4f}%) contained negative fluxes " - "(minumum found = {:.2e} maximum_found = {:.2e})", - num_neg, (100.0 * num_neg) / num_samples, min_flux, max_flux)); - } - - // Plot FSRs - std::fprintf(plot, "SCALARS FSRs float\n"); - std::fprintf(plot, "LOOKUP_TABLE default\n"); - for (int fsr : voxel_indices) { - float value = future_prn(10, fsr); - value = convert_to_big_endian(value); - std::fwrite(&value, sizeof(float), 1, plot); - } - - // Plot Materials - std::fprintf(plot, "SCALARS Materials int\n"); - std::fprintf(plot, "LOOKUP_TABLE default\n"); - for (int fsr : voxel_indices) { - int mat = -1; - if (fsr >= 0) - mat = source_regions_.material(fsr); - mat = convert_to_big_endian(mat); - std::fwrite(&mat, sizeof(int), 1, plot); - } - - // Plot fission source - if (settings::run_mode == RunMode::EIGENVALUE) { - std::fprintf(plot, "SCALARS total_fission_source float\n"); - std::fprintf(plot, "LOOKUP_TABLE default\n"); - for (int i = 0; i < Nx * Ny * Nz; i++) { - int64_t fsr = voxel_indices[i]; - float total_fission = 0.0; - if (fsr >= 0) { - int mat = source_regions_.material(fsr); - int temp = source_regions_.temperature_idx(fsr); - if (mat != MATERIAL_VOID) { - for (int g = 0; g < negroups_; g++) { - int64_t source_element = fsr * negroups_ + g; - float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g); - double sigma_f = - sigma_f_[(mat * ntemperature_ + temp) * negroups_ + g] * - source_regions_.density_mult(fsr); - total_fission += sigma_f * flux; - } - } - } - total_fission = convert_to_big_endian(total_fission); - std::fwrite(&total_fission, sizeof(float), 1, plot); - } - } else { - std::fprintf(plot, "SCALARS external_source float\n"); - std::fprintf(plot, "LOOKUP_TABLE default\n"); - for (int i = 0; i < Nx * Ny * Nz; i++) { - int64_t fsr = voxel_indices[i]; - int mat = source_regions_.material(fsr); - int temp = source_regions_.temperature_idx(fsr); - float total_external = 0.0f; - if (fsr >= 0) { - for (int g = 0; g < negroups_; g++) { - // External sources are already divided by sigma_t, so we need to - // multiply it back to get the true external source. - double sigma_t = 1.0; - if (mat != MATERIAL_VOID) { - sigma_t = sigma_t_[(mat * ntemperature_ + temp) * negroups_ + g] * - source_regions_.density_mult(fsr); - } - total_external += source_regions_.external_source(fsr, g) * sigma_t; - } - } - total_external = convert_to_big_endian(total_external); - std::fwrite(&total_external, sizeof(float), 1, plot); - } - } - - // Plot weight window data - if (variance_reduction::weight_windows.size() == 1) { - std::fprintf(plot, "SCALARS weight_window_lower float\n"); - std::fprintf(plot, "LOOKUP_TABLE default\n"); - for (int i = 0; i < Nx * Ny * Nz; i++) { - float weight = weight_windows[i]; - if (weight == 0.0) - weight = min_weight; - weight = convert_to_big_endian(weight); - std::fwrite(&weight, sizeof(float), 1, plot); - } - } - - std::fclose(plot); - } -} - -void FlatSourceDomain::apply_external_source_to_source_region( - int src_idx, SourceRegionHandle& srh) -{ - auto s = - (solve_ == RandomRaySolve::ADJOINT && !model::adjoint_sources.empty()) - ? model::adjoint_sources[src_idx].get() - : model::external_sources[src_idx].get(); - auto is = dynamic_cast(s); - auto discrete = dynamic_cast(is->energy()); - double strength_factor = is->strength(); - const auto& discrete_energies = discrete->x(); - const auto& discrete_probs = discrete->prob(); - - srh.external_source_present() = 1; - - for (int i = 0; i < discrete_energies.size(); i++) { - int g = data::mg.get_group_index(discrete_energies[i]); - srh.external_source(g) += discrete_probs[i] * strength_factor; - } -} - -void FlatSourceDomain::apply_external_source_to_cell_instances(int32_t i_cell, - int src_idx, int target_material_id, const vector& instances) -{ - Cell& cell = *model::cells[i_cell]; - - if (cell.type_ != Fill::MATERIAL) - return; - - for (int j : instances) { - int cell_material_idx = cell.material(j); - int cell_material_id; - if (cell_material_idx == MATERIAL_VOID) { - cell_material_id = MATERIAL_VOID; - } else { - cell_material_id = model::materials[cell_material_idx]->id(); - } - if (target_material_id == C_NONE || - cell_material_id == target_material_id) { - int64_t source_region = source_region_offsets_[i_cell] + j; - external_volumetric_source_map_[source_region].push_back(src_idx); - } - } -} - -void FlatSourceDomain::apply_external_source_to_cell_and_children( - int32_t i_cell, int src_idx, int32_t target_material_id) -{ - Cell& cell = *model::cells[i_cell]; - - if (cell.type_ == Fill::MATERIAL) { - vector instances(cell.n_instances()); - std::iota(instances.begin(), instances.end(), 0); - apply_external_source_to_cell_instances( - i_cell, src_idx, target_material_id, instances); - } else if (target_material_id == C_NONE) { - std::unordered_map> cell_instance_list = - cell.get_contained_cells(0, nullptr); - for (const auto& pair : cell_instance_list) { - int32_t i_child_cell = pair.first; - apply_external_source_to_cell_instances( - i_child_cell, src_idx, target_material_id, pair.second); - } - } -} - -void FlatSourceDomain::count_external_source_regions() -{ - n_external_source_regions_ = 0; -#pragma omp parallel for reduction(+ : n_external_source_regions_) - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - if (source_regions_.external_source_present(sr)) { - n_external_source_regions_++; - } - } -} - -void FlatSourceDomain::convert_external_sources(bool use_adjoint_sources) -{ - // Determine whether forward or (local) adjoint sources are desired - const auto& sources = - use_adjoint_sources ? model::adjoint_sources : model::external_sources; - - // Loop over external sources - for (int es = 0; es < sources.size(); es++) { - - // Extract source information - Source* s = sources[es].get(); - IndependentSource* is = dynamic_cast(s); - Discrete* energy = dynamic_cast(is->energy()); - const std::unordered_set& domain_ids = is->domain_ids(); - double strength_factor = is->strength(); - - // If there is no domain constraint specified, then this must be a point - // source. In this case, we need to find the source region that contains the - // point source and apply or relate it to the external source. - if (is->domain_ids().size() == 0) { - - // Extract the point source coordinate and find the base source region at - // that point - auto sp = dynamic_cast(is->space()); - GeometryState gs; - gs.r() = sp->r(); - gs.r_last() = sp->r(); - gs.u() = {1.0, 0.0, 0.0}; - bool found = exhaustive_find_cell(gs); - if (!found) { - fatal_error(fmt::format("Could not find cell containing external " - "point source at {}", - sp->r())); - } - SourceRegionKey key = lookup_source_region_key(gs); - - // With the source region and mesh bin known, we can use the - // accompanying SourceRegionKey as a key into a map that stores the - // corresponding external source index for the point source. Notably, we - // do not actually apply the external source to any source regions here, - // as if mesh subdivision is enabled, they haven't actually been - // discovered & initilized yet. When discovered, they will read from the - // external_source_map to determine if there are any external source - // terms that should be applied. - external_point_source_map_[key].push_back(es); - - } else { - // If not a point source, then use the volumetric domain constraints to - // determine which source regions to apply the external source to. - if (is->domain_type() == Source::DomainType::MATERIAL) { - for (int32_t material_id : domain_ids) { - for (int i_cell = 0; i_cell < model::cells.size(); i_cell++) { - apply_external_source_to_cell_and_children(i_cell, es, material_id); - } - } - } else if (is->domain_type() == Source::DomainType::CELL) { - for (int32_t cell_id : domain_ids) { - int32_t i_cell = model::cell_map[cell_id]; - apply_external_source_to_cell_and_children(i_cell, es, C_NONE); - } - } else if (is->domain_type() == Source::DomainType::UNIVERSE) { - for (int32_t universe_id : domain_ids) { - int32_t i_universe = model::universe_map[universe_id]; - Universe& universe = *model::universes[i_universe]; - for (int32_t i_cell : universe.cells_) { - apply_external_source_to_cell_and_children(i_cell, es, C_NONE); - } - } - } - } - } // End loop over external sources -} - -void FlatSourceDomain::flux_swap() -{ - source_regions_.flux_swap(); -} - -void FlatSourceDomain::flatten_xs() -{ - // Temperature and angle indices, if using multiple temperature - // data sets and/or anisotropic data sets. - // TODO: Currently assumes we are only using single angle data. - const int a = 0; - - n_materials_ = data::mg.macro_xs_.size(); - ntemperature_ = 1; - for (int i = 0; i < n_materials_; i++) { - ntemperature_ = - std::max(ntemperature_, data::mg.macro_xs_[i].n_temperature_points()); - } - - for (int i = 0; i < n_materials_; i++) { - auto& m = data::mg.macro_xs_[i]; - for (int t = 0; t < ntemperature_; t++) { - for (int g_out = 0; g_out < negroups_; g_out++) { - if (m.exists_in_model && t < m.n_temperature_points()) { - double sigma_t = - m.get_xs(MgxsType::TOTAL, g_out, NULL, NULL, NULL, t, a); - sigma_t_.push_back(sigma_t); - - if (sigma_t < MINIMUM_MACRO_XS) { - Material* mat = model::materials[i].get(); - warning(fmt::format( - "Material \"{}\" (id: {}) has a group {} total cross section " - "({:.3e}) below the minimum threshold " - "({:.3e}). Material will be treated as pure void.", - mat->name(), mat->id(), g_out, sigma_t, MINIMUM_MACRO_XS)); - } - - double nu_sigma_f = - m.get_xs(MgxsType::NU_FISSION, g_out, NULL, NULL, NULL, t, a); - nu_sigma_f_.push_back(nu_sigma_f); - - double sigma_f = - m.get_xs(MgxsType::FISSION, g_out, NULL, NULL, NULL, t, a); - sigma_f_.push_back(sigma_f); - - double chi = - m.get_xs(MgxsType::CHI_PROMPT, g_out, &g_out, NULL, NULL, t, a); - if (!std::isfinite(chi)) { - // MGXS interface may return NaN in some cases, such as when - // material is fissionable but has very small sigma_f. - chi = 0.0; - } - chi_.push_back(chi); - - double kappa_fission = - m.get_xs(MgxsType::KAPPA_FISSION, g_out, NULL, NULL, NULL, t, a); - kappa_fission_.push_back(kappa_fission); - - for (int g_in = 0; g_in < negroups_; g_in++) { - double sigma_s = - m.get_xs(MgxsType::NU_SCATTER, g_in, &g_out, NULL, NULL, t, a); - sigma_s_.push_back(sigma_s); - // For transport corrected XS data, diagonal elements may be - // negative. In this case, set a flag to enable transport - // stabilization for the simulation. - if (g_out == g_in && sigma_s < 0.0) - is_transport_stabilization_needed_ = true; - } - } else { - sigma_t_.push_back(0); - nu_sigma_f_.push_back(0); - sigma_f_.push_back(0); - chi_.push_back(0); - kappa_fission_.push_back(0); - for (int g_in = 0; g_in < negroups_; g_in++) { - sigma_s_.push_back(0); - } - } - } - } - } -} - -void FlatSourceDomain::set_fw_adjoint_sources() -{ - // Set the adjoint external source to 1/forward_flux. If the forward flux is - // negative, zero, or extremely close to zero, set the adjoint source to zero, - // as this is likely a very small source region that we don't need to bother - // trying to vector particles towards. In the case of flux "being extremely - // close to zero", we define this as being a fixed fraction of the maximum - // forward flux, below which we assume the flux would be physically - // undetectable. - - // First, find the maximum forward flux value - double max_flux = 0.0; -#pragma omp parallel for reduction(max : max_flux) - for (int64_t se = 0; se < n_source_elements(); se++) { - double flux = source_regions_.scalar_flux_final(se); - if (flux > max_flux) { - max_flux = flux; - } - } - - // Then, compute the adjoint source for each source region -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - for (int g = 0; g < negroups_; g++) { - double flux = source_regions_.scalar_flux_final(sr, g); - if (flux <= ZERO_FLUX_CUTOFF * max_flux) { - source_regions_.external_source(sr, g) = 0.0; - } else { - source_regions_.external_source(sr, g) = 1.0 / flux; - if (!std::isfinite(source_regions_.external_source(sr, g))) { - // If the flux is NaN or Inf, set the adjoint source to zero - source_regions_.external_source(sr, g) = 0.0; - } - } - if (flux > 0.0) { - source_regions_.external_source_present(sr) = 1; - } - source_regions_.scalar_flux_final(sr, g) = 0.0; - } - } - - // "Small" source regions in OpenMC are defined as those that are hit by - // MIN_HITS_PER_BATCH rays or fewer each batch. These regions typically have - // very small volumes combined with a low aspect ratio, and are often - // generated when applying a source region mesh that clips the edge of a - // curved surface. As perhaps only a few rays will visit these regions over - // the entire forward simulation, the forward flux estimates are extremely - // noisy and unreliable. In some cases, the noise may make the forward fluxes - // extremely low, leading to unphysically large adjoint source terms, - // resulting in weight windows that aggressively try to drive particles - // towards these regions. To fix this, we simply filter out any "small" source - // regions from consideration. If a source region is "small", we - // set its adjoint source to zero. This adds negligible bias to the adjoint - // flux solution, as the true total adjoint source contribution from small - // regions is likely to be negligible. -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - if (source_regions_.is_small(sr)) { - for (int g = 0; g < negroups_; g++) { - source_regions_.external_source(sr, g) = 0.0; - } - source_regions_.external_source_present(sr) = 0; - } - } - - // Divide the fixed source term by sigma t (to save time when applying each - // iteration) -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - int material = source_regions_.material(sr); - int temp = source_regions_.temperature_idx(sr); - if (material == MATERIAL_VOID) { - continue; - } - for (int g = 0; g < negroups_; g++) { - double sigma_t = - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - source_regions_.density_mult(sr); - source_regions_.external_source(sr, g) /= sigma_t; - if (!std::isfinite(source_regions_.external_source(sr, g))) { - // If the flux is NaN or Inf, set the adjoint source to zero - source_regions_.external_source(sr, g) = 0.0; - } - } - } - - if (fw_cadis_local_) { -// Only external sources that have a non-mesh type tally task should remain -// non-zero. Everything else gets zero'd out. -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - - // If there is already no external source, don't need to do anything - if (source_regions_.external_source_present(sr) == 0) { - continue; - } - - // If there is an adjoint source term here, then we need to check it. - - // We will track if ANY group has a valid local FW-CADIS source term - bool has_any_sources = false; - - // Now, loop over groups - for (int g = 0; g < negroups_; g++) { - - // If there are no tally tasks associated with this source element - // then it is not a local FW-CADIS source, so we continue to the next - // group - if (source_regions_.tally_task(sr, g).empty()) { - source_regions_.external_source(sr, g) = 0.0; - continue; - } - - // If there are tally tasks, we can through them and check if - // any of them are local FW-CADIS targets. - - // We track if ANY of the tasks are local FW-CADIS target tallies - bool local_fw_cadis_target_region = false; - - // Now we loop through - for (const auto& task : source_regions_.tally_task(sr, g)) { - Tally& tally {*model::tallies[task.tally_idx]}; - const auto t_id = tally.id(); - - // Search for target tallies - if (std::find(fw_cadis_local_targets_.begin(), - fw_cadis_local_targets_.end(), - t_id) != fw_cadis_local_targets_.end()) { - local_fw_cadis_target_region = true; - break; - } - } - - // If ANY of the tasks is a local FW-CADIS target, - // Then we keep the source term and set that this - // source region has a valid FW-CADIS source term. - // Otherwise, we zero out the source term. - if (local_fw_cadis_target_region) { - has_any_sources = true; - } else { - source_regions_.external_source(sr, g) = 0.0; - } - } // End loop over groups - - // If there were any valid FW-CADIS source terms for any - // of the groups, then the SR as a whole counts as a source - if (has_any_sources) { - source_regions_.external_source_present(sr) = 1; - } else { - source_regions_.external_source_present(sr) = 0; - } - } // End loop over source regions - } // End local FW-CADIS logic -} - -void FlatSourceDomain::set_local_adjoint_sources() -{ - // Set the external source to user-specified adjoint sources. - convert_external_sources(true); -} - -void FlatSourceDomain::transpose_scattering_matrix() -{ - // Transpose the inner two dimensions for each material -#pragma omp parallel for - for (int m = 0; m < n_materials_; ++m) { - for (int t = 0; t < ntemperature_; t++) { - int material_offset = (m * ntemperature_ + t) * negroups_ * negroups_; - for (int i = 0; i < negroups_; ++i) { - for (int j = i + 1; j < negroups_; ++j) { - // Calculate indices of the elements to swap - int idx1 = material_offset + i * negroups_ + j; - int idx2 = material_offset + j * negroups_ + i; - - // Swap the elements to transpose the matrix - std::swap(sigma_s_[idx1], sigma_s_[idx2]); - } - } - } - } -} - -void FlatSourceDomain::serialize_final_fluxes(vector& flux) -{ - // Ensure array is correct size - flux.resize(n_source_regions() * negroups_); -// Serialize the final fluxes for output -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - flux[se] = source_regions_.scalar_flux_final(se); - } -} - -void FlatSourceDomain::apply_mesh_to_cell_instances(int32_t i_cell, - int32_t mesh_idx, int target_material_id, const vector& instances, - bool is_target_void) -{ - Cell& cell = *model::cells[i_cell]; - if (cell.type_ != Fill::MATERIAL) - return; - for (int32_t j : instances) { - int cell_material_idx = cell.material(j); - int cell_material_id = (cell_material_idx == C_NONE) - ? C_NONE - : model::materials[cell_material_idx]->id(); - - if ((target_material_id == C_NONE && !is_target_void) || - cell_material_id == target_material_id) { - int64_t sr = source_region_offsets_[i_cell] + j; - // Check if the key is already present in the mesh_map_ - if (mesh_map_.find(sr) != mesh_map_.end()) { - fatal_error(fmt::format("Source region {} already has mesh idx {} " - "applied, but trying to apply mesh idx {}", - sr, mesh_map_[sr], mesh_idx)); - } - // If the SR has not already been assigned, then we can write to it - mesh_map_[sr] = mesh_idx; - } - } -} - -void FlatSourceDomain::apply_mesh_to_cell_and_children(int32_t i_cell, - int32_t mesh_idx, int32_t target_material_id, bool is_target_void) -{ - Cell& cell = *model::cells[i_cell]; - - if (cell.type_ == Fill::MATERIAL) { - vector instances(cell.n_instances()); - std::iota(instances.begin(), instances.end(), 0); - apply_mesh_to_cell_instances( - i_cell, mesh_idx, target_material_id, instances, is_target_void); - } else if (target_material_id == C_NONE && !is_target_void) { - for (int j = 0; j < cell.n_instances(); j++) { - std::unordered_map> cell_instance_list = - cell.get_contained_cells(j, nullptr); - for (const auto& pair : cell_instance_list) { - int32_t i_child_cell = pair.first; - apply_mesh_to_cell_instances(i_child_cell, mesh_idx, target_material_id, - pair.second, is_target_void); - } - } - } -} - -void FlatSourceDomain::apply_meshes() -{ - // Skip if there are no mappings between mesh IDs and domains - if (mesh_domain_map_.empty()) - return; - - // Loop over meshes - for (int mesh_idx = 0; mesh_idx < model::meshes.size(); mesh_idx++) { - Mesh* mesh = model::meshes[mesh_idx].get(); - int mesh_id = mesh->id(); - - // Skip if mesh id is not present in the map - if (mesh_domain_map_.find(mesh_id) == mesh_domain_map_.end()) - continue; - - // Loop over domains associated with the mesh - for (auto& domain : mesh_domain_map_[mesh_id]) { - Source::DomainType domain_type = domain.first; - int domain_id = domain.second; - - if (domain_type == Source::DomainType::MATERIAL) { - for (int i_cell = 0; i_cell < model::cells.size(); i_cell++) { - if (domain_id == C_NONE) { - apply_mesh_to_cell_and_children(i_cell, mesh_idx, domain_id, true); - } else { - apply_mesh_to_cell_and_children(i_cell, mesh_idx, domain_id, false); - } - } - } else if (domain_type == Source::DomainType::CELL) { - int32_t i_cell = model::cell_map[domain_id]; - apply_mesh_to_cell_and_children(i_cell, mesh_idx, C_NONE, false); - } else if (domain_type == Source::DomainType::UNIVERSE) { - int32_t i_universe = model::universe_map[domain_id]; - Universe& universe = *model::universes[i_universe]; - for (int32_t i_cell : universe.cells_) { - apply_mesh_to_cell_and_children(i_cell, mesh_idx, C_NONE, false); - } - } - } - } -} - -SourceRegionHandle FlatSourceDomain::get_subdivided_source_region_handle( - SourceRegionKey sr_key, Position r, Direction u) -{ - // Case 1: Check if the source region key is already present in the permanent - // map. This is the most common condition, as any source region visited in a - // previous power iteration will already be present in the permanent map. If - // the source region key is found, we translate the key into a specific 1D - // source region index and return a handle its position in the - // source_regions_ vector. - auto it = source_region_map_.find(sr_key); - if (it != source_region_map_.end()) { - int64_t sr = it->second; - return source_regions_.get_source_region_handle(sr); - } - - // Case 2: Check if the source region key is present in the temporary (thread - // safe) map. This is a common occurrence in the first power iteration when - // the source region has already been visited already by some other ray. We - // begin by locking the temporary map before any operations are performed. The - // lock is not global over the full data structure -- it will be dependent on - // which key is used. - discovered_source_regions_.lock(sr_key); - - // If the key is found in the temporary map, then we return a handle to the - // source region that is stored in the temporary map. - if (discovered_source_regions_.contains(sr_key)) { - SourceRegionHandle handle {discovered_source_regions_[sr_key]}; - discovered_source_regions_.unlock(sr_key); - return handle; - } - - // Case 3: The source region key is not present anywhere, but it is only due - // to floating point artifacts. These artifacts occur when the overlaid mesh - // overlaps with actual geometry surfaces. In these cases, roundoff error may - // result in the ray tracer detecting an additional (very short) segment - // though a mesh bin that is actually past the physical source region - // boundary. This is a result of the the multi-level ray tracing treatment in - // OpenMC, which depending on the number of universes in the hierarchy etc can - // result in the wrong surface being selected as the nearest. This can happen - // in a lattice when there are two directions that both are very close in - // distance, within the tolerance of FP_REL_PRECISION, and the are thus - // treated as being equivalent so alternative logic is used. However, when we - // go and ray trace on this with the mesh tracer we may go past the surface - // bounding the current source region. - // - // To filter out this case, before we create the new source region, we double - // check that the actual starting point of this segment (r) is still in the - // same geometry source region that we started in. If an artifact is detected, - // we discard the segment (and attenuation through it) as it is not really a - // valid source region and will have only an infinitessimally small cell - // combined with the mesh bin. Thankfully, this is a fairly rare condition, - // and only triggers for very short ray lengths. It can be fixed by decreasing - // the value of FP_REL_PRECISION in constants.h, but this may have unknown - // consequences for the general ray tracer, so for now we do the below sanity - // checks before generating phantom source regions. A significant extra cost - // is incurred in instantiating the GeometryState object and doing a cell - // lookup, but again, this is going to be an extremely rare thing to check - // after the first power iteration has completed. - - // Sanity check on source region id - GeometryState gs; - gs.r() = r + TINY_BIT * u; - gs.u() = {1.0, 0.0, 0.0}; - exhaustive_find_cell(gs); - int64_t sr_found = lookup_base_source_region_idx(gs); - if (sr_found != sr_key.base_source_region_id) { - discovered_source_regions_.unlock(sr_key); - SourceRegionHandle handle; - handle.is_numerical_fp_artifact_ = true; - return handle; - } - - // Sanity check on mesh bin - int mesh_idx = lookup_mesh_idx(sr_key.base_source_region_id); - if (mesh_idx == C_NONE) { - if (sr_key.mesh_bin != 0) { - discovered_source_regions_.unlock(sr_key); - SourceRegionHandle handle; - handle.is_numerical_fp_artifact_ = true; - return handle; - } - } else { - Mesh* mesh = model::meshes[mesh_idx].get(); - int bin_found = mesh->get_bin(r + TINY_BIT * u); - if (bin_found != sr_key.mesh_bin) { - discovered_source_regions_.unlock(sr_key); - SourceRegionHandle handle; - handle.is_numerical_fp_artifact_ = true; - return handle; - } - } - - // Case 4: The source region key is valid, but is not present anywhere. This - // condition only occurs the first time the source region is discovered - // (typically in the first power iteration). In this case, we need to handle - // creation of the new source region and its storage into the parallel map. - // Additionally, we need to determine the source region's material, initialize - // the starting scalar flux guess, and apply any known external sources. - - // Call the basic constructor for the source region and store in the parallel - // map. - bool is_linear = RandomRay::source_shape_ != RandomRaySourceShape::FLAT; - SourceRegion* sr_ptr = - discovered_source_regions_.emplace(sr_key, {negroups_, is_linear}); - SourceRegionHandle handle {*sr_ptr}; - - // Determine the material - int gs_i_cell = gs.lowest_coord().cell(); - Cell& cell = *model::cells[gs_i_cell]; - int material = cell.material(gs.cell_instance()); - int temp = 0; - - // If material total XS is extremely low, just set it to void to avoid - // problems with 1/Sigma_t - if (material != MATERIAL_VOID) { - temp = data::mg.macro_xs_[material].get_temperature_index( - cell.sqrtkT(gs.cell_instance())); - for (int g = 0; g < negroups_; g++) { - double sigma_t = - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g]; - if (sigma_t < MINIMUM_MACRO_XS) { - material = MATERIAL_VOID; - temp = 0; - break; - } - } - } - - handle.material() = material; - handle.temperature_idx() = temp; - - handle.density_mult() = cell.density_mult(gs.cell_instance()); - - // Store the mesh index (if any) assigned to this source region - handle.mesh() = mesh_idx; - - if (settings::run_mode == RunMode::FIXED_SOURCE) { - // Determine if there are any volumetric sources, and apply them. - // Volumetric sources are specifc only to the base SR idx. - auto it_vol = - external_volumetric_source_map_.find(sr_key.base_source_region_id); - if (it_vol != external_volumetric_source_map_.end()) { - const vector& vol_sources = it_vol->second; - for (int src_idx : vol_sources) { - apply_external_source_to_source_region(src_idx, handle); - } - } - - // Determine if there are any point sources, and apply them. - // Point sources are specific to the source region key. - auto it_point = external_point_source_map_.find(sr_key); - if (it_point != external_point_source_map_.end()) { - const vector& point_sources = it_point->second; - for (int src_idx : point_sources) { - apply_external_source_to_source_region(src_idx, handle); - } - } - - // Divide external source term by sigma_t - if (material != C_NONE) { - for (int g = 0; g < negroups_; g++) { - double sigma_t = - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - handle.density_mult(); - handle.external_source(g) /= sigma_t; - } - } - } - - // Compute the combined source term - update_single_neutron_source(handle); - - // Unlock the parallel map. Note: we may be tempted to release - // this lock earlier, and then just use the source region's lock to protect - // the flux/source initialization stages above. However, the rest of the code - // only protects updates to the new flux and volume fields, and assumes that - // the source is constant for the duration of transport. Thus, using just the - // source region's lock by itself would result in other threads potentially - // reading from the source before it is computed, as they won't use the lock - // when only reading from the SR's source. It would be expensive to protect - // those operations, whereas generating the SR is only done once, so we just - // hold the map's bucket lock until the source region is fully initialized. - discovered_source_regions_.unlock(sr_key); - - return handle; -} - -void FlatSourceDomain::finalize_discovered_source_regions() -{ - // Extract keys for entries with a valid volume. - vector keys; - for (const auto& pair : discovered_source_regions_) { - if (pair.second.volume_ > 0.0) { - keys.push_back(pair.first); - } - } - - if (!keys.empty()) { - // Sort the keys, so as to ensure reproducible ordering given that source - // regions may have been added to discovered_source_regions_ in an arbitrary - // order due to shared memory threading. - std::sort(keys.begin(), keys.end()); - - // Remember the index of the first new source region - int64_t start_sr_id = source_regions_.n_source_regions(); - - // Append the source regions in the sorted key order. - for (const auto& key : keys) { - const SourceRegion& sr = discovered_source_regions_[key]; - source_region_map_[key] = source_regions_.n_source_regions(); - source_regions_.push_back(sr); - } - - // Map all new source regions to tallies - convert_source_regions_to_tallies(start_sr_id); - } - - discovered_source_regions_.clear(); -} - -// This is the "diagonal stabilization" technique developed by Gunow et al. in: -// -// Geoffrey Gunow, Benoit Forget, Kord Smith, Stabilization of multi-group -// neutron transport with transport-corrected cross-sections, Annals of Nuclear -// Energy, Volume 126, 2019, Pages 211-219, ISSN 0306-4549, -// https://doi.org/10.1016/j.anucene.2018.10.036. -void FlatSourceDomain::apply_transport_stabilization() -{ - // Don't do anything if all in-group scattering - // cross sections are positive - if (!is_transport_stabilization_needed_) { - return; - } - - // Apply the stabilization factor to all source elements -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - int material = source_regions_.material(sr); - int temp = source_regions_.temperature_idx(sr); - double density_mult = source_regions_.density_mult(sr); - if (material == MATERIAL_VOID) { - continue; - } - for (int g = 0; g < negroups_; g++) { - // Only apply stabilization if the diagonal (in-group) scattering XS is - // negative - double sigma_s = - sigma_s_[((material * ntemperature_ + temp) * negroups_ + g) * - negroups_ + - g] * - density_mult; - if (sigma_s < 0.0) { - double sigma_t = - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - density_mult; - double phi_new = source_regions_.scalar_flux_new(sr, g); - double phi_old = source_regions_.scalar_flux_old(sr, g); - - // Equation 18 in the above Gunow et al. 2019 paper. For a default - // rho of 1.0, this ensures there are no negative diagonal elements - // in the iteration matrix. A lesser rho could be used (or exposed - // as a user input parameter) to reduce the negative impact on - // convergence rate though would need to be experimentally tested to see - // if it doesn't become unstable. rho = 1.0 is good as it gives the - // highest assurance of stability, and the impacts on convergence rate - // are pretty mild. - double D = diagonal_stabilization_rho_ * sigma_s / sigma_t; - - // Equation 16 in the above Gunow et al. 2019 paper - source_regions_.scalar_flux_new(sr, g) = - (phi_new - D * phi_old) / (1.0 - D); - } - } - } -} - -// Determines the base source region index (i.e., a material filled cell -// instance) that corresponds to a particular location in the geometry. Requires -// that the "gs" object passed in has already been initialized and has called -// find_cell etc. -int64_t FlatSourceDomain::lookup_base_source_region_idx( - const GeometryState& gs) const -{ - int i_cell = gs.lowest_coord().cell(); - int64_t sr = source_region_offsets_[i_cell] + gs.cell_instance(); - return sr; -} - -// Determines the index of the mesh (if any) that has been applied -// to a particular base source region index. -int FlatSourceDomain::lookup_mesh_idx(int64_t sr) const -{ - int mesh_idx = C_NONE; - auto mesh_it = mesh_map_.find(sr); - if (mesh_it != mesh_map_.end()) { - mesh_idx = mesh_it->second; - } - return mesh_idx; -} - -// Determines the source region key that corresponds to a particular location in -// the geometry. This takes into account both the base source region index as -// well as the mesh bin if a mesh is applied to this source region for -// subdivision. -SourceRegionKey FlatSourceDomain::lookup_source_region_key( - const GeometryState& gs) const -{ - int64_t sr = lookup_base_source_region_idx(gs); - int64_t mesh_bin = lookup_mesh_bin(sr, gs.r()); - return SourceRegionKey {sr, mesh_bin}; -} - -// Determines the mesh bin that corresponds to a particular base source region -// index and position. -int64_t FlatSourceDomain::lookup_mesh_bin(int64_t sr, Position r) const -{ - int mesh_idx = lookup_mesh_idx(sr); - int mesh_bin = 0; - if (mesh_idx != C_NONE) { - mesh_bin = model::meshes[mesh_idx]->get_bin(r); - } - return mesh_bin; -} - -} // namespace openmc diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp deleted file mode 100644 index b4701ed1f..000000000 --- a/src/random_ray/linear_source_domain.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "openmc/random_ray/linear_source_domain.h" - -#include "openmc/cell.h" -#include "openmc/geometry.h" -#include "openmc/material.h" -#include "openmc/message_passing.h" -#include "openmc/mgxs_interface.h" -#include "openmc/output.h" -#include "openmc/plot.h" -#include "openmc/random_ray/random_ray.h" -#include "openmc/simulation.h" -#include "openmc/tallies/filter.h" -#include "openmc/tallies/tally.h" -#include "openmc/tallies/tally_scoring.h" -#include "openmc/timer.h" - -namespace openmc { - -//============================================================================== -// LinearSourceDomain implementation -//============================================================================== - -void LinearSourceDomain::batch_reset() -{ - FlatSourceDomain::batch_reset(); -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - source_regions_.centroid_iteration(sr) = {0.0, 0.0, 0.0}; - source_regions_.mom_matrix(sr) = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - } -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - source_regions_.flux_moments_new(se) = {0.0, 0.0, 0.0}; - } -} - -void LinearSourceDomain::update_single_neutron_source(SourceRegionHandle& srh) -{ - // Reset all source regions to zero (important for void regions) - for (int g = 0; g < negroups_; g++) { - srh.source(g) = 0.0; - } - - // Add scattering + fission source - int material = srh.material(); - int temp = srh.temperature_idx(); - double density_mult = srh.density_mult(); - if (material != MATERIAL_VOID) { - double inverse_k_eff = 1.0 / k_eff_; - MomentMatrix invM = srh.mom_matrix().inverse(); - - for (int g_out = 0; g_out < negroups_; g_out++) { - double sigma_t = - sigma_t_[(material * ntemperature_ + temp) * negroups_ + g_out] * - density_mult; - - double scatter_flat = 0.0f; - double fission_flat = 0.0f; - MomentArray scatter_linear = {0.0, 0.0, 0.0}; - MomentArray fission_linear = {0.0, 0.0, 0.0}; - - for (int g_in = 0; g_in < negroups_; g_in++) { - // Handles for the flat and linear components of the flux - double flux_flat = srh.scalar_flux_old(g_in); - MomentArray flux_linear = srh.flux_moments_old(g_in); - - // Handles for cross sections - double sigma_s = - sigma_s_[((material * ntemperature_ + temp) * negroups_ + g_out) * - negroups_ + - g_in] * - density_mult; - double nu_sigma_f = - nu_sigma_f_[(material * ntemperature_ + temp) * negroups_ + g_in] * - density_mult; - double chi = - chi_[(material * ntemperature_ + temp) * negroups_ + g_out]; - - // Compute source terms for flat and linear components of the flux - scatter_flat += sigma_s * flux_flat; - scatter_linear += sigma_s * flux_linear; - if (settings::create_fission_neutrons) { - fission_flat += nu_sigma_f * flux_flat * chi; - fission_linear += nu_sigma_f * flux_linear * chi; - } - } - - // Compute the flat source term - srh.source(g_out) = - (scatter_flat + fission_flat * inverse_k_eff) / sigma_t; - - // Compute the linear source terms. In the first 10 iterations when the - // centroids and spatial moments are not well known, we will leave the - // source gradients as zero so as to avoid causing any numerical - // instability. If a negative source is encountered, this region must be - // very small/noisy or have poorly developed spatial moments, so we zero - // the source gradients (effectively making this a flat source region - // temporarily), so as to improve stability. - if (simulation::current_batch > 10 && srh.source(g_out) >= 0.0) { - srh.source_gradients(g_out) = - invM * ((scatter_linear + fission_linear * inverse_k_eff) / sigma_t); - } else { - srh.source_gradients(g_out) = {0.0, 0.0, 0.0}; - } - } - } - - // Add external source if in fixed source mode - if (settings::run_mode == RunMode::FIXED_SOURCE) { - for (int g = 0; g < negroups_; g++) { - srh.source(g) += srh.external_source(g); - } - } -} - -void LinearSourceDomain::normalize_scalar_flux_and_volumes( - double total_active_distance_per_iteration) -{ - double normalization_factor = 1.0 / total_active_distance_per_iteration; - double volume_normalization_factor = - 1.0 / (total_active_distance_per_iteration * simulation::current_batch); - -// Normalize flux to total distance travelled by all rays this iteration -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - source_regions_.scalar_flux_new(se) *= normalization_factor; - source_regions_.flux_moments_new(se) *= normalization_factor; - } - -// Accumulate cell-wise ray length tallies collected this iteration, then -// update the simulation-averaged cell-wise volume estimates -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions(); sr++) { - source_regions_.centroid_t(sr) += source_regions_.centroid_iteration(sr); - source_regions_.mom_matrix_t(sr) += source_regions_.mom_matrix(sr); - source_regions_.volume_t(sr) += source_regions_.volume(sr); - source_regions_.volume_sq_t(sr) += source_regions_.volume_sq(sr); - source_regions_.volume_naive(sr) = - source_regions_.volume(sr) * normalization_factor; - source_regions_.volume(sr) = - source_regions_.volume_t(sr) * volume_normalization_factor; - source_regions_.volume_sq(sr) = - source_regions_.volume_sq_t(sr) / source_regions_.volume_t(sr); - if (source_regions_.volume_t(sr) > 0.0) { - double inv_volume = 1.0 / source_regions_.volume_t(sr); - source_regions_.centroid(sr) = source_regions_.centroid_t(sr); - source_regions_.centroid(sr) *= inv_volume; - source_regions_.mom_matrix(sr) = source_regions_.mom_matrix_t(sr); - source_regions_.mom_matrix(sr) *= inv_volume; - } - } -} - -void LinearSourceDomain::set_flux_to_flux_plus_source( - int64_t sr, double volume, int g) -{ - int material = source_regions_.material(sr); - if (material == MATERIAL_VOID) { - FlatSourceDomain::set_flux_to_flux_plus_source(sr, volume, g); - } else { - source_regions_.scalar_flux_new(sr, g) /= volume; - source_regions_.scalar_flux_new(sr, g) += source_regions_.source(sr, g); - } - // If a source region is small, then the moments are likely noisy, so we zero - // them. This is reasonable, given that small regions can get by with a flat - // source approximation anyhow. - if (source_regions_.is_small(sr)) { - source_regions_.flux_moments_new(sr, g) = {0.0, 0.0, 0.0}; - } else { - source_regions_.flux_moments_new(sr, g) *= (1.0 / volume); - } -} - -void LinearSourceDomain::set_flux_to_old_flux(int64_t sr, int g) -{ - source_regions_.scalar_flux_new(sr, g) = - source_regions_.scalar_flux_old(sr, g); - source_regions_.flux_moments_new(sr, g) = - source_regions_.flux_moments_old(sr, g); -} - -void LinearSourceDomain::accumulate_iteration_flux() -{ - // Accumulate scalar flux - FlatSourceDomain::accumulate_iteration_flux(); - - // Accumulate scalar flux moments -#pragma omp parallel for - for (int64_t se = 0; se < n_source_elements(); se++) { - source_regions_.flux_moments_t(se) += source_regions_.flux_moments_new(se); - } -} - -double LinearSourceDomain::evaluate_flux_at_point( - Position r, int64_t sr, int g) const -{ - double phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g); - - Position local_r = r - source_regions_.centroid(sr); - MomentArray phi_linear = source_regions_.flux_moments_t(sr, g); - phi_linear *= 1.0 / (settings::n_batches - settings::n_inactive); - - MomentMatrix invM = source_regions_.mom_matrix(sr).inverse(); - MomentArray phi_solved = invM * phi_linear; - - return phi_flat + phi_solved.dot(local_r); -} - -} // namespace openmc diff --git a/src/random_ray/moment_matrix.cpp b/src/random_ray/moment_matrix.cpp deleted file mode 100644 index 0324a1494..000000000 --- a/src/random_ray/moment_matrix.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "openmc/random_ray/moment_matrix.h" -#include "openmc/error.h" - -#include - -namespace openmc { - -//============================================================================== -// UpperTriangular implementation -//============================================================================== - -// Inverts a 3x3 smmetric matrix labeled as: -// -// | a b c | -// | b d e | -// | c e f | -// -// We first check the determinant to ensure it is non-zero before proceeding -// with the inversion. If the determinant is zero, we return a matrix of zeros. -// Inversion is calculated by computing the adjoint matrix first, and then the -// inverse can be computed as: A^-1 = 1/det(A) * adj(A) -MomentMatrix MomentMatrix::inverse() const -{ - MomentMatrix inv; - - // Check if the determinant is zero - double det = determinant(); - if (det < std::abs(1.0e-10)) { - // Set the inverse to zero. In effect, this will - // result in all the linear terms of the source becoming - // zero, leaving just the flat source. - inv.set_to_zero(); - return inv; - } - - // Compute the adjoint matrix - inv.a = d * f - e * e; - inv.b = c * e - b * f; - inv.c = b * e - c * d; - inv.d = a * f - c * c; - inv.e = b * c - a * e; - inv.f = a * d - b * b; - - // A^-1 = 1/det(A) * adj(A) - inv *= 1.0 / det; - - return inv; -} - -// Computes the determinant of a 3x3 symmetric -// matrix, with elements labeled as follows: -// -// | a b c | -// | b d e | -// | c e f | -double MomentMatrix::determinant() const -{ - return a * (d * f - e * e) - b * (b * f - c * e) + c * (b * e - c * d); -} - -// Compute a 3x3 spatial moment matrix based on a single ray crossing. -// The matrix is symmetric, and is defined as: -// -// | a b c | -// | b d e | -// | c e f | -// -// The estimate of the obect's spatial moments matrix is computed based on the -// midpoint of the ray's crossing, the direction of the ray, and the distance -// the ray traveled through the 3D object. -void MomentMatrix::compute_spatial_moments_matrix( - const Position& r, const Direction& u, const double& distance) -{ - constexpr double one_over_twelve = 1.0 / 12.0; - const double distance2_12 = distance * distance * one_over_twelve; - a = r[0] * r[0] + u[0] * u[0] * distance2_12; - b = r[0] * r[1] + u[0] * u[1] * distance2_12; - c = r[0] * r[2] + u[0] * u[2] * distance2_12; - d = r[1] * r[1] + u[1] * u[1] * distance2_12; - e = r[1] * r[2] + u[1] * u[2] * distance2_12; - f = r[2] * r[2] + u[2] * u[2] * distance2_12; -} - -} // namespace openmc \ No newline at end of file diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp deleted file mode 100644 index dde5023e4..000000000 --- a/src/random_ray/random_ray.cpp +++ /dev/null @@ -1,903 +0,0 @@ -#include "openmc/random_ray/random_ray.h" - -#include "openmc/constants.h" -#include "openmc/geometry.h" -#include "openmc/message_passing.h" -#include "openmc/mgxs_interface.h" -#include "openmc/random_ray/flat_source_domain.h" -#include "openmc/random_ray/linear_source_domain.h" -#include "openmc/search.h" -#include "openmc/settings.h" -#include "openmc/simulation.h" - -#include - -#include "openmc/distribution_spatial.h" -#include "openmc/random_dist.h" -#include "openmc/source.h" - -namespace openmc { - -//============================================================================== -// Non-method functions -//============================================================================== - -// returns 1 - exp(-tau) -// Equivalent to -(_expm1f(-tau)), but faster -// Written by Colin Josey. -float cjosey_exponential(float tau) -{ - constexpr float c1n = -1.0000013559236386308f; - constexpr float c2n = 0.23151368626911062025f; - constexpr float c3n = -0.061481916409314966140f; - constexpr float c4n = 0.0098619906458127653020f; - constexpr float c5n = -0.0012629460503540849940f; - constexpr float c6n = 0.00010360973791574984608f; - constexpr float c7n = -0.000013276571933735820960f; - - constexpr float c0d = 1.0f; - constexpr float c1d = -0.73151337729389001396f; - constexpr float c2d = 0.26058381273536471371f; - constexpr float c3d = -0.059892419041316836940f; - constexpr float c4d = 0.0099070188241094279067f; - constexpr float c5d = -0.0012623388962473160860f; - constexpr float c6d = 0.00010361277635498731388f; - constexpr float c7d = -0.000013276569500666698498f; - - float x = -tau; - - float den = c7d; - den = den * x + c6d; - den = den * x + c5d; - den = den * x + c4d; - den = den * x + c3d; - den = den * x + c2d; - den = den * x + c1d; - den = den * x + c0d; - - float num = c7n; - num = num * x + c6n; - num = num * x + c5n; - num = num * x + c4n; - num = num * x + c3n; - num = num * x + c2n; - num = num * x + c1n; - num = num * x; - - return num / den; -} - -// The below two functions (exponentialG and exponentialG2) were developed -// by Colin Josey. The implementation of these functions is closely based -// on the OpenMOC versions of these functions. The OpenMOC license is given -// below: - -// Copyright (C) 2012-2023 Massachusetts Institute of Technology and OpenMOC -// contributors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -// Computes y = 1/x-(1-exp(-x))/x**2 using a 5/6th order rational -// approximation. It is accurate to 2e-7 over [0, 1e5]. Developed by Colin -// Josey using Remez's algorithm, with original implementation in OpenMOC at: -// https://github.com/mit-crpg/OpenMOC/blob/develop/src/exponentials.h -float exponentialG(float tau) -{ - // Numerator coefficients in rational approximation for 1/x - (1 - exp(-x)) / - // x^2 - constexpr float d0n = 0.5f; - constexpr float d1n = 0.176558112351595f; - constexpr float d2n = 0.04041584305811143f; - constexpr float d3n = 0.006178333902037397f; - constexpr float d4n = 0.0006429894635552992f; - constexpr float d5n = 0.00006064409107557148f; - - // Denominator coefficients in rational approximation for 1/x - (1 - exp(-x)) - // / x^2 - constexpr float d0d = 1.0f; - constexpr float d1d = 0.6864462055546078f; - constexpr float d2d = 0.2263358514260129f; - constexpr float d3d = 0.04721469893686252f; - constexpr float d4d = 0.006883236664917246f; - constexpr float d5d = 0.0007036272419147752f; - constexpr float d6d = 0.00006064409107557148f; - - float x = tau; - - float num = d5n; - num = num * x + d4n; - num = num * x + d3n; - num = num * x + d2n; - num = num * x + d1n; - num = num * x + d0n; - - float den = d6d; - den = den * x + d5d; - den = den * x + d4d; - den = den * x + d3d; - den = den * x + d2d; - den = den * x + d1d; - den = den * x + d0d; - - return num / den; -} - -// Computes G2 : y = 2/3 - (1 + 2/x) * (1/x + 0.5 - (1 + 1/x) * (1-exp(-x)) / -// x) using a 5/5th order rational approximation. It is accurate to 1e-6 over -// [0, 1e6]. Developed by Colin Josey using Remez's algorithm, with original -// implementation in OpenMOC at: -// https://github.com/mit-crpg/OpenMOC/blob/develop/src/exponentials.h -float exponentialG2(float tau) -{ - - // Coefficients for numerator in rational approximation - constexpr float g1n = -0.08335775885589858f; - constexpr float g2n = -0.003603942303847604f; - constexpr float g3n = 0.0037673183263550827f; - constexpr float g4n = 0.00001124183494990467f; - constexpr float g5n = 0.00016837426505799449f; - - // Coefficients for denominator in rational approximation - constexpr float g1d = 0.7454048371823628f; - constexpr float g2d = 0.23794300531408347f; - constexpr float g3d = 0.05367250964303789f; - constexpr float g4d = 0.006125197988351906f; - constexpr float g5d = 0.0010102514456857377f; - - float x = tau; - - float num = g5n; - num = num * x + g4n; - num = num * x + g3n; - num = num * x + g2n; - num = num * x + g1n; - num = num * x; - - float den = g5d; - den = den * x + g4d; - den = den * x + g3d; - den = den * x + g2d; - den = den * x + g1d; - den = den * x + 1.0f; - - return num / den; -} - -// Implementation of the Fisher-Yates shuffle algorithm. -// Algorithm adapted from: -// https://en.cppreference.com/w/cpp/algorithm/random_shuffle#Version_3 -void fisher_yates_shuffle(vector& arr, uint64_t* seed) -{ - // Loop over the array from the last element down to the second - for (int i = arr.size() - 1; i > 0; --i) { - // Generate a random index in the range [0, i] - int j = uniform_int_distribution(0, i, seed); - std::swap(arr[i], arr[j]); - } -} - -// Function to generate randomized Halton sequence samples -// -// Algorithm adapted from: -// A. B. Owen. A randomized halton algorithm in r. Arxiv, 6 2017. -// URL https://arxiv.org/abs/1706.02808 -vector rhalton(int dim, uint64_t* seed, int64_t skip = 0) -{ - if (dim > 10) { - fatal_error("Halton sampling dimension too large"); - } - int64_t b, res, dig; - double b2r, ans; - const std::array primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; - vector halton(dim, 0.0); - - vector perm; - for (int D = 0; D < dim; ++D) { - b = primes[D]; - perm.resize(b); - b2r = 1.0 / b; - res = skip; - ans = 0.0; - - while ((1.0 - b2r) < 1.0) { - std::iota(perm.begin(), perm.end(), 0); - fisher_yates_shuffle(perm, seed); - dig = res % b; - ans += perm[dig] * b2r; - res = (res - dig) / b; - b2r /= b; - } - - halton[D] = ans; - } - - return halton; -} - -//============================================================================== -// RandomRay implementation -//============================================================================== - -// Static Variable Declarations -double RandomRay::distance_inactive_; -double RandomRay::distance_active_; -unique_ptr RandomRay::ray_source_; -RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; -RandomRaySampleMethod RandomRay::sample_method_ {RandomRaySampleMethod::PRNG}; - -RandomRay::RandomRay() - : angular_flux_(data::mg.num_energy_groups_), - delta_psi_(data::mg.num_energy_groups_), - negroups_(data::mg.num_energy_groups_) -{ - if (source_shape_ == RandomRaySourceShape::LINEAR || - source_shape_ == RandomRaySourceShape::LINEAR_XY) { - delta_moments_.resize(negroups_); - } -} - -RandomRay::RandomRay(uint64_t ray_id, FlatSourceDomain* domain) : RandomRay() -{ - initialize_ray(ray_id, domain); -} - -// Transports ray until termination criteria are met -uint64_t RandomRay::transport_history_based_single_ray() -{ - using namespace openmc; - while (alive()) { - event_advance_ray(); - if (!alive()) - break; - event_cross_surface(); - // If ray has too many events, display warning and kill it - if (n_event() >= settings::max_particle_events) { - warning("Ray " + std::to_string(id()) + - " underwent maximum number of events, terminating ray."); - wgt() = 0.0; - } - } - - return n_event(); -} - -// Transports ray across a single source region -void RandomRay::event_advance_ray() -{ - // If geometry debug mode is on, check for cell overlaps - if (settings::check_overlaps) - check_cell_overlap(*this); - - // Find the distance to the nearest boundary - boundary() = distance_to_boundary(*this); - double distance = boundary().distance(); - - if (distance < 0.0) { - mark_as_lost("Negative transport distance detected for particle " + - std::to_string(id())); - return; - } - - if (is_active_) { - // If the ray is in the active length, need to check if it has - // reached its maximum termination distance. If so, reduce - // the ray traced length so that the ray does not overrun the - // maximum numerical length (so as to avoid numerical bias). - if (distance_travelled_ + distance >= distance_active_) { - distance = distance_active_ - distance_travelled_; - wgt() = 0.0; - } - - distance_travelled_ += distance; - attenuate_flux(distance, true); - } else { - // If the ray is still in the dead zone, need to check if it - // has entered the active phase. If so, split into two segments (one - // representing the final part of the dead zone, the other representing the - // first part of the active length) and attenuate each. Otherwise, if the - // full length of the segment is within the dead zone, attenuate as normal. - if (distance_travelled_ + distance >= distance_inactive_) { - is_active_ = true; - double distance_dead = distance_inactive_ - distance_travelled_; - attenuate_flux(distance_dead, false); - - double distance_alive = distance - distance_dead; - - // Ensure we haven't travelled past the active phase as well - if (distance_alive > distance_active_) { - distance_alive = distance_active_; - wgt() = 0.0; - } - - attenuate_flux(distance_alive, true, distance_dead); - distance_travelled_ = distance_alive; - } else { - distance_travelled_ += distance; - attenuate_flux(distance, false); - } - } - - // Advance particle - for (int j = 0; j < n_coord(); ++j) { - coord(j).r() += distance * coord(j).u(); - } -} - -void RandomRay::attenuate_flux(double distance, bool is_active, double offset) -{ - // Lookup base source region index - int64_t sr = domain_->lookup_base_source_region_idx(*this); - - // Perform ray tracing across mesh - // Determine the mesh index for the base source region, if any - int mesh_idx = domain_->lookup_mesh_idx(sr); - - if (mesh_idx == C_NONE) { - // If there's no mesh being applied to this cell, then - // we just attenuate the flux as normal, and set - // the mesh bin to 0 - attenuate_flux_inner(distance, is_active, sr, 0, r()); - } else { - // If there is a mesh being applied to this cell, then - // we loop over all the bin crossings and attenuate - // separately. - Mesh* mesh = model::meshes[mesh_idx].get(); - - // We adjust the start and end positions of the ray slightly - // to accomodate for floating point precision issues that tend - // to occur at mesh boundaries that overlap with geometry lattice - // boundaries. - Position start = r() + (offset + TINY_BIT) * u(); - Position end = start + (distance - 2.0 * TINY_BIT) * u(); - double reduced_distance = (end - start).norm(); - - // Ray trace through the mesh and record bins and lengths - mesh_bins_.resize(0); - mesh_fractional_lengths_.resize(0); - mesh->bins_crossed(start, end, u(), mesh_bins_, mesh_fractional_lengths_); - - // Loop over all mesh bins and attenuate flux - for (int b = 0; b < mesh_bins_.size(); b++) { - double physical_length = reduced_distance * mesh_fractional_lengths_[b]; - attenuate_flux_inner( - physical_length, is_active, sr, mesh_bins_[b], start); - start += physical_length * u(); - } - } -} - -void RandomRay::attenuate_flux_inner( - double distance, bool is_active, int64_t sr, int mesh_bin, Position r) -{ - SourceRegionKey sr_key {sr, mesh_bin}; - SourceRegionHandle srh; - srh = domain_->get_subdivided_source_region_handle(sr_key, r, u()); - if (srh.is_numerical_fp_artifact_) { - return; - } - - switch (source_shape_) { - case RandomRaySourceShape::FLAT: - if (srh.material() == MATERIAL_VOID) { - attenuate_flux_flat_source_void(srh, distance, is_active, r); - } else { - attenuate_flux_flat_source(srh, distance, is_active, r); - } - break; - case RandomRaySourceShape::LINEAR: - case RandomRaySourceShape::LINEAR_XY: - if (srh.material() == MATERIAL_VOID) { - attenuate_flux_linear_source_void(srh, distance, is_active, r); - } else { - attenuate_flux_linear_source(srh, distance, is_active, r); - } - break; - default: - fatal_error("Unknown source shape for random ray transport."); - } -} - -// This function forms the inner loop of the random ray transport process. -// It is responsible for several tasks. Based on the incoming angular flux -// of the ray and the source term in the region, the outgoing angular flux -// is computed. The delta psi between the incoming and outgoing fluxes is -// contributed to the estimate of the total scalar flux in the source region. -// Additionally, the contribution of the ray path to the stochastically -// estimated volume is also kept track of. All tasks involving writing -// to the data for the source region are done with a lock over the entire -// source region. Locks are used instead of atomics as all energy groups -// must be written, such that locking once is typically much more efficient -// than use of many atomic operations corresponding to each energy group -// individually (at least on CPU). Several other bookkeeping tasks are also -// performed when inside the lock. -void RandomRay::attenuate_flux_flat_source( - SourceRegionHandle& srh, double distance, bool is_active, Position r) -{ - // The number of geometric intersections is counted for reporting purposes - n_event()++; - - // Get material - int material = srh.material(); - int temp = srh.temperature_idx(); - - // MOC incoming flux attenuation + source contribution/attenuation equation - for (int g = 0; g < negroups_; g++) { - float sigma_t = - domain_->sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - srh.density_mult(); - float tau = sigma_t * distance; - float exponential = cjosey_exponential(tau); // exponential = 1 - exp(-tau) - float new_delta_psi = (angular_flux_[g] - srh.source(g)) * exponential; - delta_psi_[g] = new_delta_psi; - angular_flux_[g] -= new_delta_psi; - } - - // If ray is in the active phase (not in dead zone), make contributions to - // source region bookkeeping - - // Aquire lock for source region - srh.lock(); - - if (is_active) { - // Accumulate delta psi into new estimate of source region flux for - // this iteration - for (int g = 0; g < negroups_; g++) { - srh.scalar_flux_new(g) += delta_psi_[g]; - } - - // Accomulate volume (ray distance) into this iteration's estimate - // of the source region's volume - srh.volume() += distance; - - srh.n_hits() += 1; - } - - // Tally valid position inside the source region (e.g., midpoint of - // the ray) if not done already - if (!srh.position_recorded()) { - Position midpoint = r + u() * (distance / 2.0); - srh.position() = midpoint; - srh.position_recorded() = 1; - } - - // Release lock - srh.unlock(); -} - -// Alternative flux attenuation function for true void regions. -void RandomRay::attenuate_flux_flat_source_void( - SourceRegionHandle& srh, double distance, bool is_active, Position r) -{ - // The number of geometric intersections is counted for reporting purposes - n_event()++; - - int material = srh.material(); - - // If ray is in the active phase (not in dead zone), make contributions to - // source region bookkeeping - if (is_active) { - - // Aquire lock for source region - srh.lock(); - - // Accumulate delta psi into new estimate of source region flux for - // this iteration - for (int g = 0; g < negroups_; g++) { - srh.scalar_flux_new(g) += angular_flux_[g] * distance; - } - - // Accomulate volume (ray distance) into this iteration's estimate - // of the source region's volume - srh.volume() += distance; - srh.volume_sq() += distance * distance; - srh.n_hits() += 1; - - // Tally valid position inside the source region (e.g., midpoint of - // the ray) if not done already - if (!srh.position_recorded()) { - Position midpoint = r + u() * (distance / 2.0); - srh.position() = midpoint; - srh.position_recorded() = 1; - } - - // Release lock - srh.unlock(); - } - - // Add source to incoming angular flux, assuming void region - if (settings::run_mode == RunMode::FIXED_SOURCE) { - for (int g = 0; g < negroups_; g++) { - angular_flux_[g] += srh.external_source(g) * distance; - } - } -} - -void RandomRay::attenuate_flux_linear_source( - SourceRegionHandle& srh, double distance, bool is_active, Position r) -{ - // The number of geometric intersections is counted for reporting purposes - n_event()++; - - int material = srh.material(); - int temp = srh.temperature_idx(); - - Position& centroid = srh.centroid(); - Position midpoint = r + u() * (distance / 2.0); - - // Determine the local position of the midpoint and the ray origin - // relative to the source region's centroid - Position rm_local; - Position r0_local; - - // In the first few iterations of the simulation, the source region - // may not yet have had any ray crossings, in which case there will - // be no estimate of its centroid. We detect this by checking if it has - // any accumulated volume. If its volume is zero, just use the midpoint - // of the ray as the region's centroid. - if (srh.volume_t()) { - rm_local = midpoint - centroid; - r0_local = r - centroid; - } else { - rm_local = {0.0, 0.0, 0.0}; - r0_local = -u() * 0.5 * distance; - } - double distance_2 = distance * distance; - - // Linear Source MOC incoming flux attenuation + source - // contribution/attenuation equation - for (int g = 0; g < negroups_; g++) { - - // Compute tau, the optical thickness of the ray segment - float sigma_t = - domain_->sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] * - srh.density_mult(); - float tau = sigma_t * distance; - - // If tau is very small, set it to zero to avoid numerical issues. - // The following computations will still work with tau = 0. - if (tau < 1.0e-8f) { - tau = 0.0f; - } - - // Compute linear source terms, spatial and directional (dir), - // calculated from the source gradients dot product with local centroid - // and direction, respectively. - float spatial_source = - srh.source(g) + rm_local.dot(srh.source_gradients(g)); - float dir_source = u().dot(srh.source_gradients(g)); - - float gn = exponentialG(tau); - float f1 = 1.0f - tau * gn; - float f2 = (2.0f * gn - f1) * distance_2; - float new_delta_psi = (angular_flux_[g] - spatial_source) * f1 * distance - - 0.5 * dir_source * f2; - - float h1 = f1 - gn; - float g1 = 0.5f - h1; - float g2 = exponentialG2(tau); - g1 = g1 * spatial_source; - g2 = g2 * dir_source * distance * 0.5f; - h1 = h1 * angular_flux_[g]; - h1 = (g1 + g2 + h1) * distance_2; - spatial_source = spatial_source * distance + new_delta_psi; - - // Store contributions for this group into arrays, so that they can - // be accumulated into the source region's estimates inside of the locked - // region. - delta_psi_[g] = new_delta_psi; - delta_moments_[g] = r0_local * spatial_source + u() * h1; - - // Update the angular flux for this group - angular_flux_[g] -= new_delta_psi * sigma_t; - - // If 2D mode is enabled, the z-component of the flux moments is forced - // to zero - if (source_shape_ == RandomRaySourceShape::LINEAR_XY) { - delta_moments_[g].z = 0.0; - } - } - - // Compute an estimate of the spatial moments matrix for the source - // region based on parameters from this ray's crossing - MomentMatrix moment_matrix_estimate; - moment_matrix_estimate.compute_spatial_moments_matrix( - rm_local, u(), distance); - - // Aquire lock for source region - srh.lock(); - - // If ray is in the active phase (not in dead zone), make contributions to - // source region bookkeeping - - if (is_active) { - // Accumulate deltas into the new estimate of source region flux for this - // iteration - for (int g = 0; g < negroups_; g++) { - srh.scalar_flux_new(g) += delta_psi_[g]; - srh.flux_moments_new(g) += delta_moments_[g]; - } - - // Accumulate the volume (ray segment distance), centroid, and spatial - // momement estimates into the running totals for the iteration for this - // source region. The centroid and spatial momements estimates are scaled - // by the ray segment length as part of length averaging of the estimates. - srh.volume() += distance; - srh.centroid_iteration() += midpoint * distance; - moment_matrix_estimate *= distance; - srh.mom_matrix() += moment_matrix_estimate; - - srh.n_hits() += 1; - } - - // Tally valid position inside the source region (e.g., midpoint of - // the ray) if not done already - if (!srh.position_recorded()) { - srh.position() = midpoint; - srh.position_recorded() = 1; - } - - // Release lock - srh.unlock(); -} - -// If traveling through a void region, the source term is either zero -// or an external source. As all external sources are currently assumed -// to be flat, we don't really need this function and could instead just call -// the "attenuate_flux_flat_source_void" function and get the same numerical and -// tally results. However, computation of the flux moments in void regions is -// nonetheless useful as this information is still used by the plotter when -// estimating the flux at specific pixel coordinates. Thus, plots will look -// nicer/more accurate if we record flux moments, so this function is useful. -void RandomRay::attenuate_flux_linear_source_void( - SourceRegionHandle& srh, double distance, bool is_active, Position r) -{ - // The number of geometric intersections is counted for reporting purposes - n_event()++; - - Position& centroid = srh.centroid(); - Position midpoint = r + u() * (distance / 2.0); - - // Determine the local position of the midpoint and the ray origin - // relative to the source region's centroid - Position rm_local; - Position r0_local; - - // In the first few iterations of the simulation, the source region - // may not yet have had any ray crossings, in which case there will - // be no estimate of its centroid. We detect this by checking if it has - // any accumulated volume. If its volume is zero, just use the midpoint - // of the ray as the region's centroid. - if (srh.volume_t()) { - rm_local = midpoint - centroid; - r0_local = r - centroid; - } else { - rm_local = {0.0, 0.0, 0.0}; - r0_local = -u() * 0.5 * distance; - } - double distance_2 = distance * distance; - - // Compared to linear flux attenuation through solid regions, - // transport through a void region is greatly simplified. Here we - // compute the updated flux moments. - for (int g = 0; g < negroups_; g++) { - float spatial_source = 0.f; - if (settings::run_mode == RunMode::FIXED_SOURCE) { - spatial_source = srh.external_source(g); - } - float new_delta_psi = (angular_flux_[g] - spatial_source) * distance; - float h1 = 0.5f; - h1 = h1 * angular_flux_[g]; - h1 = h1 * distance_2; - spatial_source = spatial_source * distance + new_delta_psi; - - // Store contributions for this group into arrays, so that they can - // be accumulated into the source region's estimates inside of the locked - // region. - delta_moments_[g] = r0_local * spatial_source + u() * h1; - - // If 2D mode is enabled, the z-component of the flux moments is forced - // to zero - if (source_shape_ == RandomRaySourceShape::LINEAR_XY) { - delta_moments_[g].z = 0.0; - } - } - - // If ray is in the active phase (not in dead zone), make contributions to - // source region bookkeeping - if (is_active) { - // Compute an estimate of the spatial moments matrix for the source - // region based on parameters from this ray's crossing - MomentMatrix moment_matrix_estimate; - moment_matrix_estimate.compute_spatial_moments_matrix( - rm_local, u(), distance); - - // Aquire lock for source region - srh.lock(); - - // Accumulate delta psi into new estimate of source region flux for - // this iteration, and update flux momements - for (int g = 0; g < negroups_; g++) { - srh.scalar_flux_new(g) += angular_flux_[g] * distance; - srh.flux_moments_new(g) += delta_moments_[g]; - } - - // Accumulate the volume (ray segment distance), centroid, and spatial - // momement estimates into the running totals for the iteration for this - // source region. The centroid and spatial momements estimates are scaled by - // the ray segment length as part of length averaging of the estimates. - srh.volume() += distance; - srh.volume_sq() += distance_2; - srh.centroid_iteration() += midpoint * distance; - moment_matrix_estimate *= distance; - srh.mom_matrix() += moment_matrix_estimate; - - // Tally valid position inside the source region (e.g., midpoint of - // the ray) if not done already - if (!srh.position_recorded()) { - srh.position() = midpoint; - srh.position_recorded() = 1; - } - - srh.n_hits() += 1; - - // Release lock - srh.unlock(); - } - - // Add source to incoming angular flux, assuming void region - if (settings::run_mode == RunMode::FIXED_SOURCE) { - for (int g = 0; g < negroups_; g++) { - angular_flux_[g] += srh.external_source(g) * distance; - } - } -} - -void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) -{ - domain_ = domain; - ntemperature_ = domain->ntemperature_; - - // Reset particle event counter - n_event() = 0; - - is_active_ = (distance_inactive_ <= 0.0); - - wgt() = 1.0; - - // set identifier for particle - id() = ray_id; - - // generate source site using sample method - SourceSite site; - switch (sample_method_) { - case RandomRaySampleMethod::PRNG: - site = sample_prng(); - break; - case RandomRaySampleMethod::HALTON: - site = sample_halton(); - break; - case RandomRaySampleMethod::S2: - site = sample_s2(); - break; - default: - fatal_error("Unknown sample method for random ray transport."); - } - - site.E = 0.0; - this->from_source(&site); - - // Locate ray - if (lowest_coord().cell() == C_NONE) { - if (!exhaustive_find_cell(*this)) { - this->mark_as_lost( - "Could not find the cell containing particle " + std::to_string(id())); - } - - // Set birth cell attribute - if (cell_born() == C_NONE) - cell_born() = lowest_coord().cell(); - } - - SourceRegionKey sr_key = domain_->lookup_source_region_key(*this); - SourceRegionHandle srh = - domain_->get_subdivided_source_region_handle(sr_key, r(), u()); - - // Initialize ray's starting angular flux to starting location's isotropic - // source - if (!srh.is_numerical_fp_artifact_) { - for (int g = 0; g < negroups_; g++) { - angular_flux_[g] = srh.source(g); - } - } -} - -SourceSite RandomRay::sample_prng() -{ - // set random number seed - int64_t particle_seed = - (simulation::current_batch - 1) * settings::n_particles + id(); - init_particle_seeds(particle_seed, seeds()); - stream() = STREAM_TRACKING; - - // Sample from ray source distribution - SourceSite site {ray_source_->sample(current_seed())}; - - return site; -} - -SourceSite RandomRay::sample_halton() -{ - SourceSite site; - - // Set random number seed - int64_t batch_seed = (simulation::current_batch - 1) * settings::n_particles; - int64_t skip = id(); - init_particle_seeds(batch_seed, seeds()); - stream() = STREAM_TRACKING; - - // Calculate next samples in LDS across 5 dimensions - vector samples = rhalton(5, current_seed(), skip = skip); - - // Get spatial box of ray_source_ - SpatialBox* sb = dynamic_cast( - dynamic_cast(RandomRay::ray_source_.get())->space()); - - // Sample spatial distribution - Position xi {samples[0], samples[1], samples[2]}; - // make a small shift in position to avoid geometry floating point issues - Position shift {FP_COINCIDENT, FP_COINCIDENT, FP_COINCIDENT}; - site.r = (sb->lower_left() + shift) + - xi * ((sb->upper_right() - shift) - (sb->lower_left() + shift)); - - // Sample Polar cosine and azimuthal angles - double mu = 2.0 * samples[3] - 1.0; - double azi = 2.0 * PI * samples[4]; - // Convert to Cartesian coordinates - double c = std::sqrt(1.0 - mu * mu); - site.u.x = mu; - site.u.y = std::cos(azi) * c; - site.u.z = std::sin(azi) * c; - - return site; -} - -SourceSite RandomRay::sample_s2() -{ - // set random number seed - int64_t particle_seed = - (simulation::current_batch - 1) * settings::n_particles + id(); - init_particle_seeds(particle_seed, seeds()); - stream() = STREAM_TRACKING; - - // Get spatial component of the ray_source_ - SpatialDistribution* space = - dynamic_cast(RandomRay::ray_source_.get())->space(); - - SourceSite site; - - // Sample spatial distribution - site.r = space->sample(current_seed()).first; - - // Sample either left or right for S2 (flashlight) transport. - site.u = {prn(current_seed()) < 0.5 ? -1.0 : 1.0, 0.0, 0.0}; - - return site; -} - -} // namespace openmc diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp deleted file mode 100644 index 00fff99a7..000000000 --- a/src/random_ray/random_ray_simulation.cpp +++ /dev/null @@ -1,723 +0,0 @@ -#include "openmc/random_ray/random_ray_simulation.h" - -#include "openmc/capi.h" -#include "openmc/eigenvalue.h" -#include "openmc/geometry.h" -#include "openmc/message_passing.h" -#include "openmc/mgxs_interface.h" -#include "openmc/output.h" -#include "openmc/plot.h" -#include "openmc/random_ray/flat_source_domain.h" -#include "openmc/random_ray/random_ray.h" -#include "openmc/simulation.h" -#include "openmc/source.h" -#include "openmc/tallies/filter.h" -#include "openmc/tallies/tally.h" -#include "openmc/tallies/tally_scoring.h" -#include "openmc/timer.h" -#include "openmc/weight_windows.h" - -namespace openmc { - -//============================================================================== -// Non-member functions -//============================================================================== - -// Enforces restrictions on inputs in random ray mode. While there are -// many features that don't make sense in random ray mode, and are therefore -// unsupported, we limit our testing/enforcement operations only to inputs -// that may cause erroneous/misleading output or crashes from the solver. -void validate_random_ray_inputs() -{ - // Validate tallies - /////////////////////////////////////////////////////////////////// - for (auto& tally : model::tallies) { - - // Validate score types - for (auto score_bin : tally->scores_) { - switch (score_bin) { - case SCORE_FLUX: - case SCORE_TOTAL: - case SCORE_FISSION: - case SCORE_NU_FISSION: - case SCORE_EVENTS: - case SCORE_KAPPA_FISSION: - break; - default: - fatal_error( - "Invalid score specified. Only flux, total, fission, nu-fission, " - "kappa-fission, and event scores are supported in random ray mode."); - } - } - - // Validate filter types - for (auto f : tally->filters()) { - auto& filter = *model::tally_filters[f]; - - switch (filter.type()) { - case FilterType::CELL: - case FilterType::CELL_INSTANCE: - case FilterType::DISTRIBCELL: - case FilterType::ENERGY: - case FilterType::MATERIAL: - case FilterType::MESH: - case FilterType::UNIVERSE: - case FilterType::PARTICLE: - break; - default: - fatal_error("Invalid filter specified. Only cell, cell_instance, " - "distribcell, energy, material, mesh, and universe filters " - "are supported in random ray mode."); - } - } - } - - // Validate MGXS data - /////////////////////////////////////////////////////////////////// - for (auto& material : data::mg.macro_xs_) { - if (!material.is_isotropic) { - fatal_error("Anisotropic MGXS detected. Only isotropic XS data sets " - "supported in random ray mode."); - } - for (int g = 0; g < data::mg.num_energy_groups_; g++) { - if (material.exists_in_model) { - // Temperature and angle indices, if using multiple temperature - // data sets and/or anisotropic data sets. - // TODO: Currently assumes we are only using single temp/single angle - // data. - const int t = 0; - const int a = 0; - double sigma_t = - material.get_xs(MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); - if (sigma_t <= 0.0) { - fatal_error("No zero or negative total macroscopic cross sections " - "allowed in random ray mode. If the intention is to make " - "a void material, use a cell fill of 'None' instead."); - } - } - } - } - - // Validate ray source - /////////////////////////////////////////////////////////////////// - - // Check for independent source - IndependentSource* is = - dynamic_cast(RandomRay::ray_source_.get()); - if (!is) { - fatal_error("Invalid ray source definition. Ray source must provided and " - "be of type IndependentSource."); - } - - // Check for box source - SpatialDistribution* space_dist = is->space(); - SpatialBox* sb = dynamic_cast(space_dist); - if (!sb) { - fatal_error( - "Invalid ray source definition -- only box sources are allowed."); - } - - // Check that box source is not restricted to fissionable areas - if (sb->only_fissionable()) { - fatal_error( - "Invalid ray source definition -- fissionable spatial distribution " - "not allowed."); - } - - // Check for isotropic source - UnitSphereDistribution* angle_dist = is->angle(); - Isotropic* id = dynamic_cast(angle_dist); - if (!id) { - fatal_error("Invalid ray source definition -- only isotropic sources are " - "allowed."); - } - - // Validate external sources - /////////////////////////////////////////////////////////////////// - if (settings::run_mode == RunMode::FIXED_SOURCE) { - if (model::external_sources.size() < 1) { - fatal_error("Must provide a particle source (in addition to ray source) " - "in fixed source random ray mode."); - } - - for (int i = 0; i < model::external_sources.size(); i++) { - Source* s = model::external_sources[i].get(); - - // Check for independent source - IndependentSource* is = dynamic_cast(s); - - if (!is) { - fatal_error( - "Only IndependentSource external source types are allowed in " - "random ray mode"); - } - - // Check for isotropic source - UnitSphereDistribution* angle_dist = is->angle(); - Isotropic* id = dynamic_cast(angle_dist); - if (!id) { - fatal_error( - "Invalid source definition -- only isotropic external sources are " - "allowed in random ray mode."); - } - - // Validate that a domain ID was specified OR that it is a point source - auto sp = dynamic_cast(is->space()); - if (is->domain_ids().size() == 0 && !sp) { - fatal_error("Fixed sources must be point source or spatially " - "constrained by domain id (cell, material, or universe) in " - "random ray mode."); - } else if (is->domain_ids().size() > 0 && sp) { - // If both a domain constraint and a point source location are - // specified, notify user that domain constraint takes precedence. - warning("Fixed source has both a domain constraint and a point " - "type spatial distribution. The domain constraint takes " - "precedence in random ray mode -- point source coordinate " - "will be ignored."); - } - - // Check that a discrete energy distribution was used - Distribution* d = is->energy(); - Discrete* dd = dynamic_cast(d); - if (!dd) { - fatal_error( - "Only discrete (multigroup) energy distributions are allowed for " - "external sources in random ray mode."); - } - } - } - - // Validate adjoint sources - /////////////////////////////////////////////////////////////////// - if (FlatSourceDomain::adjoint_requested_ && !model::adjoint_sources.empty()) { - for (int i = 0; i < model::adjoint_sources.size(); i++) { - Source* s = model::adjoint_sources[i].get(); - - // Check for independent source - IndependentSource* is = dynamic_cast(s); - - if (!is) { - fatal_error( - "Only IndependentSource adjoint source types are allowed in " - "random ray mode"); - } - - // Check for isotropic source - UnitSphereDistribution* angle_dist = is->angle(); - Isotropic* id = dynamic_cast(angle_dist); - if (!id) { - fatal_error( - "Invalid source definition -- only isotropic adjoint sources are " - "allowed in random ray mode."); - } - - // Validate that a domain ID was specified OR that it is a point source - auto sp = dynamic_cast(is->space()); - if (is->domain_ids().size() == 0 && !sp) { - fatal_error("Adjoint sources must be point source or spatially " - "constrained by domain id (cell, material, or universe) in " - "random ray mode."); - } else if (is->domain_ids().size() > 0 && sp) { - // If both a domain constraint and a point source location are - // specified, notify user that domain constraint takes precedence. - warning("Adjoint source has both a domain constraint and a point " - "type spatial distribution. The domain constraint takes " - "precedence in random ray mode -- point source coordinate " - "will be ignored."); - } - - // Check that a discrete energy distribution was used - Distribution* d = is->energy(); - Discrete* dd = dynamic_cast(d); - if (!dd) { - fatal_error( - "Only discrete (multigroup) energy distributions are allowed for " - "adjoint sources in random ray mode."); - } - } - } - - // Validate plotting files - /////////////////////////////////////////////////////////////////// - for (int p = 0; p < model::plots.size(); p++) { - - // Get handle to OpenMC plot object - const auto& openmc_plottable = model::plots[p]; - Plot* openmc_plot = dynamic_cast(openmc_plottable.get()); - - // Random ray plots only support voxel plots - if (!openmc_plot) { - warning(fmt::format( - "Plot {} will not be used for end of simulation data plotting -- only " - "voxel plotting is allowed in random ray mode.", - openmc_plottable->id())); - continue; - } else if (openmc_plot->type_ != Plot::PlotType::voxel) { - warning(fmt::format( - "Plot {} will not be used for end of simulation data plotting -- only " - "voxel plotting is allowed in random ray mode.", - openmc_plottable->id())); - continue; - } - } - - // Warn about slow MPI domain replication, if detected - /////////////////////////////////////////////////////////////////// -#ifdef OPENMC_MPI - if (mpi::n_procs > 1) { - warning( - "MPI parallelism is not supported by the random ray solver. All work " - "will be performed by rank 0. Domain decomposition may be implemented in " - "the future to provide efficient MPI scaling."); - } -#endif - - // Warn about instability resulting from linear sources in small regions - // when generating weight windows with FW-CADIS and an overlaid mesh. - /////////////////////////////////////////////////////////////////// - if (RandomRay::source_shape_ == RandomRaySourceShape::LINEAR && - variance_reduction::weight_windows.size() > 0) { - warning( - "Linear sources may result in negative fluxes in small source regions " - "generated by mesh subdivision. Negative sources may result in low " - "quality FW-CADIS weight windows. We recommend you use flat source " - "mode when generating weight windows with an overlaid mesh tally."); - } -} - -void openmc_finalize_random_ray() -{ - FlatSourceDomain::volume_estimator_ = RandomRayVolumeEstimator::HYBRID; - FlatSourceDomain::volume_normalized_flux_tallies_ = false; - FlatSourceDomain::adjoint_requested_ = false; - FlatSourceDomain::solve_ = RandomRaySolve::FORWARD; - FlatSourceDomain::fw_cadis_local_ = false; - FlatSourceDomain::fw_cadis_local_targets_.clear(); - FlatSourceDomain::mesh_domain_map_.clear(); - RandomRay::ray_source_.reset(); - RandomRay::source_shape_ = RandomRaySourceShape::FLAT; - RandomRay::sample_method_ = RandomRaySampleMethod::PRNG; -} - -//============================================================================== -// RandomRaySimulation implementation -//============================================================================== - -RandomRaySimulation::RandomRaySimulation() - : negroups_(data::mg.num_energy_groups_) -{ - // There are no source sites in random ray mode, so be sure to disable to - // ensure we don't attempt to write source sites to statepoint - settings::source_write = false; - - // Random ray mode does not have an inner loop over generations within a - // batch, so set the current gen to 1 - simulation::current_gen = 1; - - switch (RandomRay::source_shape_) { - case RandomRaySourceShape::FLAT: - domain_ = make_unique(); - break; - case RandomRaySourceShape::LINEAR: - case RandomRaySourceShape::LINEAR_XY: - domain_ = make_unique(); - break; - default: - fatal_error("Unknown random ray source shape"); - } - - // Convert OpenMC native MGXS into a more efficient format - // internal to the random ray solver - domain_->flatten_xs(); -} - -void RandomRaySimulation::apply_fixed_sources_and_mesh_domains() -{ - domain_->apply_meshes(); - if (settings::run_mode == RunMode::FIXED_SOURCE) { - // Transfer external source user inputs onto random ray source regions - domain_->convert_external_sources(false); - domain_->count_external_source_regions(); - } -} - -void RandomRaySimulation::prepare_fw_fixed_sources_adjoint() -{ - // Prepare adjoint fixed sources using forward flux - domain_->source_regions_.adjoint_reset(); - if (settings::run_mode == RunMode::FIXED_SOURCE) { - domain_->set_fw_adjoint_sources(); - } -} - -void RandomRaySimulation::prepare_local_fixed_sources_adjoint() -{ - if (settings::run_mode == RunMode::FIXED_SOURCE) { - domain_->set_local_adjoint_sources(); - } -} - -void RandomRaySimulation::prepare_adjoint_simulation(bool from_forward) -{ - reset_timers(); - - if (mpi::master) - header("ADJOINT FLUX SOLVE", 3); - - if (from_forward) { - // The forward solve has already run. Re-initialize OpenMC's general data - // structures for the adjoint solve and derive the adjoint source from the - // forward flux. - openmc_simulation_init(); - - prepare_fw_fixed_sources_adjoint(); - } else { - // Initialize adjoint fixed sources - domain_->apply_meshes(); - prepare_local_fixed_sources_adjoint(); - domain_->count_external_source_regions(); - } - - domain_->k_eff_ = 1.0; - - // Transpose scattering matrix - domain_->transpose_scattering_matrix(); - - // Swap nu_sigma_f and chi - domain_->nu_sigma_f_.swap(domain_->chi_); -} - -void RandomRaySimulation::simulate() -{ - // Begin main simulation timer - simulation::time_total.start(); - - // Random ray power iteration loop - while (simulation::current_batch < settings::n_batches) { - // Initialize the current batch - initialize_batch(); - initialize_generation(); - - // MPI not supported in random ray solver, so all work is done by rank 0 - // TODO: Implement domain decomposition for MPI parallelism - if (mpi::master) { - - // Reset total starting particle weight used for normalizing tallies - simulation::total_weight = 1.0; - - // Update source term (scattering + fission) - domain_->update_all_neutron_sources(); - - // Reset scalar fluxes, iteration volume tallies, and region hit flags - // to zero - domain_->batch_reset(); - - // At the beginning of the simulation, if mesh subdivision is in use, we - // need to swap the main source region container into the base container, - // as the main source region container will be used to hold the true - // subdivided source regions. The base container will therefore only - // contain the external source region information, the mesh indices, - // material properties, and initial guess values for the flux/source. - - // Start timer for transport - simulation::time_transport.start(); - -// Transport sweep over all random rays for the iteration -#pragma omp parallel for schedule(dynamic) \ - reduction(+ : total_geometric_intersections_) - for (int i = 0; i < settings::n_particles; i++) { - RandomRay ray(i, domain_.get()); - total_geometric_intersections_ += - ray.transport_history_based_single_ray(); - } - - simulation::time_transport.stop(); - - // Add any newly discovered source regions to the main source region - // container. - domain_->finalize_discovered_source_regions(); - - // Normalize scalar flux and update volumes - domain_->normalize_scalar_flux_and_volumes( - settings::n_particles * RandomRay::distance_active_); - - // Add source to scalar flux, compute number of FSR hits - int64_t n_hits = domain_->add_source_to_scalar_flux(); - - // Apply transport stabilization factors - domain_->apply_transport_stabilization(); - - if (settings::run_mode == RunMode::EIGENVALUE) { - // Compute random ray k-eff - domain_->compute_k_eff(); - - // Store random ray k-eff into OpenMC's native k-eff variable - global_tally_tracklength = domain_->k_eff_; - } - - // Execute all tallying tasks, if this is an active batch - if (simulation::current_batch > settings::n_inactive) { - - // Add this iteration's scalar flux estimate to final accumulated - // estimate - domain_->accumulate_iteration_flux(); - - // Use above mapping to contribute FSR flux data to appropriate - // tallies - domain_->random_ray_tally(); - } - - // Set phi_old = phi_new - domain_->flux_swap(); - - // Check for any obvious insabilities/nans/infs - instability_check(n_hits, domain_->k_eff_, avg_miss_rate_); - } // End MPI master work - - // Finalize the current batch - finalize_generation(); - finalize_batch(); - } // End random ray power iteration loop - - domain_->count_external_source_regions(); - - // End main simulation timer - simulation::time_total.stop(); - - // Normalize and save the final forward flux - double source_normalization_factor = - domain_->compute_fixed_source_normalization_factor() / - (settings::n_batches - settings::n_inactive); - -#pragma omp parallel for - for (uint64_t se = 0; se < domain_->n_source_elements(); se++) { - domain_->source_regions_.scalar_flux_final(se) *= - source_normalization_factor; - } - - // Finalize OpenMC - openmc_simulation_finalize(); - - // Output all simulation results - output_simulation_results(); -} - -void RandomRaySimulation::output_simulation_results() const -{ - // Print random ray results - if (mpi::master) { - print_results_random_ray(total_geometric_intersections_, - avg_miss_rate_ / settings::n_batches, negroups_, - domain_->n_source_regions(), domain_->n_external_source_regions_); - if (model::plots.size() > 0) { - domain_->output_to_vtk(); - } - } -} - -// Apply a few sanity checks to catch obvious cases of numerical instability. -// Instability typically only occurs if ray density is extremely low. -void RandomRaySimulation::instability_check( - int64_t n_hits, double k_eff, double& avg_miss_rate) const -{ - double percent_missed = ((domain_->n_source_regions() - n_hits) / - static_cast(domain_->n_source_regions())) * - 100.0; - avg_miss_rate += percent_missed; - - if (mpi::master) { - if (percent_missed > 10.0) { - warning(fmt::format( - "Very high FSR miss rate detected ({:.3f}%). Instability may occur. " - "Increase ray density by adding more rays and/or active distance.", - percent_missed)); - } else if (percent_missed > 1.0) { - warning( - fmt::format("Elevated FSR miss rate detected ({:.3f}%). Increasing " - "ray density by adding more rays and/or active " - "distance may improve simulation efficiency.", - percent_missed)); - } - - if (k_eff > 10.0 || k_eff < 0.01 || !(std::isfinite(k_eff))) { - fatal_error(fmt::format("Instability detected: k-eff = {:.5f}", k_eff)); - } - } -} - -// Print random ray simulation results -void RandomRaySimulation::print_results_random_ray( - uint64_t total_geometric_intersections, double avg_miss_rate, int negroups, - int64_t n_source_regions, int64_t n_external_source_regions) const -{ - using namespace simulation; - - if (settings::verbosity >= 6) { - double total_integrations = total_geometric_intersections * negroups; - double time_per_integration = - simulation::time_transport.elapsed() / total_integrations; - double misc_time = time_total.elapsed() - time_update_src.elapsed() - - time_transport.elapsed() - time_tallies.elapsed() - - time_bank_sendrecv.elapsed(); - - header("Simulation Statistics", 4); - fmt::print( - " Total Iterations = {}\n", settings::n_batches); - fmt::print( - " Number of Rays per Iteration = {}\n", settings::n_particles); - fmt::print(" Inactive Distance = {} cm\n", - RandomRay::distance_inactive_); - fmt::print(" Active Distance = {} cm\n", - RandomRay::distance_active_); - fmt::print(" Source Regions (SRs) = {}\n", n_source_regions); - fmt::print( - " SRs Containing External Sources = {}\n", n_external_source_regions); - fmt::print(" Total Geometric Intersections = {:.4e}\n", - static_cast(total_geometric_intersections)); - fmt::print(" Avg per Iteration = {:.4e}\n", - static_cast(total_geometric_intersections) / settings::n_batches); - fmt::print(" Avg per Iteration per SR = {:.2f}\n", - static_cast(total_geometric_intersections) / - static_cast(settings::n_batches) / n_source_regions); - fmt::print(" Avg SR Miss Rate per Iteration = {:.4f}%\n", avg_miss_rate); - fmt::print(" Energy Groups = {}\n", negroups); - fmt::print( - " Total Integrations = {:.4e}\n", total_integrations); - fmt::print(" Avg per Iteration = {:.4e}\n", - total_integrations / settings::n_batches); - - std::string estimator; - switch (domain_->volume_estimator_) { - case RandomRayVolumeEstimator::SIMULATION_AVERAGED: - estimator = "Simulation Averaged"; - break; - case RandomRayVolumeEstimator::NAIVE: - estimator = "Naive"; - break; - case RandomRayVolumeEstimator::HYBRID: - estimator = "Hybrid"; - break; - default: - fatal_error("Invalid volume estimator type"); - } - fmt::print(" Volume Estimator Type = {}\n", estimator); - - std::string adjoint_true = - (FlatSourceDomain::solve_ == RandomRaySolve::ADJOINT) ? "ON" : "OFF"; - fmt::print(" Adjoint Flux Mode = {}\n", adjoint_true); - - std::string shape; - switch (RandomRay::source_shape_) { - case RandomRaySourceShape::FLAT: - shape = "Flat"; - break; - case RandomRaySourceShape::LINEAR: - shape = "Linear"; - break; - case RandomRaySourceShape::LINEAR_XY: - shape = "Linear XY"; - break; - default: - fatal_error("Invalid random ray source shape"); - } - fmt::print(" Source Shape = {}\n", shape); - std::string sample_method; - switch (RandomRay::sample_method_) { - case RandomRaySampleMethod::PRNG: - sample_method = "PRNG"; - break; - case RandomRaySampleMethod::HALTON: - sample_method = "Halton"; - break; - case RandomRaySampleMethod::S2: - sample_method = "PRNG S2"; - break; - } - fmt::print(" Sample Method = {}\n", sample_method); - - if (domain_->is_transport_stabilization_needed_) { - fmt::print(" Transport XS Stabilization Used = YES (rho = {:.3f})\n", - FlatSourceDomain::diagonal_stabilization_rho_); - } else { - fmt::print(" Transport XS Stabilization Used = NO\n"); - } - - header("Timing Statistics", 4); - show_time("Total time for initialization", time_initialize.elapsed()); - show_time("Reading cross sections", time_read_xs.elapsed(), 1); - show_time("Total simulation time", time_total.elapsed()); - show_time("Transport sweep only", time_transport.elapsed(), 1); - show_time("Source update only", time_update_src.elapsed(), 1); - show_time("Tally conversion only", time_tallies.elapsed(), 1); - show_time("MPI source reductions only", time_bank_sendrecv.elapsed(), 1); - show_time("Other iteration routines", misc_time, 1); - if (settings::run_mode == RunMode::EIGENVALUE) { - show_time("Time in inactive batches", time_inactive.elapsed()); - } - show_time("Time in active batches", time_active.elapsed()); - show_time("Time writing statepoints", time_statepoint.elapsed()); - show_time("Total time for finalization", time_finalize.elapsed()); - show_time("Time per integration", time_per_integration); - } - - if (settings::verbosity >= 4 && settings::run_mode == RunMode::EIGENVALUE) { - header("Results", 4); - fmt::print(" k-effective = {:.5f} +/- {:.5f}\n", - simulation::keff, simulation::keff_std); - } -} - -} // namespace openmc - -//============================================================================== -// C API functions -//============================================================================== - -void openmc_run_random_ray() -{ - using namespace openmc; - - // Determine which solves to run. If adjoint results are requested and no - // user-defined adjoint source is present, an initial forward solve is needed - // to construct the adjoint source from the forward flux (FW-CADIS). If the - // user has defined an adjoint source, the forward solve is skipped and only - // the adjoint solve is run. - const bool run_adjoint = FlatSourceDomain::adjoint_requested_; - const bool have_adjoint_source = !model::adjoint_sources.empty(); - const bool run_forward = !(run_adjoint && have_adjoint_source); - - // Set the initial solve type - if (!run_forward) { - FlatSourceDomain::solve_ = RandomRaySolve::ADJOINT; - } else if (run_adjoint) { - FlatSourceDomain::solve_ = RandomRaySolve::FORWARD_FOR_ADJOINT; - } else { - FlatSourceDomain::solve_ = RandomRaySolve::FORWARD; - } - - // Initialize OpenMC general data structures - openmc_simulation_init(); - - // Validate that inputs meet requirements for random ray mode - if (mpi::master) - validate_random_ray_inputs(); - - // Initialize Random Ray Simulation Object - RandomRaySimulation sim; - - // Run the forward solve - if (run_forward) { - // When an adjoint solve follows, report this as the initial forward solve - if (run_adjoint && mpi::master) - header("FORWARD FLUX SOLVE", 3); - sim.apply_fixed_sources_and_mesh_domains(); - sim.simulate(); - } - - // Run the adjoint solve - if (run_adjoint) { - FlatSourceDomain::solve_ = RandomRaySolve::ADJOINT; - sim.prepare_adjoint_simulation(run_forward); - sim.simulate(); - } -} diff --git a/src/random_ray/source_region.cpp b/src/random_ray/source_region.cpp deleted file mode 100644 index 78543c5ab..000000000 --- a/src/random_ray/source_region.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "openmc/random_ray/source_region.h" - -#include "openmc/error.h" -#include "openmc/message_passing.h" -#include "openmc/simulation.h" - -namespace openmc { - -//============================================================================== -// SourceRegionHandle implementation -//============================================================================== -SourceRegionHandle::SourceRegionHandle(SourceRegion& sr) - : negroups_(sr.scalar_flux_old_.size()), material_(&sr.material_), - temperature_idx_(&sr.temperature_idx_), density_mult_(&sr.density_mult_), - is_small_(&sr.is_small_), n_hits_(&sr.n_hits_), - is_linear_(sr.source_gradients_.size() > 0), lock_(&sr.lock_), - volume_(&sr.volume_), volume_t_(&sr.volume_t_), volume_sq_(&sr.volume_sq_), - volume_sq_t_(&sr.volume_sq_t_), volume_naive_(&sr.volume_naive_), - position_recorded_(&sr.position_recorded_), - external_source_present_(&sr.external_source_present_), - position_(&sr.position_), centroid_(&sr.centroid_), - centroid_iteration_(&sr.centroid_iteration_), centroid_t_(&sr.centroid_t_), - mom_matrix_(&sr.mom_matrix_), mom_matrix_t_(&sr.mom_matrix_t_), - volume_task_(&sr.volume_task_), mesh_(&sr.mesh_), - parent_sr_(&sr.parent_sr_), scalar_flux_old_(sr.scalar_flux_old_.data()), - scalar_flux_new_(sr.scalar_flux_new_.data()), source_(sr.source_.data()), - external_source_(sr.external_source_.data()), - scalar_flux_final_(sr.scalar_flux_final_.data()), - source_gradients_(sr.source_gradients_.data()), - flux_moments_old_(sr.flux_moments_old_.data()), - flux_moments_new_(sr.flux_moments_new_.data()), - flux_moments_t_(sr.flux_moments_t_.data()), - tally_task_(sr.tally_task_.data()) -{} - -//============================================================================== -// SourceRegion implementation -//============================================================================== -SourceRegion::SourceRegion(int negroups, bool is_linear) -{ - if (settings::run_mode == RunMode::EIGENVALUE) { - // If in eigenvalue mode, set starting flux to guess of 1 - scalar_flux_old_.assign(negroups, 1.0); - } else { - // If in fixed source mode, set starting flux to guess of zero - // and initialize external source arrays - scalar_flux_old_.assign(negroups, 0.0); - external_source_.assign(negroups, 0.0); - } - - scalar_flux_new_.assign(negroups, 0.0); - source_.assign(negroups, 0.0); - scalar_flux_final_.assign(negroups, 0.0); - - tally_task_.resize(negroups); - if (is_linear) { - source_gradients_.resize(negroups); - flux_moments_old_.resize(negroups); - flux_moments_new_.resize(negroups); - flux_moments_t_.resize(negroups); - } -} - -//============================================================================== -// SourceRegionContainer implementation -//============================================================================== - -void SourceRegionContainer::push_back(const SourceRegion& sr) -{ - n_source_regions_++; - - // Scalar fields - material_.push_back(sr.material_); - temperature_idx_.push_back(sr.temperature_idx_); - density_mult_.push_back(sr.density_mult_); - is_small_.push_back(sr.is_small_); - n_hits_.push_back(sr.n_hits_); - lock_.push_back(sr.lock_); - volume_.push_back(sr.volume_); - volume_t_.push_back(sr.volume_t_); - volume_sq_.push_back(sr.volume_sq_); - volume_sq_t_.push_back(sr.volume_sq_t_); - volume_naive_.push_back(sr.volume_naive_); - position_recorded_.push_back(sr.position_recorded_); - external_source_present_.push_back(sr.external_source_present_); - position_.push_back(sr.position_); - volume_task_.push_back(sr.volume_task_); - mesh_.push_back(sr.mesh_); - parent_sr_.push_back(sr.parent_sr_); - - // Only store these fields if is_linear_ is true - if (is_linear_) { - centroid_.push_back(sr.centroid_); - centroid_iteration_.push_back(sr.centroid_iteration_); - centroid_t_.push_back(sr.centroid_t_); - mom_matrix_.push_back(sr.mom_matrix_); - mom_matrix_t_.push_back(sr.mom_matrix_t_); - } - - // Energy-dependent fields - for (int g = 0; g < negroups_; ++g) { - scalar_flux_old_.push_back(sr.scalar_flux_old_[g]); - scalar_flux_new_.push_back(sr.scalar_flux_new_[g]); - scalar_flux_final_.push_back(sr.scalar_flux_final_[g]); - source_.push_back(sr.source_[g]); - if (settings::run_mode == RunMode::FIXED_SOURCE) { - external_source_.push_back(sr.external_source_[g]); - } - - // Only store these fields if is_linear_ is true - if (is_linear_) { - source_gradients_.push_back(sr.source_gradients_[g]); - flux_moments_old_.push_back(sr.flux_moments_old_[g]); - flux_moments_new_.push_back(sr.flux_moments_new_[g]); - flux_moments_t_.push_back(sr.flux_moments_t_[g]); - } - - // Tally tasks - tally_task_.emplace_back(sr.tally_task_[g]); - } -} - -void SourceRegionContainer::assign( - int n_source_regions, const SourceRegion& source_region) -{ - // Clear existing data - n_source_regions_ = 0; - material_.clear(); - temperature_idx_.clear(); - density_mult_.clear(); - is_small_.clear(); - n_hits_.clear(); - lock_.clear(); - volume_.clear(); - volume_t_.clear(); - volume_sq_.clear(); - volume_sq_t_.clear(); - volume_naive_.clear(); - position_recorded_.clear(); - external_source_present_.clear(); - position_.clear(); - mesh_.clear(); - parent_sr_.clear(); - - if (is_linear_) { - centroid_.clear(); - centroid_iteration_.clear(); - centroid_t_.clear(); - mom_matrix_.clear(); - mom_matrix_t_.clear(); - } - - scalar_flux_old_.clear(); - scalar_flux_new_.clear(); - scalar_flux_final_.clear(); - source_.clear(); - external_source_.clear(); - - if (is_linear_) { - source_gradients_.clear(); - flux_moments_old_.clear(); - flux_moments_new_.clear(); - flux_moments_t_.clear(); - } - - tally_task_.clear(); - volume_task_.clear(); - - // Fill with copies of source_region - for (int i = 0; i < n_source_regions; ++i) { - push_back(source_region); - } -} - -void SourceRegionContainer::flux_swap() -{ - scalar_flux_old_.swap(scalar_flux_new_); - if (is_linear_) { - flux_moments_old_.swap(flux_moments_new_); - } -} - -SourceRegionHandle SourceRegionContainer::get_source_region_handle(int64_t sr) -{ - SourceRegionHandle handle; - handle.negroups_ = negroups(); - handle.material_ = &material(sr); - handle.temperature_idx_ = &temperature_idx(sr); - handle.density_mult_ = &density_mult(sr); - handle.is_small_ = &is_small(sr); - handle.n_hits_ = &n_hits(sr); - handle.is_linear_ = is_linear(); - handle.lock_ = &lock(sr); - handle.volume_ = &volume(sr); - handle.volume_t_ = &volume_t(sr); - handle.volume_sq_ = &volume_sq(sr); - handle.volume_sq_t_ = &volume_sq_t(sr); - handle.volume_naive_ = &volume_naive(sr); - handle.position_recorded_ = &position_recorded(sr); - handle.external_source_present_ = &external_source_present(sr); - handle.position_ = &position(sr); - handle.volume_task_ = &volume_task(sr); - handle.mesh_ = &mesh(sr); - handle.parent_sr_ = &parent_sr(sr); - handle.scalar_flux_old_ = &scalar_flux_old(sr, 0); - handle.scalar_flux_new_ = &scalar_flux_new(sr, 0); - handle.source_ = &source(sr, 0); - if (settings::run_mode == RunMode::FIXED_SOURCE) { - handle.external_source_ = &external_source(sr, 0); - } else { - handle.external_source_ = nullptr; - } - handle.scalar_flux_final_ = &scalar_flux_final(sr, 0); - handle.tally_task_ = &tally_task(sr, 0); - - if (handle.is_linear_) { - handle.centroid_ = ¢roid(sr); - handle.centroid_iteration_ = ¢roid_iteration(sr); - handle.centroid_t_ = ¢roid_t(sr); - handle.mom_matrix_ = &mom_matrix(sr); - handle.mom_matrix_t_ = &mom_matrix_t(sr); - handle.source_gradients_ = &source_gradients(sr, 0); - handle.flux_moments_old_ = &flux_moments_old(sr, 0); - handle.flux_moments_new_ = &flux_moments_new(sr, 0); - handle.flux_moments_t_ = &flux_moments_t(sr, 0); - } - - return handle; -} - -void SourceRegionContainer::adjoint_reset() -{ - std::fill(n_hits_.begin(), n_hits_.end(), 0); - std::fill(volume_.begin(), volume_.end(), 0.0); - std::fill(volume_t_.begin(), volume_t_.end(), 0.0); - std::fill(volume_sq_.begin(), volume_sq_.end(), 0.0); - std::fill(volume_sq_t_.begin(), volume_sq_t_.end(), 0.0); - std::fill(volume_naive_.begin(), volume_naive_.end(), 0.0); - std::fill( - external_source_present_.begin(), external_source_present_.end(), 0); - std::fill(external_source_.begin(), external_source_.end(), 0.0); - std::fill(centroid_.begin(), centroid_.end(), Position {0.0, 0.0, 0.0}); - std::fill(centroid_iteration_.begin(), centroid_iteration_.end(), - Position {0.0, 0.0, 0.0}); - std::fill(centroid_t_.begin(), centroid_t_.end(), Position {0.0, 0.0, 0.0}); - std::fill(mom_matrix_.begin(), mom_matrix_.end(), - MomentMatrix {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}); - std::fill(mom_matrix_t_.begin(), mom_matrix_t_.end(), - MomentMatrix {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}); - if (settings::run_mode == RunMode::FIXED_SOURCE) { - std::fill(scalar_flux_old_.begin(), scalar_flux_old_.end(), 0.0); - } else { - std::fill(scalar_flux_old_.begin(), scalar_flux_old_.end(), 1.0); - } - std::fill(scalar_flux_new_.begin(), scalar_flux_new_.end(), 0.0); - std::fill(source_.begin(), source_.end(), 0.0f); - std::fill(external_source_.begin(), external_source_.end(), 0.0f); - std::fill(source_gradients_.begin(), source_gradients_.end(), - MomentArray {0.0, 0.0, 0.0}); - std::fill(flux_moments_old_.begin(), flux_moments_old_.end(), - MomentArray {0.0, 0.0, 0.0}); - std::fill(flux_moments_new_.begin(), flux_moments_new_.end(), - MomentArray {0.0, 0.0, 0.0}); - std::fill(flux_moments_t_.begin(), flux_moments_t_.end(), - MomentArray {0.0, 0.0, 0.0}); -} - -} // namespace openmc diff --git a/src/ray.cpp b/src/ray.cpp deleted file mode 100644 index 3d848e3a3..000000000 --- a/src/ray.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "openmc/ray.h" - -#include "openmc/error.h" -#include "openmc/geometry.h" -#include "openmc/settings.h" - -namespace openmc { - -void Ray::compute_distance() -{ - boundary() = distance_to_boundary(*this); -} - -void Ray::trace() -{ - // To trace the ray from its origin all the way through the model, we have - // to proceed in two phases. In the first, the ray may or may not be found - // inside the model. If the ray is already in the model, phase one can be - // skipped. Otherwise, the ray has to be advanced to the boundary of the - // model where all the cells are defined. Importantly, this is assuming that - // the model is convex, which is a very reasonable assumption for any - // radiation transport model. - // - // After phase one is done, we can starting tracing from cell to cell within - // the model. This step can use neighbor lists to accelerate the ray tracing. - - bool inside_cell; - // Check for location if the particle is already known - if (lowest_coord().cell() == C_NONE) { - // The geometry position of the particle is either unknown or outside of the - // edge of the model. - if (lowest_coord().universe() == C_NONE) { - // Attempt to initialize the particle. We may have to - // enter a loop to move it up to the edge of the model. - inside_cell = exhaustive_find_cell(*this, settings::verbosity >= 10); - } else { - // It has been already calculated that the current position is outside of - // the edge of the model. - inside_cell = false; - } - } else { - // Availability of the cell means that the particle is located inside the - // edge. - inside_cell = true; - } - - // Advance to the boundary of the model - while (!inside_cell) { - advance_to_boundary_from_void(); - inside_cell = exhaustive_find_cell(*this, settings::verbosity >= 10); - - // If true this means no surface was intersected. See cell.cpp and search - // for numeric_limits to see where we return it. - if (surface() == std::numeric_limits::max()) { - warning(fmt::format("Lost a ray, r = {}, u = {}", r(), u())); - return; - } - - // Exit this loop and enter into cell-to-cell ray tracing (which uses - // neighbor lists) - if (inside_cell) - break; - - // if there is no intersection with the model, we're done - if (boundary().surface() == SURFACE_NONE) - return; - - event_counter_++; - if (event_counter_ > MAX_INTERSECTIONS) { - warning("Likely infinite loop in ray traced plot"); - return; - } - } - - // Call the specialized logic for this type of ray. This is for the - // intersection for the first intersection if we had one. - if (boundary().surface() != SURFACE_NONE) { - // set the geometry state's surface attribute to be used for - // surface normal computation - surface() = boundary().surface(); - on_intersection(); - if (stop_) - return; - } - - // reset surface attribute to zero after the first intersection so that it - // doesn't perturb surface crossing logic from here on out - surface() = 0; - - // This is the ray tracing loop within the model. It exits after exiting - // the model, which is equivalent to assuming that the model is convex. - // It would be nice to factor out the on_intersection at the end of this - // loop and then do "while (inside_cell)", but we can't guarantee it's - // on a surface in that case. There might be some other way to set it - // up that is perhaps a little more elegant, but this is what works just - // fine. - while (true) { - - compute_distance(); - - // There are no more intersections to process - // if we hit the edge of the model, so stop - // the particle in that case. Also, just exit - // if a negative distance was somehow computed. - if (boundary().distance() == INFTY || boundary().distance() == INFINITY || - boundary().distance() < 0) { - return; - } - - // See below comment where call_on_intersection is checked in an - // if statement for an explanation of this. - bool call_on_intersection {true}; - if (boundary().distance() < 10 * TINY_BIT) { - call_on_intersection = false; - } - - // DAGMC surfaces expect us to go a little bit further than the advance - // distance to properly check cell inclusion. - boundary().distance() += TINY_BIT; - - // Advance particle, prepare for next intersection - for (int lev = 0; lev < n_coord(); ++lev) { - coord(lev).r() += boundary().distance() * coord(lev).u(); - } - surface() = boundary().surface(); - // Initialize last cells from the current cell, because the cell() variable - // does not contain the data for the case of a single-segment ray - for (int j = 0; j < n_coord(); ++j) { - cell_last(j) = coord(j).cell(); - } - n_coord_last() = n_coord(); - n_coord() = boundary().coord_level(); - if (boundary().lattice_translation()[0] != 0 || - boundary().lattice_translation()[1] != 0 || - boundary().lattice_translation()[2] != 0) { - cross_lattice(*this, boundary(), settings::verbosity >= 10); - } - - // Record how far the ray has traveled - traversal_distance_ += boundary().distance(); - inside_cell = neighbor_list_find_cell(*this, settings::verbosity >= 10); - - // Call the specialized logic for this type of ray. Note that we do not - // call this if the advance distance is very small. Unfortunately, it seems - // darn near impossible to get the particle advanced to the model boundary - // and through it without sometimes accidentally calling on_intersection - // twice. This incorrectly shades the region as occluded when it might not - // actually be. By screening out intersection distances smaller than a - // threshold 10x larger than the scoot distance used to advance up to the - // model boundary, we can avoid that situation. - if (call_on_intersection) { - on_intersection(); - if (stop_) - return; - } - - if (!inside_cell) - return; - - event_counter_++; - if (event_counter_ > MAX_INTERSECTIONS) { - warning("Likely infinite loop in ray traced plot"); - return; - } - } -} - -} // namespace openmc diff --git a/src/reaction.cpp b/src/reaction.cpp index c02e0cc40..ec9d32f9a 100644 --- a/src/reaction.cpp +++ b/src/reaction.cpp @@ -1,20 +1,17 @@ #include "openmc/reaction.h" -#include // for remove_if #include #include #include // for move #include -#include "openmc/chain.h" #include "openmc/constants.h" #include "openmc/endf.h" #include "openmc/hdf5_interface.h" #include "openmc/random_lcg.h" #include "openmc/search.h" #include "openmc/secondary_uncorrelated.h" -#include "openmc/settings.h" namespace openmc { @@ -22,8 +19,7 @@ namespace openmc { // Reaction implementation //============================================================================== -Reaction::Reaction( - hid_t group, const vector& temperatures, std::string name) +Reaction::Reaction(hid_t group, const vector& temperatures) { read_attribute(group, "Q_value", q_value_); read_attribute(group, "mt", mt_); @@ -67,36 +63,10 @@ Reaction::Reaction( close_group(pgroup); } } - - if (settings::use_decay_photons) { - // Remove photon products for D1S method - products_.erase(std::remove_if(products_.begin(), products_.end(), - [](const auto& p) { return p.particle_.is_photon(); }), - products_.end()); - - // Determine product for D1S method - auto nuclide_it = data::chain_nuclide_map.find(name); - if (nuclide_it != data::chain_nuclide_map.end()) { - const auto& chain_nuc = data::chain_nuclides[nuclide_it->second]; - const auto& rx_products = chain_nuc->reaction_products(); - auto product_it = rx_products.find(mt_); - if (product_it != rx_products.end()) { - auto decay_products = product_it->second; - for (const auto& decay_product : decay_products) { - auto product_it = data::chain_nuclide_map.find(decay_product.name); - if (product_it != data::chain_nuclide_map.end()) { - const auto& product_nuc = data::chain_nuclides[product_it->second]; - if (product_nuc->photon_energy()) { - products_.emplace_back(decay_product); - } - } - } - } - } - } } -double Reaction::xs(int64_t i_temp, int64_t i_grid, double interp_factor) const +double Reaction::xs( + gsl::index i_temp, gsl::index i_grid, double interp_factor) const { // If energy is below threshold, return 0. Otherwise interpolate between // nearest grid points @@ -112,8 +82,9 @@ double Reaction::xs(const NuclideMicroXS& micro) const return this->xs(micro.index_temp, micro.index_grid, micro.interp_factor); } -double Reaction::collapse_rate(int64_t i_temp, span energy, - span flux, const vector& grid) const +double Reaction::collapse_rate(gsl::index i_temp, + gsl::span energy, gsl::span flux, + const vector& grid) const { // Find index corresponding to first energy const auto& xs = xs_[i_temp].value; @@ -200,14 +171,9 @@ std::unordered_map REACTION_NAME_MAP { {SCORE_INVERSE_VELOCITY, "inverse-velocity"}, {SCORE_FISS_Q_PROMPT, "fission-q-prompt"}, {SCORE_FISS_Q_RECOV, "fission-q-recoverable"}, - {SCORE_PULSE_HEIGHT, "pulse-height"}, - {SCORE_IFP_TIME_NUM, "ifp-time-numerator"}, - {SCORE_IFP_BETA_NUM, "ifp-beta-numerator"}, - {SCORE_IFP_DENOM, "ifp-denominator"}, // Normal ENDF-based reactions {TOTAL_XS, "(n,total)"}, {ELASTIC, "(n,elastic)"}, - {N_NONELASTIC, "(n,nonelastic)"}, {N_LEVEL, "(n,level)"}, {N_2ND, "(n,2nd)"}, {N_2N, "(n,2n)"}, @@ -309,7 +275,6 @@ std::unordered_map REACTION_NAME_MAP { {N_XA, "(n,Xa)"}, {HEATING, "heating"}, {DAMAGE_ENERGY, "damage-energy"}, - {PHOTON_TOTAL, "photon-total"}, {COHERENT, "coherent-scatter"}, {INCOHERENT, "incoherent-scatter"}, {PAIR_PROD_ELEC, "pair-production-electron"}, @@ -347,24 +312,13 @@ void initialize_maps() // Create photoelectric subshells for (int mt = 534; mt <= 572; ++mt) { REACTION_NAME_MAP[mt] = - fmt::format("photoelectric-{}", SUBSHELLS[mt - 534]); + fmt::format("photoelectric, {} subshell", SUBSHELLS[mt - 534]); } // Invert name map to create type map for (const auto& kv : REACTION_NAME_MAP) { REACTION_TYPE_MAP[kv.second] = kv.first; } - - // Alternate names - REACTION_TYPE_MAP["elastic"] = ELASTIC; - REACTION_TYPE_MAP["n2n"] = N_2N; - REACTION_TYPE_MAP["n3n"] = N_3N; - REACTION_TYPE_MAP["n4n"] = N_4N; - REACTION_TYPE_MAP["H1-production"] = N_XP; - REACTION_TYPE_MAP["H2-production"] = N_XD; - REACTION_TYPE_MAP["H3-production"] = N_XT; - REACTION_TYPE_MAP["He3-production"] = N_X3HE; - REACTION_TYPE_MAP["He4-production"] = N_XA; } std::string reaction_name(int mt) @@ -382,42 +336,62 @@ std::string reaction_name(int mt) } } -int reaction_tally_mt(std::string name) +int reaction_type(std::string name) { - // All "total" scores should map to the special SCORE_TOTAL - if (name == "total" || name == "(n,total)" || name == "photon-total") - return SCORE_TOTAL; - - // All fission scores should map to the special SCORE_FISSION - if (name == "fission" || name == "(n,fission)") - return SCORE_FISSION; - - // Delegate everything else to reaction_mt() - return reaction_mt(name); -} - -int reaction_mt(const std::string& name) -{ - // Initialize maps if needed + // Initialize remainder of name map and all of type map if (REACTION_TYPE_MAP.empty()) initialize_maps(); - // Look up directly in type map (no score indirection) + // (n,total) exists in REACTION_TYPE_MAP for MT=1, but we need this to return + // the special SCORE_TOTAL score + if (name == "(n,total)") + return SCORE_TOTAL; + + // Check if type map has an entry for this reaction name auto it = REACTION_TYPE_MAP.find(name); if (it != REACTION_TYPE_MAP.end()) { - int mt = it->second; - return mt; + return it->second; } - // Assume the given string is an MT number + // Alternate names for several reactions + if (name == "elastic") { + return ELASTIC; + } else if (name == "n2n") { + return N_2N; + } else if (name == "n3n") { + return N_3N; + } else if (name == "n4n") { + return N_4N; + } else if (name == "H1-production") { + return N_XP; + } else if (name == "H2-production") { + return N_XD; + } else if (name == "H3-production") { + return N_XT; + } else if (name == "He3-production") { + return N_X3HE; + } else if (name == "He4-production") { + return N_XA; + } + + // Assume the given string is a reaction MT number. Make sure it's a natural + // number then return. int MT = 0; try { MT = std::stoi(name); } catch (const std::invalid_argument& ex) { - throw std::invalid_argument("Unknown reaction name \"" + name + "\"."); + throw std::invalid_argument( + "Invalid tally score \"" + name + + "\". See the docs " + "for details: " + "https://docs.openmc.org/en/stable/usersguide/tallies.html#scores"); } if (MT < 1) - throw std::invalid_argument("Unknown reaction name \"" + name + "\"."); + throw std::invalid_argument( + "Invalid tally score \"" + name + + "\". See the docs " + "for details: " + "https://docs.openmc.org/en/stable/usersguide/tallies.html#scores"); return MT; } diff --git a/src/reaction_product.cpp b/src/reaction_product.cpp index a1c937861..4cef8d3a9 100644 --- a/src/reaction_product.cpp +++ b/src/reaction_product.cpp @@ -1,6 +1,5 @@ #include "openmc/reaction_product.h" -#include #include // for string #include @@ -27,7 +26,7 @@ ReactionProduct::ReactionProduct(hid_t group) // Read particle type std::string temp; read_attribute(group, "particle", temp); - particle_ = ParticleType {temp}; + particle_ = str_to_particle_type(temp); // Read emission mode and decay rate read_attribute(group, "emission_mode", temp); @@ -43,7 +42,7 @@ ReactionProduct::ReactionProduct(hid_t group) if (emission_mode_ == EmissionMode::delayed) { if (attribute_exists(group, "decay_rate")) { read_attribute(group, "decay_rate", decay_rate_); - } else if (particle_.is_neutron()) { + } else if (particle_ == ParticleType::neutron) { warning(fmt::format("Decay rate doesn't exist for delayed neutron " "emission ({}).", object_name(group))); @@ -84,33 +83,9 @@ ReactionProduct::ReactionProduct(hid_t group) } } -ReactionProduct::ReactionProduct(const ChainNuclide::Product& product) +void ReactionProduct::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { - particle_ = ParticleType::photon(); - emission_mode_ = EmissionMode::delayed; - - // Get chain nuclide object for radionuclide - parent_nuclide_ = data::chain_nuclide_map.at(product.name); - const auto& chain_nuc = data::chain_nuclides[parent_nuclide_].get(); - - // Determine decay constant in [s^-1] - decay_rate_ = chain_nuc->decay_constant(); - - // Determine number of photons per decay and set yield - double photon_per_sec = chain_nuc->photon_energy()->integral(); - double photon_per_decay = photon_per_sec / decay_rate_; - vector coef = {product.branching_ratio * photon_per_decay}; - yield_ = make_unique(coef); - - // Set decay photon angle-energy distribution - distribution_.push_back( - make_unique(chain_nuc->photon_energy())); -} - -AngleEnergy& ReactionProduct::sample_dist(double E_in, uint64_t* seed) const -{ - assert(!distribution_.empty()); - auto n = applicability_.size(); if (n > 1) { double prob = 0.0; @@ -120,24 +95,15 @@ AngleEnergy& ReactionProduct::sample_dist(double E_in, uint64_t* seed) const prob += applicability_[i](E_in); // If i-th distribution is sampled, sample energy from the distribution - if (c <= prob) - return *distribution_[i]; + if (c <= prob) { + distribution_[i]->sample(E_in, E_out, mu, seed); + break; + } } + } else { + // If only one distribution is present, go ahead and sample it + distribution_[0]->sample(E_in, E_out, mu, seed); } - - return *distribution_.back(); -} - -void ReactionProduct::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - sample_dist(E_in, seed).sample(E_in, E_out, mu, seed); -} - -double ReactionProduct::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - return sample_dist(E_in, seed).sample_energy_and_pdf(E_in, mu, E_out, seed); } } // namespace openmc diff --git a/src/relaxng/cross_sections.rnc b/src/relaxng/cross_sections.rnc new file mode 100644 index 000000000..7fbc610a2 --- /dev/null +++ b/src/relaxng/cross_sections.rnc @@ -0,0 +1,12 @@ +element cross_sections { + element library { + (element materials { xsd:string } | + attribute materials { xsd:string }) & + (element type { xsd:string } | + attribute type { xsd:string }) & + (element path { xsd:string } | + attribute path { xsd:string }) + }* & + + element directory { xsd:string { maxLength = "255" } }? +} \ No newline at end of file diff --git a/src/relaxng/cross_sections.rng b/src/relaxng/cross_sections.rng new file mode 100644 index 000000000..435f7fa84 --- /dev/null +++ b/src/relaxng/cross_sections.rng @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255 + + + + + diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc new file mode 100644 index 000000000..e3c88c445 --- /dev/null +++ b/src/relaxng/geometry.rnc @@ -0,0 +1,55 @@ +element geometry { + element cell { + (element id { xsd:int } | attribute id { xsd:int }) & + (element name { xsd:string { maxLength="52" } } | + attribute name { xsd:string { maxLength="52" } })? & + (element universe { xsd:int } | attribute universe { xsd:int })? & + ( + (element fill { xsd:int } | attribute fill { xsd:int }) | + (element material { list { ( xsd:int | "void" )+ } } | + attribute material { list { ( xsd:int | "void" )+ } }) + ) & + (element temperature { list { xsd:double+ } } | + attribute temperature { list { xsd:double+ } } )? & + (element region { xsd:string } | attribute region { xsd:string })? & + (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & + (element translation { list { xsd:double+ } } | attribute translation { list { xsd:double+ } })? + }* + + & element surface { + (element id { xsd:int } | attribute id { xsd:int }) & + (element name { xsd:string { maxLength="52" } } | + attribute name { xsd:string { maxLength="52" } })? & + (element type { xsd:string { maxLength = "15" } } | + attribute type { xsd:string { maxLength = "15" } }) & + (element coeffs { list { xsd:double+ } } | attribute coeffs { list { xsd:double+ } }) & + (element boundary { ( "transmit" | "reflective" | "vacuum" | "periodic" ) } | + attribute boundary { ( "transmit" | "reflective" | "vacuum" | "periodic" ) })? & + (element periodic_surface_id { xsd:int } | attribute periodic_surface_id { xsd:int })? + }* + + & element lattice { + (element id { xsd:int } | attribute id { xsd:int }) & + (element name { xsd:string { maxLength="52" } } | + attribute name { xsd:string { maxLength="52" } })? & + (element dimension { list { xsd:positiveInteger+ } } | + attribute dimension { list { xsd:positiveInteger+ } }) & + (element lower_left { list { xsd:double+ } } | attribute lower_left { list { xsd:double+ } }) & + (element pitch { list { xsd:double+ } } | attribute pitch { list { xsd:double+ } }) & + (element universes { list { xsd:int+ } } | attribute universes { list { xsd:int+ } }) & + (element outer { xsd:int } | attribute outer { xsd:int })? + }* + + & element hex_lattice { + (element id { xsd:int } | attribute id { xsd:int }) & + (element name { xsd:string { maxLength="52" } } | + attribute name { xsd:string { maxLength="52" } })? & + (element n_rings { xsd:int } | attribute n_rings { xsd:int }) & + (element n_axial { xsd:int } | attribute n_axial { xsd:int })? & + (element center { list { xsd:double+ } } | attribute center { list { xsd:double+ } }) & + (element pitch { list { xsd:double+ } } | attribute pitch { list { xsd:double+ } }) & + (element orientation { ( "x" | "y" ) } | attribute orientation { ( "x" | "y" ) })? & + (element universes { list { xsd:int+ } } | attribute universes { list { xsd:int+ } }) & + (element outer { xsd:int } | attribute outer { xsd:int })? + }* +} diff --git a/src/relaxng/geometry.rng b/src/relaxng/geometry.rng new file mode 100644 index 000000000..56bf38580 --- /dev/null +++ b/src/relaxng/geometry.rng @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + + + + + 52 + + + + + 52 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + + + void + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 52 + + + + + 52 + + + + + + + + 15 + + + + + 15 + + + + + + + + + + + + + + + + + + + + + + + + transmit + reflective + vacuum + periodic + + + + + transmit + reflective + vacuum + periodic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 52 + + + + + 52 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 52 + + + + + 52 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + y + + + + + x + y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/relaxng/materials.rnc b/src/relaxng/materials.rnc new file mode 100644 index 000000000..c82ecfeaa --- /dev/null +++ b/src/relaxng/materials.rnc @@ -0,0 +1,41 @@ +element materials { + element material { + (element id { xsd:int } | attribute id { xsd:int }) & + + (element name { xsd:string } | attribute name { xsd:string })? & + + (element depletable { xsd:boolean } | attribute depletable { xsd:boolean })? & + + (element volume { xsd:double } | attribute volume { xsd:double })? & + + (element temperature { xsd:double } | attribute temperature { xsd:double })? & + + element density { + (element value { xsd:double } | attribute value { xsd:double })? & + (element units { xsd:string { maxLength = "10" } } | + attribute units { xsd:string { maxLength = "10" } }) + } & + + element nuclide { + (element name { xsd:string } | attribute name { xsd:string }) & + ( + (element ao { xsd:double } | attribute ao { xsd:double }) | + (element wo { xsd:double } | attribute wo { xsd:double }) + ) + }* & + + element isotropic { xsd:string }? & + + element macroscopic { + (element name { xsd:string } | + attribute name { xsd:string }) + }* & + + element sab { + (element name { xsd:string } | attribute name { xsd:string }) & + (element fraction { xsd:double } | attribute fraction { xsd:double })? + }* + }+ & + + element cross_sections { xsd:string { maxLength = "255" } }? +} diff --git a/src/relaxng/materials.rng b/src/relaxng/materials.rng new file mode 100644 index 000000000..e99fb7adf --- /dev/null +++ b/src/relaxng/materials.rng @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255 + + + + + diff --git a/src/relaxng/mg_cross_sections.rnc b/src/relaxng/mg_cross_sections.rnc new file mode 100644 index 000000000..b2aaec4d4 --- /dev/null +++ b/src/relaxng/mg_cross_sections.rnc @@ -0,0 +1,61 @@ +element cross_sections { + + element groups { xsd:int } & + + element group_structure { list { xsd:double+ } } & + + element inverse_velocities { list { xsd:double+ } }? & + + element xsdata { + (element name { xsd:string { maxLength = "15" } } | + attribute name { xsd:string { maxLength = "15" } }) & + (element alias { xsd:string { maxLength = "15" } } | + attribute alias { xsd:string { maxLength = "15" } })? & + (element kT { xsd:double } | attribute kT { xsd:double })? & + (element fissionable { ( "true" | "false" ) } | + attribute fissionable { ( "true" | "false" ) }) & + (element representation { ( "isotropic" | "angle" ) } | + attribute representation { ( "isotropic" | "angle" ) })? & + (element num_azimuthal { xsd:positiveInteger } | + attribute num_azimuthal { xsd:positiveInteger })? & + (element num_polar { xsd:positiveInteger } | + attribute num_polar { xsd:positiveInteger })? & + (element scatt_type { ( "legendre" | "histogram" | "tabular" ) } | + attribute scatt_type { ( "legendre" | "histogram" | "tabular" ) })? & + (element order { xsd:positiveInteger } | + attribute order { xsd:positiveInteger }) & + element tabular_legendre { + (element enable { ( "true" | "false" ) } | + attribute enable { ( "true" | "false" ) })? & + (element num_points { xsd:positiveInteger } | + attribute num_points { xsd:positiveInteger })? + }? & + + (element total { list { xsd:double+ } } | + attribute total { list { xsd:double+ } })? & + + (element absorption { list { xsd:double+ } } | + attribute absorption { list { xsd:double+ } }) & + + (element scatter { list { xsd:double+ } } | + attribute scatter { list { xsd:double+ } }) & + + (element fission { list { xsd:double+ } } | + attribute fission { list { xsd:double+ } })? & + + (element fission { list { xsd:double+ } } | + attribute fission { list { xsd:double+ } })? & + + (element k_fission { list { xsd:double+ } } | + attribute k_fission { list { xsd:double+ } })? & + + (element chi { list { xsd:double+ } } | + attribute chi { list { xsd:double+ } })? & + + (element nu_fission { list { xsd:double+ } } | + attribute nu_fission { list { xsd:double+ } })? + + }* + + +} \ No newline at end of file diff --git a/src/relaxng/mg_cross_sections.rng b/src/relaxng/mg_cross_sections.rng new file mode 100644 index 000000000..b293cddbe --- /dev/null +++ b/src/relaxng/mg_cross_sections.rng @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15 + + + + + 15 + + + + + + + + 15 + + + + + 15 + + + + + + + + + + + + + + + + + + true + false + + + + + true + false + + + + + + + + isotropic + angle + + + + + isotropic + angle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + legendre + histogram + tabular + + + + + legendre + histogram + tabular + + + + + + + + + + + + + + + + + + + + true + false + + + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/relaxng/plots.rnc b/src/relaxng/plots.rnc new file mode 100644 index 000000000..e53cc15f7 --- /dev/null +++ b/src/relaxng/plots.rnc @@ -0,0 +1,41 @@ +element plots { + element plot { + (element id { xsd:int } | attribute id { xsd:int })? & + (element filename { xsd:string { maxLength = "50" } } | + attribute filename { xsd:string { maxLength = "50" } })? & + (element type { "slice" | "voxel" } | + attribute type { "slice" | "voxel" })? & + (element color_by { ( "cell" | "material" ) } | + attribute color_by { ( "cell" | "material" ) })? & + (element level { xsd:int } | attribute level { xsd:int })? & + (element origin { list { xsd:double+ } } | + attribute origin { list { xsd:double+ } })? & + (element width { list { xsd:double+ } } | + attribute width { list { xsd:double+ } })? & + (element basis { ( "xy" | "yz" | "xz" ) } | + attribute basis { ( "xy" | "yz" | "xz" ) })? & + (element pixels { list { xsd:int+ } } | + attribute pixels { list { xsd:int+ } })? & + (element background { list { xsd:int+ } } | + attribute background { list { xsd:int+ } })? & + element color { + (element id { xsd:int } | attribute id { xsd:int }) & + (element rgb { list { xsd:int+ } } | + attribute rgb { list { xsd:int+ } }) + }* & + element mask { + (element components { list { xsd:int+ } } | + attribute components { list { xsd:int+ } }) & + (element background { list { xsd:int+ } } | + attribute background { list { xsd:int+ } }) + }* & + element meshlines { + (element meshtype { ( "tally" | "entropy" | "ufs" | "cmfd" ) } | + attribute meshtype { ( "tally" | "entropy" | "ufs" | "cmfd" ) }) & + (element id { xsd:int } | attribute id { xsd:int })? & + (element linewidth { xsd:int } | attribute linewidth { xsd:int }) & + (element color { list { xsd:int+ } } | + attribute color { list { xsd:int+ } })? + }* + }* +} diff --git a/src/relaxng/plots.rng b/src/relaxng/plots.rng new file mode 100644 index 000000000..55d69008e --- /dev/null +++ b/src/relaxng/plots.rng @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + 50 + + + + + 50 + + + + + + + + + slice + voxel + + + + + slice + voxel + + + + + + + + + cell + material + + + + + cell + material + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xy + yz + xz + + + + + xy + yz + xz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tally + entropy + ufs + cmfd + + + + + tally + entropy + ufs + cmfd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/relaxng/readme.rst b/src/relaxng/readme.rst new file mode 100644 index 000000000..9660e3f8c --- /dev/null +++ b/src/relaxng/readme.rst @@ -0,0 +1,19 @@ +===================== +Editing RelaxNG files +===================== + +All direct edits to RelaxNG files should be in the .rnc files. The program +TRANG_ should be used to generate a correcsponding .rng file. For Ubuntu, you +can install with: + +.. code-block:: bash + + sudo apt-get install trang + +To convert the .rnc file to .rng, use the following syntax: + +.. code-block:: bash + + trang {filename}.rnc {filename}.rng + +.. _TRANG: http://www.thaiopensource.com/relaxng/trang.html diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc new file mode 100644 index 000000000..f9877a3f9 --- /dev/null +++ b/src/relaxng/settings.rnc @@ -0,0 +1,204 @@ +element settings { + element batches { xsd:positiveInteger }? & + + element confidence_intervals { xsd:boolean }? & + + element create_fission_neutrons { xsd:boolean }? & + + element cutoff { + (element weight { xsd:double } | attribute weight { xsd:double })? & + (element weight_avg { xsd:double } | attribute weight_avg { xsd:double })? & + (element energy_neutron { xsd:double } | attribute energy_neutron { xsd:double })? & + (element energy_photon { xsd:double } | attribute energy_photon { xsd:double })? & + (element energy_electron { xsd:double } | attribute energy_electron { xsd:double })? & + (element energy_positron { xsd:double } | attribute energy_positron { xsd:double })? + }? & + + element delayed_photon_scaling { xsd:boolean }? & + + element electron_treatment { ( "led" | "ttb" ) }? & + + element energy_grid { ( "nuclide" | "log" | "logarithm" | "logarithmic" | "material-union" | "union" ) }? & + + element energy_mode { ( "continuous-energy" | "ce" | "CE" | "multi-group" | "mg" | "MG" ) }? & + + element entropy_mesh { xsd:positiveInteger }? & + + element event_based { xsd:boolean }? & + + element generations_per_batch { xsd:positiveInteger }? & + + element inactive { xsd:nonNegativeInteger }? & + + element keff_trigger { + (element type { xsd:string } | attribute type { xsd:string }) & + (element threshold { xsd:double} | attribute threshold { xsd:double }) + }? & + + element log_grid_bins { xsd:positiveInteger }? & + + element material_cell_offsets { xsd:boolean }? & + + element max_particles_in_flight { xsd:positiveInteger }? & + + element max_order { xsd:nonNegativeInteger }? & + + element mesh { + (element id { xsd:int } | attribute id { xsd:int }) & + (element type { ( "regular" ) } | + attribute type { ( "regular" ) })? & + (element dimension { list { xsd:positiveInteger+ } } | + attribute dimension { list { xsd:positiveInteger+ } }) & + (element lower_left { list { xsd:double+ } } | + attribute lower_left { list { xsd:double+ } }) & + ( + (element upper_right { list { xsd:double+ } } | + attribute upper_right { list { xsd:double+ } }) | + (element width { list { xsd:double+ } } | + attribute width { list { xsd:double+ } }) + ) + }* & + + element no_reduce { xsd:boolean }? & + + element output { + (element summary { xsd:boolean } | attribute summary { xsd:boolean })? & + (element tallies { xsd:boolean } | attribute tallies { xsd:boolean })? & + (element path { xsd:string } | attribute path { xsd:string })? + }? & + + element particles { xsd:positiveInteger }? & + + element photon_transport { xsd:boolean }? & + + element ptables { xsd:boolean }? & + + element dagmc { xsd:boolean }? & + + element run_mode { xsd:string }? & + + element seed { xsd:positiveInteger }? & + + element source { + grammar { + start = + (element particle { xsd:string } | attribute particle { xsd:string })? & + (element strength { xsd:double } | attribute strength { xsd:double })? & + (element file { xsd:string } | attribute file { xsd:string })? & + element space { + (element type { xsd:string } | attribute type { xsd:string }) & + (element parameters { list { xsd:double+ } } | + attribute parameters { list { xsd:double+ } })? & + element x { distribution }? & + element y { distribution }? & + element z { distribution }? & + element r { distribution }? & + element theta { distribution }? & + element phi { distribution }? & + element origin { list { xsd:double, xsd:double, xsd:double } }? + }? & + element angle { + (element type { xsd:string } | attribute type { xsd:string }) & + (element reference_uvw { list { xsd:double, xsd:double, xsd:double } } | + attribute reference_uvw { list { xsd:double, xsd:double, xsd:double } })? & + element mu { distribution }? & + element phi { distribution }? + }? & + element energy { distribution }? + distribution = + (element type { xsd:string { maxLength = "16" } } | + attribute type { xsd:string { maxLength = "16" } }) & + (element interpolation { xsd:string } | + attribute interpolation { xsd:string })? & + (element parameters { list { xsd:double+ } } | + attribute parameters { list { xsd:double+ } })? + } + }* & + + element state_point { + ( + (element batches { list { xsd:positiveInteger+ } } | + attribute batches { list { xsd:positiveInteger+ } }) | + (element interval { xsd:positiveInteger } | + attribute interval { xsd:positiveInteger }) + ) + }? & + + element source_point { + ( + (element batches { list { xsd:positiveInteger+ } } | + attribute batches { list { xsd:positiveInteger+ } }) | + (element interval { xsd:positiveInteger } | + attribute interval { xsd:positiveInteger }) + )? & + (element separate { xsd:boolean } | + attribute separate { xsd:boolean })? & + (element write { xsd:boolean } | + attribute write { xsd:boolean })? & + (element overwrite_latest { xsd:boolean} | + attribute overwrite_latest {xsd:boolean})? + }? & + + element surf_source_read { + (element path { xsd:string } | attribute path { xsd:string }) + }? & + + element surf_source_write { + (element surface_ids { list { xsd:positiveInteger+ } } | + attribute surface_ids { list { xsd:positiveInteger+ } }) & + (element max_particles { xsd:positiveInteger } | + attribute max_particles { xsd:positiveInteger }) + }? & + + element survival_biasing { xsd:boolean }? & + + element temperature_default { xsd:double }? & + + element temperature_method { xsd:string }? & + + element temperature_multipole { xsd:boolean }? & + + element temperature_range { list { xsd:double, xsd:double } }? & + + element temperature_tolerance { xsd:double }? & + + element threads { xsd:positiveInteger }? & + + element trace { list { xsd:positiveInteger+ } }? & + + element track { list { xsd:positiveInteger+ } }? & + + element trigger { + (element active { xsd:boolean } | attribute active { xsd:boolean }) & + (element max_batches { xsd:positiveInteger } | attribute max_batches { xsd:positiveInteger }) & + (element batch_interval { xsd:positiveInteger } | attribute batch_interval { xsd:positiveInteger })? + }? & + + element ufs_mesh { xsd:positiveInteger }? & + + element verbosity { xsd:positiveInteger }? & + + element volume_calc { + (element domain_type { xsd:string } | + attribute domain_type { xsd:string }) & + (element domain_ids { list { xsd:integer+ } } | + attribute domain_ids { list { xsd:integer+ } }) & + (element samples { xsd:positiveInteger } | + attribute samples { xsd:positiveInteger }) & + (element lower_left { list { xsd:double+ } } | + attribute lower_left { list { xsd:double+ } }) & + (element upper_right { list { xsd:double+ } } | + attribute upper_right { list { xsd:double+ } }) + }* & + + element write_initial_source { xsd:boolean }? & + + element resonance_scattering { + (element enable { xsd:boolean } | attribute enable { xsd:boolean })? & + (element method { xsd:string } | attribute method { xsd:string })? & + (element energy_min { xsd:double } | attribute energy_min { xsd:double })? & + (element energy_max { xsd:double } | attribute energy_max { xsd:double })? & + (element nuclides { list { xsd:string+ } } | + attribute nuclides { list { xsd:string+ } })? + }? +} diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng new file mode 100644 index 000000000..07b8a6d1d --- /dev/null +++ b/src/relaxng/settings.rng @@ -0,0 +1,921 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + led + ttb + + + + + + + nuclide + log + logarithm + logarithmic + material-union + union + + + + + + + continuous-energy + ce + CE + multi-group + mg + MG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + regular + + + regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16 + + + + + 16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/relaxng/tallies.rnc b/src/relaxng/tallies.rnc new file mode 100644 index 000000000..4e46c45a1 --- /dev/null +++ b/src/relaxng/tallies.rnc @@ -0,0 +1,114 @@ +element tallies { + element mesh { + (element id { xsd:int } | attribute id { xsd:int }) & + ( + ( + (element type { ( "regular" ) } | + attribute type { ( "regular" ) }) & + (element dimension { list { xsd:positiveInteger+ } } | + attribute dimension { list { xsd:positiveInteger+ } }) & + (element lower_left { list { xsd:double+ } } | + attribute lower_left { list { xsd:double+ } }) & + ( + (element upper_right { list { xsd:double+ } } | + attribute upper_right { list { xsd:double+ } }) | + (element width { list { xsd:double+ } } | + attribute width { list { xsd:double+ } }) + ) + ) | ( + (element type { ( "rectilinear" ) } | + attribute type { ( "rectilinear" ) }) & + (element x_grid { list { xsd:double+ } } | + attribute x_grid { list { xsd:double+ } }) & + (element y_grid { list { xsd:double+ } } | + attribute y_grid { list { xsd:double+ } }) & + (element z_grid { list { xsd:double+ } } | + attribute z_grid { list { xsd:double+ } }) + ) | ( + (element type { ( "cylindrical" ) } | + attribute type { ( "cylindrical" ) }) & + (element r_grid { list { xsd:double+ } } | + attribute r_grid { list { xsd:double+ } }) & + (element phi_grid { list { xsd:double+ } } | + attribute phi_grid { list { xsd:double+ } }) & + (element z_grid { list { xsd:double+ } } | + attribute z_grid { list { xsd:double+ } }) + ) | ( + (element type { ( "spherical" ) } | + attribute type { ( "spherical" ) }) & + (element r_grid { list { xsd:double+ } } | + attribute r_grid { list { xsd:double+ } }) & + (element theta_grid { list { xsd:double+ } } | + attribute theta_grid { list { xsd:double+ } }) & + (element phi_grid { list { xsd:double+ } } | + attribute phi_grid { list { xsd:double+ } }) + ) + ) + }* & + + element derivative { + (element id { xsd:int } | attribute id { xsd:int }) & + (element material { xsd:int } | attribute material { xsd:int }) & + ( (element variable { ( "density") } + | attribute variable { ( "density" ) } ) | + ( + (element variable { ( "nuclide_density" ) } + | attribute variable { ( "nuclide_density" ) } ) + & + (element nuclide { xsd:string { maxLength = "12" } } + | attribute nuclide { xsd:string { maxLength = "12" } } ) + ) | + (element variable { ( "temperature") } + | attribute variable { ( "temperature" ) } ) + ) + }* & + + element filter { + (element id { xsd:int } | attribute id { xsd:int }) & + ( + ( (element type { ( "cell" | "cellfrom" | "cellborn" | "material" | + "universe" | "surface" | "distribcell" | "mesh" | "energy" | + "energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" | + "energyfunction" | "meshsurface" | "cellinstance") } | + attribute type { ( "cell" | "cellfrom" | "cellborn" | "material" | + "universe" | "surface" | "distribcell" | "mesh" | "energy" | + "energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" | + "energyfunction" | "meshsurface" | "cellinstance") }) & + (element bins { list { xsd:double+ } } | + attribute bins { list { xsd:double+ } }) + ) | + ( + (element type { ("energyfunction") } | + attribute type { ("energyfunction") }) & + (element energy { list { xsd:double+ } } | + attribute energy { list { xsd:double+ } }) & + (element y { list { xsd:double+ } } | + attribute y { list { xsd:double+ } }) + ) + ) + }* & + + element tally { + (element id { xsd:int } | attribute id { xsd:int }) & + (element name { xsd:string { maxLength="52" } } | + attribute name { xsd:string { maxLength="52" } })? & + (element estimator { ( "analog" | "tracklength" | "collision" ) } | + attribute estimator { ( "analog" | "tracklength" | "collision" ) })? & + (element filters { list { xsd:int+ } } | + attribute filters { list { xsd:int+ } })? & + element nuclides { + list { xsd:string { maxLength = "12" }+ } + }? & + element scores { + list { xsd:string { maxLength = "20" }+ } + } & + element trigger { + (element type { xsd:string } | attribute type { xsd:string }) & + (element threshold { xsd:double} | attribute threshold { xsd:double }) & + (element scores { list { xsd:string { maxLength = "20" }+ } } | attribute scores { list { xsd:string { maxLength = "20"}+ } } )? + }* & + (element derivative { xsd:int } | attribute derivative { xsd:int } )? + }* & + + element assume_separate { xsd:boolean }? +} diff --git a/src/relaxng/tallies.rng b/src/relaxng/tallies.rng new file mode 100644 index 000000000..350c3cb4a --- /dev/null +++ b/src/relaxng/tallies.rng @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + regular + + + regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rectilinear + + + rectilinear + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + density + + + density + + + + + + nuclide_density + + + nuclide_density + + + + + + 12 + + + + + 12 + + + + + + + temperature + + + temperature + + + + + + + + + + + + + + + + + + + + + + + cell + cellfrom + cellborn + material + universe + surface + distribcell + mesh + energy + energyout + mu + polar + azimuthal + delayedgroup + energyfunction + meshsurface + cellinstance + + + + + cell + cellfrom + cellborn + material + universe + surface + distribcell + mesh + energy + energyout + mu + polar + azimuthal + delayedgroup + energyfunction + meshsurface + cellinstance + + + + + + + + + + + + + + + + + + + + + + + + energyfunction + + + energyfunction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 52 + + + + + 52 + + + + + + + + + analog + tracklength + collision + + + + + analog + tracklength + collision + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + + + + + + + + + + 20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + + + + + + + + + 20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 9aa09956d..813f9e19b 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -4,7 +4,8 @@ #include #include -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xview.hpp" #include "openmc/constants.h" #include "openmc/error.h" @@ -18,8 +19,8 @@ namespace openmc { // ScattData base-class methods //============================================================================== -void ScattData::base_init(int order, const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_energy, +void ScattData::base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, const double_2dvec& in_mult) { size_t groups = in_energy.size(); @@ -36,12 +37,22 @@ void ScattData::base_init(int order, const tensor::Tensor& in_gmin, mult[gin] = in_mult[gin]; // Make sure the multiplicity does not have 0s + unsigned long int num_converted = 0; for (int go = 0; go < mult[gin].size(); go++) { if (mult[gin][go] == 0.) { + num_converted += 1; mult[gin][go] = 1.; } } + if (num_converted > 0) { + // Raise a warning to the user if we did have to do the conversion + std::string msg = + std::to_string(num_converted) + + " entries in the Multiplicity Matrix were changed from 0 to 1"; + warning(msg); + } + // Make sure the energy is normalized double norm = std::accumulate(energy[gin].begin(), energy[gin].end(), 0.); @@ -62,26 +73,23 @@ void ScattData::base_init(int order, const tensor::Tensor& in_gmin, void ScattData::base_combine(size_t max_order, size_t order_dim, const vector& those_scatts, const vector& scalars, - tensor::Tensor& in_gmin, tensor::Tensor& in_gmax, + xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) { size_t groups = those_scatts[0]->energy.size(); // Now allocate and zero our storage spaces - tensor::Tensor this_nuscatt_matrix = - tensor::zeros({groups, groups, order_dim}); - tensor::Tensor this_nuscatt_P0 = - tensor::zeros({groups, groups}); - tensor::Tensor this_scatt_P0 = - tensor::zeros({groups, groups}); - tensor::Tensor this_mult = tensor::ones({groups, groups}); + xt::xtensor this_nuscatt_matrix({groups, groups, order_dim}, 0.); + xt::xtensor this_nuscatt_P0({groups, groups}, 0.); + xt::xtensor this_scatt_P0({groups, groups}, 0.); + xt::xtensor this_mult({groups, groups}, 1.); // Build the dense scattering and multiplicity matrices for (int i = 0; i < those_scatts.size(); i++) { ScattData* that = those_scatts[i]; // Build the dense matrix for that object - tensor::Tensor that_matrix = that->get_matrix(max_order); + xt::xtensor that_matrix = that->get_matrix(max_order); // Now add that to this for the nu-scatter matrix this_nuscatt_matrix += scalars[i] * that_matrix; @@ -99,7 +107,7 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, // Now we have the dense nuscatt and scatt, we can easily compute the // multiplicity matrix by dividing the two and fixing any nans - this_mult = tensor::nan_to_num(this_nuscatt_P0 / this_scatt_P0); + this_mult = xt::nan_to_num(this_nuscatt_P0 / this_scatt_P0); // We have the data, now we need to convert to a jagged array and then use // the initialize function to store it on the object. @@ -108,7 +116,7 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, int gmin_; for (gmin_ = 0; gmin_ < groups; gmin_++) { bool non_zero = false; - for (int l = 0; l < this_nuscatt_matrix.shape(2); l++) { + for (int l = 0; l < this_nuscatt_matrix.shape()[2]; l++) { if (this_nuscatt_matrix(gin, gmin_, l) != 0.) { non_zero = true; break; @@ -120,7 +128,7 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { bool non_zero = false; - for (int l = 0; l < this_nuscatt_matrix.shape(2); l++) { + for (int l = 0; l < this_nuscatt_matrix.shape()[2]; l++) { if (this_nuscatt_matrix(gin, gmax_, l) != 0.) { non_zero = true; break; @@ -145,8 +153,8 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, sparse_mult[gin].resize(gmax_ - gmin_ + 1); int i_gout = 0; for (int gout = gmin_; gout <= gmax_; gout++) { - sparse_scatter[gin][i_gout].resize(this_nuscatt_matrix.shape(2)); - for (int l = 0; l < this_nuscatt_matrix.shape(2); l++) { + sparse_scatter[gin][i_gout].resize(this_nuscatt_matrix.shape()[2]); + for (int l = 0; l < this_nuscatt_matrix.shape()[2]; l++) { sparse_scatter[gin][i_gout][l] = this_nuscatt_matrix(gin, gout, l); } sparse_mult[gin][i_gout] = this_mult(gin, gout); @@ -229,8 +237,8 @@ double ScattData::get_xs( // ScattDataLegendre methods //============================================================================== -void ScattDataLegendre::init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, +void ScattDataLegendre::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { size_t groups = coeffs.size(); @@ -241,7 +249,7 @@ void ScattDataLegendre::init(const tensor::Tensor& in_gmin, // Get the scattering cross section value by summing the un-normalized P0 // coefficient in the variable matrix over all outgoing groups. - scattxs = tensor::zeros({groups}); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { int num_groups = in_gmax[gin] - in_gmin[gin] + 1; for (int i_gout = 0; i_gout < num_groups; i_gout++) { @@ -388,8 +396,8 @@ void ScattDataLegendre::combine( size_t groups = those_scatts[0]->energy.size(); - tensor::Tensor in_gmin({groups}, 0); - tensor::Tensor in_gmax({groups}, 0); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -406,13 +414,12 @@ void ScattDataLegendre::combine( //============================================================================== -tensor::Tensor ScattDataLegendre::get_matrix(size_t max_order) +xt::xtensor ScattDataLegendre::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 size_t groups = energy.size(); size_t order_dim = max_order + 1; - tensor::Tensor matrix = - tensor::zeros({groups, groups, order_dim}); + xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { @@ -430,8 +437,8 @@ tensor::Tensor ScattDataLegendre::get_matrix(size_t max_order) // ScattDataHistogram methods //============================================================================== -void ScattDataHistogram::init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, +void ScattDataHistogram::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { size_t groups = coeffs.size(); @@ -442,7 +449,7 @@ void ScattDataHistogram::init(const tensor::Tensor& in_gmin, // Get the scattering cross section value by summing the distribution // over all the histogram bins in angle and outgoing energy groups - scattxs = tensor::zeros({groups}); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { scattxs[gin] += std::accumulate( @@ -471,7 +478,7 @@ void ScattDataHistogram::init(const tensor::Tensor& in_gmin, ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Build the angular distribution mu values - mu = tensor::linspace(-1., 1., order + 1); + mu = xt::linspace(-1., 1., order + 1); dmu = 2. / order; // Calculate f(mu) and integrate it so we can avoid rejection sampling @@ -516,7 +523,7 @@ double ScattDataHistogram::calc_f(int gin, int gout, double mu) int imu; if (mu == 1.) { // use size -2 to have the index one before the end - imu = this->mu.shape(0) - 2; + imu = this->mu.shape()[0] - 2; } else { imu = std::floor((mu + 1.) / dmu + 1.) - 1; } @@ -562,13 +569,13 @@ void ScattDataHistogram::sample( //============================================================================== -tensor::Tensor ScattDataHistogram::get_matrix(size_t max_order) +xt::xtensor ScattDataHistogram::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 size_t groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations size_t order_dim = get_order(); - tensor::Tensor matrix({groups, groups, order_dim}, 0); + xt::xtensor matrix({groups, groups, order_dim}, 0); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { @@ -603,8 +610,8 @@ void ScattDataHistogram::combine( size_t groups = those_scatts[0]->energy.size(); - tensor::Tensor in_gmin({groups}, 0); - tensor::Tensor in_gmax({groups}, 0); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -623,8 +630,8 @@ void ScattDataHistogram::combine( // ScattDataTabular methods //============================================================================== -void ScattDataTabular::init(const tensor::Tensor& in_gmin, - const tensor::Tensor& in_gmax, const double_2dvec& in_mult, +void ScattDataTabular::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { size_t groups = coeffs.size(); @@ -634,12 +641,12 @@ void ScattDataTabular::init(const tensor::Tensor& in_gmin, double_3dvec matrix = coeffs; // Build the angular distribution mu values - mu = tensor::linspace(-1., 1., order); + mu = xt::linspace(-1., 1., order); dmu = 2. / (order - 1); // Get the scattering cross section value by integrating the distribution // over all mu points and then combining over all outgoing groups - scattxs = tensor::zeros({groups}); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { for (int imu = 1; imu < order; imu++) { @@ -716,7 +723,7 @@ double ScattDataTabular::calc_f(int gin, int gout, double mu) int imu; if (mu == 1.) { // use size -2 to have the index one before the end - imu = this->mu.shape(0) - 2; + imu = this->mu.shape()[0] - 2; } else { imu = std::floor((mu + 1.) / dmu + 1.) - 1; } @@ -737,7 +744,7 @@ void ScattDataTabular::sample( sample_energy(gin, gout, i_gout, seed); // Determine the outgoing cosine bin - int NP = this->mu.shape(0); + int NP = this->mu.shape()[0]; double xi = prn(seed); double c_k = dist[gin][i_gout][0]; @@ -779,14 +786,13 @@ void ScattDataTabular::sample( //============================================================================== -tensor::Tensor ScattDataTabular::get_matrix(size_t max_order) +xt::xtensor ScattDataTabular::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 size_t groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations size_t order_dim = get_order(); - tensor::Tensor matrix = - tensor::zeros({groups, groups, order_dim}); + xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { @@ -820,8 +826,8 @@ void ScattDataTabular::combine( size_t groups = those_scatts[0]->energy.size(); - tensor::Tensor in_gmin({groups}, 0); - tensor::Tensor in_gmax({groups}, 0); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -858,7 +864,7 @@ void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab) tab.scattxs = leg.scattxs; // Build mu and dmu - tab.mu = tensor::linspace(-1., 1., n_mu); + tab.mu = xt::linspace(-1., 1., n_mu); tab.dmu = 2. / (n_mu - 1); // Calculate f(mu) and integrate it so we can avoid rejection sampling diff --git a/src/secondary_correlated.cpp b/src/secondary_correlated.cpp index 32701791a..0e4891dd3 100644 --- a/src/secondary_correlated.cpp +++ b/src/secondary_correlated.cpp @@ -5,11 +5,11 @@ #include // for size_t #include // for back_inserter -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" +#include "xtensor/xview.hpp" #include "openmc/endf.h" #include "openmc/hdf5_interface.h" -#include "openmc/math_functions.h" #include "openmc/random_lcg.h" #include "openmc/search.h" @@ -25,11 +25,11 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) hid_t dset = open_dataset(group, "energy"); // Get interpolation parameters - tensor::Tensor temp; + xt::xarray temp; read_attribute(dset, "interpolation", temp); - tensor::View temp_b = temp.slice(0); // breakpoints - tensor::View temp_i = temp.slice(1); // interpolation parameters + auto temp_b = xt::view(temp, 0); // view of breakpoints + auto temp_i = xt::view(temp, 1); // view of interpolation parameters std::copy(temp_b.begin(), temp_b.end(), std::back_inserter(breakpoints_)); for (const auto i : temp_i) @@ -50,12 +50,12 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) read_attribute(dset, "interpolation", interp); read_attribute(dset, "n_discrete_lines", n_discrete); - tensor::Tensor eout; + xt::xarray eout; read_dataset(dset, eout); close_dataset(dset); // Read angle distributions - tensor::Tensor mu; + xt::xarray mu; read_dataset(group, "mu", mu); for (int i = 0; i < n_energy; ++i) { @@ -65,7 +65,7 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) if (i < n_energy - 1) { n = offsets[i + 1] - j; } else { - n = eout.shape(1) - j; + n = eout.shape()[1] - j; } // Assign interpolation scheme and number of discrete lines @@ -74,9 +74,9 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) d.n_discrete = n_discrete[i]; // Copy data - d.e_out = eout.slice(0, tensor::range(j, j + n)); - d.p = eout.slice(1, tensor::range(j, j + n)); - d.c = eout.slice(2, tensor::range(j, j + n)); + d.e_out = xt::view(eout, 0, xt::range(j, j + n)); + d.p = xt::view(eout, 1, xt::range(j, j + n)); + d.c = xt::view(eout, 2, xt::range(j, j + n)); // To get answers that match ACE data, for now we still use the tabulated // CDF values that were passed through to the HDF5 library. At a later @@ -118,10 +118,10 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) // Determine offset and size of distribution int offset_mu = std::lround(eout(4, offsets[i] + j)); int m; - if (offsets[i] + j + 1 < eout.shape(1)) { + if (offsets[i] + j + 1 < eout.shape()[1]) { m = std::lround(eout(4, offsets[i] + j + 1)) - offset_mu; } else { - m = mu.shape(1) - offset_mu; + m = mu.shape()[1] - offset_mu; } // For incoherent inelastic thermal scattering, the angle distributions @@ -132,12 +132,9 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) interp_mu = 1; auto interp = int2interp(interp_mu); - tensor::View xs = - mu.slice(0, tensor::range(offset_mu, offset_mu + m)); - tensor::View ps = - mu.slice(1, tensor::range(offset_mu, offset_mu + m)); - tensor::View cs = - mu.slice(2, tensor::range(offset_mu, offset_mu + m)); + auto xs = xt::view(mu, 0, xt::range(offset_mu, offset_mu + m)); + auto ps = xt::view(mu, 1, xt::range(offset_mu, offset_mu + m)); + auto cs = xt::view(mu, 2, xt::range(offset_mu, offset_mu + m)); vector x {xs.begin(), xs.end()}; vector p {ps.begin(), ps.end()}; @@ -155,13 +152,25 @@ CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group) distribution_.push_back(std::move(d)); } // incoming energies } -Distribution& CorrelatedAngleEnergy::sample_dist( - double E_in, double& E_out, uint64_t* seed) const + +void CorrelatedAngleEnergy::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { - // Find energy bin and calculate interpolation factor + // Find energy bin and calculate interpolation factor -- if the energy is + // outside the range of the tabulated energies, choose the first or last bins + auto n_energy_in = energy_.size(); int i; double r; - get_energy_index(energy_, E_in, i, r); + if (E_in < energy_[0]) { + i = 0; + r = 0.0; + } else if (E_in > energy_[n_energy_in - 1]) { + i = n_energy_in - 2; + r = 1.0; + } else { + i = lower_bound_index(energy_.begin(), energy_.end(), E_in); + r = (E_in - energy_[i]) / (energy_[i + 1] - energy_[i]); + } // Sample between the ith and [i+1]th bin int l = r > prn(seed) ? i + 1 : i; @@ -248,22 +257,10 @@ Distribution& CorrelatedAngleEnergy::sample_dist( // Find correlated angular distribution for closest outgoing energy bin if (r1 - c_k < c_k1 - r1 || distribution_[l].interpolation == Interpolation::histogram) { - return *distribution_[l].angle[k]; + mu = distribution_[l].angle[k]->sample(seed); } else { - return *distribution_[l].angle[k + 1]; + mu = distribution_[l].angle[k + 1]->sample(seed); } } -void CorrelatedAngleEnergy::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - mu = sample_dist(E_in, E_out, seed).sample(seed).first; -} - -double CorrelatedAngleEnergy::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - return sample_dist(E_in, E_out, seed).evaluate(mu); -} - } // namespace openmc diff --git a/src/secondary_kalbach.cpp b/src/secondary_kalbach.cpp index 018ce1c8a..4a7878343 100644 --- a/src/secondary_kalbach.cpp +++ b/src/secondary_kalbach.cpp @@ -5,10 +5,10 @@ #include // for size_t #include // for back_inserter -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" +#include "xtensor/xview.hpp" #include "openmc/hdf5_interface.h" -#include "openmc/math_functions.h" #include "openmc/random_dist.h" #include "openmc/random_lcg.h" #include "openmc/search.h" @@ -26,11 +26,11 @@ KalbachMann::KalbachMann(hid_t group) hid_t dset = open_dataset(group, "energy"); // Get interpolation parameters - tensor::Tensor temp; + xt::xarray temp; read_attribute(dset, "interpolation", temp); - tensor::View temp_b = temp.slice(0); // breakpoints - tensor::View temp_i = temp.slice(1); // interpolation parameters + auto temp_b = xt::view(temp, 0); // view of breakpoints + auto temp_i = xt::view(temp, 1); // view of interpolation parameters std::copy(temp_b.begin(), temp_b.end(), std::back_inserter(breakpoints_)); for (const auto i : temp_i) @@ -51,7 +51,7 @@ KalbachMann::KalbachMann(hid_t group) read_attribute(dset, "interpolation", interp); read_attribute(dset, "n_discrete_lines", n_discrete); - tensor::Tensor eout; + xt::xarray eout; read_dataset(dset, eout); close_dataset(dset); @@ -62,7 +62,7 @@ KalbachMann::KalbachMann(hid_t group) if (i < n_energy - 1) { n = offsets[i + 1] - j; } else { - n = eout.shape(1) - j; + n = eout.shape()[1] - j; } // Assign interpolation scheme and number of discrete lines @@ -71,11 +71,11 @@ KalbachMann::KalbachMann(hid_t group) d.n_discrete = n_discrete[i]; // Copy data - d.e_out = eout.slice(0, tensor::range(j, j + n)); - d.p = eout.slice(1, tensor::range(j, j + n)); - d.c = eout.slice(2, tensor::range(j, j + n)); - d.r = eout.slice(3, tensor::range(j, j + n)); - d.a = eout.slice(4, tensor::range(j, j + n)); + d.e_out = xt::view(eout, 0, xt::range(j, j + n)); + d.p = xt::view(eout, 1, xt::range(j, j + n)); + d.c = xt::view(eout, 2, xt::range(j, j + n)); + d.r = xt::view(eout, 3, xt::range(j, j + n)); + d.a = xt::view(eout, 4, xt::range(j, j + n)); // To get answers that match ACE data, for now we still use the tabulated // CDF values that were passed through to the HDF5 library. At a later @@ -114,13 +114,24 @@ KalbachMann::KalbachMann(hid_t group) } // incoming energies } -void KalbachMann::sample_params( - double E_in, double& E_out, double& km_a, double& km_r, uint64_t* seed) const +void KalbachMann::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { - // Find energy bin and calculate interpolation factor + // Find energy bin and calculate interpolation factor -- if the energy is + // outside the range of the tabulated energies, choose the first or last bins + auto n_energy_in = energy_.size(); int i; double r; - get_energy_index(energy_, E_in, i, r); + if (E_in < energy_[0]) { + i = 0; + r = 0.0; + } else if (E_in > energy_[n_energy_in - 1]) { + i = n_energy_in - 2; + r = 1.0; + } else { + i = lower_bound_index(energy_.begin(), energy_.end(), E_in); + r = (E_in - energy_[i]) / (energy_[i + 1] - energy_[i]); + } // Sample between the ith and [i+1]th bin int l = r > prn(seed) ? i + 1 : i; @@ -170,6 +181,7 @@ void KalbachMann::sample_params( double E_l_k = distribution_[l].e_out[k]; double p_l_k = distribution_[l].p[k]; + double km_r, km_a; if (distribution_[l].interpolation == Interpolation::histogram) { // Histogram interpolation if (p_l_k > 0.0 && k >= n_discrete) { @@ -215,13 +227,6 @@ void KalbachMann::sample_params( E_out = E_1 + (E_out - E_i1_1) * (E_K - E_1) / (E_i1_K - E_i1_1); } } -} - -void KalbachMann::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - double km_r, km_a; - sample_params(E_in, E_out, km_a, km_r, seed); // Sampled correlated angle from Kalbach-Mann parameters if (prn(seed) > km_r) { @@ -232,15 +237,5 @@ void KalbachMann::sample( mu = std::log(r1 * std::exp(km_a) + (1.0 - r1) * std::exp(-km_a)) / km_a; } } -double KalbachMann::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - double km_r, km_a; - sample_params(E_in, E_out, km_a, km_r, seed); - - // https://docs.openmc.org/en/latest/methods/neutron_physics.html#equation-KM-pdf-angle - return km_a / (2 * std::sinh(km_a)) * - (std::cosh(km_a * mu) + km_r * std::sinh(km_a * mu)); -} } // namespace openmc diff --git a/src/secondary_nbody.cpp b/src/secondary_nbody.cpp index 72f0b0b92..da0bb81c4 100644 --- a/src/secondary_nbody.cpp +++ b/src/secondary_nbody.cpp @@ -22,8 +22,13 @@ NBodyPhaseSpace::NBodyPhaseSpace(hid_t group) read_attribute(group, "q_value", Q_); } -double NBodyPhaseSpace::sample_energy(double E_in, uint64_t* seed) const +void NBodyPhaseSpace::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { + // By definition, the distribution of the angle is isotropic for an N-body + // phase space distribution + mu = uniform_distribution(-1., 1., seed); + // Determine E_max parameter double Ap = mass_ratio_; double E_max = (Ap - 1.0) / Ap * (A_ / (A_ + 1.0) * E_in + Q_); @@ -54,29 +59,12 @@ double NBodyPhaseSpace::sample_energy(double E_in, uint64_t* seed) const std::log(r5) * std::pow(std::cos(PI / 2.0 * r6), 2); break; default: - fatal_error("N-body phase space with >5 bodies."); + throw std::runtime_error {"N-body phase space with >5 bodies."}; } // Now determine v and E_out double v = x / (x + y); - return E_max * v; -} - -void NBodyPhaseSpace::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - // By definition, the distribution of the angle is isotropic for an N-body - // phase space distribution - mu = uniform_distribution(-1., 1., seed); - - E_out = sample_energy(E_in, seed); -} - -double NBodyPhaseSpace::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - E_out = sample_energy(E_in, seed); - return 0.5; + E_out = E_max * v; } } // namespace openmc diff --git a/src/secondary_thermal.cpp b/src/secondary_thermal.cpp index b0f601809..0b8e1ab42 100644 --- a/src/secondary_thermal.cpp +++ b/src/secondary_thermal.cpp @@ -1,43 +1,46 @@ #include "openmc/secondary_thermal.h" #include "openmc/hdf5_interface.h" -#include "openmc/math_functions.h" #include "openmc/random_lcg.h" #include "openmc/search.h" -#include "openmc/vector.h" -#include "openmc/tensor.h" +#include + +#include "xtensor/xview.hpp" -#include #include // for log, exp namespace openmc { +// Helper function to get index on incident energy grid +void get_energy_index( + const vector& energies, double E, int& i, double& f) +{ + // Get index and interpolation factor for elastic grid + i = 0; + f = 0.0; + if (E >= energies.front()) { + i = lower_bound_index(energies.begin(), energies.end(), E); + if (i + 1 < energies.size()) + f = (E - energies[i]) / (energies[i + 1] - energies[i]); + } +} + //============================================================================== // CoherentElasticAE implementation //============================================================================== -CoherentElasticAE::CoherentElasticAE(const CoherentElasticXS& xs) : xs_ {xs} -{ - const auto& bragg = xs_.bragg_edges(); - auto n = bragg.size(); - bragg_edges_ = tensor::Tensor(bragg.data(), n); - - const auto& factors = xs_.factors(); - factors_diff_ = tensor::zeros({n}); - factors_diff_.slice(0) = factors[0]; - for (int i = 1; i < n; ++i) { - factors_diff_.slice(i) = factors[i] - factors[i - 1]; - } -} +CoherentElasticAE::CoherentElasticAE(const CoherentElasticXS& xs) : xs_ {xs} {} void CoherentElasticAE::sample( double E_in, double& E_out, double& mu, uint64_t* seed) const { // Energy doesn't change in elastic scattering (ENDF-102, Eq. 7-1) E_out = E_in; + const auto& energies {xs_.bragg_edges()}; - assert(E_in >= energies.front()); + + Expects(E_in >= energies.front()); const int i = lower_bound_index(energies.begin(), energies.end(), E_in); @@ -53,25 +56,6 @@ void CoherentElasticAE::sample( mu = 1.0 - 2.0 * energies[k] / E_in; } -double CoherentElasticAE::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - // Energy doesn't change in elastic scattering (ENDF-102, Eq. 7-1) - E_out = E_in; - const auto& factors = xs_.factors(); - - if (E_in < bragg_edges_.front()) - return 0.0; - - const int i = - lower_bound_index(bragg_edges_.begin(), bragg_edges_.end(), E_in); - double E = 0.5 * (1 - mu) * E_in; - double C = 0.5 * E_in / factors[i]; - - return C * get_pdf_discrete(bragg_edges_.slice(tensor::range(i + 1)), - factors_diff_.slice(tensor::range(i + 1)), E, 0.0, E_in); -} - //============================================================================== // IncoherentElasticAE implementation //============================================================================== @@ -84,21 +68,12 @@ IncoherentElasticAE::IncoherentElasticAE(hid_t group) void IncoherentElasticAE::sample( double E_in, double& E_out, double& mu, uint64_t* seed) const { - E_out = E_in; - // Sample angle by inverting the distribution in ENDF-102, Eq. 7.4 double c = 2 * E_in * debye_waller_; mu = std::log(1.0 + prn(seed) * (std::exp(2.0 * c) - 1)) / c - 1.0; -} -double IncoherentElasticAE::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - E_out = E_in; - // Sample angle by inverting the distribution in ENDF-102, Eq. 7.4 - double c = 2 * E_in * debye_waller_; - double A = c / (1 - std::exp(-2.0 * c)); // normalization factor - return A * std::exp(-c * (1 - mu)); + // Energy doesn't change in elastic scattering (ENDF-102, Eq. 7.4) + E_out = E_in; } //============================================================================== @@ -124,7 +99,7 @@ void IncoherentElasticAEDiscrete::sample( // incoming energies. // Sample outgoing cosine bin - int n_mu = mu_out_.shape(1); + int n_mu = mu_out_.shape()[1]; int k = prn(seed) * n_mu; // Rather than use the sampled discrete mu directly, it is smeared over @@ -155,20 +130,6 @@ void IncoherentElasticAEDiscrete::sample( E_out = E_in; } -double IncoherentElasticAEDiscrete::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - // Get index and interpolation factor for elastic grid - int i; - double f; - get_energy_index(energy_, E_in, i, f); - // Energy doesn't change in elastic scattering - E_out = E_in; - - return get_pdf_discrete_interpolated( - mu_out_.slice(i, tensor::all), mu_out_.slice(i + 1, tensor::all), f, mu); -} - //============================================================================== // IncoherentInelasticAEDiscrete implementation //============================================================================== @@ -182,8 +143,8 @@ IncoherentInelasticAEDiscrete::IncoherentInelasticAEDiscrete( read_dataset(group, "skewed", skewed_); } -void IncoherentInelasticAEDiscrete::sample_params( - double E_in, double& E_out, int& j, uint64_t* seed) const +void IncoherentInelasticAEDiscrete::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Get index and interpolation factor for inelastic grid int i; @@ -197,7 +158,8 @@ void IncoherentInelasticAEDiscrete::sample_params( // for the second and second to last bins, relative to a normal bin // probability of 1). Otherwise, each bin is equally probable. - int n = energy_out_.shape(1); + int j; + int n = energy_out_.shape()[1]; if (!skewed_) { // All bins equally likely j = prn(seed) * n; @@ -228,21 +190,9 @@ void IncoherentInelasticAEDiscrete::sample_params( // Outgoing energy E_out = (1 - f) * E_ij + f * E_i1j; -} - -void IncoherentInelasticAEDiscrete::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - // Get index and interpolation factor for inelastic grid - int i; - double f; - get_energy_index(energy_, E_in, i, f); - - int j; - sample_params(E_in, E_out, j, seed); // Sample outgoing cosine bin - int m = mu_out_.shape(2); + int m = mu_out_.shape()[2]; int k = prn(seed) * m; // Determine outgoing cosine corresponding to E_in[i] and E_in[i+1] @@ -253,20 +203,6 @@ void IncoherentInelasticAEDiscrete::sample( mu = (1 - f) * mu_ijk + f * mu_i1jk; } -double IncoherentInelasticAEDiscrete::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - // Get index and interpolation factor for inelastic grid - int i; - double f; - get_energy_index(energy_, E_in, i, f); - int j; - sample_params(E_in, E_out, j, seed); - - return get_pdf_discrete_interpolated(mu_out_.slice(i, j, tensor::all), - mu_out_.slice(i + 1, j, tensor::all), f, mu); -} - //============================================================================== // IncoherentInelasticAE implementation //============================================================================== @@ -296,11 +232,11 @@ IncoherentInelasticAE::IncoherentInelasticAE(hid_t group) // On first pass, allocate space for angles if (j == 0) { auto n_mu = adist->x().size(); - d.mu = tensor::Tensor({d.n_e_out, n_mu}); + d.mu = xt::empty({d.n_e_out, n_mu}); } // Copy outgoing angles - tensor::View mu_j = d.mu.slice(j); + auto mu_j = xt::view(d.mu, j); std::copy(adist->x().begin(), adist->x().end(), mu_j.begin()); } } @@ -309,23 +245,24 @@ IncoherentInelasticAE::IncoherentInelasticAE(hid_t group) } } -void IncoherentInelasticAE::sample_params( - double E_in, double& E_out, double& f, int& l, int& j, uint64_t* seed) const +void IncoherentInelasticAE::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Get index and interpolation factor for inelastic grid int i; - double f0; - get_energy_index(energy_, E_in, i, f0); + double f; + get_energy_index(energy_, E_in, i, f); // Pick closer energy based on interpolation factor - l = f0 > 0.5 ? i + 1 : i; + int l = f > 0.5 ? i + 1 : i; // Determine outgoing energy bin // (First reset n_energy_out to the right value) - int n = distribution_[l].n_e_out; + auto n = distribution_[l].n_e_out; double r1 = prn(seed); double c_j = distribution_[l].e_out_cdf[0]; double c_j1; + std::size_t j; for (j = 0; j < n - 1; ++j) { c_j1 = distribution_[l].e_out_cdf[j + 1]; if (r1 < c_j1) @@ -363,23 +300,15 @@ void IncoherentInelasticAE::sample_params( E_out += E_in - E_l; } - f = (r1 - c_j) / (c_j1 - c_j); -} -void IncoherentInelasticAE::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - double f; - int l, j; - sample_params(E_in, E_out, f, l, j, seed); - // Sample outgoing cosine bin - int n_mu = distribution_[l].mu.shape(1); + int n_mu = distribution_[l].mu.shape()[1]; std::size_t k = prn(seed) * n_mu; // Rather than use the sampled discrete mu directly, it is smeared over // a bin of width 0.5*min(mu[k] - mu[k-1], mu[k+1] - mu[k]) centered on the // discrete mu value itself. const auto& mu_l = distribution_[l].mu; + f = (r1 - c_j) / (c_j1 - c_j); // Interpolate kth mu value between distributions at energies j and j+1 mu = mu_l(j, k) + f * (mu_l(j + 1, k) - mu_l(j, k)); @@ -403,19 +332,6 @@ void IncoherentInelasticAE::sample( mu += std::min(mu - mu_left, mu_right - mu) * (prn(seed) - 0.5); } -double IncoherentInelasticAE::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - double f; - int l, j; - sample_params(E_in, E_out, f, l, j, seed); - - const auto& mu_l = distribution_[l].mu; - - return get_pdf_discrete_interpolated( - mu_l.slice(j, tensor::all), mu_l.slice(j + 1, tensor::all), f, mu); -} - //============================================================================== // MixedElasticAE implementation //============================================================================== @@ -438,30 +354,18 @@ MixedElasticAE::MixedElasticAE( close_group(incoherent_group); } -const AngleEnergy& MixedElasticAE::sample_dist( - double E_in, uint64_t* seed) const +void MixedElasticAE::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Evaluate coherent and incoherent elastic cross sections double xs_coh = coherent_xs_(E_in); double xs_incoh = incoherent_xs_(E_in); if (prn(seed) * (xs_coh + xs_incoh) < xs_coh) { - return coherent_dist_; + coherent_dist_.sample(E_in, E_out, mu, seed); } else { - return *incoherent_dist_; + incoherent_dist_->sample(E_in, E_out, mu, seed); } } -void MixedElasticAE::sample( - double E_in, double& E_out, double& mu, uint64_t* seed) const -{ - sample_dist(E_in, seed).sample(E_in, E_out, mu, seed); -} - -double MixedElasticAE::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - return sample_dist(E_in, seed).sample_energy_and_pdf(E_in, mu, E_out, seed); -} - } // namespace openmc diff --git a/src/secondary_uncorrelated.cpp b/src/secondary_uncorrelated.cpp index ec2af7102..5cbb76fb9 100644 --- a/src/secondary_uncorrelated.cpp +++ b/src/secondary_uncorrelated.cpp @@ -65,22 +65,4 @@ void UncorrelatedAngleEnergy::sample( E_out = energy_->sample(E_in, seed); } -double UncorrelatedAngleEnergy::sample_energy_and_pdf( - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - // Sample outgoing energy - if (energy_ != nullptr) { - E_out = energy_->sample(E_in, seed); - } else { - E_out = E_in; - } - - if (!angle_.empty()) { - return angle_.evaluate(E_in, mu); - } else { - // no angle distribution given => assume isotropic for all energies - return 0.5; - } -} - } // namespace openmc diff --git a/src/settings.cpp b/src/settings.cpp index 15a7b9c27..eb0d4936c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,5 +1,4 @@ #include "openmc/settings.h" -#include "openmc/random_ray/flat_source_domain.h" #include // for ceil, pow #include // for numeric_limits @@ -11,7 +10,6 @@ #endif #include "openmc/capi.h" -#include "openmc/collision_track.h" #include "openmc/constants.h" #include "openmc/container_util.h" #include "openmc/distribution.h" @@ -20,14 +18,10 @@ #include "openmc/eigenvalue.h" #include "openmc/error.h" #include "openmc/file_utils.h" -#include "openmc/mcpl_interface.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" #include "openmc/output.h" -#include "openmc/plot.h" #include "openmc/random_lcg.h" -#include "openmc/random_ray/random_ray.h" -#include "openmc/reaction.h" #include "openmc/simulation.h" #include "openmc/source.h" #include "openmc/string_utils.h" @@ -47,22 +41,18 @@ namespace settings { // Default values for boolean flags bool assume_separate {false}; bool check_overlaps {false}; -bool collision_track {false}; bool cmfd_run {false}; bool confidence_intervals {false}; -bool create_delayed_neutrons {true}; bool create_fission_neutrons {true}; bool delayed_photon_scaling {true}; bool entropy_on {false}; bool event_based {false}; -bool ifp_on {false}; bool legendre_to_tabular {true}; bool material_cell_offsets {true}; bool output_summary {true}; bool output_tallies {true}; bool particle_restart_run {false}; bool photon_transport {false}; -bool atomic_relaxation {true}; bool reduce_tallies {true}; bool res_scat_on {false}; bool restart_run {false}; @@ -70,23 +60,15 @@ bool run_CE {true}; bool source_latest {false}; bool source_separate {false}; bool source_write {true}; -bool source_mcpl_write {false}; bool surf_source_write {false}; -bool surf_mcpl_write {false}; bool surf_source_read {false}; bool survival_biasing {false}; -bool survival_normalization {false}; bool temperature_multipole {false}; bool trigger_on {false}; bool trigger_predict {false}; -bool uniform_source_sampling {false}; bool ufs_on {false}; bool urr_ptables_on {true}; -bool use_decay_photons {false}; -bool use_shared_secondary_bank {false}; bool weight_windows_on {false}; -bool weight_window_checkpoint_surface {false}; -bool weight_window_checkpoint_collision {true}; bool write_all_tracks {false}; bool write_initial_source {false}; @@ -96,51 +78,33 @@ std::string path_output; std::string path_particle_restart; std::string path_sourcepoint; std::string path_statepoint; -const char* path_statepoint_c {path_statepoint.c_str()}; -std::string weight_windows_file; -std::string properties_file; int32_t n_inactive {0}; int32_t max_lost_particles {10}; double rel_max_lost_particles {1.0e-6}; -int32_t max_write_lost_particles {-1}; int32_t gen_per_batch {1}; int64_t n_particles {-1}; int64_t max_particles_in_flight {100000}; -int max_particle_events {1000000}; ElectronTreatment electron_treatment {ElectronTreatment::TTB}; array energy_cutoff {0.0, 1000.0, 0.0, 0.0}; -array time_cutoff {INFTY, INFTY, INFTY, INFTY}; -int ifp_n_generation {-1}; -IFPParameter ifp_parameter {IFPParameter::None}; int legendre_to_tabular_points {C_NONE}; int max_order {0}; int n_log_bins {8000}; int n_batches; int n_max_batches; -int max_secondaries {10000}; -int max_history_splits {10'000'000}; +int max_splits {1000}; int max_tracks {1000}; ResScatMethod res_scat_method {ResScatMethod::rvs}; double res_scat_energy_min {0.01}; double res_scat_energy_max {1000.0}; vector res_scat_nuclides; RunMode run_mode {RunMode::UNSET}; -SolverType solver_type {SolverType::MONTE_CARLO}; std::unordered_set sourcepoint_batch; std::unordered_set statepoint_batch; -double source_rejection_fraction {0.05}; -double free_gas_threshold {400.0}; std::unordered_set source_write_surf_id; -CollisionTrackConfig collision_track_config {}; -int64_t ssw_max_particles; -int64_t ssw_max_files; -int64_t ssw_cell_id {C_NONE}; -SSWCellType ssw_cell_type {SSWCellType::None}; -double surface_grazing_cutoff {0.001}; -double surface_grazing_ratio {0.5}; +int64_t max_surface_particles; TemperatureMethod temperature_method {TemperatureMethod::NEAREST}; double temperature_tolerance {10.0}; double temperature_default {293.6}; @@ -150,7 +114,7 @@ int trace_gen; int64_t trace_particle; vector> track_identifiers; int trigger_batch_interval {1}; -int verbosity {-1}; +int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; @@ -181,12 +145,6 @@ void get_run_parameters(pugi::xml_node node_base) std::stoll(get_node_value(node_base, "max_particles_in_flight")); } - // Get maximum number of events allowed per particle - if (check_for_node(node_base, "max_particle_events")) { - max_particle_events = - std::stoll(get_node_value(node_base, "max_particle_events")); - } - // Get number of basic batches if (check_for_node(node_base, "batches")) { n_batches = std::stoi(get_node_value(node_base, "batches")); @@ -206,15 +164,8 @@ void get_run_parameters(pugi::xml_node node_base) std::stod(get_node_value(node_base, "rel_max_lost_particles")); } - // Get relative number of lost particles - if (check_for_node(node_base, "max_write_lost_particles")) { - max_write_lost_particles = - std::stoi(get_node_value(node_base, "max_write_lost_particles")); - } - // Get number of inactive batches - if (run_mode == RunMode::EIGENVALUE || - solver_type == SolverType::RANDOM_RAY) { + if (run_mode == RunMode::EIGENVALUE) { if (check_for_node(node_base, "inactive")) { n_inactive = std::stoi(get_node_value(node_base, "inactive")); } @@ -258,142 +209,26 @@ void get_run_parameters(pugi::xml_node node_base) } } } - - // Random ray variables - if (solver_type == SolverType::RANDOM_RAY) { - xml_node random_ray_node = node_base.child("random_ray"); - if (check_for_node(random_ray_node, "distance_active")) { - RandomRay::distance_active_ = - std::stod(get_node_value(random_ray_node, "distance_active")); - if (RandomRay::distance_active_ <= 0.0) { - fatal_error("Random ray active distance must be greater than 0"); - } - } else { - fatal_error("Specify random ray active distance in settings XML"); - } - if (check_for_node(random_ray_node, "distance_inactive")) { - RandomRay::distance_inactive_ = - std::stod(get_node_value(random_ray_node, "distance_inactive")); - if (RandomRay::distance_inactive_ < 0) { - fatal_error( - "Random ray inactive distance must be greater than or equal to 0"); - } - } else { - fatal_error("Specify random ray inactive distance in settings XML"); - } - if (check_for_node(random_ray_node, "ray_source")) { - xml_node ray_source_node = random_ray_node.child("ray_source"); - xml_node source_node = ray_source_node.child("source"); - // Get point to list of elements and make sure there is at least - // one - RandomRay::ray_source_ = Source::create(source_node); - } else { - fatal_error("Specify random ray source in settings XML"); - } - if (check_for_node(random_ray_node, "volume_estimator")) { - std::string temp_str = - get_node_value(random_ray_node, "volume_estimator", true, true); - if (temp_str == "simulation_averaged") { - FlatSourceDomain::volume_estimator_ = - RandomRayVolumeEstimator::SIMULATION_AVERAGED; - } else if (temp_str == "naive") { - FlatSourceDomain::volume_estimator_ = RandomRayVolumeEstimator::NAIVE; - } else if (temp_str == "hybrid") { - FlatSourceDomain::volume_estimator_ = RandomRayVolumeEstimator::HYBRID; - } else { - fatal_error("Unrecognized volume estimator: " + temp_str); - } - } - if (check_for_node(random_ray_node, "source_shape")) { - std::string temp_str = - get_node_value(random_ray_node, "source_shape", true, true); - if (temp_str == "flat") { - RandomRay::source_shape_ = RandomRaySourceShape::FLAT; - } else if (temp_str == "linear") { - RandomRay::source_shape_ = RandomRaySourceShape::LINEAR; - } else if (temp_str == "linear_xy") { - RandomRay::source_shape_ = RandomRaySourceShape::LINEAR_XY; - } else { - fatal_error("Unrecognized source shape: " + temp_str); - } - } - if (check_for_node(random_ray_node, "volume_normalized_flux_tallies")) { - FlatSourceDomain::volume_normalized_flux_tallies_ = - get_node_value_bool(random_ray_node, "volume_normalized_flux_tallies"); - } - if (check_for_node(random_ray_node, "adjoint")) { - FlatSourceDomain::adjoint_requested_ = - get_node_value_bool(random_ray_node, "adjoint"); - } - if (check_for_node(random_ray_node, "sample_method")) { - std::string temp_str = - get_node_value(random_ray_node, "sample_method", true, true); - if (temp_str == "prng") { - RandomRay::sample_method_ = RandomRaySampleMethod::PRNG; - } else if (temp_str == "halton") { - RandomRay::sample_method_ = RandomRaySampleMethod::HALTON; - } else if (temp_str == "s2") { - RandomRay::sample_method_ = RandomRaySampleMethod::S2; - } else { - fatal_error("Unrecognized sample method: " + temp_str); - } - } - if (check_for_node(random_ray_node, "source_region_meshes")) { - pugi::xml_node node_source_region_meshes = - random_ray_node.child("source_region_meshes"); - for (pugi::xml_node node_mesh : - node_source_region_meshes.children("mesh")) { - int mesh_id = std::stoi(node_mesh.attribute("id").value()); - for (pugi::xml_node node_domain : node_mesh.children("domain")) { - int domain_id = std::stoi(node_domain.attribute("id").value()); - std::string domain_type = node_domain.attribute("type").value(); - Source::DomainType type; - if (domain_type == "material") { - type = Source::DomainType::MATERIAL; - } else if (domain_type == "cell") { - type = Source::DomainType::CELL; - } else if (domain_type == "universe") { - type = Source::DomainType::UNIVERSE; - } else { - throw std::runtime_error("Unknown domain type: " + domain_type); - } - FlatSourceDomain::mesh_domain_map_[mesh_id].emplace_back( - type, domain_id); - } - } - } - if (check_for_node(random_ray_node, "diagonal_stabilization_rho")) { - FlatSourceDomain::diagonal_stabilization_rho_ = std::stod( - get_node_value(random_ray_node, "diagonal_stabilization_rho")); - if (FlatSourceDomain::diagonal_stabilization_rho_ < 0.0 || - FlatSourceDomain::diagonal_stabilization_rho_ > 1.0) { - fatal_error("Random ray diagonal stabilization rho factor must be " - "between 0 and 1"); - } - } - if (check_for_node(random_ray_node, "adjoint_source")) { - pugi::xml_node adj_source_node = random_ray_node.child("adjoint_source"); - for (pugi::xml_node source_node : adj_source_node.children("source")) { - // Find any local adjoint sources - model::adjoint_sources.push_back(Source::create(source_node)); - } - } - } } void read_settings_xml() { using namespace settings; using namespace pugi; + // Check if settings.xml exists - std::string filename = settings::path_input + "settings.xml"; + std::string filename = path_input + "settings.xml"; if (!file_exists(filename)) { if (run_mode != RunMode::PLOTTING) { - fatal_error("Could not find any XML input files! In order to run OpenMC, " - "you first need a set of input files; at a minimum, this " - "includes settings.xml, geometry.xml, and materials.xml or a " - "single model XML file. Please consult the user's guide at " - "https://docs.openmc.org for further information."); + fatal_error( + fmt::format("Settings XML file '{}' does not exist! In order " + "to run OpenMC, you first need a set of input files; at a " + "minimum, this " + "includes settings.xml, geometry.xml, and materials.xml. " + "Please consult " + "the user's guide at https://docs.openmc.org for further " + "information.", + filename)); } else { // The settings.xml file is optional if we just want to make a plot. return; @@ -411,10 +246,8 @@ void read_settings_xml() xml_node root = doc.document_element(); // Verbosity - if (check_for_node(root, "verbosity") && verbosity == -1) { + if (check_for_node(root, "verbosity")) { verbosity = std::stoi(get_node_value(root, "verbosity")); - } else if (verbosity == -1) { - verbosity = 7; } // To this point, we haven't displayed any output since we didn't know what @@ -423,17 +256,8 @@ void read_settings_xml() if (verbosity >= 2) title(); } - write_message("Reading settings XML file...", 5); - read_settings_xml(root); -} - -void read_settings_xml(pugi::xml_node root) -{ - using namespace settings; - using namespace pugi; - // Find if a multi-group or continuous-energy simulation is desired if (check_for_node(root, "energy_mode")) { std::string temp_str = get_node_value(root, "energy_mode", true, true); @@ -444,9 +268,6 @@ void read_settings_xml(pugi::xml_node root) } } - // Check for user meshes and allocate - read_meshes(root); - // Look for deprecated cross_sections.xml file in settings.xml if (check_for_node(root, "cross_sections")) { warning( @@ -537,14 +358,6 @@ void read_settings_xml(pugi::xml_node root) } } - // Check solver type - if (check_for_node(root, "random_ray")) { - solver_type = SolverType::RANDOM_RAY; - if (run_CE) - fatal_error("multi-group energy mode must be specified in settings XML " - "when using the random ray solver."); - } - if (run_mode == RunMode::EIGENVALUE || run_mode == RunMode::FIXED_SOURCE) { // Read run parameters get_run_parameters(node_mode); @@ -562,26 +375,6 @@ void read_settings_xml(pugi::xml_node root) } else if (rel_max_lost_particles <= 0.0 || rel_max_lost_particles >= 1.0) { fatal_error("Relative max lost particles must be between zero and one."); } - - // Check for user value for the number of generation of the Iterated Fission - // Probability (IFP) method - if (check_for_node(root, "ifp_n_generation")) { - ifp_n_generation = std::stoi(get_node_value(root, "ifp_n_generation")); - if (ifp_n_generation <= 0) { - fatal_error("'ifp_n_generation' must be greater than 0."); - } - // Avoid tallying 0 if IFP logs are not complete when active cycles start - if (ifp_n_generation > n_inactive) { - fatal_error("'ifp_n_generation' must be lower than or equal to the " - "number of inactive cycles."); - } - } - } - - // Copy plotting random number seed if specified - if (check_for_node(root, "plot_seed")) { - auto seed = std::stoll(get_node_value(root, "plot_seed")); - model::plotter_seed = seed; } // Copy random number seed if specified @@ -590,12 +383,6 @@ void read_settings_xml(pugi::xml_node root) openmc_set_seed(seed); } - // Copy random number stride if specified - if (check_for_node(root, "stride")) { - auto stride = std::stoull(get_node_value(root, "stride")); - openmc_set_stride(stride); - } - // Check for electron treatment if (check_for_node(root, "electron_treatment")) { auto temp_str = get_node_value(root, "electron_treatment", true, true); @@ -618,11 +405,6 @@ void read_settings_xml(pugi::xml_node root) } } - // Check for atomic relaxation - if (check_for_node(root, "atomic_relaxation")) { - atomic_relaxation = get_node_value_bool(root, "atomic_relaxation"); - } - // Number of bins for logarithmic grid if (check_for_node(root, "log_grid_bins")) { n_log_bins = std::stoi(get_node_value(root, "log_grid_bins")); @@ -645,7 +427,23 @@ void read_settings_xml(pugi::xml_node root) // Get point to list of elements and make sure there is at least one for (pugi::xml_node node : root.children("source")) { - model::external_sources.push_back(Source::create(node)); + if (check_for_node(node, "file")) { + auto path = get_node_value(node, "file", false, true); + model::external_sources.push_back(make_unique(path)); + } else if (check_for_node(node, "library")) { + // Get shared library path and parameters + auto path = get_node_value(node, "library", false, true); + std::string parameters; + if (check_for_node(node, "parameters")) { + parameters = get_node_value(node, "parameters", false, true); + } + + // Create custom source + model::external_sources.push_back( + make_unique(path, parameters)); + } else { + model::external_sources.push_back(make_unique(node)); + } } // Check if the user has specified to read surface source @@ -663,9 +461,8 @@ void read_settings_xml(pugi::xml_node root) } // If no source specified, default to isotropic point source at origin with - // Watt spectrum. No default source is needed in random ray mode. - if (model::external_sources.empty() && - settings::solver_type != SolverType::RANDOM_RAY) { + // Watt spectrum + if (model::external_sources.empty()) { double T[] {0.0}; double p[] {1.0}; model::external_sources.push_back(make_unique( @@ -674,36 +471,11 @@ void read_settings_xml(pugi::xml_node root) UPtrDist {new Discrete(T, p, 1)})); } - // Build probability mass function for sampling external sources - vector source_strengths; - for (auto& s : model::external_sources) { - source_strengths.push_back(s->strength()); - } - model::external_sources_probability.assign(source_strengths); - // Check if we want to write out source if (check_for_node(root, "write_initial_source")) { write_initial_source = get_node_value_bool(root, "write_initial_source"); } - // Get relative number of lost particles - if (check_for_node(root, "source_rejection_fraction")) { - source_rejection_fraction = - std::stod(get_node_value(root, "source_rejection_fraction")); - } - - if (check_for_node(root, "free_gas_threshold")) { - free_gas_threshold = std::stod(get_node_value(root, "free_gas_threshold")); - } - - // Surface grazing - if (check_for_node(root, "surface_grazing_cutoff")) - surface_grazing_cutoff = - std::stod(get_node_value(root, "surface_grazing_cutoff")); - if (check_for_node(root, "surface_grazing_ratio")) - surface_grazing_ratio = - std::stod(get_node_value(root, "surface_grazing_ratio")); - // Survival biasing if (check_for_node(root, "survival_biasing")) { survival_biasing = get_node_value_bool(root, "survival_biasing"); @@ -723,10 +495,6 @@ void read_settings_xml(pugi::xml_node root) if (check_for_node(node_cutoff, "weight_avg")) { weight_survive = std::stod(get_node_value(node_cutoff, "weight_avg")); } - if (check_for_node(node_cutoff, "survival_normalization")) { - survival_normalization = - get_node_value_bool(node_cutoff, "survival_normalization"); - } if (check_for_node(node_cutoff, "energy_neutron")) { energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy_neutron")); @@ -747,26 +515,6 @@ void read_settings_xml(pugi::xml_node root) energy_cutoff[3] = std::stod(get_node_value(node_cutoff, "energy_positron")); } - if (check_for_node(node_cutoff, "time_neutron")) { - time_cutoff[0] = std::stod(get_node_value(node_cutoff, "time_neutron")); - } - if (check_for_node(node_cutoff, "time_photon")) { - time_cutoff[1] = std::stod(get_node_value(node_cutoff, "time_photon")); - } - if (check_for_node(node_cutoff, "time_electron")) { - time_cutoff[2] = std::stod(get_node_value(node_cutoff, "time_electron")); - } - if (check_for_node(node_cutoff, "time_positron")) { - time_cutoff[3] = std::stod(get_node_value(node_cutoff, "time_positron")); - } - } - - // read properties from file - if (check_for_node(root, "properties_file")) { - properties_file = get_node_value(root, "properties_file"); - if (!file_exists(properties_file)) { - fatal_error(fmt::format("File '{}' does not exist.", properties_file)); - } } // Particle trace @@ -800,37 +548,33 @@ void read_settings_xml(pugi::xml_node root) } } - // Shannon entropy - if (solver_type == SolverType::RANDOM_RAY) { - if (check_for_node(root, "entropy_mesh")) { - fatal_error("Random ray uses FSRs to compute the Shannon entropy. " - "No user-defined entropy mesh is supported."); + // Read meshes + read_meshes(root); + + // Shannon Entropy mesh + if (check_for_node(root, "entropy_mesh")) { + int temp = std::stoi(get_node_value(root, "entropy_mesh")); + if (model::mesh_map.find(temp) == model::mesh_map.end()) { + fatal_error(fmt::format( + "Mesh {} specified for Shannon entropy does not exist.", temp)); } + + auto* m = + dynamic_cast(model::meshes[model::mesh_map.at(temp)].get()); + if (!m) + fatal_error("Only regular meshes can be used as an entropy mesh"); + simulation::entropy_mesh = m; + + // Turn on Shannon entropy calculation entropy_on = true; - } else if (solver_type == SolverType::MONTE_CARLO) { - if (check_for_node(root, "entropy_mesh")) { - int temp = std::stoi(get_node_value(root, "entropy_mesh")); - if (model::mesh_map.find(temp) == model::mesh_map.end()) { - fatal_error(fmt::format( - "Mesh {} specified for Shannon entropy does not exist.", temp)); - } - auto* m = dynamic_cast( - model::meshes[model::mesh_map.at(temp)].get()); - if (!m) - fatal_error("Only regular meshes can be used as an entropy mesh"); - simulation::entropy_mesh = m; - - // Turn on Shannon entropy calculation - entropy_on = true; - - } else if (check_for_node(root, "entropy")) { - fatal_error( - "Specifying a Shannon entropy mesh via the element " - "is deprecated. Please create a mesh using and then reference " - "it by specifying its ID in an element."); - } + } else if (check_for_node(root, "entropy")) { + fatal_error( + "Specifying a Shannon entropy mesh via the element " + "is deprecated. Please create a mesh using and then reference " + "it by specifying its ID in an element."); } + // Uniform fission source weighting mesh if (check_for_node(root, "ufs_mesh")) { auto temp = std::stoi(get_node_value(root, "ufs_mesh")); @@ -903,9 +647,6 @@ void read_settings_xml(pugi::xml_node root) if (check_for_node(node_sp, "write")) { source_write = get_node_value_bool(node_sp, "write"); } - if (check_for_node(node_sp, "mcpl")) { - source_mcpl_write = get_node_value_bool(node_sp, "mcpl"); - } if (check_for_node(node_sp, "overwrite_latest")) { source_latest = get_node_value_bool(node_sp, "overwrite_latest"); source_separate = source_latest; @@ -917,21 +658,13 @@ void read_settings_xml(pugi::xml_node root) sourcepoint_batch = statepoint_batch; } - // Check is the user specified to convert strength to statistical weight - if (check_for_node(root, "uniform_source_sampling")) { - uniform_source_sampling = - get_node_value_bool(root, "uniform_source_sampling"); - } - // Check if the user has specified to write surface source if (check_for_node(root, "surf_source_write")) { surf_source_write = true; // Get surface source write node xml_node node_ssw = root.child("surf_source_write"); - // Determine surface ids at which crossing particles are to be banked. - // If no surfaces are specified, all surfaces in the model will be used - // to bank source points. + // Determine surface ids at which crossing particles are to be banked if (check_for_node(node_ssw, "surface_ids")) { auto temp = get_node_array(node_ssw, "surface_ids"); for (const auto& b : temp) { @@ -941,112 +674,13 @@ void read_settings_xml(pugi::xml_node root) // Get maximum number of particles to be banked per surface if (check_for_node(node_ssw, "max_particles")) { - ssw_max_particles = std::stoll(get_node_value(node_ssw, "max_particles")); - } else { - fatal_error("A maximum number of particles needs to be specified " - "using the 'max_particles' parameter to store surface " - "source points."); - } - - // Get maximum number of surface source files to be created - if (check_for_node(node_ssw, "max_source_files")) { - ssw_max_files = std::stoll(get_node_value(node_ssw, "max_source_files")); - } else { - ssw_max_files = 1; - } - - if (check_for_node(node_ssw, "mcpl")) { - surf_mcpl_write = get_node_value_bool(node_ssw, "mcpl"); - } - // Get cell information - if (check_for_node(node_ssw, "cell")) { - ssw_cell_id = std::stoll(get_node_value(node_ssw, "cell")); - ssw_cell_type = SSWCellType::Both; - } - if (check_for_node(node_ssw, "cellfrom")) { - if (ssw_cell_id != C_NONE) { - fatal_error( - "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); - } - ssw_cell_id = std::stoll(get_node_value(node_ssw, "cellfrom")); - ssw_cell_type = SSWCellType::From; - } - if (check_for_node(node_ssw, "cellto")) { - if (ssw_cell_id != C_NONE) { - fatal_error( - "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); - } - ssw_cell_id = std::stoll(get_node_value(node_ssw, "cellto")); - ssw_cell_type = SSWCellType::To; + max_surface_particles = + std::stoll(get_node_value(node_ssw, "max_particles")); } } - // Check if the user has specified to write specific collisions - if (check_for_node(root, "collision_track")) { - settings::collision_track = true; - // Get collision track node - xml_node node_ct = root.child("collision_track"); - collision_track_config = CollisionTrackConfig {}; - - // Determine cell ids at which crossing particles are to be banked - if (check_for_node(node_ct, "cell_ids")) { - auto temp = get_node_array(node_ct, "cell_ids"); - for (const auto& b : temp) { - collision_track_config.cell_ids.insert(b); - } - } - if (check_for_node(node_ct, "reactions")) { - auto temp = get_node_array(node_ct, "reactions"); - for (const auto& b : temp) { - int reaction_int = reaction_mt(b); - if (reaction_int > 0) { - collision_track_config.mt_numbers.insert(reaction_int); - } - } - } - if (check_for_node(node_ct, "universe_ids")) { - auto temp = get_node_array(node_ct, "universe_ids"); - for (const auto& b : temp) { - collision_track_config.universe_ids.insert(b); - } - } - if (check_for_node(node_ct, "material_ids")) { - auto temp = get_node_array(node_ct, "material_ids"); - for (const auto& b : temp) { - collision_track_config.material_ids.insert(b); - } - } - if (check_for_node(node_ct, "nuclides")) { - auto temp = get_node_array(node_ct, "nuclides"); - for (const auto& b : temp) { - collision_track_config.nuclides.insert(b); - } - } - if (check_for_node(node_ct, "deposited_E_threshold")) { - collision_track_config.deposited_energy_threshold = - std::stod(get_node_value(node_ct, "deposited_E_threshold")); - } - // Get maximum number of particles to be banked per collision - if (check_for_node(node_ct, "max_collisions")) { - collision_track_config.max_collisions = - std::stoll(get_node_value(node_ct, "max_collisions")); - } else { - warning("A maximum number of collisions needs to be specified. " - "By default the code sets 'max_collisions' parameter equals to " - "1000."); - } - // Get maximum number of collision_track files to be created - if (check_for_node(node_ct, "max_collision_track_files")) { - collision_track_config.max_files = - std::stoll(get_node_value(node_ct, "max_collision_track_files")); - } - if (check_for_node(node_ct, "mcpl")) { - collision_track_config.mcpl_write = get_node_value_bool(node_ct, "mcpl"); - } - } - - // If source is not separate and is to be written out in the statepoint - // file, make sure that the sourcepoint batch numbers are contained in the + // If source is not seperate and is to be written out in the statepoint file, + // make sure that the sourcepoint batch numbers are contained in the // statepoint list if (!source_separate) { for (const auto& b : sourcepoint_batch) { @@ -1204,12 +838,6 @@ void read_settings_xml(pugi::xml_node root) } } - // Check whether create delayed neutrons in fission - if (check_for_node(root, "create_delayed_neutrons")) { - create_delayed_neutrons = - get_node_value_bool(root, "create_delayed_neutrons"); - } - // Check whether create fission sites if (run_mode == RunMode::FIXED_SOURCE) { if (check_for_node(root, "create_fission_neutrons")) { @@ -1238,111 +866,22 @@ void read_settings_xml(pugi::xml_node root) for (pugi::xml_node node_ww : root.children("weight_windows")) { variance_reduction::weight_windows.emplace_back( std::make_unique(node_ww)); - } - // Enable weight windows by default if one or more are present - if (variance_reduction::weight_windows.size() > 0) + // Enable weight windows by default if one or more are present settings::weight_windows_on = true; - - // read weight windows from file - if (check_for_node(root, "weight_windows_file")) { - weight_windows_file = get_node_value(root, "weight_windows_file"); - weight_windows_on = true; } - // read settings for weight windows value, this will override - // the automatic setting even if weight windows are present if (check_for_node(root, "weight_windows_on")) { weight_windows_on = get_node_value_bool(root, "weight_windows_on"); } - if (check_for_node(root, "max_secondaries")) { - settings::max_secondaries = - std::stoi(get_node_value(root, "max_secondaries")); - } - - if (check_for_node(root, "max_history_splits")) { - settings::max_history_splits = - std::stoi(get_node_value(root, "max_history_splits")); + if (check_for_node(root, "max_splits")) { + settings::max_splits = std::stoi(get_node_value(root, "max_splits")); } if (check_for_node(root, "max_tracks")) { settings::max_tracks = std::stoi(get_node_value(root, "max_tracks")); } - - // Create weight window generator objects - if (check_for_node(root, "weight_window_generators")) { - auto wwgs_node = root.child("weight_window_generators"); - for (pugi::xml_node node_wwg : - wwgs_node.children("weight_windows_generator")) { - variance_reduction::weight_windows_generators.emplace_back( - std::make_unique(node_wwg)); - } - // if any of the weight windows are intended to be generated otf, make - // sure they're applied - for (const auto& wwg : variance_reduction::weight_windows_generators) { - if (wwg->on_the_fly_) { - settings::weight_windows_on = true; - break; - } - } - // If any weight window generators have local FW-CADIS target tallies, - // user-defined adjoint sources cannot be used at the same time. - if (!model::adjoint_sources.empty()) { - for (const auto& wwg : variance_reduction::weight_windows_generators) { - if (!wwg->targets_.empty()) { - fatal_error("Cannot use both user-defined adjoint sources and " - "FW-CADIS target tallies at the same time."); - } - } - } - } - - // Set up weight window checkpoints - if (check_for_node(root, "weight_window_checkpoints")) { - xml_node ww_checkpoints = root.child("weight_window_checkpoints"); - if (check_for_node(ww_checkpoints, "collision")) { - weight_window_checkpoint_collision = - get_node_value_bool(ww_checkpoints, "collision"); - } - if (check_for_node(ww_checkpoints, "surface")) { - weight_window_checkpoint_surface = - get_node_value_bool(ww_checkpoints, "surface"); - } - } - - if (weight_windows_on) { - if (!weight_window_checkpoint_surface && - !weight_window_checkpoint_collision) - fatal_error( - "Weight Windows are enabled but there are no valid checkpoints."); - } - - if (check_for_node(root, "use_decay_photons")) { - settings::use_decay_photons = - get_node_value_bool(root, "use_decay_photons"); - } - - // If weight windows are on, also enable shared secondary bank (unless - // explicitly disabled by user). - if (check_for_node(root, "shared_secondary_bank")) { - bool val = get_node_value_bool(root, "shared_secondary_bank"); - if (val && run_mode == RunMode::EIGENVALUE) { - warning( - "Shared secondary bank is not supported in eigenvalue calculations. " - "Setting will be ignored."); - } else { - settings::use_shared_secondary_bank = val; - } - } else if (settings::weight_windows_on) { - if (run_mode == RunMode::EIGENVALUE) { - warning( - "Shared secondary bank is not supported in eigenvalue calculations. " - "Particle local secondary banks will be used instead."); - } else if (run_mode == RunMode::FIXED_SOURCE) { - settings::use_shared_secondary_bank = true; - } - } } void free_memory_settings() @@ -1365,6 +904,11 @@ extern "C" int openmc_set_n_batches( return OPENMC_E_INVALID_ARGUMENT; } + if (simulation::current_batch >= n_batches) { + set_errmsg("Number of batches must be greater than current batch."); + return OPENMC_E_INVALID_ARGUMENT; + } + if (!settings::trigger_on) { // Set n_batches and n_max_batches to same value settings::n_batches = n_batches; diff --git a/src/simulation.cpp b/src/simulation.cpp index 03f40a726..b70535c33 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -2,22 +2,18 @@ #include "openmc/bank.h" #include "openmc/capi.h" -#include "openmc/collision_track.h" #include "openmc/container_util.h" #include "openmc/eigenvalue.h" #include "openmc/error.h" #include "openmc/event.h" #include "openmc/geometry_aux.h" -#include "openmc/ifp.h" #include "openmc/material.h" #include "openmc/message_passing.h" #include "openmc/nuclide.h" -#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/particle.h" #include "openmc/photon.h" #include "openmc/random_lcg.h" -#include "openmc/random_ray/flat_source_domain.h" #include "openmc/settings.h" #include "openmc/source.h" #include "openmc/state_point.h" @@ -27,12 +23,11 @@ #include "openmc/tallies/trigger.h" #include "openmc/timer.h" #include "openmc/track_output.h" -#include "openmc/weight_windows.h" #ifdef _OPENMP #include #endif -#include "openmc/tensor.h" +#include "xtensor/xview.hpp" #ifdef OPENMC_MPI #include @@ -42,7 +37,6 @@ #include #include -#include #include //============================================================================== @@ -58,14 +52,8 @@ int openmc_run() openmc::simulation::time_total.start(); openmc_simulation_init(); - // Ensure that a batch isn't executed in the case that the maximum number of - // batches has already been run in a restart statepoint file - int status = 0; - if (openmc::simulation::current_batch >= openmc::settings::n_max_batches) { - status = openmc::STATUS_EXIT_MAX_BATCH; - } - int err = 0; + int status = 0; while (status == 0 && err == 0) { err = openmc_next_batch(&status); } @@ -89,7 +77,7 @@ int openmc_simulation_init() } // Determine how much work each process should do - calculate_work(settings::n_particles); + calculate_work(); // Allocate source, fission and surface source banks. allocate_banks(); @@ -109,7 +97,6 @@ int openmc_simulation_init() // Allocate tally results arrays if they're not allocated yet for (auto& t : model::tallies) { - t->set_strides(); t->init_results(); } @@ -121,11 +108,8 @@ int openmc_simulation_init() // Reset global variables -- this is done before loading state point (as that // will potentially populate k_generation and entropy) simulation::current_batch = 0; - simulation::ct_current_file = 1; - simulation::ssw_current_file = 1; simulation::k_generation.clear(); simulation::entropy.clear(); - reset_source_rejection_counters(); openmc_reset(); // If this is a restart run, load the state point data and binary source @@ -135,8 +119,7 @@ int openmc_simulation_init() write_message("Resuming simulation...", 6); } else { // Only initialize primary source bank for eigenvalue simulations - if (settings::run_mode == RunMode::EIGENVALUE && - settings::solver_type == SolverType::MONTE_CARLO) { + if (settings::run_mode == RunMode::EIGENVALUE) { initialize_source(); } } @@ -144,27 +127,14 @@ int openmc_simulation_init() // Display header if (mpi::master) { if (settings::run_mode == RunMode::FIXED_SOURCE) { - if (settings::solver_type == SolverType::MONTE_CARLO) { - header("FIXED SOURCE TRANSPORT SIMULATION", 3); - } else if (settings::solver_type == SolverType::RANDOM_RAY) { - header("FIXED SOURCE TRANSPORT SIMULATION (RANDOM RAY SOLVER)", 3); - } + header("FIXED SOURCE TRANSPORT SIMULATION", 3); } else if (settings::run_mode == RunMode::EIGENVALUE) { - if (settings::solver_type == SolverType::MONTE_CARLO) { - header("K EIGENVALUE SIMULATION", 3); - } else if (settings::solver_type == SolverType::RANDOM_RAY) { - header("K EIGENVALUE SIMULATION (RANDOM RAY SOLVER)", 3); - } + header("K EIGENVALUE SIMULATION", 3); if (settings::verbosity >= 7) print_columns(); } } - // load weight windows from file - if (!settings::weight_windows_file.empty()) { - openmc_weight_windows_import(settings::weight_windows_file.c_str()); - } - // Set flag indicating initialization is done simulation::initialized = true; return 0; @@ -203,15 +173,6 @@ int openmc_simulation_finalize() if (settings::output_tallies && mpi::master) write_tallies(); - // If weight window generators are present in this simulation, write a - // weight windows file. This is skipped during the forward solve of an - // adjoint (FW-CADIS) run, where only the adjoint-derived weight windows - // are meaningful. - if (variance_reduction::weight_windows_generators.size() > 0 && - FlatSourceDomain::solve_ != RandomRaySolve::FORWARD_FOR_ADJOINT) { - openmc_weight_windows_export(); - } - // Deactivate all tallies for (auto& t : model::tallies) { t->active_ = false; @@ -220,27 +181,11 @@ int openmc_simulation_finalize() // Stop timers and show timing statistics simulation::time_finalize.stop(); simulation::time_total.stop(); - -#ifdef OPENMC_MPI - // Reduce track count across ranks for correct reporting. In shared secondary - // bank mode, all ranks already have the global count; in non-shared mode, - // each rank only has its own count. - if (settings::weight_windows_on && !settings::use_shared_secondary_bank) { - int64_t total_tracks; - MPI_Reduce(&simulation::simulation_tracks_completed, &total_tracks, 1, - MPI_INT64_T, MPI_SUM, 0, mpi::intracomm); - if (mpi::master) - simulation::simulation_tracks_completed = total_tracks; - } -#endif - if (mpi::master) { - if (settings::solver_type != SolverType::RANDOM_RAY) { - if (settings::verbosity >= 6) - print_runtime(); - if (settings::verbosity >= 4) - print_results(); - } + if (settings::verbosity >= 6) + print_runtime(); + if (settings::verbosity >= 4) + print_results(); } if (settings::check_overlaps) print_overlap_check(); @@ -274,17 +219,9 @@ int openmc_next_batch(int* status) // Transport loop if (settings::event_based) { - if (settings::use_shared_secondary_bank) { - transport_event_based_shared_secondary(); - } else { - transport_event_based(); - } + transport_event_based(); } else { - if (settings::use_shared_secondary_bank) { - transport_history_based_shared_secondary(); - } else { - transport_history_based(); - } + transport_history_based(); } // Accumulate time for transport @@ -297,7 +234,7 @@ int openmc_next_batch(int* status) // Check simulation ending criteria if (status) { - if (simulation::current_batch >= settings::n_max_batches) { + if (simulation::current_batch == settings::n_max_batches) { *status = STATUS_EXIT_MAX_BATCH; } else if (simulation::satisfy_triggers) { *status = STATUS_EXIT_ON_TRIGGER; @@ -327,7 +264,6 @@ namespace openmc { namespace simulation { -int ct_current_file; int current_batch; int current_gen; bool initialized {false}; @@ -341,7 +277,6 @@ int n_lost_particles {0}; bool need_depletion_rx {false}; int restart_batch; bool satisfy_triggers {false}; -int ssw_current_file; int total_gen {0}; double total_weight; int64_t work_per_rank; @@ -352,126 +287,25 @@ const RegularMesh* ufs_mesh {nullptr}; vector k_generation; vector work_index; -int64_t simulation_tracks_completed {0}; - } // namespace simulation -namespace { - -//! Collect thread-local secondary banks into the shared secondary bank in -//! sorted order. -//! -//! \param thread_banks Secondary banks produced by each OpenMP thread -void collect_sorted_history_secondary_banks( - vector>& thread_banks) -{ - // Count the total number of all secondary sites produced - int64_t n_collected = 0; - for (const auto& bank : thread_banks) { - n_collected += bank.size(); - } - - // Count the expected number of progeny from per-parent progeny counts - int64_t n_progeny = 0; - for (int64_t count : simulation::progeny_per_particle) { - n_progeny += count; - } - - if (n_collected != n_progeny) { - fatal_error("Mismatch detected between sum of all particle progeny and " - "secondary bank size during collection."); - } - - // Convert per-parent progeny counts to offsets into the sorted bank - std::exclusive_scan(simulation::progeny_per_particle.begin(), - simulation::progeny_per_particle.end(), - simulation::progeny_per_particle.begin(), 0); - - // Allocate the shared bank once for the complete generation - simulation::shared_secondary_bank_write.resize(0); - simulation::shared_secondary_bank_write.extend_uninitialized(n_progeny); - - // Place each secondary according to its parent and progeny identifiers - for (const auto& bank : thread_banks) { - for (const auto& site : bank) { - if (site.parent_id < 0 || - site.parent_id >= - static_cast(simulation::progeny_per_particle.size())) { - fatal_error(fmt::format("Invalid parent_id {} for banked site " - "(expected range [0, {})).", - site.parent_id, simulation::progeny_per_particle.size())); - } - int64_t idx = - simulation::progeny_per_particle[site.parent_id] + site.progeny_id; - if (idx < 0 || idx >= n_progeny) { - fatal_error("Mismatch detected between sum of all particle progeny and " - "secondary bank size during collection."); - } - simulation::shared_secondary_bank_write[idx] = site; - } - } -} - -//! Collect particle-local secondary banks into the shared secondary bank. -//! -//! \param n_particles Number of particles in the active event-based buffer -void collect_event_secondary_banks(int64_t n_particles) -{ - // Compute offsets for each particle's local secondary bank. - vector offsets(n_particles); - int64_t total = 0; - for (int64_t i = 0; i < n_particles; ++i) { - offsets[i] = total; - total += simulation::particles[i].local_secondary_bank().size(); - } - - // Extend the shared bank once for all collected secondaries - int64_t bank_offset = - simulation::shared_secondary_bank_write.extend_uninitialized(total); - - // Copy each local bank into its assigned range and clear the local storage -#pragma omp parallel for schedule(static) - for (int64_t i = 0; i < n_particles; ++i) { - auto& local_bank = simulation::particles[i].local_secondary_bank(); - if (!local_bank.empty()) { - std::copy(local_bank.cbegin(), local_bank.cend(), - simulation::shared_secondary_bank_write.data() + bank_offset + - offsets[i]); - local_bank.clear(); - } - } -} - -} // namespace - //============================================================================== // Non-member functions //============================================================================== void allocate_banks() { - if (settings::run_mode == RunMode::EIGENVALUE && - settings::solver_type == SolverType::MONTE_CARLO) { + if (settings::run_mode == RunMode::EIGENVALUE) { // Allocate source bank simulation::source_bank.resize(simulation::work_per_rank); // Allocate fission bank init_fission_bank(3 * simulation::work_per_rank); - - // Allocate IFP bank - if (settings::ifp_on) { - resize_simulation_ifp_banks(); - } } if (settings::surf_source_write) { // Allocate surface source bank - simulation::surf_source_bank.reserve(settings::ssw_max_particles); - } - - if (settings::collision_track) { - // Allocate collision track bank - collision_track_reserve_bank(); + simulation::surf_source_bank.reserve(settings::max_surface_particles); } } @@ -479,14 +313,9 @@ void initialize_batch() { // Increment current batch ++simulation::current_batch; + if (settings::run_mode == RunMode::FIXED_SOURCE) { - if (settings::solver_type == SolverType::RANDOM_RAY && - simulation::current_batch < settings::n_inactive + 1) { - write_message( - 6, "Simulating batch {:<4} (inactive)", simulation::current_batch); - } else { - write_message(6, "Simulating batch {}", simulation::current_batch); - } + write_message(6, "Simulating batch {}", simulation::current_batch); } // Reset total starting particle weight used for normalizing tallies @@ -525,14 +354,9 @@ void finalize_batch() accumulate_tallies(); simulation::time_tallies.stop(); - // update weight windows if needed - for (const auto& wwg : variance_reduction::weight_windows_generators) { - wwg->update(); - } - // Reset global tally results if (simulation::current_batch <= settings::n_inactive) { - simulation::global_tallies.fill(0.0); + xt::view(simulation::global_tallies, xt::all()) = 0.0; simulation::n_realizations = 0; } @@ -566,59 +390,21 @@ void finalize_batch() // Write out a separate source point if it's been specified for this batch if (contains(settings::sourcepoint_batch, simulation::current_batch) && settings::source_write && settings::source_separate) { - - // Determine width for zero padding - int w = std::to_string(settings::n_max_batches).size(); - std::string source_point_filename = fmt::format("{0}source.{1:0{2}}", - settings::path_output, simulation::current_batch, w); - span bankspan(simulation::source_bank); - write_source_point(source_point_filename, bankspan, - simulation::work_index, settings::source_mcpl_write); + write_source_point(nullptr); } // Write a continously-overwritten source point if requested. if (settings::source_latest) { - auto filename = settings::path_output + "source"; - span bankspan(simulation::source_bank); - write_source_point(filename, bankspan, simulation::work_index, - settings::source_mcpl_write); + auto filename = settings::path_output + "source.h5"; + write_source_point(filename.c_str()); } } // Write out surface source if requested. if (settings::surf_source_write && - simulation::ssw_current_file <= settings::ssw_max_files) { - bool last_batch = (simulation::current_batch == settings::n_batches); - if (simulation::surf_source_bank.full() || last_batch) { - // Determine appropriate filename - auto filename = fmt::format("{}surface_source.{}", settings::path_output, - simulation::current_batch); - if (settings::ssw_max_files == 1 || - (simulation::ssw_current_file == 1 && last_batch)) { - filename = settings::path_output + "surface_source"; - } - - // Get span of source bank and calculate parallel index vector - auto surf_work_index = mpi::calculate_parallel_index_vector( - simulation::surf_source_bank.size()); - span surfbankspan(simulation::surf_source_bank.begin(), - simulation::surf_source_bank.size()); - - // Write surface source file - write_source_point( - filename, surfbankspan, surf_work_index, settings::surf_mcpl_write); - - // Reset surface source bank and increment counter - simulation::surf_source_bank.clear(); - if (!last_batch && settings::ssw_max_files >= 1) { - simulation::surf_source_bank.reserve(settings::ssw_max_particles); - } - ++simulation::ssw_current_file; - } - } - // Write collision track file if requested - if (settings::collision_track) { - collision_track_flush_bank(); + simulation::current_batch == settings::n_batches) { + auto filename = settings::path_output + "surface_source.h5"; + write_source_point(filename.c_str(), true); } } @@ -660,22 +446,17 @@ void finalize_generation() } global_tally_leakage = 0.0; - if (settings::run_mode == RunMode::EIGENVALUE && - settings::solver_type == SolverType::MONTE_CARLO) { + if (settings::run_mode == RunMode::EIGENVALUE) { // If using shared memory, stable sort the fission bank (by parent IDs) // so as to allow for reproducibility regardless of which order particles // are run in. - sort_bank(simulation::fission_bank, true); + sort_fission_bank(); // Distribute fission bank across processors evenly synchronize_bank(); - } - - if (settings::run_mode == RunMode::EIGENVALUE) { // Calculate shannon entropy - if (settings::entropy_on && - settings::solver_type == SolverType::MONTE_CARLO) + if (settings::entropy_on) shannon_entropy(); // Collect results and statistics @@ -689,35 +470,26 @@ void finalize_generation() } } -void sample_source_particle(Particle& p, int64_t index_source) +void initialize_history(Particle& p, int64_t index_source) { - // Sample a particle from the source bank + // set defaults if (settings::run_mode == RunMode::EIGENVALUE) { + // set defaults for eigenvalue simulations from primary bank p.from_source(&simulation::source_bank[index_source - 1]); } else if (settings::run_mode == RunMode::FIXED_SOURCE) { // initialize random number seed - int64_t id = compute_transport_seed(compute_particle_id(index_source)); + int64_t id = (simulation::total_gen + overall_generation() - 1) * + settings::n_particles + + simulation::work_index[mpi::rank] + index_source; uint64_t seed = init_seed(id, STREAM_SOURCE); // sample from external source distribution or custom library then set auto site = sample_external_source(&seed); p.from_source(&site); } -} - -void initialize_particle_track( - Particle& p, int64_t index_source, bool is_secondary) -{ - // Note: index_source is 1-based (first particle = 1), but current_work() is - // stored as 0-based for direct use as an array index into - // progeny_per_particle, source_bank, ifp banks, etc. - if (!is_secondary) { - sample_source_particle(p, index_source); - } - - p.current_work() = index_source - 1; + p.current_work() = index_source; // set identifier for particle - p.id() = compute_particle_id(index_source); + p.id() = simulation::work_index[mpi::rank] + index_source; // set progeny count to zero p.n_progeny() = 0; @@ -725,23 +497,16 @@ void initialize_particle_track( // Reset particle event counter p.n_event() = 0; - // Initialize track counter (1 for this primary/secondary track) - p.n_tracks() = 1; - // Reset split counter p.n_split() = 0; // Reset weight window ratio p.ww_factor() = 0.0; - // set particle history start weight - p.wgt_born() = p.wgt(); - - // Reset pulse_height_storage - std::fill(p.pht_storage().begin(), p.pht_storage().end(), 0); - // set random number seed - int64_t particle_seed = compute_transport_seed(p.id()); + int64_t particle_seed = + (simulation::total_gen + overall_generation() - 1) * settings::n_particles + + p.id(); init_particle_seeds(particle_seed, p.seeds()); // set particle trace @@ -754,22 +519,14 @@ void initialize_particle_track( // Set particle track. p.write_track() = check_track_criteria(p); - // Set the particle's initial weight window value. - if (!is_secondary) { - p.wgt_ww_born() = -1.0; - apply_weight_windows(p); - } - // Display message if high verbosity or trace is on if (settings::verbosity >= 9 || p.trace()) { write_message("Simulating Particle {}", p.id()); } - // Add particle's starting weight to count for normalizing tallies later - if (!is_secondary) { +// Add paricle's starting weight to count for normalizing tallies later #pragma omp atomic - simulation::total_weight += p.wgt(); - } + simulation::total_weight += p.wgt(); // Force calculation of cross-sections by setting last energy to zero if (settings::run_CE) { @@ -787,34 +544,13 @@ int overall_generation() return settings::gen_per_batch * (current_batch - 1) + current_gen; } -int64_t compute_particle_id(int64_t index_source) -{ - if (settings::use_shared_secondary_bank) { - return simulation::work_index[mpi::rank] + index_source + - simulation::simulation_tracks_completed; - } else { - return simulation::work_index[mpi::rank] + index_source; - } -} - -int64_t compute_transport_seed(int64_t particle_id) -{ - if (settings::use_shared_secondary_bank) { - return particle_id; - } else { - return (simulation::total_gen + overall_generation() - 1) * - settings::n_particles + - particle_id; - } -} - -void calculate_work(int64_t n_particles) +void calculate_work() { // Determine minimum amount of particles to simulate on each processor - int64_t min_work = n_particles / mpi::n_procs; + int64_t min_work = settings::n_particles / mpi::n_procs; // Determine number of processors that have one extra particle - int64_t remainder = n_particles % mpi::n_procs; + int64_t remainder = settings::n_particles % mpi::n_procs; int64_t i_bank = 0; simulation::work_index.resize(mpi::n_procs + 1); @@ -836,12 +572,11 @@ void calculate_work(int64_t n_particles) void initialize_data() { // Determine minimum/maximum energy for incident neutron/photon data - data::energy_max = {INFTY, INFTY, INFTY, INFTY}; - data::energy_min = {0.0, 0.0, 0.0, 0.0}; - + data::energy_max = {INFTY, INFTY}; + data::energy_min = {0.0, 0.0}; for (const auto& nuc : data::nuclides) { if (nuc->grid_.size() >= 1) { - int neutron = ParticleType::neutron().transport_index(); + int neutron = static_cast(ParticleType::neutron); data::energy_min[neutron] = std::max(data::energy_min[neutron], nuc->grid_[0].energy.front()); data::energy_max[neutron] = @@ -852,7 +587,7 @@ void initialize_data() if (settings::photon_transport) { for (const auto& elem : data::elements) { if (elem->energy_.size() >= 1) { - int photon = ParticleType::photon().transport_index(); + int photon = static_cast(ParticleType::photon); int n = elem->energy_.size(); data::energy_min[photon] = std::max(data::energy_min[photon], std::exp(elem->energy_(1))); @@ -865,22 +600,12 @@ void initialize_data() // Determine if minimum/maximum energy for bremsstrahlung is greater/less // than the current minimum/maximum if (data::ttb_e_grid.size() >= 1) { - int photon = ParticleType::photon().transport_index(); - int electron = ParticleType::electron().transport_index(); - int positron = ParticleType::positron().transport_index(); + int photon = static_cast(ParticleType::photon); int n_e = data::ttb_e_grid.size(); - - const std::vector charged = {electron, positron}; - for (auto t : charged) { - data::energy_min[t] = std::exp(data::ttb_e_grid(1)); - data::energy_max[t] = std::exp(data::ttb_e_grid(n_e - 1)); - } - data::energy_min[photon] = - std::max(data::energy_min[photon], data::energy_min[electron]); - - data::energy_max[photon] = - std::min(data::energy_max[photon], data::energy_max[electron]); + std::max(data::energy_min[photon], std::exp(data::ttb_e_grid(1))); + data::energy_max[photon] = std::min( + data::energy_max[photon], std::exp(data::ttb_e_grid(n_e - 1))); } } } @@ -891,7 +616,7 @@ void initialize_data() // grid has not been allocated if (nuc->grid_.size() > 0) { double max_E = nuc->grid_[0].energy.back(); - int neutron = ParticleType::neutron().transport_index(); + int neutron = static_cast(ParticleType::neutron); if (max_E == data::energy_max[neutron]) { write_message(7, "Maximum neutron transport energy: {} eV for {}", data::energy_max[neutron], nuc->name_); @@ -908,7 +633,7 @@ void initialize_data() for (auto& nuc : data::nuclides) { nuc->init_grid(); } - int neutron = ParticleType::neutron().transport_index(); + int neutron = static_cast(ParticleType::neutron); simulation::log_spacing = std::log(data::energy_max[neutron] / data::energy_min[neutron]) / settings::n_log_bins; @@ -957,152 +682,33 @@ void free_memory_simulation() void transport_history_based_single_particle(Particle& p) { - while (p.alive()) { + while (true) { p.event_calculate_xs(); - if (p.alive()) { - p.event_advance(); + if (!p.alive()) + break; + p.event_advance(); + if (p.collision_distance() > p.boundary().distance) { + p.event_cross_surface(); + } else { + p.event_collide(); } - if (p.alive()) { - if (p.collision_distance() > p.boundary().distance()) { - p.event_cross_surface(); - } else if (p.alive()) { - p.event_collide(); - } - } - p.event_check_limit_and_revive(); + p.event_revive_from_secondary(); + if (!p.alive()) + break; } p.event_death(); } void transport_history_based() { -#pragma omp parallel - { +#pragma omp parallel for schedule(runtime) + for (int64_t i_work = 1; i_work <= simulation::work_per_rank; ++i_work) { Particle p; -#pragma omp for schedule(runtime) - for (int64_t i_work = 1; i_work <= simulation::work_per_rank; ++i_work) { - initialize_particle_track(p, i_work, false); - transport_history_based_single_particle(p); - } + initialize_history(p, i_work); + transport_history_based_single_particle(p); } } -// The shared secondary bank transport algorithm works in two phases. In the -// first phase, all primary particles are sampled then transported, and their -// secondary particles are deposited into a shared secondary bank. The second -// phase occurs in a loop, where all secondary tracks in the shared secondary -// bank are transported. Any secondary particles generated during this phase are -// deposited back into the shared secondary bank. The shared secondary bank is -// sorted for consistent ordering and load balanced across MPI ranks. This loop -// continues until there are no more secondary tracks left to transport. -void transport_history_based_shared_secondary() -{ - // Clear shared secondary banks from any prior use - simulation::shared_secondary_bank_read.clear(); - simulation::shared_secondary_bank_write.clear(); - - if (mpi::master) { - write_message(fmt::format(" Primary source particles: {}", - settings::n_particles), - 6); - } - - simulation::progeny_per_particle.resize(simulation::work_per_rank); - std::fill(simulation::progeny_per_particle.begin(), - simulation::progeny_per_particle.end(), 0); - - vector> thread_banks(num_threads()); - - // Phase 1: Transport primary particles and deposit first generation of - // secondaries in the shared secondary bank -#pragma omp parallel - { - auto& thread_bank = thread_banks[thread_num()]; - Particle p; - -#pragma omp for schedule(runtime) - for (int64_t i = 1; i <= simulation::work_per_rank; i++) { - initialize_particle_track(p, i, false); - transport_history_based_single_particle(p); - for (auto& site : p.local_secondary_bank()) { - thread_bank.push_back(site); - } - p.local_secondary_bank().clear(); - } - } - collect_sorted_history_secondary_banks(thread_banks); - thread_banks.clear(); - - simulation::simulation_tracks_completed += settings::n_particles; - - // Phase 2: Now that the secondary bank has been populated, enter loop over - // all secondary generations - int n_generation_depth = 1; - int64_t alive_secondary = 1; - while (alive_secondary) { - - // Synchronize the shared secondary bank amongst all MPI ranks, such - // that each MPI rank has an approximately equal number of secondary - // tracks. Also reports the total number of secondaries alive across - // all MPI ranks. - alive_secondary = synchronize_global_secondary_bank( - simulation::shared_secondary_bank_write); - - // Recalculate work for each MPI rank based on number of alive secondary - // tracks - calculate_work(alive_secondary); - - // Display the number of secondary tracks in this generation. This - // is useful for user monitoring so as to see if the secondary population is - // exploding and to determine how many generations of secondaries are being - // transported. - if (mpi::master) { - write_message(fmt::format(" Secondary generation {:<2} tracks: {}", - n_generation_depth, alive_secondary), - 6); - } - - simulation::shared_secondary_bank_read = - std::move(simulation::shared_secondary_bank_write); - simulation::shared_secondary_bank_write = SharedArray(); - simulation::progeny_per_particle.resize( - simulation::shared_secondary_bank_read.size()); - std::fill(simulation::progeny_per_particle.begin(), - simulation::progeny_per_particle.end(), 0); - thread_banks.resize(num_threads()); - - // Transport all secondary tracks from the shared secondary bank -#pragma omp parallel - { - auto& thread_bank = thread_banks[thread_num()]; - Particle p; - -#pragma omp for schedule(runtime) - for (int64_t i = 1; i <= simulation::shared_secondary_bank_read.size(); - i++) { - initialize_particle_track(p, i, true); - SourceSite& site = simulation::shared_secondary_bank_read[i - 1]; - p.event_revive_from_secondary(site); - transport_history_based_single_particle(p); - for (auto& secondary_site : p.local_secondary_bank()) { - thread_bank.push_back(secondary_site); - } - p.local_secondary_bank().clear(); - } - } // End of transport loop over tracks in shared secondary bank - simulation::shared_secondary_bank_write = - std::move(simulation::shared_secondary_bank_read); - simulation::shared_secondary_bank_read = SharedArray(); - collect_sorted_history_secondary_banks(thread_banks); - thread_banks.clear(); - n_generation_depth++; - simulation::simulation_tracks_completed += alive_secondary; - } // End of loop over secondary generations - - // Reset work so that fission bank etc works correctly - calculate_work(settings::n_particles); -} - void transport_event_based() { int64_t remaining_work = simulation::work_per_rank; @@ -1120,7 +726,33 @@ void transport_event_based() // Initialize all particle histories for this subiteration process_init_events(n_particles, source_offset); - process_transport_events(); + + // Event-based transport loop + while (true) { + // Determine which event kernel has the longest queue + int64_t max = std::max({simulation::calculate_fuel_xs_queue.size(), + simulation::calculate_nonfuel_xs_queue.size(), + simulation::advance_particle_queue.size(), + simulation::surface_crossing_queue.size(), + simulation::collision_queue.size()}); + + // Execute event with the longest queue + if (max == 0) { + break; + } else if (max == simulation::calculate_fuel_xs_queue.size()) { + process_calculate_xs_events(simulation::calculate_fuel_xs_queue); + } else if (max == simulation::calculate_nonfuel_xs_queue.size()) { + process_calculate_xs_events(simulation::calculate_nonfuel_xs_queue); + } else if (max == simulation::advance_particle_queue.size()) { + process_advance_particle_events(); + } else if (max == simulation::surface_crossing_queue.size()) { + process_surface_crossing_events(); + } else if (max == simulation::collision_queue.size()) { + process_collision_events(); + } + } + + // Execute death event for all particles process_death_events(n_particles); // Adjust remaining work and source offset variables @@ -1129,110 +761,4 @@ void transport_event_based() } } -void transport_event_based_shared_secondary() -{ - // Clear shared secondary banks from any prior use - simulation::shared_secondary_bank_read.clear(); - simulation::shared_secondary_bank_write.clear(); - - if (mpi::master) { - write_message(fmt::format(" Primary source particles: {}", - settings::n_particles), - 6); - } - - simulation::progeny_per_particle.resize(simulation::work_per_rank); - std::fill(simulation::progeny_per_particle.begin(), - simulation::progeny_per_particle.end(), 0); - - // Phase 1: Transport primary particles using event-based processing and - // deposit first generation of secondaries in the shared secondary bank - int64_t remaining_work = simulation::work_per_rank; - int64_t source_offset = 0; - - while (remaining_work > 0) { - int64_t n_particles = - std::min(remaining_work, settings::max_particles_in_flight); - - process_init_events(n_particles, source_offset); - process_transport_events(); - process_death_events(n_particles); - - collect_event_secondary_banks(n_particles); - - remaining_work -= n_particles; - source_offset += n_particles; - } - - simulation::simulation_tracks_completed += settings::n_particles; - - // Phase 2: Now that the secondary bank has been populated, enter loop over - // all secondary generations - int n_generation_depth = 1; - int64_t alive_secondary = 1; - while (alive_secondary) { - - // Sort the shared secondary bank by parent ID then progeny ID to - // ensure reproducibility. - sort_bank(simulation::shared_secondary_bank_write, false); - - // Synchronize the shared secondary bank amongst all MPI ranks, such - // that each MPI rank has an approximately equal number of secondary - // tracks. - alive_secondary = synchronize_global_secondary_bank( - simulation::shared_secondary_bank_write); - - // Recalculate work for each MPI rank based on number of alive secondary - // tracks - calculate_work(alive_secondary); - - if (mpi::master) { - write_message(fmt::format(" Secondary generation {:<2} tracks: {}", - n_generation_depth, alive_secondary), - 6); - } - - simulation::shared_secondary_bank_read = - std::move(simulation::shared_secondary_bank_write); - simulation::shared_secondary_bank_write = SharedArray(); - simulation::progeny_per_particle.resize( - simulation::shared_secondary_bank_read.size()); - std::fill(simulation::progeny_per_particle.begin(), - simulation::progeny_per_particle.end(), 0); - - // Ensure particle buffer is large enough for this secondary generation - int64_t sec_buffer_length = std::min( - static_cast(simulation::shared_secondary_bank_read.size()), - settings::max_particles_in_flight); - if (sec_buffer_length > - static_cast(simulation::particles.size())) { - init_event_queues(sec_buffer_length); - } - - // Transport secondary tracks using event-based processing - int64_t sec_remaining = simulation::shared_secondary_bank_read.size(); - int64_t sec_offset = 0; - - while (sec_remaining > 0) { - int64_t n_particles = - std::min(sec_remaining, settings::max_particles_in_flight); - - process_init_secondary_events( - n_particles, sec_offset, simulation::shared_secondary_bank_read); - process_transport_events(); - process_death_events(n_particles); - - collect_event_secondary_banks(n_particles); - - sec_remaining -= n_particles; - sec_offset += n_particles; - } // End of subiteration loop over secondary tracks - n_generation_depth++; - simulation::simulation_tracks_completed += alive_secondary; - } // End of loop over secondary generations - - // Reset work so that fission bank etc works correctly - calculate_work(settings::n_particles); -} - } // namespace openmc diff --git a/src/source.cpp b/src/source.cpp index 12bbdf84e..3716720df 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -4,61 +4,35 @@ #define HAS_DYNAMIC_LINKING #endif -#include // for max -#include // for sin, cos, abs -#include // for move +#include // for move #ifdef HAS_DYNAMIC_LINKING #include // for dlopen, dlsym, dlclose, dlerror #endif -#include "openmc/tensor.h" +#include "xtensor/xadapt.hpp" #include #include "openmc/bank.h" #include "openmc/capi.h" #include "openmc/cell.h" -#include "openmc/constants.h" -#include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" -#include "openmc/geometry.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" -#include "openmc/math_functions.h" -#include "openmc/mcpl_interface.h" #include "openmc/memory.h" #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" -#include "openmc/random_dist.h" #include "openmc/random_lcg.h" #include "openmc/search.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/state_point.h" -#include "openmc/string_utils.h" #include "openmc/xml_interface.h" namespace openmc { -std::atomic source_n_accept {0}; -std::atomic source_n_reject {0}; - -namespace { - -void validate_particle_type(ParticleType type, const std::string& context) -{ - if (type.is_transportable()) - return; - - fatal_error( - fmt::format("Unsupported source particle type '{}' (PDG {}) in {}.", - type.str(), type.pdg_number(), context)); -} - -} // namespace - //============================================================================== // Global variables //============================================================================== @@ -66,242 +40,6 @@ void validate_particle_type(ParticleType type, const std::string& context) namespace model { vector> external_sources; - -vector> adjoint_sources; - -DiscreteIndex external_sources_probability; - -} // namespace model - -//============================================================================== -// Source implementation -//============================================================================== - -Source::Source(pugi::xml_node node) -{ - // Check for source strength - if (check_for_node(node, "strength")) { - strength_ = std::stod(get_node_value(node, "strength")); - if (strength_ < 0.0) { - fatal_error("Source strength is negative."); - } - } - - // Check for additional defined constraints - read_constraints(node); -} - -unique_ptr Source::create(pugi::xml_node node) -{ - // if the source type is present, use it to determine the type - // of object to create - if (check_for_node(node, "type")) { - std::string source_type = get_node_value(node, "type"); - if (source_type == "independent") { - return make_unique(node); - } else if (source_type == "file") { - return make_unique(node); - } else if (source_type == "compiled") { - return make_unique(node); - } else if (source_type == "mesh") { - return make_unique(node); - } else if (source_type == "tokamak") { - return make_unique(node); - } else { - fatal_error(fmt::format("Invalid source type '{}' found.", source_type)); - } - } else { - // support legacy source format - if (check_for_node(node, "file")) { - return make_unique(node); - } else if (check_for_node(node, "library")) { - return make_unique(node); - } else { - return make_unique(node); - } - } -} - -void Source::read_constraints(pugi::xml_node node) -{ - // Check for constraints node. For backwards compatibility, if no constraints - // node is given, still try searching for domain constraints from top-level - // node. - pugi::xml_node constraints_node = node.child("constraints"); - if (constraints_node) { - node = constraints_node; - } - - // Check for domains to reject from - if (check_for_node(node, "domain_type")) { - std::string domain_type = get_node_value(node, "domain_type"); - if (domain_type == "cell") { - domain_type_ = DomainType::CELL; - } else if (domain_type == "material") { - domain_type_ = DomainType::MATERIAL; - } else if (domain_type == "universe") { - domain_type_ = DomainType::UNIVERSE; - } else { - fatal_error( - std::string("Unrecognized domain type for constraint: " + domain_type)); - } - - auto ids = get_node_array(node, "domain_ids"); - domain_ids_.insert(ids.begin(), ids.end()); - } - - if (check_for_node(node, "time_bounds")) { - auto ids = get_node_array(node, "time_bounds"); - if (ids.size() != 2) { - fatal_error("Time bounds must be represented by two numbers."); - } - time_bounds_ = std::make_pair(ids[0], ids[1]); - } - if (check_for_node(node, "energy_bounds")) { - auto ids = get_node_array(node, "energy_bounds"); - if (ids.size() != 2) { - fatal_error("Energy bounds must be represented by two numbers."); - } - energy_bounds_ = std::make_pair(ids[0], ids[1]); - } - - if (check_for_node(node, "fissionable")) { - only_fissionable_ = get_node_value_bool(node, "fissionable"); - } - - // Check for how to handle rejected particles - if (check_for_node(node, "rejection_strategy")) { - std::string rejection_strategy = get_node_value(node, "rejection_strategy"); - if (rejection_strategy == "kill") { - rejection_strategy_ = RejectionStrategy::KILL; - } else if (rejection_strategy == "resample") { - rejection_strategy_ = RejectionStrategy::RESAMPLE; - } else { - fatal_error(std::string( - "Unrecognized strategy source rejection: " + rejection_strategy)); - } - } -} - -void check_rejection_fraction(int64_t n_reject, int64_t n_accept) -{ - // Don't check unless we've hit a minimum number of total sites rejected - if (n_reject < EXTSRC_REJECT_THRESHOLD) - return; - - // Compute fraction of accepted sites and compare against minimum - double fraction = static_cast(n_accept) / n_reject; - if (fraction <= settings::source_rejection_fraction) { - fatal_error(fmt::format( - "Too few source sites satisfied the constraints (minimum source " - "rejection fraction = {}). Please check your source definition or " - "set a lower value of Settings.source_rejection_fraction.", - settings::source_rejection_fraction)); - } -} - -SourceSite Source::sample_with_constraints(uint64_t* seed) const -{ - bool accepted = false; - int64_t n_local_reject = 0; - SourceSite site {}; - - while (!accepted) { - // Sample a source site without considering constraints yet - site = this->sample(seed); - - if (constraints_applied()) { - accepted = true; - } else { - // Check whether sampled site satisfies constraints - accepted = satisfies_spatial_constraints(site.r) && - satisfies_energy_constraints(site.E) && - satisfies_time_constraints(site.time); - if (!accepted) { - ++n_local_reject; - - // Check per-particle rejection limit - if (n_local_reject >= MAX_SOURCE_REJECTIONS_PER_SAMPLE) { - fatal_error("Exceeded maximum number of source rejections per " - "sample. Please check your source definition."); - } - - // For the "kill" strategy, accept particle but set weight to 0 so that - // it is terminated immediately - if (rejection_strategy_ == RejectionStrategy::KILL) { - accepted = true; - site.wgt = 0.0; - } - } - } - } - - // Flush local rejection count, update accept counter, and check overall - // rejection fraction - if (n_local_reject > 0) { - source_n_reject += n_local_reject; - } - ++source_n_accept; - check_rejection_fraction(source_n_reject, source_n_accept); - - return site; -} - -bool Source::satisfies_energy_constraints(double E) const -{ - return E > energy_bounds_.first && E < energy_bounds_.second; -} - -bool Source::satisfies_time_constraints(double time) const -{ - return time > time_bounds_.first && time < time_bounds_.second; -} - -bool Source::satisfies_spatial_constraints(Position r) const -{ - GeometryState geom_state; - geom_state.r() = r; - geom_state.u() = {0.0, 0.0, 1.0}; - - // Reject particle if it's not in the geometry at all - bool found = exhaustive_find_cell(geom_state); - if (!found) - return false; - - // Check the geometry state against specified domains - bool accepted = true; - if (!domain_ids_.empty()) { - if (domain_type_ == DomainType::MATERIAL) { - auto mat_index = geom_state.material(); - if (mat_index == MATERIAL_VOID) { - accepted = false; - } else { - accepted = contains(domain_ids_, model::materials[mat_index]->id()); - } - } else { - for (int i = 0; i < geom_state.n_coord(); i++) { - auto id = - (domain_type_ == DomainType::CELL) - ? model::cells[geom_state.coord(i).cell()].get()->id_ - : model::universes[geom_state.coord(i).universe()].get()->id_; - if ((accepted = contains(domain_ids_, id))) - break; - } - } - } - - // Check if spatial site is in fissionable material - if (accepted && only_fissionable_) { - // Determine material - auto mat_index = geom_state.material(); - if (mat_index == MATERIAL_VOID) { - accepted = false; - } else { - accepted = model::materials[mat_index]->fissionable(); - } - } - - return accepted; } //============================================================================== @@ -314,19 +52,25 @@ IndependentSource::IndependentSource( energy_ {std::move(energy)}, time_ {std::move(time)} {} -IndependentSource::IndependentSource(pugi::xml_node node) : Source(node) +IndependentSource::IndependentSource(pugi::xml_node node) { // Check for particle type if (check_for_node(node, "particle")) { - auto temp_str = get_node_value(node, "particle", false, true); - particle_ = ParticleType(temp_str); - if (particle_ == ParticleType::photon() || - particle_ == ParticleType::electron() || - particle_ == ParticleType::positron()) { + auto temp_str = get_node_value(node, "particle", true, true); + if (temp_str == "neutron") { + particle_ = ParticleType::neutron; + } else if (temp_str == "photon") { + particle_ = ParticleType::photon; settings::photon_transport = true; + } else { + fatal_error(std::string("Unknown source particle type: ") + temp_str); } } - validate_particle_type(particle_, "IndependentSource"); + + // Check for source strength + if (check_for_node(node, "strength")) { + strength_ = std::stod(get_node_value(node, "strength")); + } // Check for external source file if (check_for_node(node, "file")) { @@ -335,24 +79,55 @@ IndependentSource::IndependentSource(pugi::xml_node node) : Source(node) // Spatial distribution for external source if (check_for_node(node, "space")) { - space_ = SpatialDistribution::create(node.child("space")); + // Get pointer to spatial distribution + pugi::xml_node node_space = node.child("space"); + + // Check for type of spatial distribution and read + std::string type; + if (check_for_node(node_space, "type")) + type = get_node_value(node_space, "type", true, true); + if (type == "cartesian") { + space_ = UPtrSpace {new CartesianIndependent(node_space)}; + } else if (type == "cylindrical") { + space_ = UPtrSpace {new CylindricalIndependent(node_space)}; + } else if (type == "spherical") { + space_ = UPtrSpace {new SphericalIndependent(node_space)}; + } else if (type == "box") { + space_ = UPtrSpace {new SpatialBox(node_space)}; + } else if (type == "fission") { + space_ = UPtrSpace {new SpatialBox(node_space, true)}; + } else if (type == "point") { + space_ = UPtrSpace {new SpatialPoint(node_space)}; + } else { + fatal_error(fmt::format( + "Invalid spatial distribution for external source: {}", type)); + } + } else { // If no spatial distribution specified, make it a point source space_ = UPtrSpace {new SpatialPoint()}; } - // For backwards compatibility, check for only fissionable setting on box - // source - auto space_box = dynamic_cast(space_.get()); - if (space_box) { - if (!only_fissionable_) { - only_fissionable_ = space_box->only_fissionable(); - } - } - // Determine external source angular distribution if (check_for_node(node, "angle")) { - angle_ = UnitSphereDistribution::create(node.child("angle")); + // Get pointer to angular distribution + pugi::xml_node node_angle = node.child("angle"); + + // Check for type of angular distribution + std::string type; + if (check_for_node(node_angle, "type")) + type = get_node_value(node_angle, "type", true, true); + if (type == "isotropic") { + angle_ = UPtrAngle {new Isotropic()}; + } else if (type == "monodirectional") { + angle_ = UPtrAngle {new Monodirectional(node_angle)}; + } else if (type == "mu-phi") { + angle_ = UPtrAngle {new PolarAzimuthal(node_angle)}; + } else { + fatal_error(fmt::format( + "Invalid angular distribution for external source: {}", type)); + } + } else { angle_ = UPtrAngle {new Isotropic()}; } @@ -361,19 +136,6 @@ IndependentSource::IndependentSource(pugi::xml_node node) : Source(node) if (check_for_node(node, "energy")) { pugi::xml_node node_dist = node.child("energy"); energy_ = distribution_from_xml(node_dist); - - // For decay photon sources, use the absolute photon emission rate in - // [photons/s] as the source strength - if (dynamic_cast(energy_.get())) { - if (strength_ != 1.0) { - warning(fmt::format( - "Source strength of {} is ignored because the source uses a " - "DecaySpectrum energy distribution. The source strength will be " - "set from the DecaySpectrum emission rate.", - strength_)); - } - strength_ = energy_->integral(); - } } else { // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1 energy_ = UPtrDist {new Watt(0.988e6, 2.249e-6)}; @@ -394,94 +156,88 @@ IndependentSource::IndependentSource(pugi::xml_node node) : Source(node) SourceSite IndependentSource::sample(uint64_t* seed) const { - SourceSite site {}; - site.particle = particle_; - double r_wgt = 1.0; - double E_wgt = 1.0; + SourceSite site; - // Repeat sampling source location until a good site has been accepted - bool accepted = false; - int64_t n_local_reject = 0; - - while (!accepted) { + // Repeat sampling source location until a good site has been found + bool found = false; + int n_reject = 0; + static int n_accept = 0; + while (!found) { + // Set particle type + site.particle = particle_; // Sample spatial distribution - auto [r, r_wgt_temp] = space_->sample(seed); - site.r = r; - r_wgt = r_wgt_temp; + site.r = space_->sample(seed); - // Check if sampled position satisfies spatial constraints - accepted = satisfies_spatial_constraints(site.r); + // Now search to see if location exists in geometry + int32_t cell_index, instance; + double xyz[] {site.r.x, site.r.y, site.r.z}; + int err = openmc_find_cell(xyz, &cell_index, &instance); + found = (err != OPENMC_E_GEOMETRY); + + // Check if spatial site is in fissionable material + if (found) { + auto space_box = dynamic_cast(space_.get()); + if (space_box) { + if (space_box->only_fissionable()) { + // Determine material + const auto& c = model::cells[cell_index]; + auto mat_index = + c->material_.size() == 1 ? c->material_[0] : c->material_[instance]; + + if (mat_index == MATERIAL_VOID) { + found = false; + } else { + if (!model::materials[mat_index]->fissionable_) + found = false; + } + } + } + } // Check for rejection - if (!accepted) { - ++n_local_reject; - if (n_local_reject >= MAX_SOURCE_REJECTIONS_PER_SAMPLE) { - fatal_error("Exceeded maximum number of source rejections per " - "sample. Please check your source definition."); + if (!found) { + ++n_reject; + if (n_reject >= EXTSRC_REJECT_THRESHOLD && + static_cast(n_accept) / n_reject <= EXTSRC_REJECT_FRACTION) { + fatal_error("More than 95% of external source sites sampled were " + "rejected. Please check your external source definition."); } } } + // Increment number of accepted samples + ++n_accept; + // Sample angle - auto [u, u_wgt] = angle_->sample(seed); - site.u = u; + site.u = angle_->sample(seed); - site.wgt = r_wgt * u_wgt; - - // Sample energy and time for neutron and photon sources - if (settings::solver_type != SolverType::RANDOM_RAY) { - // Check for monoenergetic source above maximum particle energy - auto p = particle_.transport_index(); - auto energy_ptr = dynamic_cast(energy_.get()); - auto decay_spectrum = dynamic_cast(energy_.get()); - if (energy_ptr) { - auto energies = - tensor::Tensor(energy_ptr->x().data(), energy_ptr->x().size()); - if ((energies > data::energy_max[p]).any()) { - fatal_error("Source energy above range of energies of at least " - "one cross section table"); - } + // Check for monoenergetic source above maximum particle energy + auto p = static_cast(particle_); + auto energy_ptr = dynamic_cast(energy_.get()); + if (energy_ptr) { + auto energies = xt::adapt(energy_ptr->x()); + if (xt::any(energies > data::energy_max[p])) { + fatal_error("Source energy above range of energies of at least " + "one cross section table"); + } else if (xt::any(energies < data::energy_min[p])) { + fatal_error("Source energy below range of energies of at least " + "one cross section table"); } - - while (true) { - // Sample energy spectrum. For decay photon sources, also get the parent - // nuclide index to store in the source site for tallying purposes. - if (decay_spectrum) { - auto sample = decay_spectrum->sample_with_parent(seed); - site.E = sample.energy; - E_wgt = sample.weight; - site.parent_nuclide = sample.parent_nuclide; - } else { - auto [E, E_wgt_temp] = energy_->sample(seed); - site.E = E; - E_wgt = E_wgt_temp; - } - - // Resample if energy falls above maximum particle energy - if (site.E < data::energy_max[p] && - (satisfies_energy_constraints(site.E))) - break; - - ++n_local_reject; - if (n_local_reject >= MAX_SOURCE_REJECTIONS_PER_SAMPLE) { - fatal_error("Exceeded maximum number of source rejections per " - "sample. Please check your source definition."); - } - } - - // Sample particle creation time - auto [time, time_wgt] = time_->sample(seed); - site.time = time; - - site.wgt *= (E_wgt * time_wgt); } - // Flush local rejection count into global counter - if (n_local_reject > 0) { - source_n_reject += n_local_reject; + while (true) { + // Sample energy spectrum + site.E = energy_->sample(seed); + + // Resample if energy falls outside minimum or maximum particle energy + if (site.E < data::energy_max[p] && site.E > data::energy_min[p]) + break; } + // Sample particle creation time + site.time = time_->sample(seed); + return site; } @@ -489,84 +245,46 @@ SourceSite IndependentSource::sample(uint64_t* seed) const // FileSource implementation //============================================================================== -FileSource::FileSource(pugi::xml_node node) : Source(node) +FileSource::FileSource(std::string path) { - auto path = get_node_value(node, "file", false, true); - load_sites_from_file(path); -} - -FileSource::FileSource(const std::string& path) -{ - load_sites_from_file(path); -} - -void FileSource::load_sites_from_file(const std::string& path) -{ - // If MCPL file, use the dedicated file reader - if (ends_with(path, ".mcpl") || ends_with(path, ".mcpl.gz")) { - sites_ = mcpl_source_sites(path); - } else { - // Check if source file exists - if (!file_exists(path)) { - fatal_error(fmt::format("Source file '{}' does not exist.", path)); - } - - write_message(6, "Reading source file from {}...", path); - - // Open the binary file - hid_t file_id = file_open(path, 'r', true); - - // Check to make sure this is a source file - std::string filetype; - read_attribute(file_id, "filetype", filetype); - if (filetype != "source" && filetype != "statepoint") { - fatal_error("Specified starting source file not a source file type."); - } - - // Read in the source particles - read_source_bank(file_id, sites_, false); - - // Close file - file_close(file_id); + // Check if source file exists + if (!file_exists(path)) { + fatal_error(fmt::format("Source file '{}' does not exist.", path)); } - // Make sure particles in source file have valid types. If any particle is a - // photon, electron, or positron, enable photon transport so that the - // appropriate cross sections are loaded. - for (const auto& site : this->sites_) { - validate_particle_type(site.particle, "FileSource"); - if (site.particle == ParticleType::photon() || - site.particle == ParticleType::electron() || - site.particle == ParticleType::positron()) { - settings::photon_transport = true; - } + // Read the source from a binary file instead of sampling from some + // assumed source distribution + write_message(6, "Reading source file from {}...", path); + + // Open the binary file + hid_t file_id = file_open(path, 'r', true); + + // Check to make sure this is a source file + std::string filetype; + read_attribute(file_id, "filetype", filetype); + if (filetype != "source" && filetype != "statepoint") { + fatal_error("Specified starting source file not a source file type."); } + + // Read in the source particles + read_source_bank(file_id, sites_, false); + + // Close file + file_close(file_id); } SourceSite FileSource::sample(uint64_t* seed) const { - // Sample a particle randomly from list size_t i_site = sites_.size() * prn(seed); return sites_[i_site]; } //============================================================================== -// CompiledSourceWrapper implementation +// CustomSourceWrapper implementation //============================================================================== -CompiledSourceWrapper::CompiledSourceWrapper(pugi::xml_node node) : Source(node) -{ - // Get shared library path and parameters - auto path = get_node_value(node, "library", false, true); - std::string parameters; - if (check_for_node(node, "parameters")) { - parameters = get_node_value(node, "parameters", false, true); - } - setup(path, parameters); -} - -void CompiledSourceWrapper::setup( - const std::string& path, const std::string& parameters) +CustomSourceWrapper::CustomSourceWrapper( + std::string path, std::string parameters) { #ifdef HAS_DYNAMIC_LINKING // Open the library @@ -579,7 +297,7 @@ void CompiledSourceWrapper::setup( dlerror(); // get the function to create the custom source from the library - auto create_compiled_source = reinterpret_cast( + auto create_custom_source = reinterpret_cast( dlsym(shared_library_, "openmc_create_source")); // check for any dlsym errors @@ -592,7 +310,7 @@ void CompiledSourceWrapper::setup( } // create a pointer to an instance of the custom source - compiled_source_ = create_compiled_source(parameters); + custom_source_ = create_custom_source(parameters); #else fatal_error("Custom source libraries have not yet been implemented for " @@ -600,11 +318,11 @@ void CompiledSourceWrapper::setup( #endif } -CompiledSourceWrapper::~CompiledSourceWrapper() +CustomSourceWrapper::~CustomSourceWrapper() { // Make sure custom source is cleared before closing shared library - if (compiled_source_.get()) - compiled_source_.reset(); + if (custom_source_.get()) + custom_source_.reset(); #ifdef HAS_DYNAMIC_LINKING dlclose(shared_library_); @@ -614,537 +332,6 @@ CompiledSourceWrapper::~CompiledSourceWrapper() #endif } -//============================================================================== -// MeshElementSpatial implementation -//============================================================================== - -std::pair MeshElementSpatial::sample(uint64_t* seed) const -{ - return {model::meshes[mesh_index_]->sample_element(elem_index_, seed), 1.0}; -} - -//============================================================================== -// MeshSource implementation -//============================================================================== - -MeshSource::MeshSource(pugi::xml_node node) : Source(node) -{ - int32_t mesh_id = stoi(get_node_value(node, "mesh")); - int32_t mesh_idx = model::mesh_map.at(mesh_id); - const auto& mesh = model::meshes[mesh_idx]; - - std::vector strengths; - // read all source distributions and populate strengths vector for MeshSpatial - // object - for (auto source_node : node.children("source")) { - auto src = Source::create(source_node); - if (auto ptr = dynamic_cast(src.get())) { - src.release(); - sources_.emplace_back(ptr); - } else { - fatal_error( - "The source assigned to each element must be an IndependentSource."); - } - strengths.push_back(sources_.back()->strength()); - } - - // Set spatial distributions for each mesh element - for (int elem_index = 0; elem_index < sources_.size(); ++elem_index) { - sources_[elem_index]->set_space( - std::make_unique(mesh_idx, elem_index)); - } - - // Make sure sources use valid particle types - for (const auto& src : sources_) { - validate_particle_type(src->particle_type(), "MeshSource"); - } - - // the number of source distributions should either be one or equal to the - // number of mesh elements - if (sources_.size() > 1 && sources_.size() != mesh->n_bins()) { - fatal_error(fmt::format("Incorrect number of source distributions ({}) for " - "mesh source with {} elements.", - sources_.size(), mesh->n_bins())); - } - - space_ = std::make_unique(mesh_idx, strengths); -} - -SourceSite MeshSource::sample(uint64_t* seed) const -{ - // Sample a mesh element based on the relative strengths - int32_t element = space_->sample_element_index(seed); - - // Sample the distribution for the specific mesh element; note that the - // spatial distribution has been set for each element using MeshElementSpatial - return source(element)->sample_with_constraints(seed); -} - -//============================================================================== -// TokamakSource implementation -//============================================================================== - -TokamakSource::TokamakSource(pugi::xml_node node) : Source(node) -{ - // Read geometry parameters - major_radius_ = std::stod(get_node_value(node, "major_radius")); - minor_radius_ = std::stod(get_node_value(node, "minor_radius")); - elongation_ = std::stod(get_node_value(node, "elongation")); - triangularity_ = std::stod(get_node_value(node, "triangularity")); - shafranov_shift_ = std::stod(get_node_value(node, "shafranov_shift")); - - // Read optional vertical shift - if (check_for_node(node, "vertical_shift")) { - vertical_shift_ = std::stod(get_node_value(node, "vertical_shift")); - } else { - vertical_shift_ = 0.0; - } - - // Read optional toroidal angle bounds - if (check_for_node(node, "phi_start")) { - phi_start_ = std::stod(get_node_value(node, "phi_start")); - } else { - phi_start_ = 0.0; - } - if (check_for_node(node, "phi_extent")) { - phi_extent_ = std::stod(get_node_value(node, "phi_extent")); - } else { - phi_extent_ = 2.0 * PI; - } - if (check_for_node(node, "n_alpha")) { - n_alpha_ = std::stoi(get_node_value(node, "n_alpha")); - } else { - n_alpha_ = 101; // Default - } - - // Read emission profile - r_over_a_ = get_node_array(node, "r_over_a"); - emission_density_ = get_node_array(node, "emission_density"); - - // Read energy distribution(s) - for (auto energy_node : node.children("energy")) { - energy_dists_.push_back(distribution_from_xml(energy_node)); - } - - // Read optional time distribution; default to a delta distribution at t=0 - // for the same behavior as IndependentSource - if (check_for_node(node, "time")) { - time_ = distribution_from_xml(node.child("time")); - } else { - double T[] {0.0}; - double p[] {1.0}; - time_ = UPtrDist {new Discrete {T, p, 1}}; - } - - // Validate inputs - if (emission_density_.size() != r_over_a_.size()) { - fatal_error("TokamakSource: emission_density and r_over_a must have the " - "same length."); - } - if (r_over_a_.size() < 2) { - fatal_error( - "TokamakSource: At least 2 radial points are required for profiles."); - } - if (r_over_a_.front() != 0.0) { - fatal_error("TokamakSource: r_over_a must start at 0."); - } - if (r_over_a_.back() != 1.0) { - fatal_error("TokamakSource: r_over_a must end at 1."); - } - for (size_t i = 1; i < r_over_a_.size(); ++i) { - if (r_over_a_[i] <= r_over_a_[i - 1]) { - fatal_error("TokamakSource: r_over_a must be strictly increasing."); - } - } - for (size_t i = 0; i < emission_density_.size(); ++i) { - if (emission_density_[i] < 0.0) { - fatal_error("TokamakSource: emission_density values cannot be negative."); - } - } - if (major_radius_ <= 0.0) { - fatal_error("TokamakSource: major_radius must be > 0."); - } - if (minor_radius_ <= 0.0) { - fatal_error("TokamakSource: minor_radius must be > 0."); - } - if (minor_radius_ >= major_radius_) { - fatal_error("TokamakSource: minor_radius must be less than major_radius."); - } - if (elongation_ <= 0.0) { - fatal_error("TokamakSource: elongation must be > 0."); - } - if (triangularity_ < -1.0 || triangularity_ > 1.0) { - fatal_error("TokamakSource: triangularity must be in the range [-1, 1]."); - } - if (shafranov_shift_ < 0.0) { - fatal_error("TokamakSource: shafranov_shift must be >= 0."); - } - if (shafranov_shift_ >= 0.5 * minor_radius_) { - fatal_error("TokamakSource: shafranov_shift must be less than half the " - "minor radius."); - } - if (phi_extent_ <= 0.0 || phi_extent_ > 2.0 * PI) { - fatal_error("TokamakSource: phi_extent must be > 0 and <= 2*pi."); - } - if (n_alpha_ <= 2) { - fatal_error("TokamakSource: n_alpha must be > 2."); - } - if (n_alpha_ < 51) { - warning("TokamakSource: n_alpha values below 51 may introduce noticeable " - "discretization bias in source sampling."); - } - if (energy_dists_.empty()) { - fatal_error("TokamakSource: At least one energy distribution is required."); - } - if (energy_dists_.size() != 1 && energy_dists_.size() != r_over_a_.size()) { - fatal_error("TokamakSource: energy distributions must be either 1 (for all " - "r) or match the number of r_over_a points."); - } - - // Compute normalized geometry parameters - epsilon_ = minor_radius_ / major_radius_; - delta_tilde_ = shafranov_shift_ / minor_radius_; - - // Initialize isotropic angular distribution - angle_ = UPtrAngle {new Isotropic()}; - - precompute_sampling_distributions(); -} - -void TokamakSource::precompute_sampling_distributions() -{ - // Use precomputed normalized geometry parameters - double eps = epsilon_; // Inverse aspect ratio (a/R0) - double Dt = delta_tilde_; // Normalized Shafranov shift (Delta/a) - double delta = triangularity_; - - //========================================================================== - // RADIAL CDF (computed first since it's simpler and sampled first) - //========================================================================== - // The marginal radial PDF is obtained by analytically integrating the joint - // distribution f(r_tilde, alpha) over alpha. The result is: - // - // p(r_tilde) ~ S(r_tilde) * [(1 + eps*Dt)*r_tilde - // - (3/8)*c1*eps*r_tilde^2 - // - 2*eps*Dt*r_tilde^3] - // - // where the Bessel function coefficients are: - // c0 = J_0(delta) + J_2(delta) - // c1 = (J_1(2*delta) + J_3(2*delta)) / c0 - // - // For delta -> 0, c0 -> 1 and c1 -> 0, giving the circular cross-section - // limit. - - // Compute Bessel function coefficients. openmc::cyl_bessel_j handles - // negative arguments (negative triangularity) via the parity relation - // J_n(-x) = (-1)^n * J_n(x). - double J0_d = cyl_bessel_j(0, delta); - double J2_d = cyl_bessel_j(2, delta); - double J1_2d = cyl_bessel_j(1, 2.0 * delta); - double J3_2d = cyl_bessel_j(3, 2.0 * delta); - double c0 = J0_d + J2_d; - double c1 = (J1_2d + J3_2d) / c0; - - // Coefficients for the radial polynomial: A*r - B*r^2 - C*r^3 - radial_poly_a_ = 1.0 + eps * Dt; - radial_poly_b_ = 0.375 * c1 * eps; // 3/8 * c1 * eps - radial_poly_c_ = 2.0 * eps * Dt; - - // Build a refined radial grid that retains the user-specified grid points. - // The emission density is interpreted as linear-linear between those points. - constexpr int MIN_SUBINTERVALS = 8; - constexpr double MAX_GRID_SPACING = 1.0e-3; - vector radial_grid {r_over_a_.front()}; - vector radial_emission {emission_density_.front()}; - for (size_t i = 1; i < r_over_a_.size(); ++i) { - double r_lo = r_over_a_[i - 1]; - double r_hi = r_over_a_[i]; - double s_lo = emission_density_[i - 1]; - double s_hi = emission_density_[i]; - int n_subintervals = std::max(MIN_SUBINTERVALS, - static_cast(std::ceil((r_hi - r_lo) / MAX_GRID_SPACING))); - for (int j = 1; j <= n_subintervals; ++j) { - double t = static_cast(j) / n_subintervals; - radial_grid.push_back(r_lo + t * (r_hi - r_lo)); - radial_emission.push_back(s_lo + t * (s_hi - s_lo)); - } - } - - vector radial_pdf(radial_grid.size()); - for (size_t i = 0; i < radial_grid.size(); ++i) { - double r = radial_grid[i]; - // p(r) ~ S(r) * [A*r - B*r^2 - C*r^3] - double geometric_factor = - radial_poly_a_ * r - radial_poly_b_ * r * r - radial_poly_c_ * r * r * r; - radial_pdf[i] = radial_emission[i] * std::max(0.0, geometric_factor); - } - - // Check that the refined profile contains positive probability mass before - // constructing the normalized tabular distribution. - double total = 0.0; - for (size_t i = 1; i < radial_grid.size(); ++i) { - total += 0.5 * (radial_pdf[i - 1] + radial_pdf[i]) * - (radial_grid[i] - radial_grid[i - 1]); - } - if (total <= 0.0) { - fatal_error( - "TokamakSource: Integrated emission density is zero or negative. " - "Check emission_density profile."); - } - radial_dist_ = make_unique(radial_grid.data(), radial_pdf.data(), - radial_grid.size(), Interpolation::lin_lin); - - //========================================================================== - // POLOIDAL CDFs (for conditional sampling of alpha given r) - //========================================================================== - // The conditional distribution P(alpha | r) is a mixture: - // P(alpha | r) ~ sum_k w_k(r) * I_hat_k * p_k(alpha) - // where: - // - w_k(r) are the "dynamic" Bernstein weight functions (depend on r) - // - I_hat_k are the "static" normalized integrals (precomputed constants) - // - p_k(alpha) are the normalized basis distributions (precomputed CDFs) - // - // The static weights I_hat_k = I_k / (2*pi*c0) are: - // I_hat_0 = 1 + eps*Dt - // I_hat_1 = 1 + eps*Dt - (3/16)*c1*eps - // I_hat_2 = 1 - (3/8)*c1*eps - // I_hat_3 = 1 + eps*Dt - // I_hat_4 = 1 + (1/2)*eps*Dt - (3/16)*c1*eps - // I_hat_5 = 1 - eps*Dt - (3/8)*c1*eps - - // Compute static weights analytically - poloidal_integrals_[0] = 1.0 + eps * Dt; - poloidal_integrals_[1] = 1.0 + eps * Dt - 0.1875 * c1 * eps; // 3/16 = 0.1875 - poloidal_integrals_[2] = 1.0 - 0.375 * c1 * eps; // 3/8 = 0.375 - poloidal_integrals_[3] = 1.0 + eps * Dt; - poloidal_integrals_[4] = 1.0 + 0.5 * eps * Dt - 0.1875 * c1 * eps; - poloidal_integrals_[5] = 1.0 - eps * Dt - 0.375 * c1 * eps; - - // Build the alpha grid on [0, pi] (half domain due to up-down symmetry) - int n_alpha = n_alpha_; - vector alpha_grid(n_alpha); - double dalpha = PI / (n_alpha - 1); - for (int i = 0; i < n_alpha; ++i) { - alpha_grid[i] = i * dalpha; - } - - // Compute basis function values g_k(alpha) for tabular distributions - // Using Bernstein form: - // R_tilde = b0*(1-r)^2 + 2*b1*r*(1-r) + b2*r^2 - // J_tilde = b3*(1-r) + b4*r - // with: - // b0(alpha) = 1 + eps*Dt - // b1(alpha) = b0 + (eps/2)*cos(psi), psi = alpha + delta*sin(alpha) - // b2(alpha) = 1 + eps*cos(psi) - // b3(alpha) = cos(delta*sin(alpha)) - // + (delta/4)*(cos(alpha - delta*sin(alpha)) - // - cos(3*alpha + delta*sin(alpha))) - // b4(alpha) = b3(alpha) - 2*Dt*cos(alpha) - - array, N_POLOIDAL_BASIS> basis; - for (int k = 0; k < N_POLOIDAL_BASIS; ++k) { - basis[k].resize(n_alpha); - } - - for (int i = 0; i < n_alpha; ++i) { - double alpha = alpha_grid[i]; - double sin_alpha = std::sin(alpha); - double cos_alpha = std::cos(alpha); - double delta_sin_alpha = delta * sin_alpha; - double psi = alpha + delta_sin_alpha; - double cos_psi = std::cos(psi); - - // Bernstein coefficients b0-b4 - double b0 = 1.0 + eps * Dt; - double b1 = b0 + 0.5 * eps * cos_psi; - double b2 = 1.0 + eps * cos_psi; - double b3 = - std::cos(delta_sin_alpha) + 0.25 * delta * - (std::cos(alpha - delta_sin_alpha) - - std::cos(3.0 * alpha + delta_sin_alpha)); - double b4 = b3 - 2.0 * Dt * cos_alpha; - - // 6 basis functions g_k(alpha) = b_i * b_j - basis[0][i] = b0 * b3; // w0 = (1-r)^3 - basis[1][i] = b1 * b3; // w1 = 2*r*(1-r)^2 - basis[2][i] = b2 * b3; // w2 = r^2*(1-r) - basis[3][i] = b0 * b4; // w3 = r*(1-r)^2 - basis[4][i] = b1 * b4; // w4 = 2*r^2*(1-r) - basis[5][i] = b2 * b4; // w5 = r^3 - } - - // Build a linear-linear distribution for each basis function p_k(alpha) - for (int k = 0; k < N_POLOIDAL_BASIS; ++k) { - poloidal_dists_[k] = make_unique( - alpha_grid.data(), basis[k].data(), n_alpha, Interpolation::lin_lin); - } -} - -double TokamakSource::sample_r_over_a(uint64_t* seed) const -{ - return radial_dist_->sample(seed).first; -} - -double TokamakSource::mixture_weight(int k, double r) const -{ - double s = 1.0 - r; - switch (k) { - case 0: - return s * s * s * poloidal_integrals_[0]; - case 1: - return 2.0 * r * s * s * poloidal_integrals_[1]; - case 2: - return r * r * s * poloidal_integrals_[2]; - case 3: - return r * s * s * poloidal_integrals_[3]; - case 4: - return 2.0 * r * r * s * poloidal_integrals_[4]; - case 5: - return r * r * r * poloidal_integrals_[5]; - default: - UNREACHABLE(); - } -} - -double TokamakSource::sample_poloidal_angle(double r_norm, uint64_t* seed) const -{ - // Sample from the conditional distribution P(alpha | r_tilde) using - // mixture sampling with 6 precomputed basis distributions. - // - // The conditional is: P(alpha | r) ~ sum_k w_k(r) * I_hat_k * p_k(alpha) - // where: - // - w_k(r) are the "dynamic" Bernstein weight functions - // - I_hat_k are the "static" normalized integrals (precomputed in - // poloidal_integrals_) - // - p_k(alpha) are the normalized, precomputed basis distributions - // - // The normalization sum_k w_k(r) * I_hat_k equals the radial geometric - // polynomial evaluated at r, which is known analytically. - // - // Algorithm: - // 1. Compute total from analytical normalization - // 2. Lazily evaluate mixture weights with early exit to select component k - // 3. Sample alpha from the selected basis distribution - - // Analytical normalization: sum_k w_k(r) * I_hat_k - double total = - radial_poly_a_ - radial_poly_b_ * r_norm - radial_poly_c_ * r_norm * r_norm; - double xi = prn(seed) * total; - - // Sample component via lazy evaluation with early exit - // Order optimized for peaked emission profiles: 0, 1, 4, 5, 3, 2 - constexpr int order[] = {0, 1, 4, 5, 3, 2}; - double cumsum = 0.0; - int component = order[N_POLOIDAL_BASIS - 1]; - for (int i = 0; i < N_POLOIDAL_BASIS; ++i) { - cumsum += mixture_weight(order[i], r_norm); - if (xi < cumsum) { - component = order[i]; - break; - } - } - - // Sample alpha from [0, pi] - double alpha = poloidal_dists_[component]->sample(seed).first; - - // Exploit up-down symmetry: randomly flip to [pi, 2*pi] with 50% probability - // This is equivalent to flipping the sign of Z in the final position - if (prn(seed) >= 0.5) { - alpha = 2.0 * PI - alpha; - } - return alpha; -} - -std::pair TokamakSource::sample_energy( - double r_norm, uint64_t* seed) const -{ - if (energy_dists_.size() == 1) { - // Single distribution for all r - return energy_dists_[0]->sample(seed); - } - - // Multiple distributions: stochastic selection between bracketing r points - // Find the interval containing r_norm - size_t i = lower_bound_index(r_over_a_.begin(), r_over_a_.end(), r_norm); - - // Handle boundary cases - if (i >= energy_dists_.size() - 1) { - return energy_dists_.back()->sample(seed); - } - - // Stochastic interpolation: randomly select one of the two bracketing - // distributions based on distance to each - double t = (r_norm - r_over_a_[i]) / (r_over_a_[i + 1] - r_over_a_[i]); - size_t idx = (prn(seed) < t) ? i + 1 : i; - return energy_dists_[idx]->sample(seed); -} - -Position TokamakSource::flux_to_cartesian( - double r, double alpha, double phi) const -{ - // Flux surface parameterization: - // R = R0 + r*cos(alpha + delta*sin(alpha)) + Delta*(1 - (r/a)^2) - // Z = kappa * r * sin(alpha) - // x = R * cos(phi) - // y = R * sin(phi) - // z = Z - - double psi = alpha + triangularity_ * std::sin(alpha); - double r_over_a_sq = (r * r) / (minor_radius_ * minor_radius_); - - double R = - major_radius_ + r * std::cos(psi) + shafranov_shift_ * (1.0 - r_over_a_sq); - double Z = elongation_ * r * std::sin(alpha); - - double x = R * std::cos(phi); - double y = R * std::sin(phi); - double z = Z; - - return {x, y, z}; -} - -SourceSite TokamakSource::sample(uint64_t* seed) const -{ - SourceSite site; - site.particle = ParticleType::neutron(); - site.wgt = 1.0; - site.delayed_group = 0; - - // 1. Sample r/a from radial CDF - double r_norm = sample_r_over_a(seed); - double r = r_norm * minor_radius_; - - // 2. Sample poloidal angle from conditional distribution P(alpha|r) - double alpha = sample_poloidal_angle(r_norm, seed); - - // 3. Sample toroidal angle uniformly in [phi_start, phi_start + phi_extent] - double phi = phi_start_ + phi_extent_ * prn(seed); - - // 4. Convert to Cartesian coordinates - site.r = flux_to_cartesian(r, alpha, phi); - - // 4a. Apply vertical shift if non-zero - if (vertical_shift_ != 0.0) { - site.r.z += vertical_shift_; - } - - // 5. Sample isotropic direction - site.u = angle_->sample(seed).first; - - // 6. Sample energy from distribution(s), applying the importance weight so - // that biased distributions are handled correctly - auto [E, E_wgt] = sample_energy(r_norm, seed); - site.E = E; - - // 7. Sample particle creation time - auto [time, time_wgt] = time_->sample(seed); - site.time = time; - - site.wgt *= E_wgt * time_wgt; - - return site; -} - //============================================================================== // Non-member functions //============================================================================== @@ -1170,35 +357,32 @@ void initialize_source() write_message("Writing out initial source...", 5); std::string filename = settings::path_output + "initial_source.h5"; hid_t file_id = file_open(filename, 'w', true); - write_source_bank(file_id, simulation::source_bank, simulation::work_index); + write_source_bank(file_id, false); file_close(file_id); } } SourceSite sample_external_source(uint64_t* seed) { + // Determine total source strength + double total_strength = 0.0; + for (auto& s : model::external_sources) + total_strength += s->strength(); + // Sample from among multiple source distributions int i = 0; - int n_sources = model::external_sources.size(); - if (n_sources > 1) { - if (settings::uniform_source_sampling) { - i = prn(seed) * n_sources; - } else { - i = model::external_sources_probability.sample(seed); + if (model::external_sources.size() > 1) { + double xi = prn(seed) * total_strength; + double c = 0.0; + for (; i < model::external_sources.size(); ++i) { + c += model::external_sources[i]->strength(); + if (xi < c) + break; } } // Sample source site from i-th source distribution - SourceSite site {model::external_sources[i]->sample_with_constraints(seed)}; - - // For uniform source sampling, multiply the weight by the ratio of the actual - // probability of sampling source i to the biased probability of sampling - // source i, which is (strength_i / total_strength) / (1 / n) - if (n_sources > 1 && settings::uniform_source_sampling) { - double total_strength = model::external_sources_probability.integral(); - site.wgt *= - model::external_sources[i]->strength() * n_sources / total_strength; - } + SourceSite site {model::external_sources[i]->sample(seed)}; // If running in MG, convert site.E to group if (!settings::run_CE) { @@ -1213,14 +397,6 @@ SourceSite sample_external_source(uint64_t* seed) void free_memory_source() { model::external_sources.clear(); - model::adjoint_sources.clear(); - reset_source_rejection_counters(); -} - -void reset_source_rejection_counters() -{ - source_n_accept = 0; - source_n_reject = 0; } //============================================================================== @@ -1235,21 +411,9 @@ extern "C" int openmc_sample_external_source( return OPENMC_E_INVALID_ARGUMENT; } - if (model::external_sources.empty()) { - set_errmsg("No external sources have been defined."); - return OPENMC_E_OUT_OF_BOUNDS; - } - auto sites_array = static_cast(sites); - - // Derive independent per-particle seeds from the base seed so that - // each iteration has its own RNG state for thread-safe parallel sampling. - uint64_t base_seed = *seed; - -#pragma omp parallel for schedule(static) for (size_t i = 0; i < n; ++i) { - uint64_t particle_seed = init_seed(base_seed + i, STREAM_SOURCE); - sites_array[i] = sample_external_source(&particle_seed); + sites_array[i] = sample_external_source(seed); } return 0; } diff --git a/src/state_point.cpp b/src/state_point.cpp index 02c68bf60..648d1a249 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -4,25 +4,21 @@ #include // for int64_t #include -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" // for empty_like +#include "xtensor/xview.hpp" #include #include "openmc/bank.h" -#include "openmc/bank_io.h" #include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/eigenvalue.h" #include "openmc/error.h" -#include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" -#include "openmc/mcpl_interface.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/output.h" -#include "openmc/particle_type.h" -#include "openmc/random_ray/flat_source_domain.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/tallies/derivative.h" @@ -38,8 +34,7 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) { simulation::time_statepoint.start(); - // If a nullptr is passed in, we assume that the user - // wants a default name for this, of the form like output/statepoint.20.h5 + // Set the filename std::string filename_; if (filename) { filename_ = filename; @@ -47,22 +42,9 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) // Determine width for zero padding int w = std::to_string(settings::n_max_batches).size(); - // Tag statepoints written during the forward solve of an adjoint run - const char* forward = - (FlatSourceDomain::solve_ == RandomRaySolve::FORWARD_FOR_ADJOINT) - ? "forward." - : ""; - // Set filename for state point - filename_ = fmt::format("{0}statepoint.{3}{1:0{2}}.h5", - settings::path_output, simulation::current_batch, w, forward); - } - - // If a file name was specified, ensure it has .h5 file extension - const auto extension = get_file_extension(filename_); - if (extension != "h5") { - warning("openmc_statepoint_write was passed a file extension differing " - "from .h5, but an hdf5 file will be written."); + filename_ = fmt::format("{0}statepoint.{1:0{2}}.h5", settings::path_output, + simulation::current_batch, w); } // Determine whether or not to write the source bank @@ -97,9 +79,6 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) // Write out random number seed write_dataset(file_id, "seed", openmc_get_seed()); - // Write out random number stride - write_dataset(file_id, "stride", openmc_get_stride()); - // Write run information write_dataset(file_id, "energy_mode", settings::run_CE ? "continuous-energy" : "multi-group"); @@ -203,18 +182,6 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) continue; } - if (tally->multiply_density()) { - write_attribute(tally_group, "multiply_density", 1); - } else { - write_attribute(tally_group, "multiply_density", 0); - } - - if (tally->higher_moments()) { - write_attribute(tally_group, "higher_moments", 1); - } else { - write_attribute(tally_group, "higher_moments", 0); - } - if (tally->estimator_ == TallyEstimator::ANALOG) { write_dataset(tally_group, "estimator", "analog"); } else if (tally->estimator_ == TallyEstimator::TRACKLENGTH) { @@ -278,13 +245,12 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) for (const auto& tally : model::tallies) { if (!tally->writable_) continue; - - // Write results for each bin + // Write sum and sum_sq for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); auto& results = tally->results_; - write_tally_results(tally_group, results.shape(0), results.shape(1), - results.shape(2), results.data()); + write_tally_results(tally_group, results.shape()[0], + results.shape()[1], results.data()); close_group(tally_group); } } else { @@ -350,12 +316,12 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) if (write_source_) { if (mpi::master || parallel) file_id = file_open(filename_, 'a', true); - write_source_bank(file_id, simulation::source_bank, simulation::work_index); + write_source_bank(file_id, false); if (mpi::master || parallel) file_close(file_id); } -#if defined(OPENMC_LIBMESH_ENABLED) || defined(OPENMC_DAGMC_ENABLED) +#if defined(LIBMESH) || defined(DAGMC) // write unstructured mesh tally files write_unstructured_mesh_results(); #endif @@ -381,27 +347,11 @@ void restart_set_keff() void load_state_point() { - write_message( - fmt::format("Loading state point {}...", settings::path_statepoint_c), 5); - openmc_statepoint_load(settings::path_statepoint.c_str()); -} + // Write message + write_message("Loading state point " + settings::path_statepoint + "...", 5); -void statepoint_version_check(hid_t file_id) -{ - // Read revision number for state point file and make sure it matches with - // current version - array version_array; - read_attribute(file_id, "version", version_array); - if (version_array != VERSION_STATEPOINT) { - fatal_error( - "State point version does not match current version in OpenMC."); - } -} - -extern "C" int openmc_statepoint_load(const char* filename) -{ // Open file for reading - hid_t file_id = file_open(filename, 'r', true); + hid_t file_id = file_open(settings::path_statepoint.c_str(), 'r', true); // Read filetype std::string word; @@ -410,18 +360,20 @@ extern "C" int openmc_statepoint_load(const char* filename) fatal_error("OpenMC tried to restart from a non-statepoint file."); } - statepoint_version_check(file_id); + // Read revision number for state point file and make sure it matches with + // current version + array array; + read_attribute(file_id, "version", array); + if (array != VERSION_STATEPOINT) { + fatal_error( + "State point version does not match current version in OpenMC."); + } // Read and overwrite random number seed int64_t seed; read_dataset(file_id, "seed", seed); openmc_set_seed(seed); - // Read and overwrite random number stride - uint64_t stride; - read_dataset(file_id, "stride", stride); - openmc_set_stride(stride); - // It is not impossible for a state point to be generated from a CE run but // to be loaded in to an MG run (or vice versa), check to prevent that. read_dataset(file_id, "energy_mode", word); @@ -451,13 +403,9 @@ extern "C" int openmc_statepoint_load(const char* filename) // Read batch number to restart at read_dataset(file_id, "current_batch", simulation::restart_batch); - if (settings::restart_run && - simulation::restart_batch >= settings::n_max_batches) { - warning(fmt::format( - "The number of batches specified for simulation ({}) is smaller " - "than or equal to the number of batches in the restart statepoint file " - "({})", - settings::n_max_batches, simulation::restart_batch)); + if (simulation::restart_batch > settings::n_batches) { + fatal_error("The number batches specified in settings.xml is fewer " + " than the number of batches in the given statepoint file."); } // Logical flag for source present in statepoint file @@ -522,14 +470,15 @@ extern "C" int openmc_statepoint_load(const char* filename) if (internal) { tally->writable_ = false; } else { - auto& results = tally->results_; - read_tally_results(tally_group, results.shape(0), results.shape(1), - results.shape(2), results.data()); + auto& results = tally->results_; + read_tally_results(tally_group, results.shape()[0], + results.shape()[1], results.data()); read_dataset(tally_group, "n_realizations", tally->n_realizations_); close_group(tally_group); } } + close_group(tallies_group); } } @@ -557,11 +506,9 @@ extern "C" int openmc_statepoint_load(const char* filename) // Close file file_close(file_id); - - return 0; } -hid_t h5banktype(bool memory) +hid_t h5banktype() { // Create compound type for position hid_t postype = H5Tcreate(H5T_COMPOUND, sizeof(struct Position)); @@ -576,14 +523,10 @@ hid_t h5banktype(bool memory) // - openmc/statepoint.py // - docs/source/io_formats/statepoint.rst // - docs/source/io_formats/source.rst - auto n = sizeof(SourceSite); - if (!memory) - n = 2 * sizeof(struct Position) + 3 * sizeof(double) + 3 * sizeof(int); - hid_t banktype = H5Tcreate(H5T_COMPOUND, n); + hid_t banktype = H5Tcreate(H5T_COMPOUND, sizeof(struct SourceSite)); H5Tinsert(banktype, "r", HOFFSET(SourceSite, r), postype); H5Tinsert(banktype, "u", HOFFSET(SourceSite, u), postype); H5Tinsert(banktype, "E", HOFFSET(SourceSite, E), H5T_NATIVE_DOUBLE); - H5Tinsert(banktype, "time", HOFFSET(SourceSite, time), H5T_NATIVE_DOUBLE); H5Tinsert(banktype, "wgt", HOFFSET(SourceSite, wgt), H5T_NATIVE_DOUBLE); H5Tinsert(banktype, "delayed_group", HOFFSET(SourceSite, delayed_group), H5T_NATIVE_INT); @@ -595,33 +538,31 @@ hid_t h5banktype(bool memory) return banktype; } -void write_source_point(std::string filename, span source_bank, - const vector& bank_index, bool use_mcpl) +vector calculate_surf_source_size() { - std::string ext = use_mcpl ? "mcpl" : "h5"; + vector surf_source_index; + surf_source_index.reserve(mpi::n_procs + 1); - int total_surf_particles = source_bank.size(); #ifdef OPENMC_MPI - int num_particles = source_bank.size(); - MPI_Allreduce( - &num_particles, &total_surf_particles, 1, MPI_INT, MPI_SUM, mpi::intracomm); + surf_source_index.resize(mpi::n_procs); + vector bank_size(mpi::n_procs); + + // Populate the surf_source_index with cumulative sum of the number of + // surface source banks per process + int64_t size = simulation::surf_source_bank.size(); + MPI_Scan(&size, bank_size.data(), 1, MPI_INT64_T, MPI_SUM, mpi::intracomm); + MPI_Allgather(bank_size.data(), 1, MPI_INT64_T, surf_source_index.data(), 1, + MPI_INT64_T, mpi::intracomm); + surf_source_index.insert(surf_source_index.begin(), 0); +#else + surf_source_index.push_back(0); + surf_source_index.push_back(simulation::surf_source_bank.size()); #endif - write_message("Creating source file {}.{} with {} particles ...", filename, - ext, total_surf_particles, 5); - - // Dispatch to appropriate function based on file type - if (use_mcpl) { - filename.append(".mcpl"); - write_mcpl_source_point(filename.c_str(), source_bank, bank_index); - } else { - filename.append(".h5"); - write_h5_source_point(filename.c_str(), source_bank, bank_index); - } + return surf_source_index; } -void write_h5_source_point(const char* filename, span source_bank, - const vector& bank_index) +void write_source_point(const char* filename, bool surf_source_bank) { // When using parallel HDF5, the file is written to collectively by all // processes. With MPI-only, the file is opened and written by the master @@ -633,46 +574,144 @@ void write_h5_source_point(const char* filename, span source_bank, bool parallel = false; #endif - if (!filename) - fatal_error("write_source_point filename needs a nonempty name."); + std::string filename_; + if (filename) { + filename_ = filename; + } else { + // Determine width for zero padding + int w = std::to_string(settings::n_max_batches).size(); - std::string filename_(filename); - const auto extension = get_file_extension(filename_); - if (extension != "h5") { - warning("write_source_point was passed a file extension differing " - "from .h5, but an hdf5 file will be written."); + filename_ = fmt::format("{0}source.{1:0{2}}.h5", settings::path_output, + simulation::current_batch, w); } hid_t file_id; if (mpi::master || parallel) { - file_id = file_open(filename_.c_str(), 'w', true); + file_id = file_open(filename_, 'w', true); write_attribute(file_id, "filetype", "source"); - write_attribute(file_id, "version", VERSION_STATEPOINT); } // Get pointer to source bank and write to file - write_source_bank(file_id, source_bank, bank_index); + write_source_bank(file_id, surf_source_bank); if (mpi::master || parallel) file_close(file_id); } -void write_source_bank(hid_t group_id, span source_bank, - const vector& bank_index) +void write_source_bank(hid_t group_id, bool surf_source_bank) { - hid_t membanktype = h5banktype(true); - hid_t filebanktype = h5banktype(false); + hid_t banktype = h5banktype(); + + // Set total and individual process dataspace sizes for source bank + int64_t dims_size = settings::n_particles; + int64_t count_size = simulation::work_per_rank; + + // Set vectors for source bank and starting bank index of each process + vector* bank_index = &simulation::work_index; + vector* source_bank = &simulation::source_bank; + vector surf_source_index_vector; + vector surf_source_bank_vector; + + // Reset dataspace sizes and vectors for surface source bank + if (surf_source_bank) { + surf_source_index_vector = calculate_surf_source_size(); + dims_size = surf_source_index_vector[mpi::n_procs]; + count_size = simulation::surf_source_bank.size(); + + bank_index = &surf_source_index_vector; + + // Copy data in a SharedArray into a vector. + surf_source_bank_vector.resize(count_size); + surf_source_bank_vector.assign(simulation::surf_source_bank.data(), + simulation::surf_source_bank.data() + count_size); + source_bank = &surf_source_bank_vector; + } + +#ifdef PHDF5 + // Set size of total dataspace for all procs and rank + hsize_t dims[] {static_cast(dims_size)}; + hid_t dspace = H5Screate_simple(1, dims, nullptr); + hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + + // Create another data space but for each proc individually + hsize_t count[] {static_cast(count_size)}; + hid_t memspace = H5Screate_simple(1, count, nullptr); + + // Select hyperslab for this dataspace + hsize_t start[] {static_cast((*bank_index)[mpi::rank])}; + H5Sselect_hyperslab(dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); + + // Set up the property list for parallel writing + hid_t plist = H5Pcreate(H5P_DATASET_XFER); + H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); + + // Write data to file in parallel + H5Dwrite(dset, banktype, memspace, dspace, plist, source_bank->data()); + + // Free resources + H5Sclose(dspace); + H5Sclose(memspace); + H5Dclose(dset); + H5Pclose(plist); -#ifdef OPENMC_MPI - write_bank_dataset("source_bank", group_id, source_bank, bank_index, - membanktype, filebanktype, mpi::source_site); #else - write_bank_dataset("source_bank", group_id, source_bank, bank_index, - membanktype, filebanktype); + + if (mpi::master) { + // Create dataset big enough to hold all source sites + hsize_t dims[] {static_cast(dims_size)}; + hid_t dspace = H5Screate_simple(1, dims, nullptr); + hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + // Save source bank sites since the array is overwritten below +#ifdef OPENMC_MPI + vector temp_source {source_bank->begin(), source_bank->end()}; #endif - H5Tclose(membanktype); - H5Tclose(filebanktype); + for (int i = 0; i < mpi::n_procs; ++i) { + // Create memory space + hsize_t count[] { + static_cast((*bank_index)[i + 1] - (*bank_index)[i])}; + hid_t memspace = H5Screate_simple(1, count, nullptr); + +#ifdef OPENMC_MPI + // Receive source sites from other processes + if (i > 0) + MPI_Recv(source_bank->data(), count[0], mpi::source_site, i, i, + mpi::intracomm, MPI_STATUS_IGNORE); +#endif + + // Select hyperslab for this dataspace + dspace = H5Dget_space(dset); + hsize_t start[] {static_cast((*bank_index)[i])}; + H5Sselect_hyperslab( + dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); + + // Write data to hyperslab + H5Dwrite( + dset, banktype, memspace, dspace, H5P_DEFAULT, (*source_bank).data()); + + H5Sclose(memspace); + H5Sclose(dspace); + } + + // Close all ids + H5Dclose(dset); + +#ifdef OPENMC_MPI + // Restore state of source bank + std::copy(temp_source.begin(), temp_source.end(), source_bank->begin()); +#endif + } else { +#ifdef OPENMC_MPI + MPI_Send(source_bank->data(), count_size, mpi::source_site, 0, mpi::rank, + mpi::intracomm); +#endif + } +#endif + + H5Tclose(banktype); } // Determine member names of a compound HDF5 datatype @@ -693,17 +732,7 @@ std::string dtype_member_names(hid_t dtype_id) void read_source_bank( hid_t group_id, vector& sites, bool distribute) { - bool legacy_particle_codes = true; - if (attribute_exists(group_id, "version")) { - array version; - read_attribute(group_id, "version", version); - if (version[0] > VERSION_STATEPOINT[0] || - (version[0] == VERSION_STATEPOINT[0] && version[1] >= 2)) { - legacy_particle_codes = false; - } - } - - hid_t banktype = h5banktype(true); + hid_t banktype = h5banktype(); // Open the dataset hid_t dset = H5Dopen(group_id, "source_bank", H5P_DEFAULT); @@ -764,12 +793,6 @@ void read_source_bank( H5Sclose(memspace); H5Dclose(dset); H5Tclose(banktype); - - if (legacy_particle_codes) { - for (auto& site : sites) { - site.particle = legacy_particle_index_to_type(site.particle.pdg_number()); - } - } } void write_unstructured_mesh_results() @@ -780,7 +803,7 @@ void write_unstructured_mesh_results() vector tally_scores; for (auto filter_idx : tally->filters()) { auto& filter = model::tally_filters[filter_idx]; - if (filter->type() != FilterType::MESH) + if (filter->type() != "mesh") continue; // check if the filter uses an unstructured mesh @@ -841,7 +864,7 @@ void write_unstructured_mesh_results() // construct result vectors vector mean_vec(umesh->n_bins()), std_dev_vec(umesh->n_bins()); - for (int j = 0; j < tally->results_.shape(0); j++) { + for (int j = 0; j < tally->results_.shape()[0]; j++) { // get the volume for this bin double volume = umesh->volume(j); // compute the mean @@ -903,7 +926,7 @@ void write_tally_results_nr(hid_t file_id) #ifdef OPENMC_MPI // Reduce global tallies - tensor::Tensor gt_reduced({N_GLOBAL_TALLIES, 3}); + xt::xtensor gt_reduced = xt::empty_like(gt); MPI_Reduce(gt.data(), gt_reduced.data(), gt.size(), MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); @@ -932,18 +955,13 @@ void write_tally_results_nr(hid_t file_id) write_attribute(file_id, "tallies_present", 1); } - // Copy the SUM and SUM_SQ columns from the tally results into a - // contiguous array for MPI reduction - const int r_start = static_cast(TallyResult::SUM); - const int r_end = static_cast(TallyResult::SUM_SQ) + 1; - const size_t r_count = r_end - r_start; - const size_t ni = t->results_.shape(0); - const size_t nj = t->results_.shape(1); - tensor::Tensor values({ni, nj, r_count}); - for (size_t i = 0; i < ni; i++) - for (size_t j = 0; j < nj; j++) - for (size_t r = 0; r < r_count; r++) - values(i, j, r) = t->results_(i, j, r_start + r); + // Get view of accumulated tally values + auto values_view = xt::view(t->results_, xt::all(), xt::all(), + xt::range(static_cast(TallyResult::SUM), + static_cast(TallyResult::SUM_SQ) + 1)); + + // Make copy of tally values in contiguous array + xt::xtensor values = values_view; if (mpi::master) { // Open group for tally @@ -957,27 +975,23 @@ void write_tally_results_nr(hid_t file_id) MPI_SUM, 0, mpi::intracomm); #endif - // At the end of the simulation, store the reduced results back - // into the tally results array + // At the end of the simulation, store the results back in the + // regular TallyResults array if (simulation::current_batch == settings::n_max_batches || simulation::satisfy_triggers) { - for (size_t i = 0; i < ni; i++) - for (size_t j = 0; j < nj; j++) - for (size_t r = 0; r < r_count; r++) - t->results_(i, j, r_start + r) = values(i, j, r); + values_view = values; } - // Put reduced values into a full-sized copy for writing to HDF5 - tensor::Tensor results_copy = tensor::zeros_like(t->results_); - for (size_t i = 0; i < ni; i++) - for (size_t j = 0; j < nj; j++) - for (size_t r = 0; r < r_count; r++) - results_copy(i, j, r_start + r) = values(i, j, r); + // Put in temporary tally result + xt::xtensor results_copy = xt::zeros_like(t->results_); + auto copy_view = xt::view(results_copy, xt::all(), xt::all(), + xt::range(static_cast(TallyResult::SUM), + static_cast(TallyResult::SUM_SQ) + 1)); + copy_view = values; // Write reduced tally results to file auto shape = results_copy.shape(); - write_tally_results( - tally_group, shape[0], shape[1], shape[2], results_copy.data()); + write_tally_results(tally_group, shape[0], shape[1], results_copy.data()); close_group(tally_group); } else { diff --git a/src/string_utils.cpp b/src/string_utils.cpp index 74f048e8d..3b1c1b4a6 100644 --- a/src/string_utils.cpp +++ b/src/string_utils.cpp @@ -2,6 +2,7 @@ #include // for equal #include // for tolower, isspace +#include namespace openmc { @@ -35,7 +36,7 @@ void to_lower(std::string& str) str[i] = std::tolower(str[i]); } -int word_count(const std::string& str) +int word_count(std::string const& str) { std::stringstream stream(str); std::string dum; diff --git a/src/surface.cpp b/src/surface.cpp index 81b756dea..c0b3f0a59 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -2,14 +2,13 @@ #include #include -#include #include #include #include +#include #include "openmc/array.h" -#include "openmc/cell.h" #include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/external/quartic_solver.h" @@ -35,21 +34,100 @@ vector> surfaces; // Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== -void read_coeffs( - pugi::xml_node surf_node, int surf_id, std::initializer_list coeffs) +void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1) { // Check the given number of coefficients. - auto coeffs_file = get_node_array(surf_node, "coeffs"); - if (coeffs_file.size() != coeffs.size()) { - fatal_error( - fmt::format("Surface {} expects {} coefficient but was given {}", surf_id, - coeffs.size(), coeffs_file.size())); + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 1) { + fatal_error(fmt::format( + "Surface {} expects 1 coeff but was given {}", surf_id, n_words)); } - // Copy the coefficients - int i = 0; - for (auto c : coeffs) { - *c = coeffs_file[i++]; + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf", &c1); + if (stat != 1) { + fatal_error(fmt::format( + "Something went wrong reading coeffs for surface {}", surf_id)); + } +} + +void read_coeffs( + pugi::xml_node surf_node, int surf_id, double& c1, double& c2, double& c3) +{ + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 3) { + fatal_error(fmt::format( + "Surface {} expects 3 coeffs but was given {}", surf_id, n_words)); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf %lf %lf", &c1, &c2, &c3); + if (stat != 3) { + fatal_error(fmt::format( + "Something went wrong reading coeffs for surface {}", surf_id)); + } +} + +void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1, double& c2, + double& c3, double& c4) +{ + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 4) { + fatal_error(fmt::format( + "Surface {} expects 4 coeffs but was given ", surf_id, n_words)); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); + if (stat != 4) { + fatal_error(fmt::format( + "Something went wrong reading coeffs for surface {}", surf_id)); + } +} + +void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1, double& c2, + double& c3, double& c4, double& c5, double& c6) +{ + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 6) { + fatal_error(fmt::format( + "Surface {} expects 6 coeffs but was given {}", surf_id, n_words)); + } + + // Parse the coefficients. + int stat = sscanf( + coeffs.c_str(), "%lf %lf %lf %lf %lf %lf", &c1, &c2, &c3, &c4, &c5, &c6); + if (stat != 6) { + fatal_error(fmt::format( + "Something went wrong reading coeffs for surface {}", surf_id)); + } +} + +void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1, double& c2, + double& c3, double& c4, double& c5, double& c6, double& c7, double& c8, + double& c9, double& c10) +{ + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 10) { + fatal_error(fmt::format( + "Surface {} expects 10 coeffs but was given {}", surf_id, n_words)); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10); + if (stat != 10) { + fatal_error(fmt::format( + "Something went wrong reading coeffs for surface {}", surf_id)); } } @@ -63,8 +141,7 @@ Surface::Surface(pugi::xml_node surf_node) { if (check_for_node(surf_node, "id")) { id_ = std::stoi(get_node_value(surf_node, "id")); - if (contains(settings::source_write_surf_id, id_) || - settings::source_write_surf_id.empty()) { + if (contains(settings::source_write_surf_id, id_)) { surf_source_ = true; } } else { @@ -81,36 +158,19 @@ Surface::Surface(pugi::xml_node surf_node) if (surf_bc == "transmission" || surf_bc == "transmit" || surf_bc.empty()) { // Leave the bc_ a nullptr } else if (surf_bc == "vacuum") { - bc_ = make_unique(); + bc_ = std::make_shared(); } else if (surf_bc == "reflective" || surf_bc == "reflect" || surf_bc == "reflecting") { - bc_ = make_unique(); + bc_ = std::make_shared(); } else if (surf_bc == "white") { - bc_ = make_unique(); + bc_ = std::make_shared(); } else if (surf_bc == "periodic") { - // Periodic BCs are handled separately + // periodic BC's are handled separately } else { fatal_error(fmt::format("Unknown boundary condition \"{}\" specified " "on surface {}", surf_bc, id_)); } - - if (check_for_node(surf_node, "albedo") && bc_) { - double surf_alb = std::stod(get_node_value(surf_node, "albedo")); - - if (surf_alb < 0.0) - fatal_error(fmt::format("Surface {} has an albedo of {}. " - "Albedo values must be positive.", - id_, surf_alb)); - - if (surf_alb > 1.0) - warning(fmt::format("Surface {} has an albedo of {}. " - "Albedos greater than 1 may cause " - "unphysical behaviour.", - id_, surf_alb)); - - bc_->set_albedo(surf_alb); - } } } @@ -130,7 +190,7 @@ bool Surface::sense(Position r, Direction u) const return f > 0.0; } -Direction Surface::reflect(Position r, Direction u, GeometryState* p) const +Direction Surface::reflect(Position r, Direction u, Particle* p) const { // Determine projection of direction onto normal and squared magnitude of // normal. @@ -165,27 +225,13 @@ void Surface::to_hdf5(hid_t group_id) const { hid_t surf_group = create_group(group_id, fmt::format("surface {}", id_)); - if (geom_type() == GeometryType::DAG) { + if (geom_type_ == GeometryType::DAG) { write_string(surf_group, "geom_type", "dagmc", false); - } else if (geom_type() == GeometryType::CSG) { + } else if (geom_type_ == GeometryType::CSG) { write_string(surf_group, "geom_type", "csg", false); if (bc_) { write_string(surf_group, "boundary_type", bc_->type(), false); - bc_->to_hdf5(surf_group); - - // write periodic surface ID - if (bc_->type() == "periodic") { - auto pbc = dynamic_cast(bc_.get()); - Surface& surf1 {*model::surfaces[pbc->i_surf()]}; - Surface& surf2 {*model::surfaces[pbc->j_surf()]}; - - if (id_ == surf1.id_) { - write_dataset(surf_group, "periodic_surface_id", surf2.id_); - } else { - write_dataset(surf_group, "periodic_surface_id", surf1.id_); - } - } } else { write_string(surf_group, "boundary_type", "transmission", false); } @@ -200,6 +246,15 @@ void Surface::to_hdf5(hid_t group_id) const close_group(surf_group); } +CSGSurface::CSGSurface() : Surface {} +{ + geom_type_ = GeometryType::CSG; +}; +CSGSurface::CSGSurface(pugi::xml_node surf_node) : Surface {surf_node} +{ + geom_type_ = GeometryType::CSG; +}; + //============================================================================== // Generic functions for x-, y-, and z-, planes. //============================================================================== @@ -222,9 +277,9 @@ double axis_aligned_plane_distance( // SurfaceXPlane implementation //============================================================================== -SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_}); + read_coeffs(surf_node, id_, x0_); } double SurfaceXPlane::evaluate(Position r) const @@ -252,9 +307,9 @@ void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceXPlane::bounding_box(bool pos_side) const { if (pos_side) { - return {{x0_, -INFTY, -INFTY}, {INFTY, INFTY, INFTY}}; + return {x0_, INFTY, -INFTY, INFTY, -INFTY, INFTY}; } else { - return {{-INFTY, -INFTY, -INFTY}, {x0_, INFTY, INFTY}}; + return {-INFTY, x0_, -INFTY, INFTY, -INFTY, INFTY}; } } @@ -262,9 +317,9 @@ BoundingBox SurfaceXPlane::bounding_box(bool pos_side) const // SurfaceYPlane implementation //============================================================================== -SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&y0_}); + read_coeffs(surf_node, id_, y0_); } double SurfaceYPlane::evaluate(Position r) const @@ -292,9 +347,9 @@ void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceYPlane::bounding_box(bool pos_side) const { if (pos_side) { - return {{-INFTY, y0_, -INFTY}, {INFTY, INFTY, INFTY}}; + return {-INFTY, INFTY, y0_, INFTY, -INFTY, INFTY}; } else { - return {{-INFTY, -INFTY, -INFTY}, {INFTY, y0_, INFTY}}; + return {-INFTY, INFTY, -INFTY, y0_, -INFTY, INFTY}; } } @@ -302,9 +357,9 @@ BoundingBox SurfaceYPlane::bounding_box(bool pos_side) const // SurfaceZPlane implementation //============================================================================== -SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&z0_}); + read_coeffs(surf_node, id_, z0_); } double SurfaceZPlane::evaluate(Position r) const @@ -332,9 +387,9 @@ void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceZPlane::bounding_box(bool pos_side) const { if (pos_side) { - return {{-INFTY, -INFTY, z0_}, {INFTY, INFTY, INFTY}}; + return {-INFTY, INFTY, -INFTY, INFTY, z0_, INFTY}; } else { - return {{-INFTY, -INFTY, -INFTY}, {INFTY, INFTY, z0_}}; + return {-INFTY, INFTY, -INFTY, INFTY, -INFTY, z0_}; } } @@ -342,9 +397,9 @@ BoundingBox SurfaceZPlane::bounding_box(bool pos_side) const // SurfacePlane implementation //============================================================================== -SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : Surface(surf_node) +SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&A_, &B_, &C_, &D_}); + read_coeffs(surf_node, id_, A_, B_, C_, D_); } double SurfacePlane::evaluate(Position r) const @@ -461,9 +516,9 @@ Direction axis_aligned_cylinder_normal( //============================================================================== SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&y0_, &z0_, &radius_}); + read_coeffs(surf_node, id_, y0_, z0_, radius_); } double SurfaceXCylinder::evaluate(Position r) const @@ -493,8 +548,8 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceXCylinder::bounding_box(bool pos_side) const { if (!pos_side) { - return {{-INFTY, y0_ - radius_, z0_ - radius_}, - {INFTY, y0_ + radius_, z0_ + radius_}}; + return {-INFTY, INFTY, y0_ - radius_, y0_ + radius_, z0_ - radius_, + z0_ + radius_}; } else { return {}; } @@ -504,9 +559,9 @@ BoundingBox SurfaceXCylinder::bounding_box(bool pos_side) const //============================================================================== SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &z0_, &radius_}); + read_coeffs(surf_node, id_, x0_, z0_, radius_); } double SurfaceYCylinder::evaluate(Position r) const @@ -536,8 +591,8 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceYCylinder::bounding_box(bool pos_side) const { if (!pos_side) { - return {{x0_ - radius_, -INFTY, z0_ - radius_}, - {x0_ + radius_, INFTY, z0_ + radius_}}; + return {x0_ - radius_, x0_ + radius_, -INFTY, INFTY, z0_ - radius_, + z0_ + radius_}; } else { return {}; } @@ -548,9 +603,9 @@ BoundingBox SurfaceYCylinder::bounding_box(bool pos_side) const //============================================================================== SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) - : Surface(surf_node) + : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &radius_}); + read_coeffs(surf_node, id_, x0_, y0_, radius_); } double SurfaceZCylinder::evaluate(Position r) const @@ -580,8 +635,8 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceZCylinder::bounding_box(bool pos_side) const { if (!pos_side) { - return {{x0_ - radius_, y0_ - radius_, -INFTY}, - {x0_ + radius_, y0_ + radius_, INFTY}}; + return {x0_ - radius_, x0_ + radius_, y0_ - radius_, y0_ + radius_, -INFTY, + INFTY}; } else { return {}; } @@ -591,9 +646,9 @@ BoundingBox SurfaceZCylinder::bounding_box(bool pos_side) const // SurfaceSphere implementation //============================================================================== -SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_); } double SurfaceSphere::evaluate(Position r) const @@ -658,8 +713,8 @@ void SurfaceSphere::to_hdf5_inner(hid_t group_id) const BoundingBox SurfaceSphere::bounding_box(bool pos_side) const { if (!pos_side) { - return {{x0_ - radius_, y0_ - radius_, z0_ - radius_}, - {x0_ + radius_, y0_ + radius_, z0_ + radius_}}; + return {x0_ - radius_, x0_ + radius_, y0_ - radius_, y0_ + radius_, + z0_ - radius_, z0_ + radius_}; } else { return {}; } @@ -757,9 +812,9 @@ Direction axis_aligned_cone_normal( // SurfaceXCone implementation //============================================================================== -SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } double SurfaceXCone::evaluate(Position r) const @@ -789,9 +844,9 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const // SurfaceYCone implementation //============================================================================== -SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } double SurfaceYCone::evaluate(Position r) const @@ -821,9 +876,9 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const // SurfaceZCone implementation //============================================================================== -SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } double SurfaceZCone::evaluate(Position r) const @@ -853,10 +908,9 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const // SurfaceQuadric implementation //============================================================================== -SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs( - surf_node, id_, {&A_, &B_, &C_, &D_, &E_, &F_, &G_, &H_, &J_, &K_}); + read_coeffs(surf_node, id_, A_, B_, C_, D_, E_, F_, G_, H_, J_, K_); } double SurfaceQuadric::evaluate(Position r) const @@ -990,19 +1044,12 @@ double torus_distance(double x1, double x2, double x3, double u1, double u2, // zero but possibly small and positive. A tolerance is set to discard that // zero. double distance = INFTY; - double cutoff = coincident ? TORUS_TOL : 0.0; + double cutoff = coincident ? 1e-10 : 0.0; for (int i = 0; i < 4; ++i) { if (roots[i].imag() == 0) { double root = roots[i].real(); if (root > cutoff && root < distance) { - // Avoid roots corresponding to internal surfaces - double s1 = x1 + u1 * root; - double s2 = x2 + u2 * root; - double s3 = x3 + u3 * root; - double check = D * s3 * s3 + s1 * s1 + s2 * s2 + A * A - C * C; - if (check >= 0) { - distance = root; - } + distance = root; } } } @@ -1013,9 +1060,9 @@ double torus_distance(double x1, double x2, double x3, double u1, double u2, // SurfaceXTorus implementation //============================================================================== -SurfaceXTorus::SurfaceXTorus(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceXTorus::SurfaceXTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, A_, B_, C_); } void SurfaceXTorus::to_hdf5_inner(hid_t group_id) const @@ -1066,9 +1113,9 @@ Direction SurfaceXTorus::normal(Position r) const // SurfaceYTorus implementation //============================================================================== -SurfaceYTorus::SurfaceYTorus(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceYTorus::SurfaceYTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, A_, B_, C_); } void SurfaceYTorus::to_hdf5_inner(hid_t group_id) const @@ -1119,9 +1166,9 @@ Direction SurfaceYTorus::normal(Position r) const // SurfaceZTorus implementation //============================================================================== -SurfaceZTorus::SurfaceZTorus(pugi::xml_node surf_node) : Surface(surf_node) +SurfaceZTorus::SurfaceZTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); + read_coeffs(surf_node, id_, x0_, y0_, z0_, A_, B_, C_); } void SurfaceZTorus::to_hdf5_inner(hid_t group_id) const @@ -1170,10 +1217,7 @@ Direction SurfaceZTorus::normal(Position r) const //============================================================================== -void read_surfaces(pugi::xml_node node, - std::set>& periodic_pairs, - std::unordered_map& albedo_map, - std::unordered_map& periodic_sense_map) +void read_surfaces(pugi::xml_node node) { // Count the number of surfaces int n_surfaces = 0; @@ -1182,8 +1226,9 @@ void read_surfaces(pugi::xml_node node, } // Loop over XML surface elements and populate the array. Keep track of - // periodic surfaces and their albedos. + // periodic surfaces. model::surfaces.reserve(n_surfaces); + std::set> periodic_pairs; { pugi::xml_node surf_node; int i_surf; @@ -1246,13 +1291,6 @@ void read_surfaces(pugi::xml_node node, if (check_for_node(surf_node, "boundary")) { std::string surf_bc = get_node_value(surf_node, "boundary", true, true); if (surf_bc == "periodic") { - periodic_sense_map[model::surfaces.back()->id_] = 0; - // Check for surface albedo. Skip sanity check as it is already done - // in the Surface class's constructor. - if (check_for_node(surf_node, "albedo")) { - albedo_map[model::surfaces.back()->id_] = - std::stod(get_node_value(surf_node, "albedo")); - } if (check_for_node(surf_node, "periodic_surface_id")) { int i_periodic = std::stoi(get_node_value(surf_node, "periodic_surface_id")); @@ -1278,28 +1316,6 @@ void read_surfaces(pugi::xml_node node, fmt::format("Two or more surfaces use the same unique ID: {}", id)); } } -} - -void prepare_boundary_conditions(std::set>& periodic_pairs, - std::unordered_map& albedo_map, - std::unordered_map& periodic_sense_map) -{ - // Fill the senses map for periodic surfaces - auto n_periodic = periodic_sense_map.size(); - for (const auto& cell : model::cells) { - if (n_periodic == 0) - break; // Early exit once all periodic surfaces found - - for (auto s : cell->surfaces()) { - auto surf_idx = std::abs(s) - 1; - auto id = model::surfaces[surf_idx]->id_; - - if (periodic_sense_map.count(id)) { - periodic_sense_map[id] = std::copysign(1, s); - --n_periodic; - } - } - } // Resolve unpaired periodic surfaces. A lambda function is used with // std::find_if to identify the unpaired surfaces. @@ -1338,7 +1354,7 @@ void prepare_boundary_conditions(std::set>& periodic_pairs, periodic_pairs.erase(second_unresolved); } - // Assign the periodic boundary conditions with albedos + // Assign the periodic boundary conditions for (auto periodic_pair : periodic_pairs) { int i_surf = model::surface_map[periodic_pair.first]; int j_surf = model::surface_map[periodic_pair.second]; @@ -1356,59 +1372,11 @@ void prepare_boundary_conditions(std::set>& periodic_pairs, // planes are parallel which indicates a translational periodic boundary // condition. Otherwise, it is a rotational periodic BC. if (std::abs(1.0 - dot_prod) < FP_PRECISION) { - surf1.bc_ = make_unique(i_surf, j_surf); - surf2.bc_ = make_unique(j_surf, i_surf); + surf1.bc_ = std::make_shared(i_surf, j_surf); + surf2.bc_ = surf1.bc_; } else { - // check that both normals have at least one 0 component - if (std::abs(norm1.x) > FP_PRECISION && - std::abs(norm1.y) > FP_PRECISION && - std::abs(norm1.z) > FP_PRECISION) { - fatal_error(fmt::format( - "The normal ({}) of the periodic surface ({}) does not contain any " - "component with a zero value. A RotationalPeriodicBC requires one " - "component which is zero for both plane normals.", - norm1, i_surf)); - } - if (std::abs(norm2.x) > FP_PRECISION && - std::abs(norm2.y) > FP_PRECISION && - std::abs(norm2.z) > FP_PRECISION) { - fatal_error(fmt::format( - "The normal ({}) of the periodic surface ({}) does not contain any " - "component with a zero value. A RotationalPeriodicBC requires one " - "component which is zero for both plane normals.", - norm2, j_surf)); - } - // find common zero component, which indicates the periodic axis - RotationalPeriodicBC::PeriodicAxis axis; - if (std::abs(norm1.x) <= FP_PRECISION && - std::abs(norm2.x) <= FP_PRECISION) { - axis = RotationalPeriodicBC::PeriodicAxis::x; - } else if (std::abs(norm1.y) <= FP_PRECISION && - std::abs(norm2.y) <= FP_PRECISION) { - axis = RotationalPeriodicBC::PeriodicAxis::y; - } else if (std::abs(norm1.z) <= FP_PRECISION && - std::abs(norm2.z) <= FP_PRECISION) { - axis = RotationalPeriodicBC::PeriodicAxis::z; - } else { - fatal_error(fmt::format( - "There is no component which is 0.0 in both normal vectors. This " - "indicates that the two planes are not periodic about the X, Y, or Z " - "axis, which is not supported.")); - } - auto i_sign = periodic_sense_map[periodic_pair.first]; - auto j_sign = periodic_sense_map[periodic_pair.second]; - surf1.bc_ = make_unique( - i_sign * (i_surf + 1), j_sign * (j_surf + 1), axis); - surf2.bc_ = make_unique( - j_sign * (j_surf + 1), i_sign * (i_surf + 1), axis); - } - - // If albedo data is present in albedo map, set the boundary albedo. - if (albedo_map.count(surf1.id_)) { - surf1.bc_->set_albedo(albedo_map[surf1.id_]); - } - if (albedo_map.count(surf2.id_)) { - surf2.bc_->set_albedo(albedo_map[surf2.id_]); + surf1.bc_ = std::make_shared(i_surf, j_surf); + surf2.bc_ = surf1.bc_; } } } diff --git a/src/tallies/filter.cpp b/src/tallies/filter.cpp index badb91077..a1e5c709f 100644 --- a/src/tallies/filter.cpp +++ b/src/tallies/filter.cpp @@ -1,8 +1,7 @@ #include "openmc/tallies/filter.h" #include // for max -#include -#include // for strcpy +#include // for strcpy #include #include @@ -22,24 +21,16 @@ #include "openmc/tallies/filter_energyfunc.h" #include "openmc/tallies/filter_legendre.h" #include "openmc/tallies/filter_material.h" -#include "openmc/tallies/filter_materialfrom.h" #include "openmc/tallies/filter_mesh.h" -#include "openmc/tallies/filter_meshborn.h" -#include "openmc/tallies/filter_meshmaterial.h" #include "openmc/tallies/filter_meshsurface.h" #include "openmc/tallies/filter_mu.h" -#include "openmc/tallies/filter_musurface.h" -#include "openmc/tallies/filter_parent_nuclide.h" #include "openmc/tallies/filter_particle.h" -#include "openmc/tallies/filter_particle_production.h" #include "openmc/tallies/filter_polar.h" -#include "openmc/tallies/filter_reaction.h" #include "openmc/tallies/filter_sph_harm.h" #include "openmc/tallies/filter_sptl_legendre.h" #include "openmc/tallies/filter_surface.h" #include "openmc/tallies/filter_time.h" #include "openmc/tallies/filter_universe.h" -#include "openmc/tallies/filter_weight.h" #include "openmc/tallies/filter_zernike.h" #include "openmc/xml_interface.h" @@ -80,6 +71,21 @@ Filter::~Filter() model::filter_map.erase(id_); } +template +T* Filter::create(int32_t id) +{ + static_assert(std::is_base_of::value, + "Type specified is not derived from openmc::Filter"); + // Create filter and add to filters vector + auto filter = make_unique(); + auto ptr_out = filter.get(); + model::tally_filters.emplace_back(std::move(filter)); + // Assign ID + model::tally_filters.back()->set_id(id); + + return ptr_out; +} + Filter* Filter::create(pugi::xml_node node) { // Copy filter id @@ -109,7 +115,7 @@ Filter* Filter::create(const std::string& type, int32_t id) } else if (type == "cell") { return Filter::create(id); } else if (type == "cellborn") { - return Filter::create(id); + return Filter::create(id); } else if (type == "cellfrom") { return Filter::create(id); } else if (type == "cellinstance") { @@ -130,30 +136,16 @@ Filter* Filter::create(const std::string& type, int32_t id) return Filter::create(id); } else if (type == "material") { return Filter::create(id); - } else if (type == "materialfrom") { - return Filter::create(id); } else if (type == "mesh") { return Filter::create(id); - } else if (type == "meshborn") { - return Filter::create(id); - } else if (type == "meshmaterial") { - return Filter::create(id); } else if (type == "meshsurface") { return Filter::create(id); } else if (type == "mu") { return Filter::create(id); - } else if (type == "musurface") { - return Filter::create(id); - } else if (type == "parentnuclide") { - return Filter::create(id); } else if (type == "particle") { return Filter::create(id); - } else if (type == "particleproduction") { - return Filter::create(id); } else if (type == "polar") { return Filter::create(id); - } else if (type == "reaction") { - return Filter::create(id); } else if (type == "surface") { return Filter::create(id); } else if (type == "spatiallegendre") { @@ -164,8 +156,6 @@ Filter* Filter::create(const std::string& type, int32_t id) return Filter::create(id); } else if (type == "universe") { return Filter::create(id); - } else if (type == "weight") { - return Filter::create(id); } else if (type == "zernike") { return Filter::create(id); } else if (type == "zernikeradial") { @@ -178,7 +168,7 @@ Filter* Filter::create(const std::string& type, int32_t id) void Filter::set_id(int32_t id) { - assert(id >= 0 || id == C_NONE); + Expects(id >= 0 || id == C_NONE); // Clear entry in filter map if an ID was already assigned before if (id_ != C_NONE) { @@ -242,16 +232,7 @@ extern "C" int openmc_filter_get_type(int32_t index, char* type) if (int err = verify_filter(index)) return err; - std::strcpy(type, model::tally_filters[index]->type_str().c_str()); - return 0; -} - -extern "C" int openmc_filter_get_num_bins(int32_t index, int* n_bins) -{ - if (int err = verify_filter(index)) - return err; - - *n_bins = model::tally_filters[index]->n_bins(); + std::strcpy(type, model::tally_filters[index]->type().c_str()); return 0; } diff --git a/src/tallies/filter_azimuthal.cpp b/src/tallies/filter_azimuthal.cpp index 6525f326d..e77aa8bdc 100644 --- a/src/tallies/filter_azimuthal.cpp +++ b/src/tallies/filter_azimuthal.cpp @@ -34,14 +34,14 @@ void AzimuthalFilter::from_xml(pugi::xml_node node) this->set_bins(bins); } -void AzimuthalFilter::set_bins(span bins) +void AzimuthalFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); bins_.reserve(bins.size()); // Copy bins, ensuring they are valid - for (int64_t i = 0; i < bins.size(); ++i) { + for (gsl::index i = 0; i < bins.size(); ++i) { if (i > 0 && bins[i] <= bins[i - 1]) { throw std::runtime_error { "Azimuthal bins must be monotonically increasing."}; diff --git a/src/tallies/filter_cell.cpp b/src/tallies/filter_cell.cpp index 7a6394956..9ccae6b48 100644 --- a/src/tallies/filter_cell.cpp +++ b/src/tallies/filter_cell.cpp @@ -1,7 +1,5 @@ #include "openmc/tallies/filter_cell.h" -#include - #include #include "openmc/capi.h" @@ -27,7 +25,7 @@ void CellFilter::from_xml(pugi::xml_node node) this->set_cells(cells); } -void CellFilter::set_cells(span cells) +void CellFilter::set_cells(gsl::span cells) { // Clear existing cells cells_.clear(); @@ -36,8 +34,8 @@ void CellFilter::set_cells(span cells) // Update cells and mapping for (auto& index : cells) { - assert(index >= 0); - assert(index < model::cells.size()); + Expects(index >= 0); + Expects(index < model::cells.size()); cells_.push_back(index); map_[index] = cells_.size() - 1; } @@ -49,7 +47,7 @@ void CellFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { for (int i = 0; i < p.n_coord(); i++) { - auto search = map_.find(p.coord(i).cell()); + auto search = map_.find(p.coord(i).cell); if (search != map_.end()) { match.bins_.push_back(search->second); match.weights_.push_back(1.0); @@ -82,7 +80,7 @@ extern "C" int openmc_cell_filter_get_bins( return err; const auto& filt = model::tally_filters[index].get(); - if (filt->type() != FilterType::CELL) { + if (filt->type() != "cell") { set_errmsg("Tried to get cells from a non-cell filter."); return OPENMC_E_INVALID_TYPE; } diff --git a/src/tallies/filter_cell_instance.cpp b/src/tallies/filter_cell_instance.cpp index 928bfb6c5..59f28c7d6 100644 --- a/src/tallies/filter_cell_instance.cpp +++ b/src/tallies/filter_cell_instance.cpp @@ -1,6 +1,5 @@ #include "openmc/tallies/filter_cell_instance.h" -#include #include #include @@ -9,12 +8,11 @@ #include "openmc/cell.h" #include "openmc/error.h" #include "openmc/geometry.h" -#include "openmc/tensor.h" #include "openmc/xml_interface.h" namespace openmc { -CellInstanceFilter::CellInstanceFilter(span instances) +CellInstanceFilter::CellInstanceFilter(gsl::span instances) { this->set_cell_instances(instances); } @@ -23,26 +21,26 @@ void CellInstanceFilter::from_xml(pugi::xml_node node) { // Get cell IDs/instances auto cells = get_node_array(node, "bins"); - assert(cells.size() % 2 == 0); + Expects(cells.size() % 2 == 0); // Convert into vector of CellInstance vector instances; - for (int64_t i = 0; i < cells.size() / 2; ++i) { + for (gsl::index i = 0; i < cells.size() / 2; ++i) { int32_t cell_id = cells[2 * i]; - int64_t instance = cells[2 * i + 1]; + gsl::index instance = cells[2 * i + 1]; auto search = model::cell_map.find(cell_id); if (search == model::cell_map.end()) { throw std::runtime_error {fmt::format( "Could not find cell {} specified on tally filter.", cell_id)}; } - int64_t index = search->second; + gsl::index index = search->second; instances.push_back({index, instance}); } this->set_cell_instances(instances); } -void CellInstanceFilter::set_cell_instances(span instances) +void CellInstanceFilter::set_cell_instances(gsl::span instances) { // Clear existing cells cell_instances_.clear(); @@ -52,8 +50,8 @@ void CellInstanceFilter::set_cell_instances(span instances) // Update cells and mapping for (auto& x : instances) { - assert(x.index_cell >= 0); - assert(x.index_cell < model::cells.size()); + Expects(x.index_cell >= 0); + Expects(x.index_cell < model::cells.size()); cell_instances_.push_back(x); cells_.insert(x.index_cell); map_[x] = cell_instances_.size() - 1; @@ -74,8 +72,8 @@ void CellInstanceFilter::set_cell_instances(span instances) void CellInstanceFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - int64_t index_cell = p.lowest_coord().cell(); - int64_t instance = p.cell_instance(); + gsl::index index_cell = p.coord(p.n_coord() - 1).cell; + gsl::index instance = p.cell_instance(); if (cells_.count(index_cell) > 0) { auto search = map_.find({index_cell, instance}); @@ -90,13 +88,13 @@ void CellInstanceFilter::get_all_bins( return; for (int i = 0; i < p.n_coord() - 1; i++) { - int64_t index_cell = p.coord(i).cell(); + gsl::index index_cell = p.coord(i).cell; // if this cell isn't used on the filter, move on if (cells_.count(index_cell) == 0) continue; // if this cell is used in the filter, check the instance as well - int64_t instance = cell_instance_at_level(p, i); + gsl::index instance = cell_instance_at_level(p, i); auto search = map_.find({index_cell, instance}); if (search != map_.end()) { match.bins_.push_back(search->second); @@ -109,8 +107,8 @@ void CellInstanceFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); size_t n = cell_instances_.size(); - tensor::Tensor data({n, 2}); - for (int64_t i = 0; i < n; ++i) { + xt::xtensor data({n, 2}); + for (gsl::index i = 0; i < n; ++i) { const auto& x = cell_instances_[i]; data(i, 0) = model::cells[x.index_cell]->id_; data(i, 1) = x.instance; diff --git a/src/tallies/filter_cellborn.cpp b/src/tallies/filter_cellborn.cpp index ad8363e7b..d0d25c9a0 100644 --- a/src/tallies/filter_cellborn.cpp +++ b/src/tallies/filter_cellborn.cpp @@ -4,7 +4,7 @@ namespace openmc { -void CellBornFilter::get_all_bins( +void CellbornFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { auto search = map_.find(p.cell_born()); @@ -14,7 +14,7 @@ void CellBornFilter::get_all_bins( } } -std::string CellBornFilter::text_label(int bin) const +std::string CellbornFilter::text_label(int bin) const { return "Birth Cell " + std::to_string(model::cells[cells_[bin]]->id_); } diff --git a/src/tallies/filter_collision.cpp b/src/tallies/filter_collision.cpp index c614c3c83..fbb186a23 100644 --- a/src/tallies/filter_collision.cpp +++ b/src/tallies/filter_collision.cpp @@ -19,7 +19,7 @@ void CollisionFilter::from_xml(pugi::xml_node node) this->set_bins(bins); } -void CollisionFilter::set_bins(span bins) +void CollisionFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); @@ -27,7 +27,7 @@ void CollisionFilter::set_bins(span bins) map_.clear(); // Copy bins - for (int64_t i = 0; i < bins.size(); ++i) { + for (gsl::index i = 0; i < bins.size(); ++i) { bins_.push_back(bins[i]); map_[bins[i]] = i; } diff --git a/src/tallies/filter_delayedgroup.cpp b/src/tallies/filter_delayedgroup.cpp index 46adf529b..c6ec21766 100644 --- a/src/tallies/filter_delayedgroup.cpp +++ b/src/tallies/filter_delayedgroup.cpp @@ -11,7 +11,7 @@ void DelayedGroupFilter::from_xml(pugi::xml_node node) this->set_groups(groups); } -void DelayedGroupFilter::set_groups(span groups) +void DelayedGroupFilter::set_groups(gsl::span groups) { // Clear existing groups groups_.clear(); @@ -27,7 +27,7 @@ void DelayedGroupFilter::set_groups(span groups) } else if (group > MAX_DELAYED_GROUPS) { throw std::invalid_argument { "Encountered delayedgroup bin with index " + std::to_string(group) + - " which is greater than MAX_DELAYED_GROUPS (" + + " which is greater than MAX_DELATED_GROUPS (" + std::to_string(MAX_DELAYED_GROUPS) + ")"}; } groups_.push_back(group); @@ -39,10 +39,6 @@ void DelayedGroupFilter::set_groups(span groups) void DelayedGroupFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - // Note that the bin is set to zero here, but bins outside zero are - // tallied to regardless. This is because that logic has to be handled - // in the scoring code instead where looping over the delayed - // group takes place (tally_scoring.cpp). match.bins_.push_back(0); match.weights_.push_back(1.0); } diff --git a/src/tallies/filter_distribcell.cpp b/src/tallies/filter_distribcell.cpp index f511a6816..89349b61f 100644 --- a/src/tallies/filter_distribcell.cpp +++ b/src/tallies/filter_distribcell.cpp @@ -1,7 +1,5 @@ #include "openmc/tallies/filter_distribcell.h" -#include - #include #include "openmc/cell.h" @@ -31,10 +29,10 @@ void DistribcellFilter::from_xml(pugi::xml_node node) void DistribcellFilter::set_cell(int32_t cell) { - assert(cell >= 0); - assert(cell < model::cells.size()); + Expects(cell >= 0); + Expects(cell < model::cells.size()); cell_ = cell; - n_bins_ = model::cells[cell]->n_instances(); + n_bins_ = model::cells[cell]->n_instances_; } void DistribcellFilter::get_all_bins( @@ -43,18 +41,17 @@ void DistribcellFilter::get_all_bins( int offset = 0; auto distribcell_index = model::cells[cell_]->distribcell_index_; for (int i = 0; i < p.n_coord(); i++) { - auto& c {*model::cells[p.coord(i).cell()]}; + auto& c {*model::cells[p.coord(i).cell]}; if (c.type_ == Fill::UNIVERSE) { offset += c.offset_[distribcell_index]; } else if (c.type_ == Fill::LATTICE) { - auto& lat {*model::lattices[p.coord(i + 1).lattice()]}; - const auto& i_xyz {p.coord(i + 1).lattice_index()}; + auto& lat {*model::lattices[p.coord(i + 1).lattice]}; + const auto& i_xyz {p.coord(i + 1).lattice_i}; if (lat.are_valid_indices(i_xyz)) { - offset += - lat.offset(distribcell_index, i_xyz) + c.offset_[distribcell_index]; + offset += lat.offset(distribcell_index, i_xyz); } } - if (cell_ == p.coord(i).cell()) { + if (cell_ == p.coord(i).cell) { match.bins_.push_back(offset); match.weights_.push_back(1.0); return; diff --git a/src/tallies/filter_energy.cpp b/src/tallies/filter_energy.cpp index 566b5710a..48448cb1f 100644 --- a/src/tallies/filter_energy.cpp +++ b/src/tallies/filter_energy.cpp @@ -3,7 +3,7 @@ #include #include "openmc/capi.h" -#include "openmc/constants.h" // For C_NONE +#include "openmc/constants.h" // For F90_NONE #include "openmc/mgxs_interface.h" #include "openmc/search.h" #include "openmc/settings.h" @@ -21,14 +21,14 @@ void EnergyFilter::from_xml(pugi::xml_node node) this->set_bins(bins); } -void EnergyFilter::set_bins(span bins) +void EnergyFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); bins_.reserve(bins.size()); // Copy bins, ensuring they are valid - for (int64_t i = 0; i < bins.size(); ++i) { + for (gsl::index i = 0; i < bins.size(); ++i) { if (i > 0 && bins[i] <= bins[i - 1]) { throw std::runtime_error { "Energy bins must be monotonically increasing."}; @@ -46,7 +46,7 @@ void EnergyFilter::set_bins(span bins) if (!settings::run_CE) { if (n_bins_ == data::mg.num_energy_groups_) { matches_transport_groups_ = true; - for (int64_t i = 0; i < n_bins_ + 1; ++i) { + for (gsl::index i = 0; i < n_bins_ + 1; ++i) { if (data::mg.rev_energy_bins_[i] != bins_[i]) { matches_transport_groups_ = false; break; @@ -59,9 +59,14 @@ void EnergyFilter::set_bins(span bins) void EnergyFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - if (p.g() != C_NONE && matches_transport_groups_) { - match.bins_.push_back(data::mg.num_energy_groups_ - p.g_last() - 1); + if (p.g() != F90_NONE && matches_transport_groups_) { + if (estimator == TallyEstimator::TRACKLENGTH) { + match.bins_.push_back(data::mg.num_energy_groups_ - p.g() - 1); + } else { + match.bins_.push_back(data::mg.num_energy_groups_ - p.g_last() - 1); + } match.weights_.push_back(1.0); + } else { // Get the pre-collision energy of the particle. auto E = p.E_last(); @@ -93,7 +98,7 @@ std::string EnergyFilter::text_label(int bin) const void EnergyoutFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - if (p.g() != C_NONE && matches_transport_groups_) { + if (p.g() != F90_NONE && matches_transport_groups_) { match.bins_.push_back(data::mg.num_energy_groups_ - p.g() - 1); match.weights_.push_back(1.0); diff --git a/src/tallies/filter_energyfunc.cpp b/src/tallies/filter_energyfunc.cpp index fc4ba0ff9..fd595e332 100644 --- a/src/tallies/filter_energyfunc.cpp +++ b/src/tallies/filter_energyfunc.cpp @@ -3,7 +3,6 @@ #include #include "openmc/error.h" -#include "openmc/interpolate.h" #include "openmc/search.h" #include "openmc/settings.h" #include "openmc/xml_interface.h" @@ -25,18 +24,12 @@ void EnergyFunctionFilter::from_xml(pugi::xml_node node) fatal_error("y values not specified for EnergyFunction filter."); auto y = get_node_array(node, "y"); - this->set_data(energy, y); - // default to linear-linear interpolation - interpolation_ = Interpolation::lin_lin; - if (check_for_node(node, "interpolation")) { - std::string interpolation = get_node_value(node, "interpolation"); - this->set_interpolation(interpolation); - } + this->set_data(energy, y); } void EnergyFunctionFilter::set_data( - span energy, span y) + gsl::span energy, gsl::span y) { // Check for consistent sizes with new data if (energy.size() != y.size()) { @@ -48,7 +41,7 @@ void EnergyFunctionFilter::set_data( y_.reserve(y.size()); // Copy over energy values, ensuring they are valid - for (int64_t i = 0; i < energy.size(); ++i) { + for (gsl::index i = 0; i < energy.size(); ++i) { if (i > 0 && energy[i] <= energy[i - 1]) { throw std::runtime_error { "Energy bins must be monotonically increasing."}; @@ -58,48 +51,19 @@ void EnergyFunctionFilter::set_data( } } -void EnergyFunctionFilter::set_interpolation(const std::string& interpolation) -{ - if (interpolation == "histogram") { - interpolation_ = Interpolation::histogram; - } else if (interpolation == "linear-linear") { - interpolation_ = Interpolation::lin_lin; - } else if (interpolation == "linear-log") { - interpolation_ = Interpolation::lin_log; - } else if (interpolation == "log-linear") { - interpolation_ = Interpolation::log_lin; - } else if (interpolation == "log-log") { - interpolation_ = Interpolation::log_log; - } else if (interpolation == "quadratic") { - if (energy_.size() < 3) - fatal_error( - fmt::format("Quadratic interpolation on EnergyFunctionFilter {} " - "requires at least 3 data points.", - this->id())); - interpolation_ = Interpolation::quadratic; - } else if (interpolation == "cubic") { - if (energy_.size() < 4) - fatal_error(fmt::format("Cubic interpolation on EnergyFunctionFilter " - "{} requires at least 4 data points.", - this->id())); - interpolation_ = Interpolation::cubic; - } else { - fatal_error(fmt::format( - "Found invalid interpolation type '{}' on EnergyFunctionFilter {}.", - interpolation, this->id())); - } -} - void EnergyFunctionFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { if (p.E_last() >= energy_.front() && p.E_last() <= energy_.back()) { + // Search for the incoming energy bin. + auto i = lower_bound_index(energy_.begin(), energy_.end(), p.E_last()); - double w = interpolate(energy_, y_, p.E_last(), interpolation_); + // Compute the interpolation factor between the nearest bins. + double f = (p.E_last() - energy_[i]) / (energy_[i + 1] - energy_[i]); // Interpolate on the lin-lin grid. match.bins_.push_back(0); - match.weights_.push_back(w); + match.weights_.push_back((1 - f) * y_[i] + f * y_[i + 1]); } } @@ -108,10 +72,6 @@ void EnergyFunctionFilter::to_statepoint(hid_t filter_group) const Filter::to_statepoint(filter_group); write_dataset(filter_group, "energy", energy_); write_dataset(filter_group, "y", y_); - hid_t y_dataset = open_dataset(filter_group, "y"); - write_attribute( - y_dataset, "interpolation", static_cast(interpolation_)); - close_dataset(y_dataset); } std::string EnergyFunctionFilter::text_label(int bin) const @@ -194,51 +154,4 @@ extern "C" int openmc_energyfunc_filter_get_y( return 0; } -extern "C" int openmc_energyfunc_filter_set_interpolation( - int32_t index, const char* interp) -{ - // ensure this is a valid index to allocated filter - if (int err = verify_filter(index)) - return err; - - // get a pointer to the filter - const auto& filt_base = model::tally_filters[index].get(); - // downcast to EnergyFunctionFilter - auto* filt = dynamic_cast(filt_base); - - // check if a valid filter was produced - if (!filt) { - set_errmsg( - "Tried to set interpolation data for non-energy function filter."); - return OPENMC_E_INVALID_TYPE; - } - - // Set interpolation - filt->set_interpolation(interp); - return 0; -} - -extern "C" int openmc_energyfunc_filter_get_interpolation( - int32_t index, int* interp) -{ - // ensure this is a valid index to allocated filter - if (int err = verify_filter(index)) - return err; - - // get a pointer to the filter - const auto& filt_base = model::tally_filters[index].get(); - // downcast to EnergyFunctionFilter - auto* filt = dynamic_cast(filt_base); - - // check if a valid filter was produced - if (!filt) { - set_errmsg( - "Tried to set interpolation data for non-energy function filter."); - return OPENMC_E_INVALID_TYPE; - } - - *interp = static_cast(filt->interpolation()); - return 0; -} - } // namespace openmc diff --git a/src/tallies/filter_material.cpp b/src/tallies/filter_material.cpp index 215c9af72..6669ab2fa 100644 --- a/src/tallies/filter_material.cpp +++ b/src/tallies/filter_material.cpp @@ -1,7 +1,5 @@ #include "openmc/tallies/filter_material.h" -#include - #include #include "openmc/capi.h" @@ -26,7 +24,7 @@ void MaterialFilter::from_xml(pugi::xml_node node) this->set_materials(mats); } -void MaterialFilter::set_materials(span materials) +void MaterialFilter::set_materials(gsl::span materials) { // Clear existing materials materials_.clear(); @@ -35,8 +33,8 @@ void MaterialFilter::set_materials(span materials) // Update materials and mapping for (auto& index : materials) { - assert(index >= 0); - assert(index < model::materials.size()); + Expects(index >= 0); + Expects(index < model::materials.size()); materials_.push_back(index); map_[index] = materials_.size() - 1; } diff --git a/src/tallies/filter_materialfrom.cpp b/src/tallies/filter_materialfrom.cpp deleted file mode 100644 index 91f03aef8..000000000 --- a/src/tallies/filter_materialfrom.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "openmc/tallies/filter_materialfrom.h" - -#include "openmc/cell.h" -#include "openmc/material.h" - -namespace openmc { - -void MaterialFromFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - auto search = map_.find(p.material_last()); - if (search != map_.end()) { - match.bins_.push_back(search->second); - match.weights_.push_back(1.0); - } -} - -std::string MaterialFromFilter::text_label(int bin) const -{ - return "Material from " + - std::to_string(model::materials[materials_[bin]]->id_); -} - -} // namespace openmc diff --git a/src/tallies/filter_mesh.cpp b/src/tallies/filter_mesh.cpp index a0698992d..3f895b4f8 100644 --- a/src/tallies/filter_mesh.cpp +++ b/src/tallies/filter_mesh.cpp @@ -1,12 +1,12 @@ #include "openmc/tallies/filter_mesh.h" #include +#include #include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/mesh.h" -#include "openmc/position.h" #include "openmc/xml_interface.h" namespace openmc { @@ -16,7 +16,7 @@ void MeshFilter::from_xml(pugi::xml_node node) auto bins_ = get_node_array(node, "bins"); if (bins_.size() != 1) { fatal_error( - "Only one mesh can be specified per " + type_str() + " mesh filter."); + "Only one mesh can be specified per " + type() + " mesh filter."); } auto id = bins_[0]; @@ -31,10 +31,6 @@ void MeshFilter::from_xml(pugi::xml_node node) if (check_for_node(node, "translation")) { set_translation(get_node_array(node, "translation")); } - // Read the rotation transform. - if (check_for_node(node, "rotation")) { - set_rotation(get_node_array(node, "rotation")); - } } void MeshFilter::get_all_bins( @@ -50,12 +46,6 @@ void MeshFilter::get_all_bins( last_r -= translation(); r -= translation(); } - // apply rotation if present - if (!rotation_.empty()) { - last_r = last_r.rotate(rotation_); - r = r.rotate(rotation_); - u = u.rotate(rotation_); - } if (estimator != TallyEstimator::TRACKLENGTH) { auto bin = model::meshes[mesh_]->get_bin(r); @@ -76,9 +66,6 @@ void MeshFilter::to_statepoint(hid_t filter_group) const if (translated_) { write_dataset(filter_group, "translation", translation_); } - if (rotated_) { - write_dataset(filter_group, "rotation", rotation_); - } } std::string MeshFilter::text_label(int bin) const @@ -90,10 +77,8 @@ std::string MeshFilter::text_label(int bin) const void MeshFilter::set_mesh(int32_t mesh) { - // perform any additional perparation for mesh tallies here mesh_ = mesh; n_bins_ = model::meshes[mesh_]->n_bins(); - model::meshes[mesh_]->prepare_for_point_location(); } void MeshFilter::set_translation(const Position& translation) @@ -107,40 +92,6 @@ void MeshFilter::set_translation(const double translation[3]) this->set_translation({translation[0], translation[1], translation[2]}); } -void MeshFilter::set_rotation(const vector& rot) -{ - rotated_ = true; - - // Compute and store the inverse rotation matrix for the angles given. - rotation_.clear(); - rotation_.reserve(rot.size() == 9 ? 9 : 12); - if (rot.size() == 3) { - double phi = -rot[0] * PI / 180.0; - double theta = -rot[1] * PI / 180.0; - double psi = -rot[2] * PI / 180.0; - rotation_.push_back(std::cos(theta) * std::cos(psi)); - rotation_.push_back(-std::cos(phi) * std::sin(psi) + - std::sin(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::sin(phi) * std::sin(psi) + - std::cos(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::cos(theta) * std::sin(psi)); - rotation_.push_back(std::cos(phi) * std::cos(psi) + - std::sin(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(phi) * std::cos(psi) + - std::cos(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(theta)); - rotation_.push_back(std::sin(phi) * std::cos(theta)); - rotation_.push_back(std::cos(phi) * std::cos(theta)); - - // When user specifies angles, write them at end of vector - rotation_.push_back(rot[0]); - rotation_.push_back(rot[1]); - rotation_.push_back(rot[2]); - } else { - std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); - } -} - //============================================================================== // C-API functions //============================================================================== @@ -207,9 +158,7 @@ extern "C" int openmc_mesh_filter_get_translation( // Check the filter type const auto& filter = model::tally_filters[index]; - if (filter->type() != FilterType::MESH && - filter->type() != FilterType::MESHBORN && - filter->type() != FilterType::MESH_SURFACE) { + if (filter->type() != "mesh" && filter->type() != "meshsurface") { set_errmsg("Tried to get a translation from a non-mesh-based filter."); return OPENMC_E_INVALID_TYPE; } @@ -233,9 +182,7 @@ extern "C" int openmc_mesh_filter_set_translation( const auto& filter = model::tally_filters[index]; // Check the filter type - if (filter->type() != FilterType::MESH && - filter->type() != FilterType::MESHBORN && - filter->type() != FilterType::MESH_SURFACE) { + if (filter->type() != "mesh" && filter->type() != "meshsurface") { set_errmsg("Tried to set mesh on a non-mesh-based filter."); return OPENMC_E_INVALID_TYPE; } @@ -249,48 +196,4 @@ extern "C" int openmc_mesh_filter_set_translation( return 0; } -//! Return the rotation matrix of a mesh filter -extern "C" int openmc_mesh_filter_get_rotation( - int32_t index, double rot[], size_t* n) -{ - // Make sure this is a valid index to an allocated filter - if (int err = verify_filter(index)) - return err; - - // Check the filter type - const auto& filter = model::tally_filters[index]; - if (filter->type() != FilterType::MESH) { - set_errmsg("Tried to get a rotation from a non-mesh filter."); - return OPENMC_E_INVALID_TYPE; - } - // Get rotation from the mesh filter and set value - auto mesh_filter = dynamic_cast(filter.get()); - *n = mesh_filter->rotation().size(); - std::memcpy(rot, mesh_filter->rotation().data(), - *n * sizeof(mesh_filter->rotation()[0])); - return 0; -} - -//! Set the flattened rotation matrix of a mesh filter -extern "C" int openmc_mesh_filter_set_rotation( - int32_t index, const double rot[], size_t rot_len) -{ - // Make sure this is a valid index to an allocated filter - if (int err = verify_filter(index)) - return err; - - const auto& filter = model::tally_filters[index]; - // Check the filter type - if (filter->type() != FilterType::MESH) { - set_errmsg("Tried to set a rotation from a non-mesh filter."); - return OPENMC_E_INVALID_TYPE; - } - - // Get a pointer to the filter and downcast - auto mesh_filter = dynamic_cast(filter.get()); - std::vector vec_rot(rot, rot + rot_len); - mesh_filter->set_rotation(vec_rot); - return 0; -} - } // namespace openmc diff --git a/src/tallies/filter_meshborn.cpp b/src/tallies/filter_meshborn.cpp deleted file mode 100644 index c95dc3dc7..000000000 --- a/src/tallies/filter_meshborn.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "openmc/tallies/filter_meshborn.h" - -#include "openmc/capi.h" -#include "openmc/constants.h" -#include "openmc/error.h" -#include "openmc/mesh.h" - -namespace openmc { - -void MeshBornFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - Position r_born = p.r_born(); - - // apply translation if present - if (translated_) { - r_born -= translation(); - } - - auto bin = model::meshes[mesh_]->get_bin(r_born); - if (bin >= 0) { - match.bins_.push_back(bin); - match.weights_.push_back(1.0); - } -} - -std::string MeshBornFilter::text_label(int bin) const -{ - auto& mesh = *model::meshes.at(mesh_); - return mesh.bin_label(bin) + " (born)"; -} - -//============================================================================== -// C-API functions -//============================================================================== - -extern "C" int openmc_meshborn_filter_get_mesh( - int32_t index, int32_t* index_mesh) -{ - return openmc_mesh_filter_get_mesh(index, index_mesh); -} - -extern "C" int openmc_meshborn_filter_set_mesh( - int32_t index, int32_t index_mesh) -{ - return openmc_mesh_filter_set_mesh(index, index_mesh); -} - -extern "C" int openmc_meshborn_filter_get_translation( - int32_t index, double translation[3]) -{ - return openmc_mesh_filter_get_translation(index, translation); -} - -extern "C" int openmc_meshborn_filter_set_translation( - int32_t index, double translation[3]) -{ - return openmc_mesh_filter_set_translation(index, translation); -} - -} // namespace openmc diff --git a/src/tallies/filter_meshmaterial.cpp b/src/tallies/filter_meshmaterial.cpp deleted file mode 100644 index b45bb4164..000000000 --- a/src/tallies/filter_meshmaterial.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "openmc/tallies/filter_meshmaterial.h" - -#include -#include // for move - -#include - -#include "openmc/capi.h" -#include "openmc/constants.h" -#include "openmc/container_util.h" -#include "openmc/error.h" -#include "openmc/material.h" -#include "openmc/mesh.h" -#include "openmc/tensor.h" -#include "openmc/xml_interface.h" - -namespace openmc { - -void MeshMaterialFilter::from_xml(pugi::xml_node node) -{ - // Get mesh ID - auto mesh = get_node_array(node, "mesh"); - if (mesh.size() != 1) { - fatal_error( - "Only one mesh can be specified per " + type_str() + " mesh filter."); - } - - auto id = mesh[0]; - auto search = model::mesh_map.find(id); - if (search == model::mesh_map.end()) { - fatal_error( - fmt::format("Could not find mesh {} specified on tally filter.", id)); - } - set_mesh(search->second); - - // Get pairs of (element index, material) and set the bins - auto bins = get_node_array(node, "bins"); - this->set_bins(bins); - - if (check_for_node(node, "translation")) { - set_translation(get_node_array(node, "translation")); - } -} - -void MeshMaterialFilter::set_bins(span bins) -{ - if (bins.size() % 2 != 0) { - fatal_error( - fmt::format("Size of mesh material bins is not even: {}", bins.size())); - } - - // Create a vector of ElementMat pairs from the flat vector of bins - vector element_mats; - for (int64_t i = 0; i < bins.size() / 2; ++i) { - int32_t element = bins[2 * i]; - int32_t mat_id = bins[2 * i + 1]; - auto search = model::material_map.find(mat_id); - if (search == model::material_map.end()) { - fatal_error(fmt::format( - "Could not find material {} specified on tally filter.", mat_id)); - } - int32_t mat_index = search->second; - element_mats.push_back({element, mat_index}); - } - - this->set_bins(std::move(element_mats)); -} - -void MeshMaterialFilter::set_bins(vector&& bins) -{ - // Swap internal bins_ with the provided vector to avoid copying - bins_.swap(bins); - - // Clear and update the mapping and vector of materials - materials_.clear(); - map_.clear(); - for (std::size_t i = 0; i < bins_.size(); ++i) { - const auto& x = bins_[i]; - assert(x.index_mat >= 0); - assert(x.index_mat < model::materials.size()); - materials_.insert(x.index_mat); - map_[x] = i; - } - - n_bins_ = bins_.size(); -} - -void MeshMaterialFilter::set_mesh(int32_t mesh) -{ - // perform any additional perparation for mesh tallies here - mesh_ = mesh; - model::meshes[mesh_]->prepare_for_point_location(); -} - -void MeshMaterialFilter::set_translation(const Position& translation) -{ - translated_ = true; - translation_ = translation; -} - -void MeshMaterialFilter::set_translation(const double translation[3]) -{ - this->set_translation({translation[0], translation[1], translation[2]}); -} - -void MeshMaterialFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - // If current material is not in any bins, don't bother checking - if (!contains(materials_, p.material())) { - return; - } - - Position last_r = p.r_last(); - Position r = p.r(); - Position u = p.u(); - - // apply translation if present - if (translated_) { - last_r -= translation(); - r -= translation(); - } - - if (estimator != TallyEstimator::TRACKLENGTH) { - int32_t index_element = model::meshes[mesh_]->get_bin(r); - if (index_element >= 0) { - auto search = map_.find({index_element, p.material()}); - if (search != map_.end()) { - match.bins_.push_back(search->second); - match.weights_.push_back(1.0); - } - } - } else { - // First determine which elements the particle crosses (may or may not - // actually match bins so we have to adjust bins_/weight_ after) - int32_t n_start = match.bins_.size(); - model::meshes[mesh_]->bins_crossed( - last_r, r, u, match.bins_, match.weights_); - int32_t n_end = match.bins_.size(); - - // Go through bins and weights and check which ones are actually a match - // based on the (element, material) pair. For matches, overwrite the bin. - int i = 0; - for (int j = n_start; j < n_end; ++j) { - int32_t index_element = match.bins_[j]; - double weight = match.weights_[j]; - auto search = map_.find({index_element, p.material()}); - if (search != map_.end()) { - match.bins_[n_start + i] = search->second; - match.weights_[n_start + i] = weight; - ++i; - } - } - - // Resize the vectors to remove the unmatched bins - match.bins_.resize(n_start + i); - } -} - -void MeshMaterialFilter::to_statepoint(hid_t filter_group) const -{ - Filter::to_statepoint(filter_group); - write_dataset(filter_group, "mesh", model::meshes[mesh_]->id_); - - size_t n = bins_.size(); - tensor::Tensor data({n, 2}); - for (int64_t i = 0; i < n; ++i) { - const auto& x = bins_[i]; - data(i, 0) = x.index_element; - data(i, 1) = model::materials[x.index_mat]->id_; - } - write_dataset(filter_group, "bins", data); - - if (translated_) { - write_dataset(filter_group, "translation", translation_); - } -} - -std::string MeshMaterialFilter::text_label(int bin) const -{ - auto& x = bins_[bin]; - auto& mesh = *model::meshes.at(mesh_); - return fmt::format("Mesh {}, {}, Material {}", mesh.id(), - mesh.bin_label(x.index_element), model::materials[x.index_mat]->id_); -} - -} // namespace openmc diff --git a/src/tallies/filter_meshsurface.cpp b/src/tallies/filter_meshsurface.cpp index b26cd198b..b22085ebb 100644 --- a/src/tallies/filter_meshsurface.cpp +++ b/src/tallies/filter_meshsurface.cpp @@ -100,16 +100,4 @@ extern "C" int openmc_meshsurface_filter_set_mesh( return openmc_mesh_filter_set_mesh(index, index_mesh); } -extern "C" int openmc_meshsurface_filter_get_translation( - int32_t index, double translation[3]) -{ - return openmc_mesh_filter_get_translation(index, translation); -} - -extern "C" int openmc_meshsurface_filter_set_translation( - int32_t index, double translation[3]) -{ - return openmc_mesh_filter_set_translation(index, translation); -} - } // namespace openmc diff --git a/src/tallies/filter_mu.cpp b/src/tallies/filter_mu.cpp index 63915a533..95bb3b210 100644 --- a/src/tallies/filter_mu.cpp +++ b/src/tallies/filter_mu.cpp @@ -31,14 +31,14 @@ void MuFilter::from_xml(pugi::xml_node node) this->set_bins(bins); } -void MuFilter::set_bins(span bins) +void MuFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); bins_.reserve(bins.size()); // Copy bins, ensuring they are valid - for (int64_t i = 0; i < bins.size(); ++i) { + for (gsl::index i = 0; i < bins.size(); ++i) { if (i > 0 && bins[i] <= bins[i - 1]) { throw std::runtime_error {"Mu bins must be monotonically increasing."}; } diff --git a/src/tallies/filter_musurface.cpp b/src/tallies/filter_musurface.cpp deleted file mode 100644 index 340149d4c..000000000 --- a/src/tallies/filter_musurface.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "openmc/tallies/filter_musurface.h" - -#include // for abs, copysign - -#include "openmc/search.h" -#include "openmc/surface.h" -#include "openmc/tallies/tally_scoring.h" - -namespace openmc { - -void MuSurfaceFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - // Get surface normal (and make sure it is a unit vector) - const auto surf {model::surfaces[p.surface_index()].get()}; - auto n = surf->normal(p.r()); - n /= n.norm(); - - // Determine whether normal should be pointing in or out - if (p.surface() < 0) - n *= -1; - - // Determine cosine of angle between normal and particle direction - double mu = p.u().dot(n); - if (std::abs(mu) > 1.0) - mu = std::copysign(1.0, mu); - - // Find matching bin - if (mu >= bins_.front() && mu <= bins_.back()) { - auto bin = lower_bound_index(bins_.begin(), bins_.end(), mu); - match.bins_.push_back(bin); - match.weights_.push_back(1.0); - } -} - -} // namespace openmc diff --git a/src/tallies/filter_parent_nuclide.cpp b/src/tallies/filter_parent_nuclide.cpp deleted file mode 100644 index d04941075..000000000 --- a/src/tallies/filter_parent_nuclide.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "openmc/tallies/filter_parent_nuclide.h" - -#include // for int64_t - -#include - -#include "openmc/capi.h" -#include "openmc/chain.h" -#include "openmc/search.h" -#include "openmc/settings.h" -#include "openmc/xml_interface.h" - -namespace openmc { - -//============================================================================== -// ParentNuclideFilter implementation -//============================================================================== - -void ParentNuclideFilter::from_xml(pugi::xml_node node) -{ - nuclides_ = get_node_array(node, "bins"); - - // Convert nuclides to indices in data::chain_nuclides - std::vector bins; - for (const auto& nuclide : nuclides_) { - auto it = data::chain_nuclide_map.find(nuclide); - if (it != data::chain_nuclide_map.end()) { - bins.push_back(it->second); - } else { - // The default value of parent_nuclide is -1, so to prevent a score to - // this bin assign the value -2. - bins.push_back(-2); - } - } - this->set_bins(bins); -} - -void ParentNuclideFilter::set_bins(span bins) -{ - // Clear existing bins - bins_.clear(); - bins_.reserve(bins.size()); - map_.clear(); - - // Set bins based on chain nuclide indexing - for (int64_t i = 0; i < bins.size(); ++i) { - bins_.push_back(bins[i]); - map_[bins[i]] = i; - } - - n_bins_ = bins_.size(); -} - -void ParentNuclideFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - // Get the particle's parent nuclide - int parent_nuclide = p.parent_nuclide(); - - // Find bin matching parent nuclide - auto search = map_.find(parent_nuclide); - if (search != map_.end()) { - match.bins_.push_back(search->second); - match.weights_.push_back(1.0); - } -} - -void ParentNuclideFilter::to_statepoint(hid_t filter_group) const -{ - Filter::to_statepoint(filter_group); - write_dataset(filter_group, "bins", nuclides_); -} - -std::string ParentNuclideFilter::text_label(int bin) const -{ - return fmt::format("Parent Nuclide {}", nuclides_[bin]); -} - -} // namespace openmc diff --git a/src/tallies/filter_particle.cpp b/src/tallies/filter_particle.cpp index 031068f3a..3865824f6 100644 --- a/src/tallies/filter_particle.cpp +++ b/src/tallies/filter_particle.cpp @@ -13,12 +13,12 @@ void ParticleFilter::from_xml(pugi::xml_node node) // Convert to vector of ParticleType vector types; for (auto& p : particles) { - types.emplace_back(p); + types.push_back(str_to_particle_type(p)); } this->set_particles(types); } -void ParticleFilter::set_particles(span particles) +void ParticleFilter::set_particles(gsl::span particles) { // Clear existing particles particles_.clear(); @@ -47,7 +47,7 @@ void ParticleFilter::to_statepoint(hid_t filter_group) const Filter::to_statepoint(filter_group); vector particles; for (auto p : particles_) { - particles.push_back(p.str()); + particles.push_back(particle_type_to_str(p)); } write_dataset(filter_group, "bins", particles); } @@ -55,26 +55,7 @@ void ParticleFilter::to_statepoint(hid_t filter_group) const std::string ParticleFilter::text_label(int bin) const { const auto& p = particles_.at(bin); - return fmt::format("Particle: {}", p.str()); -} - -extern "C" int openmc_particle_filter_get_bins(int32_t idx, int32_t bins[]) -{ - if (int err = verify_filter(idx)) - return err; - - const auto& f = model::tally_filters[idx]; - auto pf = dynamic_cast(f.get()); - if (pf) { - const auto& particles = pf->particles(); - for (int i = 0; i < particles.size(); i++) { - bins[i] = particles[i].pdg_number(); - } - } else { - set_errmsg("The filter at the specified index is not a ParticleFilter"); - return OPENMC_E_INVALID_ARGUMENT; - } - return 0; + return fmt::format("Particle: {}", particle_type_to_str(p)); } } // namespace openmc diff --git a/src/tallies/filter_particle_production.cpp b/src/tallies/filter_particle_production.cpp deleted file mode 100644 index 899809679..000000000 --- a/src/tallies/filter_particle_production.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "openmc/tallies/filter_particle_production.h" - -#include - -#include "openmc/search.h" -#include "openmc/xml_interface.h" - -namespace openmc { - -//============================================================================== -// ParticleProductionFilter implementation -//============================================================================== - -void ParticleProductionFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - int start_idx = p.secondary_bank_index(); - int end_idx = start_idx + p.n_secondaries(); - - // Loop over secondary bank entries - for (int bank_idx = start_idx; bank_idx < end_idx; bank_idx++) { - const auto& site = p.local_secondary_bank(bank_idx); - - // Find which particle-type slot this secondary belongs to - auto it = type_to_index_.find(site.particle.pdg_number()); - if (it == type_to_index_.end()) - continue; - - int particle_idx = it->second; - if (energy_bins_.empty()) { - // No energy binning, just particle type - match.bins_.push_back(particle_idx); - match.weights_.push_back(site.wgt); - } else { - // Bin the energy - if (site.E >= energy_bins_.front() && site.E <= energy_bins_.back()) { - int n_energies = static_cast(energy_bins_.size()) - 1; - auto energy_idx = - lower_bound_index(energy_bins_.begin(), energy_bins_.end(), site.E); - match.bins_.push_back(particle_idx * n_energies + energy_idx); - match.weights_.push_back(site.wgt); - } - } - } -} - -std::string ParticleProductionFilter::text_label(int bin) const -{ - if (energy_bins_.empty()) { - return fmt::format("Secondary {}", secondary_types_.at(bin).str()); - } else { - int n_energies = static_cast(energy_bins_.size()) - 1; - int particle_idx = bin / n_energies; - int energy_idx = bin % n_energies; - return fmt::format("Secondary {}, Energy [{}, {})", - secondary_types_.at(particle_idx).str(), energy_bins_.at(energy_idx), - energy_bins_.at(energy_idx + 1)); - } -} - -void ParticleProductionFilter::from_xml(pugi::xml_node node) -{ - // Read energy bins if present (optional) - if (check_for_node(node, "energies")) { - auto bins = get_node_array(node, "energies"); - for (int64_t i = 1; i < bins.size(); ++i) { - if (bins[i] <= bins[i - 1]) { - throw std::runtime_error { - "Energy bins must be monotonically increasing."}; - } - } - energy_bins_.assign(bins.begin(), bins.end()); - } - - // Read particle types (required) - auto names = get_node_array(node, "particles"); - for (const auto& name : names) { - int idx = secondary_types_.size(); - secondary_types_.emplace_back(name); - type_to_index_[secondary_types_.back().pdg_number()] = idx; - } - - // Compute total bins - if (energy_bins_.empty()) { - n_bins_ = secondary_types_.size(); - } else { - n_bins_ = secondary_types_.size() * (energy_bins_.size() - 1); - } -} - -void ParticleProductionFilter::to_statepoint(hid_t filter_group) const -{ - Filter::to_statepoint(filter_group); - - // Write energy bins if present - if (!energy_bins_.empty()) { - write_dataset(filter_group, "energies", energy_bins_); - } - - // Write particle types - vector names; - for (const auto& pt : secondary_types_) { - names.push_back(pt.str()); - } - write_dataset(filter_group, "particles", names); -} - -} // namespace openmc diff --git a/src/tallies/filter_polar.cpp b/src/tallies/filter_polar.cpp index 29be6a437..d132ccf42 100644 --- a/src/tallies/filter_polar.cpp +++ b/src/tallies/filter_polar.cpp @@ -32,14 +32,14 @@ void PolarFilter::from_xml(pugi::xml_node node) this->set_bins(bins); } -void PolarFilter::set_bins(span bins) +void PolarFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); bins_.reserve(bins.size()); // Copy bins, ensuring they are valid - for (int64_t i = 0; i < bins.size(); ++i) { + for (gsl::index i = 0; i < bins.size(); ++i) { if (i > 0 && bins[i] <= bins[i - 1]) { throw std::runtime_error {"Polar bins must be monotonically increasing."}; } diff --git a/src/tallies/filter_reaction.cpp b/src/tallies/filter_reaction.cpp deleted file mode 100644 index 8ee9f3ce8..000000000 --- a/src/tallies/filter_reaction.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "openmc/tallies/filter_reaction.h" - -#include - -#include "openmc/capi.h" -#include "openmc/endf.h" -#include "openmc/error.h" -#include "openmc/reaction.h" -#include "openmc/xml_interface.h" - -namespace openmc { - -//============================================================================== -// ReactionFilter implementation -//============================================================================== - -void ReactionFilter::from_xml(pugi::xml_node node) -{ - // Read bins as reaction name strings - auto bins_str = get_node_array(node, "bins"); - - // Convert reaction names to MT numbers - vector bins_mt; - bins_mt.reserve(bins_str.size()); - for (const auto& name : bins_str) { - bins_mt.push_back(reaction_mt(name)); - } - - this->set_bins(bins_mt); -} - -void ReactionFilter::set_bins(span bins) -{ - // Clear existing bins - bins_.clear(); - bins_.reserve(bins.size()); - - // Copy bins and build lookup map - for (int64_t i = 0; i < bins.size(); ++i) { - bins_.push_back(bins[i]); - } - - n_bins_ = bins_.size(); -} - -void ReactionFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - // Get the event MT number from the particle - int event_mt = p.event_mt(); - - // Check each bin, considering summation rules - for (int64_t i = 0; i < bins_.size(); ++i) { - if (mt_matches(event_mt, bins_[i])) { - match.bins_.push_back(i); - match.weights_.push_back(1.0); - } - } -} - -void ReactionFilter::to_statepoint(hid_t filter_group) const -{ - Filter::to_statepoint(filter_group); - - // Write bins as reaction name strings for human readability - vector names; - names.reserve(bins_.size()); - for (auto mt : bins_) { - names.push_back(reaction_name(mt)); - } - write_dataset(filter_group, "bins", names); -} - -std::string ReactionFilter::text_label(int bin) const -{ - return reaction_name(bins_[bin]); -} - -} // namespace openmc diff --git a/src/tallies/filter_sph_harm.cpp b/src/tallies/filter_sph_harm.cpp index 1989e6ef1..359df379b 100644 --- a/src/tallies/filter_sph_harm.cpp +++ b/src/tallies/filter_sph_harm.cpp @@ -1,9 +1,9 @@ #include "openmc/tallies/filter_sph_harm.h" -#include #include // For pair #include +#include #include "openmc/capi.h" #include "openmc/error.h" @@ -25,15 +25,12 @@ void SphericalHarmonicsFilter::set_order(int order) if (order < 0) { throw std::invalid_argument { "Spherical harmonics order must be non-negative."}; - } else if (order > 10) { - throw std::invalid_argument {"Spherical harmonics orders greater than 10 " - "are currently not supported!"}; } order_ = order; n_bins_ = (order_ + 1) * (order_ + 1); } -void SphericalHarmonicsFilter::set_cosine(const std::string& cosine) +void SphericalHarmonicsFilter::set_cosine(gsl::cstring_span cosine) { if (cosine == "scatter") { cosine_ = SphericalHarmonicsCosine::scatter; @@ -42,7 +39,7 @@ void SphericalHarmonicsFilter::set_cosine(const std::string& cosine) } else { throw std::invalid_argument {fmt::format("Unrecognized cosine type, \"{}\" " "in spherical harmonics filter", - cosine)}; + gsl::to_string(cosine))}; } } @@ -90,7 +87,7 @@ void SphericalHarmonicsFilter::to_statepoint(hid_t filter_group) const std::string SphericalHarmonicsFilter::text_label(int bin) const { - assert(bin >= 0 && bin < n_bins_); + Expects(bin >= 0 && bin < n_bins_); for (int n = 0; n < order_ + 1; n++) { if (bin < (n + 1) * (n + 1)) { int m = (bin - n * n) - n; diff --git a/src/tallies/filter_surface.cpp b/src/tallies/filter_surface.cpp index 4a636f1aa..a84d17728 100644 --- a/src/tallies/filter_surface.cpp +++ b/src/tallies/filter_surface.cpp @@ -1,7 +1,5 @@ #include "openmc/tallies/filter_surface.h" -#include - #include #include "openmc/error.h" @@ -28,7 +26,7 @@ void SurfaceFilter::from_xml(pugi::xml_node node) this->set_surfaces(surfaces); } -void SurfaceFilter::set_surfaces(span surfaces) +void SurfaceFilter::set_surfaces(gsl::span surfaces) { // Clear existing surfaces surfaces_.clear(); @@ -37,8 +35,8 @@ void SurfaceFilter::set_surfaces(span surfaces) // Update surfaces and mapping for (auto& index : surfaces) { - assert(index >= 0); - assert(index < model::surfaces.size()); + Expects(index >= 0); + Expects(index < model::surfaces.size()); surfaces_.push_back(index); map_[index] = surfaces_.size() - 1; } @@ -49,10 +47,14 @@ void SurfaceFilter::set_surfaces(span surfaces) void SurfaceFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - auto search = map_.find(p.surface_index()); + auto search = map_.find(std::abs(p.surface()) - 1); if (search != map_.end()) { match.bins_.push_back(search->second); - match.weights_.push_back(1.0); + if (p.surface() < 0) { + match.weights_.push_back(-1.0); + } else { + match.weights_.push_back(1.0); + } } } diff --git a/src/tallies/filter_time.cpp b/src/tallies/filter_time.cpp index 948d1347a..787acc49e 100644 --- a/src/tallies/filter_time.cpp +++ b/src/tallies/filter_time.cpp @@ -21,7 +21,7 @@ void TimeFilter::from_xml(pugi::xml_node node) this->set_bins(bins); } -void TimeFilter::set_bins(span bins) +void TimeFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); @@ -80,11 +80,10 @@ void TimeFilter::get_all_bins( if (t_end < bins_[i_bin + 1]) break; } - } else if (t_end < bins_.back()) { + } else { // ------------------------------------------------------------------------- // For collision estimator or surface tallies, find a match based on the // exact time of the particle - const auto i_bin = lower_bound_index(bins_.begin(), bins_.end(), t_end); match.bins_.push_back(i_bin); match.weights_.push_back(1.0); diff --git a/src/tallies/filter_universe.cpp b/src/tallies/filter_universe.cpp index f4b22decd..96ad0212d 100644 --- a/src/tallies/filter_universe.cpp +++ b/src/tallies/filter_universe.cpp @@ -1,7 +1,5 @@ #include "openmc/tallies/filter_universe.h" -#include - #include #include "openmc/cell.h" @@ -26,7 +24,7 @@ void UniverseFilter::from_xml(pugi::xml_node node) this->set_universes(universes); } -void UniverseFilter::set_universes(span universes) +void UniverseFilter::set_universes(gsl::span universes) { // Clear existing universes universes_.clear(); @@ -35,8 +33,8 @@ void UniverseFilter::set_universes(span universes) // Update universes and mapping for (auto& index : universes) { - assert(index >= 0); - assert(index < model::universes.size()); + Expects(index >= 0); + Expects(index < model::universes.size()); universes_.push_back(index); map_[index] = universes_.size() - 1; } @@ -48,7 +46,7 @@ void UniverseFilter::get_all_bins( const Particle& p, TallyEstimator estimator, FilterMatch& match) const { for (int i = 0; i < p.n_coord(); i++) { - auto search = map_.find(p.coord(i).universe()); + auto search = map_.find(p.coord(i).universe); if (search != map_.end()) { match.bins_.push_back(search->second); match.weights_.push_back(1.0); diff --git a/src/tallies/filter_weight.cpp b/src/tallies/filter_weight.cpp deleted file mode 100644 index 31f4bd1bf..000000000 --- a/src/tallies/filter_weight.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "openmc/tallies/filter_weight.h" - -#include // for is_sorted -#include // for runtime_error - -#include - -#include "openmc/search.h" -#include "openmc/xml_interface.h" - -namespace openmc { - -//============================================================================== -// WeightFilter implementation -//============================================================================== - -void WeightFilter::from_xml(pugi::xml_node node) -{ - auto bins = get_node_array(node, "bins"); - this->set_bins(bins); -} - -void WeightFilter::set_bins(span bins) -{ - if (!std::is_sorted(bins.begin(), bins.end())) { - throw std::runtime_error {"Weight bins must be monotonically increasing."}; - } - - // Clear existing bins - bins_.clear(); - bins_.reserve(bins.size()); - - // Copy bins - bins_.insert(bins_.end(), bins.begin(), bins.end()); - n_bins_ = bins_.size() - 1; -} - -void WeightFilter::get_all_bins( - const Particle& p, TallyEstimator estimator, FilterMatch& match) const -{ - // Get particle weight - double wgt = p.wgt_last(); - - // Bin the weight - if (wgt >= bins_.front() && wgt <= bins_.back()) { - auto bin = lower_bound_index(bins_.begin(), bins_.end(), wgt); - match.bins_.push_back(bin); - match.weights_.push_back(1.0); - } -} - -void WeightFilter::to_statepoint(hid_t filter_group) const -{ - Filter::to_statepoint(filter_group); - write_dataset(filter_group, "bins", bins_); -} - -std::string WeightFilter::text_label(int bin) const -{ - return fmt::format("Weight [{}, {}]", bins_[bin], bins_[bin + 1]); -} - -} // namespace openmc diff --git a/src/tallies/filter_zernike.cpp b/src/tallies/filter_zernike.cpp index af5b595aa..eb4c8bdfd 100644 --- a/src/tallies/filter_zernike.cpp +++ b/src/tallies/filter_zernike.cpp @@ -1,11 +1,11 @@ #include "openmc/tallies/filter_zernike.h" -#include #include #include #include // For pair #include +#include #include "openmc/capi.h" #include "openmc/error.h" @@ -57,7 +57,7 @@ void ZernikeFilter::to_statepoint(hid_t filter_group) const std::string ZernikeFilter::text_label(int bin) const { - assert(bin >= 0 && bin < n_bins_); + Expects(bin >= 0 && bin < n_bins_); for (int n = 0; n < order_ + 1; n++) { int last = (n + 1) * (n + 2) / 2; if (bin < last) { diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 085633247..59adce455 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -2,9 +2,7 @@ #include "openmc/array.h" #include "openmc/capi.h" -#include "openmc/cell.h" #include "openmc/constants.h" -#include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/mesh.h" @@ -20,29 +18,25 @@ #include "openmc/tallies/derivative.h" #include "openmc/tallies/filter.h" #include "openmc/tallies/filter_cell.h" -#include "openmc/tallies/filter_cellborn.h" #include "openmc/tallies/filter_cellfrom.h" #include "openmc/tallies/filter_collision.h" #include "openmc/tallies/filter_delayedgroup.h" #include "openmc/tallies/filter_energy.h" #include "openmc/tallies/filter_legendre.h" #include "openmc/tallies/filter_mesh.h" -#include "openmc/tallies/filter_meshborn.h" -#include "openmc/tallies/filter_meshmaterial.h" #include "openmc/tallies/filter_meshsurface.h" #include "openmc/tallies/filter_particle.h" #include "openmc/tallies/filter_sph_harm.h" #include "openmc/tallies/filter_surface.h" -#include "openmc/tallies/filter_time.h" #include "openmc/xml_interface.h" -#include "openmc/tensor.h" +#include "xtensor/xadapt.hpp" +#include "xtensor/xbuilder.hpp" // for empty_like +#include "xtensor/xview.hpp" #include -#include // for max, set_union -#include -#include // for size_t -#include // for back_inserter +#include // for max +#include // for size_t #include namespace openmc { @@ -58,17 +52,13 @@ vector> tallies; vector active_tallies; vector active_analog_tallies; vector active_tracklength_tallies; -vector active_timed_tracklength_tallies; vector active_collision_tallies; vector active_meshsurf_tallies; vector active_surface_tallies; -vector active_pulse_height_tallies; -vector pulse_height_cells; -vector time_grid; } // namespace model namespace simulation { -tensor::StaticTensor2D global_tallies; +xt::xtensor_fixed> global_tallies; int32_t n_realizations {0}; } // namespace simulation @@ -102,13 +92,6 @@ Tally::Tally(pugi::xml_node node) if (check_for_node(node, "name")) name_ = get_node_value(node, "name"); - if (check_for_node(node, "multiply_density")) { - multiply_density_ = get_node_value_bool(node, "multiply_density"); - } - - if (check_for_node(node, "higher_moments")) { - higher_moments_ = get_node_value_bool(node, "higher_moments"); - } // ======================================================================= // READ DATA FOR FILTERS @@ -148,7 +131,7 @@ Tally::Tally(pugi::xml_node node) // Check for the presence of certain filter types bool has_energyout = energyout_filter_ >= 0; int particle_filter_index = C_NONE; - for (int64_t j = 0; j < filters_.size(); ++j) { + for (gsl::index j = 0; j < filters_.size(); ++j) { int i_filter = filters_[j]; const auto& f = model::tally_filters[i_filter].get(); @@ -157,25 +140,17 @@ Tally::Tally(pugi::xml_node node) particle_filter_index = i_filter; // Change the tally estimator if a filter demands it - FilterType filt_type = f->type(); - if (filt_type == FilterType::ENERGY_OUT || - filt_type == FilterType::LEGENDRE) { + std::string filt_type = f->type(); + if (filt_type == "energyout" || filt_type == "legendre") { estimator_ = TallyEstimator::ANALOG; - } else if (filt_type == FilterType::SPHERICAL_HARMONICS) { + } else if (filt_type == "sphericalharmonics") { auto sf = dynamic_cast(f); if (sf->cosine() == SphericalHarmonicsCosine::scatter) { estimator_ = TallyEstimator::ANALOG; } - } else if (filt_type == FilterType::SPATIAL_LEGENDRE || - filt_type == FilterType::ZERNIKE || - filt_type == FilterType::ZERNIKE_RADIAL) { + } else if (filt_type == "spatiallegendre" || filt_type == "zernike" || + filt_type == "zernikeradial") { estimator_ = TallyEstimator::COLLISION; - } else if (filt_type == FilterType::PARTICLE_PRODUCTION) { - estimator_ = TallyEstimator::ANALOG; - } else if (filt_type == FilterType::REACTION) { - if (estimator_ == TallyEstimator::TRACKLENGTH) { - estimator_ = TallyEstimator::COLLISION; - } } } @@ -193,75 +168,7 @@ Tally::Tally(pugi::xml_node node) fatal_error(fmt::format("No scores specified on tally {}.", id_)); } - // Set IFP if needed - if (!settings::ifp_on) { - // Determine if this tally has an IFP score - bool has_ifp_score = false; - for (int score : scores_) { - if (score == SCORE_IFP_TIME_NUM || score == SCORE_IFP_BETA_NUM || - score == SCORE_IFP_DENOM) { - has_ifp_score = true; - break; - } - } - - // Check for errors - if (has_ifp_score) { - if (settings::run_mode == RunMode::EIGENVALUE) { - if (settings::ifp_n_generation < 0) { - settings::ifp_n_generation = DEFAULT_IFP_N_GENERATION; - warning(fmt::format( - "{} generations will be used for IFP (default value). It can be " - "changed using the 'ifp_n_generation' settings.", - settings::ifp_n_generation)); - } - if (settings::ifp_n_generation > settings::n_inactive) { - fatal_error("'ifp_n_generation' must be lower than or equal to the " - "number of inactive cycles."); - } - settings::ifp_on = true; - } else if (settings::run_mode == RunMode::FIXED_SOURCE) { - fatal_error( - "Iterated Fission Probability can only be used in an eigenvalue " - "calculation."); - } - } - } - - // Set IFP parameters if needed - if (settings::ifp_on) { - for (int score : scores_) { - switch (score) { - case SCORE_IFP_TIME_NUM: - if (settings::ifp_parameter == IFPParameter::None) { - settings::ifp_parameter = IFPParameter::GenerationTime; - } else if (settings::ifp_parameter == IFPParameter::BetaEffective) { - settings::ifp_parameter = IFPParameter::Both; - } - break; - case SCORE_IFP_BETA_NUM: - case SCORE_IFP_DENOM: - if (settings::ifp_parameter == IFPParameter::None) { - settings::ifp_parameter = IFPParameter::BetaEffective; - } else if (settings::ifp_parameter == IFPParameter::GenerationTime) { - settings::ifp_parameter = IFPParameter::Both; - } - break; - } - } - } - // Check if tally is compatible with particle type - if (!settings::photon_transport) { - for (int score : scores_) { - switch (score) { - case SCORE_PULSE_HEIGHT: - fatal_error("For pulse-height tallies, photon transport needs to be " - "activated."); - break; - } - } - } if (settings::photon_transport) { if (particle_filter_index == C_NONE) { for (int score : scores_) { @@ -282,9 +189,9 @@ Tally::Tally(pugi::xml_node node) case SCORE_DELAYED_NU_FISSION: case SCORE_PROMPT_NU_FISSION: case SCORE_DECAY_RATE: - warning("You are tallying the '" + reaction_name(score) + - "' score and haven't used a particle filter. This score will " - "include contributions from all particles."); + warning("Particle filter is not used with photon transport" + " on and " + + reaction_name(score) + " score."); break; } } @@ -294,12 +201,12 @@ Tally::Tally(pugi::xml_node node) const auto& f = model::tally_filters[particle_filter_index].get(); auto pf = dynamic_cast(f); for (auto p : pf->particles()) { - if (!p.is_neutron()) { + if (p != ParticleType::neutron) { warning(fmt::format( "Particle filter other than NEUTRON used with " "photon transport turned off. All tallies for particle type {}" " will have no scores", - p.str())); + static_cast(p))); } } } @@ -331,8 +238,7 @@ Tally::Tally(pugi::xml_node node) if (has_energyout && i_nuc == -1) { fatal_error(fmt::format( "Error on tally {}: Cannot use a " - "'nuclide_density' or 'temperature' derivative on a tally with " - "an " + "'nuclide_density' or 'temperature' derivative on a tally with an " "outgoing energy filter and 'total' nuclide rate. Instead, tally " "each nuclide in the material individually.", id_)); @@ -390,7 +296,7 @@ Tally::Tally(pugi::xml_node node) } } -#ifdef OPENMC_LIBMESH_ENABLED +#ifdef LIBMESH // ensure a tracklength tally isn't used with a libMesh filter for (auto i : this->filters_) { auto df = dynamic_cast(model::tally_filters[i].get()); @@ -418,7 +324,7 @@ Tally* Tally::create(int32_t id) void Tally::set_id(int32_t id) { - assert(id >= 0 || id == C_NONE); + Expects(id >= 0 || id == C_NONE); // Clear entry in tally map if an ID was already assigned before if (id_ != C_NONE) { @@ -446,35 +352,7 @@ void Tally::set_id(int32_t id) model::tally_map[id] = index_; } -std::vector Tally::filter_types() const -{ - std::vector filter_types; - for (auto idx : this->filters()) - filter_types.push_back(model::tally_filters[idx]->type()); - return filter_types; -} - -std::unordered_map Tally::filter_indices() const -{ - std::unordered_map filter_indices; - for (int i = 0; i < this->filters().size(); i++) { - const auto& f = model::tally_filters[this->filters(i)]; - - filter_indices[f->type()] = i; - } - return filter_indices; -} - -bool Tally::has_filter(FilterType filter_type) const -{ - for (auto idx : this->filters()) { - if (model::tally_filters[idx]->type() == filter_type) - return true; - } - return false; -} - -void Tally::set_filters(span filters) +void Tally::set_filters(gsl::span filters) { // Clear old data. filters_.clear(); @@ -484,35 +362,31 @@ void Tally::set_filters(span filters) auto n = filters.size(); filters_.reserve(n); - for (auto* filter : filters) { - add_filter(filter); - } -} + for (int i = 0; i < n; ++i) { + // Add index to vector of filters + auto& f {filters[i]}; + filters_.push_back(model::filter_map.at(f->id())); -void Tally::add_filter(Filter* filter) -{ - int32_t filter_idx = model::filter_map.at(filter->id()); - // if this filter is already present, do nothing and return - if (std::find(filters_.begin(), filters_.end(), filter_idx) != filters_.end()) - return; - - // Keep track of indices for special filters - if (filter->type() == FilterType::ENERGY_OUT) { - energyout_filter_ = filters_.size(); - } else if (filter->type() == FilterType::DELAYED_GROUP) { - delayedgroup_filter_ = filters_.size(); + // Keep track of indices for special filters. + if (dynamic_cast(f)) { + energyout_filter_ = i; + } else if (dynamic_cast(f)) { + delayedgroup_filter_ = i; + } } - filters_.push_back(filter_idx); + + // Set the strides. + set_strides(); } void Tally::set_strides() { - // Set the strides. Filters are traversed in reverse so that the last - // filter has the shortest stride in memory and the first filter has the - // longest stride. + // Set the strides. Filters are traversed in reverse so that the last filter + // has the shortest stride in memory and the first filter has the longest + // stride. auto n = filters_.size(); strides_.resize(n, 0); - int64_t stride = 1; + int stride = 1; for (int i = n - 1; i >= 0; --i) { strides_[i] = stride; stride *= model::tally_filters[filters_[i]]->n_bins(); @@ -540,52 +414,33 @@ void Tally::set_scores(const vector& scores) bool legendre_present = false; bool cell_present = false; bool cellfrom_present = false; - bool material_present = false; - bool materialfrom_present = false; bool surface_present = false; bool meshsurface_present = false; - bool non_cell_energy_present = false; for (auto i_filt : filters_) { const auto* filt {model::tally_filters[i_filt].get()}; - // Checking for only cell and energy filters for pulse-height tally - if (!(filt->type() == FilterType::CELL || - filt->type() == FilterType::ENERGY)) { - non_cell_energy_present = true; - } - if (filt->type() == FilterType::LEGENDRE) { + if (dynamic_cast(filt)) { legendre_present = true; - } else if (filt->type() == FilterType::CELLFROM) { + } else if (dynamic_cast(filt)) { cellfrom_present = true; - } else if (filt->type() == FilterType::CELL) { + } else if (dynamic_cast(filt)) { cell_present = true; - } else if (filt->type() == FilterType::MATERIALFROM) { - materialfrom_present = true; - } else if (filt->type() == FilterType::MATERIAL) { - material_present = true; - } else if (filt->type() == FilterType::SURFACE) { + } else if (dynamic_cast(filt)) { surface_present = true; - } else if (filt->type() == FilterType::MESH_SURFACE) { + } else if (dynamic_cast(filt)) { meshsurface_present = true; } } - bool surface_types_present = - (surface_present || cellfrom_present || materialfrom_present); - bool non_meshsurface_types_present = - (surface_present || cell_present || cellfrom_present || material_present || - materialfrom_present); // Iterate over the given scores. for (auto score_str : scores) { - // Make sure a delayed group filter wasn't used with an incompatible - // score. + // Make sure a delayed group filter wasn't used with an incompatible score. if (delayedgroup_filter_ != C_NONE) { - if (score_str != "delayed-nu-fission" && score_str != "decay-rate" && - score_str != "ifp-beta-numerator") + if (score_str != "delayed-nu-fission" && score_str != "decay-rate") fatal_error("Cannot tally " + score_str + "with a delayedgroup filter"); } // Determine integer code for score - int score = reaction_tally_mt(score_str); + int score = reaction_type(score_str); switch (score) { case SCORE_FLUX: @@ -594,12 +449,6 @@ void Tally::set_scores(const vector& scores) fatal_error("Cannot tally flux for an individual nuclide."); if (energyout_present) fatal_error("Cannot tally flux with an outgoing energy filter."); - if (surface_types_present) { - if (meshsurface_present) - fatal_error("OpenMC does not support mesh surface fluxes yet"); - type_ = TallyType::SURFACE; - estimator_ = TallyEstimator::ANALOG; - } break; case SCORE_TOTAL: @@ -632,61 +481,22 @@ void Tally::set_scores(const vector& scores) case SCORE_CURRENT: // Check which type of current is desired: mesh or surface currents. - if (meshsurface_present) { - if (non_meshsurface_types_present) + if (surface_present || cell_present || cellfrom_present) { + if (meshsurface_present) fatal_error("Cannot tally mesh surface currents in the same tally as " "normal surface currents"); - type_ = TallyType::MESH_SURFACE; - } else { type_ = TallyType::SURFACE; estimator_ = TallyEstimator::ANALOG; + } else if (meshsurface_present) { + type_ = TallyType::MESH_SURFACE; + } else { + fatal_error("Cannot tally currents without surface type filters"); } break; case HEATING: - if (settings::photon_transport) { - // Photon heating requires a collision estimator (analog energy - // balance). However, if the tally only scores neutrons, we can keep the - // tracklength estimator since neutron heating uses kerma coefficients - // that support tracklength scoring. - bool neutron_only = false; - for (auto i_filt : filters_) { - auto pf = - dynamic_cast(model::tally_filters[i_filt].get()); - if (pf && pf->particles().size() == 1 && - pf->particles()[0].is_neutron()) { - neutron_only = true; - break; - } - } - if (!neutron_only) - estimator_ = TallyEstimator::COLLISION; - } - break; - - case SCORE_PULSE_HEIGHT: { - if (non_cell_energy_present) { - fatal_error("Pulse-height tallies are not compatible with filters " - "other than CellFilter and EnergyFilter"); - } - type_ = TallyType::PULSE_HEIGHT; - // Collect all unique cell indices covered by this tally. - // If no CellFilter is present, all cells in the geometry are scored. - const auto* cell_filter_ptr = get_filter(); - int n = cell_filter_ptr ? cell_filter_ptr->n_bins() - : static_cast(model::cells.size()); - for (int i = 0; i < n; ++i) { - int32_t cell_index = cell_filter_ptr ? cell_filter_ptr->cells()[i] : i; - if (!contains(model::pulse_height_cells, cell_index)) - model::pulse_height_cells.push_back(cell_index); - } - break; - } - - case SCORE_IFP_TIME_NUM: - case SCORE_IFP_BETA_NUM: - case SCORE_IFP_DENOM: - estimator_ = TallyEstimator::COLLISION; + if (settings::photon_transport) + estimator_ = TallyEstimator::COLLISION; break; } @@ -712,20 +522,15 @@ void Tally::set_scores(const vector& scores) "in multi-group mode"); } - // Make sure mesh surface tallies contain only current score. - if (meshsurface_present) { - if ((scores_[0] != SCORE_CURRENT) || (scores_.size() > 1)) - fatal_error("Cannot tally score other than 'current' when using a " - "mesh-surface filter."); - } - - // Make sure surface tallies contain only surface type scores score. - if (type_ == TallyType::SURFACE) { - for (auto sc : scores_) - if ((sc != SCORE_CURRENT) && (sc != SCORE_FLUX)) - fatal_error("Cannot tally scores other than 'current' or 'flux' " - "when using surface filters."); + // Make sure current scores are not mixed in with volumetric scores. + if (type_ == TallyType::SURFACE || type_ == TallyType::MESH_SURFACE) { + if (scores_.size() != 1) + fatal_error("Cannot tally other scores in the same tally as surface " + "currents."); } + if ((surface_present || meshsurface_present) && scores_[0] != SCORE_CURRENT) + fatal_error("Cannot tally score other than 'current' when using a surface " + "or mesh-surface filter."); } void Tally::set_nuclides(pugi::xml_node node) @@ -753,12 +558,11 @@ void Tally::set_nuclides(const vector& nuclides) nuclides_.push_back(-1); } else { auto search = data::nuclide_map.find(nuc); - if (search == data::nuclide_map.end()) { - int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); - if (err < 0) - throw std::runtime_error {openmc_err_msg}; - } - nuclides_.push_back(data::nuclide_map.at(nuc)); + if (search == data::nuclide_map.end()) + fatal_error(fmt::format("Could not find the nuclide {} specified in " + "tally {} in any material", + nuc, id_)); + nuclides_.push_back(search->second); } } } @@ -797,12 +601,6 @@ void Tally::init_triggers(pugi::xml_node node) "Must specify trigger threshold for tally {} in tally XML file", id_)); } - // Read whether to allow zero-tally bins to be ignored. - bool ignore_zeros = false; - if (check_for_node(trigger_node, "ignore_zeros")) { - ignore_zeros = get_node_value_bool(trigger_node, "ignore_zeros"); - } - // Read the trigger scores. vector trigger_scores; if (check_for_node(trigger_node, "scores")) { @@ -816,12 +614,12 @@ void Tally::init_triggers(pugi::xml_node node) if (score_str == "all") { triggers_.reserve(triggers_.size() + this->scores_.size()); for (auto i_score = 0; i_score < this->scores_.size(); ++i_score) { - triggers_.push_back({metric, threshold, ignore_zeros, i_score}); + triggers_.push_back({metric, threshold, i_score}); } } else { int i_score = 0; for (; i_score < this->scores_.size(); ++i_score) { - if (this->scores_[i_score] == reaction_tally_mt(score_str)) + if (reaction_name(this->scores_[i_score]) == score_str) break; } if (i_score == this->scores_.size()) { @@ -830,7 +628,7 @@ void Tally::init_triggers(pugi::xml_node node) "{} but it was listed in a trigger on that tally", score_str, id_)); } - triggers_.push_back({metric, threshold, ignore_zeros, i_score}); + triggers_.push_back({metric, threshold, i_score}); } } } @@ -839,20 +637,14 @@ void Tally::init_triggers(pugi::xml_node node) void Tally::init_results() { int n_scores = scores_.size() * nuclides_.size(); - if (higher_moments_) { - results_ = tensor::Tensor({static_cast(n_filter_bins_), - static_cast(n_scores), size_t {5}}); - } else { - results_ = tensor::Tensor({static_cast(n_filter_bins_), - static_cast(n_scores), size_t {3}}); - } + results_ = xt::empty({n_filter_bins_, n_scores, 3}); } void Tally::reset() { n_realizations_ = 0; if (results_.size() != 0) { - results_.fill(0.0); + xt::view(results_, xt::all()) = 0.0; } } @@ -865,81 +657,30 @@ void Tally::accumulate() // Calculate total source strength for normalization double total_source = 0.0; if (settings::run_mode == RunMode::FIXED_SOURCE) { - total_source = model::external_sources_probability.integral(); + for (const auto& s : model::external_sources) { + total_source += s->strength(); + } } else { total_source = 1.0; } - // Determine number of particles contributing to tally - double contributing_particles = settings::reduce_tallies - ? settings::n_particles - : simulation::work_per_rank; - // Account for number of source particles in normalization double norm = - total_source / (contributing_particles * settings::gen_per_batch); + total_source / (settings::n_particles * settings::gen_per_batch); - if (settings::solver_type == SolverType::RANDOM_RAY) { - norm = 1.0; - } - - // Accumulate each result - if (higher_moments_) { +// Accumulate each result #pragma omp parallel for - // filter bins (specific cell, energy bins) - for (int64_t i = 0; i < results_.shape(0); ++i) { - // score bins (flux, total reaction rate, fission reaction rate, etc.) - for (int j = 0; j < results_.shape(1); ++j) { - double val = results_(i, j, TallyResult::VALUE) * norm; - double val2 = val * val; - results_(i, j, TallyResult::VALUE) = 0.0; - results_(i, j, TallyResult::SUM) += val; - results_(i, j, TallyResult::SUM_SQ) += val2; - results_(i, j, TallyResult::SUM_THIRD) += val2 * val; - results_(i, j, TallyResult::SUM_FOURTH) += val2 * val2; - } - } - } else { -#pragma omp parallel for - // filter bins (specific cell, energy bins) - for (int64_t i = 0; i < results_.shape(0); ++i) { - // score bins (flux, total reaction rate, fission reaction rate, etc.) - for (int j = 0; j < results_.shape(1); ++j) { - double val = results_(i, j, TallyResult::VALUE) * norm; - results_(i, j, TallyResult::VALUE) = 0.0; - results_(i, j, TallyResult::SUM) += val; - results_(i, j, TallyResult::SUM_SQ) += val * val; - } + for (int i = 0; i < results_.shape()[0]; ++i) { + for (int j = 0; j < results_.shape()[1]; ++j) { + double val = results_(i, j, TallyResult::VALUE) * norm; + results_(i, j, TallyResult::VALUE) = 0.0; + results_(i, j, TallyResult::SUM) += val; + results_(i, j, TallyResult::SUM_SQ) += val * val; } } } } -int Tally::score_index(const std::string& score) const -{ - for (int i = 0; i < scores_.size(); i++) { - if (this->score_name(i) == score) - return i; - } - return -1; -} - -tensor::Tensor Tally::get_reshaped_data() const -{ - vector shape; - for (auto f : filters()) { - shape.push_back(model::tally_filters[f]->n_bins()); - } - - // add number of scores and nuclides to tally - shape.push_back(results_.shape(1)); - shape.push_back(results_.shape(2)); - - tensor::Tensor reshaped_results = results_; - reshaped_results.reshape(shape); - return reshaped_results; -} - std::string Tally::score_name(int score_idx) const { if (score_idx < 0 || score_idx >= scores_.size()) { @@ -948,14 +689,6 @@ std::string Tally::score_name(int score_idx) const return reaction_name(scores_[score_idx]); } -std::vector Tally::scores() const -{ - std::vector score_names; - for (int score : scores_) - score_names.push_back(reaction_name(score)); - return score_names; -} - std::string Tally::nuclide_name(int nuclide_idx) const { if (nuclide_idx < 0 || nuclide_idx >= nuclides_.size()) { @@ -987,11 +720,6 @@ void read_tallies_xml() doc.load_file(filename.c_str()); pugi::xml_node root = doc.document_element(); - read_tallies_xml(root); -} - -void read_tallies_xml(pugi::xml_node root) -{ // Check for setting if (check_for_node(root, "assume_separate")) { settings::assume_separate = get_node_value_bool(root, "assume_separate"); @@ -1040,14 +768,13 @@ void reduce_tally_results() // Skip any tallies that are not active auto& tally {model::tallies[i_tally]}; - // Extract 2D view of the VALUE column from the 3D results tensor, - // then copy into a contiguous array for MPI reduction - const int val_idx = static_cast(TallyResult::VALUE); - tensor::View val_view = - tally->results_.slice(tensor::all, tensor::all, val_idx); - tensor::Tensor values(val_view); + // Get view of accumulated tally values + auto values_view = xt::view(tally->results_, xt::all(), xt::all(), + static_cast(TallyResult::VALUE)); - tensor::Tensor values_reduced(values.shape()); + // Make copy of tally values in contiguous array + xt::xtensor values = values_view; + xt::xtensor values_reduced = xt::empty_like(values); // Reduce contiguous set of tally results MPI_Reduce(values.data(), values_reduced.data(), values.size(), @@ -1055,23 +782,24 @@ void reduce_tally_results() // Transfer values on master and reset on other ranks if (mpi::master) { - val_view = values_reduced; + values_view = values_reduced; } else { - val_view = 0.0; + values_view = 0.0; } } } - // Note that global tallies are *always* reduced even when no_reduce option - // is on. + // Note that global tallies are *always* reduced even when no_reduce option is + // on. - // Get reference to global tallies + // Get view of global tally values auto& gt = simulation::global_tallies; - const int val_col = static_cast(TallyResult::VALUE); + auto gt_values_view = + xt::view(gt, xt::all(), static_cast(TallyResult::VALUE)); - // Copy VALUE column into contiguous array for MPI reduction - tensor::Tensor gt_values(gt.slice(tensor::all, val_col)); - tensor::Tensor gt_values_reduced({size_t {N_GLOBAL_TALLIES}}); + // Make copy of values in contiguous array + xt::xtensor gt_values = gt_values_view; + xt::xtensor gt_values_reduced = xt::empty_like(gt_values); // Reduce contiguous data MPI_Reduce(gt_values.data(), gt_values_reduced.data(), N_GLOBAL_TALLIES, @@ -1079,9 +807,9 @@ void reduce_tally_results() // Transfer values on master and reset on other ranks if (mpi::master) { - gt.slice(tensor::all, val_col) = gt_values_reduced; + gt_values_view = gt_values_reduced; } else { - gt.slice(tensor::all, val_col) = 0.0; + gt_values_view = 0.0; } // We also need to determine the total starting weight of particles from the @@ -1098,9 +826,8 @@ void accumulate_tallies() { #ifdef OPENMC_MPI // Combine tally results onto master process - if (mpi::n_procs > 1 && settings::solver_type == SolverType::MONTE_CARLO) { + if (mpi::n_procs > 1) reduce_tally_results(); - } #endif // Increase number of realizations (only used for global tallies) @@ -1141,59 +868,20 @@ void accumulate_tallies() } } -double distance_to_time_boundary(double time, double speed) -{ - if (model::time_grid.empty()) { - return INFTY; - } else if (time >= model::time_grid.back()) { - return INFTY; - } else { - double next_time = - *std::upper_bound(model::time_grid.begin(), model::time_grid.end(), time); - return (next_time - time) * speed; - } -} - -//! Add new points to the global time grid -// -//! \param grid Vector of new time points to add -void add_to_time_grid(vector grid) -{ - if (grid.empty()) - return; - - // Create new vector with enough space to hold old and new grid points - vector merged; - merged.reserve(model::time_grid.size() + grid.size()); - - // Merge and remove duplicates - std::set_union(model::time_grid.begin(), model::time_grid.end(), grid.begin(), - grid.end(), std::back_inserter(merged)); - - // Swap in the new grid - model::time_grid.swap(merged); -} - void setup_active_tallies() { model::active_tallies.clear(); model::active_analog_tallies.clear(); model::active_tracklength_tallies.clear(); - model::active_timed_tracklength_tallies.clear(); model::active_collision_tallies.clear(); model::active_meshsurf_tallies.clear(); model::active_surface_tallies.clear(); - model::active_pulse_height_tallies.clear(); - model::time_grid.clear(); for (auto i = 0; i < model::tallies.size(); ++i) { const auto& tally {*model::tallies[i]}; if (tally.active_) { model::active_tallies.push_back(i); - bool mesh_present = (tally.get_filter() || - tally.get_filter()); - auto time_filter = tally.get_filter(); switch (tally.type_) { case TallyType::VOLUME: @@ -1202,12 +890,7 @@ void setup_active_tallies() model::active_analog_tallies.push_back(i); break; case TallyEstimator::TRACKLENGTH: - if (time_filter && mesh_present) { - model::active_timed_tracklength_tallies.push_back(i); - add_to_time_grid(time_filter->bins()); - } else { - model::active_tracklength_tallies.push_back(i); - } + model::active_tracklength_tallies.push_back(i); break; case TallyEstimator::COLLISION: model::active_collision_tallies.push_back(i); @@ -1220,11 +903,6 @@ void setup_active_tallies() case TallyType::SURFACE: model::active_surface_tallies.push_back(i); - break; - - case TallyType::PULSE_HEIGHT: - model::active_pulse_height_tallies.push_back(i); - break; } } } @@ -1243,12 +921,9 @@ void free_memory_tally() model::active_tallies.clear(); model::active_analog_tallies.clear(); model::active_tracklength_tallies.clear(); - model::active_timed_tracklength_tallies.clear(); model::active_collision_tallies.clear(); model::active_meshsurf_tallies.clear(); model::active_surface_tallies.clear(); - model::active_pulse_height_tallies.clear(); - model::time_grid.clear(); model::tally_map.clear(); } @@ -1370,8 +1045,6 @@ extern "C" int openmc_tally_set_type(int32_t index, const char* type) model::tallies[index]->type_ = TallyType::MESH_SURFACE; } else if (strcmp(type, "surface") == 0) { model::tallies[index]->type_ = TallyType::SURFACE; - } else if (strcmp(type, "pulse-height") == 0) { - model::tallies[index]->type_ = TallyType::PULSE_HEIGHT; } else { set_errmsg(fmt::format("Unknown tally type: {}", type)); return OPENMC_E_INVALID_ARGUMENT; @@ -1424,28 +1097,6 @@ extern "C" int openmc_tally_set_writable(int32_t index, bool writable) return 0; } -extern "C" int openmc_tally_get_multiply_density(int32_t index, bool* value) -{ - if (index < 0 || index >= model::tallies.size()) { - set_errmsg("Index in tallies array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - *value = model::tallies[index]->multiply_density(); - - return 0; -} - -extern "C" int openmc_tally_set_multiply_density(int32_t index, bool value) -{ - if (index < 0 || index >= model::tallies.size()) { - set_errmsg("Index in tallies array is out of bounds."); - return OPENMC_E_OUT_OF_BOUNDS; - } - model::tallies[index]->set_multiply_density(value); - - return 0; -} - extern "C" int openmc_tally_get_scores(int32_t index, int** scores, int* n) { if (index < 0 || index >= model::tallies.size()) { @@ -1508,13 +1159,10 @@ extern "C" int openmc_tally_set_nuclides( } else { auto search = data::nuclide_map.find(word); if (search == data::nuclide_map.end()) { - int err = openmc_load_nuclide(word.c_str(), nullptr, 0); - if (err < 0) { - set_errmsg(openmc_err_msg); - return OPENMC_E_DATA; - } + set_errmsg("Nuclide \"" + word + "\" has not been loaded yet"); + return OPENMC_E_DATA; } - nucs.push_back(data::nuclide_map.at(word)); + nucs.push_back(search->second); } } @@ -1549,7 +1197,7 @@ extern "C" int openmc_tally_set_filters( try { // Convert indices to filter pointers vector filters; - for (int64_t i = 0; i < n; ++i) { + for (gsl::index i = 0; i < n; ++i) { int32_t i_filt = indices[i]; filters.push_back(model::tally_filters.at(i_filt).get()); } @@ -1587,8 +1235,8 @@ extern "C" int openmc_tally_get_n_realizations(int32_t index, int32_t* n) return 0; } -//! \brief Returns a pointer to a tally results array along with its shape. -//! This allows a user to obtain in-memory tally results from Python directly. +//! \brief Returns a pointer to a tally results array along with its shape. This +//! allows a user to obtain in-memory tally results from Python directly. extern "C" int openmc_tally_results( int32_t index, double** results, size_t* shape) { @@ -1628,11 +1276,11 @@ extern "C" size_t tallies_size() extern "C" int openmc_remove_tally(int32_t index) { // check that id is in the map - if (index < 0 || index >= model::tallies.size()) { - set_errmsg("Index in tallies array is out of bounds."); + if (index < 0 || index > model::tallies.size()) { return OPENMC_E_OUT_OF_BOUNDS; } - + // grab tally so it's ID can be obtained to remove the (ID,index) pair from tally_map + auto& tally = model::tallies[index]; // delete the tally via iterator pointing to correct position // this calls the Tally destructor, removing the tally from the map as well model::tallies.erase(model::tallies.begin() + index); diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 241cbf008..68eb344af 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -4,7 +4,6 @@ #include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/error.h" -#include "openmc/ifp.h" #include "openmc/material.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" @@ -14,14 +13,11 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/string_utils.h" -#include "openmc/surface.h" #include "openmc/tallies/derivative.h" #include "openmc/tallies/filter.h" -#include "openmc/tallies/filter_cell.h" #include "openmc/tallies/filter_delayedgroup.h" #include "openmc/tallies/filter_energy.h" -#include #include namespace openmc { @@ -158,7 +154,7 @@ void score_fission_delayed_dg(int i_tally, int d_bin, double score, dg_match.bins_[i_bin] = d_bin; // Determine the filter scoring index - int64_t filter_index = 0; + auto filter_index = 0; double filter_weight = 1.; for (auto i = 0; i < tally.filters().size(); ++i) { auto i_filt = tally.filters(i); @@ -235,7 +231,7 @@ double score_fission_q(const Particle& p, int score_bin, const Tally& tally, double score {0.0}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); const Nuclide& nuc {*data::nuclides[j_nuclide]}; score += get_nuc_fission_q(nuc, p, score_bin) * atom_density * p.neutron_xs(j_nuclide).fission; @@ -327,56 +323,6 @@ double score_neutron_heating(const Particle& p, const Tally& tally, double flux, return score; } -//! Helper function to obtain reaction Q value for photons and charged particles -double get_reaction_q_value(const Particle& p) -{ - if (p.type().is_photon() && p.event_mt() == PAIR_PROD) { - // pair production - return -2 * MASS_ELECTRON_EV; - } else if (p.type() == ParticleType::positron()) { - // positron annihilation - return 2 * MASS_ELECTRON_EV; - } else { - return 0.0; - } -} - -//! Helper function to obtain particle heating [eV] - -double score_particle_heating(const Particle& p, const Tally& tally, - double flux, int rxn_bin, int i_nuclide, double atom_density) -{ - if (p.type().is_neutron()) - return score_neutron_heating( - p, tally, flux, rxn_bin, i_nuclide, atom_density); - if (i_nuclide == -1 || i_nuclide == p.event_nuclide() || - p.event_nuclide() == -1) { - // For pair production and positron annihilation, we need to account for the - // reaction Q value - double Q = get_reaction_q_value(p); - - // Get the pre-collision energy of the particle. - auto E = p.E_last(); - - // The energy deposited is the sum of the incident energy and the reaction - // Q-value less the energy of any outgoing particles - double score = E + Q - p.E() - p.bank_second_E(); - - score *= p.wgt_last(); - - // if no event_nuclide (charged particle) scale energy deposition by - // fractional charge density - if (i_nuclide != -1 && p.event_nuclide() == -1) { - const auto& mat {model::materials[p.material()]}; - int z = data::nuclides[i_nuclide]->Z_; - auto i = mat->mat_nuclide_index_[i_nuclide]; - score *= (z * mat->atom_density_[i] / mat->charge_density()); - } - return score; - } - return 0.0; -} - //! Helper function for nu-fission tallies with energyout filters. // //! In this case, we may need to score to multiple bins if there were multiple @@ -449,7 +395,7 @@ void score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) (score_bin == SCORE_PROMPT_NU_FISSION && g == 0)) { // Find the filter scoring index for this filter combination - int64_t filter_index = 0; + int filter_index = 0; double filter_weight = 1.0; for (auto j = 0; j < tally.filters().size(); ++j) { auto i_filt = tally.filters(j); @@ -497,7 +443,7 @@ void score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) } else { // Find the filter index and weight for this filter combination - int64_t filter_index = 0; + int filter_index = 0; double filter_weight = 1.; for (auto j = 0; j < tally.filters().size(); ++j) { auto i_filt = tally.filters(j); @@ -578,14 +524,16 @@ double get_nuclide_xs(const Particle& p, int i_nuclide, int score_bin) //! collision estimator. void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, - int64_t filter_index, double filter_weight, int i_nuclide, - double atom_density, double flux) + int filter_index, double filter_weight, int i_nuclide, double atom_density, + double flux) { Tally& tally {*model::tallies[i_tally]}; // Get the pre-collision energy of the particle. auto E = p.E_last(); + using Type = ParticleType; + for (auto i = 0; i < tally.scores_.size(); ++i) { auto score_bin = tally.scores_[i]; auto score_index = start_index + i; @@ -598,9 +546,9 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, case SCORE_TOTAL: if (i_nuclide >= 0) { - if (p.type().is_neutron()) { + if (p.type() == Type::neutron) { score = p.neutron_xs(i_nuclide).total * atom_density * flux; - } else if (p.type().is_photon()) { + } else if (p.type() == Type::photon) { score = p.photon_xs(i_nuclide).total * atom_density * flux; } } else { @@ -609,7 +557,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, break; case SCORE_INVERSE_VELOCITY: - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // Score inverse velocity in units of s/cm. @@ -617,11 +565,11 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, break; case SCORE_SCATTER: - if (!p.type().is_neutron() && !p.type().is_photon()) + if (p.type() != Type::neutron && p.type() != Type::photon) continue; if (i_nuclide >= 0) { - if (p.type().is_neutron()) { + if (p.type() == Type::neutron) { const auto& micro = p.neutron_xs(i_nuclide); score = (micro.total - micro.absorption) * atom_density * flux; } else { @@ -629,7 +577,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, score = (micro.coherent + micro.incoherent) * atom_density * flux; } } else { - if (p.type().is_neutron()) { + if (p.type() == Type::neutron) { score = (p.macro_xs().total - p.macro_xs().absorption) * flux; } else { score = (p.macro_xs().coherent + p.macro_xs().incoherent) * flux; @@ -638,11 +586,11 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, break; case SCORE_ABSORPTION: - if (!p.type().is_neutron() && !p.type().is_photon()) + if (p.type() != Type::neutron && p.type() != Type::photon) continue; if (i_nuclide >= 0) { - if (p.type().is_neutron()) { + if (p.type() == Type::neutron) { score = p.neutron_xs(i_nuclide).absorption * atom_density * flux; } else { const auto& xs = p.photon_xs(i_nuclide); @@ -650,7 +598,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, (xs.total - xs.coherent - xs.incoherent) * atom_density * flux; } } else { - if (p.type().is_neutron()) { + if (p.type() == Type::neutron) { score = p.macro_xs().absorption * flux; } else { score = @@ -696,7 +644,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); score += p.neutron_xs(j_nuclide).fission * data::nuclides[j_nuclide]->nu( E, ReactionProduct::EmissionMode::prompt) * @@ -743,7 +691,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin]; @@ -763,7 +711,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); score += p.neutron_xs(j_nuclide).fission * data::nuclides[j_nuclide]->nu( E, ReactionProduct::EmissionMode::delayed) * @@ -806,7 +754,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, // this loop. for (auto d = 1; d < rxn.products_.size(); ++d) { const auto& product = rxn.products_[d]; - if (!product.particle_.is_neutron()) + if (product.particle_ != Type::neutron) continue; auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); @@ -824,7 +772,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); const auto& nuc {*data::nuclides[j_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; @@ -849,7 +797,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); const auto& nuc {*data::nuclides[j_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; @@ -860,7 +808,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, // this loop. for (auto d = 1; d < rxn.products_.size(); ++d) { const auto& product = rxn.products_[d]; - if (!product.particle_.is_neutron()) + if (product.particle_ != Type::neutron) continue; auto yield = @@ -893,7 +841,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); const auto& nuc {*data::nuclides[j_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; @@ -905,12 +853,13 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, break; case SCORE_EVENTS: - // Simply count the number of scoring events - score = 1.0; - break; +// Simply count the number of scoring events +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0; + continue; case ELASTIC: - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; if (i_nuclide >= 0) { @@ -923,7 +872,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); if (p.neutron_xs(j_nuclide).elastic == CACHE_INVALID) data::nuclides[j_nuclide]->calculate_elastic_xs(p); score += p.neutron_xs(j_nuclide).elastic * atom_density * flux; @@ -940,64 +889,6 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, score_fission_q(p, score_bin, tally, flux, i_nuclide, atom_density); break; - case SCORE_IFP_TIME_NUM: - if (settings::ifp_on) { - if (p.type().is_neutron() && p.fission()) { - if (is_generation_time_or_both()) { - const auto& lifetimes = - simulation::ifp_source_lifetime_bank[p.current_work()]; - if (lifetimes.size() == settings::ifp_n_generation) { - score = lifetimes[0] * p.wgt_last(); - } - } - } - } - break; - - case SCORE_IFP_BETA_NUM: - if (settings::ifp_on) { - if (p.type().is_neutron() && p.fission()) { - if (is_beta_effective_or_both()) { - const auto& delayed_groups = - simulation::ifp_source_delayed_group_bank[p.current_work()]; - if (delayed_groups.size() == settings::ifp_n_generation) { - if (delayed_groups[0] > 0) { - score = p.wgt_last(); - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt { - *dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - score_fission_delayed_dg(i_tally, delayed_groups[0] - 1, - score, score_index, p.filter_matches()); - continue; - } - } - } - } - } - } - break; - - case SCORE_IFP_DENOM: - if (settings::ifp_on) { - if (p.type().is_neutron() && p.fission()) { - int ifp_data_size; - if (is_beta_effective_or_both()) { - ifp_data_size = static_cast( - simulation::ifp_source_delayed_group_bank[p.current_work()] - .size()); - } else { - ifp_data_size = static_cast( - simulation::ifp_source_lifetime_bank[p.current_work()].size()); - } - if (ifp_data_size == settings::ifp_n_generation) { - score = p.wgt_last(); - } - } - } - break; - case N_2N: case N_3N: case N_4N: @@ -1010,12 +901,12 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, if (!simulation::need_depletion_rx) goto default_case; - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; int m; switch (score_bin) { - // clang-format off + // clang-format off case N_GAMMA: m = 0; break; case N_P: m = 1; break; case N_A: m = 2; break; @@ -1032,7 +923,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); score += p.neutron_xs(j_nuclide).reaction[m] * atom_density * flux; } } @@ -1043,29 +934,53 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, case INCOHERENT: case PHOTOELECTRIC: case PAIR_PROD: - if (!p.type().is_photon()) + if (p.type() != Type::photon) continue; if (i_nuclide >= 0) { const auto& micro = p.photon_xs(i_nuclide); - double xs = (score_bin == COHERENT) ? micro.coherent - : (score_bin == INCOHERENT) ? micro.incoherent - : (score_bin == PHOTOELECTRIC) ? micro.photoelectric - : micro.pair_production; + double xs = (score_bin == COHERENT) + ? micro.coherent + : (score_bin == INCOHERENT) ? micro.incoherent + : (score_bin == PHOTOELECTRIC) + ? micro.photoelectric + : micro.pair_production; score = xs * atom_density * flux; } else { - double xs = (score_bin == COHERENT) ? p.macro_xs().coherent - : (score_bin == INCOHERENT) ? p.macro_xs().incoherent - : (score_bin == PHOTOELECTRIC) - ? p.macro_xs().photoelectric - : p.macro_xs().pair_production; + double xs = (score_bin == COHERENT) + ? p.macro_xs().coherent + : (score_bin == INCOHERENT) + ? p.macro_xs().incoherent + : (score_bin == PHOTOELECTRIC) + ? p.macro_xs().photoelectric + : p.macro_xs().pair_production; score = xs * flux; } break; case HEATING: - score = score_particle_heating( - p, tally, flux, HEATING, i_nuclide, atom_density); + if (p.type() == Type::neutron) { + score = score_neutron_heating( + p, tally, flux, HEATING, i_nuclide, atom_density); + } else { + if (i_nuclide == -1 || i_nuclide == p.event_nuclide()) { + // The energy deposited is the difference between the pre-collision + // and post-collision energy... + score = E - p.E(); + + // ...less the energy of any secondary particles since they will be + // transported individually later + const auto& bank = p.secondary_bank(); + for (auto it = bank.end() - p.n_bank_second(); it < bank.end(); + ++it) { + score -= it->E; + } + + score *= p.wgt_last(); + } else { + score = 0.0; + } + } break; default: @@ -1073,7 +988,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, // The default block is really only meant for redundant neutron reactions // (e.g. 444, 901) - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // Any other cross section has to be calculated on-the-fly @@ -1086,7 +1001,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density(i, p.density_mult()); + auto atom_density = material.atom_density_(i); score += get_nuclide_xs(p, j_nuclide, score_bin) * atom_density * flux; } @@ -1112,8 +1027,8 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, //! is not used for analog tallies. void score_general_ce_analog(Particle& p, int i_tally, int start_index, - int64_t filter_index, double filter_weight, int i_nuclide, - double atom_density, double flux) + int filter_index, double filter_weight, int i_nuclide, double atom_density, + double flux) { Tally& tally {*model::tallies[i_tally]}; @@ -1127,6 +1042,8 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, p.neutron_xs(p.event_nuclide()).total : 0.0; + using Type = ParticleType; + for (auto i = 0; i < tally.scores_.size(); ++i) { auto score_bin = tally.scores_[i]; auto score_index = start_index + i; @@ -1137,7 +1054,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, // All events score to a flux bin. We actually use a collision estimator // in place of an analog one since there is no way to count 'events' // exactly for the flux - if (p.type().is_neutron() || p.type().is_photon()) { + if (p.type() == Type::neutron || p.type() == Type::photon) { score = flux * p.wgt_last() / p.macro_xs().total; } else { score = 0.; @@ -1151,7 +1068,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, break; case SCORE_INVERSE_VELOCITY: - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // All events score to an inverse velocity bin. We actually use a @@ -1161,7 +1078,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, break; case SCORE_SCATTER: - if (!p.type().is_neutron() && !p.type().is_photon()) + if (p.type() != Type::neutron && p.type() != Type::photon) continue; // Skip any event where the particle didn't scatter @@ -1173,7 +1090,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, break; case SCORE_NU_SCATTER: - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // Only analog estimators are available. @@ -1198,7 +1115,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, break; case SCORE_ABSORPTION: - if (!p.type().is_neutron() && !p.type().is_photon()) + if (p.type() != Type::neutron && p.type() != Type::photon) continue; if (settings::survival_biasing) { @@ -1427,7 +1344,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, // this loop. for (auto d = 1; d < rxn.products_.size(); ++d) { const auto& product = rxn.products_[d]; - if (!product.particle_.is_neutron()) + if (product.particle_ != Type::neutron) continue; auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); @@ -1513,12 +1430,13 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, break; case SCORE_EVENTS: - // Simply count the number of scoring events - score = 1.0; - break; +// Simply count the number of scoring events +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0; + continue; case ELASTIC: - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // Check if event MT matches @@ -1547,7 +1465,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, if (!simulation::need_depletion_rx) goto default_case; - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // Check if the event MT matches @@ -1560,7 +1478,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, case INCOHERENT: case PHOTOELECTRIC: case PAIR_PROD: - if (!p.type().is_photon()) + if (p.type() != Type::photon) continue; if (score_bin == PHOTOELECTRIC) { @@ -1578,8 +1496,23 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, break; case HEATING: - score = score_particle_heating( - p, tally, flux, HEATING, i_nuclide, atom_density); + if (p.type() == Type::neutron) { + score = score_neutron_heating( + p, tally, flux, HEATING, i_nuclide, atom_density); + } else { + // The energy deposited is the difference between the pre-collision and + // post-collision energy... + score = E - p.E(); + + // ...less the energy of any secondary particles since they will be + // transported individually later + const auto& bank = p.secondary_bank(); + for (auto it = bank.end() - p.n_bank_second(); it < bank.end(); ++it) { + score -= it->E; + } + + score *= p.wgt_last(); + } break; default: @@ -1587,7 +1520,7 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, // The default block is really only meant for redundant neutron reactions // (e.g. 444, 901) - if (!p.type().is_neutron()) + if (p.type() != Type::neutron) continue; // Any other score is assumed to be a MT number. Thus, we just need @@ -1615,8 +1548,8 @@ void score_general_ce_analog(Particle& p, int i_tally, int start_index, //! argument is really just used for filter weights. void score_general_mg(Particle& p, int i_tally, int start_index, - int64_t filter_index, double filter_weight, int i_nuclide, - double atom_density, double flux) + int filter_index, double filter_weight, int i_nuclide, double atom_density, + double flux) { auto& tally {*model::tallies[i_tally]}; @@ -1628,7 +1561,8 @@ void score_general_mg(Particle& p, int i_tally, int start_index, tally.estimator_ == TallyEstimator::COLLISION) { if (settings::survival_biasing) { // Determine weight that was absorbed - wgt_absorb = p.wgt_last() * p.macro_xs().absorption / p.macro_xs().total; + wgt_absorb = p.wgt_last() * p.neutron_xs(p.event_nuclide()).absorption / + p.neutron_xs(p.event_nuclide()).total; // Then we either are alive and had a scatter (and so g changed), // or are dead and g did not change @@ -1664,13 +1598,10 @@ void score_general_mg(Particle& p, int i_tally, int start_index, auto& macro_xs = data::mg.macro_xs_[p.material()]; // Find the temperature and angle indices of interest - int macro_t = p.mg_xs_cache().t; - int macro_a = macro_xs.get_angle_index(p_u); - int nuc_t = 0; - int nuc_a = 0; + macro_xs.set_angle_index(p_u); if (i_nuclide >= 0) { - nuc_t = nuc_xs.get_temperature_index(p.sqrtkT()); - nuc_a = nuc_xs.get_angle_index(p_u); + nuc_xs.set_temperature_index(p.sqrtkT()); + nuc_xs.set_angle_index(p_u); } for (auto i = 0; i < tally.scores_.size(); ++i) { @@ -1698,14 +1629,12 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // use the weight of the particle entering the collision as the score score = flux * p.wgt_last(); if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::TOTAL, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::TOTAL, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::TOTAL, p_g) / + macro_xs.get_xs(MgxsType::TOTAL, p_g); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::TOTAL, p_g, nuc_t, nuc_a); + score = atom_density * flux * nuc_xs.get_xs(MgxsType::TOTAL, p_g); } else { score = p.macro_xs().total * flux; } @@ -1720,21 +1649,17 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // to count 'events' exactly for the inverse velocity score = flux * p.wgt_last(); if (i_nuclide >= 0) { - score *= - nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::TOTAL, p_g, macro_t, macro_a); + score *= nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g) / + macro_xs.get_xs(MgxsType::TOTAL, p_g); } else { - score *= - macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g, macro_t, macro_a) / - macro_xs.get_xs(MgxsType::TOTAL, p_g, macro_t, macro_a); + score *= macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g) / + macro_xs.get_xs(MgxsType::TOTAL, p_g); } } else { if (i_nuclide >= 0) { - score = - flux * nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g, nuc_t, nuc_a); + score = flux * nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g); } else { - score = flux * macro_xs.get_xs( - MgxsType::INVERSE_VELOCITY, p_g, macro_t, macro_a); + score = flux * macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g); } } break; @@ -1750,18 +1675,18 @@ void score_general_mg(Particle& p, int i_tally, int start_index, if (i_nuclide >= 0) { score *= atom_density * nuc_xs.get_xs(MgxsType::SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr, nuc_t, nuc_a) / + &p.mu(), nullptr) / macro_xs.get_xs(MgxsType::SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr, macro_t, macro_a); + &p.mu(), nullptr); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::SCATTER, p_g, nullptr, &p.mu(), - nullptr, nuc_t, nuc_a); + score = + atom_density * flux * + nuc_xs.get_xs(MgxsType::SCATTER, p_g, nullptr, &p.mu(), nullptr); } else { - score = flux * macro_xs.get_xs(MgxsType::SCATTER, p_g, nullptr, - &p.mu(), nullptr, macro_t, macro_a); + score = flux * macro_xs.get_xs( + MgxsType::SCATTER, p_g, nullptr, &p.mu(), nullptr); } } break; @@ -1781,17 +1706,16 @@ void score_general_mg(Particle& p, int i_tally, int start_index, if (i_nuclide >= 0) { score *= atom_density * nuc_xs.get_xs(MgxsType::NU_SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr, nuc_t, nuc_a) / + &p.mu(), nullptr) / macro_xs.get_xs(MgxsType::NU_SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr, macro_t, macro_a); + &p.mu(), nullptr); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::NU_SCATTER, p_g, nuc_t, nuc_a); - } else { score = - flux * macro_xs.get_xs(MgxsType::NU_SCATTER, p_g, macro_t, macro_a); + atom_density * flux * nuc_xs.get_xs(MgxsType::NU_SCATTER, p_g); + } else { + score = flux * macro_xs.get_xs(MgxsType::NU_SCATTER, p_g); } } break; @@ -1811,14 +1735,13 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = p.wgt_last() * flux; } if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::ABSORPTION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::ABSORPTION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::ABSORPTION, p_g, nuc_t, nuc_a); + score = + atom_density * flux * nuc_xs.get_xs(MgxsType::ABSORPTION, p_g); } else { score = p.macro_xs().absorption * flux; } @@ -1842,20 +1765,17 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = p.wgt_last() * flux; } if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } else { - score *= macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= macro_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a); + score = atom_density * flux * nuc_xs.get_xs(MgxsType::FISSION, p_g); } else { - score = - flux * macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); + score = flux * macro_xs.get_xs(MgxsType::FISSION, p_g); } } break; @@ -1876,14 +1796,11 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // nu-fission score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= - atom_density * - nuc_xs.get_xs(MgxsType::NU_FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::NU_FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } else { - score *= - macro_xs.get_xs(MgxsType::NU_FISSION, p_g, macro_t, macro_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= macro_xs.get_xs(MgxsType::NU_FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } } else { // Skip any non-fission events @@ -1896,18 +1813,16 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // score. score = simulation::keff * p.wgt_bank() * flux; if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::FISSION, p_g); } } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::NU_FISSION, p_g, nuc_t, nuc_a); - } else { score = - flux * macro_xs.get_xs(MgxsType::NU_FISSION, p_g, macro_t, macro_a); + atom_density * flux * nuc_xs.get_xs(MgxsType::NU_FISSION, p_g); + } else { + score = flux * macro_xs.get_xs(MgxsType::NU_FISSION, p_g); } } break; @@ -1928,15 +1843,12 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // prompt-nu-fission score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= - atom_density * - nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= atom_density * + nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } else { - score *= - macro_xs.get_xs( - MgxsType::PROMPT_NU_FISSION, p_g, macro_t, macro_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= macro_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } } else { // Skip any non-fission events @@ -1952,18 +1864,16 @@ void score_general_mg(Particle& p, int i_tally, int start_index, auto prompt_frac = 1. - n_delayed / static_cast(p.n_bank()); score = simulation::keff * p.wgt_bank() * prompt_frac * flux; if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::FISSION, p_g); } } } else { if (i_nuclide >= 0) { score = atom_density * flux * - nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g, nuc_t, nuc_a); + nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g); } else { - score = flux * macro_xs.get_xs( - MgxsType::PROMPT_NU_FISSION, p_g, macro_t, macro_a); + score = flux * macro_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g); } } break; @@ -1982,8 +1892,7 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - double abs_xs = - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + double abs_xs = macro_xs.get_xs(MgxsType::ABSORPTION, p_g); if (abs_xs > 0.) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; @@ -1996,11 +1905,11 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = wgt_absorb * flux; if (i_nuclide >= 0) { score *= nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, nuc_t, nuc_a) / + nullptr, nullptr, &d) / abs_xs; } else { score *= macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, macro_t, macro_a) / + nullptr, nullptr, &d) / abs_xs; } score_fission_delayed_dg( @@ -2013,13 +1922,11 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // delayed-nu-fission xs to the absorption xs score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= nuc_xs.get_xs( - MgxsType::DELAYED_NU_FISSION, p_g, nuc_t, nuc_a) / - abs_xs; + score *= + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g) / abs_xs; } else { - score *= macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - macro_t, macro_a) / - abs_xs; + score *= + macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g) / abs_xs; } } } @@ -2044,10 +1951,8 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = simulation::keff * p.wgt_bank() / p.n_bank() * p.n_delayed_bank(d - 1) * flux; if (i_nuclide >= 0) { - score *= - atom_density * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::FISSION, p_g); } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -2060,10 +1965,8 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = simulation::keff * p.wgt_bank() / p.n_bank() * n_delayed * flux; if (i_nuclide >= 0) { - score *= - atom_density * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::FISSION, p_g); } } } @@ -2078,10 +1981,10 @@ void score_general_mg(Particle& p, int i_tally, int start_index, if (i_nuclide >= 0) { score = flux * atom_density * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, - nullptr, &d, nuc_t, nuc_a); + nullptr, &d); } else { score = flux * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, macro_t, macro_a); + nullptr, nullptr, &d); } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -2089,12 +1992,10 @@ void score_general_mg(Particle& p, int i_tally, int start_index, continue; } else { if (i_nuclide >= 0) { - score = - flux * atom_density * - nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nuc_t, nuc_a); + score = flux * atom_density * + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g); } else { - score = flux * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - macro_t, macro_a); + score = flux * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g); } } } @@ -2106,8 +2007,7 @@ void score_general_mg(Particle& p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - double abs_xs = - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + double abs_xs = macro_xs.get_xs(MgxsType::ABSORPTION, p_g); if (abs_xs > 0) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; @@ -2119,16 +2019,16 @@ void score_general_mg(Particle& p, int i_tally, int start_index, auto d = filt.groups()[d_bin] - 1; score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, nuc_t, nuc_a) * + score *= nuc_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, nuc_t, nuc_a) / + nullptr, nullptr, &d) / abs_xs; } else { - score *= macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, macro_t, macro_a) * + score *= macro_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, macro_t, macro_a) / + nullptr, nullptr, &d) / abs_xs; } score_fission_delayed_dg( @@ -2144,17 +2044,17 @@ void score_general_mg(Particle& p, int i_tally, int start_index, for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { score += wgt_absorb * flux * - nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, nuc_t, nuc_a) * + nuc_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, nuc_t, nuc_a) / + nullptr, nullptr, &d) / abs_xs; } else { score += wgt_absorb * flux * - macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, macro_t, macro_a) * + macro_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, macro_t, macro_a) / + nullptr, nullptr, &d) / abs_xs; } } @@ -2177,16 +2077,15 @@ void score_general_mg(Particle& p, int i_tally, int start_index, auto d = bank.delayed_group - 1; if (d != -1) { if (i_nuclide >= 0) { - score += - simulation::keff * atom_density * bank.wgt * flux * - nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d, - nuc_t, nuc_a) * - nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); + score += simulation::keff * atom_density * bank.wgt * flux * + nuc_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * + nuc_xs.get_xs(MgxsType::FISSION, p_g) / + macro_xs.get_xs(MgxsType::FISSION, p_g); } else { score += simulation::keff * bank.wgt * flux * - macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, macro_t, macro_a); + macro_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d); } if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; @@ -2216,17 +2115,17 @@ void score_general_mg(Particle& p, int i_tally, int start_index, for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, - &d, nuc_t, nuc_a) * - nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, - nullptr, &d, nuc_t, nuc_a); + score = + atom_density * flux * + nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * + nuc_xs.get_xs( + MgxsType::DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); } else { score = flux * - macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, macro_t, macro_a) * + macro_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, macro_t, macro_a); + nullptr, nullptr, &d); } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -2236,17 +2135,17 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = 0.; for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { - score += atom_density * flux * - nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, nuc_t, nuc_a) * - nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, - nullptr, &d, nuc_t, nuc_a); + score += + atom_density * flux * + nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * + nuc_xs.get_xs( + MgxsType::DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); } else { score += flux * - macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d, macro_t, macro_a) * + macro_xs.get_xs( + MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d, macro_t, macro_a); + nullptr, nullptr, &d); } } } @@ -2270,29 +2169,27 @@ void score_general_mg(Particle& p, int i_tally, int start_index, score = p.wgt_last() * flux; } if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g, nuc_t, nuc_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= atom_density * nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } else { - score *= - macro_xs.get_xs(MgxsType::KAPPA_FISSION, p_g, macro_t, macro_a) / - macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); + score *= macro_xs.get_xs(MgxsType::KAPPA_FISSION, p_g) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * - nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g, nuc_t, nuc_a); + score = + atom_density * flux * nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g); } else { - score = flux * macro_xs.get_xs( - MgxsType::KAPPA_FISSION, p_g, macro_t, macro_a); + score = flux * macro_xs.get_xs(MgxsType::KAPPA_FISSION, p_g); } } break; case SCORE_EVENTS: - // Simply count the number of scoring events - score = 1.0; - break; +// Simply count the number of scoring events +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0; + continue; default: continue; @@ -2310,7 +2207,10 @@ void score_analog_tally_ce(Particle& p) // Since electrons/positrons are not transported, we assign a flux of zero. // Note that the heating score does NOT use the flux and will be non-zero for // electrons/positrons. - double flux = (p.type().is_neutron() || p.type().is_photon()) ? 1.0 : 0.0; + double flux = + (p.type() == ParticleType::neutron || p.type() == ParticleType::photon) + ? 1.0 + : 0.0; for (auto i_tally : model::active_analog_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2382,8 +2282,7 @@ void score_analog_tally_mg(Particle& p) model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; if (j == C_NONE) continue; - atom_density = - model::materials[p.material()]->atom_density(j, p.density_mult()); + atom_density = model::materials[p.material()]->atom_density_(j); } score_general_mg(p, i_tally, i * tally.scores_.size(), filter_index, @@ -2404,13 +2303,12 @@ void score_analog_tally_mg(Particle& p) match.bins_present_ = false; } -void score_tracklength_tally_general( - Particle& p, double flux, const vector& tallies) +void score_tracklength_tally(Particle& p, double distance) { - // Set 'none' value for log union grid index - int i_log_union = C_NONE; + // Determine the tracklength estimate of the flux + double flux = p.wgt() * distance; - for (auto i_tally : tallies) { + for (auto i_tally : model::active_tracklength_tallies) { const Tally& tally {*model::tallies[i_tally]}; // Initialize an iterator over valid filter bin combinations. If there are @@ -2433,24 +2331,11 @@ void score_tracklength_tally_general( double atom_density = 0.; if (i_nuclide >= 0) { if (p.material() != MATERIAL_VOID) { - const auto& mat = model::materials[p.material()]; - auto j = mat->mat_nuclide_index_[i_nuclide]; - if (j != C_NONE) - atom_density = mat->atom_density(j, p.density_mult()); - } - if (atom_density > 0) { - if (!tally.multiply_density()) - atom_density = 1.0; - } else if (!tally.multiply_density()) { - // Determine log union grid index - if (i_log_union == C_NONE) { - int neutron = ParticleType::neutron().transport_index(); - i_log_union = std::log(p.E() / data::energy_min[neutron]) / - simulation::log_spacing; - } - // Update micro xs cache - p.update_neutron_xs(i_nuclide, i_log_union); - atom_density = 1.0; + auto j = + model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; + if (j == C_NONE) + continue; + atom_density = model::materials[p.material()]->atom_density_(j); } } @@ -2478,68 +2363,14 @@ void score_tracklength_tally_general( match.bins_present_ = false; } -void score_timed_tracklength_tally(Particle& p, double total_distance) -{ - double speed = p.speed(); - double total_dt = total_distance / speed; - - // save particle last state - auto time_last = p.time_last(); - auto r_last = p.r_last(); - - // move particle back - p.move_distance(-total_distance); - p.time() -= total_dt; - p.lifetime() -= total_dt; - - double distance_traveled = 0.0; - while (distance_traveled < total_distance) { - - double distance = std::min(distance_to_time_boundary(p.time(), speed), - total_distance - distance_traveled); - double dt = distance / speed; - - // Save particle last state for tracklength tallies - p.time_last() = p.time(); - p.r_last() = p.r(); - - // Advance particle in space and time - p.move_distance(distance); - p.time() += dt; - p.lifetime() += dt; - - // Determine the tracklength estimate of the flux - double flux = p.wgt() * distance; - - score_tracklength_tally_general( - p, flux, model::active_timed_tracklength_tallies); - distance_traveled += distance; - } - - p.time_last() = time_last; - p.r_last() = r_last; -} - -void score_tracklength_tally(Particle& p, double distance) -{ - - // Determine the tracklength estimate of the flux - double flux = p.wgt() * distance; - - score_tracklength_tally_general(p, flux, model::active_tracklength_tallies); -} - void score_collision_tally(Particle& p) { // Determine the collision estimate of the flux double flux = 0.0; - if (p.type().is_neutron() || p.type().is_photon()) { + if (p.type() == ParticleType::neutron || p.type() == ParticleType::photon) { flux = p.wgt_last() / p.macro_xs().total; } - // Set 'none value for log union grid index - int i_log_union = C_NONE; - for (auto i_tally : model::active_collision_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2562,26 +2393,11 @@ void score_collision_tally(Particle& p) double atom_density = 0.; if (i_nuclide >= 0) { - if (p.material() != MATERIAL_VOID) { - const auto& mat = model::materials[p.material()]; - auto j = mat->mat_nuclide_index_[i_nuclide]; - if (j != C_NONE) - atom_density = mat->atom_density(j, p.density_mult()); - } - if (atom_density > 0) { - if (!tally.multiply_density()) - atom_density = 1.0; - } else if (!tally.multiply_density()) { - // Determine log union grid index - if (i_log_union == C_NONE) { - int neutron = ParticleType::neutron().transport_index(); - i_log_union = std::log(p.E() / data::energy_min[neutron]) / - simulation::log_spacing; - } - // Update micro xs cache - p.update_neutron_xs(i_nuclide, i_log_union); - atom_density = 1.0; - } + auto j = + model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; + if (j == C_NONE) + continue; + atom_density = model::materials[p.material()]->atom_density_(j); } // TODO: consider replacing this "if" with pointers or templates @@ -2608,7 +2424,7 @@ void score_collision_tally(Particle& p) match.bins_present_ = false; } -void score_meshsurface_tally(Particle& p, const vector& tallies) +void score_surface_tally(Particle& p, const vector& tallies) { double current = p.wgt_last(); @@ -2652,137 +2468,4 @@ void score_meshsurface_tally(Particle& p, const vector& tallies) match.bins_present_ = false; } -void score_surface_tally( - Particle& p, const vector& tallies, const Direction& normal) -{ - double wgt = p.wgt_last(); - - double mu = std::clamp(p.u().dot(normal), -1.0, 1.0); - - // Sign for net current: +1 if crossing outward (in direction of normal), - // -1 if crossing inward - double current_sign = std::copysign(1.0, mu); - - // Determine absolute cosine of angle between particle direction and surface - // normal, needed for the surface-crossing flux estimator. - double abs_mu = std::abs(mu); - if (abs_mu < settings::surface_grazing_cutoff) - abs_mu = settings::surface_grazing_ratio * settings::surface_grazing_cutoff; - - for (auto i_tally : tallies) { - auto& tally {*model::tallies[i_tally]}; - - // Initialize an iterator over valid filter bin combinations. If there are - // no valid combinations, use a continue statement to ensure we skip the - // assume_separate break below. - auto filter_iter = FilterBinIter(tally, p); - auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) - continue; - - // Loop over filter bins. - for (; filter_iter != end; ++filter_iter) { - auto filter_index = filter_iter.index_; - auto filter_weight = filter_iter.weight_; - - // Loop over scores. - for (auto score_index = 0; score_index < tally.scores_.size(); - ++score_index) { - auto score_bin = tally.scores_[score_index]; - double score; - if (score_bin == SCORE_CURRENT) { - // Net current: weight carries the sign of the crossing direction. - score = wgt * current_sign; - } else { - // SCORE_FLUX: surface-crossing estimator phi_S = sum(w / |mu|). - score = wgt / abs_mu; - } -#pragma omp atomic - tally.results_(filter_index, score_index, TallyResult::VALUE) += - score * filter_weight; - } - } - // If the user has specified that we can assume all tallies are spatially - // separate, this implies that once a tally has been scored to, we needn't - // check the others. This cuts down on overhead when there are many - // tallies specified - if (settings::assume_separate) - break; - } - - // Reset all the filter matches for the next tally event. - for (auto& match : p.filter_matches()) - match.bins_present_ = false; -} - -void score_pulse_height_tally(Particle& p, const vector& tallies) -{ - // The pulse height tally in OpenMC hijacks the logic of CellFilter and - // EnergyFilter to score specific quantities related to particle pulse height. - // This is achieved by setting the pulse-height cell of the tally to the cell - // of the particle being scored, and the energy to the particle's last - // recorded energy (E_last()). After the tally is scored, the values are reset - // to ensure proper accounting and avoid interference with subsequent - // calculations or tallies. - - // Save original cell/energy information - int orig_n_coord = p.n_coord(); - int orig_cell = p.coord(0).cell(); - double orig_E_last = p.E_last(); - - // Set particle in top level - p.n_coord() = 1; - - for (auto i_tally : tallies) { - auto& tally {*model::tallies[i_tally]}; - - // Find CellFilter in the tally (if any) to determine cells to loop over - const auto* cell_filter = tally.get_filter(); - const auto& cells = - cell_filter ? cell_filter->cells() : model::pulse_height_cells; - - for (auto cell_id : cells) { - // Temporarily change cell of particle - p.coord(0).cell() = cell_id; - - // Determine index of cell in model::pulse_height_cells - auto it = std::find(model::pulse_height_cells.begin(), - model::pulse_height_cells.end(), cell_id); - int index = std::distance(model::pulse_height_cells.begin(), it); - - // Temporarily change energy of particle to pulse-height value - p.E_last() = p.pht_storage()[index]; - - // Initialize an iterator over valid filter bin combinations. If - // there are no valid combinations, use a continue statement to ensure - // we skip the assume_separate break below. - auto filter_iter = FilterBinIter(tally, p); - auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter != end) { - - // Loop over filter bins. - for (; filter_iter != end; ++filter_iter) { - auto filter_index = filter_iter.index_; - auto filter_weight = filter_iter.weight_; - - // Loop over scores. - for (auto score_index = 0; score_index < tally.scores_.size(); - ++score_index) { -#pragma omp atomic - tally.results_(filter_index, score_index, TallyResult::VALUE) += - filter_weight; - } - } - } - - // Reset all the filter matches for the next tally event. - for (auto& match : p.filter_matches()) - match.bins_present_ = false; - } - } - // Restore cell/energy - p.n_coord() = orig_n_coord; - p.coord(0).cell() = orig_cell; - p.E_last() = orig_E_last; -} } // namespace openmc diff --git a/src/tallies/trigger.cpp b/src/tallies/trigger.cpp index 7515f01a9..2c155980e 100644 --- a/src/tallies/trigger.cpp +++ b/src/tallies/trigger.cpp @@ -28,7 +28,7 @@ KTrigger keff_trigger; //============================================================================== std::pair get_tally_uncertainty( - int i_tally, int score_index, int64_t filter_index) + int i_tally, int score_index, int filter_index) { const auto& tally {model::tallies[i_tally]}; @@ -37,11 +37,6 @@ std::pair get_tally_uncertainty( int n = tally->n_realizations_; auto mean = sum / n; - - // if the result has no contributions, return an invalid pair - if (mean == 0) - return {-1, -1}; - double std_dev = std::sqrt((sum_sq / n - mean * mean) / (n - 1)); double rel_err = (mean != 0.) ? std_dev / std::abs(mean) : 0.; @@ -71,51 +66,44 @@ void check_tally_triggers(double& ratio, int& tally_id, int& score) continue; const auto& results = t.results_; - for (int64_t filter_index = 0; filter_index < results.shape(0); + for (auto filter_index = 0; filter_index < results.shape()[0]; ++filter_index) { - // Compute the tally uncertainty metrics. - auto uncert_pair = - get_tally_uncertainty(i_tally, trigger.score_index, filter_index); + for (auto score_index = 0; score_index < results.shape()[1]; + ++score_index) { + // Compute the tally uncertainty metrics. + auto uncert_pair = + get_tally_uncertainty(i_tally, score_index, filter_index); + double std_dev = uncert_pair.first; + double rel_err = uncert_pair.second; - // If there is a score without contributions, set ratio to inf and - // exit early, unless zero scores are ignored for this trigger. - if (uncert_pair.first == -1 && !trigger.ignore_zeros) { - ratio = INFINITY; - score = t.scores_[trigger.score_index]; - tally_id = t.id_; - return; - } + // Pick out the relevant uncertainty metric for this trigger. + double uncertainty; + switch (trigger.metric) { + case TriggerMetric::variance: + uncertainty = std_dev * std_dev; + break; + case TriggerMetric::standard_deviation: + uncertainty = std_dev; + break; + case TriggerMetric::relative_error: + uncertainty = rel_err; + break; + case TriggerMetric::not_active: + UNREACHABLE(); + } - double std_dev = uncert_pair.first; - double rel_err = uncert_pair.second; + // Compute the uncertainty / threshold ratio. + double this_ratio = uncertainty / trigger.threshold; + if (trigger.metric == TriggerMetric::variance) { + this_ratio = std::sqrt(ratio); + } - // Pick out the relevant uncertainty metric for this trigger. - double uncertainty; - switch (trigger.metric) { - case TriggerMetric::variance: - uncertainty = std_dev * std_dev; - break; - case TriggerMetric::standard_deviation: - uncertainty = std_dev; - break; - case TriggerMetric::relative_error: - uncertainty = rel_err; - break; - case TriggerMetric::not_active: - UNREACHABLE(); - } - - // Compute the uncertainty / threshold ratio. - double this_ratio = uncertainty / trigger.threshold; - if (trigger.metric == TriggerMetric::variance) { - this_ratio = std::sqrt(ratio); - } - - // If this is the most uncertain value, set the output variables. - if (this_ratio > ratio) { - ratio = this_ratio; - score = t.scores_[trigger.score_index]; - tally_id = t.id_; + // If this is the most uncertain value, set the output variables. + if (this_ratio > ratio) { + ratio = this_ratio; + score = t.scores_[trigger.score_index]; + tally_id = t.id_; + } } } } @@ -193,15 +181,9 @@ void check_triggers() "eigenvalue", keff_ratio); } else { - if (tally_ratio == INFINITY) { - msg = fmt::format( - "Triggers unsatisfied, no result tallied for score {} in tally {}", - reaction_name(score), tally_id); - } else { - msg = fmt::format( - "Triggers unsatisfied, max unc./thresh. is {} for {} in tally {}", - tally_ratio, reaction_name(score), tally_id); - } + msg = fmt::format( + "Triggers unsatisfied, max unc./thresh. is {} for {} in tally {}", + tally_ratio, reaction_name(score), tally_id); } write_message(msg, 7); @@ -214,20 +196,13 @@ void check_triggers() auto n_pred_batches = static_cast(n_active * max_ratio * max_ratio) + settings::n_inactive + 1; - if (max_ratio == INFINITY) { - std::string msg = - fmt::format("One or more tallies with triggers have no scores. Unable " - "to estimate the number of remaining batches."); - write_message(msg, 7); + std::string msg = + fmt::format("The estimated number of batches is {}", n_pred_batches); + if (n_pred_batches > settings::n_max_batches) { + msg.append(" --- greater than max batches"); + warning(msg); } else { - std::string msg = - fmt::format("The estimated number of batches is {}", n_pred_batches); - if (n_pred_batches > settings::n_max_batches) { - msg.append(" --- greater than max batches"); - warning(msg); - } else { - write_message(msg, 7); - } + write_message(msg, 7); } } } diff --git a/src/thermal.cpp b/src/thermal.cpp index edfbddf23..1a9592d0a 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -3,7 +3,12 @@ #include // for sort, move, min, max, find #include // for round, sqrt, abs -#include "openmc/tensor.h" +#include "xtensor/xarray.hpp" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xtensor.hpp" +#include "xtensor/xview.hpp" #include #include "openmc/constants.h" @@ -14,7 +19,6 @@ #include "openmc/secondary_correlated.h" #include "openmc/secondary_thermal.h" #include "openmc/settings.h" -#include "openmc/string_utils.h" namespace openmc { @@ -50,12 +54,12 @@ ThermalScattering::ThermalScattering( // Determine temperatures available auto dset_names = dataset_names(kT_group); auto n = dset_names.size(); - auto temps_available = tensor::Tensor({n}); + auto temps_available = xt::empty({n}); for (int i = 0; i < dset_names.size(); ++i) { // Read temperature value double T; read_dataset(kT_group, dset_names[i].data(), T); - temps_available[i] = std::round(T / K_BOLTZMANN); + temps_available[i] = T / K_BOLTZMANN; } std::sort(temps_available.begin(), temps_available.end()); @@ -77,7 +81,7 @@ ThermalScattering::ThermalScattering( // Determine actual temperatures to read for (const auto& T : temperature) { - auto i_closest = tensor::abs(temps_available - T).argmin(); + auto i_closest = xt::argmin(xt::abs(temps_available - T))[0]; auto temp_actual = temps_available[i_closest]; if (std::abs(temp_actual - T) < settings::temperature_tolerance) { if (std::find(temps_to_read.begin(), temps_to_read.end(), @@ -85,12 +89,9 @@ ThermalScattering::ThermalScattering( temps_to_read.push_back(std::round(temp_actual)); } } else { - fatal_error(fmt::format( - "Nuclear data library does not contain cross sections " - "for {} at or near {} K. Available temperatures " - "are {} K. Consider making use of openmc.Settings.temperature " - "to specify how intermediate temperatures are treated.", - name_, std::round(T), concatenate(temps_available))); + fatal_error(fmt::format("Nuclear data library does not contain cross " + "sections for {} at or near {} K.", + name_, std::round(T))); } } break; @@ -102,8 +103,8 @@ ThermalScattering::ThermalScattering( bool found = false; for (int j = 0; j < temps_available.size() - 1; ++j) { if (temps_available[j] <= T && T < temps_available[j + 1]) { - int T_j = temps_available[j]; - int T_j1 = temps_available[j + 1]; + int T_j = std::round(temps_available[j]); + int T_j1 = std::round(temps_available[j + 1]); if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j) == temps_to_read.end()) { temps_to_read.push_back(T_j); @@ -116,26 +117,10 @@ ThermalScattering::ThermalScattering( } } if (!found) { - // If no pairs found, check if the desired temperature falls within - // bounds' tolerance - if (std::abs(T - temps_available[0]) <= - settings::temperature_tolerance) { - if (std::find(temps_to_read.begin(), temps_to_read.end(), - temps_available[0]) == temps_to_read.end()) { - temps_to_read.push_back(temps_available[0]); - } - } else if (std::abs(T - temps_available[n - 1]) <= - settings::temperature_tolerance) { - if (std::find(temps_to_read.begin(), temps_to_read.end(), - temps_available[n - 1]) == temps_to_read.end()) { - temps_to_read.push_back(temps_available[n - 1]); - } - } else { - fatal_error( - fmt::format("Nuclear data library does not contain cross " - "sections for {} at temperatures that bound {} K.", - name_, std::round(T))); - } + fatal_error( + fmt::format("Nuclear data library does not contain cross " + "sections for {} at temperatures that bound {} K.", + name_, std::round(T))); } } } @@ -174,27 +159,20 @@ void ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, auto n = kTs_.size(); if (n > 1) { + // Find temperatures that bound the actual temperature + while (kTs_[i + 1] < kT && i + 1 < n - 1) + ++i; + if (settings::temperature_method == TemperatureMethod::NEAREST) { - while (kTs_[i + 1] < kT && i + 1 < n - 1) - ++i; // Pick closer of two bounding temperatures if (kT - kTs_[i] > kTs_[i + 1] - kT) ++i; + } else { - // If current kT outside of the bounds of available, snap to the bound - if (kT < kTs_.front()) { - i = 0; - } else if (kT > kTs_.back()) { - i = kTs_.size() - 1; - } else { - // Find temperatures that bound the actual temperature - while (kTs_[i + 1] < kT && i + 1 < n - 1) - ++i; - // Randomly sample between temperature i and i+1 - double f = (kT - kTs_[i]) / (kTs_[i + 1] - kTs_[i]); - if (f > prn(seed)) - ++i; - } + // Randomly sample between temperature i and i+1 + double f = (kT - kTs_[i]) / (kTs_[i + 1] - kTs_[i]); + if (f > prn(seed)) + ++i; } } @@ -291,21 +269,16 @@ void ThermalData::calculate_xs( *inelastic = (*inelastic_.xs)(E); } -AngleEnergy& ThermalData::sample_dist( - const NuclideMicroXS& micro_xs, double E, uint64_t* seed) const +void ThermalData::sample(const NuclideMicroXS& micro_xs, double E, + double* E_out, double* mu, uint64_t* seed) { // Determine whether inelastic or elastic scattering will occur if (prn(seed) < micro_xs.thermal_elastic / micro_xs.thermal) { - return *elastic_.distribution; + elastic_.distribution->sample(E, *E_out, *mu, seed); } else { - return *inelastic_.distribution; + inelastic_.distribution->sample(E, *E_out, *mu, seed); } -} -void ThermalData::sample(const NuclideMicroXS& micro_xs, double E, - double* E_out, double* mu, uint64_t* seed) const -{ - sample_dist(micro_xs, E, seed).sample(E, *E_out, *mu, seed); // Because of floating-point roundoff, it may be possible for mu to be // outside of the range [-1,1). In these cases, we just set mu to exactly // -1 or 1 @@ -313,13 +286,6 @@ void ThermalData::sample(const NuclideMicroXS& micro_xs, double E, *mu = std::copysign(1.0, *mu); } -double ThermalData::sample_energy_and_pdf(const NuclideMicroXS& micro_xs, - double E_in, double mu, double& E_out, uint64_t* seed) const -{ - return sample_dist(micro_xs, E_in, seed) - .sample_energy_and_pdf(E_in, mu, E_out, seed); -} - void free_memory_thermal() { data::thermal_scatt.clear(); diff --git a/src/timer.cpp b/src/timer.cpp index 6d692d4fb..86436758a 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -26,7 +26,6 @@ Timer time_event_advance_particle; Timer time_event_surface_crossing; Timer time_event_collision; Timer time_event_death; -Timer time_update_src; } // namespace simulation @@ -86,7 +85,6 @@ void reset_timers() simulation::time_event_surface_crossing.reset(); simulation::time_event_collision.reset(); simulation::time_event_death.reset(); - simulation::time_update_src.reset(); } } // namespace openmc diff --git a/src/track_output.cpp b/src/track_output.cpp index 02e092236..5c1436de7 100644 --- a/src/track_output.cpp +++ b/src/track_output.cpp @@ -8,7 +8,7 @@ #include "openmc/simulation.h" #include "openmc/vector.h" -#include "openmc/tensor.h" +#include "xtensor/xtensor.hpp" #include #include @@ -31,8 +31,8 @@ int n_tracks_written; //! Number of tracks written void add_particle_track(Particle& p) { - auto& track = p.tracks().emplace_back(); - track.particle = p.type(); + p.tracks().emplace_back(); + p.tracks().back().particle = p.type(); } void write_particle_track(Particle& p) @@ -122,7 +122,7 @@ void finalize_particle_track(Particle& p) int offset = 0; for (auto& track_i : p.tracks()) { offsets.push_back(offset); - particles.push_back(track_i.particle.pdg_number()); + particles.push_back(static_cast(track_i.particle)); offset += track_i.states.size(); tracks.insert(tracks.end(), track_i.states.begin(), track_i.states.end()); } diff --git a/src/universe.cpp b/src/universe.cpp index e1db80b99..f3f9cf8e8 100644 --- a/src/universe.cpp +++ b/src/universe.cpp @@ -3,7 +3,6 @@ #include #include "openmc/hdf5_interface.h" -#include "openmc/particle.h" namespace openmc { @@ -37,22 +36,23 @@ void Universe::to_hdf5(hid_t universes_group) const close_group(group); } -bool Universe::find_cell(GeometryState& p) const +bool Universe::find_cell(Particle& p) const { const auto& cells { !partitioner_ ? cells_ : partitioner_->get_cells(p.r_local(), p.u_local())}; - Position r {p.r_local()}; - Position u {p.u_local()}; - auto surf = p.surface(); - int32_t i_univ = p.lowest_coord().universe(); - - for (auto i_cell : cells) { + for (auto it = cells.begin(); it != cells.end(); it++) { + int32_t i_cell = *it; + int32_t i_univ = p.coord(p.n_coord() - 1).universe; if (model::cells[i_cell]->universe_ != i_univ) continue; - // Check if this cell contains the particle + + // Check if this cell contains the particle; + Position r {p.r_local()}; + Direction u {p.u_local()}; + auto surf = p.surface(); if (model::cells[i_cell]->contains(r, u, surf)) { - p.lowest_coord().cell() = i_cell; + p.coord(p.n_coord() - 1).cell = i_cell; return true; } } @@ -61,7 +61,7 @@ bool Universe::find_cell(GeometryState& p) const BoundingBox Universe::bounding_box() const { - BoundingBox bbox = BoundingBox::inverted(); + BoundingBox bbox = {INFTY, -INFTY, INFTY, -INFTY, INFTY, -INFTY}; if (cells_.size() == 0) { return {}; } else { @@ -98,11 +98,13 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) // Find all of the z-planes in this universe. A set is used here for the // O(log(n)) insertions that will ensure entries are not repeated. for (auto i_cell : univ.cells_) { - for (auto token : model::cells[i_cell]->surfaces()) { - auto i_surf = std::abs(token) - 1; - const auto* surf = model::surfaces[i_surf].get(); - if (const auto* zplane = dynamic_cast(surf)) - surf_set.insert(i_surf); + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) { + auto i_surf = std::abs(token) - 1; + const auto* surf = model::surfaces[i_surf].get(); + if (const auto* zplane = dynamic_cast(surf)) + surf_set.insert(i_surf); + } } } @@ -114,7 +116,7 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) for (auto i_cell : univ.cells_) { // It is difficult to determine the bounds of a complex cell, so add complex // cells to all partitions. - if (!model::cells[i_cell]->is_simple()) { + if (!model::cells[i_cell]->simple_) { for (auto& p : partitions_) p.push_back(i_cell); continue; @@ -123,16 +125,18 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) // Find the tokens for bounding z-planes. int32_t lower_token = 0, upper_token = 0; double min_z, max_z; - for (auto token : model::cells[i_cell]->surfaces()) { - const auto* surf = model::surfaces[std::abs(token) - 1].get(); - if (const auto* zplane = dynamic_cast(surf)) { - if (lower_token == 0 || zplane->z0_ < min_z) { - lower_token = token; - min_z = zplane->z0_; - } - if (upper_token == 0 || zplane->z0_ > max_z) { - upper_token = token; - max_z = zplane->z0_; + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) { + const auto* surf = model::surfaces[std::abs(token) - 1].get(); + if (const auto* zplane = dynamic_cast(surf)) { + if (lower_token == 0 || zplane->z0_ < min_z) { + lower_token = token; + min_z = zplane->z0_; + } + if (upper_token == 0 || zplane->z0_ > max_z) { + upper_token = token; + max_z = zplane->z0_; + } } } } diff --git a/src/urr.cpp b/src/urr.cpp index b791eecb0..02cef2280 100644 --- a/src/urr.cpp +++ b/src/urr.cpp @@ -25,7 +25,7 @@ UrrData::UrrData(hid_t group_id) // Read URR tables. The HDF5 format is a little // different from how we want it laid out in memory. // This array used to be called "prob_". - tensor::Tensor tmp_prob; + xt::xtensor tmp_prob; read_dataset(group_id, "table", tmp_prob); auto shape = tmp_prob.shape(); @@ -38,7 +38,7 @@ UrrData::UrrData(hid_t group_id) xs_values_.resize({n_energy, n_cdf_values}); // Now fill in the values. Using manual loops here since we might - // not have fancy tensor slicing code written for GPU tensors. + // not have fancy xtensor slicing code written for GPU tensors. // The below enum gives how URR tables are laid out in our HDF5 tables. enum class URRTableParam { CUM_PROB, diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index f675ae78a..3ae98fdc3 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -10,15 +10,18 @@ #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" -#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/random_lcg.h" #include "openmc/settings.h" #include "openmc/timer.h" #include "openmc/xml_interface.h" -#include "openmc/tensor.h" #include +#ifdef _OPENMP +#include +#endif +#include "xtensor/xadapt.hpp" +#include "xtensor/xview.hpp" #include // for copy #include // for pow, sqrt @@ -94,43 +97,18 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) vector VolumeCalculation::execute() const { - // Check to make sure domain IDs are valid - for (auto uid : domain_ids_) { - switch (domain_type_) { - case TallyDomain::CELL: - if (model::cell_map.find(uid) == model::cell_map.end()) { - throw std::runtime_error {fmt::format( - "Cell {} in volume calculation does not exist in geometry.", uid)}; - } - break; - case TallyDomain::MATERIAL: - if (model::material_map.find(uid) == model::material_map.end()) { - throw std::runtime_error {fmt::format( - "Material {} in volume calculation does not exist in geometry.", - uid)}; - } - break; - case TallyDomain::UNIVERSE: - if (model::universe_map.find(uid) == model::universe_map.end()) { - throw std::runtime_error {fmt::format( - "Universe {} in volume calculation does not exist in geometry.", - uid)}; - } - } - } - // Shared data that is collected from all threads int n = domain_ids_.size(); - vector> master_indices( + vector> master_indices( n); // List of material indices for each domain - vector> master_hits( + vector> master_hits( n); // Number of hits for each material in each domain int iterations = 0; // Divide work over MPI processes - uint64_t min_samples = n_samples_ / mpi::n_procs; - uint64_t remainder = n_samples_ % mpi::n_procs; - uint64_t i_start, i_end; + size_t min_samples = n_samples_ / mpi::n_procs; + size_t remainder = n_samples_ % mpi::n_procs; + size_t i_start, i_end; if (mpi::rank < remainder) { i_start = (min_samples + 1) * mpi::rank; i_end = i_start + min_samples + 1; @@ -145,20 +123,20 @@ vector VolumeCalculation::execute() const #pragma omp parallel { // Variables that are private to each thread - vector> indices(n); - vector> hits(n); + vector> indices(n); + vector> hits(n); Particle p; // Sample locations and count hits #pragma omp for for (size_t i = i_start; i < i_end; i++) { - uint64_t id = iterations * n_samples_ + i; + int64_t id = iterations * n_samples_ + i; uint64_t seed = init_seed(id, STREAM_VOLUME); p.n_coord() = 1; Position xi {prn(&seed), prn(&seed), prn(&seed)}; p.r() = lower_left_ + xi * (upper_right_ - lower_left_); - p.u() = {1. / std::sqrt(3.), 1. / std::sqrt(3.), 1. / std::sqrt(3.)}; + p.u() = {0.5, 0.5, 0.5}; // If this location is not in the geometry at all, move on to next block if (!exhaustive_find_cell(p)) @@ -178,7 +156,7 @@ vector VolumeCalculation::execute() const } else if (domain_type_ == TallyDomain::CELL) { for (int level = 0; level < p.n_coord(); ++level) { for (int i_domain = 0; i_domain < n; i_domain++) { - if (model::cells[p.coord(level).cell()]->id_ == + if (model::cells[p.coord(level).cell]->id_ == domain_ids_[i_domain]) { this->check_hit( p.material(), indices[i_domain], hits[i_domain]); @@ -189,7 +167,7 @@ vector VolumeCalculation::execute() const } else if (domain_type_ == TallyDomain::UNIVERSE) { for (int level = 0; level < p.n_coord(); ++level) { for (int i_domain = 0; i_domain < n; ++i_domain) { - if (model::universes[p.coord(level).universe()]->id_ == + if (model::universes[p.coord(level).universe]->id_ == domain_ids_[i_domain]) { check_hit(p.material(), indices[i_domain], hits[i_domain]); break; @@ -202,9 +180,37 @@ vector VolumeCalculation::execute() const // At this point, each thread has its own pair of index/hits lists and we // now need to reduce them. OpenMP is not nearly smart enough to do this // on its own, so we have to manually reduce them - for (int i_domain = 0; i_domain < n; ++i_domain) { - reduce_indices_hits(indices[i_domain], hits[i_domain], - master_indices[i_domain], master_hits[i_domain]); + +#ifdef _OPENMP + int n_threads = omp_get_num_threads(); +#else + int n_threads = 1; +#endif + +#pragma omp for ordered schedule(static) + for (int i = 0; i < n_threads; ++i) { +#pragma omp ordered + for (int i_domain = 0; i_domain < n; ++i_domain) { + for (int j = 0; j < indices[i_domain].size(); ++j) { + // Check if this material has been added to the master list and if + // so, accumulate the number of hits + bool already_added = false; + for (int k = 0; k < master_indices[i_domain].size(); k++) { + if (indices[i_domain][j] == master_indices[i_domain][k]) { + master_hits[i_domain][k] += hits[i_domain][j]; + already_added = true; + break; + } + } + if (!already_added) { + // If we made it here, the material hasn't yet been added to the + // master list, so add entries to the master indices and master + // hits lists + master_indices[i_domain].push_back(indices[i_domain][j]); + master_hits[i_domain].push_back(hits[i_domain][j]); + } + } + } } } // omp parallel @@ -217,14 +223,7 @@ vector VolumeCalculation::execute() const // bump iteration counter and get total number // of samples at this point iterations++; - uint64_t total_samples = iterations * n_samples_; - - // warn user if total sample size is greater than what the uin64_t type can - // represent - if (total_samples == std::numeric_limits::max()) { - warning("The number of samples has exceeded the type used to track hits. " - "Volume results may be inaccurate."); - } + size_t total_samples = iterations * n_samples_; // reset double trigger_val = -INFTY; @@ -239,20 +238,18 @@ vector VolumeCalculation::execute() const // Create 2D array to store atoms/uncertainty for each nuclide. Later this // is compressed into vectors storing only those nuclides that are // non-zero - auto n_nuc = - settings::run_CE ? data::nuclides.size() : data::mg.nuclides_.size(); - auto atoms = - tensor::zeros({static_cast(n_nuc), size_t {2}}); + auto n_nuc = settings::run_CE ? data::nuclides.size() + : data::mg.nuclides_.size(); + xt::xtensor atoms({n_nuc, 2}, 0.0); #ifdef OPENMC_MPI if (mpi::master) { for (int j = 1; j < mpi::n_procs; j++) { int q; - // retrieve results MPI_Recv( - &q, 1, MPI_UINT64_T, j, 2 * j, mpi::intracomm, MPI_STATUS_IGNORE); - vector buffer(2 * q); - MPI_Recv(buffer.data(), 2 * q, MPI_UINT64_T, j, 2 * j + 1, + &q, 1, MPI_INTEGER, j, 2 * j, mpi::intracomm, MPI_STATUS_IGNORE); + vector buffer(2 * q); + MPI_Recv(buffer.data(), 2 * q, MPI_INTEGER, j, 2 * j + 1, mpi::intracomm, MPI_STATUS_IGNORE); for (int k = 0; k < q; ++k) { bool already_added = false; @@ -271,20 +268,20 @@ vector VolumeCalculation::execute() const } } else { int q = master_indices[i_domain].size(); - vector buffer(2 * q); + vector buffer(2 * q); for (int k = 0; k < q; ++k) { buffer[2 * k] = master_indices[i_domain][k]; buffer[2 * k + 1] = master_hits[i_domain][k]; } - MPI_Send(&q, 1, MPI_UINT64_T, 0, 2 * mpi::rank, mpi::intracomm); - MPI_Send(buffer.data(), 2 * q, MPI_UINT64_T, 0, 2 * mpi::rank + 1, + MPI_Send(&q, 1, MPI_INTEGER, 0, 2 * mpi::rank, mpi::intracomm); + MPI_Send(buffer.data(), 2 * q, MPI_INTEGER, 0, 2 * mpi::rank + 1, mpi::intracomm); } #endif if (mpi::master) { - size_t total_hits = 0; + int total_hits = 0; for (int j = 0; j < master_indices[i_domain].size(); ++j) { total_hits += master_hits[i_domain][j]; double f = @@ -452,11 +449,9 @@ void VolumeCalculation::to_hdf5( } // Create array of total # of atoms with uncertainty for each nuclide - tensor::Tensor atom_data({static_cast(n_nuc), size_t {2}}); - for (size_t k = 0; k < static_cast(n_nuc); ++k) { - atom_data(k, 0) = result.atoms[k]; - atom_data(k, 1) = result.uncertainty[k]; - } + xt::xtensor atom_data({n_nuc, 2}); + xt::view(atom_data, xt::all(), 0) = xt::adapt(result.atoms); + xt::view(atom_data, xt::all(), 1) = xt::adapt(result.uncertainty); // Write results write_dataset(group_id, "nuclides", nucnames); @@ -469,7 +464,7 @@ void VolumeCalculation::to_hdf5( } void VolumeCalculation::check_hit( - int i_material, vector& indices, vector& hits) const + int i_material, vector& indices, vector& hits) const { // Check if this material was previously hit and if so, increment count @@ -516,13 +511,7 @@ int openmc_calculate_volumes() // Run volume calculation const auto& vol_calc {model::volume_calcs[i]}; - std::vector results; - try { - results = vol_calc.execute(); - } catch (const std::exception& e) { - set_errmsg(e.what()); - return OPENMC_E_UNASSIGNED; - } + auto results = vol_calc.execute(); if (mpi::master) { std::string domain_type; @@ -537,21 +526,8 @@ int openmc_calculate_volumes() // Display domain volumes for (int j = 0; j < vol_calc.domain_ids_.size(); j++) { - std::string region_name {""}; - if (vol_calc.domain_type_ == VolumeCalculation::TallyDomain::CELL) { - int cell_idx = model::cell_map[vol_calc.domain_ids_[j]]; - region_name = model::cells[cell_idx]->name(); - } else if (vol_calc.domain_type_ == - VolumeCalculation::TallyDomain::MATERIAL) { - int mat_idx = model::material_map[vol_calc.domain_ids_[j]]; - region_name = model::materials[mat_idx]->name(); - } - if (region_name.size()) - region_name.insert(0, " "); // prepend space for formatting - - write_message(4, "{}{}{}: {} +/- {} cm^3", domain_type, - vol_calc.domain_ids_[j], region_name, results[j].volume[0], - results[j].volume[1]); + write_message(4, "{}{}: {} +/- {} cm^3", domain_type, + vol_calc.domain_ids_[j], results[j].volume[0], results[j].volume[1]); } // Write volumes to HDF5 file diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index 0d268ce17..f0431f71f 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -1,34 +1,16 @@ #include "openmc/weight_windows.h" -#include -#include -#include -#include -#include - -#include "openmc/tensor.h" - #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" -#include "openmc/mesh.h" -#include "openmc/message_passing.h" -#include "openmc/nuclide.h" -#include "openmc/output.h" #include "openmc/particle.h" #include "openmc/particle_data.h" #include "openmc/physics_common.h" -#include "openmc/random_ray/flat_source_domain.h" #include "openmc/search.h" -#include "openmc/settings.h" -#include "openmc/simulation.h" -#include "openmc/tallies/filter_energy.h" -#include "openmc/tallies/filter_mesh.h" -#include "openmc/tallies/filter_particle.h" -#include "openmc/tallies/tally.h" #include "openmc/xml_interface.h" #include +#include namespace openmc { @@ -40,26 +22,97 @@ namespace variance_reduction { std::unordered_map ww_map; openmc::vector> weight_windows; -openmc::vector> weight_windows_generators; } // namespace variance_reduction +//============================================================================== +// Non-member functions +//============================================================================== + +void apply_weight_windows(Particle& p) +{ + // skip dead or no energy + if (p.E() <= 0 || !p.alive()) + return; + + bool in_domain = false; + // TODO: this is a linear search - should do something more clever + WeightWindow weight_window; + for (const auto& ww : variance_reduction::weight_windows) { + weight_window = ww->get_weight_window(p); + if (weight_window.is_valid()) + break; + } + // particle is not in any of the ww domains, do nothing + if (!weight_window.is_valid()) + return; + + // get the paramters + double weight = p.wgt(); + + // first check to see if particle should be killed for weight cutoff + if (p.wgt() < weight_window.weight_cutoff) { + p.wgt() = 0.0; + return; + } + + // check if particle is far above current weight window + // only do this if the factor is not already set on the particle and a + // maximum lower bound ratio is specified + if (p.ww_factor() == 0.0 && weight_window.max_lb_ratio > 1.0 && + p.wgt() > weight_window.lower_weight * weight_window.max_lb_ratio) { + p.ww_factor() = + p.wgt() / (weight_window.lower_weight * weight_window.max_lb_ratio); + } + + // move weight window closer to the particle weight if needed + if (p.ww_factor() > 1.0) + weight_window.scale(p.ww_factor()); + + // if particle's weight is above the weight window split until they are within + // the window + if (weight > weight_window.upper_weight) { + // do not further split the particle if above the limit + if (p.n_split() >= settings::max_splits) + return; + + double n_split = std::ceil(weight / weight_window.upper_weight); + double max_split = weight_window.max_split; + n_split = std::min(n_split, max_split); + + p.n_split() += n_split; + + // Create secondaries and divide weight among all particles + int i_split = std::round(n_split); + for (int l = 0; l < i_split - 1; l++) { + p.create_secondary(weight / n_split, p.u(), p.E(), p.type()); + } + // remaining weight is applied to current particle + p.wgt() = weight / n_split; + + } else if (weight <= weight_window.lower_weight) { + // if the particle weight is below the window, play Russian roulette + double weight_survive = + std::min(weight * weight_window.max_split, weight_window.survival_weight); + russian_roulette(p, weight_survive); + } // else particle is in the window, continue as normal +} + +void free_memory_weight_windows() +{ + variance_reduction::ww_map.clear(); + variance_reduction::weight_windows.clear(); +} + //============================================================================== // WeightWindowSettings implementation //============================================================================== -WeightWindows::WeightWindows(int32_t id) -{ - index_ = variance_reduction::weight_windows.size(); - set_id(id); - set_defaults(); -} - WeightWindows::WeightWindows(pugi::xml_node node) { // Make sure required elements are present - const vector required_elems { - "id", "particle_type", "lower_ww_bounds", "upper_ww_bounds"}; + const vector required_elems {"id", "particle_type", + "energy_bounds", "lower_ww_bounds", "upper_ww_bounds"}; for (const auto& elem : required_elems) { if (!check_for_node(node, elem.c_str())) { fatal_error(fmt::format("Must specify <{}> for weight windows.", elem)); @@ -72,15 +125,18 @@ WeightWindows::WeightWindows(pugi::xml_node node) // get the particle type auto particle_type_str = std::string(get_node_value(node, "particle_type")); - particle_type_ = ParticleType {particle_type_str}; + particle_type_ = openmc::str_to_particle_type(particle_type_str); // Determine associated mesh int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); - set_mesh(model::mesh_map.at(mesh_id)); + mesh_idx_ = model::mesh_map.at(mesh_id); // energy bounds - if (check_for_node(node, "energy_bounds")) - energy_bounds_ = get_node_array(node, "energy_bounds"); + energy_bounds_ = get_node_array(node, "energy_bounds"); + + // read the lower/upper weight bounds + lower_ww_ = get_node_array(node, "lower_ww_bounds"); + upper_ww_ = get_node_array(node, "upper_ww_bounds"); // get the survival value - optional if (check_for_node(node, "survival_ratio")) { @@ -114,101 +170,28 @@ WeightWindows::WeightWindows(pugi::xml_node node) fatal_error("weight_cutoff must be less than 1"); } - // read the lower/upper weight bounds - this->set_bounds(get_node_array(node, "lower_ww_bounds"), - get_node_array(node, "upper_ww_bounds")); - - set_defaults(); -} - -WeightWindows::~WeightWindows() -{ - variance_reduction::ww_map.erase(id()); -} - -WeightWindows* WeightWindows::create(int32_t id) -{ - variance_reduction::weight_windows.push_back(make_unique()); - auto wws = variance_reduction::weight_windows.back().get(); - variance_reduction::ww_map[wws->id()] = - variance_reduction::weight_windows.size() - 1; - return wws; -} - -WeightWindows* WeightWindows::from_hdf5( - hid_t wws_group, const std::string& group_name) -{ - // collect ID from the name of this group - hid_t ww_group = open_group(wws_group, group_name); - - auto wws = WeightWindows::create(); - - std::string particle_type; - read_dataset(ww_group, "particle_type", particle_type); - wws->particle_type_ = ParticleType {particle_type}; - - read_dataset(ww_group, "energy_bounds", wws->energy_bounds_); - - int32_t mesh_id; - read_dataset(ww_group, "mesh", mesh_id); - - if (model::mesh_map.count(mesh_id) == 0) { - fatal_error( - fmt::format("Mesh {} used in weight windows does not exist.", mesh_id)); + // make sure that the upper and lower bounds have the same size + if (upper_ww_.size() != lower_ww_.size()) { + fatal_error("The upper and lower weight window lengths do not match."); } - wws->set_mesh(model::mesh_map[mesh_id]); - wws->lower_ww_ = - tensor::Tensor({static_cast(wws->bounds_size()[0]), - static_cast(wws->bounds_size()[1])}); - wws->upper_ww_ = - tensor::Tensor({static_cast(wws->bounds_size()[0]), - static_cast(wws->bounds_size()[1])}); - - read_dataset(ww_group, "lower_ww_bounds", wws->lower_ww_); - read_dataset(ww_group, "upper_ww_bounds", wws->upper_ww_); - read_dataset(ww_group, "survival_ratio", wws->survival_ratio_); - read_dataset(ww_group, "max_lower_bound_ratio", wws->max_lb_ratio_); - read_dataset(ww_group, "max_split", wws->max_split_); - read_dataset(ww_group, "weight_cutoff", wws->weight_cutoff_); - - close_group(ww_group); - - return wws; -} - -void WeightWindows::set_defaults() -{ - // set energy bounds to the min/max energy supported by the data - if (energy_bounds_.size() == 0) { - int p_type = particle_type_.transport_index(); - if (p_type == C_NONE) { - fatal_error("Weight windows particle is not supported for transport."); - } - energy_bounds_.push_back(data::energy_min[p_type]); - energy_bounds_.push_back(data::energy_max[p_type]); + // num spatial*energy bins must match num weight bins + int num_spatial_bins = this->mesh().n_bins(); + int num_energy_bins = energy_bounds_.size() - 1; + int num_weight_bins = lower_ww_.size(); + if (num_weight_bins != num_spatial_bins * num_energy_bins) { + auto err_msg = + fmt::format("In weight window domain {} the number of spatial " + "energy/spatial bins ({}) does not match the number " + "of weight bins ({})", + id_, num_energy_bins, num_weight_bins); + fatal_error(err_msg); } } -void WeightWindows::allocate_ww_bounds() -{ - auto shape = bounds_size(); - if (shape[0] * shape[1] == 0) { - auto msg = fmt::format( - "Size of weight window bounds is zero for WeightWindows {}", id()); - warning(msg); - } - lower_ww_ = tensor::Tensor( - {static_cast(shape[0]), static_cast(shape[1])}); - lower_ww_.fill(-1); - upper_ww_ = tensor::Tensor( - {static_cast(shape[0]), static_cast(shape[1])}); - upper_ww_.fill(-1); -} - void WeightWindows::set_id(int32_t id) { - assert(id >= 0 || id == C_NONE); + Expects(id >= 0 || id == C_NONE); // Clear entry in mesh map in case one was already assigned if (id_ != C_NONE) { @@ -233,515 +216,56 @@ void WeightWindows::set_id(int32_t id) // Update ID and entry in the mesh map id_ = id; - variance_reduction::ww_map[id] = index_; + variance_reduction::ww_map[id] = + variance_reduction::weight_windows.size() - 1; } -void WeightWindows::set_energy_bounds(span bounds) -{ - energy_bounds_.clear(); - energy_bounds_.insert(energy_bounds_.begin(), bounds.begin(), bounds.end()); - // if the mesh is set, allocate space for weight window bounds - if (mesh_idx_ != C_NONE) - allocate_ww_bounds(); -} - -void WeightWindows::set_particle_type(ParticleType p_type) -{ - if (!p_type.is_neutron() && !p_type.is_photon()) - fatal_error(fmt::format( - "Particle type '{}' cannot be applied to weight windows.", p_type.str())); - particle_type_ = p_type; -} - -void WeightWindows::set_mesh(int32_t mesh_idx) -{ - if (mesh_idx < 0 || mesh_idx >= model::meshes.size()) - fatal_error(fmt::format("Could not find a mesh for index {}", mesh_idx)); - - mesh_idx_ = mesh_idx; - model::meshes[mesh_idx_]->prepare_for_point_location(); - allocate_ww_bounds(); -} - -void WeightWindows::set_mesh(const std::unique_ptr& mesh) -{ - set_mesh(mesh.get()); -} - -void WeightWindows::set_mesh(const Mesh* mesh) -{ - set_mesh(model::mesh_map[mesh->id_]); -} - -std::pair WeightWindows::get_weight_window( - const Particle& p) const +WeightWindow WeightWindows::get_weight_window(const Particle& p) const { // check for particle type if (particle_type_ != p.type()) { - return {false, {}}; + return {}; } + // Get mesh index for particle's position + const auto& mesh = this->mesh(); + int ww_index = mesh.get_bin(p.r()); + + // particle is outside the weight window mesh + if (ww_index < 0) + return {}; + // particle energy double E = p.E(); // check to make sure energy is in range, expects sorted energy values if (E < energy_bounds_.front() || E > energy_bounds_.back()) - return {false, {}}; - - // Get mesh index for particle's position - const auto& mesh = this->mesh(); - int mesh_bin = mesh->get_bin(p.r()); - - // particle is outside the weight window mesh - if (mesh_bin < 0) - return {false, {}}; + return {}; // get the mesh bin in energy group int energy_bin = lower_bound_index(energy_bounds_.begin(), energy_bounds_.end(), E); - // mesh_bin += energy_bin * mesh->n_bins(); + // indices now points to the correct weight for the given energy + ww_index += energy_bin * mesh.n_bins(); + // Create individual weight window WeightWindow ww; - ww.lower_weight = lower_ww_(energy_bin, mesh_bin); - ww.upper_weight = upper_ww_(energy_bin, mesh_bin); + ww.lower_weight = lower_ww_[ww_index]; + ww.upper_weight = upper_ww_[ww_index]; ww.survival_weight = ww.lower_weight * survival_ratio_; ww.max_lb_ratio = max_lb_ratio_; ww.max_split = max_split_; ww.weight_cutoff = weight_cutoff_; - return {true, ww}; -} - -std::array WeightWindows::bounds_size() const -{ - int num_spatial_bins = this->mesh()->n_bins(); - int num_energy_bins = - energy_bounds_.size() > 0 ? energy_bounds_.size() - 1 : 1; - return {num_energy_bins, num_spatial_bins}; -} - -template -void WeightWindows::check_bounds(const T& lower, const T& upper) const -{ - // make sure that the upper and lower bounds have the same size - if (lower.size() != upper.size()) { - auto msg = fmt::format("The upper and lower weight window lengths do not " - "match.\n Lower size: {}\n Upper size: {}", - lower.size(), upper.size()); - fatal_error(msg); - } - this->check_bounds(lower); -} - -template -void WeightWindows::check_bounds(const T& bounds) const -{ - // check that the number of weight window entries is correct - auto dims = this->bounds_size(); - if (bounds.size() != dims[0] * dims[1]) { - auto err_msg = - fmt::format("In weight window domain {} the number of spatial " - "energy/spatial bins ({}) does not match the number " - "of weight bins ({})", - id_, dims, bounds.size()); - fatal_error(err_msg); - } -} - -void WeightWindows::set_bounds(const tensor::Tensor& lower_bounds, - const tensor::Tensor& upper_bounds) -{ - - this->check_bounds(lower_bounds, upper_bounds); - - // set new weight window values - lower_ww_ = lower_bounds; - upper_ww_ = upper_bounds; -} - -void WeightWindows::set_bounds( - const tensor::Tensor& lower_bounds, double ratio) -{ - this->check_bounds(lower_bounds); - - // set new weight window values - lower_ww_ = lower_bounds; - upper_ww_ = lower_bounds; - upper_ww_ *= ratio; -} - -void WeightWindows::set_bounds( - span lower_bounds, span upper_bounds) -{ - check_bounds(lower_bounds, upper_bounds); - auto shape = this->bounds_size(); - lower_ww_ = tensor::Tensor( - {static_cast(shape[0]), static_cast(shape[1])}); - upper_ww_ = tensor::Tensor( - {static_cast(shape[0]), static_cast(shape[1])}); - - // Copy weight window values from input spans into the tensors - std::copy(lower_bounds.data(), lower_bounds.data() + lower_ww_.size(), - lower_ww_.data()); - std::copy(upper_bounds.data(), upper_bounds.data() + upper_ww_.size(), - upper_ww_.data()); -} - -void WeightWindows::set_bounds(span lower_bounds, double ratio) -{ - this->check_bounds(lower_bounds); - - auto shape = this->bounds_size(); - lower_ww_ = tensor::Tensor( - {static_cast(shape[0]), static_cast(shape[1])}); - upper_ww_ = tensor::Tensor( - {static_cast(shape[0]), static_cast(shape[1])}); - - // Copy lower bounds into both arrays, then scale upper by ratio - std::copy(lower_bounds.data(), lower_bounds.data() + lower_ww_.size(), - lower_ww_.data()); - std::copy(lower_bounds.data(), lower_bounds.data() + upper_ww_.size(), - upper_ww_.data()); - upper_ww_ *= ratio; -} - -void WeightWindows::update_weights(const Tally* tally, const std::string& value, - double threshold, double ratio, WeightWindowUpdateMethod method) -{ - /////////////////////////// - // Setup and checks - /////////////////////////// - this->check_tally_update_compatibility(tally); - - // Dimensions of weight window arrays - int e_bins = lower_ww_.shape(0); - int64_t mesh_bins = lower_ww_.shape(1); - - // Initialize weight window arrays to -1.0 by default -#pragma omp parallel for collapse(2) schedule(static) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - lower_ww_(e, m) = -1.0; - upper_ww_(e, m) = -1.0; - } - } - - // determine which value to use - const std::set allowed_values = {"mean", "rel_err"}; - if (allowed_values.count(value) == 0) { - fatal_error(fmt::format("Invalid value '{}' specified for weight window " - "generation. Must be one of: 'mean' or 'rel_err'", - value)); - } - - // determine the index of the specified score - int score_index = tally->score_index("flux"); - if (score_index == C_NONE) { - fatal_error( - fmt::format("A 'flux' score required for weight window generation " - "is not present on tally {}.", - tally->id())); - } - - /////////////////////////// - // Extract tally data - // - // At the end of this section, mean and rel_err are - // 2D tensors of tally data (n_e_groups, n_mesh_bins) - // - /////////////////////////// - - // build a shape for the tally results, this will always be - // dimension 5 (3 filter dimensions, 1 score dimension, 1 results dimension) - // Look for the size of the last dimension of the results tensor - const auto& results = tally->results(); - const int results_dim = static_cast(results.shape(2)); - std::array shape = {1, 1, 1, tally->n_scores(), results_dim}; - - // set the shape for the filters applied on the tally - for (int i = 0; i < tally->filters().size(); i++) { - const auto& filter = model::tally_filters[tally->filters(i)]; - shape[i] = filter->n_bins(); - } - - // build the transpose information to re-order data according to filter type - std::array transpose = {0, 1, 2, 3, 4}; - - // track our filter types and where we've added new ones - std::vector filter_types = tally->filter_types(); - - // assign other filter types to dummy positions if needed - if (!tally->has_filter(FilterType::PARTICLE)) - filter_types.push_back(FilterType::PARTICLE); - - if (!tally->has_filter(FilterType::ENERGY)) - filter_types.push_back(FilterType::ENERGY); - - // particle axis mapping - transpose[0] = - std::find(filter_types.begin(), filter_types.end(), FilterType::PARTICLE) - - filter_types.begin(); - - // energy axis mapping - transpose[1] = - std::find(filter_types.begin(), filter_types.end(), FilterType::ENERGY) - - filter_types.begin(); - - // mesh axis mapping - transpose[2] = - std::find(filter_types.begin(), filter_types.end(), FilterType::MESH) - - filter_types.begin(); - - // determine the index of the particle within its filter - int particle_idx = 0; - if (tally->has_filter(FilterType::PARTICLE)) { - auto pf = tally->get_filter(); - const auto& particles = pf->particles(); - - auto p_it = - std::find(particles.begin(), particles.end(), this->particle_type_); - if (p_it == particles.end()) { - auto msg = fmt::format("Particle type '{}' not present on Filter {} for " - "Tally {} used to update WeightWindows {}", - this->particle_type_.str(), pf->id(), tally->id(), this->id()); - fatal_error(msg); - } - - particle_idx = p_it - particles.begin(); - } - - // The tally results array is 3D: (n_filter_combos, n_scores, n_result_types). - // The first dimension is a row-major flattening of up to 3 filter dimensions - // (particle, energy, mesh) whose storage order depends on which filters the - // tally has. We need to map our desired indices (particle, energy, mesh) - // into the correct flat filter combination index. - // - // transpose[i] tells us which storage position holds dimension i: - // i=0 -> particle, i=1 -> energy, i=2 -> mesh - // shape[j] gives the number of bins for filter storage position j. - - // Row-major strides for the 3 filter dimensions - const int stride0 = shape[1] * shape[2]; - const int stride1 = shape[2]; - - tensor::Tensor sum( - {static_cast(e_bins), static_cast(mesh_bins)}); - tensor::Tensor sum_sq( - {static_cast(e_bins), static_cast(mesh_bins)}); - - const int i_sum = static_cast(TallyResult::SUM); - const int i_sum_sq = static_cast(TallyResult::SUM_SQ); - - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - // Place particle, energy, and mesh indices into their storage positions - std::array idx = {0, 0, 0}; - idx[transpose[0]] = particle_idx; - idx[transpose[1]] = e; - idx[transpose[2]] = static_cast(m); - - // Compute flat filter combination index (row-major over filter dims) - int flat = idx[0] * stride0 + idx[1] * stride1 + idx[2]; - - sum(e, m) = results(flat, score_index, i_sum); - sum_sq(e, m) = results(flat, score_index, i_sum_sq); - } - } - int n = tally->n_realizations_; - - ////////////////////////////////////////////// - // - // Assign new weight windows - // - // Use references to the existing weight window data - // to store and update the values - // - ////////////////////////////////////////////// - - // up to this point the data arrays are views into the tally results (no - // computation has been performed) now we'll switch references to the tally's - // bounds to avoid allocating additional memory - auto& new_bounds = this->lower_ww_; - auto& rel_err = this->upper_ww_; - - // get mesh volumes - auto mesh_vols = this->mesh()->volumes(); - - // Calculate mean (new_bounds) and relative error -#pragma omp parallel for collapse(2) schedule(static) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - // Calculate mean - new_bounds(e, m) = sum(e, m) / n; - // Calculate relative error - if (sum(e, m) > 0.0) { - double mean_val = new_bounds(e, m); - double variance = (sum_sq(e, m) / n - mean_val * mean_val) / (n - 1); - rel_err(e, m) = std::sqrt(variance) / mean_val; - } else { - rel_err(e, m) = INFTY; - } - if (value == "rel_err") { - new_bounds(e, m) = 1.0 / rel_err(e, m); - } - } - } - - // Divide by volume of mesh elements -#pragma omp parallel for collapse(2) schedule(static) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - new_bounds(e, m) /= mesh_vols[m]; - } - } - - if (method == WeightWindowUpdateMethod::MAGIC) { - // For MAGIC, weight windows are proportional to the forward fluxes. - // We normalize weight windows independently for each energy group. - - // Find group maximum and normalize (per energy group) - for (int e = 0; e < e_bins; e++) { - double group_max = 0.0; - - // Find maximum value across all elements in this energy group -#pragma omp parallel for schedule(static) reduction(max : group_max) - for (int64_t m = 0; m < mesh_bins; m++) { - if (new_bounds(e, m) > group_max) { - group_max = new_bounds(e, m); - } - } - - // Normalize values in this energy group by the maximum value - if (group_max > 0.0) { - double norm_factor = 1.0 / (2.0 * group_max); -#pragma omp parallel for schedule(static) - for (int64_t m = 0; m < mesh_bins; m++) { - new_bounds(e, m) *= norm_factor; - } - } - } - } else { - // For (FW-)CADIS, weight windows are inversely proportional to the adjoint - // fluxes. We normalize the weight windows across all energy groups. -#pragma omp parallel for collapse(2) schedule(static) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - // Take the inverse, but are careful not to divide by zero - if (new_bounds(e, m) != 0.0) { - new_bounds(e, m) = 1.0 / new_bounds(e, m); - } else { - new_bounds(e, m) = 0.0; - } - } - } - - // Find the maximum value across all elements - double max_val = 0.0; -#pragma omp parallel for collapse(2) schedule(static) reduction(max : max_val) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - if (new_bounds(e, m) > max_val) { - max_val = new_bounds(e, m); - } - } - } - - // Parallel normalization - if (max_val > 0.0) { - double norm_factor = 1.0 / (2.0 * max_val); -#pragma omp parallel for collapse(2) schedule(static) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - new_bounds(e, m) *= norm_factor; - } - } - } - } - - // Final processing -#pragma omp parallel for collapse(2) schedule(static) - for (int e = 0; e < e_bins; e++) { - for (int64_t m = 0; m < mesh_bins; m++) { - // Values where the mean is zero should be ignored - if (sum(e, m) <= 0.0) { - new_bounds(e, m) = -1.0; - } - // Values where the relative error is higher than the threshold should be - // ignored - else if (rel_err(e, m) > threshold) { - new_bounds(e, m) = -1.0; - } - // Set the upper bounds - upper_ww_(e, m) = ratio * lower_ww_(e, m); - } - } -} - -void WeightWindows::check_tally_update_compatibility(const Tally* tally) -{ - // define the set of allowed filters for the tally - const std::set allowed_filters = { - FilterType::MESH, FilterType::ENERGY, FilterType::PARTICLE}; - - // retrieve a mapping of filter type to filter index for the tally - auto filter_indices = tally->filter_indices(); - - // a mesh filter is required for a tally used to update weight windows - if (!filter_indices.count(FilterType::MESH)) { - fatal_error( - "A mesh filter is required for a tally to update weight window bounds"); - } - - // ensure the mesh filter is using the same mesh as this weight window object - auto mesh_filter = tally->get_filter(); - - // make sure that all of the filters present on the tally are allowed - for (auto filter_pair : filter_indices) { - if (allowed_filters.find(filter_pair.first) == allowed_filters.end()) { - fatal_error(fmt::format("Invalid filter type '{}' found on tally " - "used for weight window generation.", - model::tally_filters[tally->filters(filter_pair.second)]->type_str())); - } - } - - if (mesh_filter->mesh() != mesh_idx_) { - int32_t mesh_filter_id = model::meshes[mesh_filter->mesh()]->id(); - int32_t ww_mesh_id = model::meshes[this->mesh_idx_]->id(); - fatal_error(fmt::format("Mesh filter {} uses a different mesh ({}) than " - "weight window {} mesh ({})", - mesh_filter->id(), mesh_filter_id, id_, ww_mesh_id)); - } - - // if an energy filter exists, make sure the energy grid matches that of this - // weight window object - if (auto energy_filter = tally->get_filter()) { - std::vector filter_bins = energy_filter->bins(); - std::set filter_e_bounds( - energy_filter->bins().begin(), energy_filter->bins().end()); - if (filter_e_bounds.size() != energy_bounds().size()) { - fatal_error( - fmt::format("Energy filter {} does not have the same number of energy " - "bounds ({}) as weight window object {} ({})", - energy_filter->id(), filter_e_bounds.size(), id_, - energy_bounds().size())); - } - - for (auto e : energy_bounds()) { - if (filter_e_bounds.count(e) == 0) { - fatal_error(fmt::format( - "Energy bounds of filter {} and weight windows {} do not match", - energy_filter->id(), id_)); - } - } - } + return ww; } void WeightWindows::to_hdf5(hid_t group) const { - hid_t ww_group = create_group(group, fmt::format("weight_windows_{}", id())); + hid_t ww_group = create_group(group, fmt::format("weight_windows {}", id_)); - write_dataset(ww_group, "mesh", this->mesh()->id()); - write_dataset(ww_group, "particle_type", particle_type_.str()); + write_dataset( + ww_group, "particle_type", openmc::particle_type_to_str(particle_type_)); write_dataset(ww_group, "energy_bounds", energy_bounds_); write_dataset(ww_group, "lower_ww_bounds", lower_ww_); write_dataset(ww_group, "upper_ww_bounds", upper_ww_); @@ -749,655 +273,9 @@ void WeightWindows::to_hdf5(hid_t group) const write_dataset(ww_group, "max_lower_bound_ratio", max_lb_ratio_); write_dataset(ww_group, "max_split", max_split_); write_dataset(ww_group, "weight_cutoff", weight_cutoff_); + write_dataset(ww_group, "mesh", this->mesh().id_); close_group(ww_group); } -WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) -{ - // read information from the XML node - int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); - int32_t mesh_idx = model::mesh_map[mesh_id]; - max_realizations_ = std::stoi(get_node_value(node, "max_realizations")); - - int32_t active_batches = settings::n_batches - settings::n_inactive; - if (max_realizations_ > active_batches) { - auto msg = - fmt::format("The maximum number of specified tally realizations ({}) is " - "greater than the number of active batches ({}).", - max_realizations_, active_batches); - warning(msg); - } - auto tmp_str = get_node_value(node, "particle_type", false, true); - auto particle_type = ParticleType {tmp_str}; - - update_interval_ = std::stoi(get_node_value(node, "update_interval")); - on_the_fly_ = get_node_value_bool(node, "on_the_fly"); - - std::vector e_bounds; - if (check_for_node(node, "energy_bounds")) { - e_bounds = get_node_array(node, "energy_bounds"); - } else { - int p_type = particle_type.transport_index(); - if (p_type == C_NONE) { - fatal_error("Weight windows particle is not supported for transport."); - } - e_bounds.push_back(data::energy_min[p_type]); - e_bounds.push_back(data::energy_max[p_type]); - } - - // set method - std::string method_string = get_node_value(node, "method"); - if (method_string == "magic") { - method_ = WeightWindowUpdateMethod::MAGIC; - if (settings::solver_type == SolverType::RANDOM_RAY && - FlatSourceDomain::adjoint_requested_) { - fatal_error("Random ray weight window generation with MAGIC cannot be " - "done in adjoint mode."); - } - } else if (method_string == "fw_cadis") { - method_ = WeightWindowUpdateMethod::FW_CADIS; - if (settings::solver_type != SolverType::RANDOM_RAY) { - fatal_error("FW-CADIS can only be run in random ray solver mode."); - } - FlatSourceDomain::adjoint_requested_ = true; - if (check_for_node(node, "targets")) { - FlatSourceDomain::fw_cadis_local_ = true; - targets_ = get_node_array(node, "targets"); - FlatSourceDomain::fw_cadis_local_targets_.insert( - std::end(FlatSourceDomain::fw_cadis_local_targets_), - std::begin(targets_), std::end(targets_)); - } - } else { - fatal_error(fmt::format( - "Unknown weight window update method '{}' specified", method_string)); - } - - // parse non-default update parameters if specified - if (check_for_node(node, "update_parameters")) { - pugi::xml_node params_node = node.child("update_parameters"); - if (check_for_node(params_node, "value")) - tally_value_ = get_node_value(params_node, "value"); - if (check_for_node(params_node, "threshold")) - threshold_ = std::stod(get_node_value(params_node, "threshold")); - if (check_for_node(params_node, "ratio")) { - ratio_ = std::stod(get_node_value(params_node, "ratio")); - } - } - - // check update parameter values - if (tally_value_ != "mean" && tally_value_ != "rel_err") { - fatal_error(fmt::format("Unsupported tally value '{}' specified for " - "weight window generation.", - tally_value_)); - } - if (threshold_ <= 0.0) - fatal_error(fmt::format("Invalid relative error threshold '{}' (<= 0.0) " - "specified for weight window generation", - ratio_)); - if (ratio_ <= 1.0) - fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " - "specified for weight window generation", - ratio_)); - - // create a matching weight windows object - auto wws = WeightWindows::create(); - ww_idx_ = wws->index(); - wws->set_mesh(mesh_idx); - if (e_bounds.size() > 0) - wws->set_energy_bounds(e_bounds); - wws->set_particle_type(particle_type); - wws->set_defaults(); -} - -void WeightWindowsGenerator::create_tally() -{ - const auto& wws = variance_reduction::weight_windows[ww_idx_]; - - // create a tally based on the WWG information - Tally* ww_tally = Tally::create(); - tally_idx_ = model::tally_map[ww_tally->id()]; - ww_tally->set_scores({"flux"}); - - int32_t mesh_id = wws->mesh()->id(); - int32_t mesh_idx = model::mesh_map.at(mesh_id); - // see if there's already a mesh filter using this mesh - bool found_mesh_filter = false; - for (const auto& f : model::tally_filters) { - if (f->type() == FilterType::MESH) { - const auto* mesh_filter = dynamic_cast(f.get()); - if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated() && - !mesh_filter->rotated()) { - ww_tally->add_filter(f.get()); - found_mesh_filter = true; - break; - } - } - } - - if (!found_mesh_filter) { - auto mesh_filter = Filter::create("mesh"); - openmc_mesh_filter_set_mesh(mesh_filter->index(), model::mesh_map[mesh_id]); - ww_tally->add_filter(mesh_filter); - } - - const auto& e_bounds = wws->energy_bounds(); - if (e_bounds.size() > 0) { - auto energy_filter = Filter::create("energy"); - openmc_energy_filter_set_bins( - energy_filter->index(), e_bounds.size(), e_bounds.data()); - ww_tally->add_filter(energy_filter); - } - - // add a particle filter - auto particle_type = wws->particle_type(); - auto particle_filter = Filter::create("particle"); - auto pf = dynamic_cast(particle_filter); - pf->set_particles({&particle_type, 1}); - ww_tally->add_filter(particle_filter); -} - -void WeightWindowsGenerator::update() const -{ - const auto& wws = variance_reduction::weight_windows[ww_idx_]; - - Tally* tally = model::tallies[tally_idx_].get(); - - // If in random ray mode, only update on the last batch - if (settings::solver_type == SolverType::RANDOM_RAY) { - if (simulation::current_batch != settings::n_batches) { - return; - } - // If in Monte Carlo mode and beyond the number of max realizations or - // not at the correct update interval, skip the update - } else if (max_realizations_ < tally->n_realizations_ || - tally->n_realizations_ % update_interval_ != 0) { - return; - } - - wws->update_weights(tally, tally_value_, threshold_, ratio_, method_); - - // if we're not doing on the fly generation, reset the tally results once - // we're done with the update - if (!on_the_fly_) - tally->reset(); - - // TODO: deactivate or remove tally once weight window generation is - // complete -} - -//============================================================================== -// Non-member functions -//============================================================================== - -std::pair search_weight_window(const Particle& p) -{ - // TODO: this is a linear search - should do something more clever - for (const auto& ww : variance_reduction::weight_windows) { - auto [ww_found, weight_window] = ww->get_weight_window(p); - if (ww_found) - return {true, weight_window}; - } - return {false, {}}; -} - -void apply_weight_windows(Particle& p) -{ - if (!settings::weight_windows_on) - return; - - // WW on photon and neutron only - if (!p.type().is_neutron() && !p.type().is_photon()) - return; - - // skip dead or no energy - if (p.E() <= 0 || !p.alive()) - return; - - auto [ww_found, ww] = search_weight_window(p); - if (ww_found && ww.is_valid()) { - apply_weight_window(p, ww); - } else { - if (p.wgt_ww_born() == -1.0) - p.wgt_ww_born() = 1.0; - } -} - -void apply_weight_window(Particle& p, WeightWindow weight_window) -{ - if (!weight_window.is_valid()) - return; - - // skip dead or no energy - if (p.E() <= 0 || !p.alive()) - return; - - // If particle has not yet had its birth weight window value set, set it to - // the current weight window. - if (p.wgt_ww_born() == -1.0) - p.wgt_ww_born() = - (weight_window.lower_weight + weight_window.upper_weight) / 2; - - // Normalize weight windows based on particle's starting weight - // and the value of the weight window the particle was born in. - weight_window.scale(p.wgt_born() / p.wgt_ww_born()); - - // get the paramters - double weight = p.wgt(); - - // first check to see if particle should be killed for weight cutoff - if (p.wgt() < weight_window.weight_cutoff) { - p.wgt() = 0.0; - return; - } - - // check if particle is far above current weight window - // only do this if the factor is not already set on the particle and a - // maximum lower bound ratio is specified - if (p.ww_factor() == 0.0 && weight_window.max_lb_ratio > 1.0 && - p.wgt() > weight_window.lower_weight * weight_window.max_lb_ratio) { - p.ww_factor() = - p.wgt() / (weight_window.lower_weight * weight_window.max_lb_ratio); - } - - // move weight window closer to the particle weight if needed - if (p.ww_factor() > 1.0) - weight_window.scale(p.ww_factor()); - - // if particle's weight is above the weight window split until they are within - // the window - if (weight > weight_window.upper_weight) { - // do not further split the particle if above the limit - if (p.n_split() >= settings::max_history_splits) - return; - - double n_split = std::ceil(weight / weight_window.upper_weight); - double max_split = weight_window.max_split; - n_split = std::min(n_split, max_split); - - p.n_split() += n_split; - - // Create secondaries and divide weight among all particles - int i_split = std::round(n_split); - for (int l = 0; l < i_split - 1; l++) { - p.split(weight / n_split); - } - // remaining weight is applied to current particle - p.wgt() = weight / n_split; - - } else if (weight <= weight_window.lower_weight) { - // if the particle weight is below the window, play Russian roulette - double weight_survive = - std::min(weight * weight_window.max_split, weight_window.survival_weight); - russian_roulette(p, weight_survive); - } // else particle is in the window, continue as normal -} - -void free_memory_weight_windows() -{ - variance_reduction::ww_map.clear(); - variance_reduction::weight_windows.clear(); -} - -void finalize_variance_reduction() -{ - for (const auto& wwg : variance_reduction::weight_windows_generators) { - wwg->create_tally(); - } -} - -//============================================================================== -// C API -//============================================================================== - -int verify_ww_index(int32_t index) -{ - if (index < 0 || index >= variance_reduction::weight_windows.size()) { - set_errmsg(fmt::format("Index '{}' for weight windows is invalid", index)); - return OPENMC_E_OUT_OF_BOUNDS; - } - return 0; -} - -extern "C" int openmc_get_weight_windows_index(int32_t id, int32_t* idx) -{ - auto it = variance_reduction::ww_map.find(id); - if (it == variance_reduction::ww_map.end()) { - set_errmsg(fmt::format("No weight windows exist with ID={}", id)); - return OPENMC_E_INVALID_ID; - } - - *idx = it->second; - return 0; -} - -extern "C" int openmc_weight_windows_get_id(int32_t index, int32_t* id) -{ - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows.at(index); - *id = wws->id(); - return 0; -} - -extern "C" int openmc_weight_windows_set_id(int32_t index, int32_t id) -{ - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows.at(index); - wws->set_id(id); - return 0; -} - -extern "C" int openmc_weight_windows_update_magic(int32_t ww_idx, - int32_t tally_idx, const char* value, double threshold, double ratio) -{ - if (int err = verify_ww_index(ww_idx)) - return err; - - if (tally_idx < 0 || tally_idx >= model::tallies.size()) { - set_errmsg(fmt::format("Index '{}' for tally is invalid", tally_idx)); - return OPENMC_E_OUT_OF_BOUNDS; - } - - // get the requested tally - const Tally* tally = model::tallies.at(tally_idx).get(); - - // get the WeightWindows object - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - - wws->update_weights(tally, value, threshold, ratio); - - return 0; -} - -extern "C" int openmc_weight_windows_set_mesh(int32_t ww_idx, int32_t mesh_idx) -{ - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - wws->set_mesh(mesh_idx); - return 0; -} - -extern "C" int openmc_weight_windows_get_mesh(int32_t ww_idx, int32_t* mesh_idx) -{ - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - *mesh_idx = model::mesh_map.at(wws->mesh()->id()); - return 0; -} - -extern "C" int openmc_weight_windows_set_energy_bounds( - int32_t ww_idx, double* e_bounds, size_t e_bounds_size) -{ - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - wws->set_energy_bounds({e_bounds, e_bounds_size}); - return 0; -} - -extern "C" int openmc_weight_windows_get_energy_bounds( - int32_t ww_idx, const double** e_bounds, size_t* e_bounds_size) -{ - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows[ww_idx].get(); - *e_bounds = wws->energy_bounds().data(); - *e_bounds_size = wws->energy_bounds().size(); - return 0; -} - -extern "C" int openmc_weight_windows_set_particle( - int32_t index, int32_t particle) -{ - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows.at(index); - wws->set_particle_type(ParticleType {particle}); - return 0; -} - -extern "C" int openmc_weight_windows_get_particle( - int32_t index, int32_t* particle) -{ - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows.at(index); - *particle = wws->particle_type().pdg_number(); - return 0; -} - -extern "C" int openmc_weight_windows_get_bounds(int32_t index, - const double** lower_bounds, const double** upper_bounds, size_t* size) -{ - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows[index]; - *size = wws->lower_ww_bounds().size(); - *lower_bounds = wws->lower_ww_bounds().data(); - *upper_bounds = wws->upper_ww_bounds().data(); - return 0; -} - -extern "C" int openmc_weight_windows_set_bounds(int32_t index, - const double* lower_bounds, const double* upper_bounds, size_t size) -{ - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows[index]; - wws->set_bounds(span(lower_bounds, size), - span(upper_bounds, size)); - return 0; -} - -extern "C" int openmc_weight_windows_get_survival_ratio( - int32_t index, double* ratio) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - *ratio = wws->survival_ratio(); - return 0; -} - -extern "C" int openmc_weight_windows_set_survival_ratio( - int32_t index, double ratio) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - wws->survival_ratio() = ratio; - std::cout << "Survival ratio: " << wws->survival_ratio() << std::endl; - return 0; -} - -extern "C" int openmc_weight_windows_get_max_lower_bound_ratio( - int32_t index, double* lb_ratio) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - *lb_ratio = wws->max_lower_bound_ratio(); - return 0; -} - -extern "C" int openmc_weight_windows_set_max_lower_bound_ratio( - int32_t index, double lb_ratio) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - wws->max_lower_bound_ratio() = lb_ratio; - return 0; -} - -extern "C" int openmc_weight_windows_get_weight_cutoff( - int32_t index, double* cutoff) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - *cutoff = wws->weight_cutoff(); - return 0; -} - -extern "C" int openmc_weight_windows_set_weight_cutoff( - int32_t index, double cutoff) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - wws->weight_cutoff() = cutoff; - return 0; -} - -extern "C" int openmc_weight_windows_get_max_split( - int32_t index, int* max_split) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - *max_split = wws->max_split(); - return 0; -} - -extern "C" int openmc_weight_windows_set_max_split(int32_t index, int max_split) -{ - if (int err = verify_ww_index(index)) - return err; - const auto& wws = variance_reduction::weight_windows[index]; - wws->max_split() = max_split; - return 0; -} - -extern "C" int openmc_extend_weight_windows( - int32_t n, int32_t* index_start, int32_t* index_end) -{ - if (index_start) - *index_start = variance_reduction::weight_windows.size(); - if (index_end) - *index_end = variance_reduction::weight_windows.size() + n - 1; - for (int i = 0; i < n; ++i) - variance_reduction::weight_windows.push_back(make_unique()); - return 0; -} - -extern "C" size_t openmc_weight_windows_size() -{ - return variance_reduction::weight_windows.size(); -} - -extern "C" int openmc_weight_windows_export(const char* filename) -{ - - if (!mpi::master) - return 0; - - std::string name = filename ? filename : "weight_windows.h5"; - - write_message(fmt::format("Exporting weight windows to {}...", name), 5); - - hid_t ww_file = file_open(name, 'w'); - - // Write file type - write_attribute(ww_file, "filetype", "weight_windows"); - - // Write revisiion number for state point file - write_attribute(ww_file, "version", VERSION_WEIGHT_WINDOWS); - - hid_t weight_windows_group = create_group(ww_file, "weight_windows"); - - hid_t mesh_group = create_group(ww_file, "meshes"); - - std::vector mesh_ids; - std::vector ww_ids; - for (const auto& ww : variance_reduction::weight_windows) { - - ww->to_hdf5(weight_windows_group); - ww_ids.push_back(ww->id()); - - // if the mesh has already been written, move on - int32_t mesh_id = ww->mesh()->id(); - if (std::find(mesh_ids.begin(), mesh_ids.end(), mesh_id) != mesh_ids.end()) - continue; - - mesh_ids.push_back(mesh_id); - ww->mesh()->to_hdf5(mesh_group); - } - - write_attribute(mesh_group, "n_meshes", mesh_ids.size()); - write_attribute(mesh_group, "ids", mesh_ids); - close_group(mesh_group); - - write_attribute(weight_windows_group, "n_weight_windows", ww_ids.size()); - write_attribute(weight_windows_group, "ids", ww_ids); - close_group(weight_windows_group); - - file_close(ww_file); - - return 0; -} - -extern "C" int openmc_weight_windows_import(const char* filename) -{ - std::string name = filename ? filename : "weight_windows.h5"; - - if (mpi::master) - write_message(fmt::format("Importing weight windows from {}...", name), 5); - - if (!file_exists(name)) { - set_errmsg(fmt::format("File '{}' does not exist", name)); - } - - hid_t ww_file = file_open(name, 'r'); - - // Check that filetype is correct - std::string filetype; - read_attribute(ww_file, "filetype", filetype); - if (filetype != "weight_windows") { - file_close(ww_file); - set_errmsg(fmt::format("File '{}' is not a weight windows file.", name)); - return OPENMC_E_INVALID_ARGUMENT; - } - - // Check that the file version is compatible - std::array file_version; - read_attribute(ww_file, "version", file_version); - if (file_version[0] != VERSION_WEIGHT_WINDOWS[0]) { - std::string err_msg = - fmt::format("File '{}' has version {} which is incompatible with the " - "expected version ({}).", - name, file_version, VERSION_WEIGHT_WINDOWS); - set_errmsg(err_msg); - return OPENMC_E_INVALID_ARGUMENT; - } - - hid_t weight_windows_group = open_group(ww_file, "weight_windows"); - - hid_t mesh_group = open_group(ww_file, "meshes"); - - read_meshes(mesh_group); - - std::vector names = group_names(weight_windows_group); - - for (const auto& name : names) { - WeightWindows::from_hdf5(weight_windows_group, name); - } - - close_group(weight_windows_group); - - file_close(ww_file); - - return 0; -} - } // namespace openmc diff --git a/src/wmp.cpp b/src/wmp.cpp index 6f72e1ba4..e9c4fb5e3 100644 --- a/src/wmp.cpp +++ b/src/wmp.cpp @@ -33,22 +33,22 @@ WindowedMultipole::WindowedMultipole(hid_t group) // Read the "data" array. Use its shape to figure out the number of poles // and residue types in this data. read_dataset(group, "data", data_); - int n_residues = data_.shape(1) - 1; + int n_residues = data_.shape()[1] - 1; // Check to see if this data includes fission residues. fissionable_ = (n_residues == 3); // Read the "windows" array and use its shape to figure out the number of // windows. - tensor::Tensor windows; + xt::xtensor windows; read_dataset(group, "windows", windows); - int n_windows = windows.shape(0); + int n_windows = windows.shape()[0]; windows -= 1; // Adjust to 0-based indices // Read the "broaden_poly" arrays. - tensor::Tensor broaden_poly; + xt::xtensor broaden_poly; read_dataset(group, "broaden_poly", broaden_poly); - if (n_windows != broaden_poly.shape(0)) { + if (n_windows != broaden_poly.shape()[0]) { fatal_error("broaden_poly array shape is not consistent with the windows " "array shape in WMP library for " + name_ + "."); @@ -56,12 +56,12 @@ WindowedMultipole::WindowedMultipole(hid_t group) // Read the "curvefit" array. read_dataset(group, "curvefit", curvefit_); - if (n_windows != curvefit_.shape(0)) { + if (n_windows != curvefit_.shape()[0]) { fatal_error("curvefit array shape is not consistent with the windows " "array shape in WMP library for " + name_ + "."); } - fit_order_ = curvefit_.shape(1) - 1; + fit_order_ = curvefit_.shape()[1] - 1; // Check the code is compiling to work with sufficiently high fit order if (fit_order_ + 1 > MAX_POLY_COEFFICIENTS) { diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index 840d3f5b8..cf3b981e5 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -4,7 +4,6 @@ #include "openmc/error.h" #include "openmc/string_utils.h" -#include "openmc/vector.h" namespace openmc { @@ -49,29 +48,4 @@ bool get_node_value_bool(pugi::xml_node node, const char* name) return false; } -vector get_node_position_array( - pugi::xml_node node, const char* name, bool lowercase) -{ - vector coords = get_node_array(node, name, lowercase); - if (coords.size() % 3 != 0) { - fatal_error(fmt::format( - "Incorect number of coordinates in Position array ({}) for \"{}\"", - coords.size(), name)); - } - vector positions; - positions.reserve(coords.size() / 3); - auto it = coords.begin(); - for (size_t i = 0; i < coords.size(); i += 3) { - positions.push_back({coords[i], coords[i + 1], coords[i + 2]}); - } - return positions; -} - -Position get_node_position( - pugi::xml_node node, const char* name, bool lowercase) -{ - vector arr = get_node_array(node, name, lowercase); - return Position(arr); -} - } // namespace openmc diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 33d063a7b..1929f51e6 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -5,7 +5,10 @@ #include #include -#include "openmc/tensor.h" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xindex_view.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xview.hpp" #include "openmc/constants.h" #include "openmc/error.h" @@ -34,32 +37,32 @@ XsData::XsData(bool fissionable, AngleDistributionType scatter_format, } // allocate all [temperature][angle][in group] quantities vector shape {n_ang, n_g_}; - total = tensor::zeros(shape); - absorption = tensor::zeros(shape); - inverse_velocity = tensor::zeros(shape); + total = xt::zeros(shape); + absorption = xt::zeros(shape); + inverse_velocity = xt::zeros(shape); if (fissionable) { - fission = tensor::zeros(shape); - nu_fission = tensor::zeros(shape); - prompt_nu_fission = tensor::zeros(shape); - kappa_fission = tensor::zeros(shape); + fission = xt::zeros(shape); + nu_fission = xt::zeros(shape); + prompt_nu_fission = xt::zeros(shape); + kappa_fission = xt::zeros(shape); } // allocate decay_rate; [temperature][angle][delayed group] shape[1] = n_dg_; - decay_rate = tensor::zeros(shape); + decay_rate = xt::zeros(shape); if (fissionable) { shape = {n_ang, n_dg_, n_g_}; // allocate delayed_nu_fission; [temperature][angle][delay group][in group] - delayed_nu_fission = tensor::zeros(shape); + delayed_nu_fission = xt::zeros(shape); // chi_prompt; [temperature][angle][in group][out group] shape = {n_ang, n_g_, n_g_}; - chi_prompt = tensor::zeros(shape); + chi_prompt = xt::zeros(shape); // chi_delayed; [temperature][angle][delay group][in group][out group] shape = {n_ang, n_dg_, n_g_, n_g_}; - chi_delayed = tensor::zeros(shape); + chi_delayed = xt::zeros(shape); } for (int a = 0; a < n_ang; a++) { @@ -82,30 +85,28 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, { // Reconstruct the dimension information so it doesn't need to be passed size_t n_ang = n_pol * n_azi; - size_t energy_groups = total.shape(1); + size_t energy_groups = total.shape()[1]; // Set the fissionable-specific data if (fissionable) { fission_from_hdf5(xsdata_grp, n_ang, is_isotropic); } // Get the non-fission-specific data - read_nd_tensor(xsdata_grp, "decay-rate", decay_rate); - read_nd_tensor(xsdata_grp, "absorption", absorption, true); - read_nd_tensor(xsdata_grp, "inverse-velocity", inverse_velocity); + read_nd_vector(xsdata_grp, "decay-rate", decay_rate); + read_nd_vector(xsdata_grp, "absorption", absorption, true); + read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); // Get scattering data scatter_from_hdf5( xsdata_grp, n_ang, scatter_format, final_scatter_format, order_data); - // Replace zero absorption values with a small number to avoid - // division by zero in tally methods - for (size_t i = 0; i < absorption.size(); i++) - if (absorption.data()[i] == 0.0) - absorption.data()[i] = 1.e-10; + // Check absorption to ensure it is not 0 since it is often the + // denominator in tally methods + xt::filtration(absorption, xt::equal(absorption, 0.)) = 1.e-10; // Get or calculate the total x/s if (object_exists(xsdata_grp, "total")) { - read_nd_tensor(xsdata_grp, "total", total); + read_nd_vector(xsdata_grp, "total", total); } else { for (size_t a = 0; a < n_ang; a++) { for (size_t gin = 0; gin < energy_groups; gin++) { @@ -114,11 +115,8 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, } } - // Replace zero total cross sections with a small number to avoid - // division by zero in tally methods - for (size_t i = 0; i < total.size(); i++) - if (total.data()[i] == 0.0) - total.data()[i] = 1.e-10; + // Fix if total is 0, since it is in the denominator when tallying + xt::filtration(total, xt::equal(total, 0.)) = 1.e-10; } //============================================================================== @@ -129,30 +127,21 @@ void XsData::fission_vector_beta_from_hdf5( // Data is provided as nu-fission and chi with a beta for delayed info // Get chi - tensor::Tensor temp_chi = tensor::zeros({n_ang, n_g_}); - read_nd_tensor(xsdata_grp, "chi", temp_chi, true); + xt::xtensor temp_chi({n_ang, n_g_}, 0.); + read_nd_vector(xsdata_grp, "chi", temp_chi, true); - // Normalize chi so it sums to 1 over outgoing groups for each angle - for (size_t a = 0; a < n_ang; a++) { - tensor::View row = temp_chi.slice(a); - row /= row.sum(); - } + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); - // Replicate the energy spectrum across all incoming groups — the - // spectrum is independent of the incoming neutron energy - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - chi_prompt.slice(a, gin) = temp_chi.slice(a); - - // Same spectrum for delayed neutrons, replicated across delayed groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t gin = 0; gin < n_g_; gin++) - chi_delayed.slice(a, d, gin) = temp_chi.slice(a); + // Now every incoming group in prompt_chi and delayed_chi is the normalized + // chi we just made + chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); + chi_delayed = + xt::view(temp_chi, xt::all(), xt::newaxis(), xt::newaxis(), xt::all()); // Get nu-fission - tensor::Tensor temp_nufiss = tensor::zeros({n_ang, n_g_}); - read_nd_tensor(xsdata_grp, "nu-fission", temp_nufiss, true); + xt::xtensor temp_nufiss({n_ang, n_g_}, 0.); + read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); // Get beta (strategy will depend upon the number of dimensions in beta) hid_t beta_dset = open_dataset(xsdata_grp, "beta"); @@ -162,39 +151,26 @@ void XsData::fission_vector_beta_from_hdf5( if (!is_isotropic) ndim_target += 2; if (beta_ndims == ndim_target) { - tensor::Tensor temp_beta = tensor::zeros({n_ang, n_dg_}); - read_nd_tensor(xsdata_grp, "beta", temp_beta, true); + xt::xtensor temp_beta({n_ang, n_dg_}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - // prompt_nu_fission = (1 - sum_of_beta) * nu_fission - auto beta_sum = temp_beta.sum(1); - for (size_t a = 0; a < n_ang; a++) - for (size_t g = 0; g < n_g_; g++) - prompt_nu_fission(a, g) = temp_nufiss(a, g) * (1.0 - beta_sum(a)); + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); - // Delayed nu-fission is the outer product of the delayed neutron - // fraction (beta) and the fission production rate (nu-fission) - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t g = 0; g < n_g_; g++) - delayed_nu_fission(a, d, g) = temp_beta(a, d) * temp_nufiss(a, g); + // Set delayed_nu_fission as beta * nu_fission + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } else if (beta_ndims == ndim_target + 1) { - tensor::Tensor temp_beta = - tensor::zeros({n_ang, n_dg_, n_g_}); - read_nd_tensor(xsdata_grp, "beta", temp_beta, true); + xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - // prompt_nu_fission = (1 - sum_of_beta) * nu_fission - // Here beta is energy-dependent, so sum over delayed groups (axis 1) - auto beta_sum = temp_beta.sum(1); - for (size_t a = 0; a < n_ang; a++) - for (size_t g = 0; g < n_g_; g++) - prompt_nu_fission(a, g) = temp_nufiss(a, g) * (1.0 - beta_sum(a, g)); + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); - // Delayed nu-fission: beta is already energy-dependent [n_ang, n_dg, n_g], - // so scale each delayed group's beta by the total nu-fission for that group - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t g = 0; g < n_g_; g++) - delayed_nu_fission(a, d, g) = temp_beta(a, d, g) * temp_nufiss(a, g); + // Set delayed_nu_fission as beta * nu_fission + delayed_nu_fission = + temp_beta * xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } } @@ -203,42 +179,29 @@ void XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Data is provided separately as prompt + delayed nu-fission and chi // Get chi-prompt - tensor::Tensor temp_chi_p = tensor::zeros({n_ang, n_g_}); - read_nd_tensor(xsdata_grp, "chi-prompt", temp_chi_p, true); + xt::xtensor temp_chi_p({n_ang, n_g_}, 0.); + read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); - // Normalize prompt chi so it sums to 1 over outgoing groups for each angle - for (size_t a = 0; a < n_ang; a++) { - tensor::View row = temp_chi_p.slice(a); - row /= row.sum(); - } + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi_p /= xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); // Get chi-delayed - tensor::Tensor temp_chi_d = - tensor::zeros({n_ang, n_dg_, n_g_}); - read_nd_tensor(xsdata_grp, "chi-delayed", temp_chi_d, true); + xt::xtensor temp_chi_d({n_ang, n_dg_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); - // Normalize delayed chi so it sums to 1 over outgoing groups for each - // angle and delayed group - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) { - tensor::View row = temp_chi_d.slice(a, d); - row /= row.sum(); - } + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi_d /= + xt::view(xt::sum(temp_chi_d, {2}), xt::all(), xt::all(), xt::newaxis()); - // Replicate the prompt spectrum across all incoming groups - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - chi_prompt.slice(a, gin) = temp_chi_p.slice(a); - - // Replicate the delayed spectrum across all incoming groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t gin = 0; gin < n_g_; gin++) - chi_delayed.slice(a, d, gin) = temp_chi_d.slice(a, d); + // Now assign the prompt and delayed chis by replicating for each incoming + // group + chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); + chi_delayed = + xt::view(temp_chi_d, xt::all(), xt::all(), xt::newaxis(), xt::all()); // Get prompt and delayed nu-fission directly - read_nd_tensor(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); - read_nd_tensor(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); + read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); } void XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) @@ -247,22 +210,17 @@ void XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Therefore, the code only considers the data as prompt. // Get chi - tensor::Tensor temp_chi = tensor::zeros({n_ang, n_g_}); - read_nd_tensor(xsdata_grp, "chi", temp_chi, true); + xt::xtensor temp_chi({n_ang, n_g_}, 0.); + read_nd_vector(xsdata_grp, "chi", temp_chi, true); - // Normalize chi so it sums to 1 over outgoing groups for each angle - for (size_t a = 0; a < n_ang; a++) { - tensor::View row = temp_chi.slice(a); - row /= row.sum(); - } + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); - // Replicate the energy spectrum across all incoming groups - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - chi_prompt.slice(a, gin) = temp_chi.slice(a); + // Now every incoming group in self.chi is the normalized chi we just made + chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); // Get nu-fission directly - read_nd_tensor(xsdata_grp, "nu-fission", prompt_nu_fission, true); + read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); } //============================================================================== @@ -273,9 +231,8 @@ void XsData::fission_matrix_beta_from_hdf5( // Data is provided as nu-fission and chi with a beta for delayed info // Get nu-fission matrix - tensor::Tensor temp_matrix = - tensor::zeros({n_ang, n_g_, n_g_}); - read_nd_tensor(xsdata_grp, "nu-fission", temp_matrix, true); + xt::xtensor temp_matrix({n_ang, n_g_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // Get beta (strategy will depend upon the number of dimensions in beta) hid_t beta_dset = open_dataset(xsdata_grp, "beta"); @@ -285,92 +242,65 @@ void XsData::fission_matrix_beta_from_hdf5( if (!is_isotropic) ndim_target += 2; if (beta_ndims == ndim_target) { - tensor::Tensor temp_beta = tensor::zeros({n_ang, n_dg_}); - read_nd_tensor(xsdata_grp, "beta", temp_beta, true); + xt::xtensor temp_beta({n_ang, n_dg_}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - auto beta_sum = temp_beta.sum(1); - auto matrix_gout_sum = temp_matrix.sum(2); + xt::xtensor temp_beta_sum({n_ang}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); - // prompt_nu_fission = sum_gout(matrix) * (1 - beta_total) - for (size_t a = 0; a < n_ang; a++) - for (size_t g = 0; g < n_g_; g++) - prompt_nu_fission(a, g) = matrix_gout_sum(a, g) * (1.0 - beta_sum(a)); + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); - // chi_prompt = (1 - beta_total) * nu-fission matrix (unnormalized) - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_prompt(a, gin, gout) = - (1.0 - beta_sum(a)) * temp_matrix(a, gin, gout); + // Store chi-prompt + chi_prompt = + xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), xt::newaxis()) * + temp_matrix; - // Delayed nu-fission is the outer product of the delayed neutron - // fraction (beta) and the total fission rate summed over outgoing groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t g = 0; g < n_g_; g++) - delayed_nu_fission(a, d, g) = temp_beta(a, d) * matrix_gout_sum(a, g); + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); - // chi_delayed = beta * nu-fission matrix, expanded across delayed groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_delayed(a, d, gin, gout) = - temp_beta(a, d) * temp_matrix(a, gin, gout); + // Store chi-delayed + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); } else if (beta_ndims == ndim_target + 1) { - tensor::Tensor temp_beta = - tensor::zeros({n_ang, n_dg_, n_g_}); - read_nd_tensor(xsdata_grp, "beta", temp_beta, true); + xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - auto beta_sum = temp_beta.sum(1); - auto matrix_gout_sum = temp_matrix.sum(2); + xt::xtensor temp_beta_sum({n_ang, n_g_}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); - // prompt_nu_fission = sum_gout(matrix) * (1 - beta_total) - // Here beta is energy-dependent, so beta_sum is 2D [n_ang, n_g] - for (size_t a = 0; a < n_ang; a++) - for (size_t g = 0; g < n_g_; g++) - prompt_nu_fission(a, g) = - matrix_gout_sum(a, g) * (1.0 - beta_sum(a, g)); + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); - // chi_prompt = (1 - beta_sum) * nu-fission matrix (unnormalized) - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_prompt(a, gin, gout) = - (1.0 - beta_sum(a, gin)) * temp_matrix(a, gin, gout); + // Store chi-prompt + chi_prompt = + xt::view(1.0 - temp_beta_sum, xt::all(), xt::all(), xt::newaxis()) * + temp_matrix; - // Delayed nu-fission: beta is energy-dependent [n_ang, n_dg, n_g], - // scale by total fission rate summed over outgoing groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t g = 0; g < n_g_; g++) - delayed_nu_fission(a, d, g) = - temp_beta(a, d, g) * matrix_gout_sum(a, g); + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + delayed_nu_fission = temp_beta * xt::view(xt::sum(temp_matrix, {2}), + xt::all(), xt::newaxis(), xt::all()); - // chi_delayed = beta * nu-fission matrix, expanded across delayed groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_delayed(a, d, gin, gout) = - temp_beta(a, d, gin) * temp_matrix(a, gin, gout); + // Store chi-delayed + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); } - // Normalize chi_prompt so it sums to 1 over outgoing groups - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) { - tensor::View row = chi_prompt.slice(a, gin); - row /= row.sum(); - } + // Normalize both chis + chi_prompt /= + xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); - // Normalize chi_delayed so it sums to 1 over outgoing groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t gin = 0; gin < n_g_; gin++) { - tensor::View row = chi_delayed.slice(a, d, gin); - row /= row.sum(); - } + chi_delayed /= xt::view( + xt::sum(chi_delayed, {3}), xt::all(), xt::all(), xt::all(), xt::newaxis()); } void XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) @@ -378,36 +308,28 @@ void XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Data is provided separately as prompt + delayed nu-fission and chi // Get the prompt nu-fission matrix - tensor::Tensor temp_matrix_p = - tensor::zeros({n_ang, n_g_, n_g_}); - read_nd_tensor(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); + xt::xtensor temp_matrix_p({n_ang, n_g_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); // prompt_nu_fission is the sum over outgoing groups - prompt_nu_fission = temp_matrix_p.sum(2); + prompt_nu_fission = xt::sum(temp_matrix_p, {2}); - // chi_prompt is the nu-fission matrix normalized over outgoing groups - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_prompt(a, gin, gout) = - temp_matrix_p(a, gin, gout) / prompt_nu_fission(a, gin); + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_prompt = temp_matrix_p / + xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); // Get the delayed nu-fission matrix - tensor::Tensor temp_matrix_d = - tensor::zeros({n_ang, n_dg_, n_g_, n_g_}); - read_nd_tensor(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); + xt::xtensor temp_matrix_d({n_ang, n_dg_, n_g_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); // delayed_nu_fission is the sum over outgoing groups - delayed_nu_fission = temp_matrix_d.sum(3); + delayed_nu_fission = xt::sum(temp_matrix_d, {3}); - // chi_delayed is the delayed nu-fission matrix normalized over outgoing - // groups - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg_; d++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_delayed(a, d, gin, gout) = - temp_matrix_d(a, d, gin, gout) / delayed_nu_fission(a, d, gin); + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_delayed = temp_matrix_d / xt::view(delayed_nu_fission, xt::all(), + xt::all(), xt::all(), xt::newaxis()); } void XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) @@ -416,19 +338,16 @@ void XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Therefore, the code only considers the data as prompt. // Get nu-fission matrix - tensor::Tensor temp_matrix = - tensor::zeros({n_ang, n_g_, n_g_}); - read_nd_tensor(xsdata_grp, "nu-fission", temp_matrix, true); + xt::xtensor temp_matrix({n_ang, n_g_, n_g_}, 0.); + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // prompt_nu_fission is the sum over outgoing groups - prompt_nu_fission = temp_matrix.sum(2); + prompt_nu_fission = xt::sum(temp_matrix, {2}); - // chi_prompt is the nu-fission matrix normalized over outgoing groups - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g_; gin++) - for (size_t gout = 0; gout < n_g_; gout++) - chi_prompt(a, gin, gout) = - temp_matrix(a, gin, gout) / prompt_nu_fission(a, gin); + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_prompt = temp_matrix / + xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); } //============================================================================== @@ -437,8 +356,8 @@ void XsData::fission_from_hdf5( hid_t xsdata_grp, size_t n_ang, bool is_isotropic) { // Get the fission and kappa_fission data xs; these are optional - read_nd_tensor(xsdata_grp, "fission", fission); - read_nd_tensor(xsdata_grp, "kappa-fission", kappa_fission); + read_nd_vector(xsdata_grp, "fission", fission); + read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); // Get the data; the strategy for doing so depends on if the data is provided // as a nu-fission matrix or a set of chi and nu-fission vectors @@ -469,7 +388,7 @@ void XsData::fission_from_hdf5( if (n_dg_ == 0) { nu_fission = prompt_nu_fission; } else { - nu_fission = prompt_nu_fission + delayed_nu_fission.sum(1); + nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); } } @@ -485,10 +404,10 @@ void XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - tensor::Tensor gmin = tensor::zeros({n_ang, n_g_}); - read_nd_tensor(scatt_grp, "g_min", gmin, true); - tensor::Tensor gmax = tensor::zeros({n_ang, n_g_}); - read_nd_tensor(scatt_grp, "g_max", gmax, true); + xt::xtensor gmin({n_ang, n_g_}, 0.); + read_nd_vector(scatt_grp, "g_min", gmin, true); + xt::xtensor gmax({n_ang, n_g_}, 0.); + read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library gmin -= 1; @@ -496,11 +415,11 @@ void XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Now use this info to find the length of a vector to hold the flattened // data. - size_t length = order_data * (gmax - gmin + 1).sum(); + size_t length = order_data * xt::sum(gmax - gmin + 1)(); double_4dvec input_scatt(n_ang, double_3dvec(n_g_)); - tensor::Tensor temp_arr = tensor::zeros({length}); - read_nd_tensor(scatt_grp, "scatter_matrix", temp_arr, true); + xt::xtensor temp_arr({length}, 0.); + read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); // Compare the number of orders given with the max order of the problem; // strip off the superfluous orders if needed @@ -532,7 +451,7 @@ void XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, double_3dvec temp_mult(n_ang, double_2dvec(n_g_)); if (object_exists(scatt_grp, "multiplicity_matrix")) { temp_arr.resize({length / order_data}); - read_nd_tensor(scatt_grp, "multiplicity_matrix", temp_arr); + read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data size_t temp_idx = 0; @@ -562,8 +481,8 @@ void XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, final_scatter_format == AngleDistributionType::TABULAR) { for (size_t a = 0; a < n_ang; a++) { ScattDataLegendre legendre_scatt; - tensor::Tensor in_gmin(gmin.slice(a)); - tensor::Tensor in_gmax(gmax.slice(a)); + xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); + xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); legendre_scatt.init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); @@ -577,8 +496,8 @@ void XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // We are sticking with the current representation // Initialize the ScattData object with this data for (size_t a = 0; a < n_ang; a++) { - tensor::Tensor in_gmin(gmin.slice(a)); - tensor::Tensor in_gmax(gmax.slice(a)); + xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); + xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); scatter[a]->init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); } } @@ -600,67 +519,33 @@ void XsData::combine( if (i == 0) { inverse_velocity = that->inverse_velocity; } - if (!that->prompt_nu_fission.empty()) { + if (that->prompt_nu_fission.shape()[0] > 0) { nu_fission += scalar * that->nu_fission; prompt_nu_fission += scalar * that->prompt_nu_fission; kappa_fission += scalar * that->kappa_fission; fission += scalar * that->fission; delayed_nu_fission += scalar * that->delayed_nu_fission; - // Accumulate chi_prompt weighted by total prompt nu-fission - // (summed over energy groups) for this constituent - { - auto pnf_sum = that->prompt_nu_fission.sum(1); - size_t n_ang = chi_prompt.shape(0); - size_t n_g = chi_prompt.shape(1); - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g; gin++) - for (size_t gout = 0; gout < n_g; gout++) - chi_prompt(a, gin, gout) += - scalar * pnf_sum(a) * that->chi_prompt(a, gin, gout); - } - // Accumulate chi_delayed weighted by total delayed nu-fission - // (summed over energy groups) for this constituent - { - auto dnf_sum = that->delayed_nu_fission.sum(2); - size_t n_ang = chi_delayed.shape(0); - size_t n_dg = chi_delayed.shape(1); - size_t n_g = chi_delayed.shape(2); - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg; d++) - for (size_t gin = 0; gin < n_g; gin++) - for (size_t gout = 0; gout < n_g; gout++) - chi_delayed(a, d, gin, gout) += - scalar * dnf_sum(a, d) * that->chi_delayed(a, d, gin, gout); - } + chi_prompt += scalar * + xt::view(xt::sum(that->prompt_nu_fission, {1}), xt::all(), + xt::newaxis(), xt::newaxis()) * + that->chi_prompt; + chi_delayed += scalar * + xt::view(xt::sum(that->delayed_nu_fission, {2}), xt::all(), + xt::all(), xt::newaxis(), xt::newaxis()) * + that->chi_delayed; } decay_rate += scalar * that->decay_rate; } - // Normalize chi_prompt so it sums to 1 over outgoing groups - { - size_t n_ang = chi_prompt.shape(0); - size_t n_g = chi_prompt.shape(1); - for (size_t a = 0; a < n_ang; a++) - for (size_t gin = 0; gin < n_g; gin++) { - tensor::View row = chi_prompt.slice(a, gin); - row /= row.sum(); - } - } - // Normalize chi_delayed so it sums to 1 over outgoing groups - { - size_t n_ang = chi_delayed.shape(0); - size_t n_dg = chi_delayed.shape(1); - size_t n_g = chi_delayed.shape(2); - for (size_t a = 0; a < n_ang; a++) - for (size_t d = 0; d < n_dg; d++) - for (size_t gin = 0; gin < n_g; gin++) { - tensor::View row = chi_delayed.slice(a, d, gin); - row /= row.sum(); - } - } + // Ensure the chi_prompt and chi_delayed are normalized to 1 for each + // azimuthal angle and delayed group (for chi_delayed) + chi_prompt /= + xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); + chi_delayed /= xt::view( + xt::sum(chi_delayed, {3}), xt::all(), xt::all(), xt::all(), xt::newaxis()); // Allow the ScattData object to combine itself - for (size_t a = 0; a < total.shape(0); a++) { + for (size_t a = 0; a < total.shape()[0]; a++) { // Build vector of the scattering objects to incorporate vector those_scatts(those_xs.size()); for (size_t i = 0; i < those_xs.size(); i++) { diff --git a/tests/chain_ni.xml b/tests/chain_ni.xml deleted file mode 100644 index fc96d3d8b..000000000 --- a/tests/chain_ni.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - - 557.6039 640.4896 655.72 678.8113 5847.93 5858.68 6448.81 6450.12 6499.05 6499.18 126000.0 4.281895544855688e-11 8.113092795419058e-12 2.881383486075155e-13 8.900165070824795e-12 6.680021392530635e-10 1.3098276096378766e-09 7.960187308411459e-11 1.5666266690172673e-10 2.8061406316612144e-14 4.106367573258232e-14 1.0245835494664239e-17 - - - 105210.0 231210.0 1.040592667426837e-17 8.004558980206438e-09 - - - 36.67648 65.20168 562.7812 610.8647 5155.619 5764.491 6377.571 2.257651440763611e-08 2.654244519541021e-09 1.1943434358627441e-08 2.0711244046714524e-10 3.863926291321637e-09 9.499586470057554e-10 5.918783030777615e-11 - - - - - - - - - - - - - - - - - - 780.0 6915.0 6930.0 7649.0 142651.0 189000.0 192343.0 334800.0 382000.0 1099245.0 1291590.0 1481700.0 1.0526870077721752e-12 1.0971242349369013e-11 2.1648606887732874e-11 3.9280951004469605e-12 1.8390802445841403e-09 1.622717862868359e-12 5.553301130705051e-09 4.868153588605077e-10 3.245435725736718e-11 1.018706213911803e-07 7.789045741768123e-08 1.0637817101025909e-10 - - - 750.0 6070.0 83569.95 130946.9 134942.1 141725.4 184634.1 191417.4 273599.0 327091.1 333874.4 465943.0 1091536.0 1283881.0 1565200.0 1.4515384373262843e-10 5.994999523918275e-11 1.4063554811525778e-10 2.3619560003972782e-09 2.703447959538686e-11 2.7218387619845277e-12 4.520385317374064e-11 4.498173915871091e-12 8.16767990977074e-08 8.519268780058884e-13 8.275861100628631e-14 9.574035390923319e-08 1.6299297619569002e-11 8.567950315944936e-12 3.245435725736718e-10 - - - - - - 120340.0 177610.0 297900.0 333000.0 349700.0 440500.0 542600.0 561400.0 603300.0 618400.0 657300.0 686000.0 696900.0 748100.0 769400.0 806300.0 925600.0 945400.0 978000.0 984100.0 989200.0 1027420.0 1097800.0 1205070.0 1275000.0 1285700.0 1381400.0 1403900.0 1538800.0 1618900.0 1645950.0 1659300.0 1837200.0 1879400.0 1889000.0 1899300.0 1972700.0 1999800.0 2011600.0 2177100.0 2230800.0 2484400.0 2754400.0 2920000.0 3191000.0 3204200.0 3239100.0 3364900.0 0.00010275887633317896 3.874515009283797e-05 0.00042956579450755135 4.2956579450755134e-06 3.116457724858706e-06 4.21142935791717e-06 1.263428807375151e-06 1.0949716330584643e-06 1.431885981691838e-06 1.802491765188549e-05 4.2956579450755134e-06 7.749030018567594e-06 2.1899432661169287e-06 1.558228862429353e-05 3.116457724858706e-06 3.7060578349671097e-06 6.569829798350785e-06 2.105714678958585e-06 1.431885981691838e-06 1.1792002202168078e-05 1.1792002202168078e-05 0.0008254401541517653 1.3476573945334946e-05 0.000842285871583434 1.1792002202168078e-05 7.159429908459189e-06 7.749030018567594e-06 2.2741718532752718e-06 5.306400990975635e-06 7.075201321300846e-06 0.00013476573945334945 1.4992688514185127e-05 2.6953147890669893e-06 5.053715229500604e-06 3.4533720734920796e-06 1.431885981691838e-06 1.1792002202168076e-06 2.526857614750302e-06 8.507087302992683e-05 4.042972183600483e-06 2.105714678958585e-06 2.3584004404336153e-06 1.4824231339868439e-05 1.3476573945334947e-06 1.6003431560085245e-06 8.422858715834341e-07 1.0949716330584643e-06 8.422858715834341e-07 - - - 613000.0 738800.1 773300.1 786899.9 873600.1 977699.9 1057900.0 1113610.0 1223500.0 1493500.0 1546600.0 1675000.0 1747100.0 1966500.0 2024800.0 2089000.0 2332110.0 2359120.0 2652590.0 2692270.0 2772900.0 2950510.0 3978000.0 7.969724371709087e-07 1.032441566335041e-06 1.1773456458206606e-05 1.5214928345990077e-06 1.267910695499173e-06 2.535821390998346e-05 1.267910695499173e-06 2.1735611922842964e-05 1.3947017650490904e-05 2.227900222091404e-06 2.173561192284297e-06 2.8980815897123955e-05 1.0867805961421485e-06 9.056504967851236e-05 1.7931879836345447e-05 4.709382583282643e-06 0.00014490407948561978 2.4452563413198337e-06 0.0004890512682639667 3.622601987140494e-07 0.0006882943775566939 0.00028980815897123956 9.056504967851236e-05 - - - - - - 619.9594 707.9362 726.02 741.741 6349.85 6362.71 7015.36 7016.95 7070.49 7070.66 510998.9 810759.2 863951.0 1674725.0 5.276288639112756e-10 1.3715809425619083e-10 3.759818598537813e-12 1.1767757246637665e-10 8.777123989590544e-09 1.719716697150835e-08 1.057271626846154e-09 2.0783510382283326e-09 5.201844116739253e-13 7.595270495013994e-13 3.374000922877054e-08 1.1259402850084962e-07 7.768987966558623e-10 5.854889482044179e-10 - - - 632864.1 1496834.0 2307600.0 1.3699223176071195e-09 1.1185811981783752e-07 8.491254034754873e-13 - - - 40.23492 70.00108 628.9213 675.1537 5583.843 6258.984 6938.274 803647.2 809913.1 810759.2 856839.0 863104.9 863951.0 1667613.0 1673879.0 1674725.0 2.3068291731266982e-07 2.4528685530196402e-08 1.3309519902564132e-07 1.9030055102434398e-09 4.481805021434518e-08 1.1035282426757231e-08 6.934054278993223e-10 3.366561452175404e-11 3.231448617974384e-12 4.640000480603615e-13 1.6314869068937087e-13 1.553797593311725e-14 2.2436836794554425e-15 3.3782714575729324e-14 3.2026247731116077e-15 4.614238015862169e-16 - - - - - - - - - - 751.0021 852.3381 876.89 883.6421 7417.82 7435.78 8222.319 8224.59 8287.88 8288.141 347140.0 826100.0 1173228.0 1332492.0 2158570.0 2505692.0 7.0614888325101086e-15 3.3564685966506987e-15 5.761418570090495e-17 2.3600648888691433e-15 1.3290046971181013e-13 2.5954235427719607e-13 1.6253028424014347e-14 3.186921843254948e-14 1.3932264913028456e-17 2.024904561736029e-17 3.125208966828774e-13 3.1668784197198245e-13 4.160694871171375e-09 4.166220240624728e-09 5.000334346926039e-14 8.333890578210064e-17 - - - 47.97734 78.78671 772.594 818.3802 6497.883 7313.626 8133.5 318151.8 1164895.0 1172220.0 1173228.0 1324159.0 1331484.0 1332492.0 1491392.0 2497359.0 2504684.0 2505692.0 2.430147074908485e-12 3.047352927658078e-13 1.6375715794161468e-12 1.653965175572544e-14 5.18885111875044e-13 1.2976030141139345e-13 8.558901456876446e-15 4.161944954758106e-09 6.241042306757062e-13 6.095415902793419e-14 8.94050113917305e-15 4.736991738545178e-13 4.616171159887578e-14 6.779692031857936e-15 5.000334346926038e-12 6.46709908869101e-21 6.3170890582832295e-22 9.678980517533168e-23 - - - - - - 751.028 852.3382 876.89 883.6886 7417.82 7435.78 8222.319 8224.59 8287.88 8288.141 67415.0 841700.0 909200.0 7.866502846971466e-08 3.756939402646081e-08 6.436568219422988e-10 2.637348005677196e-08 1.4671031864629482e-06 2.8654120987125446e-06 1.794509040062992e-07 3.5187803327436886e-07 1.538314140492697e-10 2.235774236842793e-10 9.880497991981766e-05 9.262966867482906e-07 4.219796017408879e-06 - - - 48.00067 78.83981 772.8435 818.5774 6498.158 7313.756 8133.501 59082.2 66406.9 67415.0 413499.9 833367.2 840691.9 841700.0 900867.2 908191.9 909200.0 1255285.0 2.6847340674754763e-05 3.3502043712197297e-06 1.814135374119958e-05 1.8444716489566865e-07 5.715307736044776e-06 1.430796977323619e-06 9.449890224831685e-08 1.2103610040177662e-05 1.246919266677299e-06 1.902588515965013e-07 5.134423559703298e-06 2.917834563257115e-10 2.862256762052218e-11 4.385088515066407e-12 9.241353278125446e-10 9.030363477255e-11 1.3801262380678854e-11 0.00011155702097900803 - - - - - - 1128900.0 1172900.0 1886300.0 1985000.0 2083000.0 2097000.0 2301800.0 2345900.0 3158200.0 3271000.0 3369500.0 3519000.0 4063100.0 0.0008553051126342747 0.006430865508528381 3.2154327542641905e-05 0.00012218644466203924 2.5723462034113525e-05 7.07395205938122e-05 0.0011318323295009952 0.0001028938481364541 6.430865508528381e-05 1.1254014639924668e-05 2.8938894788377717e-05 6.430865508528381e-06 2.5723462034113525e-05 - - - 1251800.0 1796100.0 1945400.0 2044800.0 2059000.0 2156900.0 2255700.0 3013160.0 4142070.0 5315000.0 2.5415396620531326e-05 0.00010782289475376927 2.9266214290308802e-05 9.318978760861486e-05 2.5415396620531326e-05 0.00018483924814931876 3.080654135821979e-05 0.0019870219176051766 0.005221708760218255 1.925408834888737e-05 - - - - - - 931100.0 1346100.0 0.11552453009332422 0.23104906018664845 - - - 5029800.0 5960900.0 7307000.0 0.11552453009332422 0.11552453009332422 2.079441541679836 - - - - - - 683.2094 778.5527 799.73 813.244 6873.16 6888.41 7606.53 7608.44 7666.77 7666.98 127164.0 161860.0 304100.0 379940.0 510998.9 541900.0 673440.0 696000.0 755300.0 906980.0 1046680.0 1224000.0 1279990.0 1350520.0 1377630.0 1603280.0 1730440.0 1757550.0 1897420.0 1919520.0 2133040.0 2730910.0 2804200.0 3177280.0 1.8638833690911883e-08 6.653293496572297e-09 1.4203876186268797e-10 5.409592966721624e-09 3.0832339673226584e-07 6.028687625463321e-07 3.74301586798566e-08 7.349918311628966e-08 2.4690572137876036e-11 3.5966442331457405e-11 9.014158418349326e-07 1.2284000197554473e-09 1.0604892256881559e-10 3.6233381877678664e-09 4.684800934777033e-06 1.9884172981652923e-10 2.6556417693274235e-09 4.860575617737382e-11 2.916345370642429e-10 3.3140288302754875e-09 7.246676375535733e-09 3.402402932416167e-09 5.2140720263001e-10 1.0604892256881559e-10 4.418705107033983e-06 2.1209784513763118e-10 2.827971268501749e-09 3.110768395351924e-07 1.502359736391554e-09 6.628057660550975e-07 1.546546787461894e-09 1.0737453410092578e-09 5.30244612844078e-09 6.009438945566218e-10 - - - 84790.04 154079.8 457929.9 531290.1 1129120.0 1342650.0 1504620.0 1757390.0 1884550.0 1.124957970946228e-09 3.2450710700371965e-09 1.5738594689680403e-08 1.0762819048956704e-09 1.8388736063544118e-09 6.652395693576253e-07 3.0611837094017556e-07 9.194368031772059e-07 3.488451400289987e-06 - - - 43.92123 75.12743 700.3887 749.9867 6033.611 6776.5 7523.621 119455.1 126238.4 127164.0 154151.1 160934.4 161860.0 665731.1 672514.4 673440.0 747591.1 754374.4 755300.0 1216291.0 1223074.0 1224000.0 1369921.0 1376704.0 1377630.0 1749841.0 1756624.0 1757550.0 1889711.0 1896494.0 1897420.0 1911811.0 1918594.0 1919520.0 2125331.0 2132114.0 2133040.0 7.252641897852818e-06 9.885065183674125e-07 4.453862207006767e-06 5.575973168934215e-08 1.3531437967587472e-06 3.3801747364315905e-07 2.1887831296943824e-08 1.739732899248527e-08 1.7397323584033486e-09 2.636641229198142e-10 1.272622225762379e-11 1.2627950688719498e-12 1.9160584871075314e-13 9.58686478614484e-13 9.268187990163621e-14 1.4090839543995835e-14 8.632381215411233e-14 8.34074667834699e-15 1.2155339619769639e-15 3.6814000810433283e-13 3.538499049712814e-14 5.158725716665081e-15 4.21544467211042e-10 4.0607899933642303e-11 2.1687004665322787e-10 1.822910020070542e-11 1.7482517516525527e-12 6.153697369032366e-11 7.181277376570916e-14 6.8808054292926055e-15 3.195035376537882e-13 3.115187100458958e-11 2.9826259472479385e-12 1.482406852545487e-10 6.031532471101388e-14 5.768616813006974e-15 4.833646927113489e-13 - - - - - - - - - - - - 1072500.0 2.890064045563861e-13 - - - 44.06754 75.28693 701.5928 750.7433 6035.851 6777.615 7523.68 6.689278658453111e-13 8.913674252402247e-14 4.1657845563004787e-13 5.378516121164032e-15 1.2583954438026756e-13 3.16650156158609e-14 2.0701132819599697e-15 - - - 683.3271 778.5529 799.73 813.5109 6873.16 6888.41 7606.53 7608.44 7666.77 7666.98 510998.9 1.7758787515451584e-15 6.581346326607483e-16 1.368589539770362e-17 5.248596182059754e-16 2.920762305855841e-14 5.711006429349971e-14 3.5457762265416177e-15 6.962612245690403e-15 2.338949640535961e-18 3.4071167337635547e-18 2.1386473937172572e-19 - - - - - - - - - - - - - - - - - - - - - - - - - - - - 66945.0 2.1704054025041888e-10 - - - - - - - - - - - - 820.0389 927.6652 951.42 959.5527 7984.67 8005.709 8862.7 8865.34 8933.11 8933.4 366270.0 507900.0 609500.0 770600.0 852700.0 954500.0 1115530.0 1481840.0 1623420.0 1724920.0 6.930967733828076e-11 4.4848940639261224e-11 6.225110448569713e-13 3.0091057755445835e-11 1.4120610720530457e-09 2.7533685191404717e-09 1.7112326402414573e-10 3.3482649978514024e-10 1.9318959861680173e-13 2.7929997279698636e-13 3.6755804457910027e-06 2.2374667416695354e-07 1.181887674027053e-07 7.92135402897521e-08 7.398075516810562e-08 1.3533064969775417e-09 1.1800832653644161e-05 1.804408662636722e-05 3.807302278163484e-07 3.0494506398560603e-07 - - - 56.92597 90.91714 855.942 897.216 6991.356 7880.445 8773.007 357291.1 365173.4 366270.0 412919.9 498921.1 506803.4 507900.0 514460.0 600521.1 608403.4 609500.0 656069.9 761621.1 769503.4 770600.0 1022350.0 1106551.0 1114434.0 1115530.0 1472861.0 1480743.0 1481840.0 1614441.0 1622324.0 1623420.0 1715941.0 1723824.0 1724920.0 2137900.0 2.167548391930537e-08 2.8616659297729836e-09 1.5876524466163717e-08 5.919283450210211e-11 4.8238674145478966e-09 1.1910611683428657e-09 8.251524863747208e-11 6.6528004309537836e-09 6.652800430953784e-10 9.941708721258623e-11 4.2452174979371803e-07 1.968970885650002e-10 1.9600207433178643e-11 2.840463936760989e-12 6.807646077773136e-07 6.748578656939676e-11 6.701302996997783e-12 9.996408692926368e-13 2.172327512457944e-05 2.732867560693677e-11 2.7011821751739386e-12 4.0351373644973695e-13 7.786723266486576e-06 1.953037934211798e-09 1.9247158318161006e-10 3.950919133474779e-11 1.818843931937816e-09 1.7899733933356285e-10 1.4705028396157966e-09 3.076300301948419e-11 3.022997962967563e-12 4.574485034565062e-11 2.213900812679635e-11 2.1742581302894385e-12 5.0020380532292804e-11 4.589424322094249e-05 - - - diff --git a/tests/chain_simple.xml b/tests/chain_simple.xml index 4e08995a8..c2e50a370 100644 --- a/tests/chain_simple.xml +++ b/tests/chain_simple.xml @@ -1,18 +1,12 @@ - + - - 3696.125 4095.822 4477.27 5097.122 29452.1 29781.3 33566.5 33629.4 33865.1 33878.5 34395.3 34408.0 34486.2 34488.2 112780.0 113150.0 162650.0 165740.0 184490.0 197190.0 220502.0 229720.0 247500.0 254740.0 264260.0 288451.0 290270.0 304910.0 305830.0 326000.0 333600.0 342520.0 361850.0 403030.0 414830.0 417633.0 429930.0 433741.0 451630.0 530800.0 546557.0 575970.0 588280.0 616900.0 649850.0 656090.0 679220.0 684600.0 690130.0 707920.0 785480.0 795500.0 797710.0 807200.0 836804.0 960290.0 961430.0 971960.0 972620.0 995090.0 1038760.0 1096860.0 1101580.0 1124000.0 1131511.0 1151510.0 1159900.0 1169040.0 1225600.0 1240470.0 1254800.0 1260409.0 1315770.0 1334800.0 1343660.0 1367890.0 1441800.0 1448350.0 1457560.0 1502790.0 1521990.0 1543700.0 1566410.0 1678027.0 1706459.0 1791196.0 1830690.0 1845300.0 1927300.0 1948490.0 2045880.0 2112400.0 2151500.0 2189400.0 2255457.0 2408650.0 2466070.0 2477100.0 9.714352819815078e-10 7.460941651551526e-09 6.047882056201745e-09 8.510389107205747e-10 3.7979729633684727e-08 7.033747061198817e-08 6.602815946851458e-09 1.2800909198245071e-08 6.513060244589454e-11 8.894667887850525e-11 1.3843783302275766e-09 2.700005498135763e-09 1.2141115256573815e-11 1.654893875618862e-11 3.7007705885806645e-09 2.0186021392258173e-09 2.859686363903241e-09 9.16781804898392e-09 6.896890642354875e-09 9.588360161322631e-09 5.130613770532286e-07 7.06510748729036e-08 8.410842246774237e-09 6.7286737974193905e-09 5.3829390379355124e-08 9.083709626516178e-07 8.915492781580693e-08 9.251926471451662e-09 2.783988783682273e-08 6.728673797419391e-10 1.093409492080651e-08 2.5232526740322717e-10 5.467047460403255e-08 6.812782219887132e-08 8.83138435911295e-08 1.0345335963532313e-06 8.915492781580693e-08 1.623292553627428e-07 9.251926471451663e-08 9.251926471451662e-09 2.0942997194467853e-06 3.784879011048407e-08 1.513951604419363e-08 1.093409492080651e-08 1.337323917237104e-07 2.186818984161302e-08 1.5980600268871052e-08 6.7286737974193905e-09 3.784879011048407e-08 1.9344937167580748e-07 4.457746390790346e-08 6.7286737974193905e-09 5.0465053480645434e-08 1.3457347594838781e-08 1.9597262434983976e-06 1.0093010696129087e-08 4.289529545854862e-08 2.607361096500014e-07 3.53255374364518e-07 4.541854813258089e-08 2.329803302356464e-06 2.607361096500014e-08 4.7100716581935733e-07 1.059766123093554e-06 6.6193328482113254e-06 4.205421123387119e-10 3.027903208838726e-08 2.565306885266143e-07 1.2616263370161358e-08 2.649415307733885e-07 3.3643368987096953e-09 8.410842246774237e-06 1.934493716758075e-08 9.251926471451662e-09 2.2709274066290446e-08 1.7830985563161385e-07 5.046505348064544e-09 9.251926471451663e-08 2.5400743585258203e-06 3.154065842540339e-07 1.093409492080651e-08 7.569758022096815e-09 3.784879011048407e-07 2.8008104681758214e-06 1.2027504412887161e-06 2.26251656438227e-06 1.6989901338483962e-07 1.6821684493548476e-09 8.663167514177466e-08 1.8503852942903323e-08 2.5568960430193683e-07 2.0186021392258175e-08 6.560456952483906e-09 3.784879011048407e-09 1.7999202408096872e-07 2.800810468175822e-07 2.1027105616935597e-08 4.205421123387119e-10 - - + - - 0.0 10000.0 20000.0 50000.0 100000.0 200000.0 300000.0 400000.0 600000.0 800000.0 1000000.0 1220000.0 1.1612176249914943e-11 0.0 3.1976524142990123e-11 0.0 6.418466676129901e-13 1.894551923065874e-10 5.099949011192198e-13 3.170644340540729e-13 2.756798470867507e-12 6.67627508515641e-14 3.711746246444946e-15 0.0 - @@ -34,9 +28,6 @@ - - 3065.349 12960.11 13197.49 16125.43 19185.05 19590.0 31600.0 34700.0 41400.0 41960.0 51220.0 54100.0 54250.0 64350.0 72700.0 75020.0 76198.0 90330.0 93795.0 96090.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109160.0 109395.0 109433.0 115450.0 120350.0 136550.0 140760.0 142400.0 143760.0 150930.0 163330.0 173300.0 182610.0 185715.0 194940.0 198900.0 202110.0 205311.0 215280.0 221380.0 228780.0 233500.0 240870.0 246840.0 266450.0 275129.0 275430.0 281420.0 282920.0 289560.0 291650.0 301700.0 317100.0 343500.0 345900.0 356030.0 387820.0 410290.0 428710.0 448400.0 1.4211820389290126e-18 3.695705148646686e-18 4.752472005970374e-19 4.0825252294602915e-18 8.998127221991115e-19 1.9035285506819052e-21 5.305446177665699e-21 1.1547147563154756e-20 9.362552078233586e-21 1.86835843588509e-20 1.0610892355331398e-20 2.736290732002608e-22 4.776811520523089e-21 3.977552295559136e-21 3.432935762018982e-20 1.872510415646717e-20 2.4966805541956234e-21 1.0265454754703584e-18 1.7575878976520235e-18 2.839974130397521e-20 2.1057468800839102e-19 4.1342252420362975e-19 7.098565272539688e-21 8.20050332279016e-21 5.276915360632628e-20 1.0602918581811435e-19 4.806110066826575e-19 2.0521431485853304e-21 2.375669880669523e-21 9.362552078233586e-21 8.267152210184412e-21 3.745020831293435e-21 6.865871524037964e-20 1.5604253463722645e-21 3.420452359248004e-18 2.4966805541956232e-20 1.5853921519142206e-18 1.8725104156467174e-21 1.0610892355331397e-19 1.7851265962498703e-17 1.966135936429053e-19 1.3107572909527022e-20 3.370518748164091e-19 1.5635461970650089e-18 9.050467008959134e-21 3.745020831293434e-20 2.18459548492117e-21 9.050467008959134e-21 2.3406380195583967e-20 1.6540508671546e-20 1.8725104156467174e-21 1.622842360227155e-20 2.18459548492117e-21 1.8725104156467174e-21 1.8725104156467174e-21 2.18459548492117e-21 1.2483402770978116e-20 1.5604253463722645e-21 3.120850692744529e-22 9.362552078233587e-22 1.2483402770978116e-20 1.5604253463722645e-21 1.2483402770978116e-20 9.362552078233587e-22 3.120850692744529e-22 3.120850692744529e-22 - 2.53000e-02 @@ -47,9 +38,6 @@ - - 3061.32 12959.8 13440.07 16150.05 19148.83 49550.0 90330.0 93795.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109395.0 109433.0 113500.0 5.3130501476983077e-20 1.4936931167066328e-19 1.943509007980312e-20 1.8224649880365157e-19 4.0452400597373603e-20 3.146222282132249e-21 3.300026341588747e-23 5.444173877278485e-23 6.3486292118621375e-24 1.2400176384733938e-23 2.124537722121886e-25 2.4542156071495764e-25 1.5792541400719878e-24 3.1731991718126067e-24 6.141568457919309e-26 7.109808533300877e-26 5.014291762148272e-22 - 2.53000e-02 diff --git a/tests/chain_simple_decay.xml b/tests/chain_simple_decay.xml deleted file mode 100644 index 1c8c5e4ee..000000000 --- a/tests/chain_simple_decay.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - 3696.125 4095.822 4477.27 5097.122 29452.1 29781.3 33566.5 33629.4 33865.1 33878.5 34395.3 34408.0 34486.2 34488.2 112780.0 113150.0 162650.0 165740.0 184490.0 197190.0 220502.0 229720.0 247500.0 254740.0 264260.0 288451.0 290270.0 304910.0 305830.0 326000.0 333600.0 342520.0 361850.0 403030.0 414830.0 417633.0 429930.0 433741.0 451630.0 530800.0 546557.0 575970.0 588280.0 616900.0 649850.0 656090.0 679220.0 684600.0 690130.0 707920.0 785480.0 795500.0 797710.0 807200.0 836804.0 960290.0 961430.0 971960.0 972620.0 995090.0 1038760.0 1096860.0 1101580.0 1124000.0 1131511.0 1151510.0 1159900.0 1169040.0 1225600.0 1240470.0 1254800.0 1260409.0 1315770.0 1334800.0 1343660.0 1367890.0 1441800.0 1448350.0 1457560.0 1502790.0 1521990.0 1543700.0 1566410.0 1678027.0 1706459.0 1791196.0 1830690.0 1845300.0 1927300.0 1948490.0 2045880.0 2112400.0 2151500.0 2189400.0 2255457.0 2408650.0 2466070.0 2477100.0 9.714352819815078e-10 7.460941651551526e-09 6.047882056201745e-09 8.510389107205747e-10 3.7979729633684727e-08 7.033747061198817e-08 6.602815946851458e-09 1.2800909198245071e-08 6.513060244589454e-11 8.894667887850525e-11 1.3843783302275766e-09 2.700005498135763e-09 1.2141115256573815e-11 1.654893875618862e-11 3.7007705885806645e-09 2.0186021392258173e-09 2.859686363903241e-09 9.16781804898392e-09 6.896890642354875e-09 9.588360161322631e-09 5.130613770532286e-07 7.06510748729036e-08 8.410842246774237e-09 6.7286737974193905e-09 5.3829390379355124e-08 9.083709626516178e-07 8.915492781580693e-08 9.251926471451662e-09 2.783988783682273e-08 6.728673797419391e-10 1.093409492080651e-08 2.5232526740322717e-10 5.467047460403255e-08 6.812782219887132e-08 8.83138435911295e-08 1.0345335963532313e-06 8.915492781580693e-08 1.623292553627428e-07 9.251926471451663e-08 9.251926471451662e-09 2.0942997194467853e-06 3.784879011048407e-08 1.513951604419363e-08 1.093409492080651e-08 1.337323917237104e-07 2.186818984161302e-08 1.5980600268871052e-08 6.7286737974193905e-09 3.784879011048407e-08 1.9344937167580748e-07 4.457746390790346e-08 6.7286737974193905e-09 5.0465053480645434e-08 1.3457347594838781e-08 1.9597262434983976e-06 1.0093010696129087e-08 4.289529545854862e-08 2.607361096500014e-07 3.53255374364518e-07 4.541854813258089e-08 2.329803302356464e-06 2.607361096500014e-08 4.7100716581935733e-07 1.059766123093554e-06 6.6193328482113254e-06 4.205421123387119e-10 3.027903208838726e-08 2.565306885266143e-07 1.2616263370161358e-08 2.649415307733885e-07 3.3643368987096953e-09 8.410842246774237e-06 1.934493716758075e-08 9.251926471451662e-09 2.2709274066290446e-08 1.7830985563161385e-07 5.046505348064544e-09 9.251926471451663e-08 2.5400743585258203e-06 3.154065842540339e-07 1.093409492080651e-08 7.569758022096815e-09 3.784879011048407e-07 2.8008104681758214e-06 1.2027504412887161e-06 2.26251656438227e-06 1.6989901338483962e-07 1.6821684493548476e-09 8.663167514177466e-08 1.8503852942903323e-08 2.5568960430193683e-07 2.0186021392258175e-08 6.560456952483906e-09 3.784879011048407e-09 1.7999202408096872e-07 2.800810468175822e-07 2.1027105616935597e-08 4.205421123387119e-10 - - - - - - 0.0 10000.0 20000.0 50000.0 100000.0 200000.0 300000.0 400000.0 600000.0 800000.0 1000000.0 1220000.0 1.1612176249914943e-11 0.0 3.1976524142990123e-11 0.0 6.418466676129901e-13 1.894551923065874e-10 5.099949011192198e-13 3.170644340540729e-13 2.756798470867507e-12 6.67627508515641e-14 3.711746246444946e-15 0.0 - - - - - - - - - - - - - - - - - - - - 2.53000e-02 - - Gd157 Gd156 I135 Xe135 Xe136 Cs135 - 1.093250e-04 2.087260e-04 2.780820e-02 6.759540e-03 2.392300e-02 4.356330e-05 - - - - - - - 3065.349 12960.11 13197.49 16125.43 19185.05 19590.0 31600.0 34700.0 41400.0 41960.0 51220.0 54100.0 54250.0 64350.0 72700.0 75020.0 76198.0 90330.0 93795.0 96090.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109160.0 109395.0 109433.0 115450.0 120350.0 136550.0 140760.0 142400.0 143760.0 150930.0 163330.0 173300.0 182610.0 185715.0 194940.0 198900.0 202110.0 205311.0 215280.0 221380.0 228780.0 233500.0 240870.0 246840.0 266450.0 275129.0 275430.0 281420.0 282920.0 289560.0 291650.0 301700.0 317100.0 343500.0 345900.0 356030.0 387820.0 410290.0 428710.0 448400.0 1.4211820389290126e-18 3.695705148646686e-18 4.752472005970374e-19 4.0825252294602915e-18 8.998127221991115e-19 1.9035285506819052e-21 5.305446177665699e-21 1.1547147563154756e-20 9.362552078233586e-21 1.86835843588509e-20 1.0610892355331398e-20 2.736290732002608e-22 4.776811520523089e-21 3.977552295559136e-21 3.432935762018982e-20 1.872510415646717e-20 2.4966805541956234e-21 1.0265454754703584e-18 1.7575878976520235e-18 2.839974130397521e-20 2.1057468800839102e-19 4.1342252420362975e-19 7.098565272539688e-21 8.20050332279016e-21 5.276915360632628e-20 1.0602918581811435e-19 4.806110066826575e-19 2.0521431485853304e-21 2.375669880669523e-21 9.362552078233586e-21 8.267152210184412e-21 3.745020831293435e-21 6.865871524037964e-20 1.5604253463722645e-21 3.420452359248004e-18 2.4966805541956232e-20 1.5853921519142206e-18 1.8725104156467174e-21 1.0610892355331397e-19 1.7851265962498703e-17 1.966135936429053e-19 1.3107572909527022e-20 3.370518748164091e-19 1.5635461970650089e-18 9.050467008959134e-21 3.745020831293434e-20 2.18459548492117e-21 9.050467008959134e-21 2.3406380195583967e-20 1.6540508671546e-20 1.8725104156467174e-21 1.622842360227155e-20 2.18459548492117e-21 1.8725104156467174e-21 1.8725104156467174e-21 2.18459548492117e-21 1.2483402770978116e-20 1.5604253463722645e-21 3.120850692744529e-22 9.362552078233587e-22 1.2483402770978116e-20 1.5604253463722645e-21 1.2483402770978116e-20 9.362552078233587e-22 3.120850692744529e-22 3.120850692744529e-22 - - - 2.53000e-02 - - Gd157 Gd156 I135 Xe135 Xe136 Cs135 - 6.142710e-5 1.483250e-04 0.0292737 0.002566345 0.0219242 4.9097e-6 - - - - - - - 3061.32 12959.8 13440.07 16150.05 19148.83 49550.0 90330.0 93795.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109395.0 109433.0 113500.0 5.3130501476983077e-20 1.4936931167066328e-19 1.943509007980312e-20 1.8224649880365157e-19 4.0452400597373603e-20 3.146222282132249e-21 3.300026341588747e-23 5.444173877278485e-23 6.3486292118621375e-24 1.2400176384733938e-23 2.124537722121886e-25 2.4542156071495764e-25 1.5792541400719878e-24 3.1731991718126067e-24 6.141568457919309e-26 7.109808533300877e-26 5.014291762148272e-22 - - - 2.53000e-02 - - Gd157 Gd156 I135 Xe135 Xe136 Cs135 - 4.141120e-04 7.605360e-04 0.0135457 0.00026864 0.0024432 3.7100E-07 - - - - diff --git a/tests/conftest.py b/tests/conftest.py index 8dda9f756..639d669f3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,51 +1,7 @@ -import os -import hashlib import pytest -import openmc -import openmc.lib from tests.regression_tests import config as regression_config -# MD5 hash of the official NNDC HDF5 cross_sections.xml file. -# Generated via: md5sum /path/to/nndc_hdf5/cross_sections.xml -_NNDC_XS_MD5 = "2d00773012eda670bc9f95d96a31c989" - -# Collected during pytest_configure, displayed at start and end of session -_environment_warnings = [] - - -def _check_build_environment(): - """Check STRICT_FP and cross section data, collecting any warnings.""" - if not openmc.lib._strict_fp_enabled(): - _environment_warnings.append( - "OpenMC was NOT built with -DOPENMC_ENABLE_STRICT_FP=on. " - "Regression test results may not match reference values due to " - "compiler floating-point optimizations. Rebuild with " - "-DOPENMC_ENABLE_STRICT_FP=on for reproducible results." - ) - - xs_path = os.environ.get("OPENMC_CROSS_SECTIONS") - if not xs_path: - _environment_warnings.append( - "OPENMC_CROSS_SECTIONS environment variable is not set. " - "Regression tests require the NNDC HDF5 cross section data." - ) - elif not os.path.isfile(xs_path): - _environment_warnings.append( - f"OPENMC_CROSS_SECTIONS ({xs_path}) is not a valid file path. " - "Regression tests require the NNDC HDF5 cross section data." - ) - else: - with open(xs_path, "rb") as f: - md5 = hashlib.md5(f.read()).hexdigest() - if md5 != _NNDC_XS_MD5: - _environment_warnings.append( - f"OPENMC_CROSS_SECTIONS ({xs_path}) does not match the " - "official NNDC HDF5 dataset. Regression tests expect the " - "NNDC data; results may differ with other cross section " - "libraries." - ) - def pytest_addoption(parser): parser.addoption('--exe') @@ -63,28 +19,6 @@ def pytest_configure(config): if config.getoption(opt) is not None: regression_config[opt] = config.getoption(opt) - _check_build_environment() - - -def _print_environment_warnings(terminalreporter): - """Print environment warnings as a visible section.""" - if _environment_warnings: - terminalreporter.section("OpenMC Environment Warnings") - for msg in _environment_warnings: - terminalreporter.line(f"WARNING: {msg}", yellow=True) - terminalreporter.line("") - - -def pytest_sessionstart(session): - """Print environment warnings at the start of the test session.""" - _print_environment_warnings(session.config.pluginmanager.get_plugin( - "terminalreporter")) - - -def pytest_terminal_summary(terminalreporter, exitstatus, config): - """Reprint environment warnings at the end so they aren't missed.""" - _print_environment_warnings(terminalreporter) - @pytest.fixture def run_in_tmpdir(tmpdir): @@ -93,29 +27,3 @@ def run_in_tmpdir(tmpdir): yield finally: orig.chdir() - -@pytest.fixture(scope="module") -def endf_data(): - return os.environ['OPENMC_ENDF_DATA'] - -@pytest.fixture(scope='session', autouse=True) -def resolve_paths(): - with openmc.config.patch('resolve_paths', False): - yield - - -@pytest.fixture(scope='session', autouse=True) -def disable_depletion_multiprocessing_under_mpi(): - """Fork-based depletion multiprocessing may deadlock if MPI is active.""" - if not regression_config['mpi']: - yield - return - - from openmc.deplete import pool - - original_setting = pool.USE_MULTIPROCESSING - pool.USE_MULTIPROCESSING = False - try: - yield - finally: - pool.USE_MULTIPROCESSING = original_setting diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt deleted file mode 100644 index 3eb88f023..000000000 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(TEST_NAMES - test_distribution - test_file_utils - test_tally - test_interpolate - test_math - test_mcpl_stat_sum - test_mesh - test_ray - test_region - test_tensor - # Add additional unit test files here -) - -foreach(test ${TEST_NAMES}) - add_executable(${test} ${test}.cpp) - target_link_libraries(${test} Catch2::Catch2WithMain libopenmc) - add_test(NAME ${test} COMMAND ${test} WORKING_DIRECTORY ${UNIT_TEST_BIN_OUTPUT_DIR}) -endforeach() diff --git a/tests/cpp_unit_tests/test_distribution.cpp b/tests/cpp_unit_tests/test_distribution.cpp deleted file mode 100644 index 479e7c8a7..000000000 --- a/tests/cpp_unit_tests/test_distribution.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "openmc/distribution.h" -#include "openmc/distribution_spatial.h" -#include "openmc/position.h" -#include "openmc/random_lcg.h" -#include -#include -#include -#include - -TEST_CASE("Test alias method sampling of a discrete distribution") -{ - constexpr int n_samples = 1000000; - double x[5] = {-1.6, 1.1, 20.3, 4.7, 0.9}; - double p[5] = {0.2, 0.1, 0.65, 0.02, 0.03}; - - // Initialize distribution - openmc::Discrete dist(x, p, 5); - uint64_t seed = openmc::init_seed(0, 0); - - // Calculate expected distribution mean - double mean = 0.0; - for (size_t i = 0; i < 5; i++) { - mean += x[i] * p[i]; - } - - // Sample distribution and calculate mean, standard deviation, and number of - // x[0] sampled - double dist_mean = 0.0; - double std = 0.0; - int counter = 0; - - for (size_t i = 0; i < n_samples; i++) { - auto sample = dist.sample(&seed).first; - std += sample * sample / n_samples; - dist_mean += sample; - - if (sample == x[0]) - counter++; - } - - dist_mean /= n_samples; - std -= dist_mean * dist_mean; - - // Require sampled distribution mean is within 4 standard deviations of the - // expected mean - REQUIRE(std::abs(dist_mean - mean) < 4 * std); - - // Require counter of number of x[0] is within the 95% confidence interval - // assuming a Poisson distribution of 200,000 - REQUIRE(std::abs((double)counter / n_samples - p[0]) < - 1.96 * std::sqrt(p[0] / n_samples)); -} - -TEST_CASE("Test alias sampling method for pugixml constructor") -{ - // XML doc node for Discrete contructor - pugi::xml_document doc; - pugi::xml_node energy = doc.append_child("energy"); - pugi::xml_node parameters = energy.append_child("parameters"); - parameters.append_child(pugi::node_pcdata) - .set_value("800 500000 30000 0.1 0.6 0.3"); - - // Initialize discrete distribution and seed - openmc::Discrete dist(energy); - uint64_t seed = openmc::init_seed(0, 0); - auto sample = dist.sample(&seed).first; - - // Assertions - REQUIRE(dist.x().size() == 3); - REQUIRE(dist.prob().size() == 3); - REQUIRE(dist.alias().size() == 3); - - openmc::vector correct_x = {800, 500000, 30000}; - openmc::vector correct_prob = {0.3, 1.0, 0.9}; - openmc::vector correct_alias = {1, 0, 1}; - - for (size_t i = 0; i < 3; i++) { - REQUIRE(dist.x()[i] == correct_x[i]); - REQUIRE_THAT( - dist.prob()[i], Catch::Matchers::WithinAbs(correct_prob[i], 1e-12)); - REQUIRE(dist.alias()[i] == correct_alias[i]); - } -} - -TEST_CASE("Test sampling a large linear-linear tabular distribution") -{ - constexpr int n_points = 10001; - constexpr int n_samples = 200000; - openmc::vector x(n_points); - openmc::vector p(n_points); - for (int i = 0; i < n_points; ++i) { - x[i] = static_cast(i) / (n_points - 1); - p[i] = 2.0 * x[i]; - } - - openmc::Tabular dist( - x.data(), p.data(), n_points, openmc::Interpolation::lin_lin); - uint64_t seed = openmc::init_seed(0, 0); - - double mean = 0.0; - for (int i = 0; i < n_samples; ++i) { - mean += dist.sample(&seed).first; - } - mean /= n_samples; - - // The normalized PDF is 2x on [0, 1], which has a mean of 2/3. - REQUIRE_THAT(mean, Catch::Matchers::WithinAbs(2.0 / 3.0, 0.003)); -} - -TEST_CASE("Test construction of SpatialBox with parameters") -{ - openmc::Position ll {-1, -2, -3}; - openmc::Position ur {30, 15, 5}; - openmc::SpatialBox box(ll, ur); - - REQUIRE(box.lower_left() == openmc::Position {-1, -2, -3}); - REQUIRE(box.upper_right() == openmc::Position {30, 15, 5}); - REQUIRE_FALSE(box.only_fissionable()); -} - -TEST_CASE("Test Normal distribution") -{ - // Test untruncated normal distribution - openmc::Normal normal_unbounded(0.0, 1.0); - - // Check PDF at mean (should be 1/sqrt(2*pi) ≈ 0.3989) - REQUIRE_THAT( - normal_unbounded.evaluate(0.0), Catch::Matchers::WithinRel(0.3989, 0.001)); - - // Check that it's not truncated - REQUIRE_FALSE(normal_unbounded.is_truncated()); - - // Check accessors - REQUIRE(normal_unbounded.mean_value() == 0.0); - REQUIRE(normal_unbounded.std_dev() == 1.0); - REQUIRE(normal_unbounded.lower() == -openmc::INFTY); - REQUIRE(normal_unbounded.upper() == openmc::INFTY); -} - -TEST_CASE("Test truncated Normal distribution") -{ - // Create a truncated normal: mean=0, std=1, bounds=[-1, 1] - openmc::Normal normal_truncated(0.0, 1.0, -1.0, 1.0); - - // Check that it's truncated - REQUIRE(normal_truncated.is_truncated()); - - // Check accessors - REQUIRE(normal_truncated.lower() == -1.0); - REQUIRE(normal_truncated.upper() == 1.0); - - // PDF should be zero outside bounds - REQUIRE(normal_truncated.evaluate(-2.0) == 0.0); - REQUIRE(normal_truncated.evaluate(2.0) == 0.0); - - // PDF inside bounds should be higher than untruncated (due to - // renormalization) - openmc::Normal normal_unbounded(0.0, 1.0); - REQUIRE(normal_truncated.evaluate(0.0) > normal_unbounded.evaluate(0.0)); - - // The truncated PDF at mean should be approximately 0.3989 / 0.6827 ≈ 0.584 - // (0.6827 is the probability mass of N(0,1) in [-1,1]) - REQUIRE_THAT( - normal_truncated.evaluate(0.0), Catch::Matchers::WithinRel(0.584, 0.01)); -} - -TEST_CASE("Test truncated Normal sampling") -{ - constexpr int n_samples = 10000; - openmc::Normal normal_truncated(0.0, 1.0, -1.0, 1.0); - uint64_t seed = openmc::init_seed(0, 0); - - // Sample and verify all samples are within bounds - for (int i = 0; i < n_samples; ++i) { - auto [x, w] = normal_truncated.sample(&seed); - REQUIRE(x >= -1.0); - REQUIRE(x <= 1.0); - REQUIRE(w == 1.0); // Unbiased sampling should have weight 1 - } -} - -TEST_CASE("Test one-sided truncated Normal") -{ - // Test lower-bounded only (positive half-normal) - openmc::Normal lower_bounded(0.0, 1.0, 0.0, openmc::INFTY); - REQUIRE(lower_bounded.is_truncated()); - REQUIRE(lower_bounded.evaluate(-1.0) == 0.0); - REQUIRE(lower_bounded.evaluate(1.0) > 0.0); - - // PDF at 0 should be approximately 2 * 0.3989 ≈ 0.798 (half-normal) - REQUIRE_THAT( - lower_bounded.evaluate(0.0), Catch::Matchers::WithinRel(0.798, 0.01)); - - // Test upper-bounded only - openmc::Normal upper_bounded(0.0, 1.0, -openmc::INFTY, 0.0); - REQUIRE(upper_bounded.is_truncated()); - REQUIRE(upper_bounded.evaluate(1.0) == 0.0); - REQUIRE(upper_bounded.evaluate(-1.0) > 0.0); -} - -TEST_CASE("Test Normal XML constructor with truncation") -{ - // XML doc node for truncated Normal - pugi::xml_document doc; - pugi::xml_node energy = doc.append_child("energy"); - energy.append_child("type") - .append_child(pugi::node_pcdata) - .set_value("normal"); - energy.append_child("parameters") - .append_child(pugi::node_pcdata) - .set_value("1.0e6 1.0e5 0.8e6 1.2e6"); - - openmc::Normal dist(energy); - REQUIRE(dist.mean_value() == 1.0e6); - REQUIRE(dist.std_dev() == 1.0e5); - REQUIRE(dist.lower() == 0.8e6); - REQUIRE(dist.upper() == 1.2e6); - REQUIRE(dist.is_truncated()); -} diff --git a/tests/cpp_unit_tests/test_file_utils.cpp b/tests/cpp_unit_tests/test_file_utils.cpp deleted file mode 100644 index 8b0d99d76..000000000 --- a/tests/cpp_unit_tests/test_file_utils.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "openmc/file_utils.h" -#include - -using namespace openmc; - -TEST_CASE("Test get_file_extension") -{ - REQUIRE(get_file_extension("rememberthealamo.png") == "png"); - REQUIRE(get_file_extension("statepoint.20.h5") == "h5"); - REQUIRE(get_file_extension("wEiRDNaa_ame.h4") == "h4"); - REQUIRE(get_file_extension("has_directory/asdf.20.h5") == "h5"); - REQUIRE(get_file_extension("wasssssup_lol") == ""); - REQUIRE(get_file_extension("has_directory/secret_file") == ""); - REQUIRE(get_file_extension("lovely.dir/extensionless_file") == ""); - REQUIRE(get_file_extension("lovely.dir/statepoint.20.h5") == "h5"); - REQUIRE(get_file_extension("lovely.dir/asdf123.cpp") == "cpp"); -} - -TEST_CASE("Test dir_exists") -{ - // not sure how to test this when running on windows? - REQUIRE(dir_exists("/")); - - // if this exists on your system... you deserve for this test to fail - REQUIRE(!dir_exists("/asdfa/asdfasdf/asdgasodgosuihasjkgh/")); -} - -TEST_CASE("Test file_exists") -{ - // Note: not clear how to portably test where a file should exist. - REQUIRE(!file_exists("./should_not_exist/really_do_not_make_this_please")); -} - -TEST_CASE("Test dir_name") -{ - REQUIRE(dir_name("") == ""); - REQUIRE(dir_name("/") == "/"); - REQUIRE(dir_name("hello") == ""); - REQUIRE(dir_name("hello/world") == "hello"); - REQUIRE(dir_name("/path/to/dir/") == "/path/to/dir"); -} diff --git a/tests/cpp_unit_tests/test_interpolate.cpp b/tests/cpp_unit_tests/test_interpolate.cpp deleted file mode 100644 index 4f19f2b63..000000000 --- a/tests/cpp_unit_tests/test_interpolate.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -#include -#include - -#include "openmc/interpolate.h" -#include "openmc/search.h" - -using namespace openmc; - -TEST_CASE("Test Lagranian Interpolation") -{ - std::vector xs {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - std::vector ys {0.0, 1.0, 1.0, 2.0, 3.0, 3.0, 5.0}; - - // ensure we get data points back at the x values - for (int n = 1; n <= 6; n++) { - for (int i = 0; i < xs.size(); i++) { - double x = xs[i]; - double y = ys[i]; - - size_t idx = lower_bound_index(xs.begin(), xs.end(), x); - idx = std::min(idx, xs.size() - n - 1); - double out = interpolate_lagrangian(xs, ys, idx, x, n); - REQUIRE(out == y); - } - } - - // spot checks based on an independent implementation of Lagrangian - // interpolation - std::map>> checks; - checks[1] = {{0.5, 0.5}, {4.5, 3.0}, {2.5, 1.5}, {5.5, 4.0}}; - checks[2] = {{2.5, 1.5}, {4.5, 2.75}, {4.9999, 3.0}, {4.00001, 3.0}}; - checks[3] = {{2.5592, 1.5}, {4.5, 2.9375}, {4.9999, 3.0}, {4.00001, 3.0}}; - - for (auto check_set : checks) { - int order = check_set.first; - auto checks = check_set.second; - - for (auto check : checks) { - double input = check.first; - double exp_output = check.second; - - size_t idx = lower_bound_index(xs.begin(), xs.end(), input); - idx = std::min(idx, xs.size() - order - 1); - double out = interpolate_lagrangian(xs, ys, idx, input, order); - REQUIRE_THAT(out, Catch::Matchers::WithinAbs(exp_output, 1e-04)); - } - } -} \ No newline at end of file diff --git a/tests/cpp_unit_tests/test_math.cpp b/tests/cpp_unit_tests/test_math.cpp deleted file mode 100644 index 7467aa1fe..000000000 --- a/tests/cpp_unit_tests/test_math.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#include -#include - -#include -#include -#include - -#include "openmc/math_functions.h" -#include "openmc/random_dist.h" -#include "openmc/random_lcg.h" -#include "openmc/wmp.h" - -TEST_CASE("Test t_percentile") -{ - // The reference solutions come from scipy.stats.t.ppf - std::vector> ref_ts { - {-15.894544844102773, -0.32491969623407446, 0.000000000000000, - 0.32491969623407446, 15.894544844102759}, - {-4.848732214442601, -0.2886751346880066, 0.000000000000000, - 0.2886751346880066, 4.848732214442598}, - {-2.756508521909475, -0.2671808657039658, 0.000000000000000, - 0.2671808657039658, 2.7565085219094745}}; - - // Permutations include 1 DoF, 2 DoF, and > 2 DoF - // We will test 5 p-values at 3-DoF values - std::vector test_ps {0.02, 0.4, 0.5, 0.6, 0.98}; - std::vector test_dfs {1, 2, 5}; - - for (int i = 0; i < test_dfs.size(); i++) { - int df = test_dfs[i]; - - std::vector test_ts; - - for (double p : test_ps) { - double test_t = openmc::t_percentile(p, df); - test_ts.push_back(test_t); - } - - // The 5 DoF approximation in openmc.lib.math.t_percentile is off by up to - // 8e-3 from the scipy solution, so test that one separately with looser - // tolerance - double tolerance = (df > 2) ? 1e-2 : 1e-6; - - REQUIRE_THAT( - ref_ts[i], Catch::Matchers::Approx(test_ts).epsilon(tolerance)); - } -} - -TEST_CASE("Test cylindrical Bessel functions") -{ - constexpr double x = 2.0; - constexpr double expected[] {0.22389077914123567, 0.57672480775687339, - 0.35283402861563773, 0.12894324947440205}; - - for (int n = 0; n < 4; ++n) { - REQUIRE_THAT(openmc::cyl_bessel_j(n, x), - Catch::Matchers::WithinRel(expected[n], 1.0e-14)); - REQUIRE_THAT(openmc::cyl_bessel_j(n, -x), - Catch::Matchers::WithinRel( - (n % 2 == 0 ? 1.0 : -1.0) * expected[n], 1.0e-14)); - } -} - -TEST_CASE("Test calc_pn") -{ - // The reference solutions come from scipy.special.eval_legendre - std::vector> ref_vals { - {1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1}, - {1, -0.5, -0.125, 0.4375, -0.289062, -0.0898438, 0.323242, -0.223145, - -0.0736389, 0.267899, -0.188229}, - {1, 0, -0.5, -0, 0.375, 0, -0.3125, -0, 0.273438, 0, -0.246094}, - {1, 0.5, -0.125, -0.4375, -0.289062, 0.0898438, 0.323242, 0.223145, - -0.0736389, -0.267899, -0.188229}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; - - int max_order = 10; - std::vector test_xs = {-1.0, -0.5, 0.0, 0.5, 1.0}; - - std::vector> test_vals; - for (double x : test_xs) { - std::vector test_val(max_order + 1); - openmc::calc_pn_c(max_order, x, test_val.data()); - test_vals.push_back(test_val); - } - - for (int i = 0; i < ref_vals.size(); i++) { - REQUIRE_THAT(ref_vals[i], Catch::Matchers::Approx(test_vals[i])); - } -} - -TEST_CASE("Test evaluate_legendre") -{ - // The reference solutions come from numpy.polynomial.legendre.legval - std::vector ref_vals { - 5.5, -0.45597649, -1.35351562, -2.7730999, 60.5}; - - int max_order = 10; - std::vector test_xs = {-1.0, -0.5, 0.0, 0.5, 1.0}; - - // Set the coefficients back to 1s for the test values since - // evaluate legendre incorporates the (2l+1)/2 term on its own - std::vector test_coeffs(max_order + 1, 1.0); - - std::vector test_vals; - for (double x : test_xs) { - test_vals.push_back( - openmc::evaluate_legendre(test_coeffs.size() - 1, test_coeffs.data(), x)); - } - - REQUIRE_THAT(ref_vals, Catch::Matchers::Approx(test_vals)); -} - -TEST_CASE("Test calc_rn") -{ - std::vector ref_vals {1.000000000000000, -0.019833838076210, - 0.980066577841242, -0.197676811654084, 0.006790834062088, - -0.033668438114859, 0.940795745502164, -0.335561350977312, - 0.033500236162691, -0.001831975566765, 0.014882082223994, - -0.046185860057145, 0.883359726009014, -0.460318044571973, - 0.073415616482180, -0.005922278973373, 0.000448625292461, - -0.004750335422039, 0.025089695062177, -0.057224052171859, - 0.809468042300133, -0.570331780454957, 0.123771351522967, - -0.015356543011155, 0.001061098599927, -0.000104097571795, - 0.001319047965347, -0.009263463267120, 0.037043163155191, - -0.066518621473934, 0.721310852552881, -0.662967447756079, - 0.182739660926192, -0.029946258412359, 0.003119841820746, - -0.000190549327031, 0.000023320052630, -0.000338370521658, - 0.002878809439524, -0.015562587450914, 0.050271226423217, - -0.073829294593737, 0.621486505922182, -0.735830327235834, - 0.247995745731425, -0.050309614442385, 0.006809024629381, - -0.000619383085285, 0.000034086826414, -0.000005093626712, - 0.000082405610567, -0.000809532012556, 0.005358034016708, - -0.023740240859138, 0.064242405926477, -0.078969918083157, - 0.512915839160049, -0.787065093668736, 0.316917738015632, - -0.076745744765114, 0.012672942183651, -0.001481838409317, - 0.000120451946983, -0.000006047366709, 0.000001091052697, - -0.000019334294214, 0.000213051604838, -0.001640234119608, - 0.008982263900105, -0.033788039035668, 0.078388909900756, - -0.081820779415058, 0.398746190829636, -0.815478614863816, - 0.386704633068855, -0.109227544713261, 0.021245051959237, - -0.003002428416676, 0.000311416667310, -0.000022954482885, - 0.000001059646310, -0.000000230023931, 0.000004408854505, - -0.000053457925526, 0.000464152759861, -0.002976305522860, - 0.013958017448970, -0.045594791382625, 0.092128969315914, - -0.082334538374971, 0.282248459574595, -0.820599067736528, - 0.454486474163594, -0.147395565311743, 0.033013815809602, - -0.005448090715661, 0.000678450207914, -0.000063467485444, - 0.000004281943868, -0.000000182535754, 0.000000047847775, - -0.000000982664801, 0.000012933320414, -0.000124076425457, - 0.000901739739837, -0.004982323311961, 0.020457776068931, - -0.058948376674391, 0.104888993733747, -0.080538298991650, - 0.166710763818175, -0.802696588503912, 0.517433650833039, - -0.190564076304612, 0.048387190622376, -0.009120081648146, - 0.001318069323039, -0.000147308722683, 0.000012561029621, - -0.000000779794781, 0.000000030722703}; - - int max_order = 10; - - double azi = 0.1; // Longitude - double pol = 0.2; // Latitude - double mu = std::cos(pol); - - std::vector test_uvw {std::sin(pol) * std::cos(azi), - std::sin(pol) * std::sin(azi), std::cos(pol)}; - - std::vector test_vals((max_order + 1) * (max_order + 1), 0); - openmc::calc_rn_c(max_order, test_uvw.data(), test_vals.data()); - - REQUIRE_THAT(ref_vals, Catch::Matchers::Approx(test_vals)); -} - -TEST_CASE("Test calc_zn") -{ - std::vector ref_vals {1.00000000e+00, 2.39712769e-01, 4.38791281e-01, - 2.10367746e-01, -5.00000000e-01, 1.35075576e-01, 1.24686873e-01, - -2.99640962e-01, -5.48489101e-01, 8.84215021e-03, 5.68310892e-02, - -4.20735492e-01, -1.25000000e-01, -2.70151153e-01, -2.60091773e-02, - 1.87022545e-02, -3.42888902e-01, 1.49820481e-01, 2.74244551e-01, - -2.43159131e-02, -2.50357380e-02, 2.20500013e-03, -1.98908812e-01, - 4.07587508e-01, 4.37500000e-01, 2.61708929e-01, 9.10321205e-02, - -1.54686328e-02, -2.74049397e-03, -7.94845816e-02, 4.75368705e-01, - 7.11647284e-02, 1.30266162e-01, 3.37106977e-02, 1.06401886e-01, - -7.31606787e-03, -2.95625975e-03, -1.10250006e-02, 3.55194307e-01, - -1.44627826e-01, -2.89062500e-01, -9.28644588e-02, -1.62557358e-01, - 7.73431638e-02, -2.55329539e-03, -1.90923851e-03, 1.57578403e-02, - 1.72995854e-01, -3.66267690e-01, -1.81657333e-01, -3.32521518e-01, - -2.59738162e-02, -2.31580576e-01, 4.20673902e-02, -4.11710546e-04, - -9.36449487e-04, 1.92156884e-02, 2.82515641e-02, -3.90713738e-01, - -1.69280296e-01, -8.98437500e-02, -1.08693628e-01, 1.78813094e-01, - -1.98191857e-01, 1.65964201e-02, 2.77013853e-04}; - - int n = 10; - double rho = 0.5; - double phi = 0.5; - - int nums = ((n + 1) * (n + 2)) / 2; - - std::vector test_vals(nums, 0); - openmc::calc_zn(n, rho, phi, test_vals.data()); - - REQUIRE_THAT(ref_vals, Catch::Matchers::Approx(test_vals)); -} - -TEST_CASE("Test calc_zn_rad") -{ - std::vector ref_vals {1.00000000e+00, -5.00000000e-01, - -1.25000000e-01, 4.37500000e-01, -2.89062500e-01, -8.98437500e-02}; - - int n = 10; - double rho = 0.5; - - int nums = n / 2 + 1; - std::vector test_vals(nums, 0); - openmc::calc_zn_rad(n, rho, test_vals.data()); - - REQUIRE_THAT(ref_vals, Catch::Matchers::Approx(test_vals)); -} - -TEST_CASE("Test rotate_angle") -{ - std::vector uvw0 {1.0, 0.0, 0.0}; - double phi = 0.0; - - uint64_t prn_seed = 1; - openmc::prn(&prn_seed); - - SECTION("Test rotate_angle mu is 0") - { - std::vector ref_uvw {0.0, 0.0, -1.0}; - - double mu = 0.0; - - std::vector test_uvw(uvw0); - openmc::rotate_angle_c(test_uvw.data(), mu, &phi, &prn_seed); - - REQUIRE_THAT(ref_uvw, Catch::Matchers::Approx(test_uvw)); - } - - SECTION("Test rotate_angle mu is 1") - { - std::vector ref_uvw = {1.0, 0.0, 0.0}; - - double mu = 1.0; - - std::vector test_uvw(uvw0); - openmc::rotate_angle_c(test_uvw.data(), mu, &phi, &prn_seed); - - REQUIRE_THAT(ref_uvw, Catch::Matchers::Approx(test_uvw)); - } - - // Now to test phi is None - SECTION("Test rotate_angle no phi") - { - // When seed = 1, phi will be sampled as 1.9116495709698769 - // The resultant reference is from hand-calculations given the above - std::vector ref_uvw = { - 0.9, -0.422746750548505, 0.10623175090659095}; - - double mu = 0.9; - prn_seed = 1; - - std::vector test_uvw(uvw0); - openmc::rotate_angle_c(test_uvw.data(), mu, NULL, &prn_seed); - - REQUIRE_THAT(ref_uvw, Catch::Matchers::Approx(test_uvw)); - } -} - -TEST_CASE("Test maxwell_spectrum") -{ - double ref_val = 0.27767406743161277; - - double T = 0.5; - uint64_t prn_seed = 1; - - double test_val = openmc::maxwell_spectrum(T, &prn_seed); - - REQUIRE(ref_val == test_val); -} - -TEST_CASE("Test watt_spectrum") -{ - double ref_val = 0.30957476387766697; - - double a = 0.5; - double b = 0.75; - uint64_t prn_seed = 1; - - double test_val = openmc::watt_spectrum(a, b, &prn_seed); - - REQUIRE(ref_val == test_val); -} - -TEST_CASE("Test normal_variate") -{ - - // Generate a series of normally distributed random numbers and test - // whether their mean and standard deviation are close to the expected value - SECTION("Test with non-zero standard deviation") - { - uint64_t seed = 1; - - double mean = 0.0; - double standard_deviation = 1.0; - - int num_samples = 10000; - double sum = 0.0; - double sum_squared_difference = 0.0; - - for (int i = 0; i < num_samples; ++i) { - double sample = openmc::normal_variate(mean, standard_deviation, &seed); - sum += sample; - sum_squared_difference += (sample - mean) * (sample - mean); - } - - double actual_mean = sum / num_samples; - double actual_standard_deviation = - std::sqrt(sum_squared_difference / num_samples); - - REQUIRE_THAT(mean, Catch::Matchers::WithinAbs(actual_mean, 0.1)); - REQUIRE_THAT(standard_deviation, - Catch::Matchers::WithinAbs(actual_standard_deviation, 0.1)); - } - - // When the standard deviation is zero - // the generated random number should always be equal to the mean - SECTION("Test with zero standard deviation") - { - uint64_t seed = 1; - double mean = 5.0; - double standard_deviation = 0.0; - - for (int i = 0; i < 10; ++i) { - double sample = openmc::normal_variate(mean, standard_deviation, &seed); - REQUIRE(sample == mean); - } - } -} - -TEST_CASE("Test broaden_wmp_polynomials") -{ - double test_E = 0.5; - int n = 6; - - // Two branches of the code to worry about, beta > 6 and otherwise - // beta = sqrtE * dopp - SECTION("Test broaden_wmp_polynomials beta > 6") - { - std::vector ref_val { - 2., 1.41421356, 1.0001, 0.70731891, 0.50030001, 0.353907}; - - double test_dopp = 100.0; // approximately U235 at room temperature - - std::vector test_val(n, 0); - openmc::broaden_wmp_polynomials(test_E, test_dopp, n, test_val.data()); - - REQUIRE_THAT(ref_val, Catch::Matchers::Approx(test_val)); - } - - SECTION("Test broaden_wmp_polynomials beta < 6") - { - std::vector ref_val = { - 1.99999885, 1.41421356, 1.04, 0.79195959, 0.6224, 0.50346003}; - - double test_dopp = 5.0; - - std::vector test_val(n, 0); - openmc::broaden_wmp_polynomials(test_E, test_dopp, n, test_val.data()); - - REQUIRE_THAT(ref_val, Catch::Matchers::Approx(test_val)); - } -} - -TEST_CASE("Test isclose") -{ - using openmc::isclose; - - // Identical values are always close, regardless of tolerances. - REQUIRE(isclose(1.0, 1.0, 0.0, 0.0)); - REQUIRE(isclose(0.0, 0.0, 0.0, 0.0)); - - // Absolute tolerance governs comparisons near zero. - REQUIRE(isclose(0.0, 1e-15, 0.0, 1e-14)); - REQUIRE_FALSE(isclose(0.0, 1e-13, 0.0, 1e-14)); - - // Relative tolerance scales with the magnitude of the operands. - REQUIRE(isclose(1.0e12, 1.0e12 + 1.0, 1e-12, 0.0)); - REQUIRE_FALSE(isclose(1.0e12, 1.0e12 + 10.0, 1e-12, 0.0)); - - // The looser of the two tolerances wins. - REQUIRE(isclose(1.0, 1.0 + 1e-13, 0.0, 1e-12)); - REQUIRE(isclose(1.0e6, 1.0e6 + 1e-4, 1e-9, 0.0)); -} diff --git a/tests/cpp_unit_tests/test_mcpl_stat_sum.cpp b/tests/cpp_unit_tests/test_mcpl_stat_sum.cpp deleted file mode 100644 index d0c26f26c..000000000 --- a/tests/cpp_unit_tests/test_mcpl_stat_sum.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include -#include - -#include "openmc/bank.h" -#include "openmc/mcpl_interface.h" - -// Test the MCPL stat:sum functionality (issue #3514) -TEST_CASE("MCPL stat:sum field") -{ - // Check if MCPL interface is available - if (!openmc::is_mcpl_interface_available()) { - SKIP("MCPL library not available"); - } - - SECTION("stat:sum field is written to MCPL files") - { - // Create a temporary filename - std::string filename = "test_stat_sum.mcpl"; - - // Create some test particles - std::vector source_bank(100); - std::vector bank_index = {0, 100}; // 100 particles total - - // Initialize test particles - for (int i = 0; i < 100; ++i) { - source_bank[i].particle = openmc::ParticleType::neutron(); - source_bank[i].r = {i * 0.1, i * 0.2, i * 0.3}; - source_bank[i].u = {0.0, 0.0, 1.0}; - source_bank[i].E = 2.0e6; // 2 MeV - source_bank[i].time = 0.0; - source_bank[i].wgt = 1.0; - } - - // Write the MCPL file - openmc::write_mcpl_source_point(filename.c_str(), source_bank, bank_index); - - // Verify the file was created - FILE* f = std::fopen(filename.c_str(), "r"); - REQUIRE(f != nullptr); - std::fclose(f); - - // Read the file back to check stat:sum - // Note: This would require mcpl_open_file and checking the header - // Since we can't easily read MCPL headers in C++ without the full MCPL API, - // we rely on the Python test to verify the actual content - - // Clean up - std::remove(filename.c_str()); - } - - SECTION("stat:sum uses correct particle count") - { - std::string filename = "test_count.mcpl"; - - // Test with different particle counts - std::vector test_counts = {1, 10, 100, 1000}; - - for (int count : test_counts) { - std::vector source_bank(count); - std::vector bank_index = {0, count}; - - // Initialize particles - for (int i = 0; i < count; ++i) { - source_bank[i].particle = openmc::ParticleType::neutron(); - source_bank[i].r = {0.0, 0.0, 0.0}; - source_bank[i].u = {0.0, 0.0, 1.0}; - source_bank[i].E = 1.0e6; - source_bank[i].time = 0.0; - source_bank[i].wgt = 1.0; - } - - // Write MCPL file - openmc::write_mcpl_source_point( - filename.c_str(), source_bank, bank_index); - - // The stat:sum should equal count (verified by Python test) - // Here we just verify the file was created successfully - FILE* f = std::fopen(filename.c_str(), "r"); - REQUIRE(f != nullptr); - std::fclose(f); - - // Clean up - std::remove(filename.c_str()); - } - } - - SECTION("stat:sum handles empty particle bank") - { - std::string filename = "test_empty.mcpl"; - - // Create empty particle bank - std::vector source_bank; - std::vector bank_index = {0}; - - // This should still create a valid MCPL file with stat:sum = 0 - openmc::write_mcpl_source_point(filename.c_str(), source_bank, bank_index); - - // Verify file was created - FILE* f = std::fopen(filename.c_str(), "r"); - REQUIRE(f != nullptr); - std::fclose(f); - - // Clean up - std::remove(filename.c_str()); - } -} diff --git a/tests/cpp_unit_tests/test_mesh.cpp b/tests/cpp_unit_tests/test_mesh.cpp deleted file mode 100644 index 24c4f7737..000000000 --- a/tests/cpp_unit_tests/test_mesh.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include -#include -#include - -#include -#include - -#include "openmc/hdf5_interface.h" -#include "openmc/mesh.h" - -using namespace openmc; - -TEST_CASE("Test mesh hdf5 roundtrip - regular") -{ - // The XML data as a string - std::string xml_string = R"( - - 3 4 5 - -2 -3 -5 - 2 3 5 - - )"; - - // Create a pugixml document object - pugi::xml_document doc; - - // Load the XML from the string - pugi::xml_parse_result result = doc.load_string(xml_string.c_str()); - - pugi::xml_node root = doc.child("mesh"); - - auto mesh = RegularMesh(root); - - hid_t file_id = file_open("mesh.h5", 'w'); - - mesh.to_hdf5(file_id); - - file_close(file_id); - - hid_t file_id2 = file_open("mesh.h5", 'r'); - - hid_t group = open_group(file_id2, "mesh 1"); - - auto mesh2 = RegularMesh(group); - - file_close(file_id2); - - remove("mesh.h5"); - - REQUIRE(mesh2.shape_ == mesh.shape_); - - REQUIRE(mesh2.lower_left() == mesh.lower_left()); - - REQUIRE(mesh2.upper_right() == mesh.upper_right()); -} - -TEST_CASE("Test mesh hdf5 roundtrip - rectilinear") -{ - // The XML data as a string - std::string xml_string = R"( - - 0.0 1.0 5.0 10.0 - -10.0 -5.0 0.0 - -100.0 0.0 100.0 - - )"; - - // Create a pugixml document object - pugi::xml_document doc; - - // Load the XML from the string - pugi::xml_parse_result result = doc.load_string(xml_string.c_str()); - - pugi::xml_node root = doc.child("mesh"); - - auto mesh = RectilinearMesh(root); - - hid_t file_id = file_open("mesh.h5", 'w'); - - mesh.to_hdf5(file_id); - - file_close(file_id); - - hid_t file_id2 = file_open("mesh.h5", 'r'); - - hid_t group = open_group(file_id2, "mesh 1"); - - auto mesh2 = RectilinearMesh(group); - - file_close(file_id2); - - remove("mesh.h5"); - - REQUIRE(mesh2.shape_ == mesh.shape_); - - REQUIRE(mesh2.grid_ == mesh.grid_); -} - -TEST_CASE("Test mesh hdf5 roundtrip - cylindrical") -{ - // The XML data as a string - std::string xml_string = R"( - - 0.1 0.2 0.5 1.0 - 0.0 6.283185307179586 - 0.1 0.2 0.4 0.6 1.0 - 0 0 0 - - )"; - - // Create a pugixml document object - pugi::xml_document doc; - - // Load the XML from the string - pugi::xml_parse_result result = doc.load_string(xml_string.c_str()); - - pugi::xml_node root = doc.child("mesh"); - - auto mesh = CylindricalMesh(root); - - hid_t file_id = file_open("mesh.h5", 'w'); - - mesh.to_hdf5(file_id); - - file_close(file_id); - - hid_t file_id2 = file_open("mesh.h5", 'r'); - - hid_t group = open_group(file_id2, "mesh 1"); - - auto mesh2 = CylindricalMesh(group); - - file_close(file_id2); - - remove("mesh.h5"); - - REQUIRE(mesh2.shape_ == mesh.shape_); - - REQUIRE(mesh2.grid_ == mesh.grid_); -} - -TEST_CASE("Test mesh hdf5 roundtrip - spherical") -{ - // The XML data as a string - std::string xml_string = R"( - - 0.1 0.2 0.5 1.0 - 0.0 3.141592653589793 - 0.0 6.283185307179586 - 0.0 0.0 0.0 - ' - )"; - - // Create a pugixml document object - pugi::xml_document doc; - - // Load the XML from the string - pugi::xml_parse_result result = doc.load_string(xml_string.c_str()); - - pugi::xml_node root = doc.child("mesh"); - - auto mesh = SphericalMesh(root); - - hid_t file_id = file_open("mesh.h5", 'w'); - - mesh.to_hdf5(file_id); - - file_close(file_id); - - hid_t file_id2 = file_open("mesh.h5", 'r'); - - hid_t group = open_group(file_id2, "mesh 1"); - - auto mesh2 = SphericalMesh(group); - - file_close(file_id2); - - remove("mesh.h5"); - - REQUIRE(mesh2.shape_ == mesh.shape_); - - REQUIRE(mesh2.grid_ == mesh.grid_); -} - -TEST_CASE("Test multiple meshes HDF5 roundtrip - spherical") -{ - // The XML data as a string - std::string xml_string = R"( - - - 0.1 0.2 0.5 1.0 - 0.0 3.141592653589793 - 0.0 6.283185307179586 - 0.0 0.0 0.0 - - - 3 4 5 - -2 -3 -5 - 2 3 5 - - - )"; - - // Create a pugixml document object - pugi::xml_document doc; - - // Load the XML from the string - pugi::xml_parse_result result = doc.load_string(xml_string.c_str()); - - pugi::xml_node root = doc.child("meshes"); - - read_meshes(root); - - const auto spherical_mesh_xml = - dynamic_cast(model::meshes[0].get()); - const auto regular_mesh_xml = - dynamic_cast(model::meshes[1].get()); - - hid_t file_id = file_open("meshes.h5", 'w'); - - hid_t root_group = create_group(file_id, "root"); - - open_group(file_id, "root"); - - meshes_to_hdf5(root_group); - - close_group(root_group); - - file_close(file_id); - - hid_t file_id2 = file_open("meshes.h5", 'r'); - - hid_t root_group_read = open_group(file_id2, "root"); - - hid_t mesh_group_read = open_group(root_group_read, "meshes"); - - read_meshes(mesh_group_read); - - // increment mesh IDs to avoid collision during read - for (auto& mesh : model::meshes) { - mesh->set_id(mesh->id() + 10); - } - - const auto spherical_mesh_hdf5 = dynamic_cast( - model::meshes[model::mesh_map[spherical_mesh_xml->id_]].get()); - const auto regular_mesh_hdf5 = dynamic_cast( - model::meshes[model::mesh_map[regular_mesh_xml->id_]].get()); - - remove("meshes.h5"); - - REQUIRE(spherical_mesh_hdf5->shape_ == spherical_mesh_xml->shape_); - REQUIRE(spherical_mesh_hdf5->grid_ == spherical_mesh_xml->grid_); - - REQUIRE(regular_mesh_hdf5->shape_ == regular_mesh_xml->shape_); - REQUIRE(regular_mesh_hdf5->lower_left() == regular_mesh_xml->lower_left()); - REQUIRE(regular_mesh_hdf5->upper_right() == regular_mesh_xml->upper_right()); -} diff --git a/tests/cpp_unit_tests/test_ray.cpp b/tests/cpp_unit_tests/test_ray.cpp deleted file mode 100644 index c043c4d25..000000000 --- a/tests/cpp_unit_tests/test_ray.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include - -#include -#include -#include - -#include "openmc/geometry.h" -#include "openmc/geometry_aux.h" -#include "openmc/ray.h" -#include "openmc/settings.h" -#include "openmc/surface.h" - -namespace { - -using Catch::Matchers::WithinAbs; - -constexpr double DISTANCE_TOLERANCE = 1.0e-12; - -class SphericalShellFixture { -public: - SphericalShellFixture() - : run_mode_(openmc::settings::run_mode), - root_universe_(openmc::model::root_universe), - n_coord_levels_(openmc::model::n_coord_levels) - { - openmc::settings::run_mode = openmc::RunMode::PLOTTING; - - constexpr auto geometry = R"( - - - - - - - )"; - - auto result = document_.load_string(geometry); - REQUIRE(result); - openmc::read_geometry_xml(document_.document_element()); - openmc::finalize_geometry(); - openmc::finalize_cell_densities(); - } - - ~SphericalShellFixture() - { - openmc::free_memory_geometry(); - openmc::free_memory_surfaces(); - openmc::model::universe_level_counts.clear(); - openmc::model::root_universe = root_universe_; - openmc::model::n_coord_levels = n_coord_levels_; - openmc::settings::run_mode = run_mode_; - } - -private: - pugi::xml_document document_; - openmc::RunMode run_mode_; - int root_universe_; - int n_coord_levels_; -}; - -class RecordingRay : public openmc::Ray { -public: - using Ray::Ray; - - void on_intersection() override - { - intersections.emplace_back( - traversal_distance_, boundary().surface_index() + 1); - } - - openmc::vector> intersections; -}; - -} // namespace - -TEST_CASE_METHOD(SphericalShellFixture, "Trace a single chord through a sphere") -{ - constexpr double impact_parameter = 1.5; - const double half_chord = - std::sqrt(4.0 - impact_parameter * impact_parameter); - - RecordingRay ray({-3.0, impact_parameter, 0.0}, {1.0, 0.0, 0.0}); - ray.trace(); - - REQUIRE(ray.intersections.size() == 2); - CHECK(ray.intersections[0].second == 2); - CHECK_THAT(ray.intersections[0].first, WithinAbs(0.0, DISTANCE_TOLERANCE)); - CHECK(ray.intersections[1].second == 2); - CHECK_THAT(ray.intersections[1].first, - WithinAbs(2.0 * half_chord, DISTANCE_TOLERANCE)); -} - -TEST_CASE_METHOD( - SphericalShellFixture, "Trace both segments of a spherical shell") -{ - constexpr double impact_parameter = 0.5; - const double outer = std::sqrt(4.0 - impact_parameter * impact_parameter); - const double inner = std::sqrt(1.0 - impact_parameter * impact_parameter); - - RecordingRay ray({-3.0, impact_parameter, 0.0}, {1.0, 0.0, 0.0}); - ray.trace(); - - REQUIRE(ray.intersections.size() == 4); - CHECK(ray.intersections[0].second == 2); - CHECK_THAT(ray.intersections[0].first, WithinAbs(0.0, DISTANCE_TOLERANCE)); - CHECK(ray.intersections[1].second == 1); - CHECK_THAT( - ray.intersections[1].first, WithinAbs(outer - inner, DISTANCE_TOLERANCE)); - CHECK(ray.intersections[2].second == 1); - CHECK_THAT( - ray.intersections[2].first, WithinAbs(outer + inner, DISTANCE_TOLERANCE)); - CHECK(ray.intersections[3].second == 2); - CHECK_THAT( - ray.intersections[3].first, WithinAbs(2.0 * outer, DISTANCE_TOLERANCE)); -} diff --git a/tests/cpp_unit_tests/test_region.cpp b/tests/cpp_unit_tests/test_region.cpp deleted file mode 100644 index b3d9a1427..000000000 --- a/tests/cpp_unit_tests/test_region.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include - -#include "openmc/cell.h" -#include "openmc/surface.h" - -#include - -namespace { - -// Helper class to set up and tear down test surfaces -class SurfaceFixture { -public: - SurfaceFixture() - { - pugi::xml_document doc; - pugi::xml_node surf_node = doc.append_child("surface"); - surf_node.set_name("surface"); - surf_node.append_attribute("id") = "0"; - surf_node.append_attribute("type") = "x-plane"; - surf_node.append_attribute("coeffs") = "1"; - - for (int i = 1; i < 10; ++i) { - surf_node.attribute("id") = i; - openmc::model::surfaces.push_back( - std::make_unique(surf_node)); - openmc::model::surface_map[i] = i - 1; - } - } - - ~SurfaceFixture() - { - openmc::model::surfaces.clear(); - openmc::model::surface_map.clear(); - } -}; - -} // anonymous namespace - -TEST_CASE("Test region simplification") -{ - SurfaceFixture fixture; - - SECTION("Original bug case from issue #3685") - { - // Input: "-1 2 (-3 4) | (-5 6)" was being incorrectly interpreted - auto region = openmc::Region("(-1 2 (-3 4) | (-5 6))", 0); - REQUIRE(region.str() == " ( ( -1 2 ( -3 4 ) ) | ( -5 6 ) )"); - } - - SECTION("Simple union - no extra parentheses needed") - { - auto region = openmc::Region("1 | 2", 0); - REQUIRE(region.str() == " 1 | 2"); - } - - SECTION("Intersection then union") - { - // Intersection should have higher precedence, so (1 2) grouped - auto region = openmc::Region("1 2 | 3", 0); - REQUIRE(region.str() == " ( 1 2 ) | 3"); - } - - SECTION("Union then intersection") - { - // The (2 3) intersection should be grouped - auto region = openmc::Region("1 | 2 3", 0); - REQUIRE(region.str() == " 1 | ( 2 3 )"); - } - - SECTION("Nested parentheses preserved") - { - // These parentheses are meaningful and should be preserved - auto region = openmc::Region("(1 | 2) (3 | 4)", 0); - REQUIRE(region.str() == " ( 1 | 2 ) ( 3 | 4 )"); - } - - SECTION("Deep nesting") - { - auto region = openmc::Region("((1 2) | (3 4)) 5", 0); - REQUIRE(region.str() == " ( ( 1 2 ) | ( 3 4 ) ) 5"); - } - - SECTION("Multiple unions") - { - auto region = openmc::Region("1 | 2 | 3", 0); - REQUIRE(region.str() == " 1 | 2 | 3"); - } - - SECTION("Multiple intersections") - { - auto region = openmc::Region("1 2 3", 0); - // Simple cell - no operators in output - REQUIRE(region.str() == " 1 2 3"); - } - - SECTION("Complex mixed expression") - { - auto region = openmc::Region("1 2 | 3 4 | 5 6", 0); - REQUIRE(region.str() == " ( 1 2 ) | ( 3 4 ) | ( 5 6 )"); - } -} diff --git a/tests/cpp_unit_tests/test_tally.cpp b/tests/cpp_unit_tests/test_tally.cpp deleted file mode 100644 index 03322e764..000000000 --- a/tests/cpp_unit_tests/test_tally.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "openmc/tallies/filter_energy.h" -#include "openmc/tallies/tally.h" -#include - -using namespace openmc; - -TEST_CASE("Test add/set_filter") -{ - // create a new tally object - Tally* tally = Tally::create(); - - // create a new particle filter - Filter* particle_filter = Filter::create("particle"); - - // add the particle filter to the tally - tally->add_filter(particle_filter); - - // the filter should be added to the tally - REQUIRE(tally->filters().size() == 1); - REQUIRE(model::filter_map[particle_filter->id()] == tally->filters(0)); - - // add the particle filter to the tally again - tally->add_filter(particle_filter); - // the tally should have the same number of filters - REQUIRE(tally->filters().size() == 1); - - // create a cell filter - Filter* cell_filter = Filter::create("cell"); - tally->add_filter(cell_filter); - - // now the size of the filters should have increased - REQUIRE(tally->filters().size() == 2); - REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(1)); - - // if we set the filters explicitly there shouldn't be extra filters hanging - // around - tally->set_filters({&cell_filter, 1}); - - REQUIRE(tally->filters().size() == 1); - REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); - - // set filters again using both filters - std::vector filters = {cell_filter, particle_filter}; - tally->set_filters(filters); - - REQUIRE(tally->filters().size() == 2); - REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); - REQUIRE(model::filter_map[particle_filter->id()] == tally->filters(1)); - - // set filters with a duplicate filter, should only add the filter to the - // tally once - filters = {cell_filter, cell_filter}; - tally->set_filters(filters); - REQUIRE(tally->filters().size() == 1); - REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); -} - -// Regression test for 64-bit tally filter-bin counts (mesh x groups > 2^31). -TEST_CASE("Tally filter-bin count does not overflow 32 bits") -{ - // Two energy filters whose bin counts multiply to 2.5e9, above INT32_MAX. - constexpr int64_t bins_per_filter = 50000; - - // Only the bin count matters here, so the edge values are an arbitrary ramp. - std::vector edges(bins_per_filter + 1); - for (int64_t i = 0; i < bins_per_filter + 1; ++i) - edges[i] = static_cast(i); - - Tally* tally = Tally::create(); - for (int i = 0; i < 2; ++i) { - Filter* filter = Filter::create("energy"); - dynamic_cast(filter)->set_bins(edges); - tally->add_filter(filter); - } - tally->set_strides(); - - // set_strides() previously accumulated this product in a 32-bit int. - REQUIRE(tally->n_filter_bins() == bins_per_filter * bins_per_filter); - REQUIRE(tally->n_filter_bins() > 2147483647); -} \ No newline at end of file diff --git a/tests/cpp_unit_tests/test_tensor.cpp b/tests/cpp_unit_tests/test_tensor.cpp deleted file mode 100644 index 0936d866a..000000000 --- a/tests/cpp_unit_tests/test_tensor.cpp +++ /dev/null @@ -1,1008 +0,0 @@ -#include -#include - -#include -#include - -#include "openmc/tensor.h" - -using namespace openmc; -using namespace openmc::tensor; - -// ============================================================================ -// Tensor constructors -// ============================================================================ - -TEST_CASE("Tensor default constructor") -{ - Tensor t; - REQUIRE(t.size() == 0); - REQUIRE(t.empty()); - REQUIRE(t.shape().empty()); -} - -TEST_CASE("Tensor shape constructor") -{ - Tensor t1({5}); - REQUIRE(t1.size() == 5); - REQUIRE(t1.shape().size() == 1); - REQUIRE(t1.shape(0) == 5); - - Tensor t2({3, 4}); - REQUIRE(t2.size() == 12); - REQUIRE(t2.shape().size() == 2); - REQUIRE(t2.shape(0) == 3); - REQUIRE(t2.shape(1) == 4); - - Tensor t3({2, 3, 4}); - REQUIRE(t3.size() == 24); - REQUIRE(t3.shape().size() == 3); -} - -TEST_CASE("Tensor shape + fill constructor") -{ - Tensor t({2, 3}, 7.0); - REQUIRE(t.size() == 6); - for (size_t i = 0; i < t.size(); ++i) - REQUIRE(t[i] == 7.0); -} - -TEST_CASE("Tensor pointer constructor") -{ - double vals[] = {1.0, 2.0, 3.0, 4.0}; - Tensor t(vals, 4); - REQUIRE(t.size() == 4); - REQUIRE(t.shape(0) == 4); - REQUIRE(t[0] == 1.0); - REQUIRE(t[1] == 2.0); - REQUIRE(t[2] == 3.0); - REQUIRE(t[3] == 4.0); -} - -TEST_CASE("Tensor copy and move") -{ - Tensor a({2, 3}, 5.0); - Tensor b(a); - REQUIRE(b.size() == 6); - REQUIRE(b(0, 0) == 5.0); - // Modifying copy doesn't affect original - b(0, 0) = 99.0; - REQUIRE(a(0, 0) == 5.0); - - Tensor c(std::move(b)); - REQUIRE(c(0, 0) == 99.0); - REQUIRE(c.size() == 6); -} - -// ============================================================================ -// Tensor indexing -// ============================================================================ - -TEST_CASE("Tensor 1D indexing") -{ - Tensor t({4}, 0); - t[0] = 10; - t[1] = 20; - t[2] = 30; - t[3] = 40; - REQUIRE(t(0) == 10); - REQUIRE(t(1) == 20); - REQUIRE(t(2) == 30); - REQUIRE(t(3) == 40); -} - -TEST_CASE("Tensor 2D indexing (row-major)") -{ - // Layout: [[1, 2, 3], [4, 5, 6]] - Tensor t({2, 3}, 0); - int val = 1; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - t(i, j) = val++; - - REQUIRE(t(0, 0) == 1); - REQUIRE(t(0, 2) == 3); - REQUIRE(t(1, 0) == 4); - REQUIRE(t(1, 2) == 6); - // Flat index should match row-major order - REQUIRE(t[0] == 1); - REQUIRE(t[3] == 4); - REQUIRE(t[5] == 6); -} - -TEST_CASE("Tensor 3D indexing") -{ - // 2x3x4 tensor - Tensor t({2, 3, 4}, 0); - t(1, 2, 3) = 42; - // Flat index: 1*12 + 2*4 + 3 = 23 - REQUIRE(t[23] == 42); - REQUIRE(t(1, 2, 3) == 42); -} - -// ============================================================================ -// Tensor assignment -// ============================================================================ - -TEST_CASE("Tensor initializer_list assignment") -{ - Tensor t; - t = {1.0, 2.0, 3.0}; - REQUIRE(t.size() == 3); - REQUIRE(t.shape(0) == 3); - REQUIRE(t[0] == 1.0); - REQUIRE(t[2] == 3.0); -} - -// ============================================================================ -// Tensor mutation -// ============================================================================ - -TEST_CASE("Tensor resize") -{ - Tensor t({2, 3}, 1.0); - REQUIRE(t.size() == 6); - t.resize({4, 5}); - REQUIRE(t.size() == 20); - REQUIRE(t.shape(0) == 4); - REQUIRE(t.shape(1) == 5); -} - -TEST_CASE("Tensor reshape") -{ - Tensor t({12}, 0); - for (size_t i = 0; i < 12; ++i) - t[i] = static_cast(i); - - t.reshape({3, 4}); - REQUIRE(t.shape(0) == 3); - REQUIRE(t.shape(1) == 4); - REQUIRE(t.size() == 12); - // Data unchanged, just reinterpreted - REQUIRE(t(0, 0) == 0); - REQUIRE(t(1, 0) == 4); // row 1, col 0 = flat index 4 - REQUIRE(t(2, 3) == 11); // row 2, col 3 = flat index 11 -} - -TEST_CASE("Tensor fill") -{ - Tensor t({3, 3}, 0.0); - t.fill(42.0); - for (size_t i = 0; i < t.size(); ++i) - REQUIRE(t[i] == 42.0); -} - -// ============================================================================ -// Tensor iterators -// ============================================================================ - -TEST_CASE("Tensor iterators") -{ - Tensor t({4}, 0); - t = {10, 20, 30, 40}; - int sum = 0; - for (auto val : t) - sum += val; - REQUIRE(sum == 100); -} - -// ============================================================================ -// Tensor reductions -// ============================================================================ - -TEST_CASE("Tensor sum (full)") -{ - Tensor t({3}, 0.0); - t = {1.0, 2.0, 3.0}; - REQUIRE(t.sum() == 6.0); -} - -TEST_CASE("Tensor sum (axis) on 2D") -{ - // [[1, 2, 3], - // [4, 5, 6]] - Tensor t({2, 3}, 0); - int v = 1; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - t(i, j) = v++; - - // Sum along axis 0 -> [5, 7, 9] - Tensor s0 = t.sum(0); - REQUIRE(s0.size() == 3); - REQUIRE(s0[0] == 5); - REQUIRE(s0[1] == 7); - REQUIRE(s0[2] == 9); - - // Sum along axis 1 -> [6, 15] - Tensor s1 = t.sum(1); - REQUIRE(s1.size() == 2); - REQUIRE(s1[0] == 6); - REQUIRE(s1[1] == 15); -} - -TEST_CASE("Tensor sum (axis) on 3D") -{ - // 2x3x2 tensor filled with sequential values 1..12 - Tensor t({2, 3, 2}, 0); - int v = 1; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - for (size_t k = 0; k < 2; ++k) - t(i, j, k) = v++; - - // Sum along axis 1 (middle) -> 2x2, each sums 3 values - // [0,0]: t(0,0,0)+t(0,1,0)+t(0,2,0) = 1+3+5 = 9 - // [0,1]: t(0,0,1)+t(0,1,1)+t(0,2,1) = 2+4+6 = 12 - // [1,0]: t(1,0,0)+t(1,1,0)+t(1,2,0) = 7+9+11 = 27 - // [1,1]: t(1,0,1)+t(1,1,1)+t(1,2,1) = 8+10+12 = 30 - Tensor s = t.sum(1); - REQUIRE(s.shape(0) == 2); - REQUIRE(s.shape(1) == 2); - REQUIRE(s(0, 0) == 9); - REQUIRE(s(0, 1) == 12); - REQUIRE(s(1, 0) == 27); - REQUIRE(s(1, 1) == 30); -} - -TEST_CASE("Tensor prod") -{ - Tensor t({4}, 0); - t = {1, 2, 3, 4}; - REQUIRE(t.prod() == 24); -} - -TEST_CASE("Tensor any and all") -{ - Tensor t({4}, false); - REQUIRE(!t.any()); - REQUIRE(!t.all()); - - // Set one element true - t.data()[0] = true; - REQUIRE(t.any()); - REQUIRE(!t.all()); - - // Set all true - for (size_t i = 0; i < t.size(); ++i) - t.data()[i] = true; - REQUIRE(t.any()); - REQUIRE(t.all()); -} - -TEST_CASE("Tensor argmin") -{ - Tensor t({5}, 0.0); - t = {3.0, 1.0, 4.0, 0.5, 2.0}; - REQUIRE(t.argmin() == 3); -} - -TEST_CASE("Tensor flip") -{ - Tensor t({5}, 0); - t = {1, 2, 3, 4, 5}; - Tensor f = t.flip(0); - REQUIRE(f[0] == 5); - REQUIRE(f[1] == 4); - REQUIRE(f[2] == 3); - REQUIRE(f[3] == 2); - REQUIRE(f[4] == 1); -} - -TEST_CASE("Tensor flip 2D") -{ - // [[1, 2], [3, 4], [5, 6]] - Tensor t({3, 2}, 0); - t(0, 0) = 1; - t(0, 1) = 2; - t(1, 0) = 3; - t(1, 1) = 4; - t(2, 0) = 5; - t(2, 1) = 6; - - // Flip axis 0 reverses rows -> [[5,6],[3,4],[1,2]] - Tensor f = t.flip(0); - REQUIRE(f(0, 0) == 5); - REQUIRE(f(0, 1) == 6); - REQUIRE(f(1, 0) == 3); - REQUIRE(f(2, 0) == 1); -} - -// ============================================================================ -// Tensor operators -// ============================================================================ - -TEST_CASE("Tensor scalar compound assignment") -{ - Tensor t({3}, 0.0); - t = {2.0, 4.0, 6.0}; - - t += 1.0; - REQUIRE(t[0] == 3.0); - REQUIRE(t[1] == 5.0); - - t -= 1.0; - REQUIRE(t[0] == 2.0); - - t *= 3.0; - REQUIRE(t[0] == 6.0); - REQUIRE(t[1] == 12.0); - - t /= 2.0; - REQUIRE(t[0] == 3.0); - REQUIRE(t[1] == 6.0); -} - -TEST_CASE("Tensor element-wise arithmetic") -{ - Tensor a({3}, 0.0); - Tensor b({3}, 0.0); - a = {1.0, 2.0, 3.0}; - b = {4.0, 5.0, 6.0}; - - Tensor c = a + b; - REQUIRE(c[0] == 5.0); - REQUIRE(c[1] == 7.0); - REQUIRE(c[2] == 9.0); - - c = a - b; - REQUIRE(c[0] == -3.0); - - c = a / b; - REQUIRE(c[0] == 0.25); - - c = a * b; - REQUIRE(c[0] == 4.0); -} - -TEST_CASE("Tensor scalar arithmetic") -{ - Tensor a({3}, 0.0); - a = {1.0, 2.0, 3.0}; - - Tensor b = a + 10.0; - REQUIRE(b[0] == 11.0); - REQUIRE(b[2] == 13.0); - - b = a - 1.0; - REQUIRE(b[0] == 0.0); - - b = a * 2.0; - REQUIRE(b[0] == 2.0); - REQUIRE(b[2] == 6.0); - - // Non-member scalar * tensor (commutativity) - b = 2.0 * a; - REQUIRE(b[0] == 2.0); - REQUIRE(b[2] == 6.0); - - // Non-member scalar + tensor - b = 10.0 + a; - REQUIRE(b[0] == 11.0); -} - -TEST_CASE("Tensor compound arithmetic with tensor") -{ - Tensor a({3}, 0.0); - Tensor b({3}, 0.0); - a = {1.0, 2.0, 3.0}; - b = {10.0, 20.0, 30.0}; - a += b; - REQUIRE(a[0] == 11.0); - REQUIRE(a[1] == 22.0); - REQUIRE(a[2] == 33.0); - - a = {1.0, 2.0, 3.0}; - b -= a; - REQUIRE(b[0] == 9.0); - REQUIRE(b[1] == 18.0); - REQUIRE(b[2] == 27.0); - - b = {10.0, 20.0, 30.0}; - a *= b; - REQUIRE(a[0] == 10.0); - REQUIRE(a[1] == 40.0); - REQUIRE(a[2] == 90.0); - - a = {1.0, 2.0, 3.0}; - b /= a; - REQUIRE(b[0] == 10.0); - REQUIRE(b[1] == 10.0); - REQUIRE(b[2] == 10.0); -} - -TEST_CASE("Tensor comparison operators") -{ - Tensor t({4}, 0.0); - t = {1.0, 2.0, 3.0, 4.0}; - - Tensor r = t < 3.0; - REQUIRE(r.data()[0] == true); - REQUIRE(r.data()[1] == true); - REQUIRE(r.data()[2] == false); - REQUIRE(r.data()[3] == false); - - r = t >= 3.0; - REQUIRE(r.data()[0] == false); - REQUIRE(r.data()[2] == true); - REQUIRE(r.data()[3] == true); - - r = t <= 2.0; - REQUIRE(r.data()[0] == true); - REQUIRE(r.data()[1] == true); - REQUIRE(r.data()[2] == false); - - r = t > 3.0; - REQUIRE(r.data()[0] == false); - REQUIRE(r.data()[3] == true); -} - -TEST_CASE("Tensor element-wise comparison") -{ - Tensor a({3}, 0.0); - Tensor b({3}, 0.0); - a = {1.0, 5.0, 3.0}; - b = {2.0, 4.0, 3.0}; - - Tensor r = a < b; - REQUIRE(r.data()[0] == true); - REQUIRE(r.data()[1] == false); - REQUIRE(r.data()[2] == false); -} - -TEST_CASE("Tensor mixed-type multiply") -{ - Tensor a({3}, 0); - Tensor b({3}, 0.0); - a = {2, 3, 4}; - b = {1.5, 2.5, 3.5}; - - Tensor c = a * b; - REQUIRE(c[0] == 3.0); - REQUIRE(c[1] == 7.5); - REQUIRE(c[2] == 14.0); -} - -TEST_CASE("Tensor mixed-type divide") -{ - Tensor a({3}, 0.0); - Tensor b({3}, 0); - a = {10.0, 20.0, 30.0}; - b = {2, 4, 5}; - - Tensor c = a / b; - REQUIRE(c[0] == 5.0); - REQUIRE(c[1] == 5.0); - REQUIRE(c[2] == 6.0); -} - -// ============================================================================ -// Tensor bool specialization -// ============================================================================ - -TEST_CASE("Tensor storage") -{ - // Tensor uses unsigned char internally to avoid std::vector proxy - Tensor t({4}, false); - t.data()[0] = true; - t.data()[2] = true; - REQUIRE(t.any()); - REQUIRE(!t.all()); - REQUIRE(t.data()[0] == true); - REQUIRE(t.data()[1] == false); -} - -// ============================================================================ -// View (via Tensor accessors) -// ============================================================================ - -TEST_CASE("Tensor slice axis 0 (2D)") -{ - // [[1, 2, 3], [4, 5, 6]] - Tensor t({2, 3}, 0); - int v = 1; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - t(i, j) = v++; - - auto r0 = t.slice(0); - REQUIRE(r0.size() == 3); - REQUIRE(r0[0] == 1); - REQUIRE(r0[1] == 2); - REQUIRE(r0[2] == 3); - - auto r1 = t.slice(1); - REQUIRE(r1[0] == 4); - REQUIRE(r1[1] == 5); - REQUIRE(r1[2] == 6); - - // Writing through view modifies the tensor - r0[1] = 99; - REQUIRE(t(0, 1) == 99); -} - -TEST_CASE("Tensor slice axis 1 (2D)") -{ - // [[1, 2], [3, 4], [5, 6]] - Tensor t({3, 2}, 0); - t(0, 0) = 1; - t(0, 1) = 2; - t(1, 0) = 3; - t(1, 1) = 4; - t(2, 0) = 5; - t(2, 1) = 6; - - auto c0 = t.slice(all, 0); - REQUIRE(c0.size() == 3); - REQUIRE(c0[0] == 1); - REQUIRE(c0[1] == 3); - REQUIRE(c0[2] == 5); - - auto c1 = t.slice(all, 1); - REQUIRE(c1[0] == 2); - REQUIRE(c1[1] == 4); - REQUIRE(c1[2] == 6); - - // Write through column view - c1[0] = 77; - REQUIRE(t(0, 1) == 77); -} - -TEST_CASE("Tensor slice with range") -{ - Tensor t({6}, 0); - t = {10, 20, 30, 40, 50, 60}; - - // range(start, end) - auto s = t.slice(range(1, 4)); - REQUIRE(s.size() == 3); - REQUIRE(s[0] == 20); - REQUIRE(s[1] == 30); - REQUIRE(s[2] == 40); - - // range(end) from start — range(3) means [0, 3) - auto s2 = t.slice(range(3)); - REQUIRE(s2.size() == 3); - REQUIRE(s2[0] == 10); - REQUIRE(s2[2] == 30); - - // range(start, SIZE_MAX) to end - auto s3 = t.slice(range(3, 6)); - REQUIRE(s3.size() == 3); - REQUIRE(s3[0] == 40); - REQUIRE(s3[2] == 60); - - // Write through slice - s[0] = 99; - REQUIRE(t[1] == 99); -} - -TEST_CASE("Tensor flat view") -{ - Tensor t({2, 3}, 0); - int v = 1; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - t(i, j) = v++; - - auto f = t.flat(); - REQUIRE(f.size() == 6); - REQUIRE(f[0] == 1); - REQUIRE(f[5] == 6); -} - -TEST_CASE("Tensor slice on 3D") -{ - // 2x3x4 tensor - Tensor t({2, 3, 4}, 0); - int v = 0; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - for (size_t k = 0; k < 4; ++k) - t(i, j, k) = v++; - - // slice(1) -> fix axis 0 at 1 -> 3x4 view - auto s = t.slice(1); - REQUIRE(s.size() == 12); - // t(1,0,0) = 12, t(1,0,1) = 13, ... - REQUIRE(s(0, 0) == 12); - REQUIRE(s(0, 1) == 13); - REQUIRE(s(2, 3) == 23); - - // slice(all, 2) -> fix axis 1 at 2 -> 2x4 view - auto s2 = t.slice(all, 2); - REQUIRE(s2.size() == 8); - // t(0,2,0)=8, t(0,2,1)=9, t(1,2,0)=20 - REQUIRE(s2(0, 0) == 8); - REQUIRE(s2(0, 1) == 9); - REQUIRE(s2(1, 0) == 20); -} - -TEST_CASE("Tensor multi-axis slice") -{ - // 2x3x4 tensor with sequential values - Tensor t({2, 3, 4}, 0); - int v = 0; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - for (size_t k = 0; k < 4; ++k) - t(i, j, k) = v++; - - // slice(1, 2) -> fix axes 0 and 1 -> 1D view of 4 elements - // Equivalent to numpy t[1, 2, :] -> t(1,2,0..3) = [20, 21, 22, 23] - auto s = t.slice(1, 2); - REQUIRE(s.size() == 4); - REQUIRE(s[0] == 20); - REQUIRE(s[1] == 21); - REQUIRE(s[3] == 23); - - // slice(all, 1, range(1, 3)) -> keep axis 0, fix axis 1, range on axis 2 - // Equivalent to numpy t[:, 1, 1:3] - // t(0,1,1)=5, t(0,1,2)=6, t(1,1,1)=17, t(1,1,2)=18 - auto s2 = t.slice(all, 1, range(1, 3)); - REQUIRE(s2.size() == 4); - REQUIRE(s2.ndim() == 2); - REQUIRE(s2(0, 0) == 5); - REQUIRE(s2(0, 1) == 6); - REQUIRE(s2(1, 0) == 17); - REQUIRE(s2(1, 1) == 18); - - // slice(0, range(0, 2)) -> fix axis 0 at 0, range on axis 1 - // Equivalent to numpy t[0, 0:2, :] -> shape (2, 4) - auto s3 = t.slice(0, range(0, 2)); - REQUIRE(s3.ndim() == 2); - REQUIRE(s3.shape(0) == 2); - REQUIRE(s3.shape(1) == 4); - REQUIRE(s3(0, 0) == 0); // t(0,0,0) - REQUIRE(s3(1, 3) == 7); // t(0,1,3) -} - -// ============================================================================ -// View assignment and arithmetic -// ============================================================================ - -TEST_CASE("View scalar assignment (fill)") -{ - Tensor t({2, 3}, 0.0); - auto r = t.slice(0); - r = 7.0; - REQUIRE(t(0, 0) == 7.0); - REQUIRE(t(0, 1) == 7.0); - REQUIRE(t(0, 2) == 7.0); - REQUIRE(t(1, 0) == 0.0); // Other row unchanged -} - -TEST_CASE("View initializer_list assignment") -{ - Tensor t({2, 3}, 0.0); - auto r = t.slice(1); - r = {10.0, 20.0, 30.0}; - REQUIRE(t(1, 0) == 10.0); - REQUIRE(t(1, 1) == 20.0); - REQUIRE(t(1, 2) == 30.0); -} - -TEST_CASE("View copy assignment (deep copy)") -{ - Tensor t({2, 3}, 0.0); - t.slice(0) = {1.0, 2.0, 3.0}; - t.slice(1) = {4.0, 5.0, 6.0}; - - // Copy row 0 into row 1 - t.slice(1) = t.slice(0); - REQUIRE(t(1, 0) == 1.0); - REQUIRE(t(1, 1) == 2.0); - REQUIRE(t(1, 2) == 3.0); -} - -TEST_CASE("View compound operators") -{ - Tensor t({2, 3}, 0.0); - t.slice(0) = {1.0, 2.0, 3.0}; - - t.slice(0) *= 2.0; - REQUIRE(t(0, 0) == 2.0); - REQUIRE(t(0, 1) == 4.0); - - t.slice(0) /= 2.0; - REQUIRE(t(0, 0) == 1.0); - REQUIRE(t(0, 1) == 2.0); -} - -TEST_CASE("View assignment from tensor") -{ - Tensor t({2, 3}, 0.0); - Tensor vals({3}, 0.0); - vals = {7.0, 8.0, 9.0}; - - t.slice(1) = vals; - REQUIRE(t(1, 0) == 7.0); - REQUIRE(t(1, 1) == 8.0); - REQUIRE(t(1, 2) == 9.0); -} - -TEST_CASE("View compound addition from tensor") -{ - Tensor t({2, 3}, 0.0); - t.slice(0) = {1.0, 2.0, 3.0}; - Tensor vals({3}, 0.0); - vals = {10.0, 20.0, 30.0}; - - t.slice(0) += vals; - REQUIRE(t(0, 0) == 11.0); - REQUIRE(t(0, 1) == 22.0); - REQUIRE(t(0, 2) == 33.0); -} - -TEST_CASE("View sum") -{ - Tensor t({2, 3}, 0.0); - t.slice(0) = {1.0, 2.0, 3.0}; - t.slice(1) = {4.0, 5.0, 6.0}; - - REQUIRE(t.slice(0).sum() == 6.0); - REQUIRE(t.slice(1).sum() == 15.0); -} - -TEST_CASE("View iteration") -{ - Tensor t({2, 3}, 0); - t.slice(0) = {1, 2, 3}; - - int sum = 0; - for (auto val : t.slice(0)) - sum += val; - REQUIRE(sum == 6); -} - -TEST_CASE("View sub-slice") -{ - Tensor t({6}, 0); - t = {10, 20, 30, 40, 50, 60}; - - auto s = t.slice(range(1, 5)); // [20, 30, 40, 50] - auto ss = s.slice(range(1, 3)); // [30, 40] - REQUIRE(ss.size() == 2); - REQUIRE(ss[0] == 30); - REQUIRE(ss[1] == 40); -} - -TEST_CASE("Tensor from View") -{ - Tensor t({2, 3}, 0.0); - t.slice(0) = {1.0, 2.0, 3.0}; - - // Construct a new tensor from a view (copies data) - Tensor t2(t.slice(0)); - REQUIRE(t2.size() == 3); - REQUIRE(t2[0] == 1.0); - REQUIRE(t2[2] == 3.0); - - // Modifying the new tensor doesn't affect the original - t2[0] = 99.0; - REQUIRE(t(0, 0) == 1.0); -} - -// ============================================================================ -// Const View -// ============================================================================ - -TEST_CASE("Const tensor produces const views") -{ - Tensor t({2, 3}, 0.0); - int v = 1; - for (size_t i = 0; i < 2; ++i) - for (size_t j = 0; j < 3; ++j) - t(i, j) = v++; - - const Tensor& ct = t; - auto r = ct.slice(0); // View - REQUIRE(r[0] == 1.0); - REQUIRE(r[2] == 3.0); - - auto c = ct.slice(all, 1); - REQUIRE(c[0] == 2.0); - REQUIRE(c[1] == 5.0); -} - -// ============================================================================ -// StaticTensor2D -// ============================================================================ - -TEST_CASE("StaticTensor2D basics") -{ - StaticTensor2D t; - REQUIRE(t.size() == 12); - REQUIRE(t.shape()[0] == 3); - REQUIRE(t.shape()[1] == 4); - - // Default-initialized to zero - REQUIRE(t(0, 0) == 0.0); - - t(1, 2) = 42.0; - REQUIRE(t(1, 2) == 42.0); - // Flat data: row 1, col 2 = index 1*4 + 2 = 6 - REQUIRE(t.data()[6] == 42.0); -} - -TEST_CASE("StaticTensor2D fill") -{ - StaticTensor2D t; - t.fill(5); - for (size_t i = 0; i < t.size(); ++i) - REQUIRE(t.data()[i] == 5); -} - -TEST_CASE("StaticTensor2D iteration") -{ - StaticTensor2D t; - t.fill(1); - int sum = 0; - for (auto val : t) - sum += val; - REQUIRE(sum == 6); -} - -TEST_CASE("StaticTensor2D slice") -{ - StaticTensor2D t; - t(0, 0) = 1; - t(0, 1) = 2; - t(1, 0) = 3; - t(1, 1) = 4; - t(2, 0) = 5; - t(2, 1) = 6; - - // slice(1) = row 1 (fix axis 0 at 1) - auto r1 = t.slice(1); - REQUIRE(r1.size() == 2); - REQUIRE(r1[0] == 3); - REQUIRE(r1[1] == 4); - - // slice(all, 0) = column 0 (fix axis 1 at 0) - auto c0 = t.slice(all, 0); - REQUIRE(c0.size() == 3); - REQUIRE(c0[0] == 1); - REQUIRE(c0[1] == 3); - REQUIRE(c0[2] == 5); -} - -TEST_CASE("StaticTensor2D flat view") -{ - StaticTensor2D t; - t(0, 0) = 1.0; - t(0, 1) = 2.0; - t(1, 0) = 3.0; - t(1, 1) = 4.0; - - auto f = t.flat(); - REQUIRE(f.size() == 4); - f = 0.0; - REQUIRE(t(0, 0) == 0.0); - REQUIRE(t(1, 1) == 0.0); -} - -// ============================================================================ -// Non-member functions -// ============================================================================ - -TEST_CASE("zeros") -{ - auto t = zeros({3, 4}); - REQUIRE(t.size() == 12); - for (size_t i = 0; i < t.size(); ++i) - REQUIRE(t[i] == 0.0); -} - -TEST_CASE("zeros_like") -{ - Tensor a({2, 5}, 7.0); - auto b = zeros_like(a); - REQUIRE(b.size() == 10); - REQUIRE(b.shape(0) == 2); - REQUIRE(b.shape(1) == 5); - for (size_t i = 0; i < b.size(); ++i) - REQUIRE(b[i] == 0.0); -} - -TEST_CASE("full_like") -{ - Tensor a({4}, 0); - auto b = full_like(a, 42); - REQUIRE(b.size() == 4); - for (size_t i = 0; i < b.size(); ++i) - REQUIRE(b[i] == 42); -} - -TEST_CASE("linspace") -{ - auto t = linspace(0.0, 1.0, 5); - REQUIRE(t.size() == 5); - REQUIRE(t[0] == 0.0); - REQUIRE(t[4] == 1.0); - REQUIRE_THAT(t[1], Catch::Matchers::WithinRel(0.25, 1e-12)); - REQUIRE_THAT(t[2], Catch::Matchers::WithinRel(0.5, 1e-12)); - REQUIRE_THAT(t[3], Catch::Matchers::WithinRel(0.75, 1e-12)); -} - -TEST_CASE("concatenate") -{ - Tensor a({3}, 0); - Tensor b({2}, 0); - a = {1, 2, 3}; - b = {4, 5}; - - auto c = concatenate(a, b); - REQUIRE(c.size() == 5); - REQUIRE(c[0] == 1); - REQUIRE(c[2] == 3); - REQUIRE(c[3] == 4); - REQUIRE(c[4] == 5); -} - -TEST_CASE("log") -{ - Tensor t({3}, 0.0); - t = {1.0, std::exp(1.0), std::exp(2.0)}; - - auto r = log(t); - REQUIRE_THAT(r[0], Catch::Matchers::WithinAbs(0.0, 1e-12)); - REQUIRE_THAT(r[1], Catch::Matchers::WithinAbs(1.0, 1e-12)); - REQUIRE_THAT(r[2], Catch::Matchers::WithinAbs(2.0, 1e-12)); -} - -TEST_CASE("abs") -{ - Tensor t({4}, 0.0); - t = {-3.0, -1.0, 0.0, 2.0}; - - auto r = abs(t); - REQUIRE(r[0] == 3.0); - REQUIRE(r[1] == 1.0); - REQUIRE(r[2] == 0.0); - REQUIRE(r[3] == 2.0); -} - -TEST_CASE("where") -{ - Tensor cond({4}, false); - cond.data()[0] = true; - cond.data()[2] = true; - - Tensor vals({4}, 0.0); - vals = {10.0, 20.0, 30.0, 40.0}; - - auto r = where(cond, vals, -1.0); - REQUIRE(r[0] == 10.0); - REQUIRE(r[1] == -1.0); - REQUIRE(r[2] == 30.0); - REQUIRE(r[3] == -1.0); -} - -TEST_CASE("nan_to_num") -{ - Tensor t({4}, 0.0); - t[0] = 1.0; - t[1] = std::nan(""); - t[2] = std::numeric_limits::infinity(); - t[3] = -std::numeric_limits::infinity(); - - auto r = nan_to_num(t); - REQUIRE(r[0] == 1.0); - REQUIRE(r[1] == 0.0); // NaN -> 0 - REQUIRE(r[2] == std::numeric_limits::max()); // +inf -> max - REQUIRE(r[3] == std::numeric_limits::lowest()); // -inf -> lowest -} - -// ============================================================================ -// is_tensor trait -// ============================================================================ - -TEST_CASE("is_tensor trait") -{ - REQUIRE(is_tensor>::value); - REQUIRE(is_tensor>::value); - REQUIRE(is_tensor>::value); - REQUIRE(!is_tensor::value); - REQUIRE(!is_tensor>::value); -} diff --git a/tests/dummy_operator.py b/tests/dummy_operator.py index 873633525..1bb00129d 100644 --- a/tests/dummy_operator.py +++ b/tests/dummy_operator.py @@ -24,7 +24,7 @@ DepletionSolutionTuple = namedtuple( predictor_solution = DepletionSolutionTuple( PredictorIntegrator, np.array([1.0, 2.46847546272295, 4.11525874568034]), - np.array([1.0, 0.986431226850467, 0.0])) + np.array([1.0, 0.986431226850467, -0.0581692232513460])) cecm_solution = DepletionSolutionTuple( @@ -243,4 +243,4 @@ class DummyOperator(TransportOperator): Maps cell name to index in global geometry. """ - return self.volume, self.nuc_list, self.local_mats, self.burnable_mats, {"1": ""} + return self.volume, self.nuc_list, self.local_mats, self.burnable_mats diff --git a/tests/fns_flux_709.npy b/tests/fns_flux_709.npy deleted file mode 100644 index 62c612842..000000000 Binary files a/tests/fns_flux_709.npy and /dev/null differ diff --git a/tests/micro_xs_simple.csv b/tests/micro_xs_simple.csv index 146896aa2..71981c718 100644 --- a/tests/micro_xs_simple.csv +++ b/tests/micro_xs_simple.csv @@ -1,25 +1,13 @@ -nuclides,reactions,groups,xs -U234,"(n,gamma)",1,22.23198982200245 -U234,fission,1,0.4962074466374984 -U235,"(n,gamma)",1,10.47900897119712 -U235,fission,1,48.41787337164606 -U238,"(n,gamma)",1,0.8673334105437321 -U238,fission,1,0.1046788058876236 -U236,"(n,gamma)",1,8.651710446071224 -U236,fission,1,0.3194839240001929 -O16,"(n,gamma)",1,7.497851000107522e-05 -O16,fission,1,0.0 -O17,"(n,gamma)",1,0.0004079227797153 -O17,fission,1,0.0 -I135,"(n,gamma)",1,6.842395323713929 -I135,fission,1,0.0 -Xe135,"(n,gamma)",1,227463.8642699061 -Xe135,fission,1,0.0 -Xe136,"(n,gamma)",1,0.0231789603475358 -Xe136,fission,1,0.0 -Cs135,"(n,gamma)",1,2.1721665580713623 -Cs135,fission,1,0.0 -Gd157,"(n,gamma)",1,12786.099392370175 -Gd157,fission,1,0.0 -Gd156,"(n,gamma)",1,3.4006085445846983 -Gd156,fission,1,0.0 +nuclide,"(n,gamma)",fission +U234,22.231989822002454,0.4962074466374984 +U235,10.479008971197121,48.41787337164606 +U238,0.8673334105437321,0.1046788058876236 +U236,8.651710446071224,0.31948392400019293 +O16,7.497851000107522e-05,0.0 +O17,0.0004079227797153372,0.0 +I135,6.842395323713929,0.0 +Xe135,227463.8642699061,0.0 +Xe136,0.023178960347535887,0.0 +Cs135,2.1721665580713623,0.0 +Gd157,12786.099392370175,0.0 +Gd156,3.4006085445846983,0.0 diff --git a/tests/regression_tests/__init__.py b/tests/regression_tests/__init__.py index e1cb56f1d..a887448c1 100644 --- a/tests/regression_tests/__init__.py +++ b/tests/regression_tests/__init__.py @@ -1,5 +1,3 @@ -import pytest - # Test configuration options for regression tests config = { 'event' : False, @@ -10,36 +8,3 @@ config = { 'update': False, 'build_inputs': False } - - -def assert_same_mats(res_ref, res_test): - for mat in res_ref[0].index_mat: - assert mat in res_test[0].index_mat, f"Material {mat} not in new results." - for nuc in res_ref[0].index_nuc: - assert nuc in res_test[0].index_nuc, f"Nuclide {nuc} not in new results." - for mat in res_test[0].index_mat: - assert mat in res_ref[0].index_mat, f"Material {mat} not in old results." - for nuc in res_test[0].index_nuc: - assert nuc in res_ref[0].index_nuc, f"Nuclide {nuc} not in old results." - - -def assert_atoms_equal(res_ref, res_test, tol=1e-5): - for mat in res_test[0].index_mat: - for nuc in res_test[0].index_nuc: - _, y_test = res_test.get_atoms(mat, nuc) - _, y_ref = res_ref.get_atoms(mat, nuc) - assert y_test == pytest.approx(y_ref, rel=tol), \ - f'Atoms not equal for material {mat}, nuclide {nuc}\n' \ - f'y_ref={y_ref}\ny_test={y_test}' - - -def assert_reaction_rates_equal(res_ref, res_test, tol=1e-5): - for reactions in res_test[0].rates: - for mat in reactions.index_mat: - for nuc in reactions.index_nuc: - for rx in reactions.index_rx: - y_test = res_test.get_reaction_rate(mat, nuc, rx)[1] - y_ref = res_ref.get_reaction_rate(mat, nuc, rx)[1] - assert y_test == pytest.approx(y_ref, rel=tol), \ - f'Reaction rate not equal for material {mat}, nuclide '\ - f'{nuc}, {rx}\ny_ref={y_ref}\ny_test={y_test}' diff --git a/tests/regression_tests/adj_cell_rotation/inputs_true.dat b/tests/regression_tests/adj_cell_rotation/inputs_true.dat index 18c0552ce..24b00199b 100644 --- a/tests/regression_tests/adj_cell_rotation/inputs_true.dat +++ b/tests/regression_tests/adj_cell_rotation/inputs_true.dat @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 10000 - 10 - 5 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 10000 + 10 + 5 + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + diff --git a/tests/regression_tests/adj_cell_rotation/results_true.dat b/tests/regression_tests/adj_cell_rotation/results_true.dat index ddb1546b5..2bdfe4330 100644 --- a/tests/regression_tests/adj_cell_rotation/results_true.dat +++ b/tests/regression_tests/adj_cell_rotation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.368327E-01 1.953533E-03 +4.381997E-01 1.286263E-03 diff --git a/tests/regression_tests/adj_cell_rotation/test.py b/tests/regression_tests/adj_cell_rotation/test.py index 3fe240536..25aada5aa 100644 --- a/tests/regression_tests/adj_cell_rotation/test.py +++ b/tests/regression_tests/adj_cell_rotation/test.py @@ -24,14 +24,14 @@ def model(): # Create one cell on top of the other. Only one # has a rotation - box = openmc.model.RectangularPrism(15., 15., 'z', boundary_type='vacuum') + box = openmc.rectangular_prism(15., 15., 'z', boundary_type='vacuum') lower_z = openmc.ZPlane(-7.5, boundary_type='vacuum') upper_z = openmc.ZPlane(22.5, boundary_type='vacuum') middle_z = openmc.ZPlane(7.5) - lower_cell = openmc.Cell(fill=univ, region=-box & +lower_z & -middle_z) + lower_cell = openmc.Cell(fill=univ, region=box & +lower_z & -middle_z) lower_cell.rotation = (10, 20, 30) - upper_cell = openmc.Cell(fill=univ, region=-box & +middle_z & -upper_z) + upper_cell = openmc.Cell(fill=univ, region=box & +middle_z & -upper_z) upper_cell.translation = (0, 0, 15) model.geometry = openmc.Geometry(root=[lower_cell, upper_cell]) @@ -40,7 +40,7 @@ def model(): model.settings.inactive = 5 model.settings.batches = 10 source_box = openmc.stats.Box((-4., -4., -4.), (4., 4., 4.)) - model.settings.source = openmc.IndependentSource(space=source_box) + model.settings.source = openmc.Source(space=source_box) return model diff --git a/tests/regression_tests/albedo_box/geometry.xml b/tests/regression_tests/albedo_box/geometry.xml deleted file mode 100644 index 7d0e9b5f5..000000000 --- a/tests/regression_tests/albedo_box/geometry.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/tests/regression_tests/albedo_box/results_true.dat b/tests/regression_tests/albedo_box/results_true.dat deleted file mode 100644 index dca80abcd..000000000 --- a/tests/regression_tests/albedo_box/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.593206E+00 2.925742E-03 diff --git a/tests/regression_tests/albedo_box/test.py b/tests/regression_tests/albedo_box/test.py deleted file mode 100755 index 179f58e5b..000000000 --- a/tests/regression_tests/albedo_box/test.py +++ /dev/null @@ -1,6 +0,0 @@ -from tests.testing_harness import TestHarness - - -def test_albedo_box(): - harness = TestHarness('statepoint.10.h5') - harness.main() diff --git a/tests/regression_tests/asymmetric_lattice/inputs_true.dat b/tests/regression_tests/asymmetric_lattice/inputs_true.dat index ee3d68907..bbdc79715 100644 --- a/tests/regression_tests/asymmetric_lattice/inputs_true.dat +++ b/tests/regression_tests/asymmetric_lattice/inputs_true.dat @@ -1,168 +1,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -180,50 +31,197 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 3 3 - -32.13 -32.13 - + + + 21.42 21.42 + 3 3 + -32.13 -32.13 + 8 7 7 8 8 8 7 7 7 - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -32 -32 0 32 32 32 - - - true - - - - - - 27 - - - 1 - nu-fission - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -32 -32 0 32 32 32 + + + + + + + 27 + + + 1 + nu-fission + + diff --git a/tests/regression_tests/asymmetric_lattice/results_true.dat b/tests/regression_tests/asymmetric_lattice/results_true.dat index 3d6b610a6..66ee9cdd2 100644 --- a/tests/regression_tests/asymmetric_lattice/results_true.dat +++ b/tests/regression_tests/asymmetric_lattice/results_true.dat @@ -1 +1 @@ -cc76769636be4f681137598cf366e978d7347425a1dfa1b293d17a28381b2b62595fb7f0d2f126dd06972ff9e79089a18dd53aba45fa2b1f316515b91fe6495a \ No newline at end of file +73bae264aaca0988fd2ae207722461d161ddbcf9aef083b99a2efc536b09665bbe839d6cae89b32ebab3089a820a2c35ae63a88d5869f0c91b0d6c2f2e090e55 \ No newline at end of file diff --git a/tests/regression_tests/asymmetric_lattice/test.py b/tests/regression_tests/asymmetric_lattice/test.py index fadf272ff..2197a1e7e 100644 --- a/tests/regression_tests/asymmetric_lattice/test.py +++ b/tests/regression_tests/asymmetric_lattice/test.py @@ -54,10 +54,8 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness): self._model.tallies.append(tally) # Specify summary output and correct source sampling box - self._model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box([-32, -32, 0], [32, 32, 32]), - constraints={'fissionable': True} - ) + self._model.settings.source = openmc.Source(space=openmc.stats.Box( + [-32, -32, 0], [32, 32, 32], only_fissionable = True)) def _get_results(self, hash_output=True): """Digest info in statepoint and summary and return as a string.""" diff --git a/tests/regression_tests/atomic_relaxation/__init__.py b/tests/regression_tests/atomic_relaxation/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/atomic_relaxation/inputs_true.dat b/tests/regression_tests/atomic_relaxation/inputs_true.dat deleted file mode 100644 index 637e04285..000000000 --- a/tests/regression_tests/atomic_relaxation/inputs_true.dat +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 1000000.0 1.0 - - - led - false - true - - - - photon electron - - - 1 - flux heating - - - diff --git a/tests/regression_tests/atomic_relaxation/results_true.dat b/tests/regression_tests/atomic_relaxation/results_true.dat deleted file mode 100644 index 6f100dac8..000000000 --- a/tests/regression_tests/atomic_relaxation/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -1.956204E+00 -3.826732E+00 -7.918768E+04 -6.270688E+09 -0.000000E+00 -0.000000E+00 -9.208123E+05 -8.478953E+11 diff --git a/tests/regression_tests/atomic_relaxation/test.py b/tests/regression_tests/atomic_relaxation/test.py deleted file mode 100644 index 0d2413f59..000000000 --- a/tests/regression_tests/atomic_relaxation/test.py +++ /dev/null @@ -1,41 +0,0 @@ -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - mat = openmc.Material() - mat.add_nuclide('Pb208', 1.0) - mat.set_density('g/cm3', 11.35) - - sphere = openmc.Sphere(r=1.0e9, boundary_type='reflective') - inside_sphere = openmc.Cell(fill=mat, region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([inside_sphere]) - - # Isotropic point source of 1 MeV photons at the origin - model.settings.source = openmc.IndependentSource( - particle='photon', - energy=openmc.stats.delta_function(1.0e6) - ) - - # Fixed-source photon transport with atomic relaxation disabled - model.settings.particles = 10000 - model.settings.batches = 1 - model.settings.photon_transport = True - model.settings.electron_treatment = 'led' - model.settings.atomic_relaxation = False - model.settings.run_mode = 'fixed source' - - tally = openmc.Tally() - tally.filters = [openmc.ParticleFilter(['photon', 'electron'])] - tally.scores = ['flux', 'heating'] - model.tallies = [tally] - return model - - -def test_atomic_relaxation(model): - harness = PyAPITestHarness('statepoint.1.h5', model=model) - harness.main() diff --git a/tests/regression_tests/cmfd_feed/geometry.xml b/tests/regression_tests/cmfd_feed/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_feed/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_feed/materials.xml b/tests/regression_tests/cmfd_feed/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_feed/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_feed/model.xml b/tests/regression_tests/cmfd_feed/model.xml deleted file mode 100644 index b3fe853b2..000000000 --- a/tests/regression_tests/cmfd_feed/model.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed/results_true.dat b/tests/regression_tests/cmfd_feed/results_true.dat index 1ef9624d4..90d8820d0 100644 --- a/tests/regression_tests/cmfd_feed/results_true.dat +++ b/tests/regression_tests/cmfd_feed/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.181723E+00 9.944883E-03 +1.159021E+00 8.924006E-03 tally 1: -1.169899E+01 -1.373251E+01 -2.142380E+01 -4.605511E+01 -2.968085E+01 -8.838716E+01 -3.561418E+01 -1.271206E+02 -3.777783E+01 -1.428817E+02 -3.805832E+01 -1.450213E+02 -3.439836E+01 -1.184892E+02 -2.852438E+01 -8.161896E+01 -2.088423E+01 -4.376204E+01 -1.076670E+01 -1.168108E+01 +1.140162E+01 +1.306940E+01 +2.093739E+01 +4.404780E+01 +2.914408E+01 +8.521010E+01 +3.483677E+01 +1.216824E+02 +3.778463E+01 +1.429632E+02 +3.810371E+01 +1.455108E+02 +3.465248E+01 +1.207868E+02 +2.862033E+01 +8.218833E+01 +2.086025E+01 +4.365941E+01 +1.130798E+01 +1.286509E+01 tally 2: -2.321241E+01 -2.702156E+01 -1.620912E+01 -1.317752E+01 -4.197404E+01 -8.845008E+01 -2.982666E+01 -4.469221E+01 -5.810089E+01 -1.695857E+02 -4.134123E+01 -8.588866E+01 -6.982488E+01 -2.447068E+02 -4.966939E+01 -1.238763E+02 -7.428421E+01 -2.767613E+02 -5.287955E+01 -1.403163E+02 -7.447402E+01 -2.785012E+02 -5.324628E+01 -1.423393E+02 -6.895164E+01 -2.381937E+02 -4.916366E+01 -1.211701E+02 -5.679253E+01 -1.617881E+02 -4.043125E+01 -8.204061E+01 -4.218618E+01 -8.933666E+01 -2.978592E+01 -4.456592E+01 -2.196426E+01 -2.435867E+01 -1.525576E+01 -1.175879E+01 +2.234393E+01 +2.516414E+01 +1.555024E+01 +1.218205E+01 +4.087743E+01 +8.401702E+01 +2.883717E+01 +4.185393E+01 +5.635166E+01 +1.595225E+02 +3.998857E+01 +8.040398E+01 +6.887126E+01 +2.379185E+02 +4.903103E+01 +1.206174E+02 +7.452051E+01 +2.785675E+02 +5.295380E+01 +1.406900E+02 +7.495422E+01 +2.819070E+02 +5.333191E+01 +1.427474E+02 +6.921815E+01 +2.408568E+02 +4.928246E+01 +1.221076E+02 +5.668548E+01 +1.612556E+02 +4.035856E+01 +8.181159E+01 +4.259952E+01 +9.112630E+01 +3.026717E+01 +4.600625E+01 +2.310563E+01 +2.688378E+01 +1.615934E+01 +1.315528E+01 tally 3: -1.563788E+01 -1.226528E+01 -1.053289E+00 -5.666942E-02 -2.870755E+01 -4.139654E+01 -1.838017E+00 -1.710528E-01 -3.978616E+01 -7.955764E+01 -2.560657E+00 -3.334449E-01 -4.780385E+01 -1.147770E+02 -3.139243E+00 -4.967628E-01 -5.106650E+01 -1.308704E+02 -3.170056E+00 -5.078920E-01 -5.123992E+01 -1.318586E+02 -3.211706E+00 -5.205979E-01 -4.729862E+01 -1.121695E+02 -3.068662E+00 -4.749488E-01 -3.898816E+01 -7.630564E+01 -2.516911E+00 -3.199696E-01 -2.865357E+01 -4.125742E+01 -1.852314E+00 -1.741116E-01 -1.467340E+01 -1.088460E+01 -9.268633E-01 -4.450662E-02 +1.496375E+01 +1.128154E+01 +9.905641E-01 +5.125710E-02 +2.774937E+01 +3.877241E+01 +1.786861E+00 +1.627655E-01 +3.849739E+01 +7.453828E+01 +2.494135E+00 +3.158098E-01 +4.724085E+01 +1.119901E+02 +3.031174E+00 +4.653741E-01 +5.096719E+01 +1.303552E+02 +3.254375E+00 +5.351020E-01 +5.133808E+01 +1.322892E+02 +3.383595E+00 +5.798798E-01 +4.756072E+01 +1.137527E+02 +3.001917E+00 +4.558247E-01 +3.887437E+01 +7.593416E+01 +2.517908E+00 +3.221926E-01 +2.910687E+01 +4.255173E+01 +1.817765E+00 +1.678763E-01 +1.557241E+01 +1.222026E+01 +9.852737E-01 +5.002659E-02 tally 4: -3.029754E+00 -4.613561E-01 +3.047490E+00 +4.661458E-01 0.000000E+00 0.000000E+00 -2.832501E+00 -4.049252E-01 -5.517243E+00 -1.527794E+00 +2.635775E+00 +3.524426E-01 +5.357229E+00 +1.440049E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.517243E+00 -1.527794E+00 -2.832501E+00 -4.049252E-01 -5.117178E+00 -1.316972E+00 -7.333303E+00 -2.701677E+00 +5.357229E+00 +1.440049E+00 +2.635775E+00 +3.524426E-01 +4.982072E+00 +1.251449E+00 +7.228146E+00 +2.620353E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.333303E+00 -2.701677E+00 -5.117178E+00 -1.316972E+00 -7.248464E+00 -2.641591E+00 -8.817788E+00 -3.905530E+00 +7.228146E+00 +2.620353E+00 +4.982072E+00 +1.251449E+00 +7.082265E+00 +2.520047E+00 +8.736529E+00 +3.831244E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.817788E+00 -3.905530E+00 -7.248464E+00 -2.641591E+00 -8.646465E+00 -3.749847E+00 -9.460948E+00 -4.495388E+00 +8.736529E+00 +3.831244E+00 +7.082265E+00 +2.520047E+00 +8.474631E+00 +3.607043E+00 +9.346623E+00 +4.390819E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.460948E+00 -4.495388E+00 -8.646465E+00 -3.749847E+00 -9.379341E+00 -4.415049E+00 -9.278640E+00 -4.320720E+00 +9.346623E+00 +4.390819E+00 +8.474631E+00 +3.607043E+00 +9.496684E+00 +4.522478E+00 +9.532822E+00 +4.559003E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.278640E+00 -4.320720E+00 -9.379341E+00 -4.415049E+00 -9.465746E+00 -4.498591E+00 -8.656146E+00 -3.760545E+00 +9.532822E+00 +4.559003E+00 +9.496684E+00 +4.522478E+00 +9.404949E+00 +4.446260E+00 +8.550930E+00 +3.668401E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.656146E+00 -3.760545E+00 -9.465746E+00 -4.498591E+00 -8.589782E+00 -3.700308E+00 -6.996002E+00 -2.456935E+00 +8.550930E+00 +3.668401E+00 +9.404949E+00 +4.446260E+00 +8.785273E+00 +3.874792E+00 +7.128863E+00 +2.554326E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.996002E+00 -2.456935E+00 -8.589782E+00 -3.700308E+00 -7.352050E+00 -2.714808E+00 -5.105164E+00 -1.312559E+00 +7.128863E+00 +2.554326E+00 +8.785273E+00 +3.874792E+00 +7.408549E+00 +2.755885E+00 +5.094992E+00 +1.305737E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.105164E+00 -1.312559E+00 -7.352050E+00 -2.714808E+00 -5.442756E+00 -1.486776E+00 -2.697305E+00 -3.675580E-01 +5.094992E+00 +1.305737E+00 +7.408549E+00 +2.755885E+00 +5.532149E+00 +1.537289E+00 +2.812344E+00 +3.997146E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.697305E+00 -3.675580E-01 -5.442756E+00 -1.486776E+00 -3.017025E+00 -4.571443E-01 +2.812344E+00 +3.997146E-01 +5.532149E+00 +1.537289E+00 +3.063251E+00 +4.728672E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,144 +345,144 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -1.563588E+01 -1.226217E+01 -2.209027E+00 -2.507131E-01 -2.870034E+01 -4.137550E+01 -3.726620E+00 -7.021948E-01 -3.977762E+01 -7.952285E+01 -5.304975E+00 -1.427333E+00 -4.779747E+01 -1.147456E+02 -6.528302E+00 -2.151715E+00 -5.105366E+01 -1.308037E+02 -6.986782E+00 -2.467487E+00 -5.123380E+01 -1.318264E+02 -6.845633E+00 -2.383542E+00 -4.729296E+01 -1.121433E+02 -6.252695E+00 -1.977351E+00 -3.898236E+01 -7.628315E+01 -5.461495E+00 -1.528579E+00 -2.864576E+01 -4.123538E+01 -3.857301E+00 -7.581323E-01 -1.467047E+01 -1.088031E+01 -2.277024E+00 -2.679801E-01 +1.496000E+01 +1.127586E+01 +2.280081E+00 +2.675609E-01 +2.774503E+01 +3.876011E+01 +3.908836E+00 +7.703029E-01 +3.848706E+01 +7.449836E+01 +5.299924E+00 +1.422782E+00 +4.723172E+01 +1.119459E+02 +6.450156E+00 +2.105590E+00 +5.095931E+01 +1.303132E+02 +7.050681E+00 +2.515092E+00 +5.133412E+01 +1.322694E+02 +6.853429E+00 +2.384127E+00 +4.754621E+01 +1.136848E+02 +6.370026E+00 +2.058896E+00 +3.886829E+01 +7.591042E+01 +5.266816E+00 +1.400495E+00 +2.910277E+01 +4.253981E+01 +4.090844E+00 +8.442500E-01 +1.556949E+01 +1.221526E+01 +2.266123E+00 +2.641551E-01 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.169107E+00 -1.175079E+00 -1.173912E+00 -1.175368E+00 -1.174026E+00 -1.181745E+00 -1.182261E+00 -1.183559E+00 -1.178691E+00 -1.179222E+00 -1.179017E+00 -1.172979E+00 -1.175043E+00 -1.173458E+00 -1.174152E+00 -1.171451E+00 +1.161531E+00 +1.182724E+00 +1.169653E+00 +1.164722E+00 +1.164583E+00 +1.162952E+00 +1.167024E+00 +1.164509E+00 +1.165693E+00 +1.170623E+00 +1.166618E+00 +1.170805E+00 +1.170962E+00 +1.170964E+00 +1.168224E+00 +1.169864E+00 cmfd entropy -3.207640E+00 -3.210547E+00 -3.212218E+00 -3.209573E+00 -3.211619E+00 -3.212126E+00 -3.213163E+00 -3.214288E+00 -3.215737E+00 -3.213677E+00 -3.214925E+00 -3.215612E+00 -3.216708E+00 -3.221454E+00 -3.219048E+00 -3.218387E+00 +3.206619E+00 +3.205815E+00 +3.208678E+00 +3.210820E+00 +3.217023E+00 +3.215014E+00 +3.214592E+00 +3.215913E+00 +3.214998E+00 +3.213644E+00 +3.210755E+00 +3.210496E+00 +3.212488E+00 +3.211553E+00 +3.212999E+00 +3.214052E+00 cmfd balance -4.88208E-03 -4.75139E-03 -3.15783E-03 -3.67091E-03 -2.99797E-03 -2.91060E-03 -2.06576E-03 -1.83482E-03 -1.56292E-03 -1.58659E-03 -2.32986E-03 -1.47376E-03 -1.46673E-03 -1.22627E-03 -1.31963E-03 -1.26456E-03 +4.99833E-03 +5.64677E-03 +3.62795E-03 +3.91962E-03 +3.87172E-03 +2.48450E-03 +3.15554E-03 +2.49335E-03 +2.31973E-03 +2.19156E-03 +2.31352E-03 +2.03401E-03 +1.80242E-03 +1.65868E-03 +1.47543E-03 +1.49706E-03 cmfd dominance ratio -5.467E-01 -5.453E-01 -5.458E-01 -5.436E-01 -5.442E-01 -5.406E-01 -5.401E-01 -5.413E-01 -4.995E-01 -5.396E-01 -5.409E-01 -5.414E-01 -5.423E-01 -5.456E-01 -5.442E-01 -5.441E-01 +5.283E-01 +5.289E-01 +5.305E-01 +5.327E-01 +5.377E-01 +5.360E-01 +5.353E-01 +4.983E-01 +5.379E-01 +5.370E-01 +5.359E-01 +5.349E-01 +5.364E-01 +5.347E-01 +5.360E-01 +5.378E-01 cmfd openmc source comparison -9.587418E-03 -8.150978E-03 -6.677661E-03 -6.334727E-03 -5.153692E-03 -5.082964E-03 -4.633153E-03 -4.037383E-03 -3.528742E-03 -4.559089E-03 -3.517370E-03 -3.306117E-03 -2.913809E-03 -1.906045E-03 -1.932794E-03 -1.711341E-03 +1.291827E-02 +1.027137E-02 +8.738370E-03 +6.854409E-03 +4.188357E-03 +4.941359E-03 +5.139239E-03 +4.244784E-03 +4.240559E-03 +3.375424E-03 +3.716858E-03 +3.595700E-03 +3.626952E-03 +3.999302E-03 +2.431760E-03 +1.673200E-03 cmfd source -4.496492E-02 -7.869674E-02 -1.100280E-01 -1.354045E-01 -1.363339E-01 -1.380533E-01 -1.314512E-01 -1.077480E-01 -7.847306E-02 -3.884630E-02 +4.185460E-02 +7.636314E-02 +1.075536E-01 +1.307167E-01 +1.400879E-01 +1.459944E-01 +1.297413E-01 +1.084649E-01 +7.772031E-02 +4.150306E-02 diff --git a/tests/regression_tests/cmfd_feed/settings.xml b/tests/regression_tests/cmfd_feed/settings.xml new file mode 100644 index 000000000..24b0b6ab5 --- /dev/null +++ b/tests/regression_tests/cmfd_feed/settings.xml @@ -0,0 +1,26 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + diff --git a/tests/regression_tests/cmfd_feed/tallies.xml b/tests/regression_tests/cmfd_feed/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_feed/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed/test.py b/tests/regression_tests/cmfd_feed/test.py index d513dee2a..fa22b0fe3 100644 --- a/tests/regression_tests/cmfd_feed/test.py +++ b/tests/regression_tests/cmfd_feed/test.py @@ -111,7 +111,7 @@ def test_cmfd_write_matrices(): # Load flux vector from numpy output file flux_np = np.load('fluxvec.npy') # Load flux from data file - flux_dat = np.loadtxt("fluxvec.dat") + flux_dat = np.loadtxt("fluxvec.dat", delimiter='\n') # Compare flux from numpy file, .dat file, and from simulation assert(np.all(np.isclose(flux_np, cmfd_run._phi))) diff --git a/tests/regression_tests/cmfd_feed_2g/results_true.dat b/tests/regression_tests/cmfd_feed_2g/results_true.dat index e66eae13c..d27e291e7 100644 --- a/tests/regression_tests/cmfd_feed_2g/results_true.dat +++ b/tests/regression_tests/cmfd_feed_2g/results_true.dat @@ -1,112 +1,112 @@ k-combined: -1.027434E+00 6.509170E-03 +1.021592E+00 7.184545E-03 tally 1: -1.162758E+02 -1.352562E+03 -1.138125E+02 -1.295815E+03 -1.143712E+02 -1.308316E+03 -1.150293E+02 -1.323834E+03 +1.158654E+02 +1.342707E+03 +1.151877E+02 +1.327269E+03 +1.153781E+02 +1.331661E+03 +1.151151E+02 +1.325578E+03 tally 2: -4.284580E+01 -9.207089E+01 -6.335165E+01 -2.014931E+02 -1.894187E+02 -1.818190E+03 -1.033212E+02 -5.340768E+02 -4.282771E+01 -9.186295E+01 -6.295029E+01 -1.983895E+02 -1.834276E+02 -1.684375E+03 -1.022482E+02 -5.228403E+02 -4.330690E+01 -9.402038E+01 -6.395965E+01 -2.053163E+02 -1.851113E+02 -1.714198E+03 -1.030809E+02 -5.314535E+02 -4.337097E+01 -9.426435E+01 -6.417590E+01 -2.063443E+02 -1.846817E+02 -1.706518E+03 -1.027233E+02 -5.279582E+02 +4.299142E+01 +9.258204E+01 +6.324043E+01 +2.003732E+02 +1.860419E+02 +1.731270E+03 +1.037502E+02 +5.383979E+02 +4.229132E+01 +8.952923E+01 +6.264581E+01 +1.965074E+02 +1.838340E+02 +1.690620E+03 +1.029415E+02 +5.299801E+02 +4.314759E+01 +9.337463E+01 +6.404361E+01 +2.056541E+02 +1.836548E+02 +1.687065E+03 +1.028141E+02 +5.287334E+02 +4.256836E+01 +9.079806E+01 +6.336524E+01 +2.012627E+02 +1.837730E+02 +1.689124E+03 +1.021852E+02 +5.222598E+02 tally 3: -5.992726E+01 -1.803120E+02 +5.973628E+01 +1.787876E+02 0.000000E+00 0.000000E+00 -2.172646E-02 -4.414237E-05 -4.181401E+00 -8.912796E-01 -3.536506E+00 -6.287425E-01 +1.724004E-02 +2.766372E-05 +4.379655E+00 +9.682433E-01 +3.484795E+00 +6.104792E-01 0.000000E+00 0.000000E+00 -9.824432E+01 -4.828691E+02 -9.116848E-01 -4.231247E-02 -5.955090E+01 -1.775522E+02 +9.874445E+01 +4.877157E+02 +8.886034E-01 +4.009294E-02 +5.923584E+01 +1.757014E+02 0.000000E+00 0.000000E+00 -1.893222E-02 -3.288000E-05 -4.048183E+00 -8.291130E-01 -3.384041E+00 -5.742363E-01 +1.733168E-02 +3.950365E-05 +4.212697E+00 +8.996477E-01 +3.503046E+00 +6.150657E-01 0.000000E+00 0.000000E+00 -9.734253E+01 -4.738861E+02 -9.157632E-01 -4.329280E-02 -6.045835E+01 -1.835255E+02 +9.780995E+01 +4.784706E+02 +8.648283E-01 +3.899383E-02 +6.057017E+01 +1.839745E+02 0.000000E+00 0.000000E+00 -1.501842E-02 -1.896931E-05 -4.289989E+00 -9.251538E-01 -3.481357E+00 -6.071667E-01 +2.056597E-02 +3.726744E-05 +4.280120E+00 +9.288225E-01 +3.378205E+00 +5.730279E-01 0.000000E+00 0.000000E+00 -9.799829E+01 -4.803591E+02 -8.899390E-01 -4.078750E-02 -6.064531E+01 -1.842746E+02 +9.790474E+01 +4.794523E+02 +9.073765E-01 +4.204720E-02 +5.990874E+01 +1.799224E+02 0.000000E+00 0.000000E+00 -1.495496E-02 -3.082640E-05 -4.321537E+00 -9.371611E-01 -3.453767E+00 -5.983727E-01 +1.881508E-02 +4.239902E-05 +4.206916E+00 +8.926965E-01 +3.478009E+00 +6.067461E-01 0.000000E+00 0.000000E+00 -9.771776E+01 -4.777781E+02 -8.975444E-01 -4.157471E-02 +9.715787E+01 +4.721453E+02 +8.602457E-01 +3.786346E-02 tally 4: 0.000000E+00 0.000000E+00 @@ -116,14 +116,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.840487E+00 -3.915792E+00 -3.700362E+01 -6.851588E+01 -8.756789E+00 -3.844443E+00 -3.672366E+01 -6.747174E+01 +8.735001E+00 +3.821211E+00 +3.708124E+01 +6.880811E+01 +8.713175E+00 +3.807176E+00 +3.703536E+01 +6.862245E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -132,14 +132,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.860460E+00 -3.940908E+00 -3.704658E+01 -6.864069E+01 -8.832046E+00 -3.916611E+00 -3.736239E+01 -6.982147E+01 +8.851322E+00 +3.930766E+00 +3.716154E+01 +6.908449E+01 +8.892499E+00 +3.970458E+00 +3.718644E+01 +6.918810E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -156,14 +156,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.756789E+00 -3.844443E+00 -3.672366E+01 -6.747174E+01 -8.840487E+00 -3.915792E+00 -3.700362E+01 -6.851588E+01 +8.713175E+00 +3.807176E+00 +3.703536E+01 +6.862245E+01 +8.735001E+00 +3.821211E+00 +3.708124E+01 +6.880811E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -180,14 +180,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.892576E+00 -3.964978E+00 -3.703525E+01 -6.860645E+01 -8.824229E+00 -3.906925E+00 -3.685909E+01 -6.796123E+01 +8.915310E+00 +3.982710E+00 +3.682783E+01 +6.786998E+01 +8.800405E+00 +3.881868E+00 +3.692302E+01 +6.819716E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -212,22 +212,22 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.050876E+00 -4.111409E+00 -3.656082E+01 -6.687580E+01 -9.042402E+00 -4.105842E+00 -3.687247E+01 -6.801050E+01 -8.832046E+00 -3.916611E+00 -3.736239E+01 -6.982147E+01 -8.860460E+00 -3.940908E+00 -3.704658E+01 -6.864069E+01 +8.659918E+00 +3.761908E+00 +3.709957E+01 +6.884298E+01 +8.796329E+00 +3.881588E+00 +3.693599E+01 +6.825932E+01 +8.892499E+00 +3.970458E+00 +3.718644E+01 +6.918810E+01 +8.851322E+00 +3.930766E+00 +3.716154E+01 +6.908449E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -252,14 +252,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.042402E+00 -4.105842E+00 -3.687247E+01 -6.801050E+01 -9.050876E+00 -4.111409E+00 -3.656082E+01 -6.687580E+01 +8.796329E+00 +3.881588E+00 +3.693599E+01 +6.825932E+01 +8.659918E+00 +3.761908E+00 +3.709957E+01 +6.884298E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -268,14 +268,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.824229E+00 -3.906925E+00 -3.685909E+01 -6.796123E+01 -8.892576E+00 -3.964978E+00 -3.703525E+01 -6.860645E+01 +8.800405E+00 +3.881868E+00 +3.692302E+01 +6.819716E+01 +8.915310E+00 +3.982710E+00 +3.682783E+01 +6.786998E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -301,133 +301,133 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -5.994898E+01 -1.804403E+02 -1.017670E+02 -5.181130E+02 -1.354160E+01 -9.220935E+00 -4.648971E+01 -1.081636E+02 -5.956983E+01 -1.776668E+02 -1.007226E+02 -5.073592E+02 -1.347883E+01 -9.120344E+00 -4.609907E+01 -1.063127E+02 -6.047337E+01 -1.836168E+02 -1.014777E+02 -5.150557E+02 -1.390508E+01 -9.722899E+00 -4.629251E+01 -1.072027E+02 -6.066027E+01 -1.843661E+02 -1.011648E+02 -5.120629E+02 -1.365982E+01 -9.372236E+00 -4.602994E+01 -1.060579E+02 +5.975352E+01 +1.788900E+02 +1.022213E+02 +5.226556E+02 +1.378440E+01 +9.544964E+00 +4.668065E+01 +1.090372E+02 +5.925317E+01 +1.758044E+02 +1.013043E+02 +5.132587E+02 +1.356187E+01 +9.210736E+00 +4.606346E+01 +1.061497E+02 +6.059074E+01 +1.840993E+02 +1.012721E+02 +5.130091E+02 +1.356441E+01 +9.262377E+00 +4.634250E+01 +1.074283E+02 +5.992755E+01 +1.800342E+02 +1.006299E+02 +5.065012E+02 +1.370402E+01 +9.450980E+00 +4.575433E+01 +1.047310E+02 cmfd indices 2.000000E+00 2.000000E+00 1.000000E+00 2.000000E+00 k cmfd -1.013488E+00 -1.024396E+00 -1.015533E+00 -1.009319E+00 -1.012726E+00 -1.014831E+00 -1.021757E+00 -1.022002E+00 -1.023619E+00 -1.020953E+00 -1.023910E+00 -1.027657E+00 -1.024501E+00 -1.023838E+00 -1.025464E+00 -1.022802E+00 +1.037231E+00 +1.035671E+00 +1.042384E+00 +1.033525E+00 +1.031304E+00 +1.029654E+00 +1.031704E+00 +1.032213E+00 +1.030500E+00 +1.036227E+00 +1.034924E+00 +1.035753E+00 +1.034679E+00 +1.035096E+00 +1.033818E+00 +1.030023E+00 cmfd entropy -1.998974E+00 -1.998742E+00 -1.999128E+00 -1.998952E+00 -1.998951E+00 -1.999439E+00 -1.999626E+00 -1.999826E+00 -1.999513E+00 -1.999451E+00 -1.999514E+00 -1.999590E+00 -1.999563E+00 -1.999604E+00 -1.999742E+00 -1.999736E+00 +1.999702E+00 +1.999790E+00 +1.999713E+00 +1.999852E+00 +1.999820E+00 +1.999667E+00 +1.999553E+00 +1.999649E+00 +1.999398E+00 +1.999527E+00 +1.999648E+00 +1.999607E+00 +1.999533E+00 +1.999684E+00 +1.999714E+00 +1.999812E+00 cmfd balance -9.79896E-04 -4.24873E-04 -8.05696E-04 -1.92071E-03 -3.70731E-04 -2.81424E-04 -8.28991E-04 -6.12217E-04 -5.29185E-04 -4.97799E-04 -3.09154E-04 -1.73703E-04 -2.56689E-04 -2.64938E-04 -1.96305E-04 -1.82702E-04 +7.33587E-04 +1.00987E-03 +8.26985E-04 +5.20809E-04 +6.47932E-04 +9.69990E-04 +8.62860E-04 +4.92175E-04 +5.80764E-04 +4.49167E-04 +4.05541E-04 +4.13811E-04 +4.27271E-04 +3.64944E-04 +3.43522E-04 +2.82842E-04 cmfd dominance ratio -6.304E-03 -6.246E-03 -6.159E-03 -6.249E-03 -6.101E-03 -6.155E-03 -6.010E-03 -6.177E-03 -6.349E-03 -6.241E-03 -6.244E-03 -6.249E-03 -6.270E-03 -6.272E-03 -6.278E-03 -6.290E-03 +6.259E-03 +6.252E-03 +6.292E-03 +6.347E-03 +6.360E-03 +6.403E-03 +6.375E-03 +6.400E-03 +6.374E-03 +6.343E-03 +6.331E-03 +6.312E-03 +6.305E-03 +6.271E-03 +6.267E-03 +6.265E-03 cmfd openmc source comparison -4.046094E-05 -5.979431E-05 -3.836521E-05 -4.577591E-05 -5.012911E-05 -2.114677E-05 -2.074571E-05 -3.042280E-05 -2.408163E-05 -2.434542E-05 -1.190699E-05 -9.499301E-06 -2.354221E-05 -2.937924E-05 -1.889875E-05 -1.913866E-05 +7.908947E-05 +7.452591E-05 +9.249409E-05 +8.223037E-05 +7.355125E-05 +8.926808E-05 +9.363510E-05 +7.628519E-05 +9.019193E-05 +7.130550E-05 +5.947633E-05 +5.744157E-05 +6.093797E-05 +4.505304E-05 +4.430670E-05 +3.019083E-05 cmfd source -2.489706E-01 -2.426801E-01 -2.532142E-01 -2.551351E-01 +2.557606E-01 +2.464707E-01 +2.518098E-01 +2.459589E-01 0.000000E+00 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/cmfd_feed_expanding_window/geometry.xml b/tests/regression_tests/cmfd_feed_expanding_window/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_expanding_window/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_feed_expanding_window/materials.xml b/tests/regression_tests/cmfd_feed_expanding_window/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_expanding_window/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_feed_expanding_window/model.xml b/tests/regression_tests/cmfd_feed_expanding_window/model.xml deleted file mode 100644 index b3fe853b2..000000000 --- a/tests/regression_tests/cmfd_feed_expanding_window/model.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat b/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat index b39f82f96..a235a9f6f 100644 --- a/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat +++ b/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.170835E+00 5.423480E-03 +1.184725E+00 9.808181E-03 tally 1: -1.205100E+01 -1.456707E+01 -2.183882E+01 -4.781179E+01 -2.844010E+01 -8.102358E+01 -3.356334E+01 -1.130832E+02 -3.660829E+01 -1.344973E+02 -3.697740E+01 -1.371500E+02 -3.400119E+01 -1.160196E+02 -2.839868E+01 -8.083199E+01 -2.140398E+01 -4.615447E+01 -1.118179E+01 -1.262942E+01 +1.121111E+01 +1.261033E+01 +2.101271E+01 +4.433294E+01 +2.782926E+01 +7.776546E+01 +3.351044E+01 +1.125084E+02 +3.625691E+01 +1.319666E+02 +3.741881E+01 +1.403776E+02 +3.538049E+01 +1.255798E+02 +3.030311E+01 +9.228152E+01 +2.188389E+01 +4.811272E+01 +1.172417E+01 +1.379179E+01 tally 2: -1.218245E+00 -1.484121E+00 -8.387442E-01 -7.034918E-01 -2.142134E+00 -4.588738E+00 -1.526727E+00 -2.330895E+00 -2.736157E+00 -7.486556E+00 -1.973921E+00 -3.896363E+00 -3.606244E+00 -1.300500E+01 -2.537580E+00 -6.439313E+00 -3.668958E+00 -1.346126E+01 -2.599095E+00 -6.755294E+00 -3.647982E+00 -1.330777E+01 -2.539750E+00 -6.450332E+00 -3.118921E+00 -9.727669E+00 -2.186447E+00 -4.780549E+00 -2.881110E+00 -8.300795E+00 -2.042635E+00 -4.172360E+00 -2.045602E+00 -4.184486E+00 -1.458384E+00 -2.126884E+00 -1.022124E+00 -1.044738E+00 -7.112678E-01 -5.059018E-01 +1.146940E+00 +1.315471E+00 +8.068187E-01 +6.509564E-01 +2.070090E+00 +4.285274E+00 +1.469029E+00 +2.158045E+00 +2.703224E+00 +7.307421E+00 +1.895589E+00 +3.593259E+00 +3.567634E+00 +1.272801E+01 +2.541493E+00 +6.459185E+00 +3.937463E+00 +1.550361E+01 +2.770463E+00 +7.675465E+00 +3.960472E+00 +1.568534E+01 +2.792668E+00 +7.798997E+00 +3.243459E+00 +1.052002E+01 +2.296673E+00 +5.274706E+00 +2.794726E+00 +7.810492E+00 +1.953143E+00 +3.814769E+00 +2.187302E+00 +4.784292E+00 +1.544500E+00 +2.385481E+00 +1.199609E+00 +1.439061E+00 +8.356062E-01 +6.982377E-01 tally 3: -8.048428E-01 -6.477720E-01 -6.603741E-02 -4.360940E-03 -1.466886E+00 -2.151755E+00 -1.002354E-01 -1.004713E-02 -1.909238E+00 -3.645189E+00 -1.202824E-01 -1.446786E-02 -2.443130E+00 -5.968886E+00 -1.627351E-01 -2.648270E-02 -2.492602E+00 -6.213064E+00 -1.910368E-01 -3.649506E-02 -2.437262E+00 -5.940245E+00 -1.568389E-01 -2.459843E-02 -2.104091E+00 -4.427200E+00 -1.450465E-01 -2.103848E-02 -1.965900E+00 -3.864762E+00 -1.367918E-01 -1.871199E-02 -1.402871E+00 -1.968047E+00 -1.061316E-01 -1.126391E-02 -6.832689E-01 -4.668565E-01 -4.599034E-02 -2.115112E-03 +7.817522E-01 +6.111366E-01 +5.930056E-02 +3.516556E-03 +1.426374E+00 +2.034542E+00 +8.539281E-02 +7.291931E-03 +1.815687E+00 +3.296718E+00 +1.221592E-01 +1.492286E-02 +2.447191E+00 +5.988744E+00 +1.624835E-01 +2.640090E-02 +2.670084E+00 +7.129351E+00 +1.838317E-01 +3.379411E-02 +2.683007E+00 +7.198528E+00 +1.719716E-01 +2.957424E-02 +2.215446E+00 +4.908202E+00 +1.707856E-01 +2.916773E-02 +1.872330E+00 +3.505620E+00 +1.209731E-01 +1.463450E-02 +1.484167E+00 +2.202752E+00 +1.114851E-01 +1.242892E-02 +8.018653E-01 +6.429879E-01 +5.692854E-02 +3.240858E-03 tally 4: -1.497312E-01 -2.241943E-02 +1.404203E-01 +1.971786E-02 0.000000E+00 0.000000E+00 -1.535839E-01 -2.358801E-02 -2.882052E-01 -8.306225E-02 +1.383954E-01 +1.915329E-02 +2.626162E-01 +6.896729E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.882052E-01 -8.306225E-02 -1.535839E-01 -2.358801E-02 -2.526805E-01 -6.384743E-02 -3.616220E-01 -1.307705E-01 +2.626162E-01 +6.896729E-02 +1.383954E-01 +1.915329E-02 +2.300607E-01 +5.292793E-02 +3.213893E-01 +1.032911E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.616220E-01 -1.307705E-01 -2.526805E-01 -6.384743E-02 -3.594306E-01 -1.291904E-01 -4.229730E-01 -1.789062E-01 +3.213893E-01 +1.032911E-01 +2.300607E-01 +5.292793E-02 +3.621797E-01 +1.311741E-01 +4.326081E-01 +1.871498E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.229730E-01 -1.789062E-01 -3.594306E-01 -1.291904E-01 -3.973299E-01 -1.578711E-01 -4.255879E-01 -1.811250E-01 +4.326081E-01 +1.871498E-01 +3.621797E-01 +1.311741E-01 +4.274873E-01 +1.827454E-01 +4.701391E-01 +2.210307E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.255879E-01 -1.811250E-01 -3.973299E-01 -1.578711E-01 -4.633933E-01 -2.147333E-01 -4.672837E-01 -2.183540E-01 +4.701391E-01 +2.210307E-01 +4.274873E-01 +1.827454E-01 +4.867763E-01 +2.369512E-01 +5.027339E-01 +2.527413E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.672837E-01 -2.183540E-01 -4.633933E-01 -2.147333E-01 -4.251073E-01 -1.807162E-01 -3.842922E-01 -1.476805E-01 +5.027339E-01 +2.527413E-01 +4.867763E-01 +2.369512E-01 +4.679231E-01 +2.189520E-01 +4.504626E-01 +2.029166E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.842922E-01 -1.476805E-01 -4.251073E-01 -1.807162E-01 -4.045096E-01 -1.636280E-01 -3.192860E-01 -1.019436E-01 +4.504626E-01 +2.029166E-01 +4.679231E-01 +2.189520E-01 +4.340994E-01 +1.884423E-01 +3.622741E-01 +1.312425E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.192860E-01 -1.019436E-01 -4.045096E-01 -1.636280E-01 -3.738326E-01 -1.397508E-01 -2.598153E-01 -6.750398E-02 +3.622741E-01 +1.312425E-01 +4.340994E-01 +1.884423E-01 +3.743415E-01 +1.401316E-01 +2.666952E-01 +7.112632E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.598153E-01 -6.750398E-02 -3.738326E-01 -1.397508E-01 -2.453191E-01 -6.018146E-02 -1.098964E-01 -1.207721E-02 +2.666952E-01 +7.112632E-02 +3.743415E-01 +1.401316E-01 +2.832774E-01 +8.024609E-02 +1.469617E-01 +2.159775E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.098964E-01 -1.207721E-02 -2.453191E-01 -6.018146E-02 -1.458094E-01 -2.126039E-02 +1.469617E-01 +2.159775E-02 +2.832774E-01 +8.024609E-02 +1.514998E-01 +2.295220E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,119 +345,119 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -8.048428E-01 -6.477720E-01 -1.018934E-01 -1.038226E-02 -1.466886E+00 -2.151755E+00 -1.414681E-01 -2.001322E-02 -1.909238E+00 -3.645189E+00 -2.450211E-01 -6.003535E-02 -2.443130E+00 -5.968886E+00 -3.360056E-01 -1.128997E-01 -2.492602E+00 -6.213064E+00 -3.266277E-01 -1.066856E-01 -2.437262E+00 -5.940245E+00 -2.878100E-01 -8.283461E-02 -2.104091E+00 -4.427200E+00 -3.440457E-01 -1.183675E-01 -1.965900E+00 -3.864762E+00 -2.880615E-01 -8.297945E-02 -1.401955E+00 -1.965478E+00 -1.646479E-01 -2.710892E-02 -6.832689E-01 -4.668565E-01 -1.147413E-01 -1.316557E-02 +7.817522E-01 +6.111366E-01 +1.254009E-01 +1.572539E-02 +1.426374E+00 +2.034542E+00 +2.208879E-01 +4.879148E-02 +1.815687E+00 +3.296718E+00 +2.598747E-01 +6.753484E-02 +2.446236E+00 +5.984069E+00 +3.067269E-01 +9.408137E-02 +2.670084E+00 +7.129351E+00 +3.358701E-01 +1.128087E-01 +2.682078E+00 +7.193544E+00 +3.021763E-01 +9.131050E-02 +2.215446E+00 +4.908202E+00 +3.092066E-01 +9.560869E-02 +1.871260E+00 +3.501614E+00 +2.400592E-01 +5.762841E-02 +1.483097E+00 +2.199577E+00 +2.197780E-01 +4.830237E-02 +8.009060E-01 +6.414504E-01 +1.023121E-01 +1.046776E-02 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.181376E+00 -1.176656E+00 -1.161939E+00 -1.163552E+00 -1.163035E+00 -1.170382E+00 -1.160597E+00 -1.154301E+00 -1.159007E+00 -1.148290E+00 -1.157088E+00 +1.165553E+00 +1.179705E+00 +1.191818E+00 +1.207372E+00 +1.203745E+00 +1.208055E+00 +1.208191E+00 +1.201797E+00 +1.201945E+00 +1.203753E+00 +1.209025E+00 cmfd entropy -3.246419E+00 -3.246511E+00 -3.252247E+00 -3.240919E+00 -3.237600E+00 -3.233990E+00 -3.234226E+00 -3.229356E+00 -3.224272E+00 -3.225381E+00 -3.226778E+00 +3.217557E+00 +3.209881E+00 +3.204672E+00 +3.212484E+00 +3.217253E+00 +3.216845E+00 +3.219057E+00 +3.217057E+00 +3.223643E+00 +3.230985E+00 +3.230377E+00 cmfd balance -4.18486E-03 -1.72126E-03 -1.10899E-03 -1.88170E-03 -1.31646E-03 -1.34128E-03 -1.57944E-03 -2.11251E-03 -1.79912E-03 -1.86000E-03 -1.47765E-03 +1.65304E-03 +2.29940E-03 +1.63416E-03 +1.39975E-03 +1.91312E-03 +1.62824E-03 +1.95516E-03 +2.02934E-03 +1.92846E-03 +2.33117E-03 +2.29845E-03 cmfd dominance ratio -5.524E-01 -5.597E-01 -5.622E-01 -5.544E-01 -5.541E-01 -5.519E-01 -5.532E-01 -5.550E-01 -5.484E-01 -5.497E-01 -5.500E-01 +5.465E-01 +5.481E-01 +5.432E-01 +5.459E-01 +5.463E-01 +5.486E-01 +5.515E-01 +5.493E-01 +5.511E-01 +5.518E-01 +5.499E-01 cmfd openmc source comparison -1.905464E-03 -4.145126E-03 -2.465876E-03 -2.346755E-03 -1.848120E-03 -3.263822E-03 -3.641639E-03 -4.031509E-03 -4.999010E-03 -6.640746E-03 -5.691414E-03 +6.499546E-03 +3.419761E-03 +4.342514E-03 +7.229618E-03 +9.943057E-03 +1.050086E-02 +1.055060E-02 +6.562146E-03 +7.232860E-03 +4.424331E-03 +2.531323E-03 cmfd source -4.951338E-02 -8.478025E-02 -1.083132E-01 -1.301432E-01 -1.341190E-01 -1.445825E-01 -1.255119E-01 -1.063303E-01 -7.830158E-02 -3.840469E-02 +4.224785E-02 +7.504165E-02 +1.009909E-01 +1.238160E-01 +1.301409E-01 +1.425954E-01 +1.353275E-01 +1.134617E-01 +8.830470E-02 +4.807346E-02 diff --git a/tests/regression_tests/cmfd_feed_expanding_window/settings.xml b/tests/regression_tests/cmfd_feed_expanding_window/settings.xml new file mode 100644 index 000000000..24b0b6ab5 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_expanding_window/settings.xml @@ -0,0 +1,26 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + diff --git a/tests/regression_tests/cmfd_feed_expanding_window/tallies.xml b/tests/regression_tests/cmfd_feed_expanding_window/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_expanding_window/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_ng/results_true.dat b/tests/regression_tests/cmfd_feed_ng/results_true.dat index 4ea1515f1..722cb16c8 100644 --- a/tests/regression_tests/cmfd_feed_ng/results_true.dat +++ b/tests/regression_tests/cmfd_feed_ng/results_true.dat @@ -1,208 +1,208 @@ k-combined: -1.008852E+00 9.028695E-03 +1.027584E+00 1.502267E-02 tally 1: -1.151271E+02 -1.325871E+03 -1.143934E+02 -1.309051E+03 -1.142507E+02 -1.306616E+03 -1.140242E+02 -1.300786E+03 +1.148263E+02 +1.318910E+03 +1.144863E+02 +1.311468E+03 +1.163124E+02 +1.353643E+03 +1.149445E+02 +1.321759E+03 tally 2: -3.403617E+01 -7.260478E+01 -5.031678E+01 -1.588977E+02 -1.003700E+01 -6.373741E+00 -8.514575E+00 -4.571811E+00 -1.413036E+02 -1.264708E+03 -7.321799E+01 -3.353408E+02 -3.354839E+01 -7.052647E+01 -4.895930E+01 -1.501243E+02 -9.972495E+00 -6.271276E+00 -8.436263E+00 -4.481319E+00 -1.353506E+02 -1.146040E+03 -7.309382E+01 -3.341751E+02 -3.389861E+01 -7.205501E+01 -5.005946E+01 -1.571210E+02 -1.041650E+01 -6.810868E+00 -8.839753E+00 -4.897617E+00 -1.344145E+02 -1.130242E+03 -7.270373E+01 -3.307223E+02 -3.347928E+01 -7.040185E+01 -4.940585E+01 -1.535767E+02 -9.898649E+00 -6.175319E+00 -8.406032E+00 -4.442856E+00 -1.374544E+02 -1.182191E+03 -7.334301E+01 -3.365399E+02 +3.397796E+01 +7.265736E+01 +5.019405E+01 +1.585764E+02 +1.053191E+01 +6.978659E+00 +8.739144E+00 +4.800811E+00 +1.368395E+02 +1.172003E+03 +7.370695E+01 +3.398875E+02 +3.374845E+01 +7.161454E+01 +5.011266E+01 +1.580982E+02 +1.014814E+01 +6.486800E+00 +8.590537E+00 +4.639730E+00 +1.379236E+02 +1.198395E+03 +7.277377E+01 +3.313373E+02 +3.554441E+01 +7.913690E+01 +5.224651E+01 +1.709692E+02 +1.050466E+01 +6.961148E+00 +8.866162E+00 +4.951519E+00 +1.388541E+02 +1.206000E+03 +7.399637E+01 +3.423642E+02 +3.479281E+01 +7.602778E+01 +5.139230E+01 +1.659298E+02 +1.026632E+01 +6.621042E+00 +8.649433E+00 +4.697954E+00 +1.402563E+02 +1.235504E+03 +7.374718E+01 +3.400080E+02 tally 3: -4.755532E+01 -1.419592E+02 +4.748159E+01 +1.419494E+02 0.000000E+00 0.000000E+00 -1.628248E-02 -3.680742E-05 +8.132630E-03 +1.326503E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.347160E+00 -7.104290E-01 -2.453669E+00 -3.797470E-01 +3.299481E+00 +6.900644E-01 +2.429296E+00 +3.713869E-01 0.000000E+00 0.000000E+00 -5.925795E+00 -2.220734E+00 +6.175576E+00 +2.403118E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.542527E-02 -1.118856E-03 -3.018759E-01 -6.371059E-03 +7.020357E-02 +6.481773E-04 +3.097931E-01 +6.853044E-03 0.000000E+00 0.000000E+00 -2.501316E+00 -3.938401E-01 +2.592969E+00 +4.215508E-01 0.000000E+00 0.000000E+00 -6.926265E+01 -3.001504E+02 -6.765221E-01 -2.991787E-02 -4.605523E+01 -1.328435E+02 +6.972257E+01 +3.041404E+02 +5.792796E-01 +2.191871E-02 +4.745221E+01 +1.418371E+02 0.000000E+00 0.000000E+00 -1.687782E-02 -3.921162E-05 +1.507569E-02 +3.140047E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.481608E+00 -7.705602E-01 -2.439374E+00 -3.779705E-01 +3.307769E+00 +6.924370E-01 +2.473164E+00 +3.840166E-01 0.000000E+00 0.000000E+00 -5.855806E+00 -2.162361E+00 +5.967063E+00 +2.251947E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.016677E-01 -9.263706E-04 -3.264878E-01 -7.385168E-03 +9.143833E-02 +8.020544E-04 +3.234880E-01 +7.219562E-03 0.000000E+00 0.000000E+00 -2.519730E+00 -3.986182E-01 +2.477436E+00 +3.882619E-01 0.000000E+00 0.000000E+00 -6.920950E+01 -2.996184E+02 -5.985719E-01 -2.368062E-02 -4.730723E+01 -1.403550E+02 +6.888326E+01 +2.968630E+02 +5.925099E-01 +2.344632E-02 +4.946736E+01 +1.533087E+02 0.000000E+00 0.000000E+00 -6.800415E-03 -1.163614E-05 +1.369119E-02 +3.099298E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.347607E+00 -7.085691E-01 -2.556997E+00 -4.109118E-01 +3.513467E+00 +7.852189E-01 +2.483110E+00 +3.901527E-01 0.000000E+00 0.000000E+00 -6.171063E+00 -2.391770E+00 +6.238898E+00 +2.455700E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.942016E-02 -5.628747E-04 -3.456912E-01 -7.940086E-03 +9.032973E-02 +6.677512E-04 +2.816159E-01 +5.349737E-03 0.000000E+00 0.000000E+00 -2.684459E+00 -4.546338E-01 +2.620828E+00 +4.350795E-01 0.000000E+00 0.000000E+00 -6.850588E+01 -2.936078E+02 -6.458806E-01 -2.672541E-02 -4.673301E+01 -1.374202E+02 +6.992910E+01 +3.057653E+02 +5.890670E-01 +2.307978E-02 +4.853121E+01 +1.480132E+02 0.000000E+00 0.000000E+00 -1.504681E-02 -4.202606E-05 +1.719291E-02 +4.141727E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.139138E+00 -6.206027E-01 -2.341735E+00 -3.454035E-01 +3.490129E+00 +7.743548E-01 +2.381968E+00 +3.564896E-01 0.000000E+00 0.000000E+00 -5.923755E+00 -2.216341E+00 +6.151693E+00 +2.382656E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.030156E-02 -4.283974E-04 -3.247594E-01 -7.133772E-03 +8.653178E-02 +5.524601E-04 +3.307211E-01 +7.362512E-03 0.000000E+00 0.000000E+00 -2.559691E+00 -4.119674E-01 +2.566722E+00 +4.136929E-01 0.000000E+00 0.000000E+00 -6.938051E+01 -3.012078E+02 -5.159565E-01 -1.730381E-02 +6.968935E+01 +3.036323E+02 +6.295592E-01 +2.609911E-02 tally 4: 0.000000E+00 0.000000E+00 @@ -216,18 +216,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.028166E+00 -3.103666E+00 -2.028371E+00 -2.606104E-01 -2.715466E+01 -4.614452E+01 -6.981028E+00 -3.059096E+00 -2.032450E+00 -2.610410E-01 -2.734281E+01 -4.675062E+01 +6.910417E+00 +3.013908E+00 +2.099086E+00 +2.794191E-01 +2.725309E+01 +4.645663E+01 +7.076086E+00 +3.154776E+00 +2.051075E+00 +2.671542E-01 +2.737348E+01 +4.686718E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -240,18 +240,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.969559E+00 -3.054867E+00 -2.042871E+00 -2.624815E-01 -2.766332E+01 -4.787778E+01 -7.022610E+00 -3.098329E+00 -2.109973E+00 -2.824233E-01 -2.733826E+01 -4.676309E+01 +7.215131E+00 +3.265328E+00 +2.066108E+00 +2.704238E-01 +2.755564E+01 +4.753705E+01 +7.022836E+00 +3.102535E+00 +2.076586E+00 +2.741254E-01 +2.756981E+01 +4.756632E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -276,18 +276,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.981028E+00 -3.059096E+00 -2.032450E+00 -2.610410E-01 -2.734281E+01 -4.675062E+01 -7.028166E+00 -3.103666E+00 -2.028371E+00 -2.606104E-01 -2.715466E+01 -4.614452E+01 +7.076086E+00 +3.154776E+00 +2.051075E+00 +2.671542E-01 +2.737348E+01 +4.686718E+01 +6.910417E+00 +3.013908E+00 +2.099086E+00 +2.794191E-01 +2.725309E+01 +4.645663E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -312,18 +312,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.782152E+00 -2.885448E+00 -1.951138E+00 -2.400912E-01 -2.739652E+01 -4.697696E+01 -6.873220E+00 -2.965563E+00 -1.999066E+00 -2.521586E-01 -2.732700E+01 -4.670990E+01 +7.008937E+00 +3.087084E+00 +2.040640E+00 +2.622272E-01 +2.705295E+01 +4.578207E+01 +7.038404E+00 +3.111878E+00 +2.123591E+00 +2.840551E-01 +2.708214E+01 +4.588834E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -360,30 +360,30 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.933695E+00 -3.028826E+00 -2.080336E+00 -2.719620E-01 -2.726925E+01 -4.650782E+01 -6.836291E+00 -2.935998E+00 -2.124868E+00 -2.841370E-01 -2.709685E+01 -4.591604E+01 -7.022610E+00 -3.098329E+00 -2.109973E+00 -2.824233E-01 -2.733826E+01 -4.676309E+01 -6.969559E+00 -3.054867E+00 -2.042871E+00 -2.624815E-01 -2.766332E+01 -4.787778E+01 +7.286308E+00 +3.346248E+00 +2.108252E+00 +2.794781E-01 +2.738387E+01 +4.689407E+01 +7.108444E+00 +3.172810E+00 +2.111474E+00 +2.804633E-01 +2.737249E+01 +4.687424E+01 +7.022836E+00 +3.102535E+00 +2.076586E+00 +2.741254E-01 +2.756981E+01 +4.756632E+01 +7.215131E+00 +3.265328E+00 +2.066108E+00 +2.704238E-01 +2.755564E+01 +4.753705E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -420,18 +420,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.836291E+00 -2.935998E+00 -2.124868E+00 -2.841370E-01 -2.709685E+01 -4.591604E+01 -6.933695E+00 -3.028826E+00 -2.080336E+00 -2.719620E-01 -2.726925E+01 -4.650782E+01 +7.108444E+00 +3.172810E+00 +2.111474E+00 +2.804633E-01 +2.737249E+01 +4.687424E+01 +7.286308E+00 +3.346248E+00 +2.108252E+00 +2.794781E-01 +2.738387E+01 +4.689407E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -444,18 +444,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.873220E+00 -2.965563E+00 -1.999066E+00 -2.521586E-01 -2.732700E+01 -4.670990E+01 -6.782152E+00 -2.885448E+00 -1.951138E+00 -2.400912E-01 -2.739652E+01 -4.697696E+01 +7.038404E+00 +3.111878E+00 +2.123591E+00 +2.840551E-01 +2.708214E+01 +4.588834E+01 +7.008937E+00 +3.087084E+00 +2.040640E+00 +2.622272E-01 +2.705295E+01 +4.578207E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -493,124 +493,124 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -4.757160E+01 -1.420561E+02 -8.379464E+00 -4.426892E+00 -7.205748E+01 -3.248178E+02 -1.047742E+01 -6.922945E+00 -3.879420E+00 -9.517577E-01 -3.297227E+01 -6.802001E+01 -4.607211E+01 -1.329402E+02 -8.295180E+00 -4.334618E+00 -7.205259E+01 -3.247324E+02 -1.059307E+01 -7.039382E+00 -3.783039E+00 -9.030658E-01 -3.288052E+01 -6.762048E+01 -4.731403E+01 -1.403940E+02 -8.728060E+00 -4.774750E+00 -7.152809E+01 -3.200993E+02 -1.074636E+01 -7.270116E+00 -4.007351E+00 -1.010562E+00 -3.249303E+01 -6.611829E+01 -4.674806E+01 -1.375015E+02 -8.265491E+00 -4.296947E+00 -7.226174E+01 -3.267127E+02 -1.079228E+01 -7.340408E+00 -3.843888E+00 -9.273339E-01 -3.300391E+01 -6.823122E+01 +4.748972E+01 +1.419968E+02 +8.604872E+00 +4.655596E+00 +7.261430E+01 +3.298767E+02 +1.092092E+01 +7.540081E+00 +3.984923E+00 +1.000404E+00 +3.294804E+01 +6.794642E+01 +4.746728E+01 +1.419250E+02 +8.440227E+00 +4.478243E+00 +7.167598E+01 +3.214310E+02 +1.073385E+01 +7.257545E+00 +3.904158E+00 +9.587510E-01 +3.253492E+01 +6.626202E+01 +4.948105E+01 +1.533940E+02 +8.722008E+00 +4.791509E+00 +7.283154E+01 +3.316829E+02 +1.138387E+01 +8.162117E+00 +4.131397E+00 +1.078045E+00 +3.254336E+01 +6.624925E+01 +4.854840E+01 +1.481182E+02 +8.533661E+00 +4.573316E+00 +7.258180E+01 +3.293419E+02 +1.053673E+01 +7.002045E+00 +3.988151E+00 +1.001884E+00 +3.284213E+01 +6.749116E+01 cmfd indices 2.000000E+00 2.000000E+00 1.000000E+00 3.000000E+00 k cmfd -1.011190E+00 -1.010705E+00 -1.014132E+00 -1.015900E+00 -1.019132E+00 -1.022616E+00 -1.023007E+00 -1.022300E+00 -1.014692E+00 -1.007628E+00 -1.006204E+00 +1.026167E+00 +1.026753E+00 +1.034560E+00 +1.028298E+00 +1.029032E+00 +1.033531E+00 +1.034902E+00 +1.029837E+00 +1.025313E+00 +1.019855E+00 +1.021235E+00 cmfd entropy -1.999167E+00 -1.999076E+00 -1.998507E+00 -1.997924E+00 -1.997814E+00 -1.997752E+00 -1.997882E+00 -1.998074E+00 -1.998109E+00 -1.998301E+00 -1.998581E+00 +1.998818E+00 +1.998853E+00 +1.999048E+00 +1.998864E+00 +1.998999E+00 +1.998789E+00 +1.998670E+00 +1.998822E+00 +1.998782E+00 +1.999027E+00 +1.999420E+00 cmfd balance -9.30124E-04 -2.56632E-04 -3.62598E-04 -4.17543E-04 -5.25720E-04 -4.90208E-04 -3.61304E-04 -2.24090E-04 -1.86602E-04 -1.78395E-04 -6.42497E-05 +1.00064E-03 +6.95941E-04 +5.74967E-04 +4.34776E-04 +4.03288E-04 +4.32457E-04 +4.49075E-04 +3.57342E-04 +3.62891E-04 +2.86133E-04 +2.08678E-04 cmfd dominance ratio -4.194E-03 -4.234E-03 -4.149E-03 -4.209E-03 -4.185E-03 -4.197E-03 -4.175E-03 -4.105E-03 -4.056E-03 -4.122E-03 -4.113E-03 +3.759E-03 +3.706E-03 +3.719E-03 +3.796E-03 +3.724E-03 +3.809E-03 +3.792E-03 +3.782E-03 +3.841E-03 +3.866E-03 +3.868E-03 cmfd openmc source comparison -2.078995E-05 -2.415218E-05 -3.311536E-05 -3.598613E-05 -3.156455E-05 -2.737017E-05 -2.468500E-05 -2.514215E-05 -1.601626E-05 -1.424027E-05 -4.201148E-06 +8.283222E-05 +6.636005E-05 +5.320110E-05 +4.474530E-05 +4.409263E-05 +4.914331E-05 +4.834447E-05 +4.040592E-05 +4.173469E-05 +3.118350E-05 +1.667967E-05 cmfd source -2.558585E-01 -2.597562E-01 -2.529866E-01 -2.313986E-01 +2.416781E-01 +2.442811E-01 +2.566121E-01 +2.574288E-01 0.000000E+00 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/cmfd_feed_rectlin/geometry.xml b/tests/regression_tests/cmfd_feed_rectlin/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rectlin/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_feed_rectlin/materials.xml b/tests/regression_tests/cmfd_feed_rectlin/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rectlin/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_feed_rectlin/model.xml b/tests/regression_tests/cmfd_feed_rectlin/model.xml deleted file mode 100644 index b3fe853b2..000000000 --- a/tests/regression_tests/cmfd_feed_rectlin/model.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_rectlin/results_true.dat b/tests/regression_tests/cmfd_feed_rectlin/results_true.dat index a98f3fbd3..1a9c3f4e4 100644 --- a/tests/regression_tests/cmfd_feed_rectlin/results_true.dat +++ b/tests/regression_tests/cmfd_feed_rectlin/results_true.dat @@ -1,149 +1,149 @@ k-combined: -1.157362E+00 9.651846E-03 +1.167761E+00 4.293426E-03 tally 1: -1.160989E+01 -1.351117E+01 -2.127132E+01 -4.540172E+01 -2.903242E+01 -8.450044E+01 -3.443549E+01 -1.188763E+02 -3.678332E+01 -1.355586E+02 -3.760088E+01 -1.418740E+02 -3.433077E+01 -1.181837E+02 -2.861986E+01 -8.231285E+01 -2.182277E+01 -4.792086E+01 -1.138713E+01 -1.304425E+01 +1.202277E+01 +1.452746E+01 +2.195725E+01 +4.835710E+01 +2.862021E+01 +8.215585E+01 +3.453333E+01 +1.196497E+02 +3.756803E+01 +1.414919E+02 +3.739045E+01 +1.403446E+02 +3.361501E+01 +1.134271E+02 +2.819861E+01 +7.968185E+01 +2.111919E+01 +4.472336E+01 +1.129975E+01 +1.280982E+01 tally 2: -8.861425E+00 -3.953963E+00 -6.090757E+00 -1.866235E+00 -3.309260E+01 -5.493482E+01 -2.330765E+01 -2.725350E+01 -2.295343E+01 -2.647375E+01 -1.629166E+01 -1.334081E+01 -5.714234E+01 -1.640293E+02 -4.054051E+01 -8.261123E+01 -3.331786E+01 -5.565082E+01 -2.366345E+01 -2.807637E+01 -7.034800E+01 -2.485209E+02 -5.001286E+01 -1.256087E+02 -3.651223E+01 -6.686058E+01 -2.606851E+01 -3.408881E+01 -3.729833E+01 -6.997492E+01 -2.657970E+01 -3.553107E+01 -7.212382E+01 -2.611253E+02 -5.124647E+01 -1.318756E+02 -3.304529E+01 -5.486643E+01 -2.347504E+01 -2.771353E+01 -5.711252E+01 -1.640619E+02 -4.060288E+01 -8.298231E+01 -2.384078E+01 -2.855909E+01 -1.684046E+01 -1.426180E+01 -3.329487E+01 -5.573544E+01 -2.349871E+01 -2.776487E+01 -8.676886E+00 -3.814132E+00 -5.980976E+00 -1.815143E+00 +8.743037E+00 +3.861220E+00 +6.027264E+00 +1.836570E+00 +3.366159E+01 +5.708871E+01 +2.367086E+01 +2.824484E+01 +2.348709E+01 +2.777633E+01 +1.668756E+01 +1.403629E+01 +5.609969E+01 +1.580739E+02 +3.985682E+01 +7.985715E+01 +3.319543E+01 +5.528370E+01 +2.358360E+01 +2.791829E+01 +7.132407E+01 +2.550603E+02 +5.083603E+01 +1.296049E+02 +3.801086E+01 +7.257141E+01 +2.709688E+01 +3.686995E+01 +3.751307E+01 +7.073318E+01 +2.660859E+01 +3.559134E+01 +7.258292E+01 +2.644619E+02 +5.168044E+01 +1.340982E+02 +3.304423E+01 +5.486256E+01 +2.335526E+01 +2.742989E+01 +5.655005E+01 +1.603926E+02 +4.014572E+01 +8.087797E+01 +2.351019E+01 +2.776367E+01 +1.670083E+01 +1.401374E+01 +3.451886E+01 +5.983149E+01 +2.443300E+01 +2.997375E+01 +8.551177E+00 +3.691263E+00 +5.916124E+00 +1.768556E+00 tally 3: -5.847135E+00 -1.719612E+00 -3.960040E-01 -8.297721E-03 -2.245534E+01 -2.530222E+01 -1.468678E+00 -1.094031E-01 -1.571194E+01 -1.240597E+01 -1.004169E+00 -5.156464E-02 -3.901605E+01 -7.652715E+01 -2.648696E+00 -3.571840E-01 -2.275978E+01 -2.597555E+01 -1.456067E+00 -1.075035E-01 -4.821184E+01 -1.167725E+02 -3.105774E+00 -4.859873E-01 -2.519281E+01 -3.183845E+01 -1.595498E+00 -1.292133E-01 -2.560583E+01 -3.297409E+01 -1.673871E+00 -1.429651E-01 -4.930025E+01 -1.220909E+02 -3.206604E+00 -5.220919E-01 -2.255825E+01 -2.560134E+01 -1.422870E+00 -1.027151E-01 -3.910818E+01 -7.698933E+01 -2.568903E+00 -3.333385E-01 -1.620292E+01 -1.321173E+01 -1.068678E+00 -5.798793E-02 -2.264343E+01 -2.578648E+01 -1.503553E+00 -1.158411E-01 -5.751110E+00 -1.676910E+00 -3.450582E-01 -6.411784E-03 +5.799161E+00 +1.702117E+00 +3.588837E-01 +7.127789E-03 +2.273477E+01 +2.606361E+01 +1.586822E+00 +1.296956E-01 +1.606466E+01 +1.300770E+01 +1.018209E+00 +5.281297E-02 +3.840128E+01 +7.415483E+01 +2.383738E+00 +2.877855E-01 +2.268388E+01 +2.583457E+01 +1.485208E+00 +1.122747E-01 +4.899435E+01 +1.204028E+02 +3.203505E+00 +5.163235E-01 +2.610714E+01 +3.423244E+01 +1.707156E+00 +1.476400E-01 +2.559242E+01 +3.293100E+01 +1.761813E+00 +1.597786E-01 +4.985698E+01 +1.248029E+02 +3.081386E+00 +4.824389E-01 +2.245777E+01 +2.536963E+01 +1.447127E+00 +1.065745E-01 +3.869628E+01 +7.516217E+01 +2.545419E+00 +3.270790E-01 +1.610401E+01 +1.303231E+01 +1.011897E+00 +5.274155E-02 +2.353410E+01 +2.781055E+01 +1.517873E+00 +1.184503E-01 +5.687356E+00 +1.636570E+00 +3.728435E-01 +7.203797E-03 tally 4: -3.051764E+00 -4.671879E-01 +3.060660E+00 +4.703581E-01 0.000000E+00 0.000000E+00 -1.407008E+00 -1.004485E-01 -4.354708E+00 -9.506434E-01 +1.451637E+00 +1.081522E-01 +4.402560E+00 +9.746218E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -160,14 +160,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.354708E+00 -9.506434E-01 -1.407008E+00 -1.004485E-01 -3.852730E+00 -7.498016E-01 -6.382605E+00 -2.043123E+00 +4.402560E+00 +9.746218E-01 +1.451637E+00 +1.081522E-01 +3.903491E+00 +7.713768E-01 +6.448935E+00 +2.089570E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -184,14 +184,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.382605E+00 -2.043123E+00 -3.852730E+00 -7.498016E-01 -5.061607E+00 -1.288306E+00 -7.281209E+00 -2.659444E+00 +6.448935E+00 +2.089570E+00 +3.903491E+00 +7.713768E-01 +5.075609E+00 +1.297182E+00 +7.371853E+00 +2.729133E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -208,14 +208,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.281209E+00 -2.659444E+00 -5.061607E+00 -1.288306E+00 -7.096602E+00 -2.527474E+00 -8.632232E+00 -3.736665E+00 +7.371853E+00 +2.729133E+00 +5.075609E+00 +1.297182E+00 +7.015514E+00 +2.477295E+00 +8.723726E+00 +3.828466E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -232,14 +232,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.632232E+00 -3.736665E+00 -7.096602E+00 -2.527474E+00 -7.759456E+00 -3.019026E+00 -8.968687E+00 -4.037738E+00 +8.723726E+00 +3.828466E+00 +7.015514E+00 +2.477295E+00 +7.735344E+00 +3.007547E+00 +9.106625E+00 +4.165807E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -256,14 +256,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.968687E+00 -4.037738E+00 -7.759456E+00 -3.019026E+00 -8.749025E+00 -3.839161E+00 -9.126289E+00 -4.176440E+00 +9.106625E+00 +4.165807E+00 +7.735344E+00 +3.007547E+00 +9.026526E+00 +4.098261E+00 +9.551542E+00 +4.586695E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -280,14 +280,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.126289E+00 -4.176440E+00 -8.749025E+00 -3.839161E+00 -9.259277E+00 -4.304020E+00 -9.165726E+00 -4.216173E+00 +9.551542E+00 +4.586695E+00 +9.026526E+00 +4.098261E+00 +9.344096E+00 +4.384840E+00 +9.405215E+00 +4.441966E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -304,14 +304,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.165726E+00 -4.216173E+00 -9.259277E+00 -4.304020E+00 -9.433925E+00 -4.473551E+00 -8.910566E+00 -3.991458E+00 +9.405215E+00 +4.441966E+00 +9.344096E+00 +4.384840E+00 +9.390313E+00 +4.435716E+00 +9.011690E+00 +4.080913E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -328,14 +328,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.910566E+00 -3.991458E+00 -9.433925E+00 -4.473551E+00 -9.099397E+00 -4.154062E+00 -7.770126E+00 -3.029928E+00 +9.011690E+00 +4.080913E+00 +9.390313E+00 +4.435716E+00 +9.140785E+00 +4.195868E+00 +8.003067E+00 +3.218771E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -352,14 +352,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.770126E+00 -3.029928E+00 -9.099397E+00 -4.154062E+00 -8.575842E+00 -3.694998E+00 -6.934243E+00 -2.418570E+00 +8.003067E+00 +3.218771E+00 +9.140785E+00 +4.195868E+00 +8.629258E+00 +3.736554E+00 +7.133986E+00 +2.557637E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -376,14 +376,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.934243E+00 -2.418570E+00 -8.575842E+00 -3.694998E+00 -7.437526E+00 -2.780629E+00 -5.136923E+00 -1.331553E+00 +7.133986E+00 +2.557637E+00 +8.629258E+00 +3.736554E+00 +7.284136E+00 +2.659936E+00 +5.069993E+00 +1.289638E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -400,14 +400,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.136923E+00 -1.331553E+00 -7.437526E+00 -2.780629E+00 -6.648582E+00 -2.216687E+00 -4.050691E+00 -8.279789E-01 +5.069993E+00 +1.289638E+00 +7.284136E+00 +2.659936E+00 +6.585377E+00 +2.178573E+00 +4.109746E+00 +8.535283E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -424,14 +424,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.050691E+00 -8.279789E-01 -6.648582E+00 -2.216687E+00 -4.390906E+00 -9.686686E-01 -1.391624E+00 -9.861955E-02 +4.109746E+00 +8.535283E-01 +6.585377E+00 +2.178573E+00 +4.394913E+00 +9.694834E-01 +1.455260E+00 +1.073327E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -448,12 +448,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.391624E+00 -9.861955E-02 -4.390906E+00 -9.686686E-01 -3.113477E+00 -4.874296E-01 +1.455260E+00 +1.073327E-01 +4.394913E+00 +9.694834E-01 +3.054512E+00 +4.687172E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -473,164 +473,164 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -5.846103E+00 -1.718959E+00 -8.952028E-01 -4.184063E-02 -2.245226E+01 -2.529524E+01 -3.092645E+00 -4.848878E-01 -1.571095E+01 -1.240426E+01 -2.178244E+00 -2.438479E-01 -3.900638E+01 -7.648853E+01 -5.265574E+00 -1.401505E+00 -2.275895E+01 -2.597348E+01 -3.067909E+00 -4.810969E-01 -4.820213E+01 -1.167232E+02 -6.403602E+00 -2.070034E+00 -2.519091E+01 -3.183360E+01 -3.463531E+00 -6.097568E-01 -2.560388E+01 -3.296889E+01 -3.456252E+00 -6.101655E-01 -4.929539E+01 -1.220666E+02 -6.629094E+00 -2.223366E+00 -2.255498E+01 -2.559363E+01 -2.833426E+00 -4.150907E-01 -3.909813E+01 -7.694976E+01 -5.582222E+00 -1.584757E+00 -1.620082E+01 -1.320814E+01 -2.282196E+00 -2.703156E-01 -2.263498E+01 -2.576758E+01 -3.162736E+00 -5.145038E-01 -5.750110E+00 -1.676357E+00 -9.181679E-01 -4.562885E-02 +5.798163E+00 +1.701480E+00 +7.719076E-01 +3.205800E-02 +2.272861E+01 +2.604939E+01 +3.183925E+00 +5.123120E-01 +1.606367E+01 +1.300597E+01 +2.209506E+00 +2.514085E-01 +3.839444E+01 +7.412912E+01 +5.235063E+00 +1.389014E+00 +2.268086E+01 +2.582733E+01 +3.074902E+00 +4.810618E-01 +4.898566E+01 +1.203589E+02 +6.606838E+00 +2.201101E+00 +2.609836E+01 +3.420917E+01 +3.518842E+00 +6.264238E-01 +2.558605E+01 +3.291399E+01 +3.686659E+00 +6.942431E-01 +4.984902E+01 +1.247644E+02 +6.876822E+00 +2.400434E+00 +2.245394E+01 +2.536044E+01 +3.098158E+00 +4.940204E-01 +3.868744E+01 +7.512715E+01 +5.302748E+00 +1.428609E+00 +1.610093E+01 +1.302770E+01 +2.252209E+00 +2.578778E-01 +2.352951E+01 +2.779963E+01 +3.249775E+00 +5.380883E-01 +5.685356E+00 +1.635162E+00 +7.886630E-01 +3.440650E-02 cmfd indices 1.400000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.166740E+00 -1.184008E+00 -1.166534E+00 -1.155559E+00 -1.164960E+00 -1.163229E+00 -1.165897E+00 -1.170104E+00 -1.170207E+00 -1.168091E+00 -1.170940E+00 -1.174589E+00 -1.174609E+00 -1.171505E+00 -1.174456E+00 -1.178370E+00 +1.154550E+00 +1.172635E+00 +1.171962E+00 +1.174888E+00 +1.182656E+00 +1.190779E+00 +1.200964E+00 +1.196775E+00 +1.190049E+00 +1.181514E+00 +1.180749E+00 +1.179370E+00 +1.177279E+00 +1.178924E+00 +1.177106E+00 +1.179987E+00 cmfd entropy -3.594757E+00 -3.587018E+00 -3.590385E+00 -3.595101E+00 -3.592151E+00 -3.600294E+00 -3.602102E+00 -3.604941E+00 -3.605897E+00 -3.604880E+00 -3.601658E+00 -3.602551E+00 -3.600160E+00 -3.604540E+00 -3.604094E+00 -3.602509E+00 +3.598911E+00 +3.600560E+00 +3.599978E+00 +3.601027E+00 +3.599502E+00 +3.598849E+00 +3.601916E+00 +3.605728E+00 +3.607212E+00 +3.612277E+00 +3.615627E+00 +3.618446E+00 +3.615292E+00 +3.612951E+00 +3.610620E+00 +3.607388E+00 cmfd balance -5.52960E-03 -5.42154E-03 -3.62152E-03 -2.92850E-03 -4.08642E-03 -2.07444E-03 -2.03704E-03 -2.06886E-03 -2.09646E-03 -1.94256E-03 -2.02728E-03 -1.89830E-03 -1.83910E-03 -1.48140E-03 -1.47034E-03 -1.64452E-03 +6.80696E-03 +7.03786E-03 +5.33837E-03 +5.39054E-03 +4.82209E-03 +4.46014E-03 +4.48076E-03 +3.31344E-03 +2.71476E-03 +2.03403E-03 +1.68070E-03 +1.38975E-03 +1.30457E-03 +1.29678E-03 +1.34009E-03 +1.43023E-03 cmfd dominance ratio -6.046E-01 -6.015E-01 -6.059E-01 -6.060E-01 -6.061E-01 -6.109E-01 -6.110E-01 -6.108E-01 -6.120E-01 -6.124E-01 -6.109E-01 -6.090E-01 -6.116E-01 -6.137E-01 +5.913E-01 +5.946E-01 +5.961E-01 +5.995E-01 +6.024E-01 +6.050E-01 +6.056E-01 +6.062E-01 +6.064E-01 +6.087E-01 6.117E-01 -6.131E-01 +6.120E-01 +6.089E-01 +6.074E-01 +6.052E-01 +6.030E-01 cmfd openmc source comparison -1.035187E-02 -9.394886E-03 -6.879487E-03 -7.236029E-03 -6.543528E-03 -3.600620E-03 -2.859638E-03 -2.230047E-03 -2.180643E-03 -1.638534E-03 -1.764349E-03 -1.621487E-03 -1.221762E-03 -1.626297E-03 -1.951813E-03 -9.584126E-04 +1.274461E-02 +9.191627E-03 +7.371466E-03 +4.977614E-03 +4.481864E-03 +3.396798E-03 +2.167863E-03 +4.137274E-03 +4.692749E-03 +2.955754E-03 +2.656269E-03 +2.241441E-03 +4.127496E-03 +3.040657E-03 +3.925292E-03 +3.183157E-03 cmfd source -1.677059E-02 -6.229453E-02 -4.278394E-02 -1.134852E-01 -6.231020E-02 -1.327286E-01 -6.808362E-02 -7.130954E-02 -1.362127E-01 -6.048013E-02 -1.094460E-01 -4.546687E-02 -6.403310E-02 -1.459510E-02 +1.525739E-02 +6.776716E-02 +4.352345E-02 +1.020209E-01 +6.379967E-02 +1.378464E-01 +7.334653E-02 +7.562170E-02 +1.318340E-01 +6.145426E-02 +1.073314E-01 +4.229800E-02 +6.258388E-02 +1.531527E-02 diff --git a/tests/regression_tests/cmfd_feed_rectlin/settings.xml b/tests/regression_tests/cmfd_feed_rectlin/settings.xml new file mode 100644 index 000000000..24b0b6ab5 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rectlin/settings.xml @@ -0,0 +1,26 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + diff --git a/tests/regression_tests/cmfd_feed_rectlin/tallies.xml b/tests/regression_tests/cmfd_feed_rectlin/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rectlin/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_ref_d/geometry.xml b/tests/regression_tests/cmfd_feed_ref_d/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_ref_d/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_feed_ref_d/materials.xml b/tests/regression_tests/cmfd_feed_ref_d/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_ref_d/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_feed_ref_d/model.xml b/tests/regression_tests/cmfd_feed_ref_d/model.xml deleted file mode 100644 index b3fe853b2..000000000 --- a/tests/regression_tests/cmfd_feed_ref_d/model.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_ref_d/results_true.dat b/tests/regression_tests/cmfd_feed_ref_d/results_true.dat index 34cde1a46..cf1e165b2 100644 --- a/tests/regression_tests/cmfd_feed_ref_d/results_true.dat +++ b/tests/regression_tests/cmfd_feed_ref_d/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.162249E+00 5.812620E-03 +1.184724E+00 9.807415E-03 tally 1: -1.153831E+01 -1.338142E+01 -2.155552E+01 -4.659071E+01 -2.813997E+01 -7.941672E+01 -3.270996E+01 -1.073664E+02 -3.639852E+01 -1.329148E+02 -3.729637E+01 -1.393474E+02 -3.443129E+01 -1.186461E+02 -2.832690E+01 -8.040998E+01 -2.177527E+01 -4.771147E+01 -1.146822E+01 -1.328252E+01 +1.121178E+01 +1.261180E+01 +2.101384E+01 +4.433764E+01 +2.783041E+01 +7.777181E+01 +3.351124E+01 +1.125137E+02 +3.625716E+01 +1.319682E+02 +3.741849E+01 +1.403752E+02 +3.537964E+01 +1.255737E+02 +3.030185E+01 +9.227364E+01 +2.188275E+01 +4.810760E+01 +1.172353E+01 +1.379028E+01 tally 2: -1.024353E+00 -1.049299E+00 -6.991057E-01 -4.887487E-01 -2.200432E+00 -4.841901E+00 -1.561655E+00 -2.438768E+00 -2.910400E+00 -8.470426E+00 -2.095155E+00 -4.389674E+00 -3.466006E+00 -1.201320E+01 -2.480456E+00 -6.152662E+00 -3.711781E+00 -1.377732E+01 -2.646019E+00 -7.001418E+00 -3.953648E+00 -1.563133E+01 -2.832759E+00 -8.024524E+00 -3.597870E+00 -1.294467E+01 -2.555396E+00 -6.530048E+00 -2.860871E+00 -8.184585E+00 -2.032282E+00 -4.130169E+00 -2.006740E+00 -4.027007E+00 -1.408150E+00 -1.982886E+00 -1.035163E+00 -1.071562E+00 -7.084068E-01 -5.018402E-01 +1.146903E+00 +1.315387E+00 +8.067939E-01 +6.509164E-01 +2.070041E+00 +4.285068E+00 +1.468994E+00 +2.157944E+00 +2.703198E+00 +7.307278E+00 +1.895572E+00 +3.593192E+00 +3.567627E+00 +1.272796E+01 +2.541486E+00 +6.459152E+00 +3.937479E+00 +1.550374E+01 +2.770473E+00 +7.675520E+00 +3.960493E+00 +1.568551E+01 +2.792683E+00 +7.799079E+00 +3.243496E+00 +1.052027E+01 +2.296698E+00 +5.274821E+00 +2.794771E+00 +7.810744E+00 +1.953175E+00 +3.814893E+00 +2.187333E+00 +4.784426E+00 +1.544523E+00 +2.385551E+00 +1.199628E+00 +1.439107E+00 +8.356207E-01 +6.982620E-01 tally 3: -6.713566E-01 -4.507196E-01 -5.581718E-02 -3.115557E-03 -1.508976E+00 -2.277009E+00 -1.139601E-01 -1.298690E-02 -2.035529E+00 -4.143377E+00 -1.221001E-01 -1.490843E-02 -2.385217E+00 -5.689262E+00 -1.500087E-01 -2.250260E-02 -2.546286E+00 -6.483574E+00 -1.546601E-01 -2.391975E-02 -2.726427E+00 -7.433407E+00 -1.686144E-01 -2.843081E-02 -2.466613E+00 -6.084179E+00 -1.558230E-01 -2.428079E-02 -1.951251E+00 -3.807379E+00 -1.197744E-01 -1.434590E-02 -1.347903E+00 -1.816842E+00 -9.419149E-02 -8.872037E-03 -6.840490E-01 -4.679231E-01 -5.000289E-02 -2.500289E-03 +7.817283E-01 +6.110991E-01 +5.930048E-02 +3.516547E-03 +1.426340E+00 +2.034446E+00 +8.539269E-02 +7.291911E-03 +1.815669E+00 +3.296655E+00 +1.221590E-01 +1.492282E-02 +2.447185E+00 +5.988716E+00 +1.624833E-01 +2.640082E-02 +2.670094E+00 +7.129404E+00 +1.838315E-01 +3.379401E-02 +2.683021E+00 +7.198600E+00 +1.719714E-01 +2.957416E-02 +2.215470E+00 +4.908307E+00 +1.707854E-01 +2.916764E-02 +1.872360E+00 +3.505733E+00 +1.209730E-01 +1.463446E-02 +1.484189E+00 +2.202817E+00 +1.114849E-01 +1.242888E-02 +8.018794E-01 +6.430105E-01 +5.692846E-02 +3.240849E-03 tally 4: -1.561665E-01 -2.438798E-02 +1.404164E-01 +1.971677E-02 0.000000E+00 0.000000E+00 -1.307011E-01 -1.708276E-02 -2.703168E-01 -7.307115E-02 +1.383903E-01 +1.915186E-02 +2.626104E-01 +6.896424E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.703168E-01 -7.307115E-02 -1.307011E-01 -1.708276E-02 -2.637619E-01 -6.957033E-02 -3.685390E-01 -1.358210E-01 +2.626104E-01 +6.896424E-02 +1.383903E-01 +1.915186E-02 +2.300555E-01 +5.292554E-02 +3.213857E-01 +1.032888E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.685390E-01 -1.358210E-01 -2.637619E-01 -6.957033E-02 -3.887017E-01 -1.510890E-01 -4.439407E-01 -1.970834E-01 +3.213857E-01 +1.032888E-01 +2.300555E-01 +5.292554E-02 +3.621759E-01 +1.311714E-01 +4.326073E-01 +1.871490E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.439407E-01 -1.970834E-01 -3.887017E-01 -1.510890E-01 -4.456116E-01 -1.985697E-01 -4.737035E-01 -2.243950E-01 +4.326073E-01 +1.871490E-01 +3.621759E-01 +1.311714E-01 +4.274871E-01 +1.827452E-01 +4.701411E-01 +2.210326E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.737035E-01 -2.243950E-01 -4.456116E-01 -1.985697E-01 -4.760577E-01 -2.266309E-01 -4.703245E-01 -2.212052E-01 +4.701411E-01 +2.210326E-01 +4.274871E-01 +1.827452E-01 +4.867793E-01 +2.369540E-01 +5.027352E-01 +2.527427E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.703245E-01 -2.212052E-01 -4.760577E-01 -2.266309E-01 -4.878056E-01 -2.379543E-01 -4.373120E-01 -1.912418E-01 +5.027352E-01 +2.527427E-01 +4.867793E-01 +2.369540E-01 +4.679247E-01 +2.189535E-01 +4.504680E-01 +2.029214E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.373120E-01 -1.912418E-01 -4.878056E-01 -2.379543E-01 -4.262194E-01 -1.816630E-01 -3.334152E-01 -1.111657E-01 +4.504680E-01 +2.029214E-01 +4.679247E-01 +2.189535E-01 +4.341058E-01 +1.884478E-01 +3.622812E-01 +1.312477E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.334152E-01 -1.111657E-01 -4.262194E-01 -1.816630E-01 -3.560156E-01 -1.267471E-01 -2.409954E-01 -5.807879E-02 +3.622812E-01 +1.312477E-01 +4.341058E-01 +1.884478E-01 +3.743485E-01 +1.401368E-01 +2.666983E-01 +7.112801E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.409954E-01 -5.807879E-02 -3.560156E-01 -1.267471E-01 -2.646501E-01 -7.003965E-02 -1.327244E-01 -1.761576E-02 +2.666983E-01 +7.112801E-02 +3.743485E-01 +1.401368E-01 +2.832798E-01 +8.024744E-02 +1.469655E-01 +2.159885E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.327244E-01 -1.761576E-02 -2.646501E-01 -7.003965E-02 -1.480567E-01 -2.192079E-02 +1.469655E-01 +2.159885E-02 +2.832798E-01 +8.024744E-02 +1.515017E-01 +2.295275E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,119 +345,119 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -6.713566E-01 -4.507196E-01 -9.805793E-02 -9.615358E-03 -1.508976E+00 -2.277009E+00 -1.968348E-01 -3.874394E-02 -2.032573E+00 -4.131353E+00 -2.120922E-01 -4.498309E-02 -2.385217E+00 -5.689262E+00 -2.863031E-01 -8.196946E-02 -2.545200E+00 -6.478041E+00 -3.278920E-01 -1.075131E-01 -2.726427E+00 -7.433407E+00 -3.770758E-01 -1.421861E-01 -2.466613E+00 -6.084179E+00 -3.593230E-01 -1.291130E-01 -1.951251E+00 -3.807379E+00 -2.474112E-01 -6.121229E-02 -1.347903E+00 -1.816842E+00 -2.127109E-01 -4.524594E-02 -6.823620E-01 -4.656179E-01 -1.249863E-01 -1.562159E-02 +7.817283E-01 +6.110991E-01 +1.253966E-01 +1.572431E-02 +1.426340E+00 +2.034446E+00 +2.208824E-01 +4.878905E-02 +1.815669E+00 +3.296655E+00 +2.598719E-01 +6.753342E-02 +2.446230E+00 +5.984040E+00 +3.067264E-01 +9.408108E-02 +2.670094E+00 +7.129404E+00 +3.358723E-01 +1.128102E-01 +2.682092E+00 +7.193615E+00 +3.021784E-01 +9.131179E-02 +2.215470E+00 +4.908307E+00 +3.092112E-01 +9.561158E-02 +1.871290E+00 +3.501727E+00 +2.400626E-01 +5.763006E-02 +1.483119E+00 +2.199642E+00 +2.197799E-01 +4.830323E-02 +8.009200E-01 +6.414728E-01 +1.023113E-01 +1.046761E-02 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.181365E+00 -1.176693E+00 -1.161946E+00 -1.163565E+00 -1.163043E+00 -1.169908E+00 -1.149155E+00 -1.142379E+00 -1.152957E+00 -1.137602E+00 -1.141883E+00 +1.165539E+00 +1.179703E+00 +1.191810E+00 +1.207373E+00 +1.203749E+00 +1.208059E+00 +1.208191E+00 +1.201767E+00 +1.201921E+00 +1.203758E+00 +1.209018E+00 cmfd entropy -3.246422E+00 -3.246496E+00 -3.252238E+00 -3.240920E+00 -3.237606E+00 -3.234301E+00 -3.234103E+00 -3.229918E+00 -3.226983E+00 -3.221321E+00 -3.223622E+00 +3.217563E+00 +3.209882E+00 +3.204676E+00 +3.212483E+00 +3.217256E+00 +3.216849E+00 +3.219070E+00 +3.217085E+00 +3.223663E+00 +3.230980E+00 +3.230377E+00 cmfd balance -4.18486E-03 -1.72126E-03 -1.10906E-03 -1.88158E-03 -1.31626E-03 -1.30818E-03 -1.77315E-03 -2.16148E-03 -1.67789E-03 -2.31333E-03 -1.94932E-03 +1.65304E-03 +2.29951E-03 +1.63426E-03 +1.40012E-03 +1.91396E-03 +1.62948E-03 +1.95633E-03 +2.03045E-03 +1.93004E-03 +2.33201E-03 +2.29894E-03 cmfd dominance ratio -5.505E-01 -5.580E-01 -5.610E-01 -5.526E-01 -5.519E-01 -5.499E-01 -5.504E-01 -5.504E-01 +5.460E-01 +5.473E-01 +5.415E-01 +5.446E-01 +5.451E-01 5.475E-01 -5.465E-01 -5.477E-01 +5.502E-01 +5.474E-01 +5.498E-01 +5.502E-01 +5.483E-01 cmfd openmc source comparison -1.902234E-03 -4.110960E-03 -2.452031E-03 -2.337951E-03 -1.838979E-03 -3.138637E-03 -2.684401E-03 -2.912891E-03 -2.823494E-03 -6.391584E-03 -5.904139E-03 +6.484315E-03 +3.411419E-03 +4.321857E-03 +7.194272E-03 +9.907101E-03 +1.046661E-02 +1.050754E-02 +6.523687E-03 +7.212189E-03 +4.425062E-03 +2.540177E-03 cmfd source -4.488002E-02 -8.895136E-02 -1.085930E-01 -1.229651E-01 -1.330479E-01 -1.497140E-01 -1.309102E-01 -1.028556E-01 -7.738878E-02 -4.069397E-02 +4.224343E-02 +7.503541E-02 +1.009853E-01 +1.238103E-01 +1.301388E-01 +1.425912E-01 +1.353339E-01 +1.134730E-01 +8.830826E-02 +4.808031E-02 diff --git a/tests/regression_tests/cmfd_feed_ref_d/settings.xml b/tests/regression_tests/cmfd_feed_ref_d/settings.xml new file mode 100644 index 000000000..24b0b6ab5 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_ref_d/settings.xml @@ -0,0 +1,26 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + diff --git a/tests/regression_tests/cmfd_feed_ref_d/tallies.xml b/tests/regression_tests/cmfd_feed_ref_d/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_ref_d/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_rolling_window/geometry.xml b/tests/regression_tests/cmfd_feed_rolling_window/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rolling_window/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_feed_rolling_window/materials.xml b/tests/regression_tests/cmfd_feed_rolling_window/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rolling_window/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_feed_rolling_window/model.xml b/tests/regression_tests/cmfd_feed_rolling_window/model.xml deleted file mode 100644 index b3fe853b2..000000000 --- a/tests/regression_tests/cmfd_feed_rolling_window/model.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat b/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat index 2e31b35ba..a065289ec 100644 --- a/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat +++ b/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.158333E+00 1.402684E-02 +1.169526E+00 5.973537E-03 tally 1: -1.169478E+01 -1.373162E+01 -2.192038E+01 -4.844559E+01 -2.913292E+01 -8.542569E+01 -3.446069E+01 -1.201782E+02 -3.624088E+01 -1.320213E+02 -3.569791E+01 -1.278170E+02 -3.340601E+01 -1.119165E+02 -2.908648E+01 -8.514603E+01 -2.175458E+01 -4.767916E+01 -1.171268E+01 -1.378033E+01 +1.115884E+01 +1.253283E+01 +2.176964E+01 +4.753045E+01 +2.988209E+01 +8.948736E+01 +3.426842E+01 +1.176956E+02 +3.817775E+01 +1.464502E+02 +3.802079E+01 +1.449155E+02 +3.407399E+01 +1.166067E+02 +2.938579E+01 +8.673128E+01 +2.126809E+01 +4.540856E+01 +1.105934E+01 +1.229825E+01 tally 2: -1.132414E+00 -1.282361E+00 -7.822980E-01 -6.119901E-01 -2.124428E+00 -4.513196E+00 -1.490832E+00 -2.222581E+00 -3.158472E+00 -9.975946E+00 -2.221665E+00 -4.935795E+00 -3.994786E+00 -1.595831E+01 -2.828109E+00 -7.998199E+00 -3.491035E+00 -1.218732E+01 -2.461223E+00 -6.057617E+00 -3.461784E+00 -1.198395E+01 -2.473337E+00 -6.117398E+00 -3.027132E+00 -9.163527E+00 -2.150455E+00 -4.624458E+00 -2.471217E+00 -6.106911E+00 -1.737168E+00 -3.017752E+00 -1.880969E+00 -3.538044E+00 -1.316574E+00 -1.733367E+00 -1.233103E+00 -1.520543E+00 -8.543318E-01 -7.298828E-01 +1.064631E+00 +1.133439E+00 +7.584662E-01 +5.752710E-01 +1.898252E+00 +3.603361E+00 +1.330629E+00 +1.770573E+00 +2.737585E+00 +7.494369E+00 +1.949437E+00 +3.800303E+00 +3.313845E+00 +1.098157E+01 +2.356303E+00 +5.552166E+00 +3.735566E+00 +1.395445E+01 +2.657859E+00 +7.064213E+00 +4.052274E+00 +1.642093E+01 +2.864885E+00 +8.207568E+00 +3.385112E+00 +1.145899E+01 +2.358075E+00 +5.560519E+00 +2.776429E+00 +7.708560E+00 +1.960468E+00 +3.843434E+00 +2.240243E+00 +5.018688E+00 +1.549641E+00 +2.401386E+00 +1.092006E+00 +1.192478E+00 +7.441585E-01 +5.537719E-01 tally 3: -7.540113E-01 -5.685330E-01 -6.367610E-02 -4.054646E-03 -1.436984E+00 -2.064922E+00 -8.961822E-02 -8.031425E-03 -2.132240E+00 -4.546449E+00 -1.356065E-01 -1.838913E-02 -2.726356E+00 -7.433016E+00 -1.780572E-01 -3.170438E-02 -2.379700E+00 -5.662970E+00 -1.544735E-01 -2.386206E-02 -2.383471E+00 -5.680933E+00 -1.568319E-01 -2.459624E-02 -2.047271E+00 -4.191318E+00 -1.662654E-01 -2.764418E-02 -1.673107E+00 -2.799287E+00 -1.132020E-01 -1.281468E-02 -1.271576E+00 -1.616906E+00 -7.546797E-02 -5.695415E-03 -8.249906E-01 -6.806094E-01 -5.660098E-02 -3.203671E-03 +7.295798E-01 +5.322866E-01 +4.986135E-02 +2.486155E-03 +1.280099E+00 +1.638654E+00 +9.022531E-02 +8.140606E-03 +1.859202E+00 +3.456630E+00 +1.234662E-01 +1.524390E-02 +2.274313E+00 +5.172502E+00 +1.234662E-01 +1.524390E-02 +2.548554E+00 +6.495129E+00 +1.531456E-01 +2.345357E-02 +2.773126E+00 +7.690228E+00 +1.733276E-01 +3.004244E-02 +2.270798E+00 +5.156524E+00 +1.673917E-01 +2.801998E-02 +1.887286E+00 +3.561849E+00 +1.507712E-01 +2.273196E-02 +1.480414E+00 +2.191625E+00 +1.127816E-01 +1.271970E-02 +7.126366E-01 +5.078509E-01 +6.054593E-02 +3.665809E-03 tally 4: -1.551630E-01 -2.407556E-02 +1.416041E-01 +2.005172E-02 0.000000E+00 0.000000E+00 -1.487992E-01 -2.214121E-02 -2.878091E-01 -8.283409E-02 +1.118431E-01 +1.250887E-02 +2.419761E-01 +5.855243E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.878091E-01 -8.283409E-02 -1.487992E-01 -2.214121E-02 -2.936596E-01 -8.623595E-02 -3.954149E-01 -1.563529E-01 +2.419761E-01 +5.855243E-02 +1.118431E-01 +1.250887E-02 +2.383966E-01 +5.683292E-02 +3.454391E-01 +1.193281E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.954149E-01 -1.563529E-01 -2.936596E-01 -8.623595E-02 -3.991153E-01 -1.592930E-01 -4.758410E-01 -2.264247E-01 +3.454391E-01 +1.193281E-01 +2.383966E-01 +5.683292E-02 +3.449676E-01 +1.190027E-01 +4.324309E-01 +1.869965E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.758410E-01 -2.264247E-01 -3.991153E-01 -1.592930E-01 -4.850882E-01 -2.353106E-01 -5.210840E-01 -2.715285E-01 +4.324309E-01 +1.869965E-01 +3.449676E-01 +1.190027E-01 +4.410209E-01 +1.944994E-01 +4.785286E-01 +2.289896E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.210840E-01 -2.715285E-01 -4.850882E-01 -2.353106E-01 -4.790245E-01 -2.294645E-01 -4.570092E-01 -2.088574E-01 +4.785286E-01 +2.289896E-01 +4.410209E-01 +1.944994E-01 +5.038795E-01 +2.538945E-01 +5.028063E-01 +2.528142E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.570092E-01 -2.088574E-01 -4.790245E-01 -2.294645E-01 -4.505886E-01 -2.030301E-01 -3.884038E-01 -1.508575E-01 +5.028063E-01 +2.528142E-01 +5.038795E-01 +2.538945E-01 +4.780368E-01 +2.285192E-01 +4.303602E-01 +1.852099E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.884038E-01 -1.508575E-01 -4.505886E-01 -2.030301E-01 -3.986999E-01 -1.589616E-01 -3.220889E-01 -1.037412E-01 +4.303602E-01 +1.852099E-01 +4.780368E-01 +2.285192E-01 +4.183673E-01 +1.750312E-01 +3.317104E-01 +1.100318E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.220889E-01 -1.037412E-01 -3.986999E-01 -1.589616E-01 -3.319083E-01 -1.101631E-01 -2.101261E-01 -4.415297E-02 +3.317104E-01 +1.100318E-01 +4.183673E-01 +1.750312E-01 +3.797671E-01 +1.442230E-01 +2.636003E-01 +6.948514E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.101261E-01 -4.415297E-02 -3.319083E-01 -1.101631E-01 -2.795459E-01 -7.814588E-02 -1.306499E-01 -1.706938E-02 +2.636003E-01 +6.948514E-02 +3.797671E-01 +1.442230E-01 +2.686240E-01 +7.215888E-02 +1.324766E-01 +1.755005E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.306499E-01 -1.706938E-02 -2.795459E-01 -7.814588E-02 -1.585507E-01 -2.513833E-02 +1.324766E-01 +1.755005E-02 +2.686240E-01 +7.215888E-02 +1.444839E-01 +2.087560E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,119 +345,119 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -7.530237E-01 -5.670447E-01 -1.178984E-01 -1.390004E-02 -1.436984E+00 -2.064922E+00 -1.458395E-01 -2.126916E-02 -2.132240E+00 -4.546449E+00 -2.950109E-01 -8.703141E-02 -2.726356E+00 -7.433016E+00 -3.397288E-01 -1.154157E-01 -2.379700E+00 -5.662970E+00 -3.113206E-01 -9.692053E-02 -2.383471E+00 -5.680933E+00 -3.455611E-01 -1.194125E-01 -2.047271E+00 -4.191318E+00 -2.910986E-01 -8.473841E-02 -1.673107E+00 -2.799287E+00 -2.381996E-01 -5.673907E-02 -1.270672E+00 -1.614606E+00 -1.795241E-01 -3.222889E-02 -8.249906E-01 -6.806094E-01 -1.201397E-01 -1.443354E-02 +7.285713E-01 +5.308161E-01 +1.056136E-01 +1.115423E-02 +1.280099E+00 +1.638654E+00 +1.717497E-01 +2.949797E-02 +1.859202E+00 +3.456630E+00 +2.285372E-01 +5.222927E-02 +2.274313E+00 +5.172502E+00 +2.636808E-01 +6.952757E-02 +2.547588E+00 +6.490203E+00 +2.914026E-01 +8.491545E-02 +2.773126E+00 +7.690228E+00 +3.908576E-01 +1.527696E-01 +2.269831E+00 +5.152135E+00 +3.279256E-01 +1.075352E-01 +1.886272E+00 +3.558024E+00 +2.679083E-01 +7.177487E-02 +1.479436E+00 +2.188731E+00 +2.362981E-01 +5.583681E-02 +7.126366E-01 +5.078509E-01 +1.015892E-01 +1.032038E-02 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.184474E+00 -1.188170E+00 -1.165127E+00 -1.135010E+00 -1.145439E+00 -1.158451E+00 -1.154420E+00 -1.179615E+00 -1.197843E+00 -1.181252E+00 -1.186316E+00 +1.188625E+00 +1.172261E+00 +1.172154E+00 +1.176234E+00 +1.161072E+00 +1.174217E+00 +1.176208E+00 +1.183067E+00 +1.208406E+00 +1.220367E+00 +1.208889E+00 cmfd entropy -3.243654E+00 -3.244091E+00 -3.249203E+00 -3.249952E+00 -3.245538E+00 -3.240838E+00 -3.238919E+00 -3.223131E+00 -3.216002E+00 -3.220324E+00 -3.224804E+00 +3.216548E+00 +3.213244E+00 +3.220132E+00 +3.216556E+00 +3.218184E+00 +3.208592E+00 +3.220641E+00 +3.217076E+00 +3.216257E+00 +3.212578E+00 +3.230102E+00 cmfd balance -4.21104E-03 -1.38052E-03 -1.34642E-03 -2.39255E-03 -2.07426E-03 -1.27927E-03 -2.26249E-03 -2.72103E-03 -2.71504E-03 -2.19156E-03 -1.91989E-03 +1.65186E-03 +1.76715E-03 +2.25997E-03 +2.27924E-03 +1.67354E-03 +1.72671E-03 +1.79744E-03 +1.99065E-03 +2.56417E-03 +2.45718E-03 +3.26245E-03 cmfd dominance ratio -5.520E-01 -5.535E-01 -5.628E-01 -5.696E-01 -5.723E-01 -5.651E-01 -5.648E-01 -5.555E-01 -5.448E-01 -5.488E-01 -5.484E-01 +5.445E-01 +5.466E-01 +5.539E-01 +5.547E-01 +5.569E-01 +5.518E-01 +5.553E-01 +5.544E-01 +5.474E-01 +5.355E-01 +5.460E-01 cmfd openmc source comparison -1.713810E-03 -2.429503E-03 -4.526209E-03 -7.978149E-03 -3.320012E-03 -3.880041E-03 -1.580215E-02 -1.663452E-02 -1.878103E-02 -7.436342E-03 -3.724478E-03 +5.662096E-03 +3.660183E-03 +4.806643E-03 +2.475327E-03 +6.166988E-03 +2.205088E-03 +4.010491E-03 +6.270883E-03 +3.070427E-03 +5.679208E-03 +1.488803E-02 cmfd source -4.688167E-02 -9.066303E-02 -1.150679E-01 -1.430247E-01 -1.370466E-01 -1.267615E-01 -1.244218E-01 -1.048774E-01 -7.083441E-02 -4.042108E-02 +4.111004E-02 +7.023296E-02 +1.023250E-01 +1.185886E-01 +1.386562E-01 +1.392823E-01 +1.290017E-01 +1.147469E-01 +9.733704E-02 +4.871933E-02 diff --git a/tests/regression_tests/cmfd_feed_rolling_window/settings.xml b/tests/regression_tests/cmfd_feed_rolling_window/settings.xml new file mode 100644 index 000000000..24b0b6ab5 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rolling_window/settings.xml @@ -0,0 +1,26 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + diff --git a/tests/regression_tests/cmfd_feed_rolling_window/tallies.xml b/tests/regression_tests/cmfd_feed_rolling_window/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rolling_window/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_nofeed/geometry.xml b/tests/regression_tests/cmfd_nofeed/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_nofeed/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_nofeed/materials.xml b/tests/regression_tests/cmfd_nofeed/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_nofeed/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_nofeed/model.xml b/tests/regression_tests/cmfd_nofeed/model.xml deleted file mode 100644 index b3fe853b2..000000000 --- a/tests/regression_tests/cmfd_nofeed/model.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_nofeed/results_true.dat b/tests/regression_tests/cmfd_nofeed/results_true.dat index ea1a0230b..dac35871c 100644 --- a/tests/regression_tests/cmfd_nofeed/results_true.dat +++ b/tests/regression_tests/cmfd_nofeed/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.169143E+00 7.248013E-03 +1.170405E+00 1.487119E-02 tally 1: -1.115130E+01 -1.249933E+01 -2.147608E+01 -4.643964E+01 -2.923697E+01 -8.598273E+01 -3.439175E+01 -1.189653E+02 -3.729169E+01 -1.395456E+02 -3.709975E+01 -1.380839E+02 -3.415420E+01 -1.168226E+02 -2.895696E+01 -8.419764E+01 -2.140382E+01 -4.646784E+01 -1.125483E+01 -1.275812E+01 +1.172722E+01 +1.378635E+01 +2.122139E+01 +4.511390E+01 +2.936481E+01 +8.649521E+01 +3.553909E+01 +1.265901E+02 +3.862903E+01 +1.497314E+02 +3.683895E+01 +1.358679E+02 +3.373597E+01 +1.140439E+02 +2.810435E+01 +7.932253E+01 +2.098314E+01 +4.409819E+01 +1.105096E+01 +1.224007E+01 tally 2: -2.275147E+01 -2.604974E+01 -1.587800E+01 -1.271197E+01 -4.191959E+01 -8.846441E+01 -2.966500E+01 -4.430669E+01 -5.699815E+01 -1.637359E+02 -4.037600E+01 -8.219353E+01 -6.656851E+01 -2.228703E+02 -4.718000E+01 -1.119941E+02 -7.334215E+01 -2.701014E+02 -5.223500E+01 -1.370726E+02 -7.394394E+01 -2.748295E+02 -5.273400E+01 -1.397334E+02 -6.931604E+01 -2.406234E+02 -4.949000E+01 -1.226886E+02 -5.799672E+01 -1.687992E+02 -4.142300E+01 -8.612116E+01 -4.320102E+01 -9.402138E+01 -3.068300E+01 -4.749148E+01 -2.295257E+01 -2.657057E+01 -1.606200E+01 -1.301453E+01 +2.275408E+01 +2.603315E+01 +1.590700E+01 +1.273395E+01 +4.112322E+01 +8.498758E+01 +2.911800E+01 +4.264070E+01 +5.707453E+01 +1.638375E+02 +4.069300E+01 +8.336155E+01 +6.915962E+01 +2.399628E+02 +4.926800E+01 +1.218497E+02 +7.521027E+01 +2.842789E+02 +5.357900E+01 +1.443468E+02 +7.387401E+01 +2.738660E+02 +5.263400E+01 +1.390611E+02 +6.871266E+01 +2.368771E+02 +4.902000E+01 +1.205569E+02 +5.632046E+01 +1.592677E+02 +3.999300E+01 +8.035469E+01 +4.291289E+01 +9.245946E+01 +3.046000E+01 +4.661878E+01 +2.273666E+01 +2.598211E+01 +1.590800E+01 +1.271433E+01 tally 3: -1.528200E+01 -1.177982E+01 -1.040687E+00 -5.586386E-02 -2.857900E+01 -4.113603E+01 -1.871515E+00 -1.774689E-01 -3.888800E+01 -7.626262E+01 -2.534433E+00 -3.274088E-01 -4.541400E+01 -1.037867E+02 -2.926509E+00 -4.319780E-01 -5.034500E+01 -1.273517E+02 -3.215813E+00 -5.215716E-01 -5.076100E+01 -1.295218E+02 -3.194424E+00 -5.165993E-01 -4.768100E+01 -1.138949E+02 -3.058255E+00 -4.732131E-01 -3.995800E+01 -8.015691E+01 -2.454286E+00 -3.044948E-01 -2.957000E+01 -4.412743E+01 -1.938963E+00 -1.908501E-01 -1.544000E+01 -1.202869E+01 -1.038073E+00 -5.487827E-02 +1.529800E+01 +1.178010E+01 +1.016076E+00 +5.280687E-02 +2.803900E+01 +3.955010E+01 +1.861024E+00 +1.765351E-01 +3.919400E+01 +7.734526E+01 +2.540695E+00 +3.268959E-01 +4.749400E+01 +1.132677E+02 +3.087604E+00 +4.837647E-01 +5.156500E+01 +1.337335E+02 +3.371014E+00 +5.734875E-01 +5.070500E+01 +1.290569E+02 +3.292766E+00 +5.489854E-01 +4.723400E+01 +1.119247E+02 +2.949932E+00 +4.381745E-01 +3.847900E+01 +7.441953E+01 +2.522868E+00 +3.218962E-01 +2.933900E+01 +4.325593E+01 +1.818016E+00 +1.672765E-01 +1.534700E+01 +1.183573E+01 +9.564025E-01 +4.735079E-02 tally 4: -3.086000E+00 -4.780160E-01 +3.092000E+00 +4.809100E-01 0.000000E+00 0.000000E+00 -2.739000E+00 -3.790990E-01 -5.478000E+00 -1.505928E+00 +2.628000E+00 +3.509980E-01 +5.388000E+00 +1.458946E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.478000E+00 -1.505928E+00 -2.739000E+00 -3.790990E-01 -5.094000E+00 -1.310476E+00 -7.282000E+00 -2.669810E+00 +5.388000E+00 +1.458946E+00 +2.628000E+00 +3.509980E-01 +5.063000E+00 +1.292417E+00 +7.312000E+00 +2.686738E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.282000E+00 -2.669810E+00 -5.094000E+00 -1.310476E+00 -6.987000E+00 -2.461137E+00 -8.487000E+00 -3.624153E+00 +7.312000E+00 +2.686738E+00 +5.063000E+00 +1.292417E+00 +7.115000E+00 +2.542363E+00 +8.719000E+00 +3.819081E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.487000E+00 -3.624153E+00 -6.987000E+00 -2.461137E+00 -8.250000E+00 -3.421824E+00 -9.022000E+00 -4.088536E+00 +8.719000E+00 +3.819081E+00 +7.115000E+00 +2.542363E+00 +8.483000E+00 +3.615549E+00 +9.255000E+00 +4.303287E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.022000E+00 -4.088536E+00 -8.250000E+00 -3.421824E+00 -9.300000E+00 -4.344142E+00 -9.262000E+00 -4.308946E+00 +9.255000E+00 +4.303287E+00 +8.483000E+00 +3.615549E+00 +9.375000E+00 +4.416751E+00 +9.330000E+00 +4.375230E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.262000E+00 -4.308946E+00 -9.300000E+00 -4.344142E+00 -9.267000E+00 -4.310941E+00 -8.487000E+00 -3.613257E+00 +9.330000E+00 +4.375230E+00 +9.375000E+00 +4.416751E+00 +9.346000E+00 +4.379220E+00 +8.458000E+00 +3.585930E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.487000E+00 -3.613257E+00 -9.267000E+00 -4.310941E+00 -8.682000E+00 -3.778194E+00 -7.123000E+00 -2.544345E+00 +8.458000E+00 +3.585930E+00 +9.346000E+00 +4.379220E+00 +8.671000E+00 +3.770383E+00 +7.062000E+00 +2.505966E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.123000E+00 -2.544345E+00 -8.682000E+00 -3.778194E+00 -7.421000E+00 -2.773897E+00 -5.198000E+00 -1.369216E+00 +7.062000E+00 +2.505966E+00 +8.671000E+00 +3.770383E+00 +7.279000E+00 +2.663587E+00 +4.994000E+00 +1.261468E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.198000E+00 -1.369216E+00 -7.421000E+00 -2.773897E+00 -5.567000E+00 -1.561013E+00 -2.763000E+00 -3.882750E-01 +4.994000E+00 +1.261468E+00 +7.279000E+00 +2.663587E+00 +5.492000E+00 +1.515002E+00 +2.772000E+00 +3.896040E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.763000E+00 -3.882750E-01 -5.567000E+00 -1.561013E+00 -3.106000E+00 -4.853380E-01 +2.772000E+00 +3.896040E-01 +5.492000E+00 +1.515002E+00 +3.022000E+00 +4.608940E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,144 +345,144 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -1.527700E+01 -1.177204E+01 -2.285003E+00 -2.661382E-01 -2.857200E+01 -4.111506E+01 -4.126099E+00 -8.737996E-01 -3.887800E+01 -7.622094E+01 -5.121343E+00 -1.333837E+00 -4.540600E+01 -1.037492E+02 -6.160114E+00 -1.913665E+00 -5.033400E+01 -1.272949E+02 -6.859861E+00 -2.384476E+00 -5.075800E+01 -1.295055E+02 -6.929393E+00 -2.443364E+00 -4.767500E+01 -1.138658E+02 -6.385463E+00 -2.080293E+00 -3.995300E+01 -8.013651E+01 -5.620641E+00 -1.603844E+00 -2.956200E+01 -4.410395E+01 -3.952701E+00 -7.877105E-01 -1.543500E+01 -1.202080E+01 -2.203583E+00 -2.512936E-01 +1.529600E+01 +1.177689E+01 +2.229624E+00 +2.514699E-01 +2.803300E+01 +3.953329E+01 +3.889856E+00 +7.678274E-01 +3.918900E+01 +7.732686E+01 +5.211188E+00 +1.378173E+00 +4.748700E+01 +1.132339E+02 +6.595911E+00 +2.211528E+00 +5.155000E+01 +1.336522E+02 +6.673103E+00 +2.248462E+00 +5.069800E+01 +1.290196E+02 +6.907470E+00 +2.412919E+00 +4.722500E+01 +1.118824E+02 +6.200070E+00 +1.954544E+00 +3.847200E+01 +7.439145E+01 +5.385095E+00 +1.462192E+00 +2.933600E+01 +4.324744E+01 +4.014057E+00 +8.142088E-01 +1.534200E+01 +1.182781E+01 +2.076271E+00 +2.273431E-01 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.169107E+00 -1.173852E+00 -1.181921E+00 -1.187733E+00 -1.185766E+00 -1.177020E+00 -1.181200E+00 -1.180088E+00 -1.180676E+00 -1.174948E+00 -1.174167E+00 -1.174935E+00 -1.169912E+00 -1.169058E+00 -1.170366E+00 -1.169774E+00 +1.161531E+00 +1.181707E+00 +1.176063E+00 +1.168433E+00 +1.173170E+00 +1.174671E+00 +1.176457E+00 +1.177540E+00 +1.180826E+00 +1.174158E+00 +1.171305E+00 +1.172618E+00 +1.170171E+00 +1.173235E+00 +1.172599E+00 +1.177343E+00 cmfd entropy -3.207640E+00 -3.212075E+00 -3.215463E+00 -3.219545E+00 -3.225225E+00 -3.227103E+00 -3.229048E+00 -3.228263E+00 -3.229077E+00 -3.229932E+00 -3.229351E+00 -3.228195E+00 -3.228493E+00 -3.227823E+00 -3.225830E+00 -3.227270E+00 +3.206619E+00 +3.207385E+00 +3.208853E+00 +3.210825E+00 +3.214820E+00 +3.213490E+00 +3.212717E+00 +3.210590E+00 +3.211948E+00 +3.212156E+00 +3.212900E+00 +3.212275E+00 +3.212766E+00 +3.214205E+00 +3.212717E+00 +3.214169E+00 cmfd balance -4.88208E-03 -4.63702E-03 -3.41158E-03 -2.99755E-03 -2.78360E-03 -3.31542E-03 -2.64344E-03 -2.04609E-03 -1.84340E-03 -1.65450E-03 -1.70816E-03 -1.69952E-03 -1.51417E-03 -1.32738E-03 -1.41435E-03 -1.01462E-03 +4.99833E-03 +5.81289E-03 +3.45193E-03 +2.84521E-03 +3.72331E-03 +3.07942E-03 +2.58676E-03 +2.19354E-03 +2.11522E-03 +2.02671E-03 +1.71439E-03 +1.62909E-03 +1.43261E-03 +1.26201E-03 +1.40167E-03 +1.26141E-03 cmfd dominance ratio -5.467E-01 -5.468E-01 -5.448E-01 -5.457E-01 -5.457E-01 -5.485E-01 -5.500E-01 -5.497E-01 -5.495E-01 -5.499E-01 -5.502E-01 -5.485E-01 -5.492E-01 -5.483E-01 -5.473E-01 -5.466E-01 +5.283E-01 +5.304E-01 +5.310E-01 +5.324E-01 +5.372E-01 +5.369E-01 +5.367E-01 +5.341E-01 +5.353E-01 +5.375E-01 +5.379E-01 +5.372E-01 +5.379E-01 +5.393E-01 +5.384E-01 +5.382E-01 cmfd openmc source comparison -9.587418E-03 -7.785087E-03 -6.798967E-03 -5.947641E-03 -4.980801E-03 -4.272665E-03 -4.073759E-03 -4.305612E-03 -3.572759E-03 -3.785830E-03 -3.766828E-03 -3.495462E-03 -3.017281E-03 -2.857633E-03 -2.858606E-03 -2.449010E-03 +1.291827E-02 +9.488059E-03 +8.538280E-03 +6.820006E-03 +4.300032E-03 +5.486871E-03 +4.493389E-03 +4.913340E-03 +5.132196E-03 +3.342331E-03 +3.094995E-03 +3.553279E-03 +3.284811E-03 +2.492272E-03 +3.062765E-03 +2.632092E-03 cmfd source -4.390084E-02 -7.966902E-02 -1.087889E-01 -1.263915E-01 -1.394331E-01 -1.383156E-01 -1.319970E-01 -1.051339E-01 -8.248244E-02 -4.388774E-02 +4.280100E-02 +7.944783E-02 +1.091569E-01 +1.329540E-01 +1.451697E-01 +1.413526E-01 +1.258514E-01 +1.067698E-01 +7.656551E-02 +3.993138E-02 diff --git a/tests/regression_tests/cmfd_nofeed/settings.xml b/tests/regression_tests/cmfd_nofeed/settings.xml new file mode 100644 index 000000000..24b0b6ab5 --- /dev/null +++ b/tests/regression_tests/cmfd_nofeed/settings.xml @@ -0,0 +1,26 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + diff --git a/tests/regression_tests/cmfd_nofeed/tallies.xml b/tests/regression_tests/cmfd_nofeed/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_nofeed/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_restart/geometry.xml b/tests/regression_tests/cmfd_restart/geometry.xml new file mode 100644 index 000000000..73ea679c4 --- /dev/null +++ b/tests/regression_tests/cmfd_restart/geometry.xml @@ -0,0 +1,43 @@ + + + + + + 0 + -1 2 -3 4 -5 6 + 1 + + + + + x-plane + 10 + vacuum + + + x-plane + -10 + vacuum + + + y-plane + 1 + reflective + + + y-plane + -1 + reflective + + + z-plane + 1 + reflective + + + z-plane + -1 + reflective + + + diff --git a/tests/regression_tests/cmfd_restart/materials.xml b/tests/regression_tests/cmfd_restart/materials.xml new file mode 100644 index 000000000..70580e3a8 --- /dev/null +++ b/tests/regression_tests/cmfd_restart/materials.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/regression_tests/cmfd_restart/model.xml b/tests/regression_tests/cmfd_restart/model.xml deleted file mode 100644 index 487e9b66d..000000000 --- a/tests/regression_tests/cmfd_restart/model.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 10 - - - -10.0 -1.0 -1.0 10.0 1.0 1.0 - - - - 15 20 - - 10 - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_restart/results_true.dat b/tests/regression_tests/cmfd_restart/results_true.dat index 1ef9624d4..90d8820d0 100644 --- a/tests/regression_tests/cmfd_restart/results_true.dat +++ b/tests/regression_tests/cmfd_restart/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.181723E+00 9.944883E-03 +1.159021E+00 8.924006E-03 tally 1: -1.169899E+01 -1.373251E+01 -2.142380E+01 -4.605511E+01 -2.968085E+01 -8.838716E+01 -3.561418E+01 -1.271206E+02 -3.777783E+01 -1.428817E+02 -3.805832E+01 -1.450213E+02 -3.439836E+01 -1.184892E+02 -2.852438E+01 -8.161896E+01 -2.088423E+01 -4.376204E+01 -1.076670E+01 -1.168108E+01 +1.140162E+01 +1.306940E+01 +2.093739E+01 +4.404780E+01 +2.914408E+01 +8.521010E+01 +3.483677E+01 +1.216824E+02 +3.778463E+01 +1.429632E+02 +3.810371E+01 +1.455108E+02 +3.465248E+01 +1.207868E+02 +2.862033E+01 +8.218833E+01 +2.086025E+01 +4.365941E+01 +1.130798E+01 +1.286509E+01 tally 2: -2.321241E+01 -2.702156E+01 -1.620912E+01 -1.317752E+01 -4.197404E+01 -8.845008E+01 -2.982666E+01 -4.469221E+01 -5.810089E+01 -1.695857E+02 -4.134123E+01 -8.588866E+01 -6.982488E+01 -2.447068E+02 -4.966939E+01 -1.238763E+02 -7.428421E+01 -2.767613E+02 -5.287955E+01 -1.403163E+02 -7.447402E+01 -2.785012E+02 -5.324628E+01 -1.423393E+02 -6.895164E+01 -2.381937E+02 -4.916366E+01 -1.211701E+02 -5.679253E+01 -1.617881E+02 -4.043125E+01 -8.204061E+01 -4.218618E+01 -8.933666E+01 -2.978592E+01 -4.456592E+01 -2.196426E+01 -2.435867E+01 -1.525576E+01 -1.175879E+01 +2.234393E+01 +2.516414E+01 +1.555024E+01 +1.218205E+01 +4.087743E+01 +8.401702E+01 +2.883717E+01 +4.185393E+01 +5.635166E+01 +1.595225E+02 +3.998857E+01 +8.040398E+01 +6.887126E+01 +2.379185E+02 +4.903103E+01 +1.206174E+02 +7.452051E+01 +2.785675E+02 +5.295380E+01 +1.406900E+02 +7.495422E+01 +2.819070E+02 +5.333191E+01 +1.427474E+02 +6.921815E+01 +2.408568E+02 +4.928246E+01 +1.221076E+02 +5.668548E+01 +1.612556E+02 +4.035856E+01 +8.181159E+01 +4.259952E+01 +9.112630E+01 +3.026717E+01 +4.600625E+01 +2.310563E+01 +2.688378E+01 +1.615934E+01 +1.315528E+01 tally 3: -1.563788E+01 -1.226528E+01 -1.053289E+00 -5.666942E-02 -2.870755E+01 -4.139654E+01 -1.838017E+00 -1.710528E-01 -3.978616E+01 -7.955764E+01 -2.560657E+00 -3.334449E-01 -4.780385E+01 -1.147770E+02 -3.139243E+00 -4.967628E-01 -5.106650E+01 -1.308704E+02 -3.170056E+00 -5.078920E-01 -5.123992E+01 -1.318586E+02 -3.211706E+00 -5.205979E-01 -4.729862E+01 -1.121695E+02 -3.068662E+00 -4.749488E-01 -3.898816E+01 -7.630564E+01 -2.516911E+00 -3.199696E-01 -2.865357E+01 -4.125742E+01 -1.852314E+00 -1.741116E-01 -1.467340E+01 -1.088460E+01 -9.268633E-01 -4.450662E-02 +1.496375E+01 +1.128154E+01 +9.905641E-01 +5.125710E-02 +2.774937E+01 +3.877241E+01 +1.786861E+00 +1.627655E-01 +3.849739E+01 +7.453828E+01 +2.494135E+00 +3.158098E-01 +4.724085E+01 +1.119901E+02 +3.031174E+00 +4.653741E-01 +5.096719E+01 +1.303552E+02 +3.254375E+00 +5.351020E-01 +5.133808E+01 +1.322892E+02 +3.383595E+00 +5.798798E-01 +4.756072E+01 +1.137527E+02 +3.001917E+00 +4.558247E-01 +3.887437E+01 +7.593416E+01 +2.517908E+00 +3.221926E-01 +2.910687E+01 +4.255173E+01 +1.817765E+00 +1.678763E-01 +1.557241E+01 +1.222026E+01 +9.852737E-01 +5.002659E-02 tally 4: -3.029754E+00 -4.613561E-01 +3.047490E+00 +4.661458E-01 0.000000E+00 0.000000E+00 -2.832501E+00 -4.049252E-01 -5.517243E+00 -1.527794E+00 +2.635775E+00 +3.524426E-01 +5.357229E+00 +1.440049E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.517243E+00 -1.527794E+00 -2.832501E+00 -4.049252E-01 -5.117178E+00 -1.316972E+00 -7.333303E+00 -2.701677E+00 +5.357229E+00 +1.440049E+00 +2.635775E+00 +3.524426E-01 +4.982072E+00 +1.251449E+00 +7.228146E+00 +2.620353E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.333303E+00 -2.701677E+00 -5.117178E+00 -1.316972E+00 -7.248464E+00 -2.641591E+00 -8.817788E+00 -3.905530E+00 +7.228146E+00 +2.620353E+00 +4.982072E+00 +1.251449E+00 +7.082265E+00 +2.520047E+00 +8.736529E+00 +3.831244E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.817788E+00 -3.905530E+00 -7.248464E+00 -2.641591E+00 -8.646465E+00 -3.749847E+00 -9.460948E+00 -4.495388E+00 +8.736529E+00 +3.831244E+00 +7.082265E+00 +2.520047E+00 +8.474631E+00 +3.607043E+00 +9.346623E+00 +4.390819E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.460948E+00 -4.495388E+00 -8.646465E+00 -3.749847E+00 -9.379341E+00 -4.415049E+00 -9.278640E+00 -4.320720E+00 +9.346623E+00 +4.390819E+00 +8.474631E+00 +3.607043E+00 +9.496684E+00 +4.522478E+00 +9.532822E+00 +4.559003E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.278640E+00 -4.320720E+00 -9.379341E+00 -4.415049E+00 -9.465746E+00 -4.498591E+00 -8.656146E+00 -3.760545E+00 +9.532822E+00 +4.559003E+00 +9.496684E+00 +4.522478E+00 +9.404949E+00 +4.446260E+00 +8.550930E+00 +3.668401E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.656146E+00 -3.760545E+00 -9.465746E+00 -4.498591E+00 -8.589782E+00 -3.700308E+00 -6.996002E+00 -2.456935E+00 +8.550930E+00 +3.668401E+00 +9.404949E+00 +4.446260E+00 +8.785273E+00 +3.874792E+00 +7.128863E+00 +2.554326E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.996002E+00 -2.456935E+00 -8.589782E+00 -3.700308E+00 -7.352050E+00 -2.714808E+00 -5.105164E+00 -1.312559E+00 +7.128863E+00 +2.554326E+00 +8.785273E+00 +3.874792E+00 +7.408549E+00 +2.755885E+00 +5.094992E+00 +1.305737E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.105164E+00 -1.312559E+00 -7.352050E+00 -2.714808E+00 -5.442756E+00 -1.486776E+00 -2.697305E+00 -3.675580E-01 +5.094992E+00 +1.305737E+00 +7.408549E+00 +2.755885E+00 +5.532149E+00 +1.537289E+00 +2.812344E+00 +3.997146E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.697305E+00 -3.675580E-01 -5.442756E+00 -1.486776E+00 -3.017025E+00 -4.571443E-01 +2.812344E+00 +3.997146E-01 +5.532149E+00 +1.537289E+00 +3.063251E+00 +4.728672E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,144 +345,144 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -1.563588E+01 -1.226217E+01 -2.209027E+00 -2.507131E-01 -2.870034E+01 -4.137550E+01 -3.726620E+00 -7.021948E-01 -3.977762E+01 -7.952285E+01 -5.304975E+00 -1.427333E+00 -4.779747E+01 -1.147456E+02 -6.528302E+00 -2.151715E+00 -5.105366E+01 -1.308037E+02 -6.986782E+00 -2.467487E+00 -5.123380E+01 -1.318264E+02 -6.845633E+00 -2.383542E+00 -4.729296E+01 -1.121433E+02 -6.252695E+00 -1.977351E+00 -3.898236E+01 -7.628315E+01 -5.461495E+00 -1.528579E+00 -2.864576E+01 -4.123538E+01 -3.857301E+00 -7.581323E-01 -1.467047E+01 -1.088031E+01 -2.277024E+00 -2.679801E-01 +1.496000E+01 +1.127586E+01 +2.280081E+00 +2.675609E-01 +2.774503E+01 +3.876011E+01 +3.908836E+00 +7.703029E-01 +3.848706E+01 +7.449836E+01 +5.299924E+00 +1.422782E+00 +4.723172E+01 +1.119459E+02 +6.450156E+00 +2.105590E+00 +5.095931E+01 +1.303132E+02 +7.050681E+00 +2.515092E+00 +5.133412E+01 +1.322694E+02 +6.853429E+00 +2.384127E+00 +4.754621E+01 +1.136848E+02 +6.370026E+00 +2.058896E+00 +3.886829E+01 +7.591042E+01 +5.266816E+00 +1.400495E+00 +2.910277E+01 +4.253981E+01 +4.090844E+00 +8.442500E-01 +1.556949E+01 +1.221526E+01 +2.266123E+00 +2.641551E-01 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.169107E+00 -1.175079E+00 -1.173912E+00 -1.175368E+00 -1.174026E+00 -1.181745E+00 -1.182261E+00 -1.183559E+00 -1.178691E+00 -1.179222E+00 -1.179017E+00 -1.172979E+00 -1.175043E+00 -1.173458E+00 -1.174152E+00 -1.171451E+00 +1.161531E+00 +1.182724E+00 +1.169653E+00 +1.164722E+00 +1.164583E+00 +1.162952E+00 +1.167024E+00 +1.164509E+00 +1.165693E+00 +1.170623E+00 +1.166618E+00 +1.170805E+00 +1.170962E+00 +1.170964E+00 +1.168224E+00 +1.169864E+00 cmfd entropy -3.207640E+00 -3.210547E+00 -3.212218E+00 -3.209573E+00 -3.211619E+00 -3.212126E+00 -3.213163E+00 -3.214288E+00 -3.215737E+00 -3.213677E+00 -3.214925E+00 -3.215612E+00 -3.216708E+00 -3.221454E+00 -3.219048E+00 -3.218387E+00 +3.206619E+00 +3.205815E+00 +3.208678E+00 +3.210820E+00 +3.217023E+00 +3.215014E+00 +3.214592E+00 +3.215913E+00 +3.214998E+00 +3.213644E+00 +3.210755E+00 +3.210496E+00 +3.212488E+00 +3.211553E+00 +3.212999E+00 +3.214052E+00 cmfd balance -4.88208E-03 -4.75139E-03 -3.15783E-03 -3.67091E-03 -2.99797E-03 -2.91060E-03 -2.06576E-03 -1.83482E-03 -1.56292E-03 -1.58659E-03 -2.32986E-03 -1.47376E-03 -1.46673E-03 -1.22627E-03 -1.31963E-03 -1.26456E-03 +4.99833E-03 +5.64677E-03 +3.62795E-03 +3.91962E-03 +3.87172E-03 +2.48450E-03 +3.15554E-03 +2.49335E-03 +2.31973E-03 +2.19156E-03 +2.31352E-03 +2.03401E-03 +1.80242E-03 +1.65868E-03 +1.47543E-03 +1.49706E-03 cmfd dominance ratio -5.467E-01 -5.453E-01 -5.458E-01 -5.436E-01 -5.442E-01 -5.406E-01 -5.401E-01 -5.413E-01 -4.995E-01 -5.396E-01 -5.409E-01 -5.414E-01 -5.423E-01 -5.456E-01 -5.442E-01 -5.441E-01 +5.283E-01 +5.289E-01 +5.305E-01 +5.327E-01 +5.377E-01 +5.360E-01 +5.353E-01 +4.983E-01 +5.379E-01 +5.370E-01 +5.359E-01 +5.349E-01 +5.364E-01 +5.347E-01 +5.360E-01 +5.378E-01 cmfd openmc source comparison -9.587418E-03 -8.150978E-03 -6.677661E-03 -6.334727E-03 -5.153692E-03 -5.082964E-03 -4.633153E-03 -4.037383E-03 -3.528742E-03 -4.559089E-03 -3.517370E-03 -3.306117E-03 -2.913809E-03 -1.906045E-03 -1.932794E-03 -1.711341E-03 +1.291827E-02 +1.027137E-02 +8.738370E-03 +6.854409E-03 +4.188357E-03 +4.941359E-03 +5.139239E-03 +4.244784E-03 +4.240559E-03 +3.375424E-03 +3.716858E-03 +3.595700E-03 +3.626952E-03 +3.999302E-03 +2.431760E-03 +1.673200E-03 cmfd source -4.496492E-02 -7.869674E-02 -1.100280E-01 -1.354045E-01 -1.363339E-01 -1.380533E-01 -1.314512E-01 -1.077480E-01 -7.847306E-02 -3.884630E-02 +4.185460E-02 +7.636314E-02 +1.075536E-01 +1.307167E-01 +1.400879E-01 +1.459944E-01 +1.297413E-01 +1.084649E-01 +7.772031E-02 +4.150306E-02 diff --git a/tests/regression_tests/cmfd_restart/settings.xml b/tests/regression_tests/cmfd_restart/settings.xml new file mode 100644 index 000000000..ba5495911 --- /dev/null +++ b/tests/regression_tests/cmfd_restart/settings.xml @@ -0,0 +1,28 @@ + + + + + eigenvalue + 20 + 10 + 1000 + + + + + box + -10 -1 -1 10 1 1 + + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + 10 + + + + diff --git a/tests/regression_tests/cmfd_restart/tallies.xml b/tests/regression_tests/cmfd_restart/tallies.xml new file mode 100644 index 000000000..c86971114 --- /dev/null +++ b/tests/regression_tests/cmfd_restart/tallies.xml @@ -0,0 +1,21 @@ + + + + + regular + -10 -1 -1 + 10 1 1 + 10 1 1 + + + + mesh + 1 + + + + 1 + flux + + + diff --git a/tests/regression_tests/collision_track/__init__.py b/tests/regression_tests/collision_track/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/collision_track/case_1_Reactions/collision_track_true.h5 b/tests/regression_tests/collision_track/case_1_Reactions/collision_track_true.h5 deleted file mode 100644 index c31546213..000000000 Binary files a/tests/regression_tests/collision_track/case_1_Reactions/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_1_Reactions/inputs_true.dat b/tests/regression_tests/collision_track/case_1_Reactions/inputs_true.dat deleted file mode 100644 index 005a56020..000000000 --- a/tests/regression_tests/collision_track/case_1_Reactions/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - (n,fission) 101 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/case_2_Cell_ID/collision_track_true.h5 b/tests/regression_tests/collision_track/case_2_Cell_ID/collision_track_true.h5 deleted file mode 100644 index 850bba841..000000000 Binary files a/tests/regression_tests/collision_track/case_2_Cell_ID/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_2_Cell_ID/inputs_true.dat b/tests/regression_tests/collision_track/case_2_Cell_ID/inputs_true.dat deleted file mode 100644 index 8d46c3d3b..000000000 --- a/tests/regression_tests/collision_track/case_2_Cell_ID/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 22 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/case_3_Material_ID/collision_track_true.h5 b/tests/regression_tests/collision_track/case_3_Material_ID/collision_track_true.h5 deleted file mode 100644 index 777d91f08..000000000 Binary files a/tests/regression_tests/collision_track/case_3_Material_ID/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_3_Material_ID/inputs_true.dat b/tests/regression_tests/collision_track/case_3_Material_ID/inputs_true.dat deleted file mode 100644 index 322e74f49..000000000 --- a/tests/regression_tests/collision_track/case_3_Material_ID/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 1 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/case_4_Nuclide_ID/collision_track_true.h5 b/tests/regression_tests/collision_track/case_4_Nuclide_ID/collision_track_true.h5 deleted file mode 100644 index 527705297..000000000 Binary files a/tests/regression_tests/collision_track/case_4_Nuclide_ID/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_4_Nuclide_ID/inputs_true.dat b/tests/regression_tests/collision_track/case_4_Nuclide_ID/inputs_true.dat deleted file mode 100644 index 6202bcacc..000000000 --- a/tests/regression_tests/collision_track/case_4_Nuclide_ID/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - O16 U235 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/case_5_Universe_ID/collision_track_true.h5 b/tests/regression_tests/collision_track/case_5_Universe_ID/collision_track_true.h5 deleted file mode 100644 index 65419d5ea..000000000 Binary files a/tests/regression_tests/collision_track/case_5_Universe_ID/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_5_Universe_ID/inputs_true.dat b/tests/regression_tests/collision_track/case_5_Universe_ID/inputs_true.dat deleted file mode 100644 index c06061210..000000000 --- a/tests/regression_tests/collision_track/case_5_Universe_ID/inputs_true.dat +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 22 - 77 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/case_6_deposited_energy_threshold/collision_track_true.h5 b/tests/regression_tests/collision_track/case_6_deposited_energy_threshold/collision_track_true.h5 deleted file mode 100644 index 507665a60..000000000 Binary files a/tests/regression_tests/collision_track/case_6_deposited_energy_threshold/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_6_deposited_energy_threshold/inputs_true.dat b/tests/regression_tests/collision_track/case_6_deposited_energy_threshold/inputs_true.dat deleted file mode 100644 index 434f6b434..000000000 --- a/tests/regression_tests/collision_track/case_6_deposited_energy_threshold/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 550000.0 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/case_7_all_parameters_used_together/collision_track_true.h5 b/tests/regression_tests/collision_track/case_7_all_parameters_used_together/collision_track_true.h5 deleted file mode 100644 index b7ff67c48..000000000 Binary files a/tests/regression_tests/collision_track/case_7_all_parameters_used_together/collision_track_true.h5 and /dev/null differ diff --git a/tests/regression_tests/collision_track/case_7_all_parameters_used_together/inputs_true.dat b/tests/regression_tests/collision_track/case_7_all_parameters_used_together/inputs_true.dat deleted file mode 100644 index 1449c3596..000000000 --- a/tests/regression_tests/collision_track/case_7_all_parameters_used_together/inputs_true.dat +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 80 - 5 - 4 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 22 33 - elastic 18 (n,disappear) - 77 - 1 11 - U238 U235 H1 U234 - 100000.0 - 100 - - 1 - - diff --git a/tests/regression_tests/collision_track/test.py b/tests/regression_tests/collision_track/test.py deleted file mode 100644 index 2f9de9ac0..000000000 --- a/tests/regression_tests/collision_track/test.py +++ /dev/null @@ -1,222 +0,0 @@ -"""Test the 'collision_track' setting. - -Results -------- - -All results are generated using only 1 MPI process. - -All results are generated using 1 thread except for "test_consistency_low_realization_number". -This specific test verifies that when the number of realization (i.e., point being candidate -to be stored) is lower than the capacity, results are reproducible even with multiple -threads (i.e., there is no potential thread competition that would produce different -results in that case). - -All results are generated using the history-based mode except for cases e01 to e03. - -All results are visually verified using the '_visualize.py' script in the regression test folder. - -OpenMC models -------------- - -Four OpenMC models with CSG-only geometries are used to cover the transmission, vacuum, -reflective and periodic Boundary Conditions (BC): - -- model_1: cylindrical core in 2 boxes (vacuum and transmission BC), - -# Test cases for simulation parameters using CSG-only geometries -# ============================================================ -# Each test case is defined by a combination of folder name, model name, and specific parameters. -# Below is a summary of the parameters used in the test cases: -# -# - max_collisions: Maximum number of particles to track in the simulation. -# - reactions: List of MT numbers (reaction types- 2 for scattering, 18 for fission, 101 for absorbtion). -# - cell_ids: IDs of specific cells in the model. -# - mat_ids: Material IDs for filtering particles. -# - nuclides: Nuclides for filtering particles. -# - univ_ids: Universe IDs for filtering particles. -# - E_threshold: Energy threshold for filtering particles (optional). -# -# The test cases are designed to validate the behavior of the simulation under various configurations. - -*: BC stands for Boundary Conditions, T for Transmission, R for Reflective, and V for Vacuum. - -An additional case, called 'case-a01', is used to check that the results are comparable when -the number of threads is set to 2 if the number of realization is lower than the capacity. - - -*: BC stands for Boundary Conditions, T for Transmission, and V for Vacuum. - -Notes: - -- The test cases list is non-exhaustive compared to the number of possible combinations. - Test cases have been selected based on use and internal code logic. - - - -TODO: - -- Test with a lattice. - -""" - -import openmc -import pytest - -from tests.testing_harness import CollisionTrackTestHarness -from tests.regression_tests import config - - -@pytest.fixture(scope="module") -def model_1(): - """Cylindrical core contained in a first box which is contained in a larger box. - A lower universe is used to describe the interior of the first box which - contains the core and its surrounding space. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - fuel = openmc.Material(material_id=1) - fuel.add_nuclide("U234", 0.0004524) - fuel.add_nuclide("U235", 0.0506068) - fuel.add_nuclide("U238", 0.9487090) - fuel.add_nuclide("U236", 0.0002318) - fuel.add_nuclide("O16", 2.0) - fuel.set_density("g/cm3", 11.0) - - water = openmc.Material(material_id=11) - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cm3", 1.0) - - # ============================================================================= - # Geometry - # ============================================================================= - - # ----------------------------------------------------------------------------- - # Cylindrical core - # ----------------------------------------------------------------------------- - - # Parameters - core_radius = 2.0 - core_height = 4.0 - - # Surfaces - core_cylinder = openmc.ZCylinder(r=core_radius) - core_lower_plane = openmc.ZPlane(-core_height / 2.0) - core_upper_plane = openmc.ZPlane(core_height / 2.0) - - # Region - core_region = -core_cylinder & +core_lower_plane & -core_upper_plane - - # Cells - core = openmc.Cell(fill=fuel, region=core_region, cell_id=22) - outside_core_region = +core_cylinder | -core_lower_plane | +core_upper_plane - outside_core = openmc.Cell( - fill=water, region=outside_core_region, cell_id=33) - - # Universe - inside_box1_universe = openmc.Universe( - cells=[core, outside_core], universe_id=77) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 6.0 - - # Surfaces - box1_rpp = openmc.model.RectangularParallelepiped( - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - ) - - # Cell - box1 = openmc.Cell(fill=inside_box1_universe, region=-box1_rpp, cell_id=5) - - # ----------------------------------------------------------------------------- - # Box 2 - # ----------------------------------------------------------------------------- - - # Parameters - box2_size = 8 - - # Surfaces - box2_rpp = openmc.model.RectangularParallelepiped( - -box2_size / 2.0, box2_size / 2.0, - -box2_size / 2.0, box2_size / 2.0, - -box2_size / 2.0, box2_size / 2.0, - boundary_type="vacuum" - ) - - # Cell - box2 = openmc.Cell(fill=water, region=-box2_rpp & +box1_rpp, cell_id=8) - - # Register geometry - model.geometry = openmc.Geometry([box1, box2]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 80 - model.settings.batches = 5 - model.settings.inactive = 4 - model.settings.seed = 1 - - bounds = [ - -core_radius, - -core_radius, - -core_height / 2.0, - core_radius, - core_radius, - core_height / 2.0, - ] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource( - space=distribution, constraints={'fissionable': True}) - - return model - - -@pytest.mark.parametrize( - "folder, model_name, parameter", - [("case_1_Reactions", "model_1", {"max_collisions": 100, "reactions": ["(n,fission)", 101]}), - ("case_2_Cell_ID", "model_1", { - "max_collisions": 100, "cell_ids": [22]}), - ("case_3_Material_ID", "model_1", { - "max_collisions": 100, "material_ids": [1]}), - ("case_4_Nuclide_ID", "model_1", { - "max_collisions": 100, "nuclides": ["O16", "U235"]}), - ("case_5_Universe_ID", "model_1", { - "max_collisions": 100, "cell_ids": [22], "universe_ids": [77]}), - ("case_6_deposited_energy_threshold", "model_1", { - "max_collisions": 100, "deposited_E_threshold": 5.5e5}), - ("case_7_all_parameters_used_together", "model_1", { - "max_collisions": 100, - "reactions": ["elastic", 18, "(n,disappear)"], - "material_ids": [1, 11], - "universe_ids": [77], - "nuclides": ["U238", "U235", "H1", "U234"], - "cell_ids": [22, 33], - "deposited_E_threshold": 1e5}) - ], -) -def test_collision_track_several_cases( - folder, model_name, parameter, request -): - # Since for these tests the actual number of collisions recorded is < max_collisions, - # we can run them with 1 or 2 threads, and in history or event mode. - model = request.getfixturevalue(model_name) - model.settings.collision_track = parameter - harness = CollisionTrackTestHarness( - "statepoint.5.h5", model=model, workdir=folder - ) - harness.main() diff --git a/tests/regression_tests/complex_cell/geometry.xml b/tests/regression_tests/complex_cell/geometry.xml index 638c7c9b8..a695396e0 100644 --- a/tests/regression_tests/complex_cell/geometry.xml +++ b/tests/regression_tests/complex_cell/geometry.xml @@ -19,7 +19,7 @@ - + diff --git a/tests/regression_tests/complex_cell/results_true.dat b/tests/regression_tests/complex_cell/results_true.dat index ddedb07ff..927a7a519 100644 --- a/tests/regression_tests/complex_cell/results_true.dat +++ b/tests/regression_tests/complex_cell/results_true.dat @@ -1,11 +1,11 @@ k-combined: -2.603220E-01 1.429366E-03 +2.490321E-01 1.083676E-03 tally 1: -2.624819E+00 -1.378200E+00 -2.730035E+00 -1.492361E+00 -1.013707E+00 -2.055807E-01 -1.123257E-01 -2.530233E-03 +2.617769E+00 +1.371478E+00 +2.716496E+00 +1.476169E+00 +1.005297E+00 +2.026100E-01 +1.075286E-01 +2.316593E-03 diff --git a/tests/regression_tests/confidence_intervals/results_true.dat b/tests/regression_tests/confidence_intervals/results_true.dat index 8ca256624..cb6c6f00a 100644 --- a/tests/regression_tests/confidence_intervals/results_true.dat +++ b/tests/regression_tests/confidence_intervals/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.850178E-01 9.646334E-03 +2.679617E-01 1.158917E-02 tally 1: -6.234169E+01 -4.884167E+02 +6.693704E+01 +5.643483E+02 diff --git a/tests/regression_tests/conftest.py b/tests/regression_tests/conftest.py index 1cdf414e7..b4a764476 100644 --- a/tests/regression_tests/conftest.py +++ b/tests/regression_tests/conftest.py @@ -1,12 +1,12 @@ import numpy as np import openmc -from packaging.version import parse +from pkg_resources import parse_version import pytest @pytest.fixture(scope='module', autouse=True) def numpy_version_requirement(): - assert parse(np.__version__) >= parse("1.14"), \ + assert parse_version(np.__version__) >= parse_version("1.14"), \ "Regression tests require NumPy 1.14 or greater" diff --git a/tests/regression_tests/cpp_driver/driver.cpp b/tests/regression_tests/cpp_driver/driver.cpp index a6c3e6510..48ed7f317 100644 --- a/tests/regression_tests/cpp_driver/driver.cpp +++ b/tests/regression_tests/cpp_driver/driver.cpp @@ -2,8 +2,6 @@ #include #endif -#include - #include "openmc/capi.h" #include "openmc/cell.h" #include "openmc/error.h" @@ -17,16 +15,14 @@ using namespace openmc; -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { #ifdef OPENMC_MPI MPI_Comm world {MPI_COMM_WORLD}; int err = openmc_init(argc, argv, &world); #else int err = openmc_init(argc, argv, nullptr); #endif - if (err) - fatal_error(openmc_err_msg); + if (err) fatal_error(openmc_err_msg); // create a new cell filter auto cell_filter = Filter::create(); @@ -34,7 +30,7 @@ int main(int argc, char** argv) // add all cells to the cell filter std::vector cell_indices; for (auto& entry : openmc::model::cell_map) { - cell_indices.push_back(entry.second); + cell_indices.push_back(entry.second); } // enable distribcells offsets for all cells prepare_distribcell(&cell_indices); @@ -43,6 +39,7 @@ int main(int argc, char** argv) std::sort(cell_indices.begin(), cell_indices.end()); cell_filter->set_cells(cell_indices); + // create a new tally auto tally = Tally::create(); std::vector filters = {cell_filter}; @@ -63,19 +60,14 @@ int main(int argc, char** argv) } } - // set a higher temperature for only one of the lattice cells (ID is 4 in the - // model) + // set a higher temperature for only one of the lattice cells (ID is 4 in the model) model::cells[model::cell_map[4]]->set_temperature(400.0, 3, true); - // set the density of another lattice cell to 2 - model::cells[model::cell_map[4]]->set_density(2.0, 2, true); - // the summary file will be used to check that // temperatures were set correctly so clear // error output can be provided #ifdef OPENMC_MPI - if (openmc::mpi::master) - openmc::write_summary(); + if (openmc::mpi::master) openmc::write_summary(); #else openmc::write_summary(); #endif diff --git a/tests/regression_tests/cpp_driver/inputs_true.dat b/tests/regression_tests/cpp_driver/inputs_true.dat index fd450428a..faa3fa9b1 100644 --- a/tests/regression_tests/cpp_driver/inputs_true.dat +++ b/tests/regression_tests/cpp_driver/inputs_true.dat @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - 4.0 4.0 - 2 2 - -4.0 -4.0 - + + + + + + + + 4.0 4.0 + 2 2 + -4.0 -4.0 + 2 2 2 2 - - - - - - - - - - eigenvalue - 100 - 10 - 1 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 1 + diff --git a/tests/regression_tests/cpp_driver/results_true.dat b/tests/regression_tests/cpp_driver/results_true.dat index 09f188db6..e44b45054 100644 --- a/tests/regression_tests/cpp_driver/results_true.dat +++ b/tests/regression_tests/cpp_driver/results_true.dat @@ -1,13 +1,13 @@ k-combined: -1.874924E+00 2.180236E-02 +1.902610E+00 1.901530E-02 tally 1: -9.484447E+01 -1.002269E+03 -2.746252E+01 -8.406603E+01 -9.833099E+01 -1.076376E+03 -2.206380E+02 -5.417609E+03 -2.206380E+02 -5.417609E+03 +9.580351E+01 +1.031580E+03 +2.745984E+01 +8.430494E+01 +9.422158E+01 +9.919885E+02 +2.174849E+02 +5.292948E+03 +2.174849E+02 +5.292948E+03 diff --git a/tests/regression_tests/cpp_driver/test.py b/tests/regression_tests/cpp_driver/test.py index b80e82ee0..e8b1c62ac 100644 --- a/tests/regression_tests/cpp_driver/test.py +++ b/tests/regression_tests/cpp_driver/test.py @@ -20,7 +20,7 @@ def cpp_driver(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_cpp_driver CXX) add_executable(cpp_driver driver.cpp) find_package(OpenMC REQUIRED HINTS {}) @@ -92,9 +92,10 @@ def model(): lattice.pitch = (4.0, 4.0) lattice.lower_left = (-4.0, -4.0) lattice.universes = [[extra_univ, extra_univ], [extra_univ, extra_univ]] - lattice_prism = openmc.model.RectangularPrism( - 8.0, 8.0, boundary_type='reflective') - lattice_cell = openmc.Cell(fill=lattice, region=-lattice_prism) + lattice_region = openmc.model.rectangular_prism(8.0, + 8.0, + boundary_type='reflective') + lattice_cell = openmc.Cell(fill=lattice, region=lattice_region) model.geometry = openmc.Geometry([lattice_cell]) diff --git a/tests/regression_tests/create_fission_neutrons/inputs_true.dat b/tests/regression_tests/create_fission_neutrons/inputs_true.dat index 47e8c3830..b0ca89647 100644 --- a/tests/regression_tests/create_fission_neutrons/inputs_true.dat +++ b/tests/regression_tests/create_fission_neutrons/inputs_true.dat @@ -1,36 +1,37 @@ - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - -1 -1 -1 1 1 1 - - - - false - - - - flux - - - + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + -1 -1 -1 1 1 1 + + + + false + + + + + flux + + diff --git a/tests/regression_tests/create_fission_neutrons/test.py b/tests/regression_tests/create_fission_neutrons/test.py index 0ca4a48b2..f1c1d072c 100755 --- a/tests/regression_tests/create_fission_neutrons/test.py +++ b/tests/regression_tests/create_fission_neutrons/test.py @@ -4,14 +4,14 @@ from tests.testing_harness import PyAPITestHarness class CreateFissionNeutronsTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): # Material is composed of H-1 and U-235 mat = openmc.Material(material_id=1, name='mat') mat.set_density('atom/b-cm', 0.069335) mat.add_nuclide('H1', 40.0) mat.add_nuclide('U235', 1.0) - self._model.materials = openmc.Materials([mat]) + materials_file = openmc.Materials([mat]) + materials_file.export_to_xml() # Cell is box with reflective boundary x1 = openmc.XPlane(surface_id=1, x0=-1) @@ -27,7 +27,8 @@ class CreateFissionNeutronsTestHarness(PyAPITestHarness): box.fill = mat root = openmc.Universe(universe_id=0, name='root universe') root.add_cell(box) - self._model.geometry = openmc.Geometry(root) + geometry = openmc.Geometry(root) + geometry.export_to_xml() # Set the running parameters settings_file = openmc.Settings() @@ -38,16 +39,16 @@ class CreateFissionNeutronsTestHarness(PyAPITestHarness): bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) watt_dist = openmc.stats.Watt() - settings_file.source = openmc.IndependentSource(space=uniform_dist, - energy=watt_dist) - self._model.settings = settings_file + settings_file.source = openmc.source.Source(space=uniform_dist, + energy=watt_dist) + settings_file.export_to_xml() # Create tallies tallies = openmc.Tallies() tally = openmc.Tally(1) tally.scores = ['flux'] tallies.append(tally) - self._model.tallies = tallies + tallies.export_to_xml() def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -65,6 +66,5 @@ class CreateFissionNeutronsTestHarness(PyAPITestHarness): def test_create_fission_neutrons(): - harness = CreateFissionNeutronsTestHarness('statepoint.10.h5', - model=openmc.Model()) + harness = CreateFissionNeutronsTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/dagmc/external/inputs_true.dat b/tests/regression_tests/dagmc/external/inputs_true.dat index 8a6c6fe74..dd75bbdbd 100644 --- a/tests/regression_tests/dagmc/external/inputs_true.dat +++ b/tests/regression_tests/dagmc/external/inputs_true.dat @@ -1,39 +1,40 @@ - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - 293 - - - - 1 - - - 1 - total - - - + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + 293 + + + + + 1 + + + 1 + total + + diff --git a/tests/regression_tests/dagmc/external/main.cpp b/tests/regression_tests/dagmc/external/main.cpp index e78ab03fa..42f7d97c9 100644 --- a/tests/regression_tests/dagmc/external/main.cpp +++ b/tests/regression_tests/dagmc/external/main.cpp @@ -5,7 +5,6 @@ #include "openmc/geometry.h" #include "openmc/geometry_aux.h" #include "openmc/material.h" -#include "openmc/message_passing.h" #include "openmc/nuclide.h" #include @@ -15,12 +14,7 @@ int main(int argc, char* argv[]) int openmc_err; // Initialise OpenMC -#ifdef OPENMC_MPI - MPI_Comm world = MPI_COMM_WORLD; - openmc_err = openmc_init(argc, argv, &world); -#else openmc_err = openmc_init(argc, argv, nullptr); -#endif if (openmc_err == -1) { // This happens for the -h and -v flags return EXIT_SUCCESS; @@ -39,7 +33,7 @@ int main(int argc, char* argv[]) // Initialize acceleration data structures rval = dag_ptr->init_OBBTree(); if (rval != moab::MB_SUCCESS) { - fatal_error("Failed to initialize OBB tree"); + fatal_error("Failed to initialise OBB tree"); } // Get rid of existing geometry @@ -68,20 +62,6 @@ int main(int argc, char* argv[]) // Add cells to universes openmc::populate_universes(); - // Make sure implicit complement appears last - auto dag_univ = dynamic_cast(model::universes.back().get()); - int n = dag_univ->cells_.size(); - for (int i = 0; i < n - 1; ++i) { - if (dag_univ->cells_[i] == dag_univ->implicit_complement_idx()) { - fatal_error("Implicit complement cell should appear last in vector of " - "cells for DAGMC universe."); - } - } - if (dag_univ->cells_.back() != dag_univ->implicit_complement_idx()) { - fatal_error( - "Last cell in DAGMC universe is not an implicit complement cell."); - } - // Set root universe openmc::model::root_universe = openmc::find_root_universe(); openmc::check_dagmc_root_univ(); @@ -100,9 +80,6 @@ int main(int argc, char* argv[]) } } - // Finalize cell densities - openmc::finalize_cell_densities(); - // Run OpenMC openmc_err = openmc_run(); if (openmc_err) @@ -113,9 +90,5 @@ int main(int argc, char* argv[]) if (openmc_err) fatal_error(openmc_err_msg); -#ifdef OPENMC_MPI - MPI_Finalize(); -#endif - return EXIT_SUCCESS; } diff --git a/tests/regression_tests/dagmc/external/results_true.dat b/tests/regression_tests/dagmc/external/results_true.dat index 9a6b481b7..e5127c827 100644 --- a/tests/regression_tests/dagmc/external/results_true.dat +++ b/tests/regression_tests/dagmc/external/results_true.dat @@ -1,5 +1,5 @@ k-combined: -1.083415E+00 5.991738E-02 +8.426936E-01 5.715847E-02 tally 1: -8.862860E+00 -1.602117E+01 +8.093843E+00 +1.328829E+01 diff --git a/tests/regression_tests/dagmc/external/test.py b/tests/regression_tests/dagmc/external/test.py index 3580bfa11..93123ae1e 100644 --- a/tests/regression_tests/dagmc/external/test.py +++ b/tests/regression_tests/dagmc/external/test.py @@ -25,14 +25,14 @@ def cpp_driver(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_cpp_driver CXX) add_executable(main main.cpp) find_package(OpenMC REQUIRED HINTS {}) target_link_libraries(main OpenMC::libopenmc) target_compile_features(main PUBLIC cxx_std_14) set(CMAKE_CXX_FLAGS "-pedantic-errors") - add_compile_definitions(OPENMC_DAGMC_ENABLED=1) + add_compile_definitions(DAGMC=1) """.format(openmc_dir))) # Create temporary build directory and change to there @@ -65,7 +65,7 @@ def model(): model.settings.particles = 100 source_box = openmc.stats.Box([-4, -4, -4], [ 4, 4, 4]) - source = openmc.IndependentSource(space=source_box) + source = openmc.Source(space=source_box) model.settings.source = source model.settings.temperature['default'] = 293 diff --git a/tests/regression_tests/dagmc/legacy/inputs_true.dat b/tests/regression_tests/dagmc/legacy/inputs_true.dat index ad2f8e54d..2f5641046 100644 --- a/tests/regression_tests/dagmc/legacy/inputs_true.dat +++ b/tests/regression_tests/dagmc/legacy/inputs_true.dat @@ -1,38 +1,39 @@ - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - - - - 1 - - - 1 - total - - - + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + + + + 1 + + + 1 + total + + diff --git a/tests/regression_tests/dagmc/legacy/results_true.dat b/tests/regression_tests/dagmc/legacy/results_true.dat index 9a6b481b7..e5127c827 100644 --- a/tests/regression_tests/dagmc/legacy/results_true.dat +++ b/tests/regression_tests/dagmc/legacy/results_true.dat @@ -1,5 +1,5 @@ k-combined: -1.083415E+00 5.991738E-02 +8.426936E-01 5.715847E-02 tally 1: -8.862860E+00 -1.602117E+01 +8.093843E+00 +1.328829E+01 diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index b6b1e376b..dacbc19ee 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -1,13 +1,9 @@ -from pathlib import Path - import openmc import openmc.lib -import h5py -import numpy as np +from pathlib import Path import pytest - -from tests.testing_harness import PyAPITestHarness, config +from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( not openmc.lib._dagmc_enabled(), @@ -15,9 +11,8 @@ pytestmark = pytest.mark.skipif( @pytest.fixture def model(): - openmc.reset_auto_ids() - model = openmc.Model() + model = openmc.model.Model() # settings model.settings.batches = 5 @@ -26,10 +21,12 @@ def model(): source_box = openmc.stats.Box([-4, -4, -4], [ 4, 4, 4]) - source = openmc.IndependentSource(space=source_box) + source = openmc.Source(space=source_box) model.settings.source = source + model.settings.dagmc = True + # geometry dag_univ = openmc.DAGMCUniverse(Path("dagmc.h5m")) model.geometry = openmc.Geometry(dag_univ) @@ -58,50 +55,6 @@ def model(): return model - -def test_missing_material_id(model): - # remove the last material, which is identified by ID in the DAGMC file - model.materials = model.materials[:-1] - with pytest.raises(RuntimeError) as exec_info: - model.run() - exp_error_msg = "Material with name/ID '41' not found for volume (cell) 3" - assert exp_error_msg in str(exec_info.value) - - -def test_missing_material_name(model): - # remove the first material, which is identified by name in the DAGMC file - model.materials = model.materials[1:] - with pytest.raises(RuntimeError) as exec_info: - model.run() - exp_error_msg = "Material with name/ID 'no-void fuel' not found for volume (cell) 1" - assert exp_error_msg in str(exec_info.value) - - -def test_surf_source(model): - # create a surface source read on this model to ensure - # particles are being generated correctly - n = 100 - model.settings.surf_source_write = {'surface_ids': [1], 'max_particles': n} - - # If running in MPI mode, setup proper keyword arguments for run() - kwargs = {'openmc_exec': config['exe']} - if config['mpi']: - kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] - model.run(**kwargs) - - with h5py.File('surface_source.h5') as fh: - assert fh.attrs['filetype'] == b'source' - arr = fh['source_bank'][...] - expected_size = n * int(config['mpi_np']) if config['mpi'] else n - assert arr.size == expected_size - - # check that all particles are on surface 1 (radius = 7) - xs = arr[:]['r']['x'] - ys = arr[:]['r']['y'] - rad = np.sqrt(xs**2 + ys**2) - assert np.allclose(rad, 7.0) - - def test_dagmc(model): harness = PyAPITestHarness('statepoint.5.h5', model) - harness.main() \ No newline at end of file + harness.main() diff --git a/tests/regression_tests/dagmc/refl/inputs_true.dat b/tests/regression_tests/dagmc/refl/inputs_true.dat index 58cb9e66f..938916ece 100644 --- a/tests/regression_tests/dagmc/refl/inputs_true.dat +++ b/tests/regression_tests/dagmc/refl/inputs_true.dat @@ -1,28 +1,29 @@ - - - - - - - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - - - - 2 - - - 1 - total - - - + + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + + + + 2 + + + 1 + total + + diff --git a/tests/regression_tests/dagmc/refl/results_true.dat b/tests/regression_tests/dagmc/refl/results_true.dat index b49a4a7a4..bd1169835 100644 --- a/tests/regression_tests/dagmc/refl/results_true.dat +++ b/tests/regression_tests/dagmc/refl/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.047107E+00 8.605767E-02 +2.130286E+00 2.412252E-02 tally 1: -1.145034E+01 -2.636875E+01 +1.177815E+01 +2.806871E+01 diff --git a/tests/regression_tests/dagmc/refl/test.py b/tests/regression_tests/dagmc/refl/test.py index a13acc025..3fe41345c 100644 --- a/tests/regression_tests/dagmc/refl/test.py +++ b/tests/regression_tests/dagmc/refl/test.py @@ -6,33 +6,40 @@ import pytest from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.lib._uwuw_enabled(), - reason="UWUW is not enabled.") + not openmc.lib._dagmc_enabled(), + reason="DAGMC CAD geometry is not enabled.") class UWUWTest(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + + def _build_inputs(self): + model = openmc.model.Model() # settings - self._model.settings.batches = 5 - self._model.settings.inactive = 0 - self._model.settings.particles = 100 + model.settings.batches = 5 + model.settings.inactive = 0 + model.settings.particles = 100 - source = openmc.IndependentSource(space=Box([-4, -4, -4], - [ 4, 4, 4])) - self._model.settings.source = source + source = openmc.Source(space=Box([-4, -4, -4], + [ 4, 4, 4])) + model.settings.source = source + + model.settings.dagmc = True + + model.settings.export_to_xml() # geometry dag_univ = openmc.DAGMCUniverse("dagmc.h5m", auto_geom_ids=True) - self._model.geometry = openmc.Geometry(dag_univ) + model.geometry = openmc.Geometry(dag_univ) # tally tally = openmc.Tally() tally.scores = ['total'] tally.filters = [openmc.CellFilter(2)] - self._model.tallies = [tally] + model.tallies = [tally] + model.tallies.export_to_xml() + model.export_to_xml() def test_refl(): - harness = UWUWTest('statepoint.5.h5', model=openmc.Model()) + harness = UWUWTest('statepoint.5.h5') harness.main() diff --git a/tests/regression_tests/dagmc/universes/inputs_true.dat b/tests/regression_tests/dagmc/universes/inputs_true.dat index be1a17383..ea6ad519b 100644 --- a/tests/regression_tests/dagmc/universes/inputs_true.dat +++ b/tests/regression_tests/dagmc/universes/inputs_true.dat @@ -1,72 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 24.0 24.0 - 2 2 - -24.0 -24.0 - -1 1 -1 1 - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -10.0 -10.0 -24.0 10.0 10.0 24.0 - - - true - - - - false - - - - - 4 0 4 1 4 2 4 3 4 4 - - - 1 - scatter - - - + + + + + 24.0 24.0 + 2 2 + -24.0 -24.0 + +9 9 +9 9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 2 + + false + + diff --git a/tests/regression_tests/dagmc/universes/results_true.dat b/tests/regression_tests/dagmc/universes/results_true.dat index aacb7d1ab..0dc1789d4 100644 --- a/tests/regression_tests/dagmc/universes/results_true.dat +++ b/tests/regression_tests/dagmc/universes/results_true.dat @@ -1,13 +1,2 @@ k-combined: -9.719586E-01 3.630894E-02 -tally 1: -4.463288E+00 -4.136647E+00 -4.769631E+00 -4.622840E+00 -4.315273E+00 -3.871129E+00 -4.091804E+00 -3.582192E+00 -0.000000E+00 -0.000000E+00 +9.436168E-01 2.905559E-02 diff --git a/tests/regression_tests/dagmc/universes/test.py b/tests/regression_tests/dagmc/universes/test.py index d68c6b11c..47897ad56 100644 --- a/tests/regression_tests/dagmc/universes/test.py +++ b/tests/regression_tests/dagmc/universes/test.py @@ -11,87 +11,77 @@ pytestmark = pytest.mark.skipif( reason="DAGMC CAD geometry is not enabled.") -@pytest.fixture -def pin_lattice_model(): - ### MATERIALS ### - fuel = openmc.Material(name='no-void fuel') - fuel.set_density('g/cc', 10.29769) - fuel.add_nuclide('U234', 0.93120485) - fuel.add_nuclide('U235', 0.00055815) - fuel.add_nuclide('U238', 0.022408) - fuel.add_nuclide('O16', 0.045829) +class DAGMCUniverseTest(PyAPITestHarness): - cladding = openmc.Material(name='clad') - cladding.set_density('g/cc', 6.55) - cladding.add_nuclide('Zr90', 0.021827) - cladding.add_nuclide('Zr91', 0.00476) - cladding.add_nuclide('Zr92', 0.0072758) - cladding.add_nuclide('Zr94', 0.0073734) - cladding.add_nuclide('Zr96', 0.0011879) + def _build_inputs(self): + model = openmc.model.Model() - water = openmc.Material(name='water') - water.set_density('g/cc', 0.740582) - water.add_nuclide('H1', 0.049457) - water.add_nuclide('O16', 0.024672) - water.add_nuclide('B10', 8.0042e-06) - water.add_nuclide('B11', 3.2218e-05) - water.add_s_alpha_beta('c_H_in_H2O') + ### MATERIALS ### + fuel = openmc.Material(name='no-void fuel') + fuel.set_density('g/cc', 10.29769) + fuel.add_nuclide('U234', 0.93120485) + fuel.add_nuclide('U235', 0.00055815) + fuel.add_nuclide('U238', 0.022408) + fuel.add_nuclide('O16', 0.045829) - model = openmc.Model() - model.materials = openmc.Materials([fuel, cladding, water]) + cladding = openmc.Material(name='clad') + cladding.set_density('g/cc', 6.55) + cladding.add_nuclide('Zr90', 0.021827) + cladding.add_nuclide('Zr91', 0.00476) + cladding.add_nuclide('Zr92', 0.0072758) + cladding.add_nuclide('Zr94', 0.0073734) + cladding.add_nuclide('Zr96', 0.0011879) - ### GEOMETRY ### - # create the DAGMC universe - pincell_univ = openmc.DAGMCUniverse(filename='dagmc.h5m', auto_geom_ids=True) + water = openmc.Material(name='water') + water.set_density('g/cc', 0.740582) + water.add_nuclide('H1', 0.049457) + water.add_nuclide('O16', 0.024672) + water.add_nuclide('B10', 8.0042e-06) + water.add_nuclide('B11', 3.2218e-05) + water.add_s_alpha_beta('c_H_in_H2O') - # creates another DAGMC universe, this time with within a bounded cell - bound_pincell_universe = openmc.DAGMCUniverse(filename='dagmc.h5m').bounded_universe() - # uses the bound_dag_cell as the root argument to test the type checks in openmc.Geometry - bound_pincell_geometry = openmc.Geometry(root=bound_pincell_universe) - # assigns the bound_dag_geometry to the model to test the type checks in model.Geometry setter - model.geometry = bound_pincell_geometry + model.materials = openmc.Materials([fuel, cladding, water]) - # create a 2 x 2 lattice using the DAGMC pincell - pitch = np.asarray((24.0, 24.0)) - lattice = openmc.RectLattice() - lattice.pitch = pitch - lattice.universes = [[pincell_univ] * 2] * 2 - lattice.lower_left = -pitch + ### GEOMETRY ### + # create the DAGMC universe + pincell_univ = openmc.DAGMCUniverse(filename='dagmc.h5m', auto_geom_ids=True) - left = openmc.XPlane(x0=-pitch[0], name='left', boundary_type='reflective') - right = openmc.XPlane(x0=pitch[0], name='right', boundary_type='reflective') - front = openmc.YPlane(y0=-pitch[1], name='front', boundary_type='reflective') - back = openmc.YPlane(y0=pitch[1], name='back', boundary_type='reflective') - # clip the DAGMC geometry at +/- 10 cm w/ CSG planes - bottom = openmc.ZPlane(z0=-10.0, name='bottom', boundary_type='reflective') - top = openmc.ZPlane(z0=10.0, name='top', boundary_type='reflective') + # creates another DAGMC universe, this time with within a bounded cell + bound_pincell_universe = openmc.DAGMCUniverse(filename='dagmc.h5m').bounded_universe() + # uses the bound_dag_cell as the root argument to test the type checks in openmc.Geometry + bound_pincell_geometry = openmc.Geometry(root=bound_pincell_universe) + # assigns the bound_dag_geometry to the model to test the type checks in model.Geometry setter + model.Geometry = bound_pincell_geometry - bounding_region = +left & -right & +front & -back & +bottom & -top - bounding_cell = openmc.Cell(fill=lattice, region=bounding_region) + # create a 2 x 2 lattice using the DAGMC pincell + pitch = np.asarray((24.0, 24.0)) + lattice = openmc.RectLattice() + lattice.pitch = pitch + lattice.universes = [[pincell_univ] * 2] * 2 + lattice.lower_left = -pitch - model.geometry = openmc.Geometry([bounding_cell]) + left = openmc.XPlane(x0=-pitch[0], name='left', boundary_type='reflective') + right = openmc.XPlane(x0=pitch[0], name='right', boundary_type='reflective') + front = openmc.YPlane(y0=-pitch[1], name='front', boundary_type='reflective') + back = openmc.YPlane(y0=pitch[1], name='back', boundary_type='reflective') + # clip the DAGMC geometry at +/- 10 cm w/ CSG planes + bottom = openmc.ZPlane(z0=-10.0, name='bottom', boundary_type='reflective') + top = openmc.ZPlane(z0=10.0, name='top', boundary_type='reflective') - # add a cell instance tally - tally = openmc.Tally(name='cell instance tally') - # using scattering - cell_instance_filter = openmc.CellInstanceFilter(((4, 0), (4, 1), (4, 2), (4, 3), (4, 4))) - tally.filters = [cell_instance_filter] - tally.scores = ['scatter'] - model.tallies = [tally] + bounding_region = +left & -right & +front & -back & +bottom & -top + bounding_cell = openmc.Cell(fill=lattice, region=bounding_region) - # settings - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.output = {'summary' : False} - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box((-10., -10., -24.), (10., 10., 24.)), - constraints={'fissionable': True}, - ) + model.geometry = openmc.Geometry([bounding_cell]) - return model + # settings + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.inactive = 2 + model.settings.output = {'summary' : False} + + model.export_to_xml() -def test_univ(pin_lattice_model): - harness = PyAPITestHarness('statepoint.10.h5', model=pin_lattice_model) +def test_univ(): + harness = DAGMCUniverseTest('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/dagmc/uwuw/inputs_true.dat b/tests/regression_tests/dagmc/uwuw/inputs_true.dat index 01082cb23..7d533c5db 100644 --- a/tests/regression_tests/dagmc/uwuw/inputs_true.dat +++ b/tests/regression_tests/dagmc/uwuw/inputs_true.dat @@ -1,28 +1,29 @@ - - - - - - - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - - - - 1 - - - 1 - total - - - + + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + + + + 1 + + + 1 + total + + diff --git a/tests/regression_tests/dagmc/uwuw/test.py b/tests/regression_tests/dagmc/uwuw/test.py index bea464cfa..5c9777d48 100644 --- a/tests/regression_tests/dagmc/uwuw/test.py +++ b/tests/regression_tests/dagmc/uwuw/test.py @@ -6,33 +6,39 @@ import pytest from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.lib._uwuw_enabled(), - reason="UWUW is not enabled.") + not openmc.lib._dagmc_enabled(), + reason="DAGMC CAD geometry is not enabled.") class UWUWTest(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + + def _build_inputs(self): + model = openmc.model.Model() # settings - self._model.settings.batches = 5 - self._model.settings.inactive = 0 - self._model.settings.particles = 100 + model.settings.batches = 5 + model.settings.inactive = 0 + model.settings.particles = 100 - source = openmc.IndependentSource(space=Box([-4, -4, -4], - [ 4, 4, 4])) - self._model.settings.source = source + source = openmc.Source(space=Box([-4, -4, -4], + [ 4, 4, 4])) + model.settings.source = source + + model.settings.dagmc = True + + model.settings.export_to_xml() # geometry dag_univ = openmc.DAGMCUniverse("dagmc.h5m") - self._model.geometry = openmc.Geometry(root=dag_univ) + model.geometry = openmc.Geometry(root=dag_univ) # tally tally = openmc.Tally() tally.scores = ['total'] tally.filters = [openmc.CellFilter(1)] - self._model.tallies = [tally] + model.tallies = [tally] + model.export_to_xml() def test_uwuw(): - harness = UWUWTest('statepoint.5.h5', model=openmc.Model()) + harness = UWUWTest('statepoint.5.h5') harness.main() diff --git a/tests/regression_tests/density/results_true.dat b/tests/regression_tests/density/results_true.dat index 42dc0c19f..17d0730df 100644 --- a/tests/regression_tests/density/results_true.dat +++ b/tests/regression_tests/density/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.082191E+00 3.064029E-02 +1.097336E+00 2.305434E-02 diff --git a/tests/regression_tests/deplete_decay_only/__init__.py b/tests/regression_tests/deplete_decay_only/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/deplete_decay_only/test.py b/tests/regression_tests/deplete_decay_only/test.py deleted file mode 100644 index 4345b86b8..000000000 --- a/tests/regression_tests/deplete_decay_only/test.py +++ /dev/null @@ -1,103 +0,0 @@ -""" Transport-free depletion test suite """ - -from pathlib import Path -import shutil - -import numpy as np -import pytest -import openmc -import openmc.deplete -from openmc.deplete import CoupledOperator, IndependentOperator, MicroXS - - -@pytest.fixture(scope="module") -def model(): - fuel = openmc.Material(name="uo2") - fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) - fuel.add_element("O", 2) - fuel.add_nuclide("Xe135_m1", 1) - fuel.add_nuclide("Cs135_m1", 1) - fuel.set_density("g/cc", 10.4) - - clad = openmc.Material(name="clad") - clad.add_element("Zr", 1) - clad.set_density("g/cc", 6) - - water = openmc.Material(name="water") - water.add_element("O", 1) - water.add_element("H", 2) - water.set_density("g/cc", 1.0) - water.add_s_alpha_beta("c_H_in_H2O") - - radii = [0.42, 0.45] - fuel.volume = np.pi * radii[0] ** 2 - - materials = openmc.Materials([fuel, clad, water]) - - pin_surfaces = [openmc.ZCylinder(r=r) for r in radii] - pin_univ = openmc.model.pin(pin_surfaces, materials) - bound_box = openmc.model.RectangularPrism(1.24, 1.24, boundary_type="reflective") - root_cell = openmc.Cell(fill=pin_univ, region=-bound_box) - geometry = openmc.Geometry([root_cell]) - - settings = openmc.Settings() - settings.particles = 1000 - settings.inactive = 5 - settings.batches = 10 - - return openmc.Model(geometry, materials, settings) - -@pytest.fixture(scope="module") -def micro_xs(): - micro_xs_file = Path(__file__).parents[2] / 'micro_xs_simple.csv' - return MicroXS.from_csv(micro_xs_file) - - -@pytest.fixture(scope="module") -def chain_file(): - return Path(__file__).parents[2] / 'chain_simple_decay.xml' - - -@pytest.mark.parametrize("operator_type", ["coupled", "independent"]) -def test_decay_only(run_in_tmpdir, operator_type, model, micro_xs, chain_file): - """Transport free system test suite. - - """ - # Create operator - if operator_type == "coupled": - op = CoupledOperator(model, chain_file=chain_file) - else: - op = IndependentOperator(openmc.Materials([model.materials[0]]), - [1e15], - [micro_xs], - chain_file) - - # Power and timesteps - dt = [917.4, 2262.6] # one Xe135_m1 half life and one Cs135_m1 half life - - # Perform simulation using the predictor algorithm - openmc.deplete.PredictorIntegrator(op, - dt, - power=0.0, - timestep_units='s').integrate() - - # Get path to test and reference results - path_test = op.output_dir / 'depletion_results.h5' - - # Load the reference/test results - res_test = openmc.deplete.Results(path_test) - - _, xe135m1_atoms = res_test.get_atoms('1', 'Xe135_m1') - _, xe135_atoms = res_test.get_atoms('1', 'Xe135') - _, cs135m1_atoms = res_test.get_atoms('1', 'Cs135_m1') - _, cs135_atoms = res_test.get_atoms('1', 'Cs135') - - tol = 1.0e-14 - assert xe135m1_atoms[0] == pytest.approx(xe135m1_atoms[1] * 2, rel=tol) - - # WARNING: this is generally not true as Xe135_m1 has two - # decay modes, and Xe135 will also decay, but we've modified the depletion chain so - # that Xe135_m1 only decays to Xe135, and that Xe135 has has no decay modes - assert xe135_atoms[1] == pytest.approx(xe135m1_atoms[1], rel=tol) - assert cs135m1_atoms[0] == pytest.approx(cs135m1_atoms[2] * 2, rel=tol) - assert cs135_atoms[2] == pytest.approx(cs135m1_atoms[2], rel=tol) diff --git a/tests/regression_tests/deplete_no_transport/test.py b/tests/regression_tests/deplete_no_transport/test.py index 5550ad048..f5ee4bf1d 100644 --- a/tests/regression_tests/deplete_no_transport/test.py +++ b/tests/regression_tests/deplete_no_transport/test.py @@ -1,7 +1,6 @@ """ Transport-free depletion test suite """ from pathlib import Path -import shutil import numpy as np import pytest @@ -9,10 +8,6 @@ import openmc import openmc.deplete from openmc.deplete import IndependentOperator, MicroXS -from tests.regression_tests import config, assert_atoms_equal, \ - assert_reaction_rates_equal, assert_same_mats - - @pytest.fixture(scope="module") def fuel(): fuel = openmc.Material(name="uo2") @@ -30,22 +25,17 @@ def micro_xs(): micro_xs_file = Path(__file__).parents[2] / 'micro_xs_simple.csv' return MicroXS.from_csv(micro_xs_file) - @pytest.fixture(scope="module") def chain_file(): return Path(__file__).parents[2] / 'chain_simple.xml' - -neutron_per_cm2_sec = 1164719970082145.0 - - -@pytest.mark.parametrize("multiproc, from_nuclides, normalization_mode, power, source_rate", [ - (True, True, 'source-rate', None, 1.0), - (False, True, 'source-rate', None, 1.0), +@pytest.mark.parametrize("multiproc, from_nuclides, normalization_mode, power, flux", [ + (True, True,'source-rate', None, 1164719970082145.0), + (False, True, 'source-rate', None, 1164719970082145.0), (True, True, 'fission-q', 174, None), (False, True, 'fission-q', 174, None), - (True, False, 'source-rate', None, 1.0), - (False, False, 'source-rate', None, 1.0), + (True, False,'source-rate', None, 1164719970082145.0), + (False, False, 'source-rate', None, 1164719970082145.0), (True, False, 'fission-q', 174, None), (False, False, 'fission-q', 174, None)]) def test_against_self(run_in_tmpdir, @@ -56,7 +46,7 @@ def test_against_self(run_in_tmpdir, from_nuclides, normalization_mode, power, - source_rate): + flux): """Transport free system test suite. Runs an OpenMC transport-free depletion calculation and verifies @@ -64,10 +54,8 @@ def test_against_self(run_in_tmpdir, """ # Create operator - flux = neutron_per_cm2_sec * fuel.volume op = _create_operator(from_nuclides, fuel, - flux, micro_xs, chain_file, normalization_mode) @@ -76,47 +64,39 @@ def test_against_self(run_in_tmpdir, dt = [360] # single step # Perform simulation using the predictor algorithm - if config['mpi'] and multiproc: - pytest.skip("Multiprocessing depletion is disabled when MPI is enabled.") openmc.deplete.pool.USE_MULTIPROCESSING = multiproc openmc.deplete.PredictorIntegrator(op, dt, power=power, - source_rates=source_rate, + source_rates=flux, timestep_units='s').integrate() # Get path to test and reference results path_test = op.output_dir / 'depletion_results.h5' - if power is None: + if flux is not None: ref_path = 'test_reference_source_rate.h5' else: ref_path = 'test_reference_fission_q.h5' path_reference = Path(__file__).with_name(ref_path) - # If updating results, do so and return - if config['update']: - shutil.copyfile(str(path_test), str(path_reference)) - return - # Load the reference/test results res_test = openmc.deplete.Results(path_test) res_ref = openmc.deplete.Results(path_reference) # Assert same mats - assert_same_mats(res_ref, res_test) + _assert_same_mats(res_test, res_ref) tol = 1.0e-14 - assert_atoms_equal(res_ref, res_test, tol) - assert_reaction_rates_equal(res_ref, res_test, tol) - + _assert_atoms_equal(res_test, res_ref, tol) + _assert_reaction_rates_equal(res_test, res_ref, tol) @pytest.mark.parametrize("multiproc, dt, time_units, time_type, atom_tol, rx_tol ", [ (True, 360, 's', 'minutes', 2.0e-3, 3.0e-2), (False, 360, 's', 'minutes', 2.0e-3, 3.0e-2), (True, 4, 'h', 'hours', 2.0e-3, 6.0e-2), - (False, 4, 'h', 'hours', 2.0e-3, 6.0e-2), + (False,4, 'h', 'hours', 2.0e-3, 6.0e-2), (True, 5, 'd', 'days', 2.0e-3, 5.0e-2), - (False, 5, 'd', 'days', 2.0e-3, 5.0e-2), + (False,5, 'd', 'days', 2.0e-3, 5.0e-2), (True, 100, 'd', 'months', 4.0e-3, 9.0e-2), (False, 100, 'd', 'months', 4.0e-3, 9.0e-2)]) def test_against_coupled(run_in_tmpdir, @@ -130,15 +110,12 @@ def test_against_coupled(run_in_tmpdir, atom_tol, rx_tol): # Create operator - flux = neutron_per_cm2_sec * fuel.volume - op = _create_operator(False, fuel, flux, micro_xs, chain_file, 'fission-q') + op = _create_operator(False, fuel, micro_xs, chain_file, 'fission-q') # Power and timesteps dt = [dt] # single step # Perform simulation using the predictor algorithm - if config['mpi'] and multiproc: - pytest.skip("Multiprocessing depletion is disabled when MPI is enabled.") openmc.deplete.pool.USE_MULTIPROCESSING = multiproc openmc.deplete.PredictorIntegrator( op, dt, power=174, timestep_units=time_units).integrate() @@ -149,25 +126,18 @@ def test_against_coupled(run_in_tmpdir, ref_path = f'test_reference_coupled_{time_type}.h5' path_reference = Path(__file__).with_name(ref_path) - # If updating results, do so and return - if config['update']: - shutil.copyfile(str(path_test), str(path_reference)) - return - # Load the reference/test results res_test = openmc.deplete.Results(path_test) res_ref = openmc.deplete.Results(path_reference) # Assert same mats - assert_same_mats(res_test, res_ref) - - assert_atoms_equal(res_ref, res_test, atom_tol) - assert_reaction_rates_equal(res_ref, res_test, rx_tol) + _assert_same_mats(res_test, res_ref) + _assert_atoms_equal(res_test, res_ref, atom_tol) + _assert_reaction_rates_equal(res_test, res_ref, rx_tol) def _create_operator(from_nuclides, fuel, - flux, micro_xs, chain_file, normalization_mode): @@ -176,19 +146,72 @@ def _create_operator(from_nuclides, for nuc, dens in fuel.get_nuclide_atom_densities().items(): nuclides[nuc] = dens - openmc.reset_auto_ids() op = IndependentOperator.from_nuclides(fuel.volume, nuclides, - flux, micro_xs, chain_file, normalization_mode=normalization_mode) else: op = IndependentOperator(openmc.Materials([fuel]), - [flux], - [micro_xs], + micro_xs, chain_file, normalization_mode=normalization_mode) return op + +def _assert_same_mats(res_ref, res_test): + for mat in res_ref[0].mat_to_ind: + assert mat in res_test[0].mat_to_ind, \ + "Material {} not in new results.".format(mat) + for nuc in res_ref[0].nuc_to_ind: + assert nuc in res_test[0].nuc_to_ind, \ + "Nuclide {} not in new results.".format(nuc) + + for mat in res_test[0].mat_to_ind: + assert mat in res_ref[0].mat_to_ind, \ + "Material {} not in old results.".format(mat) + for nuc in res_test[0].nuc_to_ind: + assert nuc in res_ref[0].nuc_to_ind, \ + "Nuclide {} not in old results.".format(nuc) + +def _assert_atoms_equal(res_ref, res_test, tol): + for mat in res_test[0].mat_to_ind: + for nuc in res_test[0].nuc_to_ind: + _, y_test = res_test.get_atoms(mat, nuc) + _, y_old = res_ref.get_atoms(mat, nuc) + + # Test each point + correct = True + for i, ref in enumerate(y_old): + if ref != y_test[i]: + if ref != 0.0: + correct = np.abs(y_test[i] - ref) / ref <= tol + else: + correct = False + + assert correct, "Discrepancy in mat {} and nuc {}\n{}\n{}".format( + mat, nuc, y_old, y_test) + +def _assert_reaction_rates_equal(res_ref, res_test, tol): + for reactions in res_test[0].rates: + for mat in reactions.index_mat: + for nuc in reactions.index_nuc: + for rx in reactions.index_rx: + y_test = res_test.get_reaction_rate(mat, nuc, rx)[1] / \ + res_test.get_atoms(mat, nuc)[1] + y_old = res_ref.get_reaction_rate(mat, nuc, rx)[1] / \ + res_ref.get_atoms(mat, nuc)[1] + + # Test each point + correct = True + for i, ref in enumerate(y_old): + if ref != y_test[i]: + if ref != 0.0: + correct = np.abs(y_test[i] - ref) / ref <= tol + else: + if y_test[i] != 0.0: + correct = False + + assert correct, "Discrepancy in mat {}, nuc {}, and rx {}\n{}\n{}".format( + mat, nuc, rx, y_old, y_test) diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 index 9757c9791..d97acffec 100644 Binary files a/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 index 08d4d3eed..6d9bcc91f 100644 Binary files a/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 index 41b5235bb..1e22bf2b7 100644 Binary files a/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 index 53d80aff0..43b45cb37 100644 Binary files a/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 b/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 index fe695692d..826c5f3b0 100644 Binary files a/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 and b/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 b/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 index c9c7e9e36..f5161d370 100644 Binary files a/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 and b/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 differ diff --git a/tests/regression_tests/deplete_with_keff_search_control/__init__.py b/tests/regression_tests/deplete_with_keff_search_control/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_refuel.h5 b/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_refuel.h5 deleted file mode 100644 index a335e3b47..000000000 Binary files a/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_refuel.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_rotation.h5 b/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_rotation.h5 deleted file mode 100644 index c8b4f67ff..000000000 Binary files a/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_rotation.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_translation.h5 b/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_translation.h5 deleted file mode 100644 index 35285321b..000000000 Binary files a/tests/regression_tests/deplete_with_keff_search_control/ref_depletion_with_translation.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_keff_search_control/test.py b/tests/regression_tests/deplete_with_keff_search_control/test.py deleted file mode 100644 index 82e601280..000000000 --- a/tests/regression_tests/deplete_with_keff_search_control/test.py +++ /dev/null @@ -1,140 +0,0 @@ -""" Tests for KeffSearchControl class """ - -from hmac import new -from pathlib import Path -import shutil -import sys - -import pytest -import numpy as np - -import openmc -import openmc.lib -from openmc.deplete import CoupledOperator - -from tests.regression_tests import config - -@pytest.fixture -def model(): - f = openmc.Material(name='f') - f.set_density('g/cm3', 10.29769) - f.add_element('U', 1., enrichment=2.4) - f.add_element('O', 2.) - - h = openmc.Material(name='h') - h.set_density('g/cm3', 0.001598) - h.add_element('He', 2.4044e-4) - - w = openmc.Material(name='w') - w.set_density('g/cm3', 0.740582) - w.add_element('H', 2) - w.add_element('O', 1) - - # Define overall material - materials = openmc.Materials([f, h, w]) - - # Define surfaces - radii = [0.5, 0.8, 1] - height = 80 - surf_in = openmc.ZCylinder(r=radii[0]) - surf_mid = openmc.ZCylinder(r=radii[1]) - surf_out = openmc.ZCylinder(r=radii[2], boundary_type='reflective') - surf_top = openmc.ZPlane(z0=height/2, boundary_type='vacuum') - surf_bot = openmc.ZPlane(z0=-height/2, boundary_type='vacuum') - - surf_trans = openmc.ZPlane(z0=0) - surf_rot1 = openmc.XPlane(x0=0) - surf_rot2 = openmc.YPlane(y0=0) - - # Define cells - cell_f = openmc.Cell(name='fuel_cell', fill=f, - region=-surf_in & -surf_top & +surf_bot) - cell_g = openmc.Cell(fill=h, - region = +surf_in & -surf_mid & -surf_top & +surf_bot & +surf_rot2) - - # Define unbounded cells for rotation universe - cell_w = openmc.Cell(fill=w, region = -surf_rot1) - cell_h = openmc.Cell(fill=h, region = +surf_rot1) - universe_rot = openmc.Universe(cells=(cell_w, cell_h)) - cell_rot = openmc.Cell(name="rot_cell", fill=universe_rot, - region = +surf_in & -surf_mid & -surf_top & +surf_bot & -surf_rot2) - - # Define unbounded cells for translation universe - cell_w = openmc.Cell(fill=w, region=+surf_in & -surf_trans ) - cell_h = openmc.Cell(fill=h, region=+surf_in & +surf_trans) - universe_trans = openmc.Universe(cells=(cell_w, cell_h)) - cell_trans = openmc.Cell(name="trans_cell", fill=universe_trans, - region=+surf_mid & -surf_out & -surf_top & +surf_bot) - - # Define overall geometry - geometry = openmc.Geometry([cell_f, cell_g, cell_rot, cell_trans]) - - # Set material volume for depletion fuel. - f.volume = np.pi * radii[0]**2 * height - - settings = openmc.Settings() - settings.particles = 1000 - settings.inactive = 10 - settings.batches = 50 - - return openmc.Model(geometry, materials, settings) - - -def translate_cell(position): - cell_trans = [cell for cell in openmc.lib.cells.values() if cell.name == 'trans_cell'][0] - openmc.lib.cells[cell_trans.id].translation = [0, 0, position] - - -def rotate_cell(angle): - cell_rot = [cell for cell in openmc.lib.cells.values() if cell.name == 'rot_cell'][0] - openmc.lib.cells[cell_rot.id].rotation = [0, 0, angle] - - -def set_u235_density(u235_density): - fuel = [material for material in openmc.lib.materials.values() - if material.name == 'f'][0] - nuclides = openmc.lib.materials[fuel.id].nuclides - densities = openmc.lib.materials[fuel.id].densities - nuc_idx = nuclides.index('U235') - densities[nuc_idx] = u235_density - openmc.lib.materials[fuel.id].set_densities(nuclides, densities) - - -@pytest.mark.parametrize("function, x0, x1, bracket, ref_result", [ - (translate_cell, -11, -5, (-15, 0), 'depletion_with_translation'), - (rotate_cell, -80, -50, (-90, 0), 'depletion_with_rotation'), - (set_u235_density, 2e-4, 1e-3, (1e-4, 2e-3), 'depletion_with_refuel') -]) -def test_keff_search_control(run_in_tmpdir, model, function, x0, x1, bracket, ref_result): - chain_file = Path(__file__).parents[2] / 'chain_simple.xml' - model.settings.verbosity = 1 - op = CoupledOperator(model, chain_file) - - integrator = openmc.deplete.PredictorIntegrator( - op, [1], 174., timestep_units = 'd') - integrator.add_keff_search_control( - function=function, - x0=x0, - x1=x1, - bracket=bracket, - output=True, - k_tol=0.1, - sigma_final=5e-2) - - integrator.integrate() - - # Get path to test and reference results - path_test = op.output_dir / 'depletion_results.h5' - path_reference = Path(__file__).with_name(f'ref_{ref_result}.h5') - - # If updating results, do so and return - if config['update']: - shutil.copyfile(str(path_test), str(path_reference)) - return - - # Load the reference/test results - res_test = openmc.deplete.Results(path_test) - res_ref = openmc.deplete.Results(path_reference) - - # Use high tolerance here - assert res_test[0].keff_search_root == pytest.approx(res_ref[0].keff_search_root, rel=2) diff --git a/tests/regression_tests/deplete_with_transfer_rates/__init__.py b/tests/regression_tests/deplete_with_transfer_rates/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_ext_source.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_ext_source.h5 deleted file mode 100644 index 2f9951a42..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_ext_source.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 deleted file mode 100644 index 25ab31041..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_redox.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_redox.h5 deleted file mode 100644 index c7f002ba1..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_redox.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 deleted file mode 100644 index c3121a953..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal_and_redox.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal_and_redox.h5 deleted file mode 100644 index 80ce771fc..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal_and_redox.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 deleted file mode 100644 index 2a4c227bb..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer_and_redox.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer_and_redox.h5 deleted file mode 100644 index 6847fd7df..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer_and_redox.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_feed.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_feed.h5 deleted file mode 100644 index af6733340..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_feed.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 deleted file mode 100644 index 59c65427c..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_ext_source.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_ext_source.h5 deleted file mode 100644 index cceb7fc78..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_ext_source.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 deleted file mode 100644 index a1c0e5b41..000000000 Binary files a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/test.py b/tests/regression_tests/deplete_with_transfer_rates/test.py deleted file mode 100644 index 461287f6e..000000000 --- a/tests/regression_tests/deplete_with_transfer_rates/test.py +++ /dev/null @@ -1,128 +0,0 @@ -""" ExternalRates depletion test suite """ - -from pathlib import Path -import shutil - -import numpy as np -import pytest -import openmc -import openmc.deplete -from openmc.deplete import CoupledOperator - -from tests.regression_tests import config, assert_reaction_rates_equal, \ - assert_atoms_equal - -@pytest.fixture -def model(): - openmc.reset_auto_ids() - f = openmc.Material(name="f") - f.add_element("U", 1, percent_type="ao", enrichment=4.25) - f.add_element("O", 2) - f.set_density("g/cc", 10.4) - - w = openmc.Material(name="w") - w.add_element("O", 1) - w.add_element("H", 2) - w.set_density("g/cc", 1.0) - w.depletable = True - - radii = [0.42, 0.45] - f.volume = np.pi * radii[0] ** 2 - w.volume = np.pi * (radii[1]**2 - radii[0]**2) - - materials = openmc.Materials([f, w]) - - surf_f = openmc.Sphere(r=radii[0]) - surf_w = openmc.Sphere(r=radii[1], boundary_type='reflective') - cell_f = openmc.Cell(fill=f, region=-surf_f) - cell_w = openmc.Cell(fill=w, region=+surf_f & -surf_w) - geometry = openmc.Geometry([cell_f, cell_w]) - - settings = openmc.Settings() - settings.particles = 150 - settings.inactive = 0 - settings.batches = 10 - - return openmc.Model(geometry, materials, settings) - - -@pytest.mark.parametrize("rate, dest_mat, power, ref_result", [ - (1e-5, None, 0.0, 'no_depletion_only_removal'), - (-1e-5, None, 0.0, 'no_depletion_only_feed'), - (1e-5, None, 174.0, 'depletion_with_removal'), - (-1e-5, None, 174.0, 'depletion_with_feed'), - (-1e-5, 'w', 0.0, 'no_depletion_with_transfer'), - (1e-5, 'w', 174.0, 'depletion_with_transfer'), - (0.0, None, 174.0, 'depletion_with_redox'), - (1e-5, None, 174.0, 'depletion_with_removal_and_redox'), - (1e-5, 'w', 174.0, 'depletion_with_transfer_and_redox'), - ]) -def test_transfer_rates(run_in_tmpdir, model, rate, dest_mat, power, ref_result): - """Tests transfer_rates depletion class with transfer rates""" - - chain_file = Path(__file__).parents[2] / 'chain_simple.xml' - - transfer_elements = ['Xe'] - os = {'I': -1, 'Xe':0, 'Cs': 1, 'Gd': 3, 'U': 4} - - op = CoupledOperator(model, chain_file) - op.round_number = True - integrator = openmc.deplete.PredictorIntegrator( - op, [1], power, timestep_units = 'd') - if rate != 0.0: - integrator.add_transfer_rate('f', transfer_elements, rate, - destination_material=dest_mat) - if 'redox' in ref_result.split('_'): - integrator.add_redox('f', {'Gd157':1}, os) - - integrator.integrate() - - # Get path to test and reference results - path_test = op.output_dir / 'depletion_results.h5' - path_reference = Path(__file__).with_name(f'ref_{ref_result}.h5') - - # If updating results, do so and return - if config['update']: - shutil.copyfile(str(path_test), str(path_reference)) - return - - # Load the reference/test results - res_ref = openmc.deplete.Results(path_reference) - res_test = openmc.deplete.Results(path_test) - - assert_atoms_equal(res_ref, res_test, tol=1e-3) - assert_reaction_rates_equal(res_ref, res_test, tol=1e-3) - -@pytest.mark.parametrize("rate, power, ref_result", [ - (1e-1, 0.0, 'no_depletion_with_ext_source'), - (1e-1, 174., 'depletion_with_ext_source'), -]) -def test_external_source_rates(run_in_tmpdir, model, rate, power, ref_result): - """Tests external_rates depletion class with external source rates""" - - chain_file = Path(__file__).parents[2] / 'chain_simple.xml' - - external_source_vector = {'U': 1} - - op = CoupledOperator(model, chain_file) - op.round_number = True - integrator = openmc.deplete.PredictorIntegrator( - op, [1], power, timestep_units='d') - integrator.add_external_source_rate('f', external_source_vector, rate) - integrator.integrate() - - # Get path to test and reference results - path_test = op.output_dir / 'depletion_results.h5' - path_reference = Path(__file__).with_name(f'ref_{ref_result}.h5') - - # If updating results, do so and return - if config['update']: - shutil.copyfile(str(path_test), str(path_reference)) - return - - # Load the reference/test results - res_ref = openmc.deplete.Results(path_reference) - res_test = openmc.deplete.Results(path_test) - - assert_atoms_equal(res_ref, res_test, tol=1e-3) - assert_reaction_rates_equal(res_ref, res_test, tol=1e-3) diff --git a/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml b/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml index 2dca55992..fc9fd0cf5 100644 --- a/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml +++ b/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml @@ -1,1049 +1,1057 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/deplete_with_transport/test.py b/tests/regression_tests/deplete_with_transport/test.py index a2be22c56..58065035f 100644 --- a/tests/regression_tests/deplete_with_transport/test.py +++ b/tests/regression_tests/deplete_with_transport/test.py @@ -3,7 +3,6 @@ from math import floor import shutil from pathlib import Path -from collections import defaultdict from difflib import unified_diff import numpy as np @@ -12,7 +11,7 @@ import openmc from openmc.data import JOULE_PER_EV import openmc.deplete -from tests.regression_tests import config, assert_atoms_equal +from tests.regression_tests import config from .example_geometry import generate_problem @@ -46,7 +45,7 @@ def test_full(run_in_tmpdir, problem, multiproc): settings.batches = 10 settings.inactive = 0 space = openmc.stats.Box(lower_left, upper_right) - settings.source = openmc.IndependentSource(space=space) + settings.source = openmc.Source(space=space) settings.seed = 1 settings.verbosity = 1 @@ -65,8 +64,6 @@ def test_full(run_in_tmpdir, problem, multiproc): power = 2.337e15*4*JOULE_PER_EV*1e6 # MeV/second cm from CASMO # Perform simulation using the predictor algorithm - if config['mpi'] and multiproc: - pytest.skip("Multiprocessing depletion is disabled when MPI is enabled.") openmc.deplete.pool.USE_MULTIPROCESSING = multiproc openmc.deplete.PredictorIntegrator(op, dt, power).integrate() @@ -84,21 +81,37 @@ def test_full(run_in_tmpdir, problem, multiproc): res_ref = openmc.deplete.Results(path_reference) # Assert same mats - for mat in res_ref[0].index_mat: - assert mat in res_test[0].index_mat, \ + for mat in res_ref[0].mat_to_ind: + assert mat in res_test[0].mat_to_ind, \ "Material {} not in new results.".format(mat) - for nuc in res_ref[0].index_nuc: - assert nuc in res_test[0].index_nuc, \ + for nuc in res_ref[0].nuc_to_ind: + assert nuc in res_test[0].nuc_to_ind, \ "Nuclide {} not in new results.".format(nuc) - for mat in res_test[0].index_mat: - assert mat in res_ref[0].index_mat, \ + for mat in res_test[0].mat_to_ind: + assert mat in res_ref[0].mat_to_ind, \ "Material {} not in old results.".format(mat) - for nuc in res_test[0].index_nuc: - assert nuc in res_ref[0].index_nuc, \ + for nuc in res_test[0].nuc_to_ind: + assert nuc in res_ref[0].nuc_to_ind, \ "Nuclide {} not in old results.".format(nuc) - assert_atoms_equal(res_ref, res_test, tol=1e-6) + tol = 1.0e-6 + for mat in res_test[0].mat_to_ind: + for nuc in res_test[0].nuc_to_ind: + _, y_test = res_test.get_atoms(mat, nuc) + _, y_old = res_ref.get_atoms(mat, nuc) + + # Test each point + correct = True + for i, ref in enumerate(y_old): + if ref != y_test[i]: + if ref != 0.0: + correct = np.abs(y_test[i] - ref) / ref <= tol + else: + correct = False + + assert correct, "Discrepancy in mat {} and nuc {}\n{}\n{}".format( + mat, nuc, y_old, y_test) # Compare statepoint files with depletion results @@ -109,11 +122,8 @@ def test_full(run_in_tmpdir, problem, multiproc): n_tallies = np.empty(N + 1, dtype=int) # Get statepoint files for all BOS points and EOL - runtimes = defaultdict(list) for n in range(N + 1): statepoint = openmc.StatePoint(f"openmc_simulation_n{n}.h5") - for measure, time in statepoint.runtime.items(): - runtimes[measure].append(time) k_n = statepoint.keff k_state[n] = [k_n.nominal_value, k_n.std_dev] n_tallies[n] = len(statepoint.tallies) @@ -124,21 +134,6 @@ def test_full(run_in_tmpdir, problem, multiproc): # Check that no additional tallies are loaded from the files assert np.all(n_tallies == 0) - # Convert values in runtimes to arrays - runtimes = {k: np.array(v) for k, v in runtimes.items()} - - # Check that runtimes are qualitatively correct - assert runtimes['reading cross sections'][0] != 0 - assert runtimes['total initialization'][0] != 0 - assert np.all(runtimes['reading cross sections'][1:] == 0) - assert np.all(runtimes['total initialization'][1:] == 0) - assert np.all(runtimes['inactive batches'] == 0) - del runtimes['reading cross sections'] - del runtimes['total initialization'] - del runtimes['inactive batches'] - for measure, times in runtimes.items(): - assert np.all(times != 0) - def test_depletion_results_to_material(run_in_tmpdir, problem): """Checks openmc.Materials objects can be created from depletion results""" diff --git a/tests/regression_tests/deplete_with_transport/test_reference.h5 b/tests/regression_tests/deplete_with_transport/test_reference.h5 index cc616e791..d478d628e 100644 Binary files a/tests/regression_tests/deplete_with_transport/test_reference.h5 and b/tests/regression_tests/deplete_with_transport/test_reference.h5 differ diff --git a/tests/regression_tests/diff_tally/inputs_true.dat b/tests/regression_tests/diff_tally/inputs_true.dat index 19356b64a..909475f96 100644 --- a/tests/regression_tests/diff_tally/inputs_true.dat +++ b/tests/regression_tests/diff_tally/inputs_true.dat @@ -1,187 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -199,12 +50,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -222,12 +73,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -249,12 +100,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -276,163 +127,313 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 3 - 0 - - - -160 -160 -183 160 160 183 - - - true - - - - 1 3 - - - 0.0 0.625 20000000.0 - - - 1 - flux - 1 - - - 1 - flux - 2 - - - 1 - flux - 3 - - - 1 - flux - 4 - - - 1 - flux - 5 - - - 1 - total U235 - total absorption scatter fission nu-fission - 1 - - - 1 - total U235 - total absorption scatter fission nu-fission - 2 - - - 1 - total U235 - total absorption scatter fission nu-fission - 3 - - - 1 - total U235 - total absorption scatter fission nu-fission - 4 - - - 1 - total U235 - total absorption scatter fission nu-fission - 5 - - - 1 - absorption - analog - 1 - - - 1 - absorption - analog - 2 - - - 1 - absorption - analog - 3 - - - 1 - absorption - analog - 4 - - - 1 - absorption - analog - 5 - - - 1 2 - total U235 - nu-fission scatter - 1 - - - 1 2 - total U235 - nu-fission scatter - 2 - - - 1 2 - U235 - nu-fission scatter - 3 - - - 1 2 - U235 - nu-fission scatter - 4 - - - 1 2 - U235 - nu-fission scatter - 5 - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 3 + 0 + + + -160 -160 -183 160 160 183 + + + true + + + + + 1 3 + + + 0.0 0.625 20000000.0 + + + 1 + flux + 1 + + + 1 + flux + 2 + + + 1 + flux + 3 + + + 1 + flux + 4 + + + 1 + flux + 5 + + + 1 + total U235 + total absorption scatter fission nu-fission + 1 + + + 1 + total U235 + total absorption scatter fission nu-fission + 2 + + + 1 + total U235 + total absorption scatter fission nu-fission + 3 + + + 1 + total U235 + total absorption scatter fission nu-fission + 4 + + + 1 + total U235 + total absorption scatter fission nu-fission + 5 + + + 1 + absorption + analog + 1 + + + 1 + absorption + analog + 2 + + + 1 + absorption + analog + 3 + + + 1 + absorption + analog + 4 + + + 1 + absorption + analog + 5 + + + 1 2 + total U235 + nu-fission scatter + 1 + + + 1 2 + total U235 + nu-fission scatter + 2 + + + 1 2 + U235 + nu-fission scatter + 3 + + + 1 2 + U235 + nu-fission scatter + 4 + + + 1 2 + U235 + nu-fission scatter + 5 + + + + + + + diff --git a/tests/regression_tests/diff_tally/results_true.dat b/tests/regression_tests/diff_tally/results_true.dat index a88081b7c..12157932f 100644 --- a/tests/regression_tests/diff_tally/results_true.dat +++ b/tests/regression_tests/diff_tally/results_true.dat @@ -1,27 +1,27 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. -3,,density,flux,-9.2822822e+00,1.6880315e+00 -3,,density,flux,-2.0591270e+01,3.0043477e+00 -1,,density,flux,-2.9765141e-01,5.2949290e-02 -1,,density,flux,-4.0095723e-01,1.1716168e-01 -1,O16,nuclide_density,flux,-1.4245069e+01,6.3028710e+00 -1,O16,nuclide_density,flux,-2.5098326e+01,5.7525657e+00 -1,U235,nuclide_density,flux,-2.1513560e+03,6.7234014e+02 -1,U235,nuclide_density,flux,-2.4222736e+03,7.7715656e+02 -1,,temperature,flux,-1.1242141e-04,8.1692839e-05 -1,,temperature,flux,6.1357500e-06,7.4812624e-05 -3,,density,total,-4.2880614e+00,7.0021512e-01 -3,,density,absorption,-5.0324695e-01,4.9079615e-02 -3,,density,scatter,-3.7848144e+00,6.5868388e-01 -3,,density,fission,-2.7732455e-01,6.4647487e-02 -3,,density,nu-fission,-6.7990282e-01,1.5692707e-01 -3,,density,total,-3.8043572e-01,9.6222860e-02 -3,,density,absorption,-3.3518262e-01,8.6810436e-02 -3,,density,scatter,-4.5253106e-02,9.5205809e-03 -3,,density,fission,-2.6400028e-01,6.8175997e-02 -3,,density,nu-fission,-6.4353897e-01,1.6613026e-01 -3,,density,total,-3.2070285e-01,2.8328990e+00 -3,,density,absorption,2.5921007e-02,2.2141808e-02 -3,,density,scatter,-3.4662385e-01,2.8171749e+00 +3,,density,flux,-8.9862333e+00,2.7508460e+00 +3,,density,flux,-1.9778752e+01,3.5926341e+00 +1,,density,flux,-2.6861000e-01,3.8449483e-02 +1,,density,flux,-3.7643515e-01,1.8991066e-01 +1,O16,nuclide_density,flux,-2.5795663e+00,1.6620453e+01 +1,O16,nuclide_density,flux,7.2861106e+00,1.5941849e+01 +1,U235,nuclide_density,flux,-2.2849358e+03,3.9506163e+02 +1,U235,nuclide_density,flux,-2.7845978e+03,5.6693457e+02 +1,,temperature,flux,-1.8666344e-04,1.1088646e-04 +1,,temperature,flux,9.2264971e-05,8.7268407e-05 +3,,density,total,-4.1447663e+00,1.1453915e+00 +3,,density,absorption,-6.0174688e-01,1.0525787e-01 +3,,density,scatter,-3.5430194e+00,1.0499557e+00 +3,,density,fission,-2.8547461e-01,6.7402688e-02 +3,,density,nu-fission,-6.9988357e-01,1.6360007e-01 +3,,density,total,-3.7715161e-01,1.0166405e-01 +3,,density,absorption,-3.3327322e-01,8.9912373e-02 +3,,density,scatter,-4.3878393e-02,1.3801869e-02 +3,,density,fission,-2.7256167e-01,7.1483193e-02 +3,,density,nu-fission,-6.6439453e-01,1.7417261e-01 +3,,density,total,-2.3838461e+00,4.2331432e+00 +3,,density,absorption,-5.7877951e-02,5.3522562e-02 +3,,density,scatter,-2.3259682e+00,4.1799423e+00 3,,density,fission,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,total,0.0000000e+00,0.0000000e+00 @@ -29,19 +29,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 3,,density,scatter,0.0000000e+00,0.0000000e+00 3,,density,fission,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,total,4.0321800e-01,3.5365140e-02 -1,,density,absorption,4.8426976e-03,8.3784362e-03 -1,,density,scatter,3.9837530e-01,2.9076664e-02 -1,,density,fission,-5.4793062e-03,7.1720201e-03 -1,,density,nu-fission,-1.2481616e-02,1.7542625e-02 -1,,density,total,-3.6063021e-03,7.1950060e-03 -1,,density,absorption,-8.2666439e-03,6.9274342e-03 -1,,density,scatter,4.6603417e-03,4.1803496e-04 -1,,density,fission,-7.6315741e-03,7.1774359e-03 -1,,density,nu-fission,-1.8551295e-02,1.7493106e-02 -1,,density,total,-6.2852725e-01,1.9776006e-01 -1,,density,absorption,-1.4850233e-02,4.3086611e-03 -1,,density,scatter,-6.1367701e-01,1.9363188e-01 +1,,density,total,4.0520294e-01,3.3719992e-02 +1,,density,absorption,1.3915754e-02,1.3515385e-02 +1,,density,scatter,3.9128718e-01,2.2403876e-02 +1,,density,fission,2.4781454e-04,1.0189025e-02 +1,,density,nu-fission,1.2555927e-03,2.4804599e-02 +1,,density,total,5.1306892e-03,1.1784483e-02 +1,,density,absorption,6.1064429e-04,1.1572255e-02 +1,,density,scatter,4.5200449e-03,3.2228853e-04 +1,,density,fission,-1.5830325e-03,1.0334068e-02 +1,,density,nu-fission,-3.8226434e-03,2.5181192e-02 +1,,density,total,-6.6601129e-01,2.0465955e-01 +1,,density,absorption,-1.5334818e-02,4.0664980e-03 +1,,density,scatter,-6.5067647e-01,2.0153765e-01 1,,density,fission,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,total,0.0000000e+00,0.0000000e+00 @@ -49,19 +49,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,fission,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,O16,nuclide_density,total,4.2608989e+01,2.6322158e+00 -1,O16,nuclide_density,absorption,-5.9877963e-01,4.2139216e-01 -1,O16,nuclide_density,scatter,4.3207769e+01,2.5312922e+00 -1,O16,nuclide_density,fission,-9.2838585e-01,4.3505041e-01 -1,O16,nuclide_density,nu-fission,-2.2834786e+00,1.0634300e+00 -1,O16,nuclide_density,total,-1.1195412e+00,3.3033730e-01 -1,O16,nuclide_density,absorption,-1.0650267e+00,3.2780477e-01 -1,O16,nuclide_density,scatter,-5.4514540e-02,2.4911965e-02 -1,O16,nuclide_density,fission,-8.6787386e-01,4.4270048e-01 -1,O16,nuclide_density,nu-fission,-2.1159252e+00,1.0787495e+00 -1,O16,nuclide_density,total,-3.1004750e+01,8.0776339e+00 -1,O16,nuclide_density,absorption,-5.0354237e-01,2.6144390e-01 -1,O16,nuclide_density,scatter,-3.0501208e+01,7.8176703e+00 +1,O16,nuclide_density,total,4.3895711e+01,8.6765744e+00 +1,O16,nuclide_density,absorption,-7.3377277e-01,1.1652783e+00 +1,O16,nuclide_density,scatter,4.4629484e+01,7.5113743e+00 +1,O16,nuclide_density,fission,-1.0525946e+00,6.2358336e-01 +1,O16,nuclide_density,nu-fission,-2.5950001e+00,1.5266115e+00 +1,O16,nuclide_density,total,-1.0686783e+00,8.1661764e-01 +1,O16,nuclide_density,absorption,-1.0549848e+00,7.2501792e-01 +1,O16,nuclide_density,scatter,-1.3693500e-02,9.5152724e-02 +1,O16,nuclide_density,fission,-9.8026040e-01,6.2874064e-01 +1,O16,nuclide_density,nu-fission,-2.3899304e+00,1.5323042e+00 +1,O16,nuclide_density,total,4.3744802e+00,1.8346830e+01 +1,O16,nuclide_density,absorption,-7.6879459e-03,1.9447931e-01 +1,O16,nuclide_density,scatter,4.3821681e+00,1.8168908e+01 1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,total,0.0000000e+00,0.0000000e+00 @@ -69,19 +69,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,U235,nuclide_density,total,-5.3578869e+02,3.4044374e+02 -1,U235,nuclide_density,absorption,2.0769087e+02,1.0873543e+02 -1,U235,nuclide_density,scatter,-7.4347956e+02,2.5966153e+02 -1,U235,nuclide_density,fission,2.8982867e+02,8.5348425e+01 -1,U235,nuclide_density,nu-fission,7.0772332e+02,2.0847449e+02 -1,U235,nuclide_density,total,4.8356107e+02,1.0276621e+02 -1,U235,nuclide_density,absorption,3.6683548e+02,9.6924085e+01 -1,U235,nuclide_density,scatter,1.1672558e+02,6.1773010e+00 -1,U235,nuclide_density,fission,2.8941699e+02,8.4475937e+01 -1,U235,nuclide_density,nu-fission,7.0639136e+02,2.0594285e+02 -1,U235,nuclide_density,total,-4.6777522e+03,1.5037171e+03 -1,U235,nuclide_density,absorption,-1.1585081e+02,3.8299177e+01 -1,U235,nuclide_density,scatter,-4.5619014e+03,1.4660078e+03 +1,U235,nuclide_density,total,-6.4251150e+02,2.3106826e+02 +1,U235,nuclide_density,absorption,1.5311660e+02,8.7788828e+01 +1,U235,nuclide_density,scatter,-7.9562811e+02,1.5432248e+02 +1,U235,nuclide_density,fission,2.3667219e+02,6.4506235e+01 +1,U235,nuclide_density,nu-fission,5.7770896e+02,1.5738708e+02 +1,U235,nuclide_density,total,4.1238071e+02,7.5208565e+01 +1,U235,nuclide_density,absorption,3.0507276e+02,7.3015316e+01 +1,U235,nuclide_density,scatter,1.0730795e+02,3.4182980e+00 +1,U235,nuclide_density,fission,2.3734641e+02,6.4221163e+01 +1,U235,nuclide_density,nu-fission,5.7953503e+02,1.5657365e+02 +1,U235,nuclide_density,total,-5.5174298e+03,1.1185254e+03 +1,U235,nuclide_density,absorption,-1.3416339e+02,3.2272881e+01 +1,U235,nuclide_density,scatter,-5.3832664e+03,1.0864829e+03 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,total,0.0000000e+00,0.0000000e+00 @@ -89,19 +89,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,total,8.2134941e-05,1.3941434e-05 -1,,temperature,absorption,4.1502002e-05,3.5967068e-05 -1,,temperature,scatter,4.0632939e-05,2.6595574e-05 -1,,temperature,fission,3.1768469e-06,2.1582455e-05 -1,,temperature,nu-fission,7.7368345e-06,5.2593375e-05 -1,,temperature,total,1.0834099e-06,2.6707333e-05 -1,,temperature,absorption,1.6240165e-06,2.6844372e-05 -1,,temperature,scatter,-5.4060665e-07,2.5905412e-07 -1,,temperature,fission,3.1674458e-06,2.1588836e-05 -1,,temperature,nu-fission,7.7134913e-06,5.2609321e-05 -1,,temperature,total,9.5175179e-05,1.0549922e-04 -1,,temperature,absorption,4.3553888e-06,2.9261613e-06 -1,,temperature,scatter,9.0819790e-05,1.0362538e-04 +1,,temperature,total,3.0892324e-05,5.5277596e-05 +1,,temperature,absorption,2.2324596e-05,2.6209954e-05 +1,,temperature,scatter,8.5677277e-06,6.2111314e-05 +1,,temperature,fission,-1.7715856e-05,1.2803586e-05 +1,,temperature,nu-fission,-4.3163971e-05,3.1203107e-05 +1,,temperature,total,-2.3895766e-05,1.6226810e-05 +1,,temperature,absorption,-2.2388970e-05,1.6503185e-05 +1,,temperature,scatter,-1.5067967e-06,8.6753589e-07 +1,,temperature,fission,-1.7806576e-05,1.2760443e-05 +1,,temperature,nu-fission,-4.3390060e-05,3.1095620e-05 +1,,temperature,total,1.3388075e-04,1.1361483e-04 +1,,temperature,absorption,1.3825063e-06,1.3898795e-06 +1,,temperature,scatter,1.3249824e-04,1.1224449e-04 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,total,0.0000000e+00,0.0000000e+00 @@ -109,68 +109,68 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,absorption,-5.4897740e-01,8.6529144e-02 -3,,density,absorption,1.3410763e-01,5.6235628e-02 -1,,density,absorption,2.9551566e-02,1.5215007e-02 -1,,density,absorption,-8.6382033e-03,5.5181454e-03 -1,O16,nuclide_density,absorption,2.7111116e-01,9.6922067e-01 -1,O16,nuclide_density,absorption,-7.3785997e-01,7.7252792e-01 -1,U235,nuclide_density,absorption,2.7361252e+02,1.6168134e+02 -1,U235,nuclide_density,absorption,-9.6885408e+01,1.9390948e+01 -1,,temperature,absorption,1.0054736e-05,4.2876538e-05 -1,,temperature,absorption,-1.8280609e-06,1.0133065e-05 +3,,density,absorption,-4.3471777e-01,1.4851761e-01 +3,,density,absorption,4.8155520e-02,1.3781656e-01 +1,,density,absorption,9.4994508e-03,2.4533642e-03 +1,,density,absorption,-1.0306958e-02,3.9360517e-03 +1,O16,nuclide_density,absorption,-1.6745789e+00,6.7608522e-01 +1,O16,nuclide_density,absorption,1.2254539e+00,7.5421132e-01 +1,U235,nuclide_density,absorption,7.1093314e+01,1.0278274e+02 +1,U235,nuclide_density,absorption,-1.3158317e+02,1.0057325e+01 +1,,temperature,absorption,-2.8254564e-05,2.2125234e-05 +1,,temperature,absorption,1.3248119e-05,8.9856151e-06 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,-5.4273849e-01,1.8081153e-01 +3,,density,scatter,-5.9591692e-01,1.8102644e-01 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,1.3451827e-02,7.2870304e-03 -3,,density,nu-fission,-8.4200508e-01,3.4267126e-01 -3,,density,scatter,-3.1963455e+00,5.0369564e-01 -3,,density,nu-fission,-8.2934702e-01,3.4526131e-01 -3,,density,scatter,-7.0221960e-02,6.8067882e-02 +3,,density,scatter,-1.0186140e-04,6.5335918e-04 +3,,density,nu-fission,-7.7216010e-01,6.6235203e-02 +3,,density,scatter,-3.1141316e+00,8.7438594e-01 +3,,density,nu-fission,-7.4472975e-01,6.8932536e-02 +3,,density,scatter,-1.0613299e-02,1.4747505e-02 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,1.1368387e+00,1.2091778e+00 +3,,density,scatter,-2.3938461e+00,2.0442591e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,-1.5916491e+00,2.3551913e+00 +3,,density,scatter,-3.8155549e-02,2.1549075e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-1.8655633e-03,2.4061808e-02 +1,,density,scatter,9.6114352e-03,3.0773624e-02 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-1.7672807e-04,7.4702879e-04 -1,,density,nu-fission,4.4506944e-03,3.1478180e-02 -1,,density,scatter,3.7553200e-01,2.3420342e-02 -1,,density,nu-fission,-1.3567324e-03,3.0610901e-02 -1,,density,scatter,6.9330560e-03,4.6649873e-03 +1,,density,scatter,-4.8445916e-04,4.1692636e-04 +1,,density,nu-fission,-2.0032982e-02,1.5628598e-02 +1,,density,scatter,3.8609205e-01,2.0651677e-02 +1,,density,nu-fission,-2.4325475e-02,1.6087936e-02 +1,,density,scatter,2.1127093e-03,1.1144847e-03 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-5.1560927e-01,1.4846253e-01 +1,,density,scatter,-5.6312059e-01,1.2644279e-01 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-1.0427977e-01,6.6396271e-02 +1,,density,scatter,-9.2583739e-02,1.3802271e-01 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,O16,nuclide_density,scatter,4.6587151e-02,9.0232672e-02 -1,O16,nuclide_density,nu-fission,-2.1162226e+00,2.4773842e+00 -1,O16,nuclide_density,scatter,6.6533325e-01,2.4693113e-01 +1,O16,nuclide_density,scatter,2.8010197e-02,9.9675258e-02 +1,O16,nuclide_density,nu-fission,-2.7133439e+00,1.9638343e+00 +1,O16,nuclide_density,scatter,-5.8699167e-02,2.9596632e-01 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,U235,nuclide_density,scatter,2.8979849e+01,2.0235325e+01 -1,U235,nuclide_density,nu-fission,8.1210341e+02,2.9252040e+02 -1,U235,nuclide_density,scatter,1.0307302e+02,4.4919960e+01 +1,U235,nuclide_density,scatter,1.0007013e+01,5.9794002e+00 +1,U235,nuclide_density,nu-fission,4.3209054e+02,1.5648214e+02 +1,U235,nuclide_density,scatter,4.6100250e+01,2.3766583e+01 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,scatter,-3.3782154e-06,3.8240314e-06 -1,,temperature,nu-fission,-6.8920903e-05,4.4384761e-05 -1,,temperature,scatter,1.6325729e-07,2.3270228e-06 +1,,temperature,scatter,1.9350898e-06,2.0685006e-06 +1,,temperature,nu-fission,-6.5233572e-05,6.4075926e-05 +1,,temperature,scatter,-7.6629325e-07,7.6629325e-07 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 diff --git a/tests/regression_tests/diff_tally/test.py b/tests/regression_tests/diff_tally/test.py index 89460df91..b688e6d23 100644 --- a/tests/regression_tests/diff_tally/test.py +++ b/tests/regression_tests/diff_tally/test.py @@ -16,7 +16,7 @@ class DiffTallyTestHarness(PyAPITestHarness): self._model.settings.batches = 3 self._model.settings.inactive = 0 self._model.settings.particles = 100 - self._model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + self._model.settings.source = openmc.Source(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) self._model.settings.temperature['multipole'] = True @@ -103,8 +103,9 @@ class DiffTallyTestHarness(PyAPITestHarness): sp = openmc.StatePoint(statepoint) # Extract the tally data as a Pandas DataFrame. - tally_dfs = [t.get_pandas_dataframe() for t in sp.tallies.values()] - df = pd.concat(tally_dfs, ignore_index=True) + df = pd.DataFrame() + for t in sp.tallies.values(): + df = df.append(t.get_pandas_dataframe(), ignore_index=True) # Extract the relevant data as a CSV string. cols = ('d_material', 'd_nuclide', 'd_variable', 'score', 'mean', diff --git a/tests/regression_tests/distribmat/inputs_true.dat b/tests/regression_tests/distribmat/inputs_true.dat index 8087d7564..a1c1e8311 100644 --- a/tests/regression_tests/distribmat/inputs_true.dat +++ b/tests/regression_tests/distribmat/inputs_true.dat @@ -1,63 +1,62 @@ - - - - - - - - - - - - - - - - - - - - 2 void 3 2 - - - - - 2.0 2.0 - 1 - 2 2 - -2.0 -2.0 - + + + + + + + 2.0 2.0 + 1 + 2 2 + -2.0 -2.0 + 11 11 11 11 - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - -1 -1 -1 1 1 1 - - - - - - 400 400 - 0 0 0 - 7 7 - - - 400 400 - 0 0 0 - 7 7 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + -1 -1 -1 1 1 1 + + + + + + + 0 0 0 + 7 7 + 400 400 + + + 0 0 0 + 7 7 + 400 400 + + diff --git a/tests/regression_tests/distribmat/results_true.dat b/tests/regression_tests/distribmat/results_true.dat index 166fd4662..a33cbec0f 100644 --- a/tests/regression_tests/distribmat/results_true.dat +++ b/tests/regression_tests/distribmat/results_true.dat @@ -1,10 +1,10 @@ k-combined: -1.246391E+00 1.414798E-02 +1.234870E+00 1.724266E-02 Cell ID = 11 Name = Fill = [2, None, 3, 2] - Region = -1 + Region = -9 Rotation = None Translation = None Volume = None diff --git a/tests/regression_tests/distribmat/test.py b/tests/regression_tests/distribmat/test.py index dd09eec36..33f64ba03 100644 --- a/tests/regression_tests/distribmat/test.py +++ b/tests/regression_tests/distribmat/test.py @@ -4,8 +4,7 @@ from tests.testing_harness import TestHarness, PyAPITestHarness class DistribmatTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): #################### # Materials #################### @@ -23,8 +22,8 @@ class DistribmatTestHarness(PyAPITestHarness): light_fuel.set_density('g/cc', 2.0) light_fuel.add_nuclide('U235', 1.0) - self._model.materials = openmc.Materials([moderator, dense_fuel, - light_fuel]) + mats_file = openmc.Materials([moderator, dense_fuel, light_fuel]) + mats_file.export_to_xml() #################### # Geometry @@ -55,7 +54,8 @@ class DistribmatTestHarness(PyAPITestHarness): c101.region = +x0 & -x1 & +y0 & -y1 root_univ = openmc.Universe(universe_id=0, cells=[c101]) - self._model.geometry = openmc.Geometry(root_univ) + geometry = openmc.Geometry(root_univ) + geometry.export_to_xml() #################### # Settings @@ -65,15 +65,15 @@ class DistribmatTestHarness(PyAPITestHarness): sets_file.batches = 5 sets_file.inactive = 0 sets_file.particles = 1000 - sets_file.source = openmc.IndependentSource(space=openmc.stats.Box( + sets_file.source = openmc.Source(space=openmc.stats.Box( [-1, -1, -1], [1, 1, 1])) - self._model.settings = sets_file + sets_file.export_to_xml() #################### # Plots #################### - plot1 = openmc.SlicePlot(plot_id=1) + plot1 = openmc.Plot(plot_id=1) plot1.basis = 'xy' plot1.color_by = 'cell' plot1.filename = 'cellplot' @@ -81,7 +81,7 @@ class DistribmatTestHarness(PyAPITestHarness): plot1.width = (7, 7) plot1.pixels = (400, 400) - plot2 = openmc.SlicePlot(plot_id=2) + plot2 = openmc.Plot(plot_id=2) plot2.basis = 'xy' plot2.color_by = 'material' plot2.filename = 'matplot' @@ -89,7 +89,8 @@ class DistribmatTestHarness(PyAPITestHarness): plot2.width = (7, 7) plot2.pixels = (400, 400) - self._model.plots = openmc.Plots([plot1, plot2]) + plots = openmc.Plots([plot1, plot2]) + plots.export_to_xml() def _get_results(self): outstr = super()._get_results() @@ -99,5 +100,5 @@ class DistribmatTestHarness(PyAPITestHarness): def test_distribmat(): - harness = DistribmatTestHarness('statepoint.5.h5', model=openmc.Model()) + harness = DistribmatTestHarness('statepoint.5.h5') harness.main() diff --git a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat index 15b810a62..7348663e8 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat +++ b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat @@ -1,30 +1,31 @@ - - - - - - - - - - - - - eigenvalue - 1000 - 7 - 3 - 3 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - - - flux - - - + + + + + + + + + + + + + + eigenvalue + 1000 + 7 + 3 + 3 + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + + + + flux + + diff --git a/tests/regression_tests/eigenvalue_genperbatch/results_true.dat b/tests/regression_tests/eigenvalue_genperbatch/results_true.dat index d171c5e87..91d1c393a 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/results_true.dat +++ b/tests/regression_tests/eigenvalue_genperbatch/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.975937E-01 1.293390E-03 +3.029569E-01 9.632511E-05 tally 1: -3.173222E+01 -2.517683E+02 +3.226370E+01 +2.602467E+02 diff --git a/tests/regression_tests/eigenvalue_genperbatch/test.py b/tests/regression_tests/eigenvalue_genperbatch/test.py index 17c6dff7f..7e21c8d36 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/test.py +++ b/tests/regression_tests/eigenvalue_genperbatch/test.py @@ -22,7 +22,7 @@ def model(): model.settings.batches = 7 model.settings.generations_per_batch = 3 space = openmc.stats.Box((-4.0, -4.0, -4.0), (4.0, 4.0, 4.)) - model.settings.source = openmc.IndependentSource(space=space) + model.settings.source = openmc.Source(space=space) t = openmc.Tally() t.scores = ['flux'] diff --git a/tests/regression_tests/eigenvalue_no_inactive/results_true.dat b/tests/regression_tests/eigenvalue_no_inactive/results_true.dat index 3ba7485a9..80d463a3c 100644 --- a/tests/regression_tests/eigenvalue_no_inactive/results_true.dat +++ b/tests/regression_tests/eigenvalue_no_inactive/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.072780E-01 6.882841E-03 +3.066848E-01 7.260987E-03 diff --git a/tests/regression_tests/electron_heating/__init__.py b/tests/regression_tests/electron_heating/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/electron_heating/inputs_true.dat b/tests/regression_tests/electron_heating/inputs_true.dat deleted file mode 100644 index ec8e5a837..000000000 --- a/tests/regression_tests/electron_heating/inputs_true.dat +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 10000000.0 1.0 - - - - 1000.0 - - - - - heating - - - diff --git a/tests/regression_tests/electron_heating/results_true.dat b/tests/regression_tests/electron_heating/results_true.dat deleted file mode 100644 index 4f54ceaa4..000000000 --- a/tests/regression_tests/electron_heating/results_true.dat +++ /dev/null @@ -1,3 +0,0 @@ -tally 1: -1.000000E+07 -1.000000E+14 diff --git a/tests/regression_tests/electron_heating/test.py b/tests/regression_tests/electron_heating/test.py deleted file mode 100644 index e7a58560c..000000000 --- a/tests/regression_tests/electron_heating/test.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest -import openmc - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def water_model(): - # Define materals and geometry - water = openmc.Material() - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cc", 1.0) - sphere = openmc.Sphere(r=1.0, boundary_type="reflective") - sph = openmc.Cell(fill=water, region=-sphere) - geometry = openmc.Geometry([sph]) - source = openmc.IndependentSource( - energy=openmc.stats.delta_function(10.0e6), - particle="electron" - ) - - # Define settings - settings = openmc.Settings() - settings.particles = 10000 - settings.batches = 1 - settings.cutoff = {"energy_photon": 1000.0} - settings.run_mode = "fixed source" - settings.source = source - - # Define tallies - tally = openmc.Tally() - tally.scores = ["heating"] - tallies = openmc.Tallies([tally]) - - return openmc.Model(geometry=geometry, settings=settings, tallies=tallies) - - -def test_electron_heating_calc(water_model): - harness = PyAPITestHarness("statepoint.1.h5", water_model) - harness.main() diff --git a/tests/regression_tests/energy_cutoff/inputs_true.dat b/tests/regression_tests/energy_cutoff/inputs_true.dat index 557cb7a3b..bb02369dc 100644 --- a/tests/regression_tests/energy_cutoff/inputs_true.dat +++ b/tests/regression_tests/energy_cutoff/inputs_true.dat @@ -1,41 +1,42 @@ - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - -1 -1 -1 1 1 1 - - - - - 4.0 - - - - - 0.0 4.0 - - - 1 - flux - - - + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + -1 -1 -1 1 1 1 + + + + + 4.0 + + + + + + 0.0 4.0 + + + 1 + flux + + diff --git a/tests/regression_tests/energy_cutoff/test.py b/tests/regression_tests/energy_cutoff/test.py index 9aca802fa..d76edd9a0 100755 --- a/tests/regression_tests/energy_cutoff/test.py +++ b/tests/regression_tests/energy_cutoff/test.py @@ -4,8 +4,7 @@ from tests.testing_harness import PyAPITestHarness class EnergyCutoffTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): # Set energy cutoff energy_cutoff = 4.0 @@ -13,7 +12,8 @@ class EnergyCutoffTestHarness(PyAPITestHarness): mat = openmc.Material(material_id=1, name='mat') mat.set_density('atom/b-cm', 0.069335) mat.add_nuclide('H1', 40.0) - self._model.materials = openmc.Materials([mat]) + materials_file = openmc.Materials([mat]) + materials_file.export_to_xml() # Cell is box with reflective boundary x1 = openmc.XPlane(surface_id=1, x0=-1) @@ -29,7 +29,8 @@ class EnergyCutoffTestHarness(PyAPITestHarness): box.fill = mat root = openmc.Universe(universe_id=0, name='root universe') root.add_cell(box) - self._model.geometry = openmc.Geometry(root) + geometry = openmc.Geometry(root) + geometry.export_to_xml() # Set the running parameters settings_file = openmc.Settings() @@ -40,9 +41,9 @@ class EnergyCutoffTestHarness(PyAPITestHarness): bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) watt_dist = openmc.stats.Watt() - settings_file.source = openmc.IndependentSource(space=uniform_dist, - energy=watt_dist) - self._model.settings = settings_file + settings_file.source = openmc.source.Source(space=uniform_dist, + energy=watt_dist) + settings_file.export_to_xml() # Tally flux under energy cutoff tallies = openmc.Tallies() @@ -51,7 +52,7 @@ class EnergyCutoffTestHarness(PyAPITestHarness): energy_filter = openmc.filter.EnergyFilter((0.0, energy_cutoff)) tally.filters = [energy_filter] tallies.append(tally) - self._model.tallies = tallies + tallies.export_to_xml() def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -69,5 +70,5 @@ class EnergyCutoffTestHarness(PyAPITestHarness): def test_energy_cutoff(): - harness = EnergyCutoffTestHarness('statepoint.10.h5', model=openmc.Model()) + harness = EnergyCutoffTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/energy_grid/results_true.dat b/tests/regression_tests/energy_grid/results_true.dat index 3a042d882..b06742c1b 100644 --- a/tests/regression_tests/energy_grid/results_true.dat +++ b/tests/regression_tests/energy_grid/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.218009E-01 4.687417E-03 +3.317249E-01 1.079825E-02 diff --git a/tests/regression_tests/energy_laws/inputs_true.dat b/tests/regression_tests/energy_laws/inputs_true.dat index 8c5191217..2320b21d5 100644 --- a/tests/regression_tests/energy_laws/inputs_true.dat +++ b/tests/regression_tests/energy_laws/inputs_true.dat @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + diff --git a/tests/regression_tests/energy_laws/results_true.dat b/tests/regression_tests/energy_laws/results_true.dat index 780278683..534a299b5 100644 --- a/tests/regression_tests/energy_laws/results_true.dat +++ b/tests/regression_tests/energy_laws/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.458770E+00 9.422203E-03 +2.444000E+00 1.044626E-02 diff --git a/tests/regression_tests/entropy/results_true.dat b/tests/regression_tests/entropy/results_true.dat index 92d7f091d..864905fa7 100644 --- a/tests/regression_tests/entropy/results_true.dat +++ b/tests/regression_tests/entropy/results_true.dat @@ -1,13 +1,13 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 entropy: 7.688862E+00 -8.226316E+00 -8.308355E+00 -8.243413E+00 -8.369345E+00 -8.304865E+00 -8.230689E+00 -8.338304E+00 -8.270630E+00 -8.386598E+00 +8.184416E+00 +8.363034E+00 +8.174200E+00 +8.243373E+00 +8.298547E+00 +8.267346E+00 +8.253347E+00 +8.329508E+00 +8.363320E+00 diff --git a/tests/regression_tests/external_moab/inputs_true.dat b/tests/regression_tests/external_moab/inputs_true.dat index ed035f897..af259eee4 100644 --- a/tests/regression_tests/external_moab/inputs_true.dat +++ b/tests/regression_tests/external_moab/inputs_true.dat @@ -1,72 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - 0.0 0.0 0.0 - - - - 15000000.0 1.0 - - - - - - test_mesh_tets.h5m - - - 1 - - - 1 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + 0.0 0.0 0.0 + + + + 15000000.0 1.0 + + + + + + + test_mesh_tets.h5m + + + 1 + + + 1 + flux + tracklength + + diff --git a/tests/regression_tests/external_moab/test.py b/tests/regression_tests/external_moab/test.py index 2d64eb14b..b9d307239 100644 --- a/tests/regression_tests/external_moab/test.py +++ b/tests/regression_tests/external_moab/test.py @@ -32,14 +32,14 @@ def cpp_driver(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_cpp_driver CXX) add_executable(main main.cpp) find_package(OpenMC REQUIRED HINTS {}) target_link_libraries(main OpenMC::libopenmc) target_compile_features(main PUBLIC cxx_std_14) set(CMAKE_CXX_FLAGS "-pedantic-errors") - add_compile_definitions(OPENMC_DAGMC_ENABLED=1) + add_compile_definitions(DAGMC=1) """.format(openmc_dir))) # Create temporary build directory and change to there @@ -162,6 +162,8 @@ def test_external_mesh(cpp_driver): water_mat.set_density("atom/b-cm", 0.07416) materials.append(water_mat) + materials.export_to_xml() + # Geometry fuel_min_x = openmc.XPlane(-5.0, name="minimum x") fuel_max_x = openmc.XPlane(5.0, name="maximum x") @@ -258,7 +260,7 @@ def test_external_mesh(cpp_driver): space = openmc.stats.Point() angle = openmc.stats.Monodirectional((-1.0, 0.0, 0.0)) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.IndependentSource(space=space, energy=energy, angle=angle) + source = openmc.Source(space=space, energy=energy, angle=angle) settings.source = source model = openmc.model.Model(geometry=geometry, diff --git a/tests/regression_tests/filter_cellfrom/__init__.py b/tests/regression_tests/filter_cellfrom/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/filter_cellfrom/inputs_true.dat b/tests/regression_tests/filter_cellfrom/inputs_true.dat deleted file mode 100644 index 20d0d69d4..000000000 --- a/tests/regression_tests/filter_cellfrom/inputs_true.dat +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 2000 - 15 - 5 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - 1 - - - - 1 - - - 1 - - - 2 - - - 3 - - - 4 - - - 2 - - - 3 - - - 4 - - - 5 1 - total - - - 5 2 - total - - - 5 3 - total - - - 5 4 - total - - - 6 1 - total - - - 6 2 - total - - - 6 3 - total - - - 6 4 - total - - - 7 1 - total - - - 7 2 - total - - - 7 3 - total - - - 7 4 - total - - - 8 1 - total - - - 8 2 - total - - - 8 3 - total - - - 8 4 - total - - - total - - - diff --git a/tests/regression_tests/filter_cellfrom/results_true.dat b/tests/regression_tests/filter_cellfrom/results_true.dat deleted file mode 100644 index 408a4965b..000000000 --- a/tests/regression_tests/filter_cellfrom/results_true.dat +++ /dev/null @@ -1,53 +0,0 @@ -k-combined: -9.035025E-02 2.654309E-03 -tally 1: -5.994069E+00 -3.594398E+00 -tally 2: -4.559707E-04 -2.080739E-08 -tally 3: -5.994525E+00 -3.594945E+00 -tally 4: -0.000000E+00 -0.000000E+00 -tally 5: -1.473892E+00 -2.187509E-01 -tally 6: -5.223875E-05 -2.992861E-10 -tally 7: -1.473945E+00 -2.187663E-01 -tally 8: -1.885798E+01 -3.558423E+01 -tally 9: -7.467961E+00 -5.580255E+00 -tally 10: -5.082094E-04 -2.584432E-08 -tally 11: -7.468470E+00 -5.581014E+00 -tally 12: -1.885798E+01 -3.558423E+01 -tally 13: -0.000000E+00 -0.000000E+00 -tally 14: -2.739543E-04 -7.600983E-09 -tally 15: -2.739543E-04 -7.600983E-09 -tally 16: -7.881296E+01 -6.221087E+02 -tally 17: -1.051397E+02 -1.106292E+03 diff --git a/tests/regression_tests/filter_cellfrom/test.py b/tests/regression_tests/filter_cellfrom/test.py deleted file mode 100644 index 5559b4c81..000000000 --- a/tests/regression_tests/filter_cellfrom/test.py +++ /dev/null @@ -1,316 +0,0 @@ -"""This test ensures that the CellFromFilter works correctly even if the level of -coordinates (number of encapsulated universes) is different in the cell from -where the particle originates compared to the cell where the particle is going. - -A matrix of reaction rates based on where the particle is coming from and -where it goes to is calculated and compared to the total reaction rate of the problem. -The components of this matrix are also compared to other components using symmetric -properties. - -TODO: - -- Test with a lattice, -- Test with mesh, -- Test with reflective boundary conditions, -- Test with periodic boundary conditions. - -""" - -from numpy.testing import assert_allclose, assert_equal -import numpy as np -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -RTOL = 1.0e-7 -ATOL = 0.0 - - -@pytest.fixture -def model(): - """Cylindrical core contained in a first box which is contained in a larger box. - A lower universe is used to describe the interior of the first box which - contains the core and its surrounding space.""" - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - fuel = openmc.Material() - fuel.add_nuclide("U234", 0.0004524) - fuel.add_nuclide("U235", 0.0506068) - fuel.add_nuclide("U238", 0.9487090) - fuel.add_nuclide("U236", 0.0002318) - fuel.add_nuclide("O16", 2.0) - fuel.set_density("g/cm3", 10.97) - - water = openmc.Material() - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cm3", 1.0) - - air = openmc.Material() - air.add_element("O", 0.2) - air.add_element("N", 0.8) - air.set_density("g/cm3", 0.001225) - - # ============================================================================= - # Geometry - # ============================================================================= - - # ----------------------------------------------------------------------------- - # Cylindrical core - # ----------------------------------------------------------------------------- - - # Parameters - core_radius = 2.0 - core_height = 4.0 - - # Surfaces - core_cylinder = openmc.ZCylinder(r=core_radius) - core_lower_plane = openmc.ZPlane(z0=-core_height / 2.0) - core_upper_plane = openmc.ZPlane(z0=core_height / 2.0) - - # Region - core_region = -core_cylinder & +core_lower_plane & -core_upper_plane - - # Cells - core = openmc.Cell(fill=fuel, region=core_region) - outside_core_region = +core_cylinder | -core_lower_plane | +core_upper_plane - outside_core = openmc.Cell(fill=air, region=outside_core_region) - - # Universe - inside_box1_universe = openmc.Universe(cells=[core, outside_core]) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 4.1 - - # Surfaces - box1_rpp = openmc.model.RectangularParallelepiped( - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - ) - - # Cell - box1 = openmc.Cell(fill=inside_box1_universe, region=-box1_rpp) - - # ----------------------------------------------------------------------------- - # Box 2 - # ----------------------------------------------------------------------------- - - # Parameters - box2_size = 12 - - # Surfaces - box2_rpp = openmc.model.RectangularParallelepiped( - -box2_size / 2.0, box2_size / 2.0, - -box2_size / 2.0, box2_size / 2.0, - -box2_size / 2.0, box2_size / 2.0, - boundary_type="vacuum" - ) - - # Cell - box2 = openmc.Cell(fill=water, region=-box2_rpp & +box1_rpp) - - # Register geometry - model.geometry = openmc.Geometry([box1, box2]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 2000 - model.settings.batches = 15 - model.settings.inactive = 5 - model.settings.seed = 1 - - bounds = [ - -core_radius, - -core_radius, - -core_height / 2.0, - core_radius, - core_radius, - core_height / 2.0, - ] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource( - space=distribution, constraints={'fissionable': True}) - - # ============================================================================= - # Tallies - # ============================================================================= - - in_core_filter = openmc.CellFilter([core]) - in_outside_core_filter = openmc.CellFilter([outside_core]) - in_box1_filter = openmc.CellFilter([box1]) - in_box2_filter = openmc.CellFilter([box2]) - - from_core_filter = openmc.CellFromFilter([core]) - from_outside_core_filter = openmc.CellFromFilter([outside_core]) - from_box1_filter = openmc.CellFromFilter([box1]) - from_box2_filter = openmc.CellFromFilter([box2]) - - t1_1 = openmc.Tally(name="total from 1 in 1") - t1_1.filters = [from_core_filter, in_core_filter] - t1_1.scores = ["total"] - - t1_2 = openmc.Tally(name="total from 1 in 2") - t1_2.filters = [from_core_filter, in_outside_core_filter] - t1_2.scores = ["total"] - - t1_3 = openmc.Tally(name="total from 1 in 3") - t1_3.filters = [from_core_filter, in_box1_filter] - t1_3.scores = ["total"] - - t1_4 = openmc.Tally(name="total from 1 in 4") - t1_4.filters = [from_core_filter, in_box2_filter] - t1_4.scores = ["total"] - - t2_1 = openmc.Tally(name="total from 2 in 1") - t2_1.filters = [from_outside_core_filter, in_core_filter] - t2_1.scores = ["total"] - - t2_2 = openmc.Tally(name="total from 2 in 2") - t2_2.filters = [from_outside_core_filter, in_outside_core_filter] - t2_2.scores = ["total"] - - t2_3 = openmc.Tally(name="total from 2 in 3") - t2_3.filters = [from_outside_core_filter, in_box1_filter] - t2_3.scores = ["total"] - - t2_4 = openmc.Tally(name="total from 2 in 4") - t2_4.filters = [from_outside_core_filter, in_box2_filter] - t2_4.scores = ["total"] - - t3_1 = openmc.Tally(name="total from 3 in 1") - t3_1.filters = [from_box1_filter, in_core_filter] - t3_1.scores = ["total"] - - t3_2 = openmc.Tally(name="total from 3 in 2") - t3_2.filters = [from_box1_filter, in_outside_core_filter] - t3_2.scores = ["total"] - - t3_3 = openmc.Tally(name="total from 3 in 3") - t3_3.filters = [from_box1_filter, in_box1_filter] - t3_3.scores = ["total"] - - t3_4 = openmc.Tally(name="total from 3 in 4") - t3_4.filters = [from_box1_filter, in_box2_filter] - t3_4.scores = ["total"] - - t4_1 = openmc.Tally(name="total from 4 in 1") - t4_1.filters = [from_box2_filter, in_core_filter] - t4_1.scores = ["total"] - - t4_2 = openmc.Tally(name="total from 4 in 2") - t4_2.filters = [from_box2_filter, in_outside_core_filter] - t4_2.scores = ["total"] - - t4_3 = openmc.Tally(name="total from 4 in 3") - t4_3.filters = [from_box2_filter, in_box1_filter] - t4_3.scores = ["total"] - - t4_4 = openmc.Tally(name="total from 4 in 4") - t4_4.filters = [from_box2_filter, in_box2_filter] - t4_4.scores = ["total"] - - tglobal = openmc.Tally(name="total") - tglobal.scores = ["total"] - - model.tallies += [ - t1_1, - t1_2, - t1_3, - t1_4, - t2_1, - t2_2, - t2_3, - t2_4, - t3_1, - t3_2, - t3_3, - t3_4, - t4_1, - t4_2, - t4_3, - t4_4, - tglobal, - ] - return model - - -class CellFromFilterTest(PyAPITestHarness): - - def _compare_results(self): - """Additional unit tests on the tally results to check - consistency of CellFromFilter.""" - with openmc.StatePoint(self.statepoint_name) as sp: - - t1_1 = sp.get_tally(name="total from 1 in 1").mean - t1_2 = sp.get_tally(name="total from 1 in 2").mean - t1_3 = sp.get_tally(name="total from 1 in 3").mean - t1_4 = sp.get_tally(name="total from 1 in 4").mean - - t2_1 = sp.get_tally(name="total from 2 in 1").mean - t2_2 = sp.get_tally(name="total from 2 in 2").mean - t2_3 = sp.get_tally(name="total from 2 in 3").mean - t2_4 = sp.get_tally(name="total from 2 in 4").mean - - t3_1 = sp.get_tally(name="total from 3 in 1").mean - t3_2 = sp.get_tally(name="total from 3 in 2").mean - t3_3 = sp.get_tally(name="total from 3 in 3").mean - t3_4 = sp.get_tally(name="total from 3 in 4").mean - - t4_1 = sp.get_tally(name="total from 4 in 1").mean - t4_2 = sp.get_tally(name="total from 4 in 2").mean - t4_3 = sp.get_tally(name="total from 4 in 3").mean - t4_4 = sp.get_tally(name="total from 4 in 4").mean - - tglobal = sp.get_tally(name="total").mean - - # From 1 and 2 is equivalent to from 3 - assert_allclose(t1_1 + t2_1, t3_1, rtol=RTOL, atol=ATOL) - assert_allclose(t1_2 + t2_2, t3_2, rtol=RTOL, atol=ATOL) - assert_allclose(t1_3 + t2_3, t3_3, rtol=RTOL, atol=ATOL) - assert_allclose(t1_4 + t2_4, t3_4, rtol=RTOL, atol=ATOL) - - # In 1 and 2 equivalent to in 3 - assert_allclose(t1_1 + t1_2, t1_3, rtol=RTOL, atol=ATOL) - assert_allclose(t2_1 + t2_2, t2_3, rtol=RTOL, atol=ATOL) - assert_allclose(t3_1 + t3_2, t3_3, rtol=RTOL, atol=ATOL) - assert_allclose(t4_1 + t4_2, t4_3, rtol=RTOL, atol=ATOL) - - # Comparison to global from 3 - assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL) - - # Comparison to global from 1 and 2 - t_from_1_wo_3 = t1_1 + t1_2 + t1_4 - t_from_2_wo_3 = t2_1 + t2_2 + t2_4 - t_from_4_wo_3 = t4_1 + t4_2 + t4_4 - assert_allclose( - t_from_1_wo_3 + t_from_2_wo_3 + t_from_4_wo_3, - tglobal, - rtol=RTOL, - atol=ATOL, - ) - - # 1 cannot contribute to 4 and 4 cannot contribute to 1 by symmetry - assert_equal(t1_4, np.zeros_like(t1_4)) - assert_equal(t4_1, np.zeros_like(t4_1)) - - return super()._compare_results() - - -def test_filter_cellfrom(model): - harness = CellFromFilterTest("statepoint.15.h5", model) - harness.main() diff --git a/tests/regression_tests/filter_cellinstance/inputs_true.dat b/tests/regression_tests/filter_cellinstance/inputs_true.dat index 2677d7ad2..f9d3ca58d 100644 --- a/tests/regression_tests/filter_cellinstance/inputs_true.dat +++ b/tests/regression_tests/filter_cellinstance/inputs_true.dat @@ -1,64 +1,65 @@ - - - - - - - - - - - - - - - - - - - - 2 2 - 4 4 - -4 -4 - + + + + + + + + + 2 2 + 4 4 + -4 -4 + 2 3 3 3 3 2 3 3 3 3 2 3 3 3 3 2 - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - 0.0 0.0 0.0 - - - - - - 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 4 10 4 11 2 0 2 1 2 2 2 3 3 0 3 1 3 2 3 3 - - - 3 3 3 2 3 1 3 0 2 3 2 2 2 1 2 0 4 11 4 10 4 9 4 8 4 7 4 6 4 5 4 4 4 3 4 2 4 1 4 0 - - - 1 - total - - - 2 - total - - - + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + 0.0 0.0 0.0 + + + + + + + 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 4 10 4 11 2 0 2 1 2 2 2 3 3 0 3 1 3 2 3 3 + + + 3 3 3 2 3 1 3 0 2 3 2 2 2 1 2 0 4 11 4 10 4 9 4 8 4 7 4 6 4 5 4 4 4 3 4 2 4 1 4 0 + + + 1 + total + + + 2 + total + + diff --git a/tests/regression_tests/filter_cellinstance/results_true.dat b/tests/regression_tests/filter_cellinstance/results_true.dat index 152986595..c6832c6e1 100644 --- a/tests/regression_tests/filter_cellinstance/results_true.dat +++ b/tests/regression_tests/filter_cellinstance/results_true.dat @@ -1,84 +1,84 @@ k-combined: -1.097679E+00 8.074294E-03 +1.045340E+00 4.712608E-02 tally 1: -7.125168E-02 -1.412152E-03 -1.254059E-01 -4.145686E-03 -1.609454E-01 -6.174116E-03 -1.444278E-01 -4.523981E-03 -3.363588E-01 -2.342988E-02 -1.751677E-01 -7.108034E-03 -1.384074E-01 -3.949804E-03 -2.856450E-01 -1.824185E-02 -9.680810E-02 -2.256338E-03 -1.691663E-01 -6.456530E-03 -1.160968E-01 -3.233815E-03 -7.334131E-02 -1.456688E-03 -1.168548E+01 -3.210924E+01 -2.860162E+01 -1.876786E+02 -2.857267E+01 -1.996553E+02 -1.050245E+01 -2.569953E+01 -1.168548E+01 -3.210924E+01 -2.860162E+01 -1.876786E+02 -2.857267E+01 -1.996553E+02 -1.050245E+01 -2.569953E+01 +7.410456E-02 +1.481523E-03 +1.225401E-01 +3.736978E-03 +1.383468E-01 +4.249085E-03 +1.197994E-01 +3.155257E-03 +2.966893E-01 +2.045198E-02 +1.570258E-01 +5.313506E-03 +1.655546E-01 +6.093224E-03 +2.749756E-01 +1.582780E-02 +1.184686E-01 +3.543719E-03 +1.354860E-01 +3.990719E-03 +1.299309E-01 +3.988554E-03 +6.794395E-02 +1.135006E-03 +1.061333E+01 +2.508486E+01 +2.767786E+01 +1.781264E+02 +2.898957E+01 +2.015188E+02 +9.951936E+00 +2.345815E+01 +1.061333E+01 +2.508486E+01 +2.767786E+01 +1.781264E+02 +2.898957E+01 +2.015188E+02 +9.951936E+00 +2.345815E+01 tally 2: -1.050245E+01 -2.569953E+01 -2.857267E+01 -1.996553E+02 -2.860162E+01 -1.876786E+02 -1.168548E+01 -3.210924E+01 -1.050245E+01 -2.569953E+01 -2.857267E+01 -1.996553E+02 -2.860162E+01 -1.876786E+02 -1.168548E+01 -3.210924E+01 -7.334131E-02 -1.456688E-03 -1.160968E-01 -3.233815E-03 -1.691663E-01 -6.456530E-03 -9.680810E-02 -2.256338E-03 -2.856450E-01 -1.824185E-02 -1.384074E-01 -3.949804E-03 -1.751677E-01 -7.108034E-03 -3.363588E-01 -2.342988E-02 -1.444278E-01 -4.523981E-03 -1.609454E-01 -6.174116E-03 -1.254059E-01 -4.145686E-03 -7.125168E-02 -1.412152E-03 +9.951936E+00 +2.345815E+01 +2.898957E+01 +2.015188E+02 +2.767786E+01 +1.781264E+02 +1.061333E+01 +2.508486E+01 +9.951936E+00 +2.345815E+01 +2.898957E+01 +2.015188E+02 +2.767786E+01 +1.781264E+02 +1.061333E+01 +2.508486E+01 +6.794395E-02 +1.135006E-03 +1.299309E-01 +3.988554E-03 +1.354860E-01 +3.990719E-03 +1.184686E-01 +3.543719E-03 +2.749756E-01 +1.582780E-02 +1.655546E-01 +6.093224E-03 +1.570258E-01 +5.313506E-03 +2.966893E-01 +2.045198E-02 +1.197994E-01 +3.155257E-03 +1.383468E-01 +4.249085E-03 +1.225401E-01 +3.736978E-03 +7.410456E-02 +1.481523E-03 diff --git a/tests/regression_tests/filter_cellinstance/test.py b/tests/regression_tests/filter_cellinstance/test.py index 61f17d88a..3f5fa54b2 100644 --- a/tests/regression_tests/filter_cellinstance/test.py +++ b/tests/regression_tests/filter_cellinstance/test.py @@ -60,8 +60,8 @@ def model(): [u3, u3, u2, u3], [u3, u3, u3, u2] ] - box = openmc.model.RectangularPrism(8.0, 8.0, boundary_type='reflective') - main_cell = openmc.Cell(fill=lat, region=-box) + box = openmc.model.rectangular_prism(8.0, 8.0, boundary_type='reflective') + main_cell = openmc.Cell(fill=lat, region=box) model.geometry.root_universe = openmc.Universe(cells=[main_cell]) model.geometry.determine_paths() @@ -69,7 +69,7 @@ def model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + model.settings.source = openmc.Source(space=openmc.stats.Point()) instances = ([(c4, i) for i in range(c4.num_instances)] + [(c2, i) for i in range(c2.num_instances)] + diff --git a/tests/regression_tests/filter_distribcell/case-3/results_true.dat b/tests/regression_tests/filter_distribcell/case-3/results_true.dat index 77f2a2a87..c12903fed 100644 --- a/tests/regression_tests/filter_distribcell/case-3/results_true.dat +++ b/tests/regression_tests/filter_distribcell/case-3/results_true.dat @@ -1 +1 @@ -93c1efbc586874a715982d26609e9e79232de25a0b73093a00938d658440644f0ee6bb823902a6ef1b7a2a855e67b2da0a0e767ef550f9ffa4dea723e35af6f5 \ No newline at end of file +d3ecf354b33d09064f43816325f33ec1229d1258255ee8413e83f7ba96ca921b8f4be738c10af99c5376bfe2b6be45976595634efcafddec0d9296eb45ffed3e \ No newline at end of file diff --git a/tests/regression_tests/filter_distribcell/case-4/geometry.xml b/tests/regression_tests/filter_distribcell/case-4/geometry.xml new file mode 100644 index 000000000..c835218bc --- /dev/null +++ b/tests/regression_tests/filter_distribcell/case-4/geometry.xml @@ -0,0 +1,23 @@ + + + + + + + + 1.0 + 3 +
0.0 0.0
+ + 1 +1 1 + 1 +1 1 + 1 +
+ + + + + +
diff --git a/tests/regression_tests/filter_distribcell/case-4/materials.xml b/tests/regression_tests/filter_distribcell/case-4/materials.xml new file mode 100644 index 000000000..2eb744fe6 --- /dev/null +++ b/tests/regression_tests/filter_distribcell/case-4/materials.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/filter_distribcell/case-4/model.xml b/tests/regression_tests/filter_distribcell/case-4/model.xml deleted file mode 100644 index 869421919..000000000 --- a/tests/regression_tests/filter_distribcell/case-4/model.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 1.0 - 3 -
0.0 0.0
- - 1 -1 1 - 1 -1 1 - 1 -
- - - - - -
- - eigenvalue - 1000 - 1 - 0 - - - -1.0 -1.0 -1.0 1.0 1.0 1.0 - - - - - - 101 - - - 1 - total - - -
diff --git a/tests/regression_tests/filter_distribcell/case-4/results_true.dat b/tests/regression_tests/filter_distribcell/case-4/results_true.dat index ed84838ee..228456c58 100644 --- a/tests/regression_tests/filter_distribcell/case-4/results_true.dat +++ b/tests/regression_tests/filter_distribcell/case-4/results_true.dat @@ -1,12 +1,12 @@ k-combined: -1.069692E-01 INF +1.068596E-01 INF tally 1: 1.812612E-02 3.285561E-04 2.870442E-02 8.239436E-04 -1.824058E-02 -3.327188E-04 +1.807689E-02 +3.267740E-04 2.660796E-02 7.079835E-04 1.961572E-02 diff --git a/tests/regression_tests/filter_distribcell/case-4/settings.xml b/tests/regression_tests/filter_distribcell/case-4/settings.xml new file mode 100644 index 000000000..f3f0779bc --- /dev/null +++ b/tests/regression_tests/filter_distribcell/case-4/settings.xml @@ -0,0 +1,12 @@ + + + eigenvalue + 1000 + 1 + 0 + + + -1 -1 -1 1 1 1 + + + diff --git a/tests/regression_tests/filter_distribcell/case-4/tallies.xml b/tests/regression_tests/filter_distribcell/case-4/tallies.xml new file mode 100644 index 000000000..b923c030b --- /dev/null +++ b/tests/regression_tests/filter_distribcell/case-4/tallies.xml @@ -0,0 +1,14 @@ + + + + + distribcell + 101 + + + + 1 + total + + + diff --git a/tests/regression_tests/filter_energyfun/inputs_true.dat b/tests/regression_tests/filter_energyfun/inputs_true.dat index b7a70290f..0f506f3f5 100644 --- a/tests/regression_tests/filter_energyfun/inputs_true.dat +++ b/tests/regression_tests/filter_energyfun/inputs_true.dat @@ -1,105 +1,35 @@ - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 - 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 - linear-linear - - - 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 - 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 - log-log - - - 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 - 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 - linear-log - - - 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 - 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 - log-linear - - - 0.0 5000000.0 10000000.0 15000000.0 - 0.2 0.7 0.7 0.2 - linear-linear - - - 0.0 5000000.0 10000000.0 15000000.0 - 0.2 0.7 0.7 0.2 - quadratic - - - 0.0 5000000.0 10000000.0 15000000.0 - 0.2 0.7 0.7 0.2 - cubic - - - 0.0 5000000.0 10000000.0 15000000.0 - 0.2 0.7 0.7 0.2 - histogram - - - Am241 - (n,gamma) - - - 1 - Am241 - (n,gamma) - - - 3 - Am241 - (n,gamma) - - - 4 - Am241 - (n,gamma) - - - 5 - Am241 - (n,gamma) - - - 6 - Am241 - (n,gamma) - - - 7 - Am241 - (n,gamma) - - - 8 - Am241 - (n,gamma) - - - 9 - Am241 - (n,gamma) - - - + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + + 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 + 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 + + + Am241 + (n,gamma) + + + 1 + Am241 + (n,gamma) + + diff --git a/tests/regression_tests/filter_energyfun/results_true.dat b/tests/regression_tests/filter_energyfun/results_true.dat index d64de58a6..a1fda93a8 100644 --- a/tests/regression_tests/filter_energyfun/results_true.dat +++ b/tests/regression_tests/filter_energyfun/results_true.dat @@ -1,10 +1,2 @@ energyfunction nuclide score mean std. dev. -0 448ee8dfd19c4f Am241 ((n,gamma) / (n,gamma)) 1.74e-01 5.44e-03 - energyfunction nuclide score mean std. dev. -0 37e006ae6b2e74 Am241 (n,gamma) 8.35e-02 1.83e-03 - energyfunction nuclide score mean std. dev. -0 b4e2ac84068d2d Am241 (n,gamma) 8.39e-02 1.84e-03 - energyfunction nuclide score mean std. dev. -0 dacf88242512ea Am241 (n,gamma) 8.14e-02 1.78e-03 - energyfunction nuclide score mean std. dev. -0 fe168c70d9e078 Am241 (n,gamma) 1.09e-01 2.41e-03 +0 d2effa26cb3cf2 Am241 ((n,gamma) / (n,gamma)) 1.74e-01 6.83e-03 diff --git a/tests/regression_tests/filter_energyfun/test.py b/tests/regression_tests/filter_energyfun/test.py index 295b8ebd8..f61f05d78 100644 --- a/tests/regression_tests/filter_energyfun/test.py +++ b/tests/regression_tests/filter_energyfun/test.py @@ -28,66 +28,20 @@ def model(): # Make an EnergyFunctionFilter directly from the x and y lists. filt1 = openmc.EnergyFunctionFilter(x, y) - # check interpolatoin property setter - assert filt1.interpolation == 'linear-linear' - - with pytest.raises(ValueError): - filt1.interpolation = '🥏' - # Also make a filter with the .from_tabulated1d constructor. Make sure # the filters are identical. tab1d = openmc.data.Tabulated1D(x, y) filt2 = openmc.EnergyFunctionFilter.from_tabulated1d(tab1d) assert filt1 == filt2, 'Error with the .from_tabulated1d constructor' - filt3 = openmc.EnergyFunctionFilter(x, y) - filt3.interpolation = 'log-log' - - filt4 = openmc.EnergyFunctionFilter(x, y) - filt4.interpolation = 'linear-log' - - filt5 = openmc.EnergyFunctionFilter(x, y) - filt5.interpolation = 'log-linear' - - # define a trapezoidal function for comparison - x = [0.0, 5e6, 1e7, 1.5e7] - y = [0.2, 0.7, 0.7, 0.2] - - filt6 = openmc.EnergyFunctionFilter(x, y) - - filt7 = openmc.EnergyFunctionFilter(x, y) - filt7.interpolation = 'quadratic' - - filt8 = openmc.EnergyFunctionFilter(x, y) - filt8.interpolation = 'cubic' - - filt9 = openmc.EnergyFunctionFilter(x, y) - filt9.interpolation = 'histogram' - - filters = [filt1, filt3, filt4, filt5, filt6, filt7, filt8, filt9] # Make tallies - tallies = [openmc.Tally() for _ in range(len(filters) + 1)] + tallies = [openmc.Tally(), openmc.Tally()] for t in tallies: t.scores = ['(n,gamma)'] t.nuclides = ['Am241'] - - for t, f in zip(tallies[1:], filters): - t.filters = [f] - + tallies[1].filters = [filt1] model.tallies.extend(tallies) - interpolation_vals = \ - list(openmc.EnergyFunctionFilter.INTERPOLATION_SCHEMES.keys()) - for i_val in interpolation_vals: - # breakpoint here is fake and unused - t1d = openmc.data.Tabulated1D(x, - y, - breakpoints=[1], - interpolation=[i_val]) - f = openmc.EnergyFunctionFilter.from_tabulated1d(t1d) - assert f.interpolation == \ - openmc.EnergyFunctionFilter.INTERPOLATION_SCHEMES[i_val] - return model @@ -96,74 +50,13 @@ class FilterEnergyFunHarness(PyAPITestHarness): # Read the statepoint file. sp = openmc.StatePoint(self._sp_name) - dataframes_string = "" # Use tally arithmetic to compute the branching ratio. br_tally = sp.tallies[2] / sp.tallies[1] - dataframes_string += br_tally.get_pandas_dataframe().to_string() + '\n' - - for t_id in (3, 4, 5, 6): - ef_tally = sp.tallies[t_id] - dataframes_string += ef_tally.get_pandas_dataframe().to_string() + '\n' # Output the tally in a Pandas DataFrame. - return dataframes_string + return br_tally.get_pandas_dataframe().to_string() + '\n' - def _compare_results(self): - super()._compare_results() - - # Read the statepoint file. - sp = openmc.StatePoint(self._sp_name) - - # statepoint file round-trip checks - - # linear-linear interpolation tally - sp_lin_lin_tally = sp.get_tally(id=2) - sp_lin_lin_filt = sp_lin_lin_tally.find_filter(openmc.EnergyFunctionFilter) - - model_lin_lin_tally = self._model.tallies[1] - model_lin_lin_filt = model_lin_lin_tally.find_filter(openmc.EnergyFunctionFilter) - - assert sp_lin_lin_filt.interpolation == 'linear-linear' - assert all(sp_lin_lin_filt.energy == model_lin_lin_filt.energy) - assert all(sp_lin_lin_filt.y == model_lin_lin_filt.y) - - # log-log interpolation tally - sp_log_log_tally = sp.get_tally(id=3) - sp_log_log_filt = sp_log_log_tally.find_filter(openmc.EnergyFunctionFilter) - - model_log_log_tally = self._model.tallies[2] - model_log_log_filt = model_log_log_tally.find_filter(openmc.EnergyFunctionFilter) - - assert sp_log_log_filt.interpolation == 'log-log' - assert all(sp_log_log_filt.energy == model_log_log_filt.energy) - assert all(sp_log_log_filt.y == model_log_log_filt.y) - - # because the values of y are monotonically increasing, - # we expect the log-log tally to have a higher value - assert all(sp_lin_lin_tally.mean < sp_log_log_tally.mean) - - sp_lin_log_tally = self._model.tallies[3] - sp_lin_log_filt = sp_lin_log_tally.find_filter(openmc.EnergyFunctionFilter) - assert sp_lin_log_filt.interpolation == 'linear-log' - - sp_log_lin_tally = self._model.tallies[4] - sp_log_lin_filt = sp_log_lin_tally.find_filter(openmc.EnergyFunctionFilter) - assert sp_log_lin_filt.interpolation == 'log-linear' - - # check that the cubic interpolation provides a higher value - # than linear-linear - contrived_lin_lin_tally = sp.get_tally(id=6) - contrived_quadratic_tally = sp.get_tally(id=7) - contrived_cubic_tally = sp.get_tally(id=8) - - assert all(contrived_lin_lin_tally.mean < contrived_quadratic_tally.mean) - assert all(contrived_lin_lin_tally.mean < contrived_cubic_tally.mean) - - # check that the histogram tally is less than the quadratic/cubic interpolations - histogram_tally = sp.get_tally(id=9) - assert all(histogram_tally.mean < contrived_quadratic_tally.mean) - assert all(histogram_tally.mean < contrived_cubic_tally.mean) def test_filter_energyfun(model): harness = FilterEnergyFunHarness('statepoint.5.h5', model) - harness.main() \ No newline at end of file + harness.main() diff --git a/tests/regression_tests/filter_mesh/inputs_true.dat b/tests/regression_tests/filter_mesh/inputs_true.dat index 10f70a720..d0c481d60 100644 --- a/tests/regression_tests/filter_mesh/inputs_true.dat +++ b/tests/regression_tests/filter_mesh/inputs_true.dat @@ -1,151 +1,150 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 5 - -7.5 - 7.5 - - - 5 5 - -7.5 -7.5 - 7.5 7.5 - - - 5 5 5 - -7.5 -7.5 -7.5 - 7.5 7.5 7.5 - - - -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 - -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 - 1.0 1.223224374241637 1.4962778697388448 1.8302835609029084 2.2388474634702153 2.7386127875258306 3.3499379133114306 4.09772570775871 5.012437964687018 6.131336292779302 7.500000000000001 - - - 0.0 0.4411764705882353 0.8823529411764706 1.3235294117647058 1.7647058823529411 2.2058823529411766 2.6470588235294117 3.0882352941176467 3.5294117647058822 3.9705882352941178 4.411764705882353 4.852941176470588 5.294117647058823 5.735294117647059 6.1764705882352935 6.617647058823529 7.0588235294117645 7.5 - 0.0 0.3490658503988659 0.6981317007977318 1.0471975511965976 1.3962634015954636 1.7453292519943295 2.0943951023931953 2.443460952792061 2.792526803190927 3.141592653589793 3.490658503988659 3.839724354387525 4.1887902047863905 4.537856055185257 4.886921905584122 5.235987755982989 5.585053606381854 5.93411945678072 6.283185307179586 - 0.0 0.9375 1.875 2.8125 3.75 4.6875 5.625 6.5625 7.5 8.4375 9.375 10.3125 11.25 12.1875 13.125 14.0625 15.0 - 0.0 0.0 -7.5 - - - 0.0 0.4411764705882353 0.8823529411764706 1.3235294117647058 1.7647058823529411 2.2058823529411766 2.6470588235294117 3.0882352941176467 3.5294117647058822 3.9705882352941178 4.411764705882353 4.852941176470588 5.294117647058823 5.735294117647059 6.1764705882352935 6.617647058823529 7.0588235294117645 7.5 - 0.0 0.39269908169872414 0.7853981633974483 1.1780972450961724 1.5707963267948966 1.9634954084936207 2.356194490192345 2.748893571891069 3.141592653589793 - 0.0 0.3490658503988659 0.6981317007977318 1.0471975511965976 1.3962634015954636 1.7453292519943295 2.0943951023931953 2.443460952792061 2.792526803190927 3.141592653589793 3.490658503988659 3.839724354387525 4.1887902047863905 4.537856055185257 4.886921905584122 5.235987755982989 5.585053606381854 5.93411945678072 6.283185307179586 - 0.0 0.0 0.0 - - - 1 - - - 1 - - - 2 - - - 2 - - - 3 - - - 3 - - - 4 - - - 4 - - - 5 - - - 5 - - - 6 - - - 6 - - - 1 - total - - - 7 - current - - - 2 - total - - - 8 - current - - - 3 - total - - - 9 - current - - - 4 - total - - - 10 - current - - - 5 - total - - - 11 - current - - - 6 - total - - - 12 - current - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + + 5 + -7.5 + 7.5 + + + 5 5 + -7.5 -7.5 + 7.5 7.5 + + + 5 5 5 + -7.5 -7.5 -7.5 + 7.5 7.5 7.5 + + + -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 + -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 + 1.0 1.223224374241637 1.4962778697388448 1.8302835609029084 2.2388474634702153 2.7386127875258306 3.3499379133114306 4.09772570775871 5.012437964687018 6.131336292779302 7.500000000000001 + + + 0.0 0.4411764705882353 0.8823529411764706 1.3235294117647058 1.7647058823529411 2.2058823529411766 2.6470588235294117 3.0882352941176467 3.5294117647058822 3.9705882352941178 4.411764705882353 4.852941176470588 5.294117647058823 5.735294117647059 6.1764705882352935 6.617647058823529 7.0588235294117645 7.5 + 0.0 0.3490658503988659 0.6981317007977318 1.0471975511965976 1.3962634015954636 1.7453292519943295 2.0943951023931953 2.443460952792061 2.792526803190927 3.141592653589793 3.490658503988659 3.839724354387525 4.1887902047863905 4.537856055185257 4.886921905584122 5.235987755982989 5.585053606381854 5.93411945678072 6.283185307179586 + -7.5 -6.5625 -5.625 -4.6875 -3.75 -2.8125 -1.875 -0.9375 0.0 0.9375 1.875 2.8125 3.75 4.6875 5.625 6.5625 7.5 + + + 0.0 0.4411764705882353 0.8823529411764706 1.3235294117647058 1.7647058823529411 2.2058823529411766 2.6470588235294117 3.0882352941176467 3.5294117647058822 3.9705882352941178 4.411764705882353 4.852941176470588 5.294117647058823 5.735294117647059 6.1764705882352935 6.617647058823529 7.0588235294117645 7.5 + 0.0 0.39269908169872414 0.7853981633974483 1.1780972450961724 1.5707963267948966 1.9634954084936207 2.356194490192345 2.748893571891069 3.141592653589793 + 0.0 0.3490658503988659 0.6981317007977318 1.0471975511965976 1.3962634015954636 1.7453292519943295 2.0943951023931953 2.443460952792061 2.792526803190927 3.141592653589793 3.490658503988659 3.839724354387525 4.1887902047863905 4.537856055185257 4.886921905584122 5.235987755982989 5.585053606381854 5.93411945678072 6.283185307179586 + + + 1 + + + 1 + + + 2 + + + 2 + + + 3 + + + 3 + + + 4 + + + 4 + + + 5 + + + 5 + + + 6 + + + 6 + + + 1 + total + + + 7 + current + + + 2 + total + + + 8 + current + + + 3 + total + + + 9 + current + + + 4 + total + + + 10 + current + + + 5 + total + + + 11 + current + + + 6 + total + + + 12 + current + + diff --git a/tests/regression_tests/filter_mesh/results_true.dat b/tests/regression_tests/filter_mesh/results_true.dat index 34e99c17e..ef52af2c7 100644 --- a/tests/regression_tests/filter_mesh/results_true.dat +++ b/tests/regression_tests/filter_mesh/results_true.dat @@ -1 +1 @@ -e07ed2bc8893c69721abf61b123336f1f6128a3bee6ec63b84d1f549f31707a74a6ce885091ccc0eac6b7f16f7cab39ede4784584c08825829e108de878ea5fb \ No newline at end of file +70243ebdb882e4367bf821667a9f4d41dea03eaf8b27d734e014a13e14922b5158cd47b0a7edf3733d4e23ca6a5ab06457220c9138b7e9720acf547f2eaa06e2 \ No newline at end of file diff --git a/tests/regression_tests/filter_mesh/test.py b/tests/regression_tests/filter_mesh/test.py index 165ba2a0c..b047dd252 100644 --- a/tests/regression_tests/filter_mesh/test.py +++ b/tests/regression_tests/filter_mesh/test.py @@ -19,12 +19,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.RectangularPrism(10.0, 10.0) - box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.rectangular_prism(10.0, 10.0) + box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 @@ -60,12 +60,11 @@ def model(): recti_mesh_exp_vols = np.multiply.outer(dxdy, dz) np.testing.assert_allclose(recti_mesh.volumes, recti_mesh_exp_vols) - cyl_mesh = openmc.CylindricalMesh( - origin=(0, 0, -7.5), - r_grid=np.linspace(0, 7.5, 18), - phi_grid=np.linspace(0, 2*pi, 19), - z_grid=np.linspace(0, 15, 17), - ) + cyl_mesh = openmc.CylindricalMesh() + cyl_mesh.r_grid = np.linspace(0, 7.5, 18) + cyl_mesh.phi_grid = np.linspace(0, 2*pi, 19) + cyl_mesh.z_grid = np.linspace(-7.5, 7.5, 17) + dr = 0.5 * np.diff(np.linspace(0, 7.5, 18)**2) dp = np.full(cyl_mesh.dimension[1], 2*pi / 18) dz = np.full(cyl_mesh.dimension[2], 15 / 16) @@ -73,11 +72,10 @@ def model(): cyl_mesh_exp_vols = np.multiply.outer(drdp, dz) np.testing.assert_allclose(cyl_mesh.volumes, cyl_mesh_exp_vols) - sph_mesh = openmc.SphericalMesh( - r_grid=np.linspace(0, 7.5, 18), - theta_grid=np.linspace(0, pi, 9), - phi_grid=np.linspace(0, 2*pi, 19) - ) + sph_mesh = openmc.SphericalMesh() + sph_mesh.r_grid = np.linspace(0, 7.5, 18) + sph_mesh.theta_grid = np.linspace(0, pi, 9) + sph_mesh.phi_grid = np.linspace(0, 2*pi, 19) dr = np.diff(np.linspace(0, 7.5, 18)**3) / 3 dt = np.diff(-np.cos(np.linspace(0, pi, 9))) dp = np.full(sph_mesh.dimension[2], 2*pi / 18) diff --git a/tests/regression_tests/filter_meshborn/__init__.py b/tests/regression_tests/filter_meshborn/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/filter_meshborn/inputs_true.dat b/tests/regression_tests/filter_meshborn/inputs_true.dat deleted file mode 100644 index a94646ec8..000000000 --- a/tests/regression_tests/filter_meshborn/inputs_true.dat +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - fixed source - 2000 - 8 - - - 0.0 -10.0 -10.0 10.0 10.0 10.0 - - - - - - 2 2 1 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - 1 - - - 1 - - - 1 2 - scatter - - - 1 - scatter - - - 2 - scatter - - - scatter - - - diff --git a/tests/regression_tests/filter_meshborn/results_true.dat b/tests/regression_tests/filter_meshborn/results_true.dat deleted file mode 100644 index 62f2707ff..000000000 --- a/tests/regression_tests/filter_meshborn/results_true.dat +++ /dev/null @@ -1,54 +0,0 @@ -tally 1: -0.000000E+00 -0.000000E+00 -2.631246E+01 -8.845079E+01 -0.000000E+00 -0.000000E+00 -2.450265E+00 -9.462266E-01 -0.000000E+00 -0.000000E+00 -3.878380E+02 -1.881752E+04 -0.000000E+00 -0.000000E+00 -2.932956E+01 -1.091674E+02 -0.000000E+00 -0.000000E+00 -1.837753E+00 -5.195343E-01 -0.000000E+00 -0.000000E+00 -2.944919E+01 -1.095819E+02 -0.000000E+00 -0.000000E+00 -2.921731E+01 -1.097387E+02 -0.000000E+00 -0.000000E+00 -4.019442E+02 -2.021184E+04 -tally 2: -2.876273E+01 -1.060244E+02 -4.171676E+02 -2.176683E+04 -3.128695E+01 -1.238772E+02 -4.311615E+02 -2.325871E+04 -tally 3: -0.000000E+00 -0.000000E+00 -4.452055E+02 -2.478148E+04 -0.000000E+00 -0.000000E+00 -4.631732E+02 -2.683862E+04 -tally 4: -9.083787E+02 -1.031695E+05 diff --git a/tests/regression_tests/filter_meshborn/test.py b/tests/regression_tests/filter_meshborn/test.py deleted file mode 100644 index ff4adbc9f..000000000 --- a/tests/regression_tests/filter_meshborn/test.py +++ /dev/null @@ -1,107 +0,0 @@ -"""Test the meshborn filter using a fixed source calculation on a H1 sphere. - -""" - -from numpy.testing import assert_allclose -import numpy as np -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -RTOL = 1.0e-7 -ATOL = 0.0 - - -@pytest.fixture -def model(): - """Sphere of H1 with one hemisphere containing the source (x>0) and one - hemisphere with no source (x<0). - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # Materials - h1 = openmc.Material() - h1.add_nuclide("H1", 1.0) - h1.set_density("g/cm3", 1.0) - model.materials = openmc.Materials([h1]) - - # Core geometry - r = 10.0 - sphere = openmc.Sphere(r=r, boundary_type="reflective") - core = openmc.Cell(fill=h1, region=-sphere) - model.geometry = openmc.Geometry([core]) - - # Settings - model.settings.run_mode = 'fixed source' - model.settings.particles = 2000 - model.settings.batches = 8 - distribution = openmc.stats.Box((0., -r, -r), (r, r, r)) - model.settings.source = openmc.IndependentSource(space=distribution) - - # Tallies - mesh = openmc.RegularMesh() - mesh.dimension = (2, 2, 1) - mesh.lower_left = (-r, -r, -r) - mesh.upper_right = (r, r, r) - - f_1 = openmc.MeshFilter(mesh) - f_2 = openmc.MeshBornFilter(mesh) - - t_1 = openmc.Tally(name="scatter") - t_1.filters = [f_1, f_2] - t_1.scores = ["scatter"] - - t_2 = openmc.Tally(name="scatter-mesh") - t_2.filters = [f_1] - t_2.scores = ["scatter"] - - t_3 = openmc.Tally(name="scatter-meshborn") - t_3.filters = [f_2] - t_3.scores = ["scatter"] - - t_4 = openmc.Tally(name="scatter-total") - t_4.scores = ["scatter"] - - model.tallies = [t_1, t_2, t_3, t_4] - - return model - - -class MeshBornFilterTest(PyAPITestHarness): - - def _compare_results(self): - """Additional unit tests on the tally results to check consistency.""" - with openmc.StatePoint(self.statepoint_name) as sp: - - t1 = sp.get_tally(name="scatter").mean.reshape(4, 4) - t2 = sp.get_tally(name="scatter-mesh").mean.reshape(4) - t3 = sp.get_tally(name="scatter-meshborn").mean.reshape(4) - t4 = sp.get_tally(name="scatter-total").mean.reshape(1) - - # Consistency between mesh+meshborn matrix tally and meshborn tally - for i in range(4): - assert_allclose(t1[:, i].sum(), t3[i], rtol=RTOL, atol=ATOL) - - # Consistency between mesh+meshborn matrix tally and mesh tally - for i in range(4): - assert_allclose(t1[i, :].sum(), t2[i], rtol=RTOL, atol=ATOL) - - # Mesh cells in x<0 do not contribute to meshborn - assert_allclose(t1[:, 0].sum(), np.zeros(4), rtol=RTOL, atol=ATOL) - assert_allclose(t1[:, 2].sum(), np.zeros(4), rtol=RTOL, atol=ATOL) - - # Consistency with total scattering - assert_allclose(t1.sum(), t4, rtol=RTOL, atol=ATOL) - assert_allclose(t2.sum(), t4, rtol=RTOL, atol=ATOL) - assert_allclose(t3.sum(), t4, rtol=RTOL, atol=ATOL) - - super()._compare_results() - - -def test_filter_meshborn(model): - harness = MeshBornFilterTest("statepoint.8.h5", model) - harness.main() diff --git a/tests/regression_tests/filter_musurface/__init__.py b/tests/regression_tests/filter_musurface/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/filter_musurface/inputs_true.dat b/tests/regression_tests/filter_musurface/inputs_true.dat deleted file mode 100644 index b457f5028..000000000 --- a/tests/regression_tests/filter_musurface/inputs_true.dat +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 1 - - - -1.0 -0.5 0.0 0.5 1.0 - - - 1 2 - current flux - - - diff --git a/tests/regression_tests/filter_musurface/results_true.dat b/tests/regression_tests/filter_musurface/results_true.dat deleted file mode 100644 index 657c141a0..000000000 --- a/tests/regression_tests/filter_musurface/results_true.dat +++ /dev/null @@ -1,19 +0,0 @@ -k-combined: -1.202075E-01 1.113188E-02 -tally 1: -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.230000E-01 -1.791510E-01 -3.294304E+00 -2.314403E+00 -3.869000E+00 -3.002523E+00 -5.154125E+00 -5.314334E+00 diff --git a/tests/regression_tests/filter_musurface/test.py b/tests/regression_tests/filter_musurface/test.py deleted file mode 100644 index bfc12a47c..000000000 --- a/tests/regression_tests/filter_musurface/test.py +++ /dev/null @@ -1,40 +0,0 @@ -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - model = openmc.Model() - fuel = openmc.Material() - fuel.set_density('g/cm3', 10.0) - fuel.add_nuclide('U235', 1.0) - zr = openmc.Material() - zr.set_density('g/cm3', 1.0) - zr.add_nuclide('Zr90', 1.0) - - cyl1 = openmc.ZCylinder(r=1.0) - cyl2 = openmc.ZCylinder(r=3.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=-cyl1) - cell2 = openmc.Cell(fill=zr, region=+cyl1 & -cyl2) - model.geometry = openmc.Geometry([cell1, cell2]) - - model.settings.batches = 5 - model.settings.inactive = 0 - model.settings.particles = 1000 - - # Create a tally for current through the first surface binned by mu - surf_filter = openmc.SurfaceFilter([cyl1]) - mu_filter = openmc.MuSurfaceFilter([-1.0, -0.5, 0.0, 0.5, 1.0]) - tally = openmc.Tally() - tally.filters = [surf_filter, mu_filter] - tally.scores = ['current', 'flux'] - model.tallies.append(tally) - - return model - - -def test_filter_musurface(model): - harness = PyAPITestHarness('statepoint.5.h5', model) - harness.main() diff --git a/tests/regression_tests/filter_reaction/__init__.py b/tests/regression_tests/filter_reaction/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/filter_reaction/inputs_true.dat b/tests/regression_tests/filter_reaction/inputs_true.dat deleted file mode 100644 index 3ab9ab3fb..000000000 --- a/tests/regression_tests/filter_reaction/inputs_true.dat +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - - - - (n,elastic) (n,2n) (n,fission) (n,gamma) (n,total) - - - 1 - flux - - - diff --git a/tests/regression_tests/filter_reaction/results_true.dat b/tests/regression_tests/filter_reaction/results_true.dat deleted file mode 100644 index 61ec1c65f..000000000 --- a/tests/regression_tests/filter_reaction/results_true.dat +++ /dev/null @@ -1,13 +0,0 @@ -k-combined: -2.265297E+00 7.172807E-03 -tally 1: -8.364316E+01 -1.400120E+03 -1.412312E-01 -4.277446E-03 -5.471503E+00 -7.015849E+00 -0.000000E+00 -0.000000E+00 -1.349840E+02 -3.644648E+03 diff --git a/tests/regression_tests/filter_reaction/test.py b/tests/regression_tests/filter_reaction/test.py deleted file mode 100644 index 3c60fd517..000000000 --- a/tests/regression_tests/filter_reaction/test.py +++ /dev/null @@ -1,31 +0,0 @@ -import openmc - -from tests.testing_harness import PyAPITestHarness - - -def test_filter_reaction(): - model = openmc.Model() - - m = openmc.Material() - m.set_density('g/cm3', 10.0) - m.add_nuclide('U235', 1.0) - model.materials.append(m) - - s = openmc.Sphere(r=100.0, boundary_type='vacuum') - c = openmc.Cell(fill=m, region=-s) - model.geometry = openmc.Geometry([c]) - - # Create a tally with reaction filter - tally = openmc.Tally() - tally.filters = [openmc.ReactionFilter( - ['(n,elastic)', '(n,2n)', '(n,fission)', '(n,gamma)', 'total'] - )] - tally.scores = ['flux'] - model.tallies = openmc.Tallies([tally]) - - # Reduce particles for faster testing - model.settings.particles = 1000 - model.settings.batches = 5 - - harness = PyAPITestHarness('statepoint.5.h5', model) - harness.main() diff --git a/tests/regression_tests/filter_rotations/__init__.py b/tests/regression_tests/filter_rotations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/filter_rotations/inputs_true.dat b/tests/regression_tests/filter_rotations/inputs_true.dat deleted file mode 100644 index 1ad2b9e86..000000000 --- a/tests/regression_tests/filter_rotations/inputs_true.dat +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 3 4 5 - -9 -9 -9 - 9 9 9 - - - 3 4 5 - -9 -9 -9 - 9 9 9 - - - 1 - - - 2 - - - 1 - total - - - 2 - total - - - diff --git a/tests/regression_tests/filter_rotations/results_true.dat b/tests/regression_tests/filter_rotations/results_true.dat deleted file mode 100644 index 5c8b83b76..000000000 --- a/tests/regression_tests/filter_rotations/results_true.dat +++ /dev/null @@ -1,244 +0,0 @@ -k-combined: -7.729082E-01 3.775399E-02 -tally 1: -5.296804E-02 -5.661701E-04 -8.356446E-02 -1.412139E-03 -5.041335E-02 -5.143568E-04 -1.299348E-01 -3.467618E-03 -3.929702E-01 -3.147038E-02 -1.379707E-01 -3.888484E-03 -1.405034E-01 -4.473799E-03 -3.785796E-01 -2.940585E-02 -1.422010E-01 -4.113723E-03 -5.647073E-02 -6.735251E-04 -7.911154E-02 -1.329137E-03 -5.160755E-02 -5.361448E-04 -6.669424E-02 -9.090832E-04 -1.008621E-01 -2.134534E-03 -6.808932E-02 -9.355993E-04 -1.873006E-01 -7.135961E-03 -6.221575E-01 -7.819842E-02 -1.856653E-01 -6.954762E-03 -2.014929E-01 -8.327845E-03 -5.853251E-01 -6.945708E-02 -1.709645E-01 -5.917124E-03 -7.214913E-02 -1.058962E-03 -1.027720E-01 -2.138475E-03 -6.099853E-02 -7.493941E-04 -6.892071E-02 -9.630680E-04 -1.035459E-01 -2.173883E-03 -6.973870E-02 -9.904237E-04 -2.125703E-01 -9.112659E-03 -9.012205E-01 -2.163546E-01 -2.066426E-01 -8.617414E-03 -2.258950E-01 -1.039607E-02 -9.476792E-01 -2.350708E-01 -2.225585E-01 -1.017898E-02 -7.111503E-02 -1.036847E-03 -1.117012E-01 -2.530040E-03 -6.870474E-02 -9.551035E-04 -5.738897E-02 -6.699030E-04 -9.522335E-02 -1.835769E-03 -6.570917E-02 -8.656870E-04 -1.945592E-01 -7.593336E-03 -5.514753E-01 -6.122981E-02 -2.144202E-01 -9.421739E-03 -1.971631E-01 -7.944046E-03 -6.088996E-01 -7.442954E-02 -1.965447E-01 -7.765628E-03 -7.005494E-02 -1.012891E-03 -1.010633E-01 -2.084095E-03 -6.145926E-02 -7.694351E-04 -4.999479E-02 -5.129164E-04 -7.238243E-02 -1.062921E-03 -4.902309E-02 -4.852193E-04 -1.324655E-01 -3.642431E-03 -3.305312E-01 -2.265726E-02 -1.332993E-01 -3.728385E-03 -1.547469E-01 -4.894837E-03 -3.625944E-01 -2.747313E-02 -1.435761E-01 -4.334405E-03 -5.789603E-02 -7.065383E-04 -7.589559E-02 -1.205386E-03 -5.210018E-02 -5.790843E-04 -tally 2: -4.597932E-02 -4.246849E-04 -8.494738E-02 -1.467238E-03 -5.155072E-02 -5.373129E-04 -1.479395E-01 -4.468164E-03 -3.931843E-01 -3.141943E-02 -1.264081E-01 -3.243689E-03 -1.229742E-01 -3.276501E-03 -3.768427E-01 -2.927971E-02 -1.574908E-01 -5.079304E-03 -5.621044E-02 -6.877866E-04 -8.490616E-02 -1.510673E-03 -4.709600E-02 -4.576632E-04 -5.382674E-02 -5.890600E-04 -1.116560E-01 -2.599817E-03 -6.648634E-02 -8.862677E-04 -1.996861E-01 -8.137198E-03 -6.218616E-01 -7.805532E-02 -1.672379E-01 -5.667797E-03 -1.841275E-01 -6.936896E-03 -5.887874E-01 -7.031665E-02 -1.872574E-01 -7.086584E-03 -7.574698E-02 -1.160992E-03 -1.100173E-01 -2.453972E-03 -5.427866E-02 -5.955556E-04 -5.644318E-02 -6.503634E-04 -1.058628E-01 -2.254338E-03 -8.012794E-02 -1.297032E-03 -2.292757E-01 -1.064490E-02 -9.001874E-01 -2.153097E-01 -1.921874E-01 -7.537343E-03 -2.058642E-01 -8.537136E-03 -9.442653E-01 -2.359241E-01 -2.419900E-01 -1.202201E-02 -7.563876E-02 -1.169874E-03 -1.165428E-01 -2.750405E-03 -5.646354E-02 -6.408683E-04 -4.963879E-02 -4.975915E-04 -1.005478E-01 -2.046400E-03 -7.041191E-02 -1.002590E-03 -1.959123E-01 -7.727902E-03 -5.625596E-01 -6.366248E-02 -1.987313E-01 -8.108832E-03 -1.922194E-01 -7.602752E-03 -6.062527E-01 -7.384124E-02 -2.039506E-01 -8.379010E-03 -7.019905E-02 -1.034239E-03 -1.081383E-01 -2.344040E-03 -5.125142E-02 -5.430397E-04 -4.230495E-02 -3.666730E-04 -7.722275E-02 -1.208856E-03 -4.998937E-02 -5.049355E-04 -1.461632E-01 -4.456332E-03 -3.315459E-01 -2.288314E-02 -1.238273E-01 -3.205844E-03 -1.355317E-01 -3.754923E-03 -3.646520E-01 -2.766067E-02 -1.543013E-01 -5.044487E-03 -6.082173E-02 -7.636985E-04 -8.490569E-02 -1.506309E-03 -4.046126E-02 -3.495832E-04 diff --git a/tests/regression_tests/filter_rotations/test.py b/tests/regression_tests/filter_rotations/test.py deleted file mode 100644 index f5d63d6b4..000000000 --- a/tests/regression_tests/filter_rotations/test.py +++ /dev/null @@ -1,72 +0,0 @@ -import numpy as np - -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - - model = openmc.model.Model() - - fuel = openmc.Material() - fuel.set_density('g/cm3', 10.0) - fuel.add_nuclide('U235', 1.0) - zr = openmc.Material() - zr.set_density('g/cm3', 1.0) - zr.add_nuclide('Zr90', 1.0) - model.materials.extend([fuel, zr]) - - box1 = openmc.model.RectangularPrism(10.0, 10.0) - box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') - top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') - bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) - model.geometry = openmc.Geometry([cell1, cell2]) - - model.settings.batches = 5 - model.settings.inactive = 0 - model.settings.particles = 1000 - - rotation = np.array((0, 0, 10)) - - llc = np.array([-9, -9, -9]) - urc = np.array([9, 9, 9]) - - mesh_dims = (3, 4, 5) - - filters = [] - - # un-rotated meshes - reg_mesh = openmc.RegularMesh() - reg_mesh.dimension = mesh_dims - reg_mesh.lower_left = llc - reg_mesh.upper_right = urc - - filters.append(openmc.MeshFilter(reg_mesh)) - - # rotated meshes - rotated_reg_mesh = openmc.RegularMesh() - rotated_reg_mesh.dimension = mesh_dims - rotated_reg_mesh.lower_left = llc - rotated_reg_mesh.upper_right = urc - - filters.append(openmc.MeshFilter(rotated_reg_mesh)) - filters[-1].rotation = rotation - - # Create tallies - for f in filters: - tally = openmc.Tally() - tally.filters = [f] - tally.scores = ['total'] - model.tallies.append(tally) - - return model - - -def test_filter_mesh_rotations(model): - harness = PyAPITestHarness('statepoint.5.h5', model) - harness.main() diff --git a/tests/regression_tests/filter_translations/inputs_true.dat b/tests/regression_tests/filter_translations/inputs_true.dat index 41ae9b6dc..d38bec39f 100644 --- a/tests/regression_tests/filter_translations/inputs_true.dat +++ b/tests/regression_tests/filter_translations/inputs_true.dat @@ -1,83 +1,84 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 3 4 5 - -9 -9 -9 - 9 9 9 - - - -9.0 0.0 9.0 - -9.0 -3.0 3.0 9.0 - -9.0 -4.5 0.0 4.5 9.0 - - - 3 4 5 - -19 -4 -9 - -1 14 9 - - - -19.0 -10.0 -1.0 - -4.0 2.0 8.0 14.0 - -9.0 -4.5 0.0 4.5 9.0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 1 - total - - - 2 - total - - - 3 - total - - - 4 - total - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + + 3 4 5 + -9 -9 -9 + 9 9 9 + + + -9.0 0.0 9.0 + -9.0 -3.0 3.0 9.0 + -9.0 -4.5 0.0 4.5 9.0 + + + 3 4 5 + -19 -4 -9 + -1 14 9 + + + -19.0 -10.0 -1.0 + -4.0 2.0 8.0 14.0 + -9.0 -4.5 0.0 4.5 9.0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 1 + total + + + 2 + total + + + 3 + total + + + 4 + total + + diff --git a/tests/regression_tests/filter_translations/results_true.dat b/tests/regression_tests/filter_translations/results_true.dat index a63586d2d..e5e620b97 100644 --- a/tests/regression_tests/filter_translations/results_true.dat +++ b/tests/regression_tests/filter_translations/results_true.dat @@ -1,342 +1,342 @@ k-combined: -7.729082E-01 3.775399E-02 +7.952381E-01 3.714273E-02 tally 1: -5.296804E-02 -5.661701E-04 -8.356446E-02 -1.412139E-03 -5.041335E-02 -5.143568E-04 -1.299348E-01 -3.467618E-03 -3.929702E-01 -3.147038E-02 -1.379707E-01 -3.888484E-03 -1.405034E-01 -4.473799E-03 -3.785796E-01 -2.940585E-02 -1.422010E-01 -4.113723E-03 -5.647073E-02 -6.735251E-04 -7.911154E-02 -1.329137E-03 -5.160755E-02 -5.361448E-04 -6.669424E-02 -9.090832E-04 -1.008621E-01 -2.134534E-03 -6.808932E-02 -9.355993E-04 -1.873006E-01 -7.135961E-03 -6.221575E-01 -7.819842E-02 -1.856653E-01 -6.954762E-03 -2.014929E-01 -8.327845E-03 -5.853251E-01 -6.945708E-02 -1.709645E-01 -5.917124E-03 -7.214913E-02 -1.058962E-03 -1.027720E-01 -2.138475E-03 -6.099853E-02 -7.493941E-04 -6.892071E-02 -9.630680E-04 -1.035459E-01 -2.173883E-03 -6.973870E-02 -9.904237E-04 -2.125703E-01 -9.112659E-03 -9.012205E-01 -2.163546E-01 -2.066426E-01 -8.617414E-03 -2.258950E-01 -1.039607E-02 -9.476792E-01 -2.350708E-01 -2.225585E-01 -1.017898E-02 -7.111503E-02 -1.036847E-03 -1.117012E-01 -2.530040E-03 -6.870474E-02 -9.551035E-04 -5.738897E-02 -6.699030E-04 -9.522335E-02 -1.835769E-03 -6.570917E-02 -8.656870E-04 -1.945592E-01 -7.593336E-03 -5.514753E-01 -6.122981E-02 -2.144202E-01 -9.421739E-03 -1.971631E-01 -7.944046E-03 -6.088996E-01 -7.442954E-02 -1.965447E-01 -7.765628E-03 -7.005494E-02 -1.012891E-03 -1.010633E-01 -2.084095E-03 -6.145926E-02 -7.694351E-04 -4.999479E-02 -5.129164E-04 -7.238243E-02 -1.062921E-03 -4.902309E-02 -4.852193E-04 -1.324655E-01 -3.642431E-03 -3.305312E-01 -2.265726E-02 -1.332993E-01 -3.728385E-03 -1.547469E-01 -4.894837E-03 -3.625944E-01 -2.747313E-02 -1.435761E-01 -4.334405E-03 -5.789603E-02 -7.065383E-04 -7.589559E-02 -1.205386E-03 -5.210018E-02 -5.790843E-04 +5.340506E-02 +5.744901E-04 +8.160966E-02 +1.360702E-03 +5.306458E-02 +5.712302E-04 +1.263577E-01 +3.302526E-03 +3.858930E-01 +3.008104E-02 +1.511449E-01 +4.656419E-03 +1.279399E-01 +3.429368E-03 +3.676349E-01 +2.739091E-02 +1.410822E-01 +4.100718E-03 +5.379722E-02 +5.997669E-04 +8.933947E-02 +1.635151E-03 +5.212766E-02 +5.497167E-04 +7.332108E-02 +1.098591E-03 +1.040477E-01 +2.211291E-03 +5.326449E-02 +5.881665E-04 +1.952299E-01 +7.733668E-03 +5.683168E-01 +6.600345E-02 +1.866765E-01 +7.004663E-03 +2.262997E-01 +1.033597E-02 +6.280081E-01 +7.932045E-02 +1.861170E-01 +6.952815E-03 +7.317076E-02 +1.109977E-03 +1.145829E-01 +2.646373E-03 +6.567032E-02 +8.836880E-04 +6.614241E-02 +8.902720E-04 +1.083575E-01 +2.356190E-03 +6.479323E-02 +8.604886E-04 +2.202887E-01 +9.846484E-03 +9.405324E-01 +2.263338E-01 +1.993991E-01 +7.984693E-03 +2.310168E-01 +1.084962E-02 +9.617014E-01 +2.432501E-01 +2.127786E-01 +9.085201E-03 +7.772444E-02 +1.217267E-03 +1.170744E-01 +2.791253E-03 +7.480464E-02 +1.126824E-03 +6.321842E-02 +8.234272E-04 +1.002360E-01 +2.026069E-03 +6.532157E-02 +8.622865E-04 +1.934126E-01 +7.639724E-03 +5.583838E-01 +6.274792E-02 +1.914812E-01 +7.440011E-03 +1.808706E-01 +6.774850E-03 +6.259735E-01 +7.874410E-02 +1.959623E-01 +7.771208E-03 +6.301362E-02 +8.178688E-04 +1.062362E-01 +2.292485E-03 +5.916939E-02 +7.078944E-04 +5.265976E-02 +5.634399E-04 +6.747063E-02 +9.141711E-04 +4.478697E-02 +4.077583E-04 +1.277486E-01 +3.308655E-03 +3.585674E-01 +2.641571E-02 +1.192882E-01 +2.901276E-03 +1.457696E-01 +4.299462E-03 +3.467377E-01 +2.463831E-02 +1.305729E-01 +3.605534E-03 +5.067715E-02 +5.273379E-04 +7.374940E-02 +1.102912E-03 +5.226497E-02 +5.649644E-04 tally 2: -2.572693E-01 -1.338921E-02 -2.567576E-01 -1.333558E-02 -6.127899E-01 -7.781914E-02 -6.163075E-01 -7.600273E-02 -2.566545E-01 -1.372553E-02 -2.509744E-01 -1.286275E-02 -3.366720E-01 -2.282560E-02 -3.216175E-01 -2.103222E-02 -1.118187E+00 -2.697988E-01 -1.050003E+00 -2.391098E-01 -3.407360E-01 -2.332214E-02 -3.150094E-01 -2.006040E-02 -3.130223E-01 -2.001074E-02 -3.238651E-01 -2.101351E-02 -1.061186E+00 -2.372828E-01 -1.099461E+00 -2.597134E-01 -3.445524E-01 -2.400393E-02 -3.429055E-01 -2.372392E-02 -2.299776E-01 -1.064851E-02 -2.208901E-01 -9.829109E-03 -6.015657E-01 -7.399276E-02 -5.851229E-01 -7.165716E-02 -2.583609E-01 -1.364046E-02 -2.456380E-01 -1.257735E-02 +2.442367E-01 +1.209459E-02 +2.543262E-01 +1.314598E-02 +5.639744E-01 +6.449959E-02 +6.415410E-01 +8.269091E-02 +2.631124E-01 +1.406544E-02 +2.513955E-01 +1.285616E-02 +3.570608E-01 +2.559924E-02 +2.978502E-01 +1.787722E-02 +1.142500E+00 +2.799696E-01 +1.072656E+00 +2.465813E-01 +3.720711E-01 +2.776168E-02 +3.520288E-01 +2.482313E-02 +3.406093E-01 +2.332649E-02 +3.186893E-01 +2.046998E-02 +1.039053E+00 +2.337911E-01 +1.055863E+00 +2.442418E-01 +3.636093E-01 +2.679467E-02 +3.514845E-01 +2.481131E-02 +2.356811E-01 +1.112305E-02 +2.424590E-01 +1.205945E-02 +5.851380E-01 +6.974618E-02 +5.788717E-01 +6.882684E-02 +2.430058E-01 +1.205907E-02 +2.390704E-01 +1.167330E-02 tally 3: -5.296804E-02 -5.661701E-04 -8.356446E-02 -1.412139E-03 -5.041335E-02 -5.143568E-04 -1.299348E-01 -3.467618E-03 -3.929702E-01 -3.147038E-02 -1.379707E-01 -3.888484E-03 -1.405034E-01 -4.473799E-03 -3.785796E-01 -2.940585E-02 -1.422010E-01 -4.113723E-03 -5.647073E-02 -6.735251E-04 -7.911154E-02 -1.329137E-03 -5.160755E-02 -5.361448E-04 -6.669424E-02 -9.090832E-04 -1.008621E-01 -2.134534E-03 -6.808932E-02 -9.355993E-04 -1.873006E-01 -7.135961E-03 -6.221575E-01 -7.819842E-02 -1.856653E-01 -6.954762E-03 -2.014929E-01 -8.327845E-03 -5.853251E-01 -6.945708E-02 -1.709645E-01 -5.917124E-03 -7.214913E-02 -1.058962E-03 -1.027720E-01 -2.138475E-03 -6.099853E-02 -7.493941E-04 -6.892071E-02 -9.630680E-04 -1.035459E-01 -2.173883E-03 -6.973870E-02 -9.904237E-04 -2.125703E-01 -9.112659E-03 -9.012205E-01 -2.163546E-01 -2.066426E-01 -8.617414E-03 -2.258950E-01 -1.039607E-02 -9.476792E-01 -2.350708E-01 -2.225585E-01 -1.017898E-02 -7.111503E-02 -1.036847E-03 -1.117012E-01 -2.530040E-03 -6.870474E-02 -9.551035E-04 -5.738897E-02 -6.699030E-04 -9.522335E-02 -1.835769E-03 -6.570917E-02 -8.656870E-04 -1.945592E-01 -7.593336E-03 -5.514753E-01 -6.122981E-02 -2.144202E-01 -9.421739E-03 -1.971631E-01 -7.944046E-03 -6.088996E-01 -7.442954E-02 -1.965447E-01 -7.765628E-03 -7.005494E-02 -1.012891E-03 -1.010633E-01 -2.084095E-03 -6.145926E-02 -7.694351E-04 -4.999479E-02 -5.129164E-04 -7.238243E-02 -1.062921E-03 -4.902309E-02 -4.852193E-04 -1.324655E-01 -3.642431E-03 -3.305312E-01 -2.265726E-02 -1.332993E-01 -3.728385E-03 -1.547469E-01 -4.894837E-03 -3.625944E-01 -2.747313E-02 -1.435761E-01 -4.334405E-03 -5.789603E-02 -7.065383E-04 -7.589559E-02 -1.205386E-03 -5.210018E-02 -5.790843E-04 +5.340506E-02 +5.744901E-04 +8.160966E-02 +1.360702E-03 +5.306458E-02 +5.712302E-04 +1.263577E-01 +3.302526E-03 +3.858930E-01 +3.008104E-02 +1.511449E-01 +4.656419E-03 +1.279399E-01 +3.429368E-03 +3.676349E-01 +2.739091E-02 +1.410822E-01 +4.100718E-03 +5.379722E-02 +5.997669E-04 +8.933947E-02 +1.635151E-03 +5.212766E-02 +5.497167E-04 +7.332108E-02 +1.098591E-03 +1.040477E-01 +2.211291E-03 +5.326449E-02 +5.881665E-04 +1.952299E-01 +7.733668E-03 +5.683168E-01 +6.600345E-02 +1.866765E-01 +7.004663E-03 +2.262997E-01 +1.033597E-02 +6.280081E-01 +7.932045E-02 +1.861170E-01 +6.952815E-03 +7.317076E-02 +1.109977E-03 +1.145829E-01 +2.646373E-03 +6.567032E-02 +8.836880E-04 +6.614241E-02 +8.902720E-04 +1.083575E-01 +2.356190E-03 +6.479323E-02 +8.604886E-04 +2.202887E-01 +9.846484E-03 +9.405324E-01 +2.263338E-01 +1.993991E-01 +7.984693E-03 +2.310168E-01 +1.084962E-02 +9.617014E-01 +2.432501E-01 +2.127786E-01 +9.085201E-03 +7.772444E-02 +1.217267E-03 +1.170744E-01 +2.791253E-03 +7.480464E-02 +1.126824E-03 +6.321842E-02 +8.234272E-04 +1.002360E-01 +2.026069E-03 +6.532157E-02 +8.622865E-04 +1.934126E-01 +7.639724E-03 +5.583838E-01 +6.274792E-02 +1.914812E-01 +7.440011E-03 +1.808706E-01 +6.774850E-03 +6.259735E-01 +7.874410E-02 +1.959623E-01 +7.771208E-03 +6.301362E-02 +8.178688E-04 +1.062362E-01 +2.292485E-03 +5.916939E-02 +7.078944E-04 +5.265976E-02 +5.634399E-04 +6.747063E-02 +9.141711E-04 +4.478697E-02 +4.077583E-04 +1.277486E-01 +3.308655E-03 +3.585674E-01 +2.641571E-02 +1.192882E-01 +2.901276E-03 +1.457696E-01 +4.299462E-03 +3.467377E-01 +2.463831E-02 +1.305729E-01 +3.605534E-03 +5.067715E-02 +5.273379E-04 +7.374940E-02 +1.102912E-03 +5.226497E-02 +5.649644E-04 tally 4: -2.572693E-01 -1.338921E-02 -2.567576E-01 -1.333558E-02 -6.127899E-01 -7.781914E-02 -6.163075E-01 -7.600273E-02 -2.566545E-01 -1.372553E-02 -2.509744E-01 -1.286275E-02 -3.366720E-01 -2.282560E-02 -3.216175E-01 -2.103222E-02 -1.118187E+00 -2.697988E-01 -1.050003E+00 -2.391098E-01 -3.407360E-01 -2.332214E-02 -3.150094E-01 -2.006040E-02 -3.130223E-01 -2.001074E-02 -3.238651E-01 -2.101351E-02 -1.061186E+00 -2.372828E-01 -1.099461E+00 -2.597134E-01 -3.445524E-01 -2.400393E-02 -3.429055E-01 -2.372392E-02 -2.299776E-01 -1.064851E-02 -2.208901E-01 -9.829109E-03 -6.015657E-01 -7.399276E-02 -5.851229E-01 -7.165716E-02 -2.583609E-01 -1.364046E-02 -2.456380E-01 -1.257735E-02 +2.442367E-01 +1.209459E-02 +2.543262E-01 +1.314598E-02 +5.639744E-01 +6.449959E-02 +6.415410E-01 +8.269091E-02 +2.631124E-01 +1.406544E-02 +2.513955E-01 +1.285616E-02 +3.570608E-01 +2.559924E-02 +2.978502E-01 +1.787722E-02 +1.142500E+00 +2.799696E-01 +1.072656E+00 +2.465813E-01 +3.720711E-01 +2.776168E-02 +3.520288E-01 +2.482313E-02 +3.406093E-01 +2.332649E-02 +3.186893E-01 +2.046998E-02 +1.039053E+00 +2.337911E-01 +1.055863E+00 +2.442418E-01 +3.636093E-01 +2.679467E-02 +3.514845E-01 +2.481131E-02 +2.356811E-01 +1.112305E-02 +2.424590E-01 +1.205945E-02 +5.851380E-01 +6.974618E-02 +5.788717E-01 +6.882684E-02 +2.430058E-01 +1.205907E-02 +2.390704E-01 +1.167330E-02 diff --git a/tests/regression_tests/filter_translations/test.py b/tests/regression_tests/filter_translations/test.py index 4f0fe7141..d61667b01 100644 --- a/tests/regression_tests/filter_translations/test.py +++ b/tests/regression_tests/filter_translations/test.py @@ -19,12 +19,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.RectangularPrism(10.0, 10.0) - box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.rectangular_prism(10.0, 10.0) + box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 diff --git a/tests/regression_tests/fixed_source/inputs_true.dat b/tests/regression_tests/fixed_source/inputs_true.dat index a36741775..f1aebb3b2 100644 --- a/tests/regression_tests/fixed_source/inputs_true.dat +++ b/tests/regression_tests/fixed_source/inputs_true.dat @@ -1,30 +1,31 @@ - - - - - - - - - - - - - - fixed source - 100 - 10 - - - 0.0 0.0 0.0 - - - 294 - - - - flux - - - + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + 0.0 0.0 0.0 + + + 294 + + + + + flux + + diff --git a/tests/regression_tests/fixed_source/test.py b/tests/regression_tests/fixed_source/test.py index b9ee25125..74908f87c 100644 --- a/tests/regression_tests/fixed_source/test.py +++ b/tests/regression_tests/fixed_source/test.py @@ -48,8 +48,8 @@ def test_fixed_source(): model.settings.batches = 10 model.settings.particles = 100 model.settings.temperature = {'default': 294} - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(), - strength=10.0) + model.settings.source = openmc.Source(space=openmc.stats.Point(), + strength=10.0) tally = openmc.Tally() tally.scores = ['flux'] diff --git a/tests/regression_tests/ifp/__init__.py b/tests/regression_tests/ifp/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/ifp/groupwise/__init__.py b/tests/regression_tests/ifp/groupwise/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/ifp/groupwise/inputs_true.dat b/tests/regression_tests/ifp/groupwise/inputs_true.dat deleted file mode 100644 index 6d7e20717..000000000 --- a/tests/regression_tests/ifp/groupwise/inputs_true.dat +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 5 - - - -10.0 -10.0 -10.0 10.0 10.0 10.0 - - - true - - - 5 - - - - 1 2 3 4 5 6 - - - ifp-time-numerator - - - 1 - ifp-beta-numerator - - - ifp-denominator - - - diff --git a/tests/regression_tests/ifp/groupwise/results_true.dat b/tests/regression_tests/ifp/groupwise/results_true.dat deleted file mode 100644 index ea66a8de3..000000000 --- a/tests/regression_tests/ifp/groupwise/results_true.dat +++ /dev/null @@ -1,21 +0,0 @@ -k-combined: -1.006559E+00 5.389391E-03 -tally 1: -9.109384E-08 -5.667165E-16 -tally 2: -3.000000E-03 -9.000000E-06 -0.000000E+00 -0.000000E+00 -2.100000E-02 -1.370000E-04 -2.800000E-02 -2.220000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -tally 3: -1.489000E+01 -1.480036E+01 diff --git a/tests/regression_tests/ifp/groupwise/test.py b/tests/regression_tests/ifp/groupwise/test.py deleted file mode 100644 index a1a0ebefb..000000000 --- a/tests/regression_tests/ifp/groupwise/test.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Test the Iterated Fission Probability (IFP) method to compute adjoint-weighted -kinetics parameters using dedicated tallies.""" - -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - -@pytest.fixture() -def ifp_model(): - # Material - material = openmc.Material(name="core") - material.add_nuclide("U235", 1.0) - material.set_density('g/cm3', 16.0) - - # Geometry - radius = 10.0 - sphere = openmc.Sphere(r=radius, boundary_type="vacuum") - cell = openmc.Cell(region=-sphere, fill=material) - geometry = openmc.Geometry([cell]) - - # Settings - settings = openmc.Settings() - settings.particles = 1000 - settings.batches = 20 - settings.inactive = 5 - settings.ifp_n_generation = 5 - - model = openmc.Model(settings=settings, geometry=geometry) - - space = openmc.stats.Box(*cell.bounding_box) - model.settings.source = openmc.IndependentSource( - space=space, constraints={'fissionable': True}) - model.add_kinetics_parameters_tallies(num_groups=6) - return model - - -def test_iterated_fission_probability(ifp_model): - harness = PyAPITestHarness("statepoint.20.h5", model=ifp_model) - harness.main() diff --git a/tests/regression_tests/ifp/total/__init__.py b/tests/regression_tests/ifp/total/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/ifp/total/inputs_true.dat b/tests/regression_tests/ifp/total/inputs_true.dat deleted file mode 100644 index 2d69b29ab..000000000 --- a/tests/regression_tests/ifp/total/inputs_true.dat +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 20 - 5 - - - -10.0 -10.0 -10.0 10.0 10.0 10.0 - - - true - - - 5 - - - - ifp-time-numerator ifp-beta-numerator ifp-denominator - - - diff --git a/tests/regression_tests/ifp/total/results_true.dat b/tests/regression_tests/ifp/total/results_true.dat deleted file mode 100644 index 466ca1f01..000000000 --- a/tests/regression_tests/ifp/total/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -k-combined: -1.006559E+00 5.389391E-03 -tally 1: -9.109384E-08 -5.667165E-16 -5.200000E-02 -5.420000E-04 -1.489000E+01 -1.480036E+01 diff --git a/tests/regression_tests/ifp/total/test.py b/tests/regression_tests/ifp/total/test.py deleted file mode 100644 index 18b89cfc0..000000000 --- a/tests/regression_tests/ifp/total/test.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Test the Iterated Fission Probability (IFP) method to compute adjoint-weighted -kinetics parameters using dedicated tallies.""" - -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - -@pytest.fixture() -def ifp_model(): - model = openmc.Model() - - # Material - material = openmc.Material(name="core") - material.add_nuclide("U235", 1.0) - material.set_density('g/cm3', 16.0) - - # Geometry - radius = 10.0 - sphere = openmc.Sphere(r=radius, boundary_type="vacuum") - cell = openmc.Cell(region=-sphere, fill=material) - model.geometry = openmc.Geometry([cell]) - - # Settings - model.settings.particles = 1000 - model.settings.batches = 20 - model.settings.inactive = 5 - model.settings.ifp_n_generation = 5 - - space = openmc.stats.Box(*cell.bounding_box) - model.settings.source = openmc.IndependentSource( - space=space, constraints={'fissionable': True}) - - # Tally IFP scores - tally = openmc.Tally(name="ifp-scores") - tally.scores = ["ifp-time-numerator", "ifp-beta-numerator", "ifp-denominator"] - model.tallies = [tally] - - return model - - -def test_iterated_fission_probability(ifp_model): - harness = PyAPITestHarness("statepoint.20.h5", model=ifp_model) - harness.main() diff --git a/tests/regression_tests/infinite_cell/geometry.xml b/tests/regression_tests/infinite_cell/geometry.xml new file mode 100644 index 000000000..90bd2233b --- /dev/null +++ b/tests/regression_tests/infinite_cell/geometry.xml @@ -0,0 +1,17 @@ + + + + + + + + 11 12 + 12 11 + + + + + + + diff --git a/tests/regression_tests/source_mcpl_file/materials.xml b/tests/regression_tests/infinite_cell/materials.xml similarity index 58% rename from tests/regression_tests/source_mcpl_file/materials.xml rename to tests/regression_tests/infinite_cell/materials.xml index 2472a7471..6acd8df74 100644 --- a/tests/regression_tests/source_mcpl_file/materials.xml +++ b/tests/regression_tests/infinite_cell/materials.xml @@ -6,4 +6,9 @@ + + + + + diff --git a/tests/regression_tests/infinite_cell/model.xml b/tests/regression_tests/infinite_cell/model.xml deleted file mode 100644 index 0f741a86d..000000000 --- a/tests/regression_tests/infinite_cell/model.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - 2.0 2.0 - 12 - 2 2 - -2.0 -2.0 - -11 12 -12 11 - - - - - eigenvalue - 1000 - 10 - 5 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - diff --git a/tests/regression_tests/infinite_cell/results_true.dat b/tests/regression_tests/infinite_cell/results_true.dat index 4cdbcaf88..b73c733ae 100644 --- a/tests/regression_tests/infinite_cell/results_true.dat +++ b/tests/regression_tests/infinite_cell/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.603664E-02 1.050772E-03 +9.537627E-02 2.349145E-03 diff --git a/tests/regression_tests/source_mcpl_file/settings.xml b/tests/regression_tests/infinite_cell/settings.xml similarity index 77% rename from tests/regression_tests/source_mcpl_file/settings.xml rename to tests/regression_tests/infinite_cell/settings.xml index bb08e6fd7..70b4e802f 100644 --- a/tests/regression_tests/source_mcpl_file/settings.xml +++ b/tests/regression_tests/infinite_cell/settings.xml @@ -1,14 +1,15 @@ + eigenvalue - - 10 5 1000 + -4 -4 -4 4 4 4 + diff --git a/tests/regression_tests/iso_in_lab/inputs_true.dat b/tests/regression_tests/iso_in_lab/inputs_true.dat index adfcf7e51..2a302ada6 100644 --- a/tests/regression_tests/iso_in_lab/inputs_true.dat +++ b/tests/regression_tests/iso_in_lab/inputs_true.dat @@ -1,199 +1,38 @@ - - - - - - - - - - U234 U235 U238 Xe135 O16 - - - - - - - - - Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - H1 O16 B10 B11 - - - - - - - - - H1 O16 B10 B11 - - - - - - - - - - - - - - Fe54 Fe56 Fe57 Fe58 Ni58 Ni60 Mn55 Cr52 C0 Cu63 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - - - - - - H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -211,12 +50,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -234,12 +73,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -261,12 +100,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -288,34 +127,195 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -160 -160 -183 160 160 183 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + U234 U235 U238 Xe135 O16 + + + + + + + + + Zr90 Zr91 Zr92 Zr94 Zr96 + + + + + + + + + H1 O16 B10 B11 + + + + + + + + + H1 O16 B10 B11 + + + + + + + + + + + + + + Fe54 Fe56 Fe57 Fe58 Ni58 Ni60 Mn55 Cr52 C0 Cu63 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 + + + + + + + + + + + + + + H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 + + + + + eigenvalue + 100 + 10 + 5 + + + -160 -160 -183 160 160 183 + + + diff --git a/tests/regression_tests/iso_in_lab/results_true.dat b/tests/regression_tests/iso_in_lab/results_true.dat index 0378ec86d..ce9cf316f 100644 --- a/tests/regression_tests/iso_in_lab/results_true.dat +++ b/tests/regression_tests/iso_in_lab/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.365837E-01 5.366122E-02 +9.050918E-01 3.355799E-02 diff --git a/tests/regression_tests/lattice/results_true.dat b/tests/regression_tests/lattice/results_true.dat index dca84bd6a..ff0ff626f 100644 --- a/tests/regression_tests/lattice/results_true.dat +++ b/tests/regression_tests/lattice/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.182679E-01 5.270201E-02 +1.068493E+00 1.318070E-01 diff --git a/tests/regression_tests/lattice_corner_crossing/__init__.py b/tests/regression_tests/lattice_corner_crossing/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/lattice_corner_crossing/inputs_true.dat b/tests/regression_tests/lattice_corner_crossing/inputs_true.dat deleted file mode 100644 index 4b49b1403..000000000 --- a/tests/regression_tests/lattice_corner_crossing/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - 10.0 10.0 - 2 2 - -10.0 -10.0 - -1 2 -2 1 - - - - - - - - - fixed source - 1000 - 10 - - - -0.7071067811865476 -0.7071067811865475 0.0 - - - - - - - 10 10 - -20.0 -20.0 - 20.0 20.0 - - - 1 - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/lattice_corner_crossing/results_true.dat b/tests/regression_tests/lattice_corner_crossing/results_true.dat deleted file mode 100644 index bd81cf535..000000000 --- a/tests/regression_tests/lattice_corner_crossing/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.648775E-03 -7.016009E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.981847E-03 -8.891414E-06 -3.331677E-03 -1.110007E-05 -6.742237E-03 -4.545776E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.388206E-03 -1.925636E-05 -2.032104E-03 -4.129446E-06 -3.014946E-03 -9.089898E-06 -7.058968E-03 -4.982903E-05 -9.013188E-04 -8.123755E-07 -7.501461E-04 -5.627191E-07 -0.000000E+00 -0.000000E+00 -5.134898E-03 -2.636718E-05 -1.207302E-03 -1.457579E-06 -3.045925E-03 -9.277657E-06 -4.132399E-03 -1.707672E-05 -1.055271E-02 -5.829711E-05 -4.014909E-03 -1.611949E-05 -2.698215E-03 -7.280363E-06 -1.751215E-02 -1.073504E-04 -1.356908E-02 -9.589157E-05 -5.451466E-03 -2.971848E-05 -3.165676E-04 -1.002151E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.724938E-03 -1.387516E-05 -2.812863E-03 -7.278837E-06 -1.000700E+01 -1.001402E+01 -2.345904E-02 -2.127641E-04 -2.451653E-02 -1.750725E-04 -8.695904E-03 -5.553981E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.947565E-03 -2.447840E-05 -1.725721E-02 -8.878803E-05 -5.656444E+01 -3.199538E+02 -2.159961E-02 -1.034364E-04 -3.091063E-02 -5.543317E-04 -4.232209E-03 -1.791159E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.716170E-03 -2.224226E-05 -1.321855E-02 -5.288265E-05 -5.309576E-02 -7.984865E-04 -5.656179E+01 -3.199238E+02 -2.399311E-02 -2.936670E-04 -4.680753E-02 -9.526509E-04 -1.074699E-02 -1.154978E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.526425E-03 -2.048853E-05 -3.983003E-03 -9.553596E-06 -1.726789E-02 -9.579848E-05 -3.355605E-02 -3.331438E-04 -3.578422E-02 -3.560242E-04 -5.649209E+01 -3.191358E+02 -2.591495E-02 -4.169753E-04 -9.484744E-03 -8.065715E-05 -0.000000E+00 -0.000000E+00 -4.232587E-03 -9.113263E-06 -5.787378E-03 -2.194940E-05 -6.193626E-03 -2.357423E-05 -4.552787E-03 -6.987360E-06 -9.641308E-03 -3.506339E-05 -1.303892E-02 -4.378408E-05 -1.831744E-02 -8.836683E-05 -3.024725E+01 -9.148969E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.488204E-03 -2.214752E-06 -5.067487E-03 -1.520987E-05 -7.550927E-03 -2.993991E-05 -3.215559E-03 -1.033982E-05 -4.258525E-03 -1.205064E-05 -2.115487E-03 -4.475286E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/lattice_corner_crossing/test.py b/tests/regression_tests/lattice_corner_crossing/test.py deleted file mode 100644 index 4684d144e..000000000 --- a/tests/regression_tests/lattice_corner_crossing/test.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -This test is designed to ensure that we account for potential corner crossings -in floating point precision. - -""" - -from math import pi, cos, sin - -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - model = openmc.Model() - - # Length of lattice on each side - lat_size = 20.0 - - # Angle that we're crossing the corner at - phi = pi/4.0 - - air = openmc.Material() - air.set_density('g/cm3', 0.001) - air.add_nuclide('N14', 1.0) - metal = openmc.Material() - metal.set_density('g/cm3', 7.0) - metal.add_nuclide('Fe56', 1.0) - - metal_cell = openmc.Cell(fill=metal) - metal_uni = openmc.Universe(cells=[metal_cell]) - - air_cell = openmc.Cell(fill=air) - air_uni = openmc.Universe(cells=[air_cell]) - - # Define a checkerboard lattice - lattice = openmc.RectLattice() - lattice.lower_left = (-lat_size/2.0, -lat_size/2.0) - lattice.pitch = (lat_size/2, lat_size/2) - lattice.universes = [ - [metal_uni, air_uni], - [air_uni, metal_uni] - ] - - box = openmc.model.RectangularPrism(lat_size, lat_size) - cyl = openmc.ZCylinder(r=lat_size, boundary_type='vacuum') - outside_lattice = openmc.Cell(region=-cyl & +box, fill=air) - inside_lattice = openmc.Cell(region=-box, fill=lattice) - - model.geometry = openmc.Geometry([outside_lattice, inside_lattice]) - - # Set all runtime parameters - model.settings.run_mode = 'fixed source' - model.settings.batches = 10 - model.settings.particles = 1000 - - # Define a source located outside the lattice and pointing straight into its - # corner at 45 degrees - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point((-cos(phi), -sin(phi), 0.0)), - angle=openmc.stats.Monodirectional((cos(phi), sin(phi), 0.0)) - ) - - # Create a mesh tally - mesh = openmc.RegularMesh() - mesh.dimension = (10, 10) - mesh.lower_left = (-lat_size, -lat_size) - mesh.upper_right = (lat_size, lat_size) - mesh_filter = openmc.MeshFilter(mesh) - tally = openmc.Tally(tally_id=1) - tally.filters = [mesh_filter] - tally.scores = ['flux'] - tally.estimator = 'tracklength' - model.tallies = [tally] - - return model - - -def test_lattice_corner_crossing(model): - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/lattice_distribmat/False/inputs_true.dat b/tests/regression_tests/lattice_distribmat/False/inputs_true.dat deleted file mode 100644 index 783989057..000000000 --- a/tests/regression_tests/lattice_distribmat/False/inputs_true.dat +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 1.0 1.0 - 1 - 1 1 - -1.0 -1.0 - -1 - - - 1.0 1.0 - 1 - 1 1 - -1.0 0 - -1 - - - 1.0 1.0 - 1 - 1 1 - 0 -1.0 - -1 - - - 1.0 1.0 - 1 - 1 1 - 0 0 - -1 - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - diff --git a/tests/regression_tests/lattice_distribmat/False/results_true.dat b/tests/regression_tests/lattice_distribmat/False/results_true.dat deleted file mode 100644 index 9ebbb43b8..000000000 --- a/tests/regression_tests/lattice_distribmat/False/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.848895E+00 1.480242E-02 diff --git a/tests/regression_tests/lattice_distribmat/True/inputs_true.dat b/tests/regression_tests/lattice_distribmat/True/inputs_true.dat deleted file mode 100644 index ab827dfde..000000000 --- a/tests/regression_tests/lattice_distribmat/True/inputs_true.dat +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 2 3 4 - - - 5 6 7 8 - - - - - - - - 1.0 1.0 - 8 - 1 1 - -1.0 -1.0 - -8 - - - 1.0 1.0 - 8 - 1 1 - -1.0 0 - -8 - - - 1.0 1.0 - 8 - 1 1 - 0 -1.0 - -8 - - - 1.0 1.0 - 8 - 1 1 - 0 0 - -8 - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - diff --git a/tests/regression_tests/lattice_distribmat/True/results_true.dat b/tests/regression_tests/lattice_distribmat/True/results_true.dat deleted file mode 100644 index 9ebbb43b8..000000000 --- a/tests/regression_tests/lattice_distribmat/True/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.848895E+00 1.480242E-02 diff --git a/tests/regression_tests/lattice_distribmat/__init__.py b/tests/regression_tests/lattice_distribmat/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/lattice_distribmat/test.py b/tests/regression_tests/lattice_distribmat/test.py deleted file mode 100644 index 4d0b6e156..000000000 --- a/tests/regression_tests/lattice_distribmat/test.py +++ /dev/null @@ -1,83 +0,0 @@ -import numpy as np -import openmc -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - model = openmc.model.Model() - - uo2 = openmc.Material(name='UO2') - uo2.set_density('g/cm3', 10.0) - uo2.add_nuclide('U235', 1.0) - uo2.add_nuclide('O16', 2.0) - water = openmc.Material(name='light water') - water.add_nuclide('H1', 2.0) - water.add_nuclide('O16', 1.0) - water.set_density('g/cm3', 1.0) - water.add_s_alpha_beta('c_H_in_H2O') - model.materials.extend([uo2, water]) - - cyl = openmc.ZCylinder(r=0.4) - pin = openmc.model.pin([cyl], [uo2, water]) - d = 1.0 - - lattice00 = openmc.RectLattice() - lattice00.lower_left = (-d, -d) - lattice00.pitch = (d, d) - lattice00.outer = pin - lattice00.universes = [[pin]] - box00 = openmc.model.RectangularPrism(d, d, origin=(-d/2,-d/2)) - - lattice01 = openmc.RectLattice() - lattice01.lower_left = (-d, 0) - lattice01.pitch = (d, d) - lattice01.outer = pin - lattice01.universes = [[pin]] - box01 = openmc.model.RectangularPrism(d, d, origin=(-d/2,d/2)) - - lattice10 = openmc.RectLattice() - lattice10.lower_left = (0, -d) - lattice10.pitch = (d, d) - lattice10.outer = pin - lattice10.universes = [[pin]] - box10 = openmc.model.RectangularPrism(d, d, origin=(d/2,-d/2)) - - lattice11 = openmc.RectLattice() - lattice11.lower_left = (0, 0) - lattice11.pitch = (d, d) - lattice11.outer = pin - lattice11.universes = [[pin]] - box11 = openmc.model.RectangularPrism(d, d, origin=(d/2,d/2)) - - - cell00 = openmc.Cell(fill=lattice00, region = -box00) - cell01 = openmc.Cell(fill=lattice01, region = -box01) - cell10 = openmc.Cell(fill=lattice10, region = -box10) - cell11 = openmc.Cell(fill=lattice11, region = -box11) - - univ = openmc.Universe(cells=[cell00, cell01, cell10, cell11]) - - box = openmc.model.RectangularPrism(2*d, 2*d, boundary_type='reflective') - - main_cell = openmc.Cell(fill=univ, region=-box) - model.geometry = openmc.Geometry([main_cell]) - model.geometry.merge_surfaces = True - - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 1000 - - return model - -@pytest.mark.parametrize("distribmat", [False, True]) -def test_lattice(model, distribmat): - with change_directory(str(distribmat)): - openmc.reset_auto_ids() - if distribmat: - model.differentiate_mats(depletable_only=False) - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/lattice_distribrho/__init__.py b/tests/regression_tests/lattice_distribrho/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/lattice_distribrho/inputs_true.dat b/tests/regression_tests/lattice_distribrho/inputs_true.dat deleted file mode 100644 index 99994af3d..000000000 --- a/tests/regression_tests/lattice_distribrho/inputs_true.dat +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - 10.0 20.0 10.0 20.0 - - - - - 1.0 1.0 - 2 2 - -1.0 -1.0 - -1 1 -1 1 - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - diff --git a/tests/regression_tests/lattice_distribrho/results_true.dat b/tests/regression_tests/lattice_distribrho/results_true.dat deleted file mode 100644 index f7f3da8e6..000000000 --- a/tests/regression_tests/lattice_distribrho/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.900249E+00 8.157834E-03 diff --git a/tests/regression_tests/lattice_distribrho/test.py b/tests/regression_tests/lattice_distribrho/test.py deleted file mode 100644 index ec94fe96b..000000000 --- a/tests/regression_tests/lattice_distribrho/test.py +++ /dev/null @@ -1,51 +0,0 @@ -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - model = openmc.Model() - - uo2 = openmc.Material(name='UO2') - uo2.set_density('g/cm3', 10.0) - uo2.add_nuclide('U235', 1.0) - uo2.add_nuclide('O16', 2.0) - water = openmc.Material(name='light water') - water.add_nuclide('H1', 2.0) - water.add_nuclide('O16', 1.0) - water.set_density('g/cm3', 1.0) - water.add_s_alpha_beta('c_H_in_H2O') - model.materials.extend([uo2, water]) - - cyl = openmc.ZCylinder(r=0.4) - pin = openmc.model.pin([cyl], [uo2, water]) - d = 1.0 - - lattice = openmc.RectLattice() - lattice.lower_left = (-d, -d) - lattice.pitch = (d, d) - lattice.universes = [[pin, pin], - [pin, pin]] - box = openmc.model.RectangularPrism( - 2.0 * d, 2.0 * d, - origin=(0.0, 0.0), - boundary_type='reflective' - ) - - pin.cells[1].density = [10.0, 20.0, 10.0, 20.0] - - model.geometry = openmc.Geometry([openmc.Cell(fill=lattice, region=-box)]) - model.geometry.merge_surfaces = True - - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 1000 - - return model - - -def test_lattice_checkerboard(model): - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/lattice_hex/results_true.dat b/tests/regression_tests/lattice_hex/results_true.dat index 46db641eb..3d53292ab 100644 --- a/tests/regression_tests/lattice_hex/results_true.dat +++ b/tests/regression_tests/lattice_hex/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.595598E-01 9.089294E-03 +2.522694E-01 1.422929E-02 diff --git a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat index fafc03da1..0388a4f55 100644 --- a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat @@ -1,81 +1,81 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.4 - 3 -
0.0 0.0
- - 2 -2 2 - 1 -2 2 - 2 -
- - - - - - - - - - - - -
- - eigenvalue - 1000 - 5 - 2 - - - -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 - - - - false - - 22 - -
+ + + + + + + + + + + 1.4 + 11 +
0.0 0.0
+ + 10 +10 10 + 9 +10 10 + 10 +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 2 + + + -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 + + + + false + + 22 + diff --git a/tests/regression_tests/lattice_hex_coincident/results_true.dat b/tests/regression_tests/lattice_hex_coincident/results_true.dat index c798b66e4..94115e6ee 100644 --- a/tests/regression_tests/lattice_hex_coincident/results_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.931086E+00 5.968486E-02 +1.901983E+00 1.772999E-02 diff --git a/tests/regression_tests/lattice_hex_coincident/test.py b/tests/regression_tests/lattice_hex_coincident/test.py index f971098c0..30bc470f2 100644 --- a/tests/regression_tests/lattice_hex_coincident/test.py +++ b/tests/regression_tests/lattice_hex_coincident/test.py @@ -6,8 +6,7 @@ from tests.testing_harness import PyAPITestHarness class HexLatticeCoincidentTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): materials = openmc.Materials() fuel_mat = openmc.Material() @@ -41,7 +40,7 @@ class HexLatticeCoincidentTestHarness(PyAPITestHarness): zirc.add_nuclide('Zr96', 1.131E-03, 'ao') materials.append(zirc) - self._model.materials = materials + materials.export_to_xml() ### Geometry ### pin_rad = 0.7 # cm @@ -104,10 +103,10 @@ class HexLatticeCoincidentTestHarness(PyAPITestHarness): inf_mat_univ = openmc.Universe(cells=[inf_mat,]) # a hex surface for the core to go inside of - hexprism = openmc.model.HexagonalPrism(edge_length=edge_length, - origin=(0.0, 0.0), - boundary_type = 'reflective', - orientation='x') + hexprism = openmc.model.hexagonal_prism(edge_length=edge_length, + origin=(0.0, 0.0), + boundary_type = 'reflective', + orientation='x') pincell_only_lattice = openmc.HexLattice(name="regular fuel assembly") pincell_only_lattice.center = (0., 0.) @@ -120,19 +119,20 @@ class HexLatticeCoincidentTestHarness(PyAPITestHarness): pincell_only_lattice.universes = [ring1, ring0] pincell_only_cell = openmc.Cell(name="container cell") - pincell_only_cell.region = -hexprism & +fuel_btm & -fuel_top + pincell_only_cell.region = hexprism & +fuel_btm & -fuel_top pincell_only_cell.fill = pincell_only_lattice root_univ = openmc.Universe(name="root universe", cells=[pincell_only_cell,]) - self._model.geometry = openmc.Geometry(root_univ) + geom = openmc.Geometry(root_univ) + geom.export_to_xml() ### Settings ### settings = openmc.Settings() settings.run_mode = 'eigenvalue' - source = openmc.IndependentSource() + source = openmc.Source() corner_dist = sqrt(2) * pin_rad ll = [-corner_dist, -corner_dist, 0.0] ur = [corner_dist, corner_dist, 10.0] @@ -144,9 +144,8 @@ class HexLatticeCoincidentTestHarness(PyAPITestHarness): settings.inactive = 2 settings.particles = 1000 settings.seed = 22 - self._model.settings = settings + settings.export_to_xml() def test_lattice_hex_coincident_surf(): - harness = HexLatticeCoincidentTestHarness('statepoint.5.h5', - model=openmc.Model()) + harness = HexLatticeCoincidentTestHarness('statepoint.5.h5') harness.main() diff --git a/tests/regression_tests/lattice_hex_x/inputs_true.dat b/tests/regression_tests/lattice_hex_x/inputs_true.dat index b6536c6a8..b528a97b7 100644 --- a/tests/regression_tests/lattice_hex_x/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_x/inputs_true.dat @@ -1,53 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.235 5.0 - 4 -
0.0 0.0 5.0
- + + + + + + + + + + + + + + + + 1.235 5.0 + 4 +
0.0 0.0 5.0
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 @@ -90,34 +60,64 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -
- - - - - - - - - - - - - - - - -
- - eigenvalue - 1000 - 10 - 5 - - - -13.62546635287517 -13.62546635287517 0.0 13.62546635287517 13.62546635287517 10.0 - - - 22 - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -13.62546635287517 -13.62546635287517 0.0 13.62546635287517 13.62546635287517 10.0 + + + 22 + diff --git a/tests/regression_tests/lattice_hex_x/results_true.dat b/tests/regression_tests/lattice_hex_x/results_true.dat index 44f947283..b1177911e 100644 --- a/tests/regression_tests/lattice_hex_x/results_true.dat +++ b/tests/regression_tests/lattice_hex_x/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.326294E+00 1.193578E-02 +1.345955E+00 3.225468E-02 diff --git a/tests/regression_tests/lattice_hex_x/test.py b/tests/regression_tests/lattice_hex_x/test.py index dd5c53d0c..ecb27c9c2 100644 --- a/tests/regression_tests/lattice_hex_x/test.py +++ b/tests/regression_tests/lattice_hex_x/test.py @@ -4,8 +4,8 @@ import numpy as np class HexLatticeOXTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + + def _build_inputs(self): materials = openmc.Materials() fuel_mat = openmc.Material(material_id=1, name="UO2") @@ -35,7 +35,7 @@ class HexLatticeOXTestHarness(PyAPITestHarness): zirc.add_element('Zr', 4.23e-2) materials.append(zirc) - self._model.materials = materials + materials.export_to_xml() # Geometry # @@ -139,11 +139,11 @@ class HexLatticeOXTestHarness(PyAPITestHarness): # a hex surface for the core to go inside of - hexprism = openmc.model.HexagonalPrism(edge_length=edge_length, - origin=(0.0, 0.0), - boundary_type='reflective', - orientation='x') - region = -hexprism & +fuel_bottom & -fuel_top + hexprism = openmc.model.hexagonal_prism(edge_length=edge_length, + origin=(0.0, 0.0), + boundary_type='reflective', + orientation='x') + region = hexprism & +fuel_bottom & -fuel_top inf_mat = openmc.Cell(cell_id=12) inf_mat.fill = coolant @@ -165,7 +165,7 @@ class HexLatticeOXTestHarness(PyAPITestHarness): (4, 21), (5, 20), (4, 27), (5, 25), (4, 33)] for i, j in channels: universes[i][j] = abs_ch_univ - lattice = openmc.HexLattice(lattice_id=6, name="regular fuel assembly") + lattice = openmc.HexLattice(name="regular fuel assembly") lattice.orientation = "x" lattice.center = (0., 0., length/2.0) lattice.pitch = (assembly_pitch, length/2.0) @@ -180,14 +180,15 @@ class HexLatticeOXTestHarness(PyAPITestHarness): root_univ = openmc.Universe(universe_id=5, name="root universe", cells=[assembly_cell]) - self._model.geometry = openmc.Geometry(root_univ) + geom = openmc.Geometry(root_univ) + geom.export_to_xml() # Settings # settings = openmc.Settings() settings.run_mode = 'eigenvalue' - source = openmc.IndependentSource() + source = openmc.Source() ll = [-edge_length, -edge_length, 0.0] ur = [edge_length, edge_length, 10.0] source.space = openmc.stats.Box(ll, ur) @@ -197,9 +198,9 @@ class HexLatticeOXTestHarness(PyAPITestHarness): settings.inactive = 5 settings.particles = 1000 settings.seed = 22 - self._model.settings = settings + settings.export_to_xml() def test_lattice_hex_ox_surf(): - harness = HexLatticeOXTestHarness('statepoint.10.h5', model=openmc.Model()) + harness = HexLatticeOXTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/lattice_large_pitch/__init__.py b/tests/regression_tests/lattice_large_pitch/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/lattice_large_pitch/inputs_true.dat b/tests/regression_tests/lattice_large_pitch/inputs_true.dat deleted file mode 100644 index 4dd4f0bd7..000000000 --- a/tests/regression_tests/lattice_large_pitch/inputs_true.dat +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - 100.0 100.0 - 2 - 3 3 - -150.0 -150.0 - -1 2 1 -2 1 2 -1 2 1 - - - - - - - - fixed source - 1000 - 10 - - - - 6 6 - -150.0 -150.0 - 150.0 150.0 - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/lattice_large_pitch/results_true.dat b/tests/regression_tests/lattice_large_pitch/results_true.dat deleted file mode 100644 index 58c4e306d..000000000 --- a/tests/regression_tests/lattice_large_pitch/results_true.dat +++ /dev/null @@ -1,73 +0,0 @@ -tally 1: -1.749265E+01 -3.275925E+01 -4.159430E+01 -1.799568E+02 -7.027454E+01 -4.967568E+02 -6.789716E+01 -4.652258E+02 -4.272935E+01 -1.861129E+02 -2.073342E+01 -4.374279E+01 -4.028297E+01 -1.641642E+02 -6.734263E+01 -4.627171E+02 -1.037657E+02 -1.078682E+03 -1.108394E+02 -1.240927E+03 -7.236770E+01 -5.302034E+02 -4.356361E+01 -1.921990E+02 -6.731536E+01 -4.615977E+02 -9.850684E+01 -9.810272E+02 -5.164863E+02 -2.670336E+04 -5.097770E+02 -2.604770E+04 -1.064847E+02 -1.137536E+03 -7.052986E+01 -5.003220E+02 -7.065046E+01 -5.036723E+02 -1.044890E+02 -1.103250E+03 -5.121544E+02 -2.632389E+04 -5.065331E+02 -2.570752E+04 -1.044794E+02 -1.101249E+03 -6.569142E+01 -4.361120E+02 -4.739812E+01 -2.313289E+02 -7.402284E+01 -5.591689E+02 -1.066905E+02 -1.149521E+03 -1.038665E+02 -1.086813E+03 -7.160008E+01 -5.217744E+02 -4.219705E+01 -1.816100E+02 -2.089838E+01 -4.464899E+01 -4.154271E+01 -1.745866E+02 -7.081253E+01 -5.049997E+02 -6.673273E+01 -4.509038E+02 -4.184624E+01 -1.771546E+02 -1.853898E+01 -3.538608E+01 diff --git a/tests/regression_tests/lattice_large_pitch/test.py b/tests/regression_tests/lattice_large_pitch/test.py deleted file mode 100644 index 0f409badd..000000000 --- a/tests/regression_tests/lattice_large_pitch/test.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Regression test for rectangular lattices with large pitch values. - -Large pitches used to trigger a segmentation fault in ``RectLattice::distance`` -because the boundary-crossing check compared a reconstructed crossing position -against an absolute tolerance that did not scale with the geometry (see #3852). -This test transports particles across a lattice with a large pitch to ensure the -crossing logic remains robust. - -""" - -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - model = openmc.Model() - - # Large pitch that previously caused floating-point cancellation - pitch = 100.0 - n = 3 - - air = openmc.Material() - air.set_density('g/cm3', 0.001) - air.add_nuclide('N14', 1.0) - metal = openmc.Material() - metal.set_density('g/cm3', 7.0) - metal.add_nuclide('Fe56', 1.0) - - metal_cell = openmc.Cell(fill=metal) - metal_uni = openmc.Universe(cells=[metal_cell]) - air_cell = openmc.Cell(fill=air) - air_uni = openmc.Universe(cells=[air_cell]) - - lattice = openmc.RectLattice() - lattice.lower_left = (-pitch*n/2, -pitch*n/2) - lattice.pitch = (pitch, pitch) - lattice.outer = air_uni - lattice.universes = [ - [metal_uni, air_uni, metal_uni], - [air_uni, metal_uni, air_uni], - [metal_uni, air_uni, metal_uni], - ] - - box = openmc.model.RectangularPrism(pitch*n, pitch*n, boundary_type='vacuum') - root_cell = openmc.Cell(region=-box, fill=lattice) - model.geometry = openmc.Geometry([root_cell]) - - model.settings.run_mode = 'fixed source' - model.settings.batches = 10 - model.settings.particles = 1000 - - mesh = openmc.RegularMesh() - mesh.dimension = (6, 6) - mesh.lower_left = (-pitch*n/2, -pitch*n/2) - mesh.upper_right = (pitch*n/2, pitch*n/2) - mesh_filter = openmc.MeshFilter(mesh) - tally = openmc.Tally(tally_id=1) - tally.filters = [mesh_filter] - tally.scores = ['flux'] - model.tallies = [tally] - - return model - - -def test_lattice_large_pitch(model): - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/lattice_multiple/inputs_true.dat b/tests/regression_tests/lattice_multiple/inputs_true.dat index 06abef582..c92e841bc 100644 --- a/tests/regression_tests/lattice_multiple/inputs_true.dat +++ b/tests/regression_tests/lattice_multiple/inputs_true.dat @@ -1,53 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - - - 1.2 1.2 - 1 - 2 2 - -1.2 -1.2 - + + + + + + + + + 1.2 1.2 + 1 + 2 2 + -1.2 -1.2 + 2 1 1 1 - - - 2.4 2.4 - 2 2 - -2.4 -2.4 - + + + 2.4 2.4 + 2 2 + -2.4 -2.4 + 4 4 4 4 - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + diff --git a/tests/regression_tests/lattice_multiple/results_true.dat b/tests/regression_tests/lattice_multiple/results_true.dat index 0866932d2..88b911e78 100644 --- a/tests/regression_tests/lattice_multiple/results_true.dat +++ b/tests/regression_tests/lattice_multiple/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.843982E+00 5.815875E-03 +1.859909E+00 1.768384E-02 diff --git a/tests/regression_tests/lattice_multiple/test.py b/tests/regression_tests/lattice_multiple/test.py index 10d9e50bc..c287c0102 100644 --- a/tests/regression_tests/lattice_multiple/test.py +++ b/tests/regression_tests/lattice_multiple/test.py @@ -42,8 +42,8 @@ def model(): lattice.pitch = (2*d, 2*d) lattice.universes = np.full((2, 2), inner_univ) - box = openmc.model.RectangularPrism(4*d, 4*d, boundary_type='reflective') - main_cell = openmc.Cell(fill=lattice, region=-box) + box = openmc.model.rectangular_prism(4*d, 4*d, boundary_type='reflective') + main_cell = openmc.Cell(fill=lattice, region=box) model.geometry = openmc.Geometry([main_cell]) model.settings.batches = 10 diff --git a/tests/regression_tests/lattice_rotated/inputs_true.dat b/tests/regression_tests/lattice_rotated/inputs_true.dat index e53b93f93..8ee34b4f3 100644 --- a/tests/regression_tests/lattice_rotated/inputs_true.dat +++ b/tests/regression_tests/lattice_rotated/inputs_true.dat @@ -1,35 +1,18 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.25 - 30 -
0.0 0.0
- + + + + + + + + + + + 1.25 + 30 +
0.0 0.0
+ 2 1 1 1 2 1 @@ -39,33 +22,50 @@ 1 1 1 1 1 1 -
- - 1.25 1.25 - 30 - 4 4 - -2.5 -2.5 - +
+ + 1.25 1.25 + 30 + 4 4 + -2.5 -2.5 + 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - -
- - eigenvalue - 1000 - 5 - 0 - - - 0.0 0.0 0.0 - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + 0.0 0.0 0.0 + + + diff --git a/tests/regression_tests/lattice_rotated/results_true.dat b/tests/regression_tests/lattice_rotated/results_true.dat index 9a96a9259..d02656a3f 100644 --- a/tests/regression_tests/lattice_rotated/results_true.dat +++ b/tests/regression_tests/lattice_rotated/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.515246E-01 2.358354E-02 +4.674233E-01 1.599236E-02 diff --git a/tests/regression_tests/lattice_rotated/test.py b/tests/regression_tests/lattice_rotated/test.py index 63641fb84..9cab92e1e 100644 --- a/tests/regression_tests/lattice_rotated/test.py +++ b/tests/regression_tests/lattice_rotated/test.py @@ -73,7 +73,7 @@ def rotated_lattice_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + model.settings.source = openmc.Source(space=openmc.stats.Point()) model.settings.export_to_xml() return model diff --git a/tests/regression_tests/mg_basic/inputs_true.dat b/tests/regression_tests/mg_basic/inputs_true.dat index aa2c2fa0a..4f2fd3f0b 100644 --- a/tests/regression_tests/mg_basic/inputs_true.dat +++ b/tests/regression_tests/mg_basic/inputs_true.dat @@ -1,64 +1,64 @@ - - - 2g.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 - - - - false - - multi-group - - false - - - + + + + + + + + + + + + + + + + + + 2g.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_basic/results_true.dat b/tests/regression_tests/mg_basic/results_true.dat index 16980732d..15a9f2186 100644 --- a/tests/regression_tests/mg_basic/results_true.dat +++ b/tests/regression_tests/mg_basic/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.004679E+00 1.329350E-02 +1.009864E+00 1.107115E-02 diff --git a/tests/regression_tests/mg_basic_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat index cc3f2cfb2..9fb7afe7e 100644 --- a/tests/regression_tests/mg_basic_delayed/inputs_true.dat +++ b/tests/regression_tests/mg_basic_delayed/inputs_true.dat @@ -1,63 +1,63 @@ - - - 2g.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 - - - - false - - multi-group - - false - - - + + + + + + + + + + + + + + + + + + 2g.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_basic_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat index f150030b9..6f7c79c1b 100644 --- a/tests/regression_tests/mg_basic_delayed/results_true.dat +++ b/tests/regression_tests/mg_basic_delayed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.017078E+00 1.181139E-02 +1.024610E+00 9.643746E-03 diff --git a/tests/regression_tests/mg_convert/inputs_true.dat b/tests/regression_tests/mg_convert/inputs_true.dat index 3b1f511e6..753c0d304 100644 --- a/tests/regression_tests/mg_convert/inputs_true.dat +++ b/tests/regression_tests/mg_convert/inputs_true.dat @@ -1,29 +1,29 @@ - - - mgxs.h5 - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -5 -5 -5 5 5 5 - - - multi-group - - + + + + + + + + + + mgxs.h5 + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -5 -5 -5 5 5 5 + + + multi-group + diff --git a/tests/regression_tests/mg_convert/results_true.dat b/tests/regression_tests/mg_convert/results_true.dat index f8f748cc7..ff3d7bb91 100644 --- a/tests/regression_tests/mg_convert/results_true.dat +++ b/tests/regression_tests/mg_convert/results_true.dat @@ -1,24 +1,24 @@ k-combined: -9.926427E-01 3.067527E-03 +9.984888E-01 1.558301E-03 k-combined: -9.932868E-01 2.780271E-03 +1.001035E+00 7.622447E-04 k-combined: -9.926427E-01 3.067527E-03 +9.984888E-01 1.558301E-03 k-combined: -1.000000E+00 0.000000E+00 +9.991101E-01 2.776191E-03 k-combined: -9.902969E-01 1.654717E-02 +9.965954E-01 5.185046E-03 k-combined: -9.882796E-01 1.929843E-03 +9.987613E-01 4.806845E-04 k-combined: -1.000000E+00 0.000000E+00 +9.991101E-01 2.776191E-03 k-combined: -9.902953E-01 1.654291E-02 +9.965954E-01 5.185315E-03 k-combined: -9.882814E-01 1.927488E-03 +9.987610E-01 4.791528E-04 k-combined: -9.893153E-01 7.576652E-03 +9.944808E-01 4.458524E-03 k-combined: -9.926427E-01 3.067527E-03 +9.984888E-01 1.558301E-03 k-combined: -9.926427E-01 3.067527E-03 +9.984888E-01 1.558301E-03 diff --git a/tests/regression_tests/mg_convert/test.py b/tests/regression_tests/mg_convert/test.py index 0e50f3a74..c6ab485ea 100755 --- a/tests/regression_tests/mg_convert/test.py +++ b/tests/regression_tests/mg_convert/test.py @@ -1,4 +1,3 @@ -from math import isnan import os import hashlib @@ -62,8 +61,7 @@ def build_mgxs_library(convert): class MGXSTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): # Instantiate some Macroscopic Data uo2_data = openmc.Macroscopic('UO2') @@ -75,7 +73,7 @@ class MGXSTestHarness(PyAPITestHarness): # Instantiate a Materials collection and export to XML materials_file = openmc.Materials([mat]) materials_file.cross_sections = "./mgxs.h5" - self._model.materials = materials_file + materials_file.export_to_xml() # Instantiate ZCylinder surfaces left = openmc.XPlane(surface_id=4, x0=-5., name='left') @@ -104,7 +102,8 @@ class MGXSTestHarness(PyAPITestHarness): root.add_cells([fuel]) # Instantiate a Geometry, register the root Universe, and export to XML - self._model.geometry = openmc.Geometry(root) + geometry = openmc.Geometry(root) + geometry.export_to_xml() settings_file = openmc.Settings() settings_file.energy_mode = "multi-group" @@ -115,9 +114,9 @@ class MGXSTestHarness(PyAPITestHarness): # Create an initial uniform spatial source distribution bounds = [-5, -5, -5, 5, 5, 5] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.IndependentSource(space=uniform_dist) + settings_file.source = openmc.source.Source(space=uniform_dist) - self._model.settings = settings_file + settings_file.export_to_xml() def _run_openmc(self): # Run multiple conversions to compare results @@ -143,13 +142,10 @@ class MGXSTestHarness(PyAPITestHarness): openmc.run(openmc_exec=config['exe']) with openmc.StatePoint('statepoint.{}.h5'.format(batches)) as sp: - # Sometimes NaN results are produced; convert these to 0.0 - std_dev = 0.0 if isnan(sp.keff.s) else sp.keff.s - # Write out k-combined. outstr += 'k-combined:\n' form = '{:12.6E} {:12.6E}\n' - outstr += form.format(sp.keff.n, std_dev) + outstr += form.format(sp.keff.n, sp.keff.s) return outstr @@ -198,5 +194,5 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_convert(): - harness = MGXSTestHarness('statepoint.10.h5', model=openmc.Model()) + harness = MGXSTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/__init__.py b/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/inputs_true.dat b/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/inputs_true.dat deleted file mode 100644 index 318fdc7b9..000000000 --- a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/inputs_true.dat +++ /dev/null @@ -1,65 +0,0 @@ - - - - 2g.h5 - - - - - - - - - - - - fixed source - 100 - 2 - 0 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - - false - - true - - 1 - neutron - 0.0 0.625 20000000.0 - 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 - 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 - 3.0 - 10 - 1e-38 - - - 5 1 1 - 0.0 -1000.0 -1000.0 - 929.45 1000.0 1000.0 - - true - 100 - - - - 5 1 1 - 0.0 -1000.0 -1000.0 - 929.45 1000.0 1000.0 - - - 2 - - - 1 - flux - - - diff --git a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/results_true.dat b/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/results_true.dat deleted file mode 100644 index 38ff94417..000000000 --- a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/results_true.dat +++ /dev/null @@ -1,11 +0,0 @@ -tally 1: -1.765369E+04 -3.087787E+08 -1.708316E+04 -2.842002E+08 -9.444106E+03 -7.488341E+07 -2.066528E+03 -2.142445E+06 -8.689619E+02 -5.652099E+05 diff --git a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/test.py b/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/test.py deleted file mode 100644 index 336c8461f..000000000 --- a/tests/regression_tests/mg_fixed_source_ww_fission_shared_secondary/test.py +++ /dev/null @@ -1,91 +0,0 @@ -import os - -import numpy as np -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups([0.0, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_fixed_source_ww_fission_shared_secondary(): - create_library() - model = slab_mg() - - # Override settings for fixed-source mode with shared secondary bank - model.settings.run_mode = 'fixed source' - model.settings.inactive = 0 - model.settings.batches = 2 - model.settings.particles = 100 - model.settings.create_fission_neutrons = True - model.settings.shared_secondary_bank = True - model.settings.max_history_splits = 100 - - # Add weight windows on a simple 1D mesh - ww_mesh = openmc.RegularMesh() - ww_mesh.lower_left = (0.0, -1000.0, -1000.0) - ww_mesh.upper_right = (929.45, 1000.0, 1000.0) - ww_mesh.dimension = (5, 1, 1) - - # Uniform lower bounds for 2 energy groups, 5 spatial bins - lower_bounds = np.full((2, 5, 1, 1), 0.5) - ww = openmc.WeightWindows( - ww_mesh, - lower_bounds.flatten(), - None, - 5.0, - [0.0, 0.625, 20.0e6], - 'neutron' - ) - model.settings.weight_windows = [ww] - - # Add a flux tally - mesh = openmc.RegularMesh() - mesh.lower_left = (0.0, -1000.0, -1000.0) - mesh.upper_right = (929.45, 1000.0, 1000.0) - mesh.dimension = (5, 1, 1) - - tally = openmc.Tally() - tally.filters = [openmc.MeshFilter(mesh)] - tally.scores = ['flux'] - model.tallies = [tally] - - harness = MGXSTestHarness('statepoint.2.h5', model) - harness.main() diff --git a/tests/regression_tests/mg_legendre/inputs_true.dat b/tests/regression_tests/mg_legendre/inputs_true.dat index 81362f20a..ad3b434e6 100644 --- a/tests/regression_tests/mg_legendre/inputs_true.dat +++ b/tests/regression_tests/mg_legendre/inputs_true.dat @@ -1,33 +1,33 @@ - - - 2g.h5 - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - - false - - - + + + + + + + + 2g.h5 + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_legendre/results_true.dat b/tests/regression_tests/mg_legendre/results_true.dat index 04d9c9874..e2989469c 100644 --- a/tests/regression_tests/mg_legendre/results_true.dat +++ b/tests/regression_tests/mg_legendre/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.009220E+00 9.571832E-03 +1.003646E+00 9.134747E-03 diff --git a/tests/regression_tests/mg_max_order/inputs_true.dat b/tests/regression_tests/mg_max_order/inputs_true.dat index c8f42d1a3..2ac83852c 100644 --- a/tests/regression_tests/mg_max_order/inputs_true.dat +++ b/tests/regression_tests/mg_max_order/inputs_true.dat @@ -1,34 +1,34 @@ - - - 2g.h5 - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - 1 - - false - - - + + + + + + + + 2g.h5 + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + 1 + + false + + diff --git a/tests/regression_tests/mg_max_order/results_true.dat b/tests/regression_tests/mg_max_order/results_true.dat index 04d9c9874..e2989469c 100644 --- a/tests/regression_tests/mg_max_order/results_true.dat +++ b/tests/regression_tests/mg_max_order/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.009220E+00 9.571832E-03 +1.003646E+00 9.134747E-03 diff --git a/tests/regression_tests/mg_survival_biasing/inputs_true.dat b/tests/regression_tests/mg_survival_biasing/inputs_true.dat index bee69729d..5ece3ce9f 100644 --- a/tests/regression_tests/mg_survival_biasing/inputs_true.dat +++ b/tests/regression_tests/mg_survival_biasing/inputs_true.dat @@ -1,34 +1,34 @@ - - - 2g.h5 - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - true - - false - - - + + + + + + + + 2g.h5 + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + true + + false + + diff --git a/tests/regression_tests/mg_survival_biasing/results_true.dat b/tests/regression_tests/mg_survival_biasing/results_true.dat index 4b26978ad..cddbdaceb 100644 --- a/tests/regression_tests/mg_survival_biasing/results_true.dat +++ b/tests/regression_tests/mg_survival_biasing/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.889968E-01 9.144186E-03 +9.878738E-01 8.326224E-03 diff --git a/tests/regression_tests/mg_tallies/inputs_true.dat b/tests/regression_tests/mg_tallies/inputs_true.dat index f4f154244..562958722 100644 --- a/tests/regression_tests/mg_tallies/inputs_true.dat +++ b/tests/regression_tests/mg_tallies/inputs_true.dat @@ -1,164 +1,165 @@ - - - 2g.h5 - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - - false - - - - - 10 1 1 - 0.0 0.0 0.0 - 929.45 1000 1000 - - - 1 - - - 1 - - - 0.0 20000000.0 - - - 0.0 20000000.0 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 5 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - analog - - - 5 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - tracklength - - - 6 1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter - analog - - - 6 1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - collision - - - 6 1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - tracklength - - - 6 1 2 - scatter nu-scatter nu-fission - - - 6 3 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter - analog - - - 6 3 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - collision - - - 6 3 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - tracklength - - - 6 3 4 - scatter nu-scatter nu-fission - - - 5 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - analog - - - 5 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - tracklength - - - 6 1 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter - analog - - - 6 1 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - collision - - - 6 1 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - tracklength - - - 6 1 2 - mat_1 - scatter nu-scatter nu-fission - - - 6 3 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter - analog - - - 6 3 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - collision - - - 6 3 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - tracklength - - - 6 3 4 - mat_1 - scatter nu-scatter nu-fission - - - + + + + + + + + 2g.h5 + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + + false + + + + + + 10 1 1 + 0.0 0.0 0.0 + 929.45 1000 1000 + + + 1 + + + 1 + + + 0.0 20000000.0 + + + 0.0 20000000.0 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 5 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + analog + + + 5 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + tracklength + + + 6 1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter + analog + + + 6 1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + collision + + + 6 1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + tracklength + + + 6 1 2 + scatter nu-scatter nu-fission + + + 6 3 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter + analog + + + 6 3 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + collision + + + 6 3 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + tracklength + + + 6 3 4 + scatter nu-scatter nu-fission + + + 5 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + analog + + + 5 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + tracklength + + + 6 1 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter + analog + + + 6 1 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + collision + + + 6 1 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + tracklength + + + 6 1 2 + mat_1 + scatter nu-scatter nu-fission + + + 6 3 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter + analog + + + 6 3 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + collision + + + 6 3 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + tracklength + + + 6 3 4 + mat_1 + scatter nu-scatter nu-fission + + diff --git a/tests/regression_tests/mg_tallies/results_true.dat b/tests/regression_tests/mg_tallies/results_true.dat index c1591cca2..7484dd248 100644 --- a/tests/regression_tests/mg_tallies/results_true.dat +++ b/tests/regression_tests/mg_tallies/results_true.dat @@ -1,1324 +1,1324 @@ k-combined: -1.012390E+00 9.679132E-03 +1.003646E+00 9.134747E-03 tally 1: -1.342000E+00 -4.291640E-01 -7.000000E-02 -1.158000E-03 -2.919844E-02 -1.953371E-04 -5.372246E-02 -6.734832E-04 -2.939310E-07 -2.375686E-14 -5.372246E-02 -6.734832E-04 +5.220000E-01 +5.995400E-02 +1.400000E-02 +4.000000E-05 +6.718865E-03 +9.371695E-06 +1.106435E-02 +3.119729E-05 +1.216992E-07 +3.699412E-15 +1.106435E-02 +3.119729E-05 0.000000E+00 0.000000E+00 -5.839688E+06 -7.813485E+12 -1.342000E+00 -4.291640E-01 +1.343773E+06 +3.748678E+11 +5.220000E-01 +5.995400E-02 0.000000E+00 0.000000E+00 -3.915206E+00 -3.646810E+00 -2.701000E+00 -1.486587E+00 -1.340000E-01 -3.598000E-03 -5.583136E-02 -6.266530E-04 -1.267275E-01 -3.349463E-03 -7.209619E-07 -1.153253E-13 -1.267275E-01 -3.349463E-03 +1.520872E+00 +5.121226E-01 +2.564000E+00 +1.338762E+00 +1.160000E-01 +2.738000E-03 +4.593685E-02 +4.275719E-04 +1.360763E-01 +3.951569E-03 +8.079937E-07 +1.577355E-13 +1.350645E-01 +3.872739E-03 +1.011813E-03 +1.023765E-06 +9.187371E+06 +1.710288E+13 +2.564000E+00 +1.338762E+00 +8.595248E-04 +7.387829E-07 +7.412367E+00 +1.121746E+01 +2.184000E+00 +9.895940E-01 +1.080000E-01 +2.394000E-03 +4.782785E-02 +4.787428E-04 +1.140806E-01 +2.886440E-03 +6.242229E-07 +9.307161E-14 +1.130687E-01 +2.811706E-03 +1.011813E-03 +1.023765E-06 +9.565570E+06 +1.914971E+13 +2.184000E+00 +9.895940E-01 +3.312574E-05 +1.097314E-09 +6.331465E+00 +8.328826E+00 +5.970000E-01 +8.325100E-02 +3.500000E-02 +3.150000E-04 +1.514871E-02 +5.131352E-05 +3.795718E-02 +3.631435E-04 +2.299730E-07 +1.295603E-14 +3.795718E-02 +3.631435E-04 0.000000E+00 0.000000E+00 -1.116627E+07 -2.506612E+13 -2.701000E+00 -1.486587E+00 +3.029741E+06 +2.052541E+12 +5.970000E-01 +8.325100E-02 0.000000E+00 0.000000E+00 -7.844332E+00 -1.252301E+01 -2.791000E+00 -1.658877E+00 -1.240000E-01 -3.282000E-03 -5.173865E-02 -5.560435E-04 -1.292971E-01 -3.436301E-03 -6.920456E-07 -9.917496E-14 -1.263311E-01 -3.290664E-03 -2.965960E-03 -4.837204E-06 -1.034773E+07 -2.224174E+13 -2.791000E+00 -1.658877E+00 -7.133747E-04 -3.640977E-07 -8.120311E+00 -1.408288E+01 -3.169000E+00 -2.031747E+00 -1.620000E-01 -5.364000E-03 -6.707115E-02 -9.171975E-04 -1.648345E-01 -5.547084E-03 -1.008876E-06 -2.201766E-13 -1.638199E-01 -5.463700E-03 -1.014608E-03 -1.029429E-06 -1.341423E+07 -3.668790E+13 -3.169000E+00 -2.031747E+00 -8.618993E-04 -7.428703E-07 -9.158565E+00 -1.699756E+01 -3.660000E+00 -2.796494E+00 -1.580000E-01 -5.158000E-03 -6.719242E-02 -9.422093E-04 -1.591500E-01 -5.615224E-03 -8.020080E-07 -1.480166E-13 -1.581743E-01 -5.540021E-03 -9.756761E-04 -9.519438E-07 -1.343848E+07 -3.768837E+13 -3.660000E+00 -2.796494E+00 -2.954152E-04 -8.727014E-08 -1.067773E+01 -2.376726E+01 -2.527000E+00 -1.452369E+00 -1.140000E-01 -2.834000E-03 -4.984389E-02 -5.325247E-04 -1.111356E-01 -2.793586E-03 -7.289084E-07 -1.302125E-13 -1.111356E-01 -2.793586E-03 +1.714353E+00 +6.970480E-01 +1.852000E+00 +7.973360E-01 +7.900000E-02 +1.689000E-03 +2.755187E-02 +2.091740E-04 +5.453423E-02 +7.484037E-04 +2.368001E-07 +1.753710E-14 +5.453423E-02 +7.484037E-04 0.000000E+00 0.000000E+00 -9.968777E+06 -2.130099E+13 -2.527000E+00 -1.452369E+00 +5.510374E+06 +8.366961E+12 +1.852000E+00 +7.973360E-01 0.000000E+00 0.000000E+00 -7.323996E+00 -1.221424E+01 -3.204000E+00 -2.092834E+00 -1.500000E-01 -4.600000E-03 -6.029165E-02 -7.387235E-04 -1.410668E-01 -4.414885E-03 -8.384625E-07 -1.602532E-13 -1.400911E-01 -4.332066E-03 -9.756761E-04 -9.519438E-07 -1.205833E+07 -2.954894E+13 -3.204000E+00 -2.092834E+00 -3.194266E-05 -1.020333E-09 -9.309783E+00 -1.769870E+01 -3.463000E+00 -2.477679E+00 -1.670000E-01 -5.837000E-03 -6.829328E-02 -9.882225E-04 -1.758063E-01 -6.470636E-03 -9.887100E-07 -2.199856E-13 -1.737856E-01 -6.307226E-03 -2.020620E-03 -2.041459E-06 -1.365866E+07 -3.952890E+13 -3.463000E+00 -2.477679E+00 -4.276023E-04 -1.081885E-07 -1.003961E+01 -2.083120E+01 -2.970000E-01 -4.491300E-02 -1.500000E-02 -9.100000E-05 -4.215863E-03 -6.275840E-06 -6.040786E-03 -1.401662E-05 -2.142282E-08 -4.361920E-16 -6.040786E-03 -1.401662E-05 +5.449659E+00 +6.908544E+00 +4.177000E+00 +3.780409E+00 +1.760000E-01 +6.584000E-03 +7.049310E-02 +1.047700E-03 +2.082153E-01 +9.154274E-03 +1.090026E-06 +2.590031E-13 +2.082153E-01 +9.154274E-03 0.000000E+00 0.000000E+00 -8.431726E+05 -2.510336E+11 -2.970000E-01 -4.491300E-02 +1.409862E+07 +4.190799E+13 +4.177000E+00 +3.780409E+00 0.000000E+00 0.000000E+00 -8.785109E-01 -3.967096E-01 -1.250000E-01 -5.357000E-03 -2.000000E-03 -2.000000E-06 -4.888503E-04 -1.194873E-07 -2.028292E-03 -2.059943E-06 -8.582314E-09 -7.099216E-17 -2.028292E-03 -2.059943E-06 +1.213785E+01 +3.197979E+01 +2.287000E+00 +1.059809E+00 +1.040000E-01 +2.254000E-03 +4.025632E-02 +3.309459E-04 +9.479325E-02 +1.956154E-03 +4.705869E-07 +4.509695E-14 +9.479325E-02 +1.956154E-03 0.000000E+00 0.000000E+00 -9.777007E+04 -4.779493E+09 -1.250000E-01 -5.357000E-03 +8.051265E+06 +1.323783E+13 +2.287000E+00 +1.059809E+00 0.000000E+00 0.000000E+00 -3.698633E-01 -4.679347E-02 +6.680550E+00 +9.051488E+00 +6.398000E+00 +8.323220E+00 +2.580000E-01 +1.356600E-02 +1.070205E-01 +2.345401E-03 +2.825180E-01 +1.658268E-02 +1.510574E-06 +5.135513E-13 +2.805357E-01 +1.633928E-02 +1.982273E-03 +1.965559E-06 +2.140411E+07 +9.381603E+13 +6.398000E+00 +8.323220E+00 +6.001927E-04 +1.801940E-07 +1.863566E+01 +7.066273E+01 +1.167000E+00 +4.778410E-01 +5.100000E-02 +9.290000E-04 +1.851002E-02 +1.273765E-04 +3.405873E-02 +6.277248E-04 +1.688115E-07 +1.480555E-14 +3.195431E-02 +5.302962E-04 +2.104418E-03 +4.428574E-06 +3.702005E+06 +5.095061E+12 +1.167000E+00 +4.778410E-01 +3.530361E-04 +1.246345E-07 +3.428588E+00 +4.115657E+00 +3.630000E+00 +2.765806E+00 +1.490000E-01 +4.587000E-03 +5.894825E-02 +7.367371E-04 +1.434581E-01 +4.305327E-03 +7.603618E-07 +1.250071E-13 +1.414758E-01 +4.212618E-03 +1.982273E-03 +1.965559E-06 +1.178965E+07 +2.946948E+13 +3.630000E+00 +2.765806E+00 +4.160428E-04 +1.012741E-07 +1.059988E+01 +2.359174E+01 tally 2: -1.353006E+00 -4.298474E-01 -6.067126E-02 -9.182923E-04 -2.407597E-02 -1.589874E-04 -6.018994E-02 -9.936715E-04 -3.157310E-07 -3.268202E-14 -5.980833E-02 -9.811116E-04 -3.816044E-04 -3.994127E-08 -4.815195E+06 -6.359497E+12 -1.340228E+00 -4.256704E-01 -1.788012E-04 -8.768717E-09 -3.941968E+00 -3.631126E+00 -2.806910E+00 -1.600166E+00 -1.295488E-01 -3.449533E-03 -5.323702E-02 -5.945274E-04 -1.330925E-01 -3.715796E-03 -7.358638E-07 -1.182977E-13 -1.322487E-01 -3.668829E-03 -8.438073E-04 -1.493588E-07 -1.064740E+07 -2.378109E+13 -2.698926E+00 -1.484990E+00 -3.953669E-04 -3.279028E-08 -8.155605E+00 -1.349706E+01 -2.869647E+00 -1.739405E+00 -1.278179E-01 -3.407189E-03 -5.029332E-02 -5.252401E-04 -1.257333E-01 -3.282751E-03 -6.507109E-07 -8.979533E-14 -1.249362E-01 -3.241257E-03 -7.971497E-04 -1.319523E-07 -1.005866E+07 -2.100960E+13 -2.795871E+00 -1.662994E+00 -3.735055E-04 -2.896884E-08 -8.365907E+00 -1.480669E+01 -3.141043E+00 -1.981851E+00 -1.526263E-01 -4.699686E-03 -6.641498E-02 -9.211853E-04 -1.660374E-01 -5.757408E-03 -9.915981E-07 -2.229928E-13 -1.649848E-01 -5.684636E-03 -1.052678E-03 -2.314228E-07 -1.328300E+07 -3.684741E+13 -3.162533E+00 -2.024101E+00 -4.932336E-04 -5.080661E-08 -9.080077E+00 -1.658064E+01 -3.682383E+00 -2.808072E+00 -1.593265E-01 -5.346789E-03 -6.034523E-02 -7.901305E-04 -1.508631E-01 -4.938316E-03 -7.319663E-07 -1.246559E-13 -1.499066E-01 -4.875896E-03 -9.564725E-04 -1.984988E-07 -1.206905E+07 -3.160522E+13 -3.670108E+00 -2.815133E+00 -4.481564E-04 -4.357848E-08 -1.076370E+01 -2.396100E+01 -2.634850E+00 -1.584334E+00 -1.218122E-01 -3.391010E-03 -5.015643E-02 -5.871038E-04 -1.253911E-01 -3.669399E-03 -6.952485E-07 -1.202338E-13 -1.245961E-01 -3.623018E-03 -7.949798E-04 -1.474939E-07 -1.003129E+07 -2.348415E+13 -2.523640E+00 -1.451617E+00 -3.724888E-04 -3.238084E-08 -7.654439E+00 -1.338000E+01 -3.192584E+00 -2.071165E+00 -1.491327E-01 -4.485370E-03 -6.214556E-02 -7.933462E-04 -1.553639E-01 -4.958414E-03 -8.761442E-07 -1.691919E-13 -1.543789E-01 -4.895740E-03 -9.850078E-04 -1.993067E-07 -1.242911E+07 -3.173385E+13 -3.198836E+00 -2.085466E+00 -4.615266E-04 -4.375584E-08 -9.265396E+00 -1.747782E+01 -3.402213E+00 -2.415762E+00 -1.592235E-01 -5.219460E-03 -6.649290E-02 -9.066793E-04 -1.662323E-01 -5.666746E-03 -9.402303E-07 -1.840541E-13 -1.651783E-01 -5.595119E-03 -1.053913E-03 -2.277785E-07 -1.329858E+07 -3.626717E+13 -3.467276E+00 -2.484377E+00 -4.938123E-04 -5.000655E-08 -9.871966E+00 -2.037665E+01 -3.110378E-01 -5.227746E-02 -1.171121E-02 -6.542918E-05 -3.536640E-03 -5.149982E-06 -8.841599E-03 -3.218739E-05 -2.347065E-08 -5.243075E-16 -8.785544E-03 -3.178055E-05 -5.605578E-05 -1.293793E-09 -7.073280E+05 -2.059993E+11 -2.978788E-01 -4.498561E-02 -2.626500E-05 -2.840396E-10 -9.197485E-01 -4.619575E-01 -1.267544E-01 -5.491246E-03 -4.806410E-03 -8.161899E-06 -1.471497E-03 -8.779657E-07 -3.678743E-03 -5.487286E-06 -1.030812E-08 -1.028225E-16 -3.655420E-03 -5.417928E-06 -2.332325E-05 -2.205650E-10 -2.942995E+05 -3.511863E+10 -1.270281E-01 -5.517180E-03 -1.092814E-05 -4.842290E-11 -3.746117E-01 -4.790053E-02 +5.033991E-01 +5.701830E-02 +2.304219E-02 +1.162005E-04 +9.376617E-03 +1.933443E-05 +2.344154E-02 +1.208402E-04 +1.277674E-07 +3.888071E-15 +2.329292E-02 +1.193128E-04 +1.486195E-04 +4.857250E-09 +1.875323E+06 +7.733771E+11 +5.220000E-01 +5.995400E-02 +6.963583E-05 +1.066362E-09 +1.463809E+00 +4.840945E-01 +2.621546E+00 +1.396717E+00 +1.276380E-01 +3.311549E-03 +5.565805E-02 +6.598224E-04 +1.391451E-01 +4.123890E-03 +8.331879E-07 +1.660597E-13 +1.382629E-01 +4.071765E-03 +8.821806E-04 +1.657624E-07 +1.113161E+07 +2.639289E+13 +2.581000E+00 +1.357455E+00 +4.133468E-04 +3.639153E-08 +7.576783E+00 +1.169599E+01 +2.230626E+00 +1.033217E+00 +1.065165E-01 +2.416670E-03 +4.549248E-02 +4.740035E-04 +1.137312E-01 +2.962522E-03 +6.630810E-07 +1.170893E-13 +1.130101E-01 +2.925076E-03 +7.210562E-04 +1.190805E-07 +9.098495E+06 +1.896014E+13 +2.202000E+00 +1.007194E+00 +3.378518E-04 +2.614296E-08 +6.459596E+00 +8.662758E+00 +5.565395E-01 +7.242839E-02 +2.955239E-02 +1.840142E-04 +1.400990E-02 +4.103227E-05 +3.502476E-02 +2.564517E-04 +2.308081E-07 +1.205491E-14 +3.480270E-02 +2.532102E-04 +2.220571E-04 +1.030824E-08 +2.801981E+06 +1.641291E+12 +6.090000E-01 +8.636300E-02 +1.040451E-04 +2.263074E-09 +1.593637E+00 +6.040566E-01 +1.817267E+00 +7.710225E-01 +7.367627E-02 +1.267666E-03 +2.535616E-02 +1.551036E-04 +6.339039E-02 +9.693976E-04 +2.524798E-07 +1.896478E-14 +6.298850E-02 +9.571446E-04 +4.018954E-04 +3.896557E-08 +5.071232E+06 +6.204145E+12 +1.881000E+00 +8.206930E-01 +1.883086E-04 +8.554511E-09 +5.341905E+00 +6.666854E+00 +4.106914E+00 +3.704316E+00 +1.888617E-01 +7.777635E-03 +7.727973E-02 +1.309080E-03 +1.931993E-01 +8.181751E-03 +1.061590E-06 +2.554724E-13 +1.919744E-01 +8.078335E-03 +1.224884E-03 +3.288708E-07 +1.545595E+07 +5.236321E+13 +4.223000E+00 +3.850821E+00 +5.739211E-04 +7.220038E-08 +1.193698E+01 +3.133321E+01 +2.346339E+00 +1.119793E+00 +1.017476E-01 +2.080323E-03 +3.865443E-02 +3.024337E-04 +9.663608E-02 +1.890211E-03 +4.714003E-07 +4.853805E-14 +9.602340E-02 +1.866319E-03 +6.126731E-04 +7.597824E-08 +7.730886E+06 +1.209735E+13 +2.338000E+00 +1.106368E+00 +2.870687E-04 +1.668028E-08 +6.857029E+00 +9.581045E+00 +6.446883E+00 +8.447751E+00 +2.867793E-01 +1.670093E-02 +1.126541E-01 +2.611201E-03 +2.816352E-01 +1.632001E-02 +1.453669E-06 +4.585416E-13 +2.798496E-01 +1.611372E-02 +1.785568E-03 +6.559933E-07 +2.253081E+07 +1.044480E+14 +6.454000E+00 +8.471478E+00 +8.366302E-04 +1.440169E-07 +1.879692E+01 +7.185693E+01 +1.219419E+00 +5.127750E-01 +4.857020E-02 +8.389250E-04 +1.623897E-02 +1.008738E-04 +4.059741E-02 +6.304611E-04 +1.503579E-07 +1.146797E-14 +4.034003E-02 +6.224921E-04 +2.573878E-04 +2.534179E-08 +3.247793E+06 +4.034951E+12 +1.199000E+00 +4.975810E-01 +1.205994E-04 +5.563543E-09 +3.589772E+00 +4.434695E+00 +3.623361E+00 +2.780040E+00 +1.560708E-01 +5.162316E-03 +5.875078E-02 +7.419979E-04 +1.468770E-01 +4.637487E-03 +7.048177E-07 +1.136014E-13 +1.459458E-01 +4.578870E-03 +9.312005E-04 +1.864068E-07 +1.175016E+07 +2.967992E+13 +3.668000E+00 +2.824270E+00 +4.363151E-04 +4.092380E-08 +1.059543E+01 +2.377944E+01 tally 3: -1.098420E+02 -2.414277E+03 -4.993000E+00 -4.986021E+00 -2.023763E+00 -8.192234E-01 -5.037812E+00 -5.086734E+00 -2.745346E-05 -1.509092E-10 -5.002505E+00 -5.014944E+00 -3.530702E-02 -2.695026E-04 -4.047525E+08 -3.276894E+16 -1.098420E+02 -2.414277E+03 -1.059695E-02 -2.782849E-05 -3.195213E+02 -2.042961E+04 -1.048490E+02 -2.199887E+03 -1.048490E+02 -2.199887E+03 +1.092010E+02 +2.386227E+03 +4.975000E+00 +4.950147E+00 +2.009472E+00 +8.076733E-01 +5.000649E+00 +5.012321E+00 +2.728992E-05 +1.491241E-10 +4.964474E+00 +4.939215E+00 +3.617555E-02 +2.875519E-04 +4.018944E+08 +3.230693E+16 +1.092010E+02 +2.386227E+03 +1.333979E-02 +5.019969E-05 +3.176576E+02 +2.019260E+04 +1.042260E+02 +2.173864E+03 +1.042260E+02 +2.173864E+03 tally 4: -1.098420E+02 -2.414277E+03 -5.008447E+00 -5.018748E+00 -2.028674E+00 -8.234818E-01 -5.071684E+00 -5.146761E+00 -5.050718E-05 -5.107669E-10 -5.039530E+00 -5.081707E+00 -3.215450E-02 -2.068774E-04 -4.057347E+08 -3.293927E+16 -1.098420E+02 -2.414277E+03 -1.506603E-02 -4.541792E-05 -3.195213E+02 -2.042961E+04 +1.092010E+02 +2.386227E+03 +4.979068E+00 +4.959690E+00 +2.016700E+00 +8.137138E-01 +5.041749E+00 +5.085712E+00 +5.020635E-05 +5.047241E-10 +5.009785E+00 +5.021429E+00 +3.196471E-02 +2.044235E-04 +4.033399E+08 +3.254855E+16 +1.092010E+02 +2.386227E+03 +1.497710E-02 +4.487918E-05 +3.176576E+02 +2.019260E+04 tally 5: -1.103689E+02 -2.437562E+03 -5.035611E+00 -5.073005E+00 -2.041209E+00 -8.337913E-01 -5.103022E+00 -5.211196E+00 -2.765405E-05 -1.532759E-10 -5.070669E+00 -5.145327E+00 -3.235318E-02 -2.094674E-04 -4.082417E+08 -3.335165E+16 -1.098580E+02 -2.414983E+03 -1.515912E-02 -4.598653E-05 -3.210351E+02 -2.062463E+04 +1.097121E+02 +2.408636E+03 +5.009145E+00 +5.019563E+00 +2.032191E+00 +8.264420E-01 +5.080477E+00 +5.165263E+00 +2.756641E-05 +1.523527E-10 +5.048267E+00 +5.099975E+00 +3.221025E-02 +2.076211E-04 +4.064382E+08 +3.305768E+16 +1.093810E+02 +2.394075E+03 +1.509215E-02 +4.558119E-05 +3.191033E+02 +2.037736E+04 tally 6: -1.048490E+02 -2.199887E+03 -1.048490E+02 -2.199887E+03 -5.037812E+00 -5.086734E+00 +1.042260E+02 +2.173864E+03 +1.042260E+02 +2.173864E+03 +5.000649E+00 +5.012321E+00 tally 7: -6.546000E+00 -8.579894E+00 -1.462000E+00 -4.278220E-01 -1.160697E+00 -2.696537E-01 -2.879845E+00 -1.663297E+00 -2.723379E-05 -1.485067E-10 -2.862628E+00 -1.643479E+00 -1.721726E-02 -6.055382E-05 -2.321395E+08 -1.078615E+16 -6.546000E+00 -8.579894E+00 -6.709978E-03 -1.387848E-05 -1.198287E+01 -2.875089E+01 -5.084000E+00 -5.178800E+00 -5.084000E+00 -5.178800E+00 -1.032960E+02 -2.135240E+03 +6.507000E+00 +8.478423E+00 +1.444000E+00 +4.172780E-01 +1.146407E+00 +2.630079E-01 +2.867025E+00 +1.647980E+00 +2.707153E-05 +1.467503E-10 +2.848880E+00 +1.627146E+00 +1.814469E-02 +6.685238E-05 +2.292814E+08 +1.052031E+16 +6.507000E+00 +8.478423E+00 +9.467712E-03 +2.396878E-05 +1.191147E+01 +2.841087E+01 +5.063000E+00 +5.136983E+00 +5.063000E+00 +5.136983E+00 +1.026940E+02 +2.110535E+03 3.531000E+00 -2.493943E+00 +2.493861E+00 8.630652E-01 -1.489973E-01 -2.157967E+00 -9.345420E-01 -2.196703E-07 -9.656558E-15 -2.139877E+00 -9.185178E-01 -1.808977E-02 -8.744581E-05 +1.489924E-01 +2.133624E+00 +9.150435E-01 +2.183901E-07 +9.544829E-15 +2.115593E+00 +8.991467E-01 +1.803087E-02 +8.677353E-05 1.726130E+08 -5.959891E+15 -1.032960E+02 -2.135240E+03 -3.886968E-03 -5.976458E-06 -3.075384E+02 -1.892685E+04 -9.976500E+01 -1.991860E+03 -9.976500E+01 -1.991860E+03 +5.959695E+15 +1.026940E+02 +2.110535E+03 +3.872081E-03 +5.919692E-06 +3.057461E+02 +1.870786E+04 +9.916300E+01 +1.968002E+03 +9.916300E+01 +1.968002E+03 tally 8: -6.546000E+00 -8.579894E+00 -1.464067E+00 -4.291919E-01 -1.162338E+00 -2.705171E-01 -2.905845E+00 -1.690732E+00 -4.985316E-05 -4.976401E-10 -2.887422E+00 -1.669362E+00 -1.842307E-02 -6.796008E-05 -2.324676E+08 -1.082069E+16 -6.546000E+00 -8.579894E+00 -8.632151E-03 -1.491997E-05 -1.198287E+01 -2.875089E+01 -1.032960E+02 -2.135240E+03 -3.544380E+00 -2.513971E+00 -8.663357E-01 -1.501938E-01 -2.165839E+00 -9.387115E-01 -6.540142E-07 -8.559612E-14 -2.152108E+00 -9.268463E-01 -1.373143E-02 -3.773212E-05 -1.732671E+08 -6.007753E+15 -1.032960E+02 -2.135240E+03 -6.433878E-03 -8.283719E-06 -3.075384E+02 -1.892685E+04 +6.507000E+00 +8.478423E+00 +1.455344E+00 +4.241161E-01 +1.155413E+00 +2.673178E-01 +2.888532E+00 +1.670737E+00 +4.955615E-05 +4.917547E-10 +2.870219E+00 +1.649619E+00 +1.831331E-02 +6.715634E-05 +2.310826E+08 +1.069271E+16 +6.507000E+00 +8.478423E+00 +8.580723E-03 +1.474352E-05 +1.191147E+01 +2.841087E+01 +1.026940E+02 +2.110535E+03 +3.523724E+00 +2.484884E+00 +8.612868E-01 +1.484560E-01 +2.153217E+00 +9.278503E-01 +6.502027E-07 +8.460574E-14 +2.139566E+00 +9.161225E-01 +1.365140E-02 +3.729555E-05 +1.722574E+08 +5.938242E+15 +1.026940E+02 +2.110535E+03 +6.396382E-03 +8.187874E-06 +3.057461E+02 +1.870786E+04 tally 9: -6.593971E+00 -8.715030E+00 -1.474796E+00 -4.359519E-01 -1.170856E+00 -2.747779E-01 -2.927140E+00 -1.717362E+00 -2.743336E-05 -1.508457E-10 -2.908582E+00 -1.695655E+00 -1.855808E-02 -6.903047E-05 -2.341712E+08 -1.099112E+16 -6.547000E+00 -8.582573E+00 -8.695410E-03 -1.515497E-05 -1.207068E+01 -2.920373E+01 -1.037750E+02 -2.155274E+03 -3.560815E+00 -2.537559E+00 -8.703528E-01 -1.516031E-01 -2.175882E+00 -9.475192E-01 -2.206889E-07 -9.747163E-15 -2.162087E+00 -9.355427E-01 -1.379510E-02 -3.808615E-05 -1.740706E+08 -6.064123E+15 -1.033110E+02 -2.135863E+03 -6.463712E-03 -8.361443E-06 -3.089644E+02 -1.910444E+04 +6.573230E+00 +8.663027E+00 +1.470157E+00 +4.333505E-01 +1.167173E+00 +2.731383E-01 +2.917933E+00 +1.707114E+00 +2.734707E-05 +1.499456E-10 +2.899433E+00 +1.685536E+00 +1.849971E-02 +6.861856E-05 +2.334346E+08 +1.092553E+16 +6.518000E+00 +8.507644E+00 +8.668060E-03 +1.506454E-05 +1.203271E+01 +2.902947E+01 +1.031389E+02 +2.128993E+03 +3.538988E+00 +2.506616E+00 +8.650177E-01 +1.497544E-01 +2.162544E+00 +9.359650E-01 +2.193361E-07 +9.628305E-15 +2.148834E+00 +9.241346E-01 +1.371054E-02 +3.762172E-05 +1.730035E+08 +5.990176E+15 +1.028630E+02 +2.117467E+03 +6.424090E-03 +8.259483E-06 +3.070706E+02 +1.887148E+04 tally 10: -5.084000E+00 -5.178800E+00 -5.084000E+00 -5.178800E+00 +5.063000E+00 +5.136983E+00 +5.063000E+00 +5.136983E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.879845E+00 -1.663297E+00 -1.463000E+00 -4.284330E-01 -1.463000E+00 -4.284330E-01 +2.867025E+00 +1.647980E+00 +1.445000E+00 +4.178610E-01 +1.445000E+00 +4.178610E-01 0.000000E+00 0.000000E+00 -9.830200E+01 -1.933884E+03 -9.830200E+01 -1.933884E+03 -2.157967E+00 -9.345420E-01 +9.771800E+01 +1.911083E+03 +9.771800E+01 +1.911083E+03 +2.133624E+00 +9.150435E-01 tally 11: -1.342000E+00 -4.291640E-01 -7.000000E-02 -1.158000E-03 -2.919844E-02 -1.953371E-04 -5.372246E-02 -6.734832E-04 -2.939310E-07 -2.375686E-14 -5.372246E-02 -6.734832E-04 +5.220000E-01 +5.995400E-02 +1.400000E-02 +4.000000E-05 +6.718865E-03 +9.371695E-06 +1.106435E-02 +3.119729E-05 +1.216992E-07 +3.699412E-15 +1.106435E-02 +3.119729E-05 0.000000E+00 0.000000E+00 -5.839688E+06 -7.813485E+12 -1.342000E+00 -4.291640E-01 +1.343773E+06 +3.748678E+11 +5.220000E-01 +5.995400E-02 0.000000E+00 0.000000E+00 -2.701000E+00 -1.486587E+00 -1.340000E-01 -3.598000E-03 -5.583136E-02 -6.266530E-04 -1.267275E-01 -3.349463E-03 -7.209619E-07 -1.153253E-13 -1.267275E-01 -3.349463E-03 +2.564000E+00 +1.338762E+00 +1.160000E-01 +2.738000E-03 +4.593685E-02 +4.275719E-04 +1.360763E-01 +3.951569E-03 +8.079937E-07 +1.577355E-13 +1.350645E-01 +3.872739E-03 +1.011813E-03 +1.023765E-06 +9.187371E+06 +1.710288E+13 +2.564000E+00 +1.338762E+00 +8.595248E-04 +7.387829E-07 +2.184000E+00 +9.895940E-01 +1.080000E-01 +2.394000E-03 +4.782785E-02 +4.787428E-04 +1.140806E-01 +2.886440E-03 +6.242229E-07 +9.307161E-14 +1.130687E-01 +2.811706E-03 +1.011813E-03 +1.023765E-06 +9.565570E+06 +1.914971E+13 +2.184000E+00 +9.895940E-01 +3.312574E-05 +1.097314E-09 +5.970000E-01 +8.325100E-02 +3.500000E-02 +3.150000E-04 +1.514871E-02 +5.131352E-05 +3.795718E-02 +3.631435E-04 +2.299730E-07 +1.295603E-14 +3.795718E-02 +3.631435E-04 0.000000E+00 0.000000E+00 -1.116627E+07 -2.506612E+13 -2.701000E+00 -1.486587E+00 +3.029741E+06 +2.052541E+12 +5.970000E-01 +8.325100E-02 0.000000E+00 0.000000E+00 -2.791000E+00 -1.658877E+00 -1.240000E-01 -3.282000E-03 -5.173865E-02 -5.560435E-04 -1.292971E-01 -3.436301E-03 -6.920456E-07 -9.917496E-14 -1.263311E-01 -3.290664E-03 -2.965960E-03 -4.837204E-06 -1.034773E+07 -2.224174E+13 -2.791000E+00 -1.658877E+00 -7.133747E-04 -3.640977E-07 -3.169000E+00 -2.031747E+00 -1.620000E-01 -5.364000E-03 -6.707115E-02 -9.171975E-04 -1.648345E-01 -5.547084E-03 -1.008876E-06 -2.201766E-13 -1.638199E-01 -5.463700E-03 -1.014608E-03 -1.029429E-06 -1.341423E+07 -3.668790E+13 -3.169000E+00 -2.031747E+00 -8.618993E-04 -7.428703E-07 -3.660000E+00 -2.796494E+00 -1.580000E-01 -5.158000E-03 -6.719242E-02 -9.422093E-04 -1.591500E-01 -5.615224E-03 -8.020080E-07 -1.480166E-13 -1.581743E-01 -5.540021E-03 -9.756761E-04 -9.519438E-07 -1.343848E+07 -3.768837E+13 -3.660000E+00 -2.796494E+00 -2.954152E-04 -8.727014E-08 -2.527000E+00 -1.452369E+00 -1.140000E-01 -2.834000E-03 -4.984389E-02 -5.325247E-04 -1.111356E-01 -2.793586E-03 -7.289084E-07 -1.302125E-13 -1.111356E-01 -2.793586E-03 +1.852000E+00 +7.973360E-01 +7.900000E-02 +1.689000E-03 +2.755187E-02 +2.091740E-04 +5.453423E-02 +7.484037E-04 +2.368001E-07 +1.753710E-14 +5.453423E-02 +7.484037E-04 0.000000E+00 0.000000E+00 -9.968777E+06 -2.130099E+13 -2.527000E+00 -1.452369E+00 +5.510374E+06 +8.366961E+12 +1.852000E+00 +7.973360E-01 0.000000E+00 0.000000E+00 -3.204000E+00 -2.092834E+00 -1.500000E-01 -4.600000E-03 -6.029165E-02 -7.387235E-04 -1.410668E-01 -4.414885E-03 -8.384625E-07 -1.602532E-13 -1.400911E-01 -4.332066E-03 -9.756761E-04 -9.519438E-07 -1.205833E+07 -2.954894E+13 -3.204000E+00 -2.092834E+00 -3.194266E-05 -1.020333E-09 -3.463000E+00 -2.477679E+00 -1.670000E-01 -5.837000E-03 -6.829328E-02 -9.882225E-04 -1.758063E-01 -6.470636E-03 -9.887100E-07 -2.199856E-13 -1.737856E-01 -6.307226E-03 -2.020620E-03 -2.041459E-06 -1.365866E+07 -3.952890E+13 -3.463000E+00 -2.477679E+00 -4.276023E-04 -1.081885E-07 -2.970000E-01 -4.491300E-02 -1.500000E-02 -9.100000E-05 -4.215863E-03 -6.275840E-06 -6.040786E-03 -1.401662E-05 -2.142282E-08 -4.361920E-16 -6.040786E-03 -1.401662E-05 +4.177000E+00 +3.780409E+00 +1.760000E-01 +6.584000E-03 +7.049310E-02 +1.047700E-03 +2.082153E-01 +9.154274E-03 +1.090026E-06 +2.590031E-13 +2.082153E-01 +9.154274E-03 0.000000E+00 0.000000E+00 -8.431726E+05 -2.510336E+11 -2.970000E-01 -4.491300E-02 +1.409862E+07 +4.190799E+13 +4.177000E+00 +3.780409E+00 0.000000E+00 0.000000E+00 -1.250000E-01 -5.357000E-03 -2.000000E-03 -2.000000E-06 -4.888503E-04 -1.194873E-07 -2.028292E-03 -2.059943E-06 -8.582314E-09 -7.099216E-17 -2.028292E-03 -2.059943E-06 +2.287000E+00 +1.059809E+00 +1.040000E-01 +2.254000E-03 +4.025632E-02 +3.309459E-04 +9.479325E-02 +1.956154E-03 +4.705869E-07 +4.509695E-14 +9.479325E-02 +1.956154E-03 0.000000E+00 0.000000E+00 -9.777007E+04 -4.779493E+09 -1.250000E-01 -5.357000E-03 +8.051265E+06 +1.323783E+13 +2.287000E+00 +1.059809E+00 0.000000E+00 0.000000E+00 +6.398000E+00 +8.323220E+00 +2.580000E-01 +1.356600E-02 +1.070205E-01 +2.345401E-03 +2.825180E-01 +1.658268E-02 +1.510574E-06 +5.135513E-13 +2.805357E-01 +1.633928E-02 +1.982273E-03 +1.965559E-06 +2.140411E+07 +9.381603E+13 +6.398000E+00 +8.323220E+00 +6.001927E-04 +1.801940E-07 +1.167000E+00 +4.778410E-01 +5.100000E-02 +9.290000E-04 +1.851002E-02 +1.273765E-04 +3.405873E-02 +6.277248E-04 +1.688115E-07 +1.480555E-14 +3.195431E-02 +5.302962E-04 +2.104418E-03 +4.428574E-06 +3.702005E+06 +5.095061E+12 +1.167000E+00 +4.778410E-01 +3.530361E-04 +1.246345E-07 +3.630000E+00 +2.765806E+00 +1.490000E-01 +4.587000E-03 +5.894825E-02 +7.367371E-04 +1.434581E-01 +4.305327E-03 +7.603618E-07 +1.250071E-13 +1.414758E-01 +4.212618E-03 +1.982273E-03 +1.965559E-06 +1.178965E+07 +2.946948E+13 +3.630000E+00 +2.765806E+00 +4.160428E-04 +1.012741E-07 tally 12: -1.353006E+00 -4.298474E-01 -6.067126E-02 -9.182923E-04 -2.407597E-02 -1.589874E-04 -6.018994E-02 -9.936715E-04 -3.157310E-07 -3.268202E-14 -5.980833E-02 -9.811116E-04 -3.816044E-04 -3.994127E-08 -4.815195E+06 -6.359497E+12 -1.340228E+00 -4.256704E-01 -1.788012E-04 -8.768717E-09 -2.806910E+00 -1.600166E+00 -1.295488E-01 -3.449533E-03 -5.323702E-02 -5.945274E-04 -1.330925E-01 -3.715796E-03 -7.358638E-07 -1.182977E-13 -1.322487E-01 -3.668829E-03 -8.438073E-04 -1.493588E-07 -1.064740E+07 -2.378109E+13 -2.698926E+00 -1.484990E+00 -3.953669E-04 -3.279028E-08 -2.869647E+00 -1.739405E+00 -1.278179E-01 -3.407189E-03 -5.029332E-02 -5.252401E-04 -1.257333E-01 -3.282751E-03 -6.507109E-07 -8.979533E-14 -1.249362E-01 -3.241257E-03 -7.971497E-04 -1.319523E-07 -1.005866E+07 -2.100960E+13 -2.795871E+00 -1.662994E+00 -3.735055E-04 -2.896884E-08 -3.141043E+00 -1.981851E+00 -1.526263E-01 -4.699686E-03 -6.641498E-02 -9.211853E-04 -1.660374E-01 -5.757408E-03 -9.915981E-07 -2.229928E-13 -1.649848E-01 -5.684636E-03 -1.052678E-03 -2.314228E-07 -1.328300E+07 -3.684741E+13 -3.162533E+00 -2.024101E+00 -4.932336E-04 -5.080661E-08 -3.682383E+00 -2.808072E+00 -1.593265E-01 -5.346789E-03 -6.034523E-02 -7.901305E-04 -1.508631E-01 -4.938316E-03 -7.319663E-07 -1.246559E-13 -1.499066E-01 -4.875896E-03 -9.564725E-04 -1.984988E-07 -1.206905E+07 -3.160522E+13 -3.670108E+00 -2.815133E+00 -4.481564E-04 -4.357848E-08 -2.634850E+00 -1.584334E+00 -1.218122E-01 -3.391010E-03 -5.015643E-02 -5.871038E-04 -1.253911E-01 -3.669399E-03 -6.952485E-07 -1.202338E-13 -1.245961E-01 -3.623018E-03 -7.949798E-04 -1.474939E-07 -1.003129E+07 -2.348415E+13 -2.523640E+00 -1.451617E+00 -3.724888E-04 -3.238084E-08 -3.192584E+00 -2.071165E+00 -1.491327E-01 -4.485370E-03 -6.214556E-02 -7.933462E-04 -1.553639E-01 -4.958414E-03 -8.761442E-07 -1.691919E-13 -1.543789E-01 -4.895740E-03 -9.850078E-04 -1.993067E-07 -1.242911E+07 -3.173385E+13 -3.198836E+00 -2.085466E+00 -4.615266E-04 -4.375584E-08 -3.402213E+00 -2.415762E+00 -1.592235E-01 -5.219460E-03 -6.649290E-02 -9.066793E-04 -1.662323E-01 -5.666746E-03 -9.402303E-07 -1.840541E-13 -1.651783E-01 -5.595119E-03 -1.053913E-03 -2.277785E-07 -1.329858E+07 -3.626717E+13 -3.467276E+00 -2.484377E+00 -4.938123E-04 -5.000655E-08 -3.110378E-01 -5.227746E-02 -1.171121E-02 -6.542918E-05 -3.536640E-03 -5.149982E-06 -8.841599E-03 -3.218739E-05 -2.347065E-08 -5.243075E-16 -8.785544E-03 -3.178055E-05 -5.605578E-05 -1.293793E-09 -7.073280E+05 -2.059993E+11 -2.978788E-01 -4.498561E-02 -2.626500E-05 -2.840396E-10 -1.267544E-01 -5.491246E-03 -4.806410E-03 -8.161899E-06 -1.471497E-03 -8.779657E-07 -3.678743E-03 -5.487286E-06 -1.030812E-08 -1.028225E-16 -3.655420E-03 -5.417928E-06 -2.332325E-05 -2.205650E-10 -2.942995E+05 -3.511863E+10 -1.270281E-01 -5.517180E-03 -1.092814E-05 -4.842290E-11 +5.033991E-01 +5.701830E-02 +2.304219E-02 +1.162005E-04 +9.376617E-03 +1.933443E-05 +2.344154E-02 +1.208402E-04 +1.277674E-07 +3.888071E-15 +2.329292E-02 +1.193128E-04 +1.486195E-04 +4.857250E-09 +1.875323E+06 +7.733771E+11 +5.220000E-01 +5.995400E-02 +6.963583E-05 +1.066362E-09 +2.621546E+00 +1.396717E+00 +1.276380E-01 +3.311549E-03 +5.565805E-02 +6.598224E-04 +1.391451E-01 +4.123890E-03 +8.331879E-07 +1.660597E-13 +1.382629E-01 +4.071765E-03 +8.821806E-04 +1.657624E-07 +1.113161E+07 +2.639289E+13 +2.581000E+00 +1.357455E+00 +4.133468E-04 +3.639153E-08 +2.230626E+00 +1.033217E+00 +1.065165E-01 +2.416670E-03 +4.549248E-02 +4.740035E-04 +1.137312E-01 +2.962522E-03 +6.630810E-07 +1.170893E-13 +1.130101E-01 +2.925076E-03 +7.210562E-04 +1.190805E-07 +9.098495E+06 +1.896014E+13 +2.202000E+00 +1.007194E+00 +3.378518E-04 +2.614296E-08 +5.565395E-01 +7.242839E-02 +2.955239E-02 +1.840142E-04 +1.400990E-02 +4.103227E-05 +3.502476E-02 +2.564517E-04 +2.308081E-07 +1.205491E-14 +3.480270E-02 +2.532102E-04 +2.220571E-04 +1.030824E-08 +2.801981E+06 +1.641291E+12 +6.090000E-01 +8.636300E-02 +1.040451E-04 +2.263074E-09 +1.817267E+00 +7.710225E-01 +7.367627E-02 +1.267666E-03 +2.535616E-02 +1.551036E-04 +6.339039E-02 +9.693976E-04 +2.524798E-07 +1.896478E-14 +6.298850E-02 +9.571446E-04 +4.018954E-04 +3.896557E-08 +5.071232E+06 +6.204145E+12 +1.881000E+00 +8.206930E-01 +1.883086E-04 +8.554511E-09 +4.106914E+00 +3.704316E+00 +1.888617E-01 +7.777635E-03 +7.727973E-02 +1.309080E-03 +1.931993E-01 +8.181751E-03 +1.061590E-06 +2.554724E-13 +1.919744E-01 +8.078335E-03 +1.224884E-03 +3.288708E-07 +1.545595E+07 +5.236321E+13 +4.223000E+00 +3.850821E+00 +5.739211E-04 +7.220038E-08 +2.346339E+00 +1.119793E+00 +1.017476E-01 +2.080323E-03 +3.865443E-02 +3.024337E-04 +9.663608E-02 +1.890211E-03 +4.714003E-07 +4.853805E-14 +9.602340E-02 +1.866319E-03 +6.126731E-04 +7.597824E-08 +7.730886E+06 +1.209735E+13 +2.338000E+00 +1.106368E+00 +2.870687E-04 +1.668028E-08 +6.446883E+00 +8.447751E+00 +2.867793E-01 +1.670093E-02 +1.126541E-01 +2.611201E-03 +2.816352E-01 +1.632001E-02 +1.453669E-06 +4.585416E-13 +2.798496E-01 +1.611372E-02 +1.785568E-03 +6.559933E-07 +2.253081E+07 +1.044480E+14 +6.454000E+00 +8.471478E+00 +8.366302E-04 +1.440169E-07 +1.219419E+00 +5.127750E-01 +4.857020E-02 +8.389250E-04 +1.623897E-02 +1.008738E-04 +4.059741E-02 +6.304611E-04 +1.503579E-07 +1.146797E-14 +4.034003E-02 +6.224921E-04 +2.573878E-04 +2.534179E-08 +3.247793E+06 +4.034951E+12 +1.199000E+00 +4.975810E-01 +1.205994E-04 +5.563543E-09 +3.623361E+00 +2.780040E+00 +1.560708E-01 +5.162316E-03 +5.875078E-02 +7.419979E-04 +1.468770E-01 +4.637487E-03 +7.048177E-07 +1.136014E-13 +1.459458E-01 +4.578870E-03 +9.312005E-04 +1.864068E-07 +1.175016E+07 +2.967992E+13 +3.668000E+00 +2.824270E+00 +4.363151E-04 +4.092380E-08 tally 13: -1.098420E+02 -2.414277E+03 -4.993000E+00 -4.986021E+00 -2.023763E+00 -8.192234E-01 -5.037812E+00 -5.086734E+00 -2.745346E-05 -1.509092E-10 -5.002505E+00 -5.014944E+00 -3.530702E-02 -2.695026E-04 -4.047525E+08 -3.276894E+16 -1.098420E+02 -2.414277E+03 -1.059695E-02 -2.782849E-05 -1.048490E+02 -2.199887E+03 -1.048490E+02 -2.199887E+03 +1.092010E+02 +2.386227E+03 +4.975000E+00 +4.950147E+00 +2.009472E+00 +8.076733E-01 +5.000649E+00 +5.012321E+00 +2.728992E-05 +1.491241E-10 +4.964474E+00 +4.939215E+00 +3.617555E-02 +2.875519E-04 +4.018944E+08 +3.230693E+16 +1.092010E+02 +2.386227E+03 +1.333979E-02 +5.019969E-05 +1.042260E+02 +2.173864E+03 +1.042260E+02 +2.173864E+03 tally 14: -1.098420E+02 -2.414277E+03 -5.008447E+00 -5.018748E+00 -2.028674E+00 -8.234818E-01 -5.071684E+00 -5.146761E+00 -5.050718E-05 -5.107669E-10 -5.039530E+00 -5.081707E+00 -3.215450E-02 -2.068774E-04 -4.057347E+08 -3.293927E+16 -1.098420E+02 -2.414277E+03 -1.506603E-02 -4.541792E-05 +1.092010E+02 +2.386227E+03 +4.979068E+00 +4.959690E+00 +2.016700E+00 +8.137138E-01 +5.041749E+00 +5.085712E+00 +5.020635E-05 +5.047241E-10 +5.009785E+00 +5.021429E+00 +3.196471E-02 +2.044235E-04 +4.033399E+08 +3.254855E+16 +1.092010E+02 +2.386227E+03 +1.497710E-02 +4.487918E-05 tally 15: -1.103689E+02 -2.437562E+03 -5.035611E+00 -5.073005E+00 -2.041209E+00 -8.337913E-01 -5.103022E+00 -5.211196E+00 -2.765405E-05 -1.532759E-10 -5.070669E+00 -5.145327E+00 -3.235318E-02 -2.094674E-04 -4.082417E+08 -3.335165E+16 -1.098580E+02 -2.414983E+03 -1.515912E-02 -4.598653E-05 +1.097121E+02 +2.408636E+03 +5.009145E+00 +5.019563E+00 +2.032191E+00 +8.264420E-01 +5.080477E+00 +5.165263E+00 +2.756641E-05 +1.523527E-10 +5.048267E+00 +5.099975E+00 +3.221025E-02 +2.076211E-04 +4.064382E+08 +3.305768E+16 +1.093810E+02 +2.394075E+03 +1.509215E-02 +4.558119E-05 tally 16: -1.048490E+02 -2.199887E+03 -1.048490E+02 -2.199887E+03 -5.037812E+00 -5.086734E+00 +1.042260E+02 +2.173864E+03 +1.042260E+02 +2.173864E+03 +5.000649E+00 +5.012321E+00 tally 17: -6.546000E+00 -8.579894E+00 -1.462000E+00 -4.278220E-01 -1.160697E+00 -2.696537E-01 -2.879845E+00 -1.663297E+00 -2.723379E-05 -1.485067E-10 -2.862628E+00 -1.643479E+00 -1.721726E-02 -6.055382E-05 -2.321395E+08 -1.078615E+16 -6.546000E+00 -8.579894E+00 -6.709978E-03 -1.387848E-05 -5.084000E+00 -5.178800E+00 -5.084000E+00 -5.178800E+00 -1.032960E+02 -2.135240E+03 +6.507000E+00 +8.478423E+00 +1.444000E+00 +4.172780E-01 +1.146407E+00 +2.630079E-01 +2.867025E+00 +1.647980E+00 +2.707153E-05 +1.467503E-10 +2.848880E+00 +1.627146E+00 +1.814469E-02 +6.685238E-05 +2.292814E+08 +1.052031E+16 +6.507000E+00 +8.478423E+00 +9.467712E-03 +2.396878E-05 +5.063000E+00 +5.136983E+00 +5.063000E+00 +5.136983E+00 +1.026940E+02 +2.110535E+03 3.531000E+00 -2.493943E+00 +2.493861E+00 8.630652E-01 -1.489973E-01 -2.157967E+00 -9.345420E-01 -2.196703E-07 -9.656558E-15 -2.139877E+00 -9.185178E-01 -1.808977E-02 -8.744581E-05 +1.489924E-01 +2.133624E+00 +9.150435E-01 +2.183901E-07 +9.544829E-15 +2.115593E+00 +8.991467E-01 +1.803087E-02 +8.677353E-05 1.726130E+08 -5.959891E+15 -1.032960E+02 -2.135240E+03 -3.886968E-03 -5.976458E-06 -9.976500E+01 -1.991860E+03 -9.976500E+01 -1.991860E+03 +5.959695E+15 +1.026940E+02 +2.110535E+03 +3.872081E-03 +5.919692E-06 +9.916300E+01 +1.968002E+03 +9.916300E+01 +1.968002E+03 tally 18: -6.546000E+00 -8.579894E+00 -1.464067E+00 -4.291919E-01 -1.162338E+00 -2.705171E-01 -2.905845E+00 -1.690732E+00 -4.985316E-05 -4.976401E-10 -2.887422E+00 -1.669362E+00 -1.842307E-02 -6.796008E-05 -2.324676E+08 -1.082069E+16 -6.546000E+00 -8.579894E+00 -8.632151E-03 -1.491997E-05 -1.032960E+02 -2.135240E+03 -3.544380E+00 -2.513971E+00 -8.663357E-01 -1.501938E-01 -2.165839E+00 -9.387115E-01 -6.540142E-07 -8.559612E-14 -2.152108E+00 -9.268463E-01 -1.373143E-02 -3.773212E-05 -1.732671E+08 -6.007753E+15 -1.032960E+02 -2.135240E+03 -6.433878E-03 -8.283719E-06 +6.507000E+00 +8.478423E+00 +1.455344E+00 +4.241161E-01 +1.155413E+00 +2.673178E-01 +2.888532E+00 +1.670737E+00 +4.955615E-05 +4.917547E-10 +2.870219E+00 +1.649619E+00 +1.831331E-02 +6.715634E-05 +2.310826E+08 +1.069271E+16 +6.507000E+00 +8.478423E+00 +8.580723E-03 +1.474352E-05 +1.026940E+02 +2.110535E+03 +3.523724E+00 +2.484884E+00 +8.612868E-01 +1.484560E-01 +2.153217E+00 +9.278503E-01 +6.502027E-07 +8.460574E-14 +2.139566E+00 +9.161225E-01 +1.365140E-02 +3.729555E-05 +1.722574E+08 +5.938242E+15 +1.026940E+02 +2.110535E+03 +6.396382E-03 +8.187874E-06 tally 19: -6.593971E+00 -8.715030E+00 -1.474796E+00 -4.359519E-01 -1.170856E+00 -2.747779E-01 -2.927140E+00 -1.717362E+00 -2.743336E-05 -1.508457E-10 -2.908582E+00 -1.695655E+00 -1.855808E-02 -6.903047E-05 -2.341712E+08 -1.099112E+16 -6.547000E+00 -8.582573E+00 -8.695410E-03 -1.515497E-05 -1.037750E+02 -2.155274E+03 -3.560815E+00 -2.537559E+00 -8.703528E-01 -1.516031E-01 -2.175882E+00 -9.475192E-01 -2.206889E-07 -9.747163E-15 -2.162087E+00 -9.355427E-01 -1.379510E-02 -3.808615E-05 -1.740706E+08 -6.064123E+15 -1.033110E+02 -2.135863E+03 -6.463712E-03 -8.361443E-06 +6.573230E+00 +8.663027E+00 +1.470157E+00 +4.333505E-01 +1.167173E+00 +2.731383E-01 +2.917933E+00 +1.707114E+00 +2.734707E-05 +1.499456E-10 +2.899433E+00 +1.685536E+00 +1.849971E-02 +6.861856E-05 +2.334346E+08 +1.092553E+16 +6.518000E+00 +8.507644E+00 +8.668060E-03 +1.506454E-05 +1.031389E+02 +2.128993E+03 +3.538988E+00 +2.506616E+00 +8.650177E-01 +1.497544E-01 +2.162544E+00 +9.359650E-01 +2.193361E-07 +9.628305E-15 +2.148834E+00 +9.241346E-01 +1.371054E-02 +3.762172E-05 +1.730035E+08 +5.990176E+15 +1.028630E+02 +2.117467E+03 +6.424090E-03 +8.259483E-06 tally 20: -5.084000E+00 -5.178800E+00 -5.084000E+00 -5.178800E+00 +5.063000E+00 +5.136983E+00 +5.063000E+00 +5.136983E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.879845E+00 -1.663297E+00 -1.463000E+00 -4.284330E-01 -1.463000E+00 -4.284330E-01 +2.867025E+00 +1.647980E+00 +1.445000E+00 +4.178610E-01 +1.445000E+00 +4.178610E-01 0.000000E+00 0.000000E+00 -9.830200E+01 -1.933884E+03 -9.830200E+01 -1.933884E+03 -2.157967E+00 -9.345420E-01 +9.771800E+01 +1.911083E+03 +9.771800E+01 +1.911083E+03 +2.133624E+00 +9.150435E-01 diff --git a/tests/regression_tests/mg_temperature/build_2g.py b/tests/regression_tests/mg_temperature/build_2g.py index bca87364e..1256ca0f7 100644 --- a/tests/regression_tests/mg_temperature/build_2g.py +++ b/tests/regression_tests/mg_temperature/build_2g.py @@ -1,297 +1,297 @@ -import openmc -import numpy as np - -names = ['H', 'O', 'Zr', 'U235', 'U238'] - - -def build_openmc_xs_lib(name, groups, temperatures, xsdict, micro=True): - """Build an Openm XSdata based on dictionary values""" - xsdata = openmc.XSdata(name, groups, temperatures=temperatures) - xsdata.order = 0 - for tt in temperatures: - xsdata.set_absorption(xsdict[tt]['absorption'][name], temperature=tt) - xsdata.set_scatter_matrix(xsdict[tt]['scatter'][name], temperature=tt) - xsdata.set_total(xsdict[tt]['total'][name], temperature=tt) - if (name in xsdict[tt]['nu-fission'].keys()): - xsdata.set_nu_fission(xsdict[tt]['nu-fission'][name], - temperature=tt) - xsdata.set_chi(np.array([1., 0.]), temperature=tt) - return xsdata - - -def create_micro_xs_dict(): - """Returns micro xs library""" - xs_micro = {} - reactions = ['absorption', 'total', 'scatter', 'nu-fission'] - # chi is unnecessary when energy bound is in thermal region - # Temperature 300K - # absorption - xs_micro[300] = {r: {} for r in reactions} - xs_micro[300]['absorption']['H'] = np.array([1.0285E-4, 0.0057]) - xs_micro[300]['absorption']['O'] = np.array([7.1654E-5, 3.0283E-6]) - xs_micro[300]['absorption']['Zr'] = np.array([4.5918E-5, 3.6303E-5]) - xs_micro[300]['absorption']['U235'] = np.array([0.0035, 0.1040]) - xs_micro[300]['absorption']['U238'] = np.array([0.0056, 0.0094]) - # nu-scatter matrix - xs_micro[300]['scatter']['H'] = np.array([[[0.0910, 0.01469], - [0.0, 0.3316]]]) - xs_micro[300]['scatter']['O'] = np.array([[[0.0814, 3.3235E-4], - [0.0, 0.0960]]]) - xs_micro[300]['scatter']['Zr'] = np.array([[[0.0311, 2.6373E-5], - [0.0, 0.0315]]]) - xs_micro[300]['scatter']['U235'] = np.array([[[0.0311, 2.6373E-5], - [0.0, 0.0315]]]) - xs_micro[300]['scatter']['U238'] = np.array([[[0.0551, 2.2341E-5], - [0.0, 0.0526]]]) - # nu-fission - xs_micro[300]['nu-fission']['U235'] = np.array([0.0059, 0.2160]) - xs_micro[300]['nu-fission']['U238'] = np.array([0.0019, 1.4627E-7]) - # total - xs_micro[300]['total']['H'] = xs_micro[300]['absorption']['H'] + \ - np.sum(xs_micro[300]['scatter']['H'][0], 1) - xs_micro[300]['total']['O'] = xs_micro[300]['absorption']['O'] + \ - np.sum(xs_micro[300]['scatter']['O'][0], 1) - - xs_micro[300]['total']['Zr'] = xs_micro[300]['absorption']['Zr'] + \ - np.sum(xs_micro[300]['scatter']['Zr'][0], 1) - - xs_micro[300]['total']['U235'] = xs_micro[300]['absorption']['U235'] + \ - np.sum(xs_micro[300]['scatter']['U235'][0], 1) - - xs_micro[300]['total']['U238'] = xs_micro[300]['absorption']['U238'] + \ - np.sum(xs_micro[300]['scatter']['U238'][0], 1) - - # Temperature 600K - xs_micro[600] = {r: {} for r in reactions} - # absorption - xs_micro[600]['absorption']['H'] = np.array([1.0356E-4, 0.0046]) - xs_micro[600]['absorption']['O'] = np.array([7.2678E-5, 2.4963E-6]) - xs_micro[600]['absorption']['Zr'] = np.array([4.7256E-5, 2.9757E-5]) - xs_micro[600]['absorption']['U235'] = np.array([0.0035, 0.0853]) - xs_micro[600]['absorption']['U238'] = np.array([0.0058, 0.0079]) - # nu-scatter matrix - xs_micro[600]['scatter']['H'] = np.array([[[0.0910, 0.0138], - [0.0, 0.3316]]]) - xs_micro[600]['scatter']['O'] = np.array([[[0.0814, 3.5367E-4], - [0.0, 0.0959]]]) - xs_micro[600]['scatter']['Zr'] = np.array([[[0.0311, 3.2293E-5], - [0.0, 0.0314]]]) - xs_micro[600]['scatter']['U235'] = np.array([[[0.0022, 1.9763E-6], - [9.1634E-8, 0.0039]]]) - xs_micro[600]['scatter']['U238'] = np.array([[[0.0556, 2.8803E-5], - [0.0, 0.0536]]]) - # nu-fission - xs_micro[600]['nu-fission']['U235'] = np.array([0.0059, 0.1767]) - xs_micro[600]['nu-fission']['U238'] = np.array([0.0019, 1.2405E-7]) - # total - xs_micro[600]['total']['H'] = xs_micro[600]['absorption']['H'] + \ - np.sum(xs_micro[600]['scatter']['H'][0], 1) - xs_micro[600]['total']['O'] = xs_micro[600]['absorption']['O'] + \ - np.sum(xs_micro[600]['scatter']['O'][0], 1) - - xs_micro[600]['total']['Zr'] = xs_micro[600]['absorption']['Zr'] + \ - np.sum(xs_micro[600]['scatter']['Zr'][0], 1) - - xs_micro[600]['total']['U235'] = xs_micro[600]['absorption']['U235'] + \ - np.sum(xs_micro[600]['scatter']['U235'][0], 1) - - xs_micro[600]['total']['U238'] = xs_micro[600]['absorption']['U238'] + \ - np.sum(xs_micro[600]['scatter']['U238'][0], 1) - - # Temperature 900K - xs_micro[900] = {r: {} for r in reactions} - # absorption - xs_micro[900]['absorption']['H'] = np.array([1.0529E-4, 0.0040]) - xs_micro[900]['absorption']['O'] = np.array([7.3055E-5, 2.1850E-6]) - xs_micro[900]['absorption']['Zr'] = np.array([4.7141E-5, 2.5941E-5]) - xs_micro[900]['absorption']['U235'] = np.array([0.0035, 0.0749]) - xs_micro[900]['absorption']['U238'] = np.array([0.0060, 0.0071]) - # total - xs_micro[900]['total']['H'] = np.array([0.2982, 0.7332]) - xs_micro[900]['total']['O'] = np.array([0.0885, 0.1004]) - xs_micro[900]['total']['Zr'] = np.array([0.0370, 0.0317]) - xs_micro[900]['total']['U235'] = np.array([0.0061, 0.0789]) - xs_micro[900]['total']['U238'] = np.array([0.0707, 0.0613]) - # nu-scatter matrix - xs_micro[900]['scatter']['H'] = np.array([[[0.0913, 0.0147], - [0.0, 0.4020]]]) - xs_micro[900]['scatter']['O'] = np.array([[[0.0812, 4.0413E-4], - [0.0, 0.0965]]]) - xs_micro[900]['scatter']['Zr'] = np.array([[[0.0311, 3.6735E-5], - [0.0, 0.0314]]]) - xs_micro[900]['scatter']['U235'] = np.array([[[0.0022, 2.9034E-6], - [1.3117E-8, 0.0039]]]) - xs_micro[900]['scatter']['U238'] = np.array([[[0.0560, 3.7619E-5], - [0.0, 0.0538]]]) - # nu-fission - xs_micro[900]['nu-fission']['U235'] = np.array([0.0059, 0.1545]) - xs_micro[900]['nu-fission']['U238'] = np.array([0.0019, 1.1017E-7]) - # total - xs_micro[900]['total']['H'] = xs_micro[900]['absorption']['H'] + \ - np.sum(xs_micro[900]['scatter']['H'][0], 1) - xs_micro[900]['total']['O'] = xs_micro[900]['absorption']['O'] + \ - np.sum(xs_micro[900]['scatter']['O'][0], 1) - - xs_micro[900]['total']['Zr'] = xs_micro[900]['absorption']['Zr'] + \ - np.sum(xs_micro[900]['scatter']['Zr'][0], 1) - - xs_micro[900]['total']['U235'] = xs_micro[900]['absorption']['U235'] + \ - np.sum(xs_micro[900]['scatter']['U235'][0], 1) - - xs_micro[900]['total']['U238'] = xs_micro[900]['absorption']['U238'] + \ - np.sum(xs_micro[900]['scatter']['U238'][0], 1) - - # roll axis for scatter matrix - for t in xs_micro: - for n in xs_micro[t]['scatter']: - xs_micro[t]['scatter'][n] = np.rollaxis(xs_micro[t]['scatter'][n], - 0, 3) - return xs_micro - - -def create_macro_dict(xs_micro): - """Create a dictionary with two group cross-section""" - xs_macro = {} - for t, d1 in xs_micro.items(): - xs_macro[t] = {} - for r, d2 in d1.items(): - temp = [] - xs_macro[t][r] = {} - for n, v in d2.items(): - temp.append(d2[n]) - # The name 'macro' is needed to store data at the same level - # of a xs_macro dictionary as for xs_micro and use it in - # function build_openmc_xs_lib - xs_macro[t][r]['macro'] = sum(temp) - return xs_macro - - -def create_openmc_2mg_libs(names): - """Built a micro/macro two group openmc MGXS libraries""" - # Initialized library params - group_edges = [0.0, 0.625, 20.0e6] - groups = openmc.mgxs.EnergyGroups(group_edges=group_edges) - mg_cross_sections_file_micro = openmc.MGXSLibrary(groups) - mg_cross_sections_file_macro = openmc.MGXSLibrary(groups) - # Building a micro mg library - micro_cs = create_micro_xs_dict() - for name in names: - mg_cross_sections_file_micro.add_xsdata(build_openmc_xs_lib(name, - groups, - [t for t in - micro_cs], - micro_cs)) - # Building a macro mg library - macro_xs = create_macro_dict(micro_cs) - mg_cross_sections_file_macro.add_xsdata(build_openmc_xs_lib('macro', - groups, - [t for t in - macro_xs], - macro_xs)) - # Exporting library to hdf5 files - mg_cross_sections_file_micro.export_to_hdf5('micro_2g.h5') - mg_cross_sections_file_macro.export_to_hdf5('macro_2g.h5') - # Returning the macro_xs dict is needed for analytical solution - return macro_xs - - -def analytical_solution_2g_therm(xsmin, xsmax=None, wgt=1.0): - """ Calculate eigenvalue based on analytical solution for eq Lf = (1/k)Qf - in two group for infinity dilution media in assumption of group - boundary in thermal spectra < 1.e+3 Ev - Parameters: - ---------- - xsmin : dict - macro cross-sections dictionary with minimum range temperature - xsmax : dict - macro cross-sections dictionary with maximum range temperature - by default: None not used for standalone temperature - wgt : float - weight for interpolation by default 1.0 - Returns: - ------- - keff : np.float64 - analytical eigenvalue of critical eq matrix - """ - if xsmax is None: - sa = xsmin['absorption']['macro'] - ss12 = xsmin['scatter']['macro'][0][1][0] - nsf = xsmin['nu-fission']['macro'] - else: - sa = xsmin['absorption']['macro'] * wgt + \ - xsmax['absorption']['macro'] * (1 - wgt) - ss12 = xsmin['scatter']['macro'][0][1][0] * wgt + \ - xsmax['scatter']['macro'][0][1][0] * (1 - wgt) - nsf = xsmin['nu-fission']['macro'] * wgt + \ - xsmax['nu-fission']['macro'] * (1 - wgt) - L = np.array([sa[0] + ss12, 0.0, -ss12, sa[1]]).reshape(2, 2) - Q = np.array([nsf[0], nsf[1], 0.0, 0.0]).reshape(2, 2) - arr = np.linalg.inv(L).dot(Q) - return np.amax(np.linalg.eigvals(arr).real) - - -def build_inf_model(xsnames, xslibname, temperature, tempmethod='nearest'): - """ Building an infinite medium for openmc multi-group testing - Parameters: - ---------- - xsnames : list of str() - list with xs names - xslibname: - name of hdf5 file with cross-section library - temperature : float - value of a current temperature in K - tempmethod : {'nearest', 'interpolation'} - by default 'nearest' - """ - model = openmc.Model() - inf_medium = openmc.Material(name='test material', material_id=1) - inf_medium.set_density("sum") - for xs in xsnames: - inf_medium.add_nuclide(xs, 1) - INF = 11.1 - # Instantiate a Materials collection and export to XML - materials_file = openmc.Materials([inf_medium]) - materials_file.cross_sections = xslibname - model.materials = materials_file - - # Instantiate boundary Planes - min_x = openmc.XPlane(boundary_type='reflective', x0=-INF) - max_x = openmc.XPlane(boundary_type='reflective', x0=INF) - min_y = openmc.YPlane(boundary_type='reflective', y0=-INF) - max_y = openmc.YPlane(boundary_type='reflective', y0=INF) - - # Instantiate a Cell - cell = openmc.Cell(cell_id=1, name='cell') - cell.temperature = temperature - # Register bounding Surfaces with the Cell - cell.region = +min_x & -max_x & +min_y & -max_y - - # Fill the Cell with the Material - cell.fill = inf_medium - - # Create root universe - root_universe = openmc.Universe(name='root universe', cells=[cell]) - - # Create Geometry and set root Universe - model.geometry = openmc.Geometry(root_universe) - - # OpenMC simulation parameters - batches = 200 - inactive = 5 - particles = 5000 - - # Instantiate a Settings object - settings_file = openmc.Settings() - settings_file.batches = batches - settings_file.inactive = inactive - settings_file.particles = particles - settings_file.energy_mode = 'multi-group' - settings_file.output = {'summary': False} - # Create an initial uniform spatial source distribution over fissionable zones - bounds = [-INF, -INF, -INF, INF, INF, INF] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.temperature = {'method': tempmethod} - settings_file.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) - model.settings = settings_file - model.export_to_model_xml() +import openmc +import numpy as np + +names = ['H', 'O', 'Zr', 'U235', 'U238'] + + +def build_openmc_xs_lib(name, groups, temperatures, xsdict, micro=True): + """Build an Openm XSdata based on dictionary values""" + xsdata = openmc.XSdata(name, groups, temperatures=temperatures) + xsdata.order = 0 + for tt in temperatures: + xsdata.set_absorption(xsdict[tt]['absorption'][name], temperature=tt) + xsdata.set_scatter_matrix(xsdict[tt]['scatter'][name], temperature=tt) + xsdata.set_total(xsdict[tt]['total'][name], temperature=tt) + if (name in xsdict[tt]['nu-fission'].keys()): + xsdata.set_nu_fission(xsdict[tt]['nu-fission'][name], + temperature=tt) + xsdata.set_chi(np.array([1., 0.]), temperature=tt) + return xsdata + + +def create_micro_xs_dict(): + """Returns micro xs library""" + xs_micro = {} + reactions = ['absorption', 'total', 'scatter', 'nu-fission'] + # chi is unnecessary when energy bound is in thermal region + # Temperature 300K + # absorption + xs_micro[300] = {r: {} for r in reactions} + xs_micro[300]['absorption']['H'] = np.array([1.0285E-4, 0.0057]) + xs_micro[300]['absorption']['O'] = np.array([7.1654E-5, 3.0283E-6]) + xs_micro[300]['absorption']['Zr'] = np.array([4.5918E-5, 3.6303E-5]) + xs_micro[300]['absorption']['U235'] = np.array([0.0035, 0.1040]) + xs_micro[300]['absorption']['U238'] = np.array([0.0056, 0.0094]) + # nu-scatter matrix + xs_micro[300]['scatter']['H'] = np.array([[[0.0910, 0.01469], + [0.0, 0.3316]]]) + xs_micro[300]['scatter']['O'] = np.array([[[0.0814, 3.3235E-4], + [0.0, 0.0960]]]) + xs_micro[300]['scatter']['Zr'] = np.array([[[0.0311, 2.6373E-5], + [0.0, 0.0315]]]) + xs_micro[300]['scatter']['U235'] = np.array([[[0.0311, 2.6373E-5], + [0.0, 0.0315]]]) + xs_micro[300]['scatter']['U238'] = np.array([[[0.0551, 2.2341E-5], + [0.0, 0.0526]]]) + # nu-fission + xs_micro[300]['nu-fission']['U235'] = np.array([0.0059, 0.2160]) + xs_micro[300]['nu-fission']['U238'] = np.array([0.0019, 1.4627E-7]) + # total + xs_micro[300]['total']['H'] = xs_micro[300]['absorption']['H'] + \ + np.sum(xs_micro[300]['scatter']['H'][0], 1) + xs_micro[300]['total']['O'] = xs_micro[300]['absorption']['O'] + \ + np.sum(xs_micro[300]['scatter']['O'][0], 1) + + xs_micro[300]['total']['Zr'] = xs_micro[300]['absorption']['Zr'] + \ + np.sum(xs_micro[300]['scatter']['Zr'][0], 1) + + xs_micro[300]['total']['U235'] = xs_micro[300]['absorption']['U235'] + \ + np.sum(xs_micro[300]['scatter']['U235'][0], 1) + + xs_micro[300]['total']['U238'] = xs_micro[300]['absorption']['U238'] + \ + np.sum(xs_micro[300]['scatter']['U238'][0], 1) + + # Temperature 600K + xs_micro[600] = {r: {} for r in reactions} + # absorption + xs_micro[600]['absorption']['H'] = np.array([1.0356E-4, 0.0046]) + xs_micro[600]['absorption']['O'] = np.array([7.2678E-5, 2.4963E-6]) + xs_micro[600]['absorption']['Zr'] = np.array([4.7256E-5, 2.9757E-5]) + xs_micro[600]['absorption']['U235'] = np.array([0.0035, 0.0853]) + xs_micro[600]['absorption']['U238'] = np.array([0.0058, 0.0079]) + # nu-scatter matrix + xs_micro[600]['scatter']['H'] = np.array([[[0.0910, 0.0138], + [0.0, 0.3316]]]) + xs_micro[600]['scatter']['O'] = np.array([[[0.0814, 3.5367E-4], + [0.0, 0.0959]]]) + xs_micro[600]['scatter']['Zr'] = np.array([[[0.0311, 3.2293E-5], + [0.0, 0.0314]]]) + xs_micro[600]['scatter']['U235'] = np.array([[[0.0022, 1.9763E-6], + [9.1634E-8, 0.0039]]]) + xs_micro[600]['scatter']['U238'] = np.array([[[0.0556, 2.8803E-5], + [0.0, 0.0536]]]) + # nu-fission + xs_micro[600]['nu-fission']['U235'] = np.array([0.0059, 0.1767]) + xs_micro[600]['nu-fission']['U238'] = np.array([0.0019, 1.2405E-7]) + # total + xs_micro[600]['total']['H'] = xs_micro[600]['absorption']['H'] + \ + np.sum(xs_micro[600]['scatter']['H'][0], 1) + xs_micro[600]['total']['O'] = xs_micro[600]['absorption']['O'] + \ + np.sum(xs_micro[600]['scatter']['O'][0], 1) + + xs_micro[600]['total']['Zr'] = xs_micro[600]['absorption']['Zr'] + \ + np.sum(xs_micro[600]['scatter']['Zr'][0], 1) + + xs_micro[600]['total']['U235'] = xs_micro[600]['absorption']['U235'] + \ + np.sum(xs_micro[600]['scatter']['U235'][0], 1) + + xs_micro[600]['total']['U238'] = xs_micro[600]['absorption']['U238'] + \ + np.sum(xs_micro[600]['scatter']['U238'][0], 1) + + # Temperature 900K + xs_micro[900] = {r: {} for r in reactions} + # absorption + xs_micro[900]['absorption']['H'] = np.array([1.0529E-4, 0.0040]) + xs_micro[900]['absorption']['O'] = np.array([7.3055E-5, 2.1850E-6]) + xs_micro[900]['absorption']['Zr'] = np.array([4.7141E-5, 2.5941E-5]) + xs_micro[900]['absorption']['U235'] = np.array([0.0035, 0.0749]) + xs_micro[900]['absorption']['U238'] = np.array([0.0060, 0.0071]) + # total + xs_micro[900]['total']['H'] = np.array([0.2982, 0.7332]) + xs_micro[900]['total']['O'] = np.array([0.0885, 0.1004]) + xs_micro[900]['total']['Zr'] = np.array([0.0370, 0.0317]) + xs_micro[900]['total']['U235'] = np.array([0.0061, 0.0789]) + xs_micro[900]['total']['U238'] = np.array([0.0707, 0.0613]) + # nu-scatter matrix + xs_micro[900]['scatter']['H'] = np.array([[[0.0913, 0.0147], + [0.0, 0.4020]]]) + xs_micro[900]['scatter']['O'] = np.array([[[0.0812, 4.0413E-4], + [0.0, 0.0965]]]) + xs_micro[900]['scatter']['Zr'] = np.array([[[0.0311, 3.6735E-5], + [0.0, 0.0314]]]) + xs_micro[900]['scatter']['U235'] = np.array([[[0.0022, 2.9034E-6], + [1.3117E-8, 0.0039]]]) + xs_micro[900]['scatter']['U238'] = np.array([[[0.0560, 3.7619E-5], + [0.0, 0.0538]]]) + # nu-fission + xs_micro[900]['nu-fission']['U235'] = np.array([0.0059, 0.1545]) + xs_micro[900]['nu-fission']['U238'] = np.array([0.0019, 1.1017E-7]) + # total + xs_micro[900]['total']['H'] = xs_micro[900]['absorption']['H'] + \ + np.sum(xs_micro[900]['scatter']['H'][0], 1) + xs_micro[900]['total']['O'] = xs_micro[900]['absorption']['O'] + \ + np.sum(xs_micro[900]['scatter']['O'][0], 1) + + xs_micro[900]['total']['Zr'] = xs_micro[900]['absorption']['Zr'] + \ + np.sum(xs_micro[900]['scatter']['Zr'][0], 1) + + xs_micro[900]['total']['U235'] = xs_micro[900]['absorption']['U235'] + \ + np.sum(xs_micro[900]['scatter']['U235'][0], 1) + + xs_micro[900]['total']['U238'] = xs_micro[900]['absorption']['U238'] + \ + np.sum(xs_micro[900]['scatter']['U238'][0], 1) + + # roll axis for scatter matrix + for t in xs_micro: + for n in xs_micro[t]['scatter']: + xs_micro[t]['scatter'][n] = np.rollaxis(xs_micro[t]['scatter'][n], + 0, 3) + return xs_micro + + +def create_macro_dict(xs_micro): + """Create a dictionary with two group cross-section""" + xs_macro = {} + for t, d1 in xs_micro.items(): + xs_macro[t] = {} + for r, d2 in d1.items(): + temp = [] + xs_macro[t][r] = {} + for n, v in d2.items(): + temp.append(d2[n]) + # The name 'macro' is needed to store data at the same level + # of a xs_macro dictionary as for xs_micro and use it in + # function build_openmc_xs_lib + xs_macro[t][r]['macro'] = sum(temp) + return xs_macro + + +def create_openmc_2mg_libs(names): + """Built a micro/macro two group openmc MGXS libraries""" + # Initialized library params + group_edges = [0.0, 0.625, 20.0e6] + groups = openmc.mgxs.EnergyGroups(group_edges=group_edges) + mg_cross_sections_file_micro = openmc.MGXSLibrary(groups) + mg_cross_sections_file_macro = openmc.MGXSLibrary(groups) + # Building a micro mg library + micro_cs = create_micro_xs_dict() + for name in names: + mg_cross_sections_file_micro.add_xsdata(build_openmc_xs_lib(name, + groups, + [t for t in + micro_cs], + micro_cs)) + # Building a macro mg library + macro_xs = create_macro_dict(micro_cs) + mg_cross_sections_file_macro.add_xsdata(build_openmc_xs_lib('macro', + groups, + [t for t in + macro_xs], + macro_xs)) + # Exporting library to hdf5 files + mg_cross_sections_file_micro.export_to_hdf5('micro_2g.h5') + mg_cross_sections_file_macro.export_to_hdf5('macro_2g.h5') + # Returning the macro_xs dict is needed for analytical solution + return macro_xs + + +def analytical_solution_2g_therm(xsmin, xsmax=None, wgt=1.0): + """ Calculate eigenvalue based on analytical solution for eq Lf = (1/k)Qf + in two group for infinity dilution media in assumption of group + boundary in thermal spectra < 1.e+3 Ev + Parameters: + ---------- + xsmin : dict + macro cross-sections dictionary with minimum range temperature + xsmax : dict + macro cross-sections dictionary with maximum range temperature + by default: None not used for standalone temperature + wgt : float + weight for interpolation by default 1.0 + Returns: + ------- + keff : np.float64 + analytical eigenvalue of critical eq matrix + """ + if xsmax is None: + sa = xsmin['absorption']['macro'] + ss12 = xsmin['scatter']['macro'][0][1][0] + nsf = xsmin['nu-fission']['macro'] + else: + sa = xsmin['absorption']['macro'] * wgt + \ + xsmax['absorption']['macro'] * (1 - wgt) + ss12 = xsmin['scatter']['macro'][0][1][0] * wgt + \ + xsmax['scatter']['macro'][0][1][0] * (1 - wgt) + nsf = xsmin['nu-fission']['macro'] * wgt + \ + xsmax['nu-fission']['macro'] * (1 - wgt) + L = np.array([sa[0] + ss12, 0.0, -ss12, sa[1]]).reshape(2, 2) + Q = np.array([nsf[0], nsf[1], 0.0, 0.0]).reshape(2, 2) + arr = np.linalg.inv(L).dot(Q) + return np.amax(np.linalg.eigvals(arr)) + + +def build_inf_model(xsnames, xslibname, temperature, tempmethod='nearest'): + """ Building an infinite medium for openmc multi-group testing + Parameters: + ---------- + xsnames : list of str() + list with xs names + xslibname: + name of hdf5 file with cross-section library + temperature : float + value of a current temperature in K + tempmethod : {'nearest', 'interpolation'} + by default 'nearest' + """ + inf_medium = openmc.Material(name='test material', material_id=1) + inf_medium.set_density("sum") + for xs in xsnames: + inf_medium.add_nuclide(xs, 1) + INF = 11.1 + # Instantiate a Materials collection and export to XML + materials_file = openmc.Materials([inf_medium]) + materials_file.cross_sections = xslibname + materials_file.export_to_xml() + + # Instantiate boundary Planes + min_x = openmc.XPlane(boundary_type='reflective', x0=-INF) + max_x = openmc.XPlane(boundary_type='reflective', x0=INF) + min_y = openmc.YPlane(boundary_type='reflective', y0=-INF) + max_y = openmc.YPlane(boundary_type='reflective', y0=INF) + + # Instantiate a Cell + cell = openmc.Cell(cell_id=1, name='cell') + cell.temperature = temperature + # Register bounding Surfaces with the Cell + cell.region = +min_x & -max_x & +min_y & -max_y + + # Fill the Cell with the Material + cell.fill = inf_medium + + # Create root universe + root_universe = openmc.Universe(name='root universe', cells=[cell]) + + # Create Geometry and set root Universe + openmc_geometry = openmc.Geometry(root_universe) + + # Export to "geometry.xml" + openmc_geometry.export_to_xml() + + # OpenMC simulation parameters + batches = 200 + inactive = 5 + particles = 5000 + + # Instantiate a Settings object + settings_file = openmc.Settings() + settings_file.batches = batches + settings_file.inactive = inactive + settings_file.particles = particles + settings_file.energy_mode = 'multi-group' + settings_file.output = {'summary': False} + # Create an initial uniform spatial source distribution over fissionable zones + bounds = [-INF, -INF, -INF, INF, INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) + settings_file.temperature = {'method': tempmethod} + settings_file.source = openmc.Source(space=uniform_dist) + settings_file.export_to_xml() diff --git a/tests/regression_tests/mg_temperature/results_true.dat b/tests/regression_tests/mg_temperature/results_true.dat index 6de4c6bb1..19364e1d9 100644 --- a/tests/regression_tests/mg_temperature/results_true.dat +++ b/tests/regression_tests/mg_temperature/results_true.dat @@ -1,40 +1,40 @@ micro, method: nearest, t: 300.0, k-combined: -1.439913E+00 4.285638E-04 +1.439563E+00 4.526076E-04 kanalyt 1.440410E+00 micro, method: nearest, t: 600.0, k-combined: -1.410750E+00 4.829834E-04 +1.409389E+00 4.684481E-04 kanalyt 1.410164E+00 micro, method: nearest, t: 900.0, k-combined: -1.408232E+00 4.946310E-04 +1.407593E+00 4.410387E-04 kanalyt 1.407830E+00 micro, method: interpolation, t: 520.0, k-combined: -1.418877E+00 4.651822E-04 +1.418259E+00 4.242856E-04 kanalyt 1.418514E+00 micro, method: interpolation, t: 600.0, k-combined: -1.410750E+00 4.829834E-04 +1.409389E+00 4.684481E-04 kanalyt 1.410164E+00 macro, method: nearest, t: 300.0, k-combined: -1.439913E+00 4.285638E-04 +1.439563E+00 4.526076E-04 kanalyt 1.440410E+00 macro, method: nearest, t: 600.0, k-combined: -1.410750E+00 4.829834E-04 +1.409389E+00 4.684481E-04 kanalyt 1.410164E+00 macro, method: nearest, t: 900.0, k-combined: -1.408232E+00 4.946310E-04 +1.407593E+00 4.410387E-04 kanalyt 1.407830E+00 macro, method: interpolation, t: 520.0, k-combined: -1.418877E+00 4.651822E-04 +1.418259E+00 4.242856E-04 kanalyt 1.418514E+00 macro, method: interpolation, t: 600, k-combined: -1.410750E+00 4.829834E-04 +1.409389E+00 4.684481E-04 kanalyt 1.410164E+00 diff --git a/tests/regression_tests/mg_temperature_multi/__init__.py b/tests/regression_tests/mg_temperature_multi/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/mg_temperature_multi/inputs_true.dat b/tests/regression_tests/mg_temperature_multi/inputs_true.dat deleted file mode 100644 index b84a6782b..000000000 --- a/tests/regression_tests/mg_temperature_multi/inputs_true.dat +++ /dev/null @@ -1,56 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - 1 - - - 2 - - - 1 - flux - - - 2 - flux - - - diff --git a/tests/regression_tests/mg_temperature_multi/results_true.dat b/tests/regression_tests/mg_temperature_multi/results_true.dat deleted file mode 100644 index 3e2f990c8..000000000 --- a/tests/regression_tests/mg_temperature_multi/results_true.dat +++ /dev/null @@ -1,8 +0,0 @@ -k-combined: -1.309371E+00 6.765039E-03 -tally 1: -2.532303E+01 -1.282689E+02 -tally 2: -9.336894E+01 -1.743765E+03 diff --git a/tests/regression_tests/mg_temperature_multi/test.py b/tests/regression_tests/mg_temperature_multi/test.py deleted file mode 100755 index 3117e29ba..000000000 --- a/tests/regression_tests/mg_temperature_multi/test.py +++ /dev/null @@ -1,167 +0,0 @@ -import os - -import numpy as np -import openmc -import openmc.mgxs - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data - egroups = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] - groups = openmc.mgxs.EnergyGroups(egroups) - - # Instantiate the 7-group (C5G7) cross section data - uo2_xsdata = openmc.XSdata('UO2', groups, temperatures=[294.0, 600.0]) - uo2_xsdata.order = 0 - scatter_matrix = np.array([[ - [0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800] - ]]) - scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) - - # Original C5G7 data - uo2_xsdata.set_total([0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, 0.5644058], temperature=294.0) - uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02, 3.0020E-02, 1.1126E-01, 2.8278E-01], temperature=294.0) - uo2_xsdata.set_scatter_matrix(scatter_matrix, temperature=294.0) - uo2_xsdata.set_fission([7.21206E-03, 8.19301E-04, 6.45320E-03, 1.85648E-02, 1.78084E-02, 8.30348E-02, 2.16004E-01], temperature=294.0) - uo2_xsdata.set_nu_fission([2.005998E-02, 2.027303E-03, 1.570599E-02, 4.518301E-02, 4.334208E-02, 2.020901E-01, 5.257105E-01], temperature=294.0) - uo2_xsdata.set_chi([5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07, 0.0000E+00, 0.0000E+00, 0.0000E+00], temperature=294.0) - - # Altered C5G7 data (permuted Chi) - uo2_xsdata.set_total([0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, 0.5644058], temperature=600.0) - uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02, 3.0020E-02, 1.1126E-01, 2.8278E-01], temperature=600.0) - uo2_xsdata.set_scatter_matrix(scatter_matrix, temperature=600.0) - uo2_xsdata.set_fission([7.21206E-03, 8.19301E-04, 6.45320E-03, 1.85648E-02, 1.78084E-02, 8.30348E-02, 2.16004E-01], temperature=600.0) - uo2_xsdata.set_nu_fission([2.005998E-02, 2.027303E-03, 1.570599E-02, 4.518301E-02, 4.334208E-02, 2.020901E-01, 5.257105E-01], temperature=600.0) - uo2_xsdata.set_chi([4.1176E-01, 5.8791E-01, 3.3906E-04, 1.1761E-07, 0.0000E+00, 0.0000E+00, 0.0000E+00], temperature=600.0) - - h2o_xsdata = openmc.XSdata('LWTR', groups) - h2o_xsdata.order = 0 - h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, - 0.718, 1.2544497, 2.650379]) - h2o_xsdata.set_absorption([6.0105E-04, 1.5793E-05, 3.3716E-04, - 1.9406E-03, 5.7416E-03, 1.5001E-02, - 3.7239E-02]) - scatter_matrix = np.array([[ - [0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], - [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], - [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], - [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], - [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000] - ]]) - scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) - h2o_xsdata.set_scatter_matrix(scatter_matrix) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata]) - mg_cross_sections_file.export_to_hdf5() - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_temperature_multi(): - ############################################################################### - # Create multigroup data - create_library() - - ############################################################################### - # Create materials for the problem - - # Instantiate some Macroscopic Data - uo2_data = openmc.Macroscopic('UO2') - h2o_data = openmc.Macroscopic('LWTR') - - # Instantiate some Materials and register the appropriate Macroscopic objects - uo2 = openmc.Material(name='UO2 fuel') - uo2.set_density('macro', 1.0) - uo2.add_macroscopic(uo2_data) - - water = openmc.Material(name='Water') - water.set_density('macro', 1.0) - water.add_macroscopic(h2o_data) - - # Instantiate a Materials collection and export to XML - materials = openmc.Materials([uo2, water]) - materials.cross_sections = "mgxs.h5" - - ############################################################################### - # Define problem geometry - - # Create a surface for the fuel outer radius - fuel_ir = openmc.ZCylinder(r=0.25, name='Fuel IR') - fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') - - # Create a region represented as the inside of a rectangular prism - pitch = 1.26 - box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') - - # Instantiate Cells - fuel_inner = openmc.Cell(fill=uo2, region=-fuel_ir, name='fuel inner') - fuel_inner.temperature = 600.0 - fuel_outer = openmc.Cell(fill=uo2, region=+fuel_ir & -fuel_or, name='fuel outer') - fuel_outer.temperature = 294.0 - moderator = openmc.Cell(fill=water, region=+fuel_or & -box, name='moderator') - - # Create a geometry with the two cells and export to XML - geometry = openmc.Geometry([fuel_inner, fuel_outer, moderator]) - - ############################################################################### - # Define problem settings - - # Instantiate a Settings object, set all runtime parameters, and export to XML - settings = openmc.Settings() - settings.energy_mode = "multi-group" - settings.batches = 10 - settings.inactive = 5 - settings.particles = 1000 - - # Create an initial uniform spatial source distribution over fissionable zones - lower_left = (-pitch/2, -pitch/2, -1) - upper_right = (pitch/2, pitch/2, 1) - uniform_dist = openmc.stats.Box(lower_left, upper_right) - settings.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) - - ############################################################################### - # Define tallies - - # Instantiate the energy group data - egroups = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] - - inner_filter = openmc.CellFilter(fuel_inner) - outer_filter = openmc.CellFilter(fuel_outer) - energy_filter = openmc.EnergyFilter(egroups) - - inner_tally = openmc.Tally(name="inner tally") - inner_tally.filters = [energy_filter] - inner_tally.filters = [inner_filter] - inner_tally.scores = ['flux'] - - outer_tally = openmc.Tally(name="outer tally") - outer_tally.filters = [energy_filter] - outer_tally.filters = [outer_filter] - outer_tally.scores = ['flux'] - - # Instantiate a Tallies collection and export to XML - tallies = openmc.Tallies([inner_tally, outer_tally]) - - # Generate model and run test - model = openmc.Model(geometry, materials, settings, tallies) - - harness = MGXSTestHarness('statepoint.10.h5', model=model) - harness.main() diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat new file mode 100644 index 000000000..bc5c4b2d4 --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 3 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + analog + + + 1 2 7 + total + nu-fission + analog + + + 1 2 + total + flux + analog + + + 1 2 7 11 + total + nu-scatter + analog + + + 1 2 7 + total + nu-scatter + analog + + + 1 2 7 + total + scatter + analog + + + 15 2 + total + flux + tracklength + + + 15 2 + total + total + tracklength + + + 15 2 + total + flux + tracklength + + + 15 2 + total + absorption + tracklength + + + 15 2 + total + flux + analog + + + 15 2 7 + total + nu-fission + analog + + + 15 2 + total + flux + analog + + + 15 2 7 11 + total + nu-scatter + analog + + + 15 2 7 + total + nu-scatter + analog + + + 15 2 7 + total + scatter + analog + + + 29 2 + total + flux + tracklength + + + 29 2 + total + total + tracklength + + + 29 2 + total + flux + tracklength + + + 29 2 + total + absorption + tracklength + + + 29 2 + total + flux + analog + + + 29 2 7 + total + nu-fission + analog + + + 29 2 + total + flux + analog + + + 29 2 7 11 + total + nu-scatter + analog + + + 29 2 7 + total + nu-scatter + analog + + + 29 2 7 + total + scatter + analog + + diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true_multiplicity_matrix.dat b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true_multiplicity_matrix.dat deleted file mode 100644 index 2f6dde1ab..000000000 --- a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true_multiplicity_matrix.dat +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 3 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - analog - - - 1 2 7 - total - nu-fission - analog - - - 1 2 - total - flux - analog - - - 1 2 7 11 - total - nu-scatter - analog - - - 1 2 7 - total - nu-scatter - analog - - - 1 2 7 - total - scatter - analog - - - 15 2 - total - flux - tracklength - - - 15 2 - total - total - tracklength - - - 15 2 - total - flux - tracklength - - - 15 2 - total - absorption - tracklength - - - 15 2 - total - flux - analog - - - 15 2 7 - total - nu-fission - analog - - - 15 2 - total - flux - analog - - - 15 2 7 11 - total - nu-scatter - analog - - - 15 2 7 - total - nu-scatter - analog - - - 15 2 7 - total - scatter - analog - - - 29 2 - total - flux - tracklength - - - 29 2 - total - total - tracklength - - - 29 2 - total - flux - tracklength - - - 29 2 - total - absorption - tracklength - - - 29 2 - total - flux - analog - - - 29 2 7 - total - nu-fission - analog - - - 29 2 - total - flux - analog - - - 29 2 7 11 - total - nu-scatter - analog - - - 29 2 7 - total - nu-scatter - analog - - - 29 2 7 - total - scatter - analog - - - diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true_scatter_matrix.dat b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true_scatter_matrix.dat deleted file mode 100644 index 6e60f1b19..000000000 --- a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true_scatter_matrix.dat +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 7 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 3 - - - 8 - - - 9 - - - 43 44 - total - flux - tracklength - - - 43 44 - total - total - tracklength - - - 43 44 - total - flux - tracklength - - - 43 44 - total - absorption - tracklength - - - 43 44 - total - flux - analog - - - 43 44 49 - total - nu-fission - analog - - - 43 44 - total - flux - analog - - - 43 44 49 53 - total - scatter - analog - - - 54 44 - total - flux - tracklength - - - 54 44 - total - total - tracklength - - - 54 44 - total - flux - tracklength - - - 54 44 - total - absorption - tracklength - - - 54 44 - total - flux - analog - - - 54 44 49 - total - nu-fission - analog - - - 54 44 - total - flux - analog - - - 54 44 49 53 - total - scatter - analog - - - 65 44 - total - flux - tracklength - - - 65 44 - total - total - tracklength - - - 65 44 - total - flux - tracklength - - - 65 44 - total - absorption - tracklength - - - 65 44 - total - flux - analog - - - 65 44 49 - total - nu-fission - analog - - - 65 44 - total - flux - analog - - - 65 44 49 53 - total - scatter - analog - - - diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat index 7ce106314..b4de4c775 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.152065E+00 2.768158E-02 +1.263928E+00 3.768356E-02 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index b68fbd6c3..72f052e68 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -9,7 +9,7 @@ from tests.regression_tests import config class MGXSTestHarness(PyAPITestHarness): - def __init__(self, *args, scatter_mgxs_type=None, **kwargs): + def __init__(self, *args, **kwargs): # Generate inputs using parent class routine super().__init__(*args, **kwargs) @@ -19,8 +19,8 @@ class MGXSTestHarness(PyAPITestHarness): # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) self.mgxs_lib.by_nuclide = False - self.mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission matrix'] - self.mgxs_lib.mgxs_types += scatter_mgxs_type + self.mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission matrix', + 'nu-scatter matrix', 'multiplicity matrix'] self.mgxs_lib.energy_groups = energy_groups self.mgxs_lib.correction = None self.mgxs_lib.legendre_order = 3 @@ -28,7 +28,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Initialize a tallies file - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _run_openmc(self): # Initial run @@ -40,20 +40,28 @@ class MGXSTestHarness(PyAPITestHarness): # Build MG Inputs # Get data needed to execute Library calculations. - with openmc.StatePoint(self._sp_name) as sp: - self.mgxs_lib.load_from_statepoint(sp) + sp = openmc.StatePoint(self._sp_name) + self.mgxs_lib.load_from_statepoint(sp) self._model.mgxs_file, self._model.materials, \ self._model.geometry = self.mgxs_lib.create_mg_mode() # Modify materials and settings so we can run in MG mode self._model.materials.cross_sections = './mgxs.h5' self._model.settings.energy_mode = 'multi-group' - # Dont need tallies so clear them from the model - self._model.tallies = openmc.Tallies() # Write modified input files - self._model.export_to_model_xml() + self._model.settings.export_to_xml() + self._model.geometry.export_to_xml() + self._model.materials.export_to_xml() self._model.mgxs_file.export_to_hdf5() + # Dont need tallies.xml, so remove the file + if os.path.exists('tallies.xml'): + os.remove('tallies.xml') + + # Enforce closing statepoint and summary files so HDF5 + # does not throw an error during the next OpenMC execution + sp._f.close() + sp._summary._f.close() # Re-run MG mode. if config['mpi']: @@ -69,23 +77,9 @@ class MGXSTestHarness(PyAPITestHarness): os.remove(f) -def test_mgxs_library_ce_to_mg_multiplicity_matrix(): +def test_mgxs_library_ce_to_mg(): # Set the input set to use the pincell model model = pwr_pin_cell() - harness = MGXSTestHarness( - 'statepoint.10.h5', model, - inputs_true='inputs_true_multiplicity_matrix.dat', - scatter_mgxs_type=['nu-scatter matrix', 'multiplicity matrix'] - ) - harness.main() - - -def test_mgxs_library_ce_to_mg_scatter_matrix(): - # Set the input set to use the pincell model - model = pwr_pin_cell() - - harness = MGXSTestHarness('statepoint.10.h5', model, - inputs_true='inputs_true_scatter_matrix.dat', - scatter_mgxs_type=['scatter matrix']) + harness = MGXSTestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat index e1f330cf9..576f27966 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat @@ -1,253 +1,251 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 3 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - total - flux - analog - - - 1 2 7 - U234 U235 U238 O16 - nu-fission - analog - - - 1 2 - total - flux - analog - - - 1 2 7 11 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 7 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 7 - U234 U235 U238 O16 - scatter - analog - - - 15 2 - total - flux - tracklength - - - 15 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 15 2 - total - flux - tracklength - - - 15 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 15 2 - total - flux - analog - - - 15 2 7 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 15 2 - total - flux - analog - - - 15 2 7 11 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 15 2 7 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 15 2 7 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 29 2 - total - flux - tracklength - - - 29 2 - H1 O16 B10 B11 - total - tracklength - - - 29 2 - total - flux - tracklength - - - 29 2 - H1 O16 B10 B11 - absorption - tracklength - - - 29 2 - total - flux - analog - - - 29 2 7 - H1 O16 B10 B11 - nu-fission - analog - - - 29 2 - total - flux - analog - - - 29 2 7 11 - H1 O16 B10 B11 - nu-scatter - analog - - - 29 2 7 - H1 O16 B10 B11 - nu-scatter - analog - - - 29 2 7 - H1 O16 B10 B11 - scatter - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 3 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + total + flux + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-fission + analog + + + 1 2 + total + flux + analog + + + 1 2 7 11 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + scatter + analog + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 15 2 + total + flux + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 15 2 + total + flux + analog + + + 15 2 7 11 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + total + tracklength + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + absorption + tracklength + + + 29 2 + total + flux + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-fission + analog + + + 29 2 + total + flux + analog + + + 29 2 7 11 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + scatter + analog + + diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat index 50c8328c8..f2844ed29 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.139942E-01 1.181308E-02 +3.817369E-01 1.166296E-02 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py index 489105f8f..b624140d4 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py @@ -28,7 +28,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Initialize a tallies file - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _run_openmc(self): # Initial run @@ -40,20 +40,28 @@ class MGXSTestHarness(PyAPITestHarness): # Build MG Inputs # Get data needed to execute Library calculations. - with openmc.StatePoint(self._sp_name) as sp: - self.mgxs_lib.load_from_statepoint(sp) + sp = openmc.StatePoint(self._sp_name) + self.mgxs_lib.load_from_statepoint(sp) self._model.mgxs_file, self._model.materials, \ self._model.geometry = self.mgxs_lib.create_mg_mode() # Modify materials and settings so we can run in MG mode self._model.materials.cross_sections = './mgxs.h5' self._model.settings.energy_mode = 'multi-group' - # Dont need tallies so clear them from the model - self._model.tallies = openmc.Tallies() # Write modified input files - self._model.export_to_model_xml() + self._model.settings.export_to_xml() + self._model.geometry.export_to_xml() + self._model.materials.export_to_xml() self._model.mgxs_file.export_to_hdf5() + # Dont need tallies.xml, so remove the file + if os.path.exists('tallies.xml'): + os.remove('tallies.xml') + + # Enforce closing statepoint and summary files so HDF5 + # does not throw an error during the next OpenMC execution + sp._f.close() + sp._summary._f.close() # Re-run MG mode. if config['mpi']: diff --git a/tests/regression_tests/mgxs_library_condense/inputs_true.dat b/tests/regression_tests/mgxs_library_condense/inputs_true.dat index 4451d214c..cac18ffcd 100644 --- a/tests/regression_tests/mgxs_library_condense/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_condense/inputs_true.dat @@ -1,534 +1,532 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 2 2 - -100.0 -100.0 - 100.0 100.0 - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 1 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - (n,3n) - tracklength - - - 1 2 - total - (n,4n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 54 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 54 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 68 2 - total - current - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 79 2 - total - delayed-nu-fission - tracklength - - - 1 79 54 - total - delayed-nu-fission - analog - - - 1 79 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 79 2 - total - delayed-nu-fission - tracklength - - - 1 79 - total - delayed-nu-fission - tracklength - - - 1 79 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 79 2 5 - total - delayed-nu-fission - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 2 2 + -100.0 -100.0 + 100.0 100.0 + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 1 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 54 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 54 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 68 2 + total + current + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 54 + total + delayed-nu-fission + analog + + + 1 79 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 + total + delayed-nu-fission + tracklength + + + 1 79 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 79 2 5 + total + delayed-nu-fission + analog + + diff --git a/tests/regression_tests/mgxs_library_condense/results_true.dat b/tests/regression_tests/mgxs_library_condense/results_true.dat index 023d5afa2..e0b47a78b 100644 --- a/tests/regression_tests/mgxs_library_condense/results_true.dat +++ b/tests/regression_tests/mgxs_library_condense/results_true.dat @@ -1,362 +1,362 @@ - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.702881 0.026175 -2 1 2 1 total 0.706921 0.029169 -1 2 1 1 total 0.707809 0.024766 -3 2 2 1 total 0.717967 0.024008 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.431023 0.028803 -2 1 2 1 total 0.451864 0.030748 -1 2 1 1 total 0.456990 0.026359 -3 2 2 1 total 0.450621 0.026744 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.431023 0.028803 -2 1 2 1 total 0.451864 0.030748 -1 2 1 1 total 0.456990 0.026359 -3 2 2 1 total 0.450621 0.026744 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.022398 0.001401 -2 1 2 1 total 0.022325 0.001371 -1 2 1 1 total 0.022942 0.000990 -3 2 2 1 total 0.022705 0.001322 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.022394 0.001401 -2 1 2 1 total 0.022321 0.001371 -1 2 1 1 total 0.022935 0.000990 -3 2 2 1 total 0.022699 0.001322 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.011562 0.001544 -2 1 2 1 total 0.011852 0.001418 -1 2 1 1 total 0.012168 0.000958 -3 2 2 1 total 0.011986 0.001418 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.010836 0.000803 -2 1 2 1 total 0.010473 0.000591 -1 2 1 1 total 0.010774 0.000415 -3 2 2 1 total 0.010719 0.000688 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.026602 0.001957 -2 1 2 1 total 0.025695 0.001442 -1 2 1 1 total 0.026454 0.001015 -3 2 2 1 total 0.026310 0.001678 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 2.098256e+06 155243.612264 -2 1 2 1 total 2.027699e+06 114334.400924 -1 2 1 1 total 2.086255e+06 80325.567787 -3 2 2 1 total 2.075596e+06 133128.805680 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.680483 0.025407 -2 1 2 1 total 0.684597 0.028126 -1 2 1 1 total 0.684867 0.024133 -3 2 2 1 total 0.695262 0.023087 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.678017 0.026288 -2 1 2 1 total 0.674888 0.033989 -1 2 1 1 total 0.681736 0.025618 -3 2 2 1 total 0.683701 0.023788 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.678017 0.026290 -1 1 1 1 1 P1 total 0.271858 0.011693 -2 1 1 1 1 P2 total 0.095219 0.002950 -3 1 1 1 1 P3 total 0.012808 0.004686 -8 1 2 1 1 P0 total 0.674888 0.033578 -9 1 2 1 1 P1 total 0.255058 0.009912 -10 1 2 1 1 P2 total 0.098001 0.005459 -11 1 2 1 1 P3 total 0.012058 0.005439 -4 2 1 1 1 P0 total 0.681736 0.025439 -5 2 1 1 1 P1 total 0.250820 0.009035 -6 2 1 1 1 P2 total 0.092563 0.006549 -7 2 1 1 1 P3 total 0.008511 0.003905 -12 2 2 1 1 P0 total 0.683701 0.024254 -13 2 2 1 1 P1 total 0.267345 0.011695 -14 2 2 1 1 P2 total 0.096222 0.005551 -15 2 2 1 1 P3 total 0.011515 0.003236 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.678017 0.026290 -1 1 1 1 1 P1 total 0.271858 0.011693 -2 1 1 1 1 P2 total 0.095219 0.002950 -3 1 1 1 1 P3 total 0.012808 0.004686 -8 1 2 1 1 P0 total 0.674888 0.033578 -9 1 2 1 1 P1 total 0.255058 0.009912 -10 1 2 1 1 P2 total 0.098001 0.005459 -11 1 2 1 1 P3 total 0.012058 0.005439 -4 2 1 1 1 P0 total 0.681736 0.025439 -5 2 1 1 1 P1 total 0.250820 0.009035 -6 2 1 1 1 P2 total 0.092563 0.006549 -7 2 1 1 1 P3 total 0.008511 0.003905 -12 2 2 1 1 P0 total 0.683701 0.024254 -13 2 2 1 1 P1 total 0.267345 0.011695 -14 2 2 1 1 P2 total 0.096222 0.005551 -15 2 2 1 1 P3 total 0.011515 0.003236 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 1.0 0.041785 -2 1 2 1 1 total 1.0 0.057717 -1 2 1 1 1 total 1.0 0.040074 -3 2 2 1 1 total 1.0 0.042758 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 0.028438 0.003513 -2 1 2 1 1 total 0.022222 0.001560 -1 2 1 1 1 total 0.025698 0.002756 -3 2 2 1 1 total 0.026501 0.002315 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 1.0 0.041785 -2 1 2 1 1 total 1.0 0.057717 -1 2 1 1 1 total 1.0 0.040074 -3 2 2 1 1 total 1.0 0.042758 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.680483 0.038131 -1 1 1 1 1 P1 total 0.272847 0.016111 -2 1 1 1 1 P2 total 0.095565 0.004869 -3 1 1 1 1 P3 total 0.012854 0.004731 -8 1 2 1 1 P0 total 0.684597 0.048501 -9 1 2 1 1 P1 total 0.258727 0.016473 -10 1 2 1 1 P2 total 0.099411 0.007470 -11 1 2 1 1 P3 total 0.012231 0.005552 -4 2 1 1 1 P0 total 0.684867 0.036546 -5 2 1 1 1 P1 total 0.251972 0.013220 -6 2 1 1 1 P2 total 0.092988 0.007474 -7 2 1 1 1 P3 total 0.008550 0.003936 -12 2 2 1 1 P0 total 0.695262 0.037640 -13 2 2 1 1 P1 total 0.271866 0.016280 -14 2 2 1 1 P2 total 0.097849 0.006919 -15 2 2 1 1 P3 total 0.011710 0.003325 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.680483 0.047566 -1 1 1 1 1 P1 total 0.272847 0.019737 -2 1 1 1 1 P2 total 0.095565 0.006297 -3 1 1 1 1 P3 total 0.012854 0.004762 -8 1 2 1 1 P0 total 0.684597 0.062559 -9 1 2 1 1 P1 total 0.258727 0.022234 -10 1 2 1 1 P2 total 0.099411 0.009420 -11 1 2 1 1 P3 total 0.012231 0.005597 -4 2 1 1 1 P0 total 0.684867 0.045704 -5 2 1 1 1 P1 total 0.251972 0.016635 -6 2 1 1 1 P2 total 0.092988 0.008352 -7 2 1 1 1 P3 total 0.008550 0.003951 -12 2 2 1 1 P0 total 0.695262 0.047964 -13 2 2 1 1 P1 total 0.271866 0.020004 -14 2 2 1 1 P2 total 0.097849 0.008086 -15 2 2 1 1 P3 total 0.011710 0.003363 - mesh 1 group out nuclide mean std. dev. - x y -0 1 1 1 total 1.0 0.142430 -2 1 2 1 total 1.0 0.112715 -1 2 1 1 total 1.0 0.192385 -3 2 2 1 total 1.0 0.109836 - mesh 1 group out nuclide mean std. dev. - x y -0 1 1 1 total 1.0 0.143959 -2 1 2 1 total 1.0 0.102504 -1 2 1 1 total 1.0 0.188381 -3 2 2 1 total 1.0 0.116230 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 5.060544e-07 3.651604e-08 -2 1 2 1 total 5.101988e-07 4.947639e-08 -1 2 1 1 total 5.206450e-07 2.814648e-08 -3 2 2 1 total 5.278759e-07 3.171554e-08 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.026414 0.001944 -2 1 2 1 total 0.025515 0.001432 -1 2 1 1 total 0.026267 0.001008 -3 2 2 1 total 0.026125 0.001667 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 0.028220 0.003510 -2 1 2 1 1 total 0.021754 0.001519 -1 2 1 1 1 total 0.025487 0.002676 -3 2 2 1 1 total 0.026281 0.002263 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.693468 0.019161 +2 1 2 1 1 total 0.694532 0.021411 +1 2 1 1 1 total 0.693746 0.023378 +3 2 2 1 1 total 0.697424 0.031315 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.439784 0.020575 +2 1 2 1 1 total 0.427837 0.025828 +1 2 1 1 1 total 0.423294 0.027075 +3 2 2 1 1 total 0.433094 0.032674 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.439784 0.020575 +2 1 2 1 1 total 0.427935 0.025836 +1 2 1 1 1 total 0.423294 0.027075 +3 2 2 1 1 total 0.433094 0.032674 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.021509 0.001396 +2 1 2 1 1 total 0.020854 0.001436 +1 2 1 1 1 total 0.021469 0.001983 +3 2 2 1 1 total 0.022046 0.001594 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.021489 0.001396 +2 1 2 1 1 total 0.020837 0.001436 +1 2 1 1 1 total 0.021454 0.001983 +3 2 2 1 1 total 0.022036 0.001594 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.011598 0.001508 +2 1 2 1 1 total 0.010856 0.001613 +1 2 1 1 1 total 0.011622 0.002259 +3 2 2 1 1 total 0.012002 0.001685 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.009911 0.000667 +2 1 2 1 1 total 0.009998 0.000859 +1 2 1 1 1 total 0.009847 0.001153 +3 2 2 1 1 total 0.010044 0.000939 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.024369 0.001625 +2 1 2 1 1 total 0.024572 0.002095 +1 2 1 1 1 total 0.024189 0.002811 +3 2 2 1 1 total 0.024677 0.002291 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 1.919781e+06 128933.976741 +2 1 2 1 1 total 1.936343e+06 166141.202022 +1 2 1 1 1 total 1.906964e+06 223076.300071 +3 2 2 1 1 total 1.945248e+06 181591.269295 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.671959 0.018153 +2 1 2 1 1 total 0.673678 0.020448 +1 2 1 1 1 total 0.672277 0.021882 +3 2 2 1 1 total 0.675378 0.030166 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.672619 0.022961 +2 1 2 1 1 total 0.687448 0.033696 +1 2 1 1 1 total 0.676738 0.023823 +3 2 2 1 1 total 0.673350 0.021595 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.672619 0.023173 +1 1 1 1 1 1 P1 total 0.253684 0.007398 +2 1 1 1 1 1 P2 total 0.083914 0.004899 +3 1 1 1 1 1 P3 total 0.006851 0.005511 +8 1 2 1 1 1 P0 total 0.687265 0.033719 +9 1 2 1 1 1 P1 total 0.266694 0.014161 +10 1 2 1 1 1 P2 total 0.110092 0.005824 +11 1 2 1 1 1 P3 total 0.014970 0.004933 +4 2 1 1 1 1 P0 total 0.676738 0.023406 +5 2 1 1 1 1 P1 total 0.270452 0.013885 +6 2 1 1 1 1 P2 total 0.107918 0.005840 +7 2 1 1 1 1 P3 total 0.016160 0.004108 +12 2 2 1 1 1 P0 total 0.673350 0.021192 +13 2 2 1 1 1 P1 total 0.264330 0.009415 +14 2 2 1 1 1 P2 total 0.093703 0.004850 +15 2 2 1 1 1 P3 total 0.019800 0.005236 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.672619 0.023173 +1 1 1 1 1 1 P1 total 0.253684 0.007398 +2 1 1 1 1 1 P2 total 0.083914 0.004899 +3 1 1 1 1 1 P3 total 0.006851 0.005511 +8 1 2 1 1 1 P0 total 0.687448 0.033656 +9 1 2 1 1 1 P1 total 0.266596 0.014177 +10 1 2 1 1 1 P2 total 0.110079 0.005826 +11 1 2 1 1 1 P3 total 0.015046 0.004973 +4 2 1 1 1 1 P0 total 0.676738 0.023406 +5 2 1 1 1 1 P1 total 0.270452 0.013885 +6 2 1 1 1 1 P2 total 0.107918 0.005840 +7 2 1 1 1 1 P3 total 0.016160 0.004108 +12 2 2 1 1 1 P0 total 0.673350 0.021192 +13 2 2 1 1 1 P1 total 0.264330 0.009415 +14 2 2 1 1 1 P2 total 0.093703 0.004850 +15 2 2 1 1 1 P3 total 0.019800 0.005236 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.000000 0.036767 +2 1 2 1 1 1 total 1.000266 0.042769 +1 2 1 1 1 1 total 1.000000 0.034289 +3 2 2 1 1 1 total 1.000000 0.022887 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.025263 0.001825 +2 1 2 1 1 1 total 0.021868 0.001931 +1 2 1 1 1 1 total 0.025960 0.002413 +3 2 2 1 1 1 total 0.028694 0.002815 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.0 0.036767 +2 1 2 1 1 1 total 1.0 0.042878 +1 2 1 1 1 1 total 1.0 0.034289 +3 2 2 1 1 1 total 1.0 0.022887 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.671959 0.030658 +1 1 1 1 1 1 P1 total 0.253435 0.010587 +2 1 1 1 1 1 P2 total 0.083831 0.005499 +3 1 1 1 1 1 P3 total 0.006845 0.005509 +8 1 2 1 1 1 P0 total 0.673678 0.035391 +9 1 2 1 1 1 P1 total 0.261422 0.014724 +10 1 2 1 1 1 P2 total 0.107915 0.006058 +11 1 2 1 1 1 P3 total 0.014674 0.004843 +4 2 1 1 1 1 P0 total 0.672277 0.031784 +5 2 1 1 1 1 P1 total 0.268669 0.016287 +6 2 1 1 1 1 P2 total 0.107206 0.006753 +7 2 1 1 1 1 P3 total 0.016054 0.004114 +12 2 2 1 1 1 P0 total 0.675378 0.033896 +13 2 2 1 1 1 P1 total 0.265126 0.014021 +14 2 2 1 1 1 P2 total 0.093985 0.006096 +15 2 2 1 1 1 P3 total 0.019860 0.005309 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.671959 0.039374 +1 1 1 1 1 1 P1 total 0.253435 0.014104 +2 1 1 1 1 1 P2 total 0.083831 0.006304 +3 1 1 1 1 1 P3 total 0.006845 0.005515 +8 1 2 1 1 1 P0 total 0.673857 0.045644 +9 1 2 1 1 1 P1 total 0.261492 0.018491 +10 1 2 1 1 1 P2 total 0.107944 0.007617 +11 1 2 1 1 1 P3 total 0.014678 0.004885 +4 2 1 1 1 1 P0 total 0.672277 0.039263 +5 2 1 1 1 1 P1 total 0.268669 0.018712 +6 2 1 1 1 1 P2 total 0.107206 0.007689 +7 2 1 1 1 1 P3 total 0.016054 0.004150 +12 2 2 1 1 1 P0 total 0.675378 0.037254 +13 2 2 1 1 1 P1 total 0.265126 0.015278 +14 2 2 1 1 1 P2 total 0.093985 0.006465 +15 2 2 1 1 1 P3 total 0.019860 0.005328 + mesh 1 group out nuclide mean std. dev. + x y z +0 1 1 1 1 total 1.0 0.080776 +2 1 2 1 1 total 1.0 0.117674 +1 2 1 1 1 total 1.0 0.160576 +3 2 2 1 1 total 1.0 0.151384 + mesh 1 group out nuclide mean std. dev. + x y z +0 1 1 1 1 total 1.0 0.080742 +2 1 2 1 1 total 1.0 0.117674 +1 2 1 1 1 total 1.0 0.160576 +3 2 2 1 1 total 1.0 0.150417 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 4.800874e-07 2.910227e-08 +2 1 2 1 1 total 5.008000e-07 3.613802e-08 +1 2 1 1 1 total 4.872638e-07 4.324238e-08 +3 2 2 1 1 total 4.890453e-07 2.833017e-08 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.024194 0.001614 +2 1 2 1 1 total 0.024397 0.002081 +1 2 1 1 1 total 0.024017 0.002793 +3 2 2 1 1 total 0.024501 0.002276 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.024899 0.001762 +2 1 2 1 1 1 total 0.021868 0.001931 +1 2 1 1 1 1 total 0.025960 0.002413 +3 2 2 1 1 1 total 0.028508 0.002818 mesh 1 group in nuclide mean std. dev. x y surf -3 1 1 x-max in 1 total 4.244 0.096333 -2 1 1 x-max out 1 total 4.378 0.107210 +3 1 1 x-max in 1 total 4.520 0.122262 +2 1 1 x-max out 1 total 4.486 0.128841 1 1 1 x-min in 1 total 0.000 0.000000 0 1 1 x-min out 1 total 0.000 0.000000 -7 1 1 y-max in 1 total 4.388 0.116508 -6 1 1 y-max out 1 total 4.284 0.129066 +7 1 1 y-max in 1 total 4.406 0.116576 +6 1 1 y-max out 1 total 4.436 0.064637 5 1 1 y-min in 1 total 0.000 0.000000 4 1 1 y-min out 1 total 0.000 0.000000 -19 1 2 x-max in 1 total 4.280 0.139971 -18 1 2 x-max out 1 total 4.152 0.117141 +19 1 2 x-max in 1 total 4.460 0.122752 +18 1 2 x-max out 1 total 4.480 0.162721 17 1 2 x-min in 1 total 0.000 0.000000 16 1 2 x-min out 1 total 0.000 0.000000 23 1 2 y-max in 1 total 0.000 0.000000 22 1 2 y-max out 1 total 0.000 0.000000 -21 1 2 y-min in 1 total 4.284 0.129066 -20 1 2 y-min out 1 total 4.388 0.116508 +21 1 2 y-min in 1 total 4.436 0.064637 +20 1 2 y-min out 1 total 4.406 0.116576 11 2 1 x-max in 1 total 0.000 0.000000 10 2 1 x-max out 1 total 0.000 0.000000 -9 2 1 x-min in 1 total 4.378 0.107210 -8 2 1 x-min out 1 total 4.244 0.096333 -15 2 1 y-max in 1 total 4.280 0.079070 -14 2 1 y-max out 1 total 4.416 0.093648 +9 2 1 x-min in 1 total 4.486 0.128841 +8 2 1 x-min out 1 total 4.520 0.122262 +15 2 1 y-max in 1 total 4.548 0.156691 +14 2 1 y-max out 1 total 4.526 0.166571 13 2 1 y-min in 1 total 0.000 0.000000 12 2 1 y-min out 1 total 0.000 0.000000 27 2 2 x-max in 1 total 0.000 0.000000 26 2 2 x-max out 1 total 0.000 0.000000 -25 2 2 x-min in 1 total 4.152 0.117141 -24 2 2 x-min out 1 total 4.280 0.139971 +25 2 2 x-min in 1 total 4.480 0.162721 +24 2 2 x-min out 1 total 4.460 0.122752 31 2 2 y-max in 1 total 0.000 0.000000 30 2 2 y-max out 1 total 0.000 0.000000 -29 2 2 y-min in 1 total 4.416 0.093648 -28 2 2 y-min out 1 total 4.280 0.079070 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.943198 0.067915 -2 1 2 1 total 0.895741 0.058714 -1 2 1 1 total 0.911011 0.068461 -3 2 2 1 total 0.927611 0.066426 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.943198 0.067915 -2 1 2 1 total 0.895741 0.058714 -1 2 1 1 total 0.911011 0.068461 -3 2 2 1 total 0.927611 0.066426 - mesh 1 delayedgroup group in nuclide mean std. dev. - x y -0 1 1 1 1 total 0.000006 4.453421e-07 -1 1 1 2 1 total 0.000032 2.303082e-06 -2 1 1 3 1 total 0.000031 2.202789e-06 -3 1 1 4 1 total 0.000072 4.961025e-06 -4 1 1 5 1 total 0.000032 2.071919e-06 -5 1 1 6 1 total 0.000013 8.662934e-07 -12 1 2 1 1 total 0.000006 3.282329e-07 -13 1 2 2 1 total 0.000031 1.701766e-06 -14 1 2 3 1 total 0.000030 1.629615e-06 -15 1 2 4 1 total 0.000070 3.675759e-06 -16 1 2 5 1 total 0.000031 1.536226e-06 -17 1 2 6 1 total 0.000013 6.423838e-07 -6 2 1 1 1 total 0.000006 2.308186e-07 -7 2 1 2 1 total 0.000032 1.211112e-06 -8 2 1 3 1 total 0.000031 1.169911e-06 -9 2 1 4 1 total 0.000072 2.685832e-06 -10 2 1 5 1 total 0.000032 1.187072e-06 -11 2 1 6 1 total 0.000013 4.939053e-07 -18 2 2 1 1 total 0.000006 3.819684e-07 -19 2 2 2 1 total 0.000032 1.976073e-06 -20 2 2 3 1 total 0.000031 1.889748e-06 -21 2 2 4 1 total 0.000072 4.252207e-06 -22 2 2 5 1 total 0.000032 1.765565e-06 -23 2 2 6 1 total 0.000013 7.386890e-07 - mesh 1 delayedgroup group out nuclide mean std. dev. - x y -0 1 1 1 1 total 0.0 0.000000 -1 1 1 2 1 total 0.0 0.000000 -2 1 1 3 1 total 0.0 0.000000 -3 1 1 4 1 total 1.0 1.414214 -4 1 1 5 1 total 0.0 0.000000 -5 1 1 6 1 total 0.0 0.000000 -12 1 2 1 1 total 0.0 0.000000 -13 1 2 2 1 total 0.0 0.000000 -14 1 2 3 1 total 0.0 0.000000 -15 1 2 4 1 total 1.0 0.869026 -16 1 2 5 1 total 0.0 0.000000 -17 1 2 6 1 total 0.0 0.000000 -6 2 1 1 1 total 0.0 0.000000 -7 2 1 2 1 total 0.0 0.000000 -8 2 1 3 1 total 0.0 0.000000 -9 2 1 4 1 total 1.0 1.414214 -10 2 1 5 1 total 0.0 0.000000 -11 2 1 6 1 total 0.0 0.000000 -18 2 2 1 1 total 0.0 0.000000 -19 2 2 2 1 total 0.0 0.000000 -20 2 2 3 1 total 0.0 0.000000 -21 2 2 4 1 total 1.0 1.414214 -22 2 2 5 1 total 0.0 0.000000 -23 2 2 6 1 total 0.0 0.000000 - mesh 1 delayedgroup group in nuclide mean std. dev. - x y -0 1 1 1 1 total 0.000227 0.000023 -1 1 1 2 1 total 0.001210 0.000119 -2 1 1 3 1 total 0.001176 0.000114 -3 1 1 4 1 total 0.002722 0.000261 -4 1 1 5 1 total 0.001204 0.000112 -5 1 1 6 1 total 0.000501 0.000047 -12 1 2 1 1 total 0.000227 0.000017 -13 1 2 2 1 total 0.001208 0.000087 -14 1 2 3 1 total 0.001174 0.000084 -15 1 2 4 1 total 0.002710 0.000192 -16 1 2 5 1 total 0.001194 0.000082 -17 1 2 6 1 total 0.000497 0.000034 -6 2 1 1 1 total 0.000227 0.000010 -7 2 1 2 1 total 0.001210 0.000053 -8 2 1 3 1 total 0.001177 0.000052 -9 2 1 4 1 total 0.002726 0.000119 -10 2 1 5 1 total 0.001208 0.000053 -11 2 1 6 1 total 0.000503 0.000022 -18 2 2 1 1 total 0.000227 0.000019 -19 2 2 2 1 total 0.001211 0.000102 -20 2 2 3 1 total 0.001178 0.000098 -21 2 2 4 1 total 0.002726 0.000223 -22 2 2 5 1 total 0.001207 0.000096 -23 2 2 6 1 total 0.000503 0.000040 - mesh 1 delayedgroup nuclide mean std. dev. - x y -0 1 1 1 total 0.013353 0.001345 -1 1 1 2 total 0.032619 0.003120 -2 1 1 3 total 0.121042 0.011142 -3 1 1 4 total 0.305503 0.026418 -4 1 1 5 total 0.860433 0.064665 -5 1 1 6 total 2.889963 0.219527 -12 1 2 1 total 0.013352 0.001049 -13 1 2 2 total 0.032626 0.002465 -14 1 2 3 total 0.121027 0.008891 -15 1 2 4 total 0.305351 0.021426 -16 1 2 5 total 0.859866 0.054490 -17 1 2 6 total 2.888034 0.184436 -6 2 1 1 total 0.013353 0.000612 -7 2 1 2 total 0.032616 0.001412 -8 2 1 3 total 0.121047 0.005039 -9 2 1 4 total 0.305559 0.012002 -10 2 1 5 total 0.860640 0.030707 -11 2 1 6 total 2.890664 0.103692 -18 2 2 1 total 0.013353 0.001132 -19 2 2 2 total 0.032617 0.002633 -20 2 2 3 total 0.121046 0.009426 -21 2 2 4 total 0.305545 0.022417 -22 2 2 5 total 0.860588 0.055030 -23 2 2 6 total 2.890489 0.186821 - mesh 1 delayedgroup group in group out nuclide mean std. dev. - x y -0 1 1 1 1 1 total 0.000000 0.000000 -1 1 1 2 1 1 total 0.000000 0.000000 -2 1 1 3 1 1 total 0.000000 0.000000 -3 1 1 4 1 1 total 0.000219 0.000219 -4 1 1 5 1 1 total 0.000000 0.000000 -5 1 1 6 1 1 total 0.000000 0.000000 -12 1 2 1 1 1 total 0.000000 0.000000 -13 1 2 2 1 1 total 0.000000 0.000000 -14 1 2 3 1 1 total 0.000000 0.000000 -15 1 2 4 1 1 total 0.000467 0.000287 -16 1 2 5 1 1 total 0.000000 0.000000 -17 1 2 6 1 1 total 0.000000 0.000000 -6 2 1 1 1 1 total 0.000000 0.000000 -7 2 1 2 1 1 total 0.000000 0.000000 -8 2 1 3 1 1 total 0.000000 0.000000 -9 2 1 4 1 1 total 0.000211 0.000211 -10 2 1 5 1 1 total 0.000000 0.000000 -11 2 1 6 1 1 total 0.000000 0.000000 -18 2 2 1 1 1 total 0.000000 0.000000 -19 2 2 2 1 1 total 0.000000 0.000000 -20 2 2 3 1 1 total 0.000000 0.000000 -21 2 2 4 1 1 total 0.000219 0.000219 -22 2 2 5 1 1 total 0.000000 0.000000 -23 2 2 6 1 1 total 0.000000 0.000000 +29 2 2 y-min in 1 total 4.526 0.166571 +28 2 2 y-min out 1 total 4.548 0.156691 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.757948 0.035459 +2 1 2 1 1 total 0.779112 0.047034 +1 2 1 1 1 total 0.787475 0.050368 +3 2 2 1 1 total 0.769656 0.058065 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.757948 0.035459 +2 1 2 1 1 total 0.778934 0.047027 +1 2 1 1 1 total 0.787475 0.050368 +3 2 2 1 1 total 0.769656 0.058065 + mesh 1 delayedgroup group in nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.000006 3.699363e-07 +1 1 1 1 2 1 total 0.000030 1.914853e-06 +2 1 1 1 3 1 total 0.000029 1.834339e-06 +3 1 1 1 4 1 total 0.000068 4.149880e-06 +4 1 1 1 5 1 total 0.000030 1.769320e-06 +5 1 1 1 6 1 total 0.000013 7.382097e-07 +12 1 2 1 1 1 total 0.000006 4.767315e-07 +13 1 2 1 2 1 total 0.000030 2.471571e-06 +14 1 2 1 3 1 total 0.000029 2.368041e-06 +15 1 2 1 4 1 total 0.000068 5.351482e-06 +16 1 2 1 5 1 total 0.000030 2.259042e-06 +17 1 2 1 6 1 total 0.000013 9.436237e-07 +6 2 1 1 1 1 total 0.000005 6.400406e-07 +7 2 1 1 2 1 total 0.000029 3.309040e-06 +8 2 1 1 3 1 total 0.000029 3.163385e-06 +9 2 1 1 4 1 total 0.000067 7.114281e-06 +10 2 1 1 5 1 total 0.000030 2.951164e-06 +11 2 1 1 6 1 total 0.000012 1.234794e-06 +18 2 2 1 1 1 total 0.000006 5.212824e-07 +19 2 2 1 2 1 total 0.000030 2.712206e-06 +20 2 2 1 3 1 total 0.000029 2.604912e-06 +21 2 2 1 4 1 total 0.000068 5.914482e-06 +22 2 2 1 5 1 total 0.000030 2.531950e-06 +23 2 2 1 6 1 total 0.000013 1.056326e-06 + mesh 1 delayedgroup group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.0 0.000000 +1 1 1 1 2 1 total 0.0 0.000000 +2 1 1 1 3 1 total 0.0 0.000000 +3 1 1 1 4 1 total 1.0 1.414214 +4 1 1 1 5 1 total 1.0 1.414214 +5 1 1 1 6 1 total 0.0 0.000000 +12 1 2 1 1 1 total 0.0 0.000000 +13 1 2 1 2 1 total 0.0 0.000000 +14 1 2 1 3 1 total 0.0 0.000000 +15 1 2 1 4 1 total 0.0 0.000000 +16 1 2 1 5 1 total 0.0 0.000000 +17 1 2 1 6 1 total 0.0 0.000000 +6 2 1 1 1 1 total 0.0 0.000000 +7 2 1 1 2 1 total 0.0 0.000000 +8 2 1 1 3 1 total 0.0 0.000000 +9 2 1 1 4 1 total 0.0 0.000000 +10 2 1 1 5 1 total 0.0 0.000000 +11 2 1 1 6 1 total 0.0 0.000000 +18 2 2 1 1 1 total 0.0 0.000000 +19 2 2 1 2 1 total 1.0 1.414214 +20 2 2 1 3 1 total 0.0 0.000000 +21 2 2 1 4 1 total 0.0 0.000000 +22 2 2 1 5 1 total 0.0 0.000000 +23 2 2 1 6 1 total 0.0 0.000000 + mesh 1 delayedgroup group in nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.000227 0.000021 +1 1 1 1 2 1 total 0.001219 0.000109 +2 1 1 1 3 1 total 0.001191 0.000106 +3 1 1 1 4 1 total 0.002775 0.000243 +4 1 1 1 5 1 total 0.001249 0.000106 +5 1 1 1 6 1 total 0.000519 0.000044 +12 1 2 1 1 1 total 0.000227 0.000026 +13 1 2 1 2 1 total 0.001216 0.000140 +14 1 2 1 3 1 total 0.001187 0.000135 +15 1 2 1 4 1 total 0.002760 0.000309 +16 1 2 1 5 1 total 0.001236 0.000135 +17 1 2 1 6 1 total 0.000514 0.000056 +6 2 1 1 1 1 total 0.000227 0.000037 +7 2 1 1 2 1 total 0.001215 0.000194 +8 2 1 1 3 1 total 0.001184 0.000187 +9 2 1 1 4 1 total 0.002749 0.000428 +10 2 1 1 5 1 total 0.001227 0.000185 +11 2 1 1 6 1 total 0.000511 0.000077 +18 2 2 1 1 1 total 0.000227 0.000027 +19 2 2 1 2 1 total 0.001215 0.000145 +20 2 2 1 3 1 total 0.001185 0.000140 +21 2 2 1 4 1 total 0.002752 0.000321 +22 2 2 1 5 1 total 0.001229 0.000140 +23 2 2 1 6 1 total 0.000511 0.000058 + mesh 1 delayedgroup nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.013357 0.001250 +1 1 1 1 2 total 0.032589 0.002884 +2 1 1 1 3 total 0.121105 0.010300 +3 1 1 1 4 total 0.306138 0.024490 +4 1 1 1 5 total 0.862757 0.061312 +5 1 1 1 6 total 2.897868 0.207582 +12 1 2 1 1 total 0.013356 0.001625 +13 1 2 1 2 total 0.032597 0.003869 +14 1 2 1 3 total 0.121088 0.014125 +15 1 2 1 4 total 0.305963 0.034783 +16 1 2 1 5 total 0.862125 0.093434 +17 1 2 1 6 total 2.895716 0.314825 +6 2 1 1 1 total 0.013355 0.002181 +7 2 1 1 2 total 0.032604 0.005141 +8 2 1 1 3 total 0.121074 0.018615 +9 2 1 1 4 total 0.305828 0.045169 +10 2 1 1 5 total 0.861633 0.116817 +11 2 1 1 6 total 2.894042 0.394847 +18 2 2 1 1 total 0.013355 0.001620 +19 2 2 1 2 total 0.032602 0.003798 +20 2 2 1 3 total 0.121077 0.013715 +21 2 2 1 4 total 0.305857 0.033214 +22 2 2 1 5 total 0.861740 0.086567 +23 2 2 1 6 total 2.894407 0.292238 + mesh 1 delayedgroup group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 1 total 0.000000 0.000000 +1 1 1 1 2 1 1 total 0.000000 0.000000 +2 1 1 1 3 1 1 total 0.000000 0.000000 +3 1 1 1 4 1 1 total 0.000172 0.000172 +4 1 1 1 5 1 1 total 0.000192 0.000192 +5 1 1 1 6 1 1 total 0.000000 0.000000 +12 1 2 1 1 1 1 total 0.000000 0.000000 +13 1 2 1 2 1 1 total 0.000000 0.000000 +14 1 2 1 3 1 1 total 0.000000 0.000000 +15 1 2 1 4 1 1 total 0.000000 0.000000 +16 1 2 1 5 1 1 total 0.000000 0.000000 +17 1 2 1 6 1 1 total 0.000000 0.000000 +6 2 1 1 1 1 1 total 0.000000 0.000000 +7 2 1 1 2 1 1 total 0.000000 0.000000 +8 2 1 1 3 1 1 total 0.000000 0.000000 +9 2 1 1 4 1 1 total 0.000000 0.000000 +10 2 1 1 5 1 1 total 0.000000 0.000000 +11 2 1 1 6 1 1 total 0.000000 0.000000 +18 2 2 1 1 1 1 total 0.000000 0.000000 +19 2 2 1 2 1 1 total 0.000186 0.000186 +20 2 2 1 3 1 1 total 0.000000 0.000000 +21 2 2 1 4 1 1 total 0.000000 0.000000 +22 2 2 1 5 1 1 total 0.000000 0.000000 +23 2 2 1 6 1 1 total 0.000000 0.000000 diff --git a/tests/regression_tests/mgxs_library_condense/test.py b/tests/regression_tests/mgxs_library_condense/test.py index bbc4c11bf..a7e60617f 100644 --- a/tests/regression_tests/mgxs_library_condense/test.py +++ b/tests/regression_tests/mgxs_library_condense/test.py @@ -36,7 +36,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _get_results(self, hash_output=False): """Digest info in the statepoint and return as a string.""" diff --git a/tests/regression_tests/mgxs_library_correction/inputs_true.dat b/tests/regression_tests/mgxs_library_correction/inputs_true.dat index bb463778f..8c1cd4d16 100644 --- a/tests/regression_tests/mgxs_library_correction/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_correction/inputs_true.dat @@ -1,346 +1,344 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 0 - - - 2 - - - 3 - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 12 - total - scatter - analog - - - 1 3 4 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 12 - total - scatter - analog - - - 1 2 3 - total - nu-scatter - analog - - - 1 3 4 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 19 2 - total - flux - analog - - - 19 2 3 4 - total - scatter - analog - - - 19 2 - total - flux - analog - - - 19 2 3 4 - total - nu-scatter - analog - - - 19 2 - total - flux - tracklength - - - 19 2 - total - scatter - tracklength - - - 19 2 3 12 - total - scatter - analog - - - 19 3 4 - total - scatter - analog - - - 19 2 - total - flux - analog - - - 19 2 - total - flux - tracklength - - - 19 2 - total - scatter - tracklength - - - 19 2 3 12 - total - scatter - analog - - - 19 2 3 - total - nu-scatter - analog - - - 19 3 4 - total - nu-scatter - analog - - - 19 2 - total - flux - analog - - - 37 2 - total - flux - analog - - - 37 2 3 4 - total - scatter - analog - - - 37 2 - total - flux - analog - - - 37 2 3 4 - total - nu-scatter - analog - - - 37 2 - total - flux - tracklength - - - 37 2 - total - scatter - tracklength - - - 37 2 3 12 - total - scatter - analog - - - 37 3 4 - total - scatter - analog - - - 37 2 - total - flux - analog - - - 37 2 - total - flux - tracklength - - - 37 2 - total - scatter - tracklength - - - 37 2 3 12 - total - scatter - analog - - - 37 2 3 - total - nu-scatter - analog - - - 37 3 4 - total - nu-scatter - analog - - - 37 2 - total - flux - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 0 + + + 2 + + + 3 + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 12 + total + scatter + analog + + + 1 3 4 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 12 + total + scatter + analog + + + 1 2 3 + total + nu-scatter + analog + + + 1 3 4 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 19 2 + total + flux + analog + + + 19 2 3 4 + total + scatter + analog + + + 19 2 + total + flux + analog + + + 19 2 3 4 + total + nu-scatter + analog + + + 19 2 + total + flux + tracklength + + + 19 2 + total + scatter + tracklength + + + 19 2 3 12 + total + scatter + analog + + + 19 3 4 + total + scatter + analog + + + 19 2 + total + flux + analog + + + 19 2 + total + flux + tracklength + + + 19 2 + total + scatter + tracklength + + + 19 2 3 12 + total + scatter + analog + + + 19 2 3 + total + nu-scatter + analog + + + 19 3 4 + total + nu-scatter + analog + + + 19 2 + total + flux + analog + + + 37 2 + total + flux + analog + + + 37 2 3 4 + total + scatter + analog + + + 37 2 + total + flux + analog + + + 37 2 3 4 + total + nu-scatter + analog + + + 37 2 + total + flux + tracklength + + + 37 2 + total + scatter + tracklength + + + 37 2 3 12 + total + scatter + analog + + + 37 3 4 + total + scatter + analog + + + 37 2 + total + flux + analog + + + 37 2 + total + flux + tracklength + + + 37 2 + total + scatter + tracklength + + + 37 2 3 12 + total + scatter + analog + + + 37 2 3 + total + nu-scatter + analog + + + 37 3 4 + total + nu-scatter + analog + + + 37 2 + total + flux + analog + + diff --git a/tests/regression_tests/mgxs_library_correction/results_true.dat b/tests/regression_tests/mgxs_library_correction/results_true.dat index b6aaad044..690c9e4dc 100644 --- a/tests/regression_tests/mgxs_library_correction/results_true.dat +++ b/tests/regression_tests/mgxs_library_correction/results_true.dat @@ -1,60 +1,60 @@ material group in group out nuclide mean std. dev. -3 1 1 1 total 0.353477 0.019952 -2 1 1 2 total 0.000522 0.000349 +3 1 1 1 total 0.353219 0.011858 +2 1 1 2 total 0.000876 0.000554 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.414134 0.029955 +0 1 2 2 total 0.367572 0.024736 material group in group out nuclide mean std. dev. -3 1 1 1 total 0.353477 0.019952 -2 1 1 2 total 0.000522 0.000349 +3 1 1 1 total 0.353488 0.011854 +2 1 1 2 total 0.000876 0.000554 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.414134 0.029955 +0 1 2 2 total 0.367572 0.024736 material group in group out nuclide mean std. dev. -3 1 1 1 total 0.356124 0.026110 -2 1 1 2 total 0.000526 0.000352 +3 1 1 1 total 0.350138 0.017141 +2 1 1 2 total 0.000869 0.000551 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.413622 0.044755 +0 1 2 2 total 0.378130 0.046663 material group in group out nuclide mean std. dev. -3 1 1 1 total 0.356124 0.033873 -2 1 1 2 total 0.000526 0.000608 +3 1 1 1 total 0.350406 0.018910 +2 1 1 2 total 0.000869 0.000953 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.413622 0.054899 +0 1 2 2 total 0.378130 0.057580 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.261901 0.016456 -2 2 1 2 total 0.000000 0.000000 +3 2 1 1 total 0.272853 0.018051 +2 2 1 2 total 0.000486 0.000486 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.322376 0.044195 +0 2 2 2 total 0.287308 0.063393 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.261901 0.016456 -2 2 1 2 total 0.000000 0.000000 +3 2 1 1 total 0.272853 0.018051 +2 2 1 2 total 0.000486 0.000486 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.322376 0.044195 +0 2 2 2 total 0.287308 0.063393 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.266612 0.021169 -2 2 1 2 total 0.000000 0.000000 +3 2 1 1 total 0.273465 0.021487 +2 2 1 2 total 0.000487 0.000487 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.321966 0.054140 +0 2 2 2 total 0.294966 0.065882 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.266612 0.025384 -2 2 1 2 total 0.000000 0.000000 +3 2 1 1 total 0.273465 0.025834 +2 2 1 2 total 0.000487 0.000843 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.321966 0.068014 +0 2 2 2 total 0.294966 0.089321 material group in group out nuclide mean std. dev. -3 3 1 1 total 0.259426 0.012116 -2 3 1 2 total 0.031650 0.000613 -1 3 2 1 total 0.000474 0.000475 -0 3 2 2 total 1.416407 0.162435 +3 3 1 1 total 0.262301 0.012948 +2 3 1 2 total 0.029783 0.000974 +1 3 2 1 total 0.000000 0.000000 +0 3 2 2 total 1.418218 0.082199 material group in group out nuclide mean std. dev. -3 3 1 1 total 0.259426 0.012116 -2 3 1 2 total 0.031650 0.000613 -1 3 2 1 total 0.000474 0.000475 -0 3 2 2 total 1.416407 0.162435 +3 3 1 1 total 0.262301 0.012948 +2 3 1 2 total 0.029783 0.000974 +1 3 2 1 total 0.000000 0.000000 +0 3 2 2 total 1.418218 0.082199 material group in group out nuclide mean std. dev. -3 3 1 1 total 0.266083 0.024503 -2 3 1 2 total 0.031973 0.001157 -1 3 2 1 total 0.000477 0.000480 -0 3 2 2 total 1.427932 0.269812 +3 3 1 1 total 0.261486 0.022535 +2 3 1 2 total 0.029746 0.001063 +1 3 2 1 total 0.000000 0.000000 +0 3 2 2 total 1.432958 0.149985 material group in group out nuclide mean std. dev. -3 3 1 1 total 0.266083 0.027910 -2 3 1 2 total 0.031973 0.001391 -1 3 2 1 total 0.000477 0.000827 -0 3 2 2 total 1.427932 0.328026 +3 3 1 1 total 0.261486 0.026061 +2 3 1 2 total 0.029746 0.001468 +1 3 2 1 total 0.000000 0.000000 +0 3 2 2 total 1.432958 0.178757 diff --git a/tests/regression_tests/mgxs_library_correction/test.py b/tests/regression_tests/mgxs_library_correction/test.py index 64e638e44..05eedfef8 100644 --- a/tests/regression_tests/mgxs_library_correction/test.py +++ b/tests/regression_tests/mgxs_library_correction/test.py @@ -29,7 +29,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _get_results(self, hash_output=False): """Digest info in the statepoint and return as a string.""" diff --git a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat index e3826cc18..bd6abbb7c 100644 --- a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat @@ -1,43 +1,17 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -55,490 +29,514 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -10.71 -10.71 -1 10.71 10.71 1 - - - true - - - - - - 1 - - - 0.0 20000000.0 - - - 0.0 20000000.0 - - - 1 - - - 3 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - (n,3n) - tracklength - - - 1 2 - total - (n,4n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 2 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 75 2 - total - delayed-nu-fission - tracklength - - - 1 75 2 - total - delayed-nu-fission - analog - - - 1 75 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 75 2 - total - delayed-nu-fission - tracklength - - - 1 75 - total - delayed-nu-fission - tracklength - - - 1 75 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 75 2 5 - total - delayed-nu-fission - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -10.71 -10.71 -1 10.71 10.71 1 + + + + + + + 1 + + + 0.0 20000000.0 + + + 0.0 20000000.0 + + + 1 + + + 3 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 2 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 75 2 + total + delayed-nu-fission + tracklength + + + 1 75 2 + total + delayed-nu-fission + analog + + + 1 75 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 75 2 + total + delayed-nu-fission + tracklength + + + 1 75 + total + delayed-nu-fission + tracklength + + + 1 75 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 75 2 5 + total + delayed-nu-fission + analog + + diff --git a/tests/regression_tests/mgxs_library_distribcell/results_true.dat b/tests/regression_tests/mgxs_library_distribcell/results_true.dat index 127df75c1..3d362c1bd 100644 --- a/tests/regression_tests/mgxs_library_distribcell/results_true.dat +++ b/tests/regression_tests/mgxs_library_distribcell/results_true.dat @@ -1,97 +1,97 @@ sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.459656 0.010039 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.450382 0.010238 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.416327 0.01121 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.413436 0.011349 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.416327 0.01121 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.070545 0.002486 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.070348 0.002485 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.029374 0.002719 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.041172 0.001562 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.101218 0.003812 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 7.972654e+06 302079.851251 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.413276 0.011357 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.38911 0.00831 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.06484 0.002514 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.394876 0.014019 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.064761 0.002514 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.028638 0.002713 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.036203 0.001449 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.089088 0.003536 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 7.011996e+06 280281.488034 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.385542 0.008566 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.386602 0.013718 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.394876 0.014019 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.043329 0.004988 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.027490 0.003974 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.016004 0.003232 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.386439 0.013702 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.036946 0.004896 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016245 0.003818 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005544 0.003119 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.394876 0.014019 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.043329 0.004988 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.027490 0.003974 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.016004 0.003232 - sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 0.036306 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.386602 0.013718 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.037106 0.004917 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016398 0.003839 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005688 0.003138 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.097856 0.006191 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.000421 0.036026 + sum(distribcell) group in group out nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.083975 0.005759 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 0.036306 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 0.035985 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.389110 0.016390 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.042696 0.005009 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.027088 0.003964 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.015770 0.003204 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.385542 0.016305 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.036860 0.004958 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016207 0.003827 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005531 0.003114 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.389110 0.021638 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.042696 0.005244 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.027088 0.004084 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.015770 0.003255 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.385704 0.021424 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.036876 0.005135 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016214 0.003873 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005533 0.003122 sum(distribcell) group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.082469 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.090473 sum(distribcell) group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.082587 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.090571 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 5.626624e-07 2.235532e-08 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 4.896406e-07 2.047455e-08 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.100506 0.003787 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.088451 0.003512 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.097658 0.006185 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.082789 0.005683 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.800653 0.021558 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.806252 0.022131 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.800653 0.021558 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.806564 0.022166 sum(distribcell) delayedgroup group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000023 8.667436e-07 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.000122 4.499059e-06 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.000119 4.311220e-06 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.000275 9.735290e-06 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.000122 4.078954e-06 -5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000051 1.705327e-06 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000020 8.047454e-07 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.000108 4.184372e-06 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.000106 4.014315e-06 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.000246 9.085237e-06 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.000111 3.832957e-06 +5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000046 1.601490e-06 sum(distribcell) delayedgroup group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.0 0.000000 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 1.0 1.414214 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 1.414214 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.0 0.000000 2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.0 0.000000 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.0 0.000000 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.0 0.000000 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 1.0 0.708218 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 1.0 1.414214 5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.0 0.000000 sum(distribcell) delayedgroup group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000227 0.000011 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.001208 0.000059 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.001175 0.000056 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.002721 0.000129 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.001206 0.000055 -5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000502 0.000023 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000227 0.000012 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.001216 0.000062 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.001187 0.000060 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.002764 0.000138 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.001241 0.000060 +5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000516 0.000025 sum(distribcell) delayedgroup nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.013353 0.000658 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 total 0.032616 0.001562 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 total 0.121048 0.005678 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 total 0.305568 0.013868 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 total 0.860675 0.036434 -5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 total 2.890786 0.122997 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.013356 0.000697 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 total 0.032593 0.001644 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 total 0.121097 0.005963 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 total 0.306056 0.014519 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 total 0.862463 0.037889 +5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 total 2.896867 0.127967 sum(distribcell) delayedgroup group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 1 total 0.000000 0.000000 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 1 total 0.000198 0.000198 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 1 total 0.000189 0.000189 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 1 total 0.000000 0.000000 2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 1 total 0.000000 0.000000 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 1 total 0.000000 0.000000 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 1 total 0.000000 0.000000 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 1 total 0.000807 0.000405 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 1 total 0.000191 0.000191 5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 1 total 0.000000 0.000000 diff --git a/tests/regression_tests/mgxs_library_distribcell/test.py b/tests/regression_tests/mgxs_library_distribcell/test.py index 464b309c0..fd6c8e938 100644 --- a/tests/regression_tests/mgxs_library_distribcell/test.py +++ b/tests/regression_tests/mgxs_library_distribcell/test.py @@ -36,7 +36,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) self._model.tallies.export_to_xml() def _get_results(self, hash_output=False): diff --git a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat index 4451d214c..cac18ffcd 100644 --- a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat @@ -1,534 +1,532 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 2 2 - -100.0 -100.0 - 100.0 100.0 - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 1 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - (n,3n) - tracklength - - - 1 2 - total - (n,4n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 54 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 54 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 68 2 - total - current - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 79 2 - total - delayed-nu-fission - tracklength - - - 1 79 54 - total - delayed-nu-fission - analog - - - 1 79 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 79 2 - total - delayed-nu-fission - tracklength - - - 1 79 - total - delayed-nu-fission - tracklength - - - 1 79 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 79 2 5 - total - delayed-nu-fission - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 2 2 + -100.0 -100.0 + 100.0 100.0 + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 1 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 54 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 54 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 68 2 + total + current + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 54 + total + delayed-nu-fission + analog + + + 1 79 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 + total + delayed-nu-fission + tracklength + + + 1 79 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 79 2 5 + total + delayed-nu-fission + analog + + diff --git a/tests/regression_tests/mgxs_library_hdf5/results_true.dat b/tests/regression_tests/mgxs_library_hdf5/results_true.dat index 14d7371fe..b075939f2 100644 --- a/tests/regression_tests/mgxs_library_hdf5/results_true.dat +++ b/tests/regression_tests/mgxs_library_hdf5/results_true.dat @@ -1,201 +1,201 @@ domain=1 type=total -[5.66580451e-01 1.44262943e+00] -[1.96770003e-02 1.46112369e-01] +[5.62093429e-01 1.47762208e+00] +[1.25813379e-02 1.33969236e-01] domain=1 type=transport -[3.14856281e-01 1.05346368e+00] -[2.15203447e-02 1.60562179e-01] +[3.20646457e-01 1.15112225e+00] +[1.43813685e-02 1.38168210e-01] domain=1 type=nu-transport -[3.14856281e-01 1.05346368e+00] -[2.15203447e-02 1.60562179e-01] +[3.20646457e-01 1.15112225e+00] +[1.43813685e-02 1.38168210e-01] domain=1 type=absorption -[8.63921263e-03 9.70718967e-02] -[7.09849180e-04 9.96697703e-03] +[9.18204614e-03 9.50890834e-02] +[1.02291781e-03 9.51211716e-03] domain=1 type=reduced absorption -[8.63459183e-03 9.70718967e-02] -[7.09826160e-04 9.96697703e-03] +[9.15806809e-03 9.50890834e-02] +[1.02286279e-03 9.51211716e-03] domain=1 type=capture -[6.29732743e-03 4.01344183e-02] -[7.03181817e-04 9.43458504e-03] +[6.76780024e-03 4.04282690e-02] +[1.01848835e-03 8.89313901e-03] domain=1 type=fission -[2.34188519e-03 5.69374784e-02] -[1.04006997e-04 6.19904834e-03] +[2.41424590e-03 5.46608144e-02] +[4.85861462e-05 5.74352403e-03] domain=1 type=nu-fission -[5.93985124e-03 1.38739554e-01] -[2.57215008e-04 1.51052211e-02] +[6.13719950e-03 1.33192007e-01] +[1.12501202e-04 1.39952450e-02] domain=1 type=kappa-fission -[4.55876276e+05 1.10120160e+07] -[2.00450394e+04 1.19892945e+06] +[4.70267044e+05 1.05716969e+07] +[9.26434576e+03 1.11082859e+06] domain=1 type=scatter -[5.57941239e-01 1.34555753e+00] -[1.96103602e-02 1.38008873e-01] +[5.52911383e-01 1.38253299e+00] +[1.21249866e-02 1.25146938e-01] domain=1 type=nu-scatter -[5.53883536e-01 1.40126963e+00] -[1.89917740e-02 1.62647765e-01] +[5.53262132e-01 1.38285128e+00] +[1.67013167e-02 1.47879104e-01] domain=1 type=scatter matrix -[[[5.35878034e-01 2.51724170e-01 1.01011269e-01 1.03439439e-02] - [1.80055019e-02 5.80562809e-03 -1.57470166e-03 -2.27320020e-03]] +[[[5.38262098e-01 2.41446972e-01 9.56713637e-02 1.27736375e-02] + [1.50000342e-02 3.45918070e-03 -2.20959984e-03 -2.07635400e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.40126963e+00 3.55339640e-01 7.06453615e-02 4.04065595e-02]]] -[[[1.86010787e-02 8.71440749e-03 3.01351835e-03 5.22968320e-03] - [1.36795874e-03 6.67372701e-04 3.26122899e-04 8.68935369e-04]] + [1.38285128e+00 3.05915919e-01 2.70982432e-02 -1.60336325e-02]]] +[[[1.67044118e-02 6.96661310e-03 4.42653888e-03 5.36446548e-03] + [2.18467018e-03 6.35479378e-04 8.96740238e-04 4.72822150e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.62647765e-01 6.23420543e-02 9.61788834e-03 8.80966610e-03]]] + [1.47879104e-01 3.12865012e-02 2.09135204e-02 2.10640949e-02]]] domain=1 type=nu-scatter matrix -[[[5.35878034e-01 2.51724170e-01 1.01011269e-01 1.03439439e-02] - [1.80055019e-02 5.80562809e-03 -1.57470166e-03 -2.27320020e-03]] +[[[5.38262098e-01 2.41446972e-01 9.56713637e-02 1.27736375e-02] + [1.50000342e-02 3.45918070e-03 -2.20959984e-03 -2.07635400e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.40126963e+00 3.55339640e-01 7.06453615e-02 4.04065595e-02]]] -[[[1.86010787e-02 8.71440749e-03 3.01351835e-03 5.22968320e-03] - [1.36795874e-03 6.67372701e-04 3.26122899e-04 8.68935369e-04]] + [1.38285128e+00 3.05915919e-01 2.70982432e-02 -1.60336325e-02]]] +[[[1.67044118e-02 6.96661310e-03 4.42653888e-03 5.36446548e-03] + [2.18467018e-03 6.35479378e-04 8.96740238e-04 4.72822150e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.62647765e-01 6.23420543e-02 9.61788834e-03 8.80966610e-03]]] + [1.47879104e-01 3.12865012e-02 2.09135204e-02 2.10640949e-02]]] domain=1 type=multiplicity matrix [[1.00000000e+00 1.00000000e+00] [0.00000000e+00 1.00000000e+00]] -[[3.27047397e-02 1.01015254e-01] - [0.00000000e+00 1.16966513e-01]] +[[2.96568009e-02 2.03415491e-01] + [0.00000000e+00 1.02759493e-01]] domain=1 type=nu-fission matrix -[[7.11392182e-03 0.00000000e+00] - [1.52683850e-01 0.00000000e+00]] -[[1.05605314e-03 0.00000000e+00] - [2.58713491e-02 0.00000000e+00]] +[[4.80904641e-03 0.00000000e+00] + [1.46971102e-01 0.00000000e+00]] +[[7.56765200e-04 0.00000000e+00] + [1.60726822e-02 0.00000000e+00]] domain=1 type=scatter probability matrix -[[9.67492260e-01 3.25077399e-02] +[[9.72888016e-01 2.71119843e-02] [0.00000000e+00 1.00000000e+00]] -[[3.12124830e-02 2.43439942e-03] - [0.00000000e+00 1.16966513e-01]] +[[2.87160386e-02 3.94014457e-03] + [0.00000000e+00 1.02759493e-01]] domain=1 type=consistent scatter matrix -[[[5.39803830e-01 2.53568280e-01 1.01751269e-01 1.04197228e-02] - [1.81374087e-02 5.84815962e-03 -1.58623779e-03 -2.28985347e-03]] +[[[5.37920858e-01 2.41293903e-01 9.56107113e-02 1.27655394e-02] + [1.49905247e-02 3.45698770e-03 -2.20819902e-03 -2.07503766e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.34555753e+00 3.41211940e-01 6.78366221e-02 3.88000634e-02]]] -[[[2.57534994e-02 1.20804286e-02 4.50621873e-03 5.27902298e-03] - [1.50041314e-03 6.98980912e-04 3.32589287e-04 8.78503928e-04]] + [1.38253299e+00 3.05845506e-01 2.70920060e-02 -1.60299421e-02]]] +[[[1.97798945e-02 8.43331598e-03 4.80888930e-03 5.36697350e-03] + [2.20321323e-03 6.38726086e-04 8.97229401e-04 4.74291433e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [2.09324012e-01 6.95175402e-02 1.16044952e-02 9.36549883e-03]]] + [1.89328242e-01 4.07787000e-02 2.10367544e-02 2.11038436e-02]]] domain=1 type=consistent nu-scatter matrix -[[[5.39803830e-01 2.53568280e-01 1.01751269e-01 1.04197228e-02] - [1.81374087e-02 5.84815962e-03 -1.58623779e-03 -2.28985347e-03]] +[[[5.37920858e-01 2.41293903e-01 9.56107113e-02 1.27655394e-02] + [1.49905247e-02 3.45698770e-03 -2.20819902e-03 -2.07503766e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.34555753e+00 3.41211940e-01 6.78366221e-02 3.88000634e-02]]] -[[[3.12235732e-02 1.46529414e-02 5.60177820e-03 5.29001047e-03] - [2.36812824e-03 9.15185125e-04 3.69175618e-04 9.08445666e-04]] + [1.38253299e+00 3.05845506e-01 2.70920060e-02 -1.60299421e-02]]] +[[[2.54114701e-02 1.10602545e-02 5.58260879e-03 5.38030958e-03] + [3.76196879e-03 9.49983195e-04 1.00338675e-03 6.34914473e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [2.61890501e-01 8.01593794e-02 1.40578233e-02 1.04071518e-02]]] + [2.36703634e-01 5.14845104e-02 2.12201666e-02 2.11680319e-02]]] domain=1 type=chi [1.00000000e+00 0.00000000e+00] -[1.42429813e-01 0.00000000e+00] +[8.07756455e-02 0.00000000e+00] domain=1 type=chi-prompt [1.00000000e+00 0.00000000e+00] -[1.43958515e-01 0.00000000e+00] +[8.07424611e-02 0.00000000e+00] domain=1 type=inverse-velocity -[6.05275939e-08 2.92408191e-06] -[4.98534008e-09 2.95326306e-07] +[5.93309775e-08 2.99151502e-06] +[3.31163250e-09 2.75469881e-07] domain=1 type=prompt-nu-fission -[5.88433433e-03 1.37837093e-01] -[2.56012352e-04 1.50069660e-02] +[6.07803967e-03 1.32325631e-01] +[1.12229103e-04 1.39042100e-02] domain=1 type=prompt-nu-fission matrix -[[7.11392182e-03 0.00000000e+00] - [1.51190909e-01 0.00000000e+00]] -[[1.05605314e-03 0.00000000e+00] - [2.57973847e-02 0.00000000e+00]] +[[4.80904641e-03 0.00000000e+00] + [1.44441596e-01 0.00000000e+00]] +[[7.56765200e-04 0.00000000e+00] + [1.55945206e-02 0.00000000e+00]] domain=1 type=current -[[[0.00000000e+00 0.00000000e+00 3.71800000e+00 3.58600000e+00 - 0.00000000e+00 0.00000000e+00 3.62200000e+00 3.71800000e+00] - [0.00000000e+00 0.00000000e+00 6.60000000e-01 6.58000000e-01 - 0.00000000e+00 0.00000000e+00 6.62000000e-01 6.70000000e-01]] +[[[0.00000000e+00 0.00000000e+00 3.87200000e+00 3.85800000e+00 + 0.00000000e+00 0.00000000e+00 3.79800000e+00 3.79400000e+00] + [0.00000000e+00 0.00000000e+00 6.14000000e-01 6.62000000e-01 + 0.00000000e+00 0.00000000e+00 6.38000000e-01 6.12000000e-01]] - [[3.58600000e+00 3.71800000e+00 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 3.71200000e+00 3.60600000e+00] - [6.58000000e-01 6.60000000e-01 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 7.04000000e-01 6.74000000e-01]] + [[3.85800000e+00 3.87200000e+00 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 3.87000000e+00 3.85400000e+00] + [6.62000000e-01 6.14000000e-01 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 6.56000000e-01 6.94000000e-01]] - [[0.00000000e+00 0.00000000e+00 3.48600000e+00 3.60600000e+00 - 3.71800000e+00 3.62200000e+00 0.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00 6.66000000e-01 6.74000000e-01 - 6.70000000e-01 6.62000000e-01 0.00000000e+00 0.00000000e+00]] + [[0.00000000e+00 0.00000000e+00 3.77200000e+00 3.82200000e+00 + 3.79400000e+00 3.79800000e+00 0.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00 7.08000000e-01 6.38000000e-01 + 6.12000000e-01 6.38000000e-01 0.00000000e+00 0.00000000e+00]] - [[3.60600000e+00 3.48600000e+00 0.00000000e+00 0.00000000e+00 - 3.60600000e+00 3.71200000e+00 0.00000000e+00 0.00000000e+00] - [6.74000000e-01 6.66000000e-01 0.00000000e+00 0.00000000e+00 - 6.74000000e-01 7.04000000e-01 0.00000000e+00 0.00000000e+00]]] -[[[0.00000000e+00 0.00000000e+00 9.96192752e-02 8.73269718e-02 - 0.00000000e+00 0.00000000e+00 1.22531629e-01 1.08369737e-01] - [0.00000000e+00 0.00000000e+00 3.96232255e-02 4.06693988e-02 - 0.00000000e+00 0.00000000e+00 4.05462699e-02 4.27784993e-02]] + [[3.82200000e+00 3.77200000e+00 0.00000000e+00 0.00000000e+00 + 3.85400000e+00 3.87000000e+00 0.00000000e+00 0.00000000e+00] + [6.38000000e-01 7.08000000e-01 0.00000000e+00 0.00000000e+00 + 6.94000000e-01 6.56000000e-01 0.00000000e+00 0.00000000e+00]]] +[[[0.00000000e+00 0.00000000e+00 1.14952164e-01 1.04661359e-01 + 0.00000000e+00 0.00000000e+00 5.36097006e-02 1.14873844e-01] + [0.00000000e+00 0.00000000e+00 5.81893461e-02 6.31981012e-02 + 0.00000000e+00 0.00000000e+00 3.61109402e-02 1.98494332e-02]] - [[8.73269718e-02 9.96192752e-02 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 7.09506871e-02 5.27825729e-02] - [4.06693988e-02 3.96232255e-02 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 6.11228272e-02 5.88727441e-02]] + [[1.04661359e-01 1.14952164e-01 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 1.52643375e-01 1.35003704e-01] + [6.31981012e-02 5.81893461e-02 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 6.66783323e-02 7.95361553e-02]] - [[0.00000000e+00 0.00000000e+00 1.00279609e-01 1.31209756e-01 - 1.08369737e-01 1.22531629e-01 0.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00 6.05475020e-02 4.87442304e-02 - 4.27784993e-02 4.05462699e-02 0.00000000e+00 0.00000000e+00]] + [[0.00000000e+00 0.00000000e+00 1.58946532e-01 1.20971071e-01 + 1.14873844e-01 5.36097006e-02 0.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00 3.48425028e-02 2.08326667e-02 + 1.98494332e-02 3.61109402e-02 0.00000000e+00 0.00000000e+00]] - [[1.31209756e-01 1.00279609e-01 0.00000000e+00 0.00000000e+00 - 5.27825729e-02 7.09506871e-02 0.00000000e+00 0.00000000e+00] - [4.87442304e-02 6.05475020e-02 0.00000000e+00 0.00000000e+00 - 5.88727441e-02 6.11228272e-02 0.00000000e+00 0.00000000e+00]]] + [[1.20971071e-01 1.58946532e-01 0.00000000e+00 0.00000000e+00 + 1.35003704e-01 1.52643375e-01 0.00000000e+00 0.00000000e+00] + [2.08326667e-02 3.48425028e-02 0.00000000e+00 0.00000000e+00 + 7.95361553e-02 6.66783323e-02 0.00000000e+00 0.00000000e+00]]] domain=1 type=diffusion-coefficient -[1.05868408e+00 3.16416542e-01] -[7.23607812e-02 4.82261806e-02] +[1.03956656e+00 2.89572488e-01] +[4.66257756e-02 3.47571359e-02] domain=1 type=nu-diffusion-coefficient -[1.05868408e+00 3.16416542e-01] -[7.23607812e-02 4.82261806e-02] +[1.03956656e+00 2.89572488e-01] +[4.66257756e-02 3.47571359e-02] domain=1 type=delayed-nu-fission -[[1.33370452e-06 3.15928985e-05] - [8.06563789e-06 1.63072885e-04] - [8.37555675e-06 1.55683610e-04] - [2.14225848e-05 3.49055766e-04] - [1.15633419e-05 1.43108212e-04] - [4.74849054e-06 5.99475175e-05]] -[[5.58190638e-08 3.43966581e-06] - [2.80924725e-07 1.77545031e-05] - [2.81900859e-07 1.69499982e-05] - [7.44207592e-07 3.80033227e-05] - [4.95821820e-07 1.55808550e-05] - [2.00315983e-07 6.52676436e-06]] +[[1.37840363e-06 3.03296462e-05] + [8.45663047e-06 1.56552364e-04] + [8.84043266e-06 1.49458552e-04] + [2.28234463e-05 3.35098665e-04] + [1.25147617e-05 1.37385990e-04] + [5.13410858e-06 5.75504990e-05]] +[[2.55826273e-08 3.18690909e-06] + [1.59619691e-07 1.64498503e-05] + [2.08725713e-07 1.57044628e-05] + [7.35913253e-07 3.52107280e-05] + [6.08970534e-07 1.44359288e-05] + [2.44376821e-07 6.04715887e-06]] domain=1 type=chi-delayed [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] [1.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00] + [1.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] [1.41421356e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00] + [1.41421356e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]] domain=1 type=beta -[[2.24535003e-04 2.27713710e-04] - [1.35788550e-03 1.17538857e-03] - [1.41006170e-03 1.12212852e-03] - [3.60658609e-03 2.51590665e-03] - [1.94673931e-03 1.03148820e-03] - [7.99429201e-04 4.32086711e-04]] -[[1.15072629e-05 2.77827007e-05] - [6.20475481e-05 1.43405806e-04] - [6.31808205e-05 1.36907698e-04] - [1.64551758e-04 3.06958585e-04] - [1.01406915e-04 1.25848924e-04] - [4.11875799e-05 5.27176635e-05]] +[[2.24598146e-04 2.27713712e-04] + [1.37792986e-03 1.17538858e-03] + [1.44046689e-03 1.12212854e-03] + [3.71886987e-03 2.51590672e-03] + [2.03916489e-03 1.03148825e-03] + [8.36555595e-04 4.32086733e-04]] +[[2.89454288e-06 2.65002712e-05] + [1.83788053e-05 1.36786298e-04] + [2.80459046e-05 1.30588139e-04] + [1.09140523e-04 2.92789605e-04] + [9.54156078e-05 1.20039834e-04] + [3.82194001e-05 5.02842563e-05]] domain=1 type=decay-rate -[1.33525569e-02 3.26187089e-02 1.21041926e-01 3.05503129e-01 - 8.60433350e-01 2.88996258e+00] -[1.34484408e-03 3.11955840e-03 1.11418058e-02 2.64184722e-02 - 6.46651447e-02 2.19526509e-01] +[1.33568264e-02 3.25888950e-02 1.21105369e-01 3.06137651e-01 + 8.62756682e-01 2.89786766e+00] +[1.25011470e-03 2.88396059e-03 1.03002481e-02 2.44903689e-02 + 6.13119717e-02 2.07581680e-01] domain=1 type=delayed-nu-fission matrix [[[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]] @@ -207,10 +207,10 @@ domain=1 type=delayed-nu-fission matrix [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [1.49294023e-03 0.00000000e+00]] + [1.19201367e-03 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00]] + [1.33749216e-03 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]]] @@ -224,10 +224,10 @@ domain=1 type=delayed-nu-fission matrix [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [1.49788268e-03 0.00000000e+00]] + [1.19567703e-03 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00]] + [1.34160260e-03 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]]] diff --git a/tests/regression_tests/mgxs_library_hdf5/test.py b/tests/regression_tests/mgxs_library_hdf5/test.py index 4fb4bf093..2f3c9d149 100644 --- a/tests/regression_tests/mgxs_library_hdf5/test.py +++ b/tests/regression_tests/mgxs_library_hdf5/test.py @@ -40,7 +40,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _get_results(self, hash_output=False): """Digest info in the statepoint and return as a string.""" @@ -54,11 +54,6 @@ class MGXSTestHarness(PyAPITestHarness): # Export the MGXS Library to an HDF5 file self.mgxs_lib.build_hdf5_store(directory='.') - # Test export of the MGXS Library to an Excel spreadsheet - for mgxs in self.mgxs_lib.all_mgxs.values(): - for xs in mgxs.values(): - xs.export_xs_data('mgxs', xs_type='macro', format='excel') - # Open the MGXS HDF5 file with h5py.File('mgxs.h5', 'r') as f: @@ -81,8 +76,9 @@ class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() - files = ['mgxs.h5', 'mgxs.xlsx'] - (os.remove(f) for f in files if os.path.exists(f)) + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) def test_mgxs_library_hdf5(): diff --git a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat index 94c656418..d1bd197a7 100644 --- a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat @@ -1,271 +1,269 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - -1.0 -0.8181818181818181 -0.6363636363636364 -0.4545454545454546 -0.2727272727272727 -0.09090909090909083 0.09090909090909083 0.2727272727272727 0.4545454545454546 0.6363636363636365 0.8181818181818183 1.0 - - - 2 - - - 3 - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 4 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 4 - total - scatter - analog - - - 1 2 3 - total - nu-scatter - analog - - - 17 2 - total - flux - analog - - - 17 2 3 4 - total - scatter - analog - - - 17 2 - total - flux - analog - - - 17 2 3 4 - total - nu-scatter - analog - - - 17 2 - total - flux - tracklength - - - 17 2 - total - scatter - tracklength - - - 17 2 3 4 - total - scatter - analog - - - 17 2 - total - flux - tracklength - - - 17 2 - total - scatter - tracklength - - - 17 2 3 4 - total - scatter - analog - - - 17 2 3 - total - nu-scatter - analog - - - 33 2 - total - flux - analog - - - 33 2 3 4 - total - scatter - analog - - - 33 2 - total - flux - analog - - - 33 2 3 4 - total - nu-scatter - analog - - - 33 2 - total - flux - tracklength - - - 33 2 - total - scatter - tracklength - - - 33 2 3 4 - total - scatter - analog - - - 33 2 - total - flux - tracklength - - - 33 2 - total - scatter - tracklength - - - 33 2 3 4 - total - scatter - analog - - - 33 2 3 - total - nu-scatter - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + -1.0 -0.8181818181818181 -0.6363636363636364 -0.4545454545454546 -0.2727272727272727 -0.09090909090909083 0.09090909090909083 0.2727272727272727 0.4545454545454546 0.6363636363636365 0.8181818181818183 1.0 + + + 2 + + + 3 + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 4 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 4 + total + scatter + analog + + + 1 2 3 + total + nu-scatter + analog + + + 17 2 + total + flux + analog + + + 17 2 3 4 + total + scatter + analog + + + 17 2 + total + flux + analog + + + 17 2 3 4 + total + nu-scatter + analog + + + 17 2 + total + flux + tracklength + + + 17 2 + total + scatter + tracklength + + + 17 2 3 4 + total + scatter + analog + + + 17 2 + total + flux + tracklength + + + 17 2 + total + scatter + tracklength + + + 17 2 3 4 + total + scatter + analog + + + 17 2 3 + total + nu-scatter + analog + + + 33 2 + total + flux + analog + + + 33 2 3 4 + total + scatter + analog + + + 33 2 + total + flux + analog + + + 33 2 3 4 + total + nu-scatter + analog + + + 33 2 + total + flux + tracklength + + + 33 2 + total + scatter + tracklength + + + 33 2 3 4 + total + scatter + analog + + + 33 2 + total + flux + tracklength + + + 33 2 + total + scatter + tracklength + + + 33 2 3 4 + total + scatter + analog + + + 33 2 3 + total + nu-scatter + analog + + diff --git a/tests/regression_tests/mgxs_library_histogram/results_true.dat b/tests/regression_tests/mgxs_library_histogram/results_true.dat index f927d057e..74ae456e5 100644 --- a/tests/regression_tests/mgxs_library_histogram/results_true.dat +++ b/tests/regression_tests/mgxs_library_histogram/results_true.dat @@ -1,115 +1,25 @@ material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.029945 0.003043 -34 1 1 1 2 total 0.028378 0.003793 -35 1 1 1 3 total 0.033079 0.002866 -36 1 1 1 4 total 0.030119 0.002259 -37 1 1 1 5 total 0.033601 0.003739 -38 1 1 1 6 total 0.035516 0.001929 -39 1 1 1 7 total 0.032382 0.001744 -40 1 1 1 8 total 0.031860 0.002565 -41 1 1 1 9 total 0.038302 0.004757 -42 1 1 1 10 total 0.041784 0.003047 -43 1 1 1 11 total 0.057453 0.003686 -22 1 1 2 1 total 0.000174 0.000174 -23 1 1 2 2 total 0.000000 0.000000 -24 1 1 2 3 total 0.000174 0.000174 -25 1 1 2 4 total 0.000174 0.000174 -26 1 1 2 5 total 0.000000 0.000000 -27 1 1 2 6 total 0.000000 0.000000 -28 1 1 2 7 total 0.000000 0.000000 -29 1 1 2 8 total 0.000000 0.000000 -30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000000 0.000000 -32 1 1 2 11 total 0.000000 0.000000 -11 1 2 1 1 total 0.000000 0.000000 -12 1 2 1 2 total 0.000000 0.000000 -13 1 2 1 3 total 0.000000 0.000000 -14 1 2 1 4 total 0.000000 0.000000 -15 1 2 1 5 total 0.000000 0.000000 -16 1 2 1 6 total 0.000000 0.000000 -17 1 2 1 7 total 0.000000 0.000000 -18 1 2 1 8 total 0.000000 0.000000 -19 1 2 1 9 total 0.000000 0.000000 -20 1 2 1 10 total 0.000000 0.000000 -21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.037212 0.004892 -1 1 2 2 2 total 0.039224 0.003682 -2 1 2 2 3 total 0.044253 0.005869 -3 1 2 2 4 total 0.043247 0.004970 -4 1 2 2 5 total 0.025144 0.006632 -5 1 2 2 6 total 0.037212 0.009199 -6 1 2 2 7 total 0.035201 0.008964 -7 1 2 2 8 total 0.041235 0.009733 -8 1 2 2 9 total 0.032184 0.002384 -9 1 2 2 10 total 0.026149 0.006714 -10 1 2 2 11 total 0.035201 0.008073 - material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.029945 0.003043 -34 1 1 1 2 total 0.028378 0.003793 -35 1 1 1 3 total 0.033079 0.002866 -36 1 1 1 4 total 0.030119 0.002259 -37 1 1 1 5 total 0.033601 0.003739 -38 1 1 1 6 total 0.035516 0.001929 -39 1 1 1 7 total 0.032382 0.001744 -40 1 1 1 8 total 0.031860 0.002565 -41 1 1 1 9 total 0.038302 0.004757 -42 1 1 1 10 total 0.041784 0.003047 -43 1 1 1 11 total 0.057453 0.003686 -22 1 1 2 1 total 0.000174 0.000174 -23 1 1 2 2 total 0.000000 0.000000 -24 1 1 2 3 total 0.000174 0.000174 -25 1 1 2 4 total 0.000174 0.000174 -26 1 1 2 5 total 0.000000 0.000000 -27 1 1 2 6 total 0.000000 0.000000 -28 1 1 2 7 total 0.000000 0.000000 -29 1 1 2 8 total 0.000000 0.000000 -30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000000 0.000000 -32 1 1 2 11 total 0.000000 0.000000 -11 1 2 1 1 total 0.000000 0.000000 -12 1 2 1 2 total 0.000000 0.000000 -13 1 2 1 3 total 0.000000 0.000000 -14 1 2 1 4 total 0.000000 0.000000 -15 1 2 1 5 total 0.000000 0.000000 -16 1 2 1 6 total 0.000000 0.000000 -17 1 2 1 7 total 0.000000 0.000000 -18 1 2 1 8 total 0.000000 0.000000 -19 1 2 1 9 total 0.000000 0.000000 -20 1 2 1 10 total 0.000000 0.000000 -21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.037212 0.004892 -1 1 2 2 2 total 0.039224 0.003682 -2 1 2 2 3 total 0.044253 0.005869 -3 1 2 2 4 total 0.043247 0.004970 -4 1 2 2 5 total 0.025144 0.006632 -5 1 2 2 6 total 0.037212 0.009199 -6 1 2 2 7 total 0.035201 0.008964 -7 1 2 2 8 total 0.041235 0.009733 -8 1 2 2 9 total 0.032184 0.002384 -9 1 2 2 10 total 0.026149 0.006714 -10 1 2 2 11 total 0.035201 0.008073 - material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.030147 0.003165 -34 1 1 1 2 total 0.028570 0.003893 -35 1 1 1 3 total 0.033302 0.003016 -36 1 1 1 4 total 0.030322 0.002411 -37 1 1 1 5 total 0.033828 0.003868 -38 1 1 1 6 total 0.035756 0.002159 -39 1 1 1 7 total 0.032601 0.001955 -40 1 1 1 8 total 0.032075 0.002718 -41 1 1 1 9 total 0.038560 0.004896 -42 1 1 1 10 total 0.042066 0.003262 -43 1 1 1 11 total 0.057840 0.004013 -22 1 1 2 1 total 0.000175 0.000175 -23 1 1 2 2 total 0.000000 0.000000 +33 1 1 1 1 total 0.028385 0.002919 +34 1 1 1 2 total 0.031890 0.001548 +35 1 1 1 3 total 0.027684 0.002596 +36 1 1 1 4 total 0.035920 0.003337 +37 1 1 1 5 total 0.034343 0.001897 +38 1 1 1 6 total 0.032591 0.002289 +39 1 1 1 7 total 0.033467 0.002209 +40 1 1 1 8 total 0.031714 0.002398 +41 1 1 1 9 total 0.033467 0.003343 +42 1 1 1 10 total 0.041001 0.002362 +43 1 1 1 11 total 0.060801 0.003580 +22 1 1 2 1 total 0.000000 0.000000 +23 1 1 2 2 total 0.000350 0.000351 24 1 1 2 3 total 0.000175 0.000175 -25 1 1 2 4 total 0.000175 0.000175 -26 1 1 2 5 total 0.000000 0.000000 +25 1 1 2 4 total 0.000000 0.000000 +26 1 1 2 5 total 0.000175 0.000175 27 1 1 2 6 total 0.000000 0.000000 28 1 1 2 7 total 0.000000 0.000000 29 1 1 2 8 total 0.000000 0.000000 30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000000 0.000000 +31 1 1 2 10 total 0.000175 0.000175 32 1 1 2 11 total 0.000000 0.000000 11 1 2 1 1 total 0.000000 0.000000 12 1 2 1 2 total 0.000000 0.000000 @@ -122,39 +32,39 @@ 19 1 2 1 9 total 0.000000 0.000000 20 1 2 1 10 total 0.000000 0.000000 21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.037164 0.005797 -1 1 2 2 2 total 0.039173 0.004933 -2 1 2 2 3 total 0.044195 0.006937 -3 1 2 2 4 total 0.043191 0.006147 -4 1 2 2 5 total 0.025111 0.006951 -5 1 2 2 6 total 0.037164 0.009702 -6 1 2 2 7 total 0.035155 0.009426 -7 1 2 2 8 total 0.041182 0.010317 -8 1 2 2 9 total 0.032142 0.003598 -9 1 2 2 10 total 0.026115 0.007055 -10 1 2 2 11 total 0.035155 0.008586 +0 1 2 2 1 total 0.023599 0.005270 +1 1 2 2 2 total 0.036471 0.008401 +2 1 2 2 3 total 0.034325 0.003271 +3 1 2 2 4 total 0.030035 0.003674 +4 1 2 2 5 total 0.039688 0.001478 +5 1 2 2 6 total 0.033253 0.005499 +6 1 2 2 7 total 0.039688 0.004725 +7 1 2 2 8 total 0.031107 0.006458 +8 1 2 2 9 total 0.031107 0.005996 +9 1 2 2 10 total 0.052560 0.005543 +10 1 2 2 11 total 0.033253 0.002688 material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.030147 0.003454 -34 1 1 1 2 total 0.028570 0.004107 -35 1 1 1 3 total 0.033302 0.003381 -36 1 1 1 4 total 0.030322 0.002783 -37 1 1 1 5 total 0.033828 0.004168 -38 1 1 1 6 total 0.035756 0.002711 -39 1 1 1 7 total 0.032601 0.002461 -40 1 1 1 8 total 0.032075 0.003090 -41 1 1 1 9 total 0.038560 0.005205 -42 1 1 1 10 total 0.042066 0.003790 -43 1 1 1 11 total 0.057840 0.004811 -22 1 1 2 1 total 0.000175 0.000234 -23 1 1 2 2 total 0.000000 0.000000 -24 1 1 2 3 total 0.000175 0.000234 -25 1 1 2 4 total 0.000175 0.000234 -26 1 1 2 5 total 0.000000 0.000000 +33 1 1 1 1 total 0.028385 0.002919 +34 1 1 1 2 total 0.031890 0.001548 +35 1 1 1 3 total 0.027860 0.002738 +36 1 1 1 4 total 0.035920 0.003337 +37 1 1 1 5 total 0.034343 0.001897 +38 1 1 1 6 total 0.032591 0.002289 +39 1 1 1 7 total 0.033467 0.002209 +40 1 1 1 8 total 0.031714 0.002398 +41 1 1 1 9 total 0.033467 0.003343 +42 1 1 1 10 total 0.041001 0.002362 +43 1 1 1 11 total 0.060801 0.003580 +22 1 1 2 1 total 0.000000 0.000000 +23 1 1 2 2 total 0.000350 0.000351 +24 1 1 2 3 total 0.000175 0.000175 +25 1 1 2 4 total 0.000000 0.000000 +26 1 1 2 5 total 0.000175 0.000175 27 1 1 2 6 total 0.000000 0.000000 28 1 1 2 7 total 0.000000 0.000000 29 1 1 2 8 total 0.000000 0.000000 30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000000 0.000000 +31 1 1 2 10 total 0.000175 0.000175 32 1 1 2 11 total 0.000000 0.000000 11 1 2 1 1 total 0.000000 0.000000 12 1 2 1 2 total 0.000000 0.000000 @@ -167,29 +77,119 @@ 19 1 2 1 9 total 0.000000 0.000000 20 1 2 1 10 total 0.000000 0.000000 21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.037164 0.006511 -1 1 2 2 2 total 0.039173 0.005840 -2 1 2 2 3 total 0.044195 0.007782 -3 1 2 2 4 total 0.043191 0.007047 -4 1 2 2 5 total 0.025111 0.007234 -5 1 2 2 6 total 0.037164 0.010146 -6 1 2 2 7 total 0.035155 0.009835 -7 1 2 2 8 total 0.041182 0.010828 -8 1 2 2 9 total 0.032142 0.004419 -9 1 2 2 10 total 0.026115 0.007356 -10 1 2 2 11 total 0.035155 0.009032 +0 1 2 2 1 total 0.023599 0.005270 +1 1 2 2 2 total 0.036471 0.008401 +2 1 2 2 3 total 0.034325 0.003271 +3 1 2 2 4 total 0.030035 0.003674 +4 1 2 2 5 total 0.039688 0.001478 +5 1 2 2 6 total 0.033253 0.005499 +6 1 2 2 7 total 0.039688 0.004725 +7 1 2 2 8 total 0.031107 0.006458 +8 1 2 2 9 total 0.031107 0.005996 +9 1 2 2 10 total 0.052560 0.005543 +10 1 2 2 11 total 0.033253 0.002688 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025373 0.004281 -34 2 1 1 2 total 0.023909 0.004395 -35 2 1 1 3 total 0.019518 0.003911 -36 2 1 1 4 total 0.019518 0.003424 -37 2 1 1 5 total 0.020006 0.002901 -38 2 1 1 6 total 0.024885 0.005801 -39 2 1 1 7 total 0.019030 0.002566 -40 2 1 1 8 total 0.030741 0.001410 -41 2 1 1 9 total 0.034156 0.002902 -42 2 1 1 10 total 0.042939 0.004498 -43 2 1 1 11 total 0.054650 0.003865 +33 1 1 1 1 total 0.028162 0.003056 +34 1 1 1 2 total 0.031639 0.001886 +35 1 1 1 3 total 0.027466 0.002746 +36 1 1 1 4 total 0.035637 0.003533 +37 1 1 1 5 total 0.034072 0.002221 +38 1 1 1 6 total 0.032334 0.002532 +39 1 1 1 7 total 0.033203 0.002475 +40 1 1 1 8 total 0.031465 0.002617 +41 1 1 1 9 total 0.033203 0.003510 +42 1 1 1 10 total 0.040678 0.002734 +43 1 1 1 11 total 0.060322 0.004120 +22 1 1 2 1 total 0.000000 0.000000 +23 1 1 2 2 total 0.000348 0.000348 +24 1 1 2 3 total 0.000174 0.000174 +25 1 1 2 4 total 0.000000 0.000000 +26 1 1 2 5 total 0.000174 0.000174 +27 1 1 2 6 total 0.000000 0.000000 +28 1 1 2 7 total 0.000000 0.000000 +29 1 1 2 8 total 0.000000 0.000000 +30 1 1 2 9 total 0.000000 0.000000 +31 1 1 2 10 total 0.000174 0.000174 +32 1 1 2 11 total 0.000000 0.000000 +11 1 2 1 1 total 0.000000 0.000000 +12 1 2 1 2 total 0.000000 0.000000 +13 1 2 1 3 total 0.000000 0.000000 +14 1 2 1 4 total 0.000000 0.000000 +15 1 2 1 5 total 0.000000 0.000000 +16 1 2 1 6 total 0.000000 0.000000 +17 1 2 1 7 total 0.000000 0.000000 +18 1 2 1 8 total 0.000000 0.000000 +19 1 2 1 9 total 0.000000 0.000000 +20 1 2 1 10 total 0.000000 0.000000 +21 1 2 1 11 total 0.000000 0.000000 +0 1 2 2 1 total 0.024246 0.005837 +1 1 2 2 2 total 0.037470 0.009265 +2 1 2 2 3 total 0.035266 0.004620 +3 1 2 2 4 total 0.030858 0.004684 +4 1 2 2 5 total 0.040777 0.003968 +5 1 2 2 6 total 0.034164 0.006431 +6 1 2 2 7 total 0.040777 0.006083 +7 1 2 2 8 total 0.031960 0.007230 +8 1 2 2 9 total 0.031960 0.006797 +9 1 2 2 10 total 0.054002 0.007483 +10 1 2 2 11 total 0.034164 0.004130 + material group in group out mu bin nuclide mean std. dev. +33 1 1 1 1 total 0.028174 0.003144 +34 1 1 1 2 total 0.031653 0.002058 +35 1 1 1 3 total 0.027479 0.002838 +36 1 1 1 4 total 0.035653 0.003654 +37 1 1 1 5 total 0.034088 0.002392 +38 1 1 1 6 total 0.032348 0.002668 +39 1 1 1 7 total 0.033218 0.002621 +40 1 1 1 8 total 0.031479 0.002742 +41 1 1 1 9 total 0.033218 0.003616 +42 1 1 1 10 total 0.040696 0.002931 +43 1 1 1 11 total 0.060349 0.004409 +22 1 1 2 1 total 0.000000 0.000000 +23 1 1 2 2 total 0.000348 0.000451 +24 1 1 2 3 total 0.000174 0.000225 +25 1 1 2 4 total 0.000000 0.000000 +26 1 1 2 5 total 0.000174 0.000225 +27 1 1 2 6 total 0.000000 0.000000 +28 1 1 2 7 total 0.000000 0.000000 +29 1 1 2 8 total 0.000000 0.000000 +30 1 1 2 9 total 0.000000 0.000000 +31 1 1 2 10 total 0.000174 0.000225 +32 1 1 2 11 total 0.000000 0.000000 +11 1 2 1 1 total 0.000000 0.000000 +12 1 2 1 2 total 0.000000 0.000000 +13 1 2 1 3 total 0.000000 0.000000 +14 1 2 1 4 total 0.000000 0.000000 +15 1 2 1 5 total 0.000000 0.000000 +16 1 2 1 6 total 0.000000 0.000000 +17 1 2 1 7 total 0.000000 0.000000 +18 1 2 1 8 total 0.000000 0.000000 +19 1 2 1 9 total 0.000000 0.000000 +20 1 2 1 10 total 0.000000 0.000000 +21 1 2 1 11 total 0.000000 0.000000 +0 1 2 2 1 total 0.024246 0.006112 +1 1 2 2 2 total 0.037470 0.009679 +2 1 2 2 3 total 0.035266 0.005319 +3 1 2 2 4 total 0.030858 0.005221 +4 1 2 2 5 total 0.040777 0.005003 +5 1 2 2 6 total 0.034164 0.006919 +6 1 2 2 7 total 0.040777 0.006803 +7 1 2 2 8 total 0.031960 0.007614 +8 1 2 2 9 total 0.031960 0.007205 +9 1 2 2 10 total 0.054002 0.008502 +10 1 2 2 11 total 0.034164 0.004856 + material group in group out mu bin nuclide mean std. dev. +33 2 1 1 1 total 0.025262 0.003309 +34 2 1 1 2 total 0.023805 0.004083 +35 2 1 1 3 total 0.027205 0.001631 +36 2 1 1 4 total 0.021376 0.003175 +37 2 1 1 5 total 0.017489 0.002412 +38 2 1 1 6 total 0.024291 0.002862 +39 2 1 1 7 total 0.029634 0.005250 +40 2 1 1 8 total 0.025262 0.001228 +41 2 1 1 9 total 0.028663 0.003403 +42 2 1 1 10 total 0.034493 0.004425 +43 2 1 1 11 total 0.052467 0.006227 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -199,7 +199,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000000 0.000000 +31 2 1 2 10 total 0.000486 0.000486 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -212,29 +212,29 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.026892 0.012233 -1 2 2 2 2 total 0.034959 0.007449 -2 2 2 2 3 total 0.040337 0.009144 -3 2 2 2 4 total 0.021513 0.003750 -4 2 2 2 5 total 0.018824 0.005602 -5 2 2 2 6 total 0.026892 0.004806 -6 2 2 2 7 total 0.037648 0.012716 -7 2 2 2 8 total 0.026892 0.009768 -8 2 2 2 9 total 0.024202 0.005420 -9 2 2 2 10 total 0.018824 0.010183 -10 2 2 2 11 total 0.018824 0.007033 +0 2 2 2 1 total 0.032689 0.010313 +1 2 2 2 2 total 0.035958 0.011071 +2 2 2 2 3 total 0.019614 0.012398 +3 2 2 2 4 total 0.022883 0.009072 +4 2 2 2 5 total 0.009807 0.009926 +5 2 2 2 6 total 0.029420 0.011781 +6 2 2 2 7 total 0.032689 0.014602 +7 2 2 2 8 total 0.019614 0.006844 +8 2 2 2 9 total 0.032689 0.010313 +9 2 2 2 10 total 0.022883 0.009072 +10 2 2 2 11 total 0.029420 0.005650 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025373 0.004281 -34 2 1 1 2 total 0.023909 0.004395 -35 2 1 1 3 total 0.019518 0.003911 -36 2 1 1 4 total 0.019518 0.003424 -37 2 1 1 5 total 0.020006 0.002901 -38 2 1 1 6 total 0.024885 0.005801 -39 2 1 1 7 total 0.019030 0.002566 -40 2 1 1 8 total 0.030741 0.001410 -41 2 1 1 9 total 0.034156 0.002902 -42 2 1 1 10 total 0.042939 0.004498 -43 2 1 1 11 total 0.054650 0.003865 +33 2 1 1 1 total 0.025262 0.003309 +34 2 1 1 2 total 0.023805 0.004083 +35 2 1 1 3 total 0.027205 0.001631 +36 2 1 1 4 total 0.021376 0.003175 +37 2 1 1 5 total 0.017489 0.002412 +38 2 1 1 6 total 0.024291 0.002862 +39 2 1 1 7 total 0.029634 0.005250 +40 2 1 1 8 total 0.025262 0.001228 +41 2 1 1 9 total 0.028663 0.003403 +42 2 1 1 10 total 0.034493 0.004425 +43 2 1 1 11 total 0.052467 0.006227 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -244,7 +244,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000000 0.000000 +31 2 1 2 10 total 0.000486 0.000486 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -257,29 +257,29 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.026892 0.012233 -1 2 2 2 2 total 0.034959 0.007449 -2 2 2 2 3 total 0.040337 0.009144 -3 2 2 2 4 total 0.021513 0.003750 -4 2 2 2 5 total 0.018824 0.005602 -5 2 2 2 6 total 0.026892 0.004806 -6 2 2 2 7 total 0.037648 0.012716 -7 2 2 2 8 total 0.026892 0.009768 -8 2 2 2 9 total 0.024202 0.005420 -9 2 2 2 10 total 0.018824 0.010183 -10 2 2 2 11 total 0.018824 0.007033 +0 2 2 2 1 total 0.032689 0.010313 +1 2 2 2 2 total 0.035958 0.011071 +2 2 2 2 3 total 0.019614 0.012398 +3 2 2 2 4 total 0.022883 0.009072 +4 2 2 2 5 total 0.009807 0.009926 +5 2 2 2 6 total 0.029420 0.011781 +6 2 2 2 7 total 0.032689 0.014602 +7 2 2 2 8 total 0.019614 0.006844 +8 2 2 2 9 total 0.032689 0.010313 +9 2 2 2 10 total 0.022883 0.009072 +10 2 2 2 11 total 0.029420 0.005650 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025753 0.004484 -34 2 1 1 2 total 0.024267 0.004581 -35 2 1 1 3 total 0.019810 0.004060 -36 2 1 1 4 total 0.019810 0.003579 -37 2 1 1 5 total 0.020305 0.003071 -38 2 1 1 6 total 0.025258 0.005987 -39 2 1 1 7 total 0.019315 0.002734 -40 2 1 1 8 total 0.031201 0.001961 -41 2 1 1 9 total 0.034668 0.003301 -42 2 1 1 10 total 0.043582 0.004935 -43 2 1 1 11 total 0.055468 0.004591 +33 2 1 1 1 total 0.025312 0.003469 +34 2 1 1 2 total 0.023852 0.004203 +35 2 1 1 3 total 0.027259 0.001971 +36 2 1 1 4 total 0.021418 0.003297 +37 2 1 1 5 total 0.017524 0.002518 +38 2 1 1 6 total 0.024339 0.003032 +39 2 1 1 7 total 0.029693 0.005395 +40 2 1 1 8 total 0.025312 0.001600 +41 2 1 1 9 total 0.028719 0.003602 +42 2 1 1 10 total 0.034561 0.004648 +43 2 1 1 11 total 0.052571 0.006591 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -289,7 +289,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000000 0.000000 +31 2 1 2 10 total 0.000487 0.000487 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -302,29 +302,29 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.026854 0.012543 -1 2 2 2 2 total 0.034911 0.008307 -2 2 2 2 3 total 0.040281 0.010079 -3 2 2 2 4 total 0.021483 0.004382 -4 2 2 2 5 total 0.018798 0.005938 -5 2 2 2 6 total 0.026854 0.005579 -6 2 2 2 7 total 0.037596 0.013308 -7 2 2 2 8 total 0.026854 0.010161 -8 2 2 2 9 total 0.024169 0.005987 -9 2 2 2 10 total 0.018798 0.010362 -10 2 2 2 11 total 0.018798 0.007300 +0 2 2 2 1 total 0.033560 0.010222 +1 2 2 2 2 total 0.036916 0.010953 +2 2 2 2 3 total 0.020136 0.012619 +3 2 2 2 4 total 0.023492 0.009111 +4 2 2 2 5 total 0.010068 0.010157 +5 2 2 2 6 total 0.030204 0.011837 +6 2 2 2 7 total 0.033560 0.014735 +7 2 2 2 8 total 0.020136 0.006828 +8 2 2 2 9 total 0.033560 0.010222 +9 2 2 2 10 total 0.023492 0.009111 +10 2 2 2 11 total 0.030204 0.005242 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025753 0.004661 -34 2 1 1 2 total 0.024267 0.004736 -35 2 1 1 3 total 0.019810 0.004177 -36 2 1 1 4 total 0.019810 0.003711 -37 2 1 1 5 total 0.020305 0.003231 -38 2 1 1 6 total 0.025258 0.006117 -39 2 1 1 7 total 0.019315 0.002897 -40 2 1 1 8 total 0.031201 0.002497 -41 2 1 1 9 total 0.034668 0.003721 -42 2 1 1 10 total 0.043582 0.005386 -43 2 1 1 11 total 0.055468 0.005350 +33 2 1 1 1 total 0.025312 0.003700 +34 2 1 1 2 total 0.023852 0.004373 +35 2 1 1 3 total 0.027259 0.002407 +36 2 1 1 4 total 0.021418 0.003471 +37 2 1 1 5 total 0.017524 0.002670 +38 2 1 1 6 total 0.024339 0.003273 +39 2 1 1 7 total 0.029693 0.005602 +40 2 1 1 8 total 0.025312 0.002052 +41 2 1 1 9 total 0.028719 0.003886 +42 2 1 1 10 total 0.034561 0.004968 +43 2 1 1 11 total 0.052571 0.007110 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -334,7 +334,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000000 0.000000 +31 2 1 2 10 total 0.000487 0.000843 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -347,40 +347,40 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.026854 0.013054 -1 2 2 2 2 total 0.034911 0.009546 -2 2 2 2 3 total 0.040281 0.011446 -3 2 2 2 4 total 0.021483 0.005251 -4 2 2 2 5 total 0.018798 0.006456 -5 2 2 2 6 total 0.026854 0.006649 -6 2 2 2 7 total 0.037596 0.014239 -7 2 2 2 8 total 0.026854 0.010785 -8 2 2 2 9 total 0.024169 0.006815 -9 2 2 2 10 total 0.018798 0.010667 -10 2 2 2 11 total 0.018798 0.007727 +0 2 2 2 1 total 0.033560 0.011889 +1 2 2 2 2 total 0.036916 0.012828 +2 2 2 2 3 total 0.020136 0.013135 +3 2 2 2 4 total 0.023492 0.010054 +4 2 2 2 5 total 0.010068 0.010319 +5 2 2 2 6 total 0.030204 0.013037 +6 2 2 2 7 total 0.033560 0.015937 +7 2 2 2 8 total 0.020136 0.007739 +8 2 2 2 9 total 0.033560 0.011889 +9 2 2 2 10 total 0.023492 0.010054 +10 2 2 2 11 total 0.030204 0.007573 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.007681 0.001043 -34 3 1 1 2 total 0.005645 0.000710 -35 3 1 1 3 total 0.007403 0.000552 -36 3 1 1 4 total 0.007866 0.000512 -37 3 1 1 5 total 0.007589 0.000524 -38 3 1 1 6 total 0.011198 0.001548 -39 3 1 1 7 total 0.039701 0.002533 -40 3 1 1 8 total 0.075978 0.001897 -41 3 1 1 9 total 0.112532 0.003677 -42 3 1 1 10 total 0.166670 0.005003 -43 3 1 1 11 total 0.210443 0.005656 -22 3 1 2 1 total 0.000463 0.000207 -23 3 1 2 2 total 0.000555 0.000227 -24 3 1 2 3 total 0.000740 0.000429 -25 3 1 2 4 total 0.001111 0.000236 -26 3 1 2 5 total 0.002128 0.000631 -27 3 1 2 6 total 0.003146 0.000645 -28 3 1 2 7 total 0.004905 0.000561 -29 3 1 2 8 total 0.005738 0.000742 -30 3 1 2 9 total 0.005090 0.000672 -31 3 1 2 10 total 0.005367 0.000561 -32 3 1 2 11 total 0.002406 0.000593 +33 3 1 1 1 total 0.008818 0.001587 +34 3 1 1 2 total 0.006389 0.000610 +35 3 1 1 3 total 0.007288 0.000775 +36 3 1 1 4 total 0.008008 0.001111 +37 3 1 1 5 total 0.007828 0.000452 +38 3 1 1 6 total 0.011247 0.000473 +39 3 1 1 7 total 0.039411 0.002111 +40 3 1 1 8 total 0.071443 0.002082 +41 3 1 1 9 total 0.115713 0.004165 +42 3 1 1 10 total 0.164662 0.005479 +43 3 1 1 11 total 0.214060 0.006189 +22 3 1 2 1 total 0.000360 0.000090 +23 3 1 2 2 total 0.000810 0.000169 +24 3 1 2 3 total 0.000810 0.000331 +25 3 1 2 4 total 0.001440 0.000332 +26 3 1 2 5 total 0.002339 0.000267 +27 3 1 2 6 total 0.003149 0.000256 +28 3 1 2 7 total 0.004409 0.000601 +29 3 1 2 8 total 0.004139 0.000398 +30 3 1 2 9 total 0.004769 0.000639 +31 3 1 2 10 total 0.004769 0.000453 +32 3 1 2 11 total 0.002789 0.000630 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -391,41 +391,41 @@ 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 20 3 2 1 10 total 0.000000 0.000000 -21 3 2 1 11 total 0.000474 0.000475 -0 3 2 2 1 total 0.074402 0.007811 -1 3 2 2 2 total 0.103783 0.009042 -2 3 2 2 3 total 0.106153 0.012691 -3 3 2 2 4 total 0.115631 0.011475 -4 3 2 2 5 total 0.128900 0.014096 -5 3 2 2 6 total 0.169655 0.021010 -6 3 2 2 7 total 0.175816 0.016086 -7 3 2 2 8 total 0.217519 0.029631 -8 3 2 2 9 total 0.247374 0.021476 -9 3 2 2 10 total 0.299977 0.031756 -10 3 2 2 11 total 0.351157 0.027654 +21 3 2 1 11 total 0.000000 0.000000 +0 3 2 2 1 total 0.086327 0.004499 +1 3 2 2 2 total 0.088278 0.008634 +2 3 2 2 3 total 0.108275 0.008710 +3 3 2 2 4 total 0.115103 0.005859 +4 3 2 2 5 total 0.139489 0.012654 +5 3 2 2 6 total 0.152658 0.005193 +6 3 2 2 7 total 0.182897 0.007164 +7 3 2 2 8 total 0.202894 0.014663 +8 3 2 2 9 total 0.268249 0.019575 +9 3 2 2 10 total 0.294098 0.015467 +10 3 2 2 11 total 0.354088 0.012355 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.007681 0.001043 -34 3 1 1 2 total 0.005645 0.000710 -35 3 1 1 3 total 0.007403 0.000552 -36 3 1 1 4 total 0.007866 0.000512 -37 3 1 1 5 total 0.007589 0.000524 -38 3 1 1 6 total 0.011198 0.001548 -39 3 1 1 7 total 0.039701 0.002533 -40 3 1 1 8 total 0.075978 0.001897 -41 3 1 1 9 total 0.112532 0.003677 -42 3 1 1 10 total 0.166670 0.005003 -43 3 1 1 11 total 0.210443 0.005656 -22 3 1 2 1 total 0.000463 0.000207 -23 3 1 2 2 total 0.000555 0.000227 -24 3 1 2 3 total 0.000740 0.000429 -25 3 1 2 4 total 0.001111 0.000236 -26 3 1 2 5 total 0.002128 0.000631 -27 3 1 2 6 total 0.003146 0.000645 -28 3 1 2 7 total 0.004905 0.000561 -29 3 1 2 8 total 0.005738 0.000742 -30 3 1 2 9 total 0.005090 0.000672 -31 3 1 2 10 total 0.005367 0.000561 -32 3 1 2 11 total 0.002406 0.000593 +33 3 1 1 1 total 0.008818 0.001587 +34 3 1 1 2 total 0.006389 0.000610 +35 3 1 1 3 total 0.007288 0.000775 +36 3 1 1 4 total 0.008008 0.001111 +37 3 1 1 5 total 0.007828 0.000452 +38 3 1 1 6 total 0.011247 0.000473 +39 3 1 1 7 total 0.039411 0.002111 +40 3 1 1 8 total 0.071443 0.002082 +41 3 1 1 9 total 0.115713 0.004165 +42 3 1 1 10 total 0.164662 0.005479 +43 3 1 1 11 total 0.214060 0.006189 +22 3 1 2 1 total 0.000360 0.000090 +23 3 1 2 2 total 0.000810 0.000169 +24 3 1 2 3 total 0.000810 0.000331 +25 3 1 2 4 total 0.001440 0.000332 +26 3 1 2 5 total 0.002339 0.000267 +27 3 1 2 6 total 0.003149 0.000256 +28 3 1 2 7 total 0.004409 0.000601 +29 3 1 2 8 total 0.004139 0.000398 +30 3 1 2 9 total 0.004769 0.000639 +31 3 1 2 10 total 0.004769 0.000453 +32 3 1 2 11 total 0.002789 0.000630 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -436,41 +436,41 @@ 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 20 3 2 1 10 total 0.000000 0.000000 -21 3 2 1 11 total 0.000474 0.000475 -0 3 2 2 1 total 0.074402 0.007811 -1 3 2 2 2 total 0.103783 0.009042 -2 3 2 2 3 total 0.106153 0.012691 -3 3 2 2 4 total 0.115631 0.011475 -4 3 2 2 5 total 0.128900 0.014096 -5 3 2 2 6 total 0.169655 0.021010 -6 3 2 2 7 total 0.175816 0.016086 -7 3 2 2 8 total 0.217519 0.029631 -8 3 2 2 9 total 0.247374 0.021476 -9 3 2 2 10 total 0.299977 0.031756 -10 3 2 2 11 total 0.351157 0.027654 +21 3 2 1 11 total 0.000000 0.000000 +0 3 2 2 1 total 0.086327 0.004499 +1 3 2 2 2 total 0.088278 0.008634 +2 3 2 2 3 total 0.108275 0.008710 +3 3 2 2 4 total 0.115103 0.005859 +4 3 2 2 5 total 0.139489 0.012654 +5 3 2 2 6 total 0.152658 0.005193 +6 3 2 2 7 total 0.182897 0.007164 +7 3 2 2 8 total 0.202894 0.014663 +8 3 2 2 9 total 0.268249 0.019575 +9 3 2 2 10 total 0.294098 0.015467 +10 3 2 2 11 total 0.354088 0.012355 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.007759 0.001080 -34 3 1 1 2 total 0.005703 0.000738 -35 3 1 1 3 total 0.007479 0.000602 -36 3 1 1 4 total 0.007946 0.000571 -37 3 1 1 5 total 0.007666 0.000578 -38 3 1 1 6 total 0.011312 0.001601 -39 3 1 1 7 total 0.040106 0.002833 -40 3 1 1 8 total 0.076753 0.003016 -41 3 1 1 9 total 0.113680 0.005068 -42 3 1 1 10 total 0.168370 0.007185 -43 3 1 1 11 total 0.212589 0.008616 -22 3 1 2 1 total 0.000467 0.000210 -23 3 1 2 2 total 0.000561 0.000230 -24 3 1 2 3 total 0.000748 0.000434 -25 3 1 2 4 total 0.001122 0.000241 -26 3 1 2 5 total 0.002150 0.000641 -27 3 1 2 6 total 0.003179 0.000659 -28 3 1 2 7 total 0.004955 0.000586 -29 3 1 2 8 total 0.005796 0.000770 -30 3 1 2 9 total 0.005142 0.000697 -31 3 1 2 10 total 0.005422 0.000590 -32 3 1 2 11 total 0.002431 0.000604 +33 3 1 1 1 total 0.008807 0.001589 +34 3 1 1 2 total 0.006381 0.000614 +35 3 1 1 3 total 0.007279 0.000779 +36 3 1 1 4 total 0.007998 0.001113 +37 3 1 1 5 total 0.007818 0.000461 +38 3 1 1 6 total 0.011233 0.000491 +39 3 1 1 7 total 0.039362 0.002160 +40 3 1 1 8 total 0.071354 0.002246 +41 3 1 1 9 total 0.115569 0.004381 +42 3 1 1 10 total 0.164456 0.005812 +43 3 1 1 11 total 0.213793 0.006684 +22 3 1 2 1 total 0.000359 0.000090 +23 3 1 2 2 total 0.000809 0.000169 +24 3 1 2 3 total 0.000809 0.000331 +25 3 1 2 4 total 0.001438 0.000332 +26 3 1 2 5 total 0.002337 0.000269 +27 3 1 2 6 total 0.003145 0.000259 +28 3 1 2 7 total 0.004403 0.000603 +29 3 1 2 8 total 0.004134 0.000400 +30 3 1 2 9 total 0.004763 0.000640 +31 3 1 2 10 total 0.004763 0.000456 +32 3 1 2 11 total 0.002786 0.000630 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -481,41 +481,41 @@ 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 20 3 2 1 10 total 0.000000 0.000000 -21 3 2 1 11 total 0.000477 0.000479 -0 3 2 2 1 total 0.074833 0.009685 -1 3 2 2 2 total 0.104384 0.012046 -2 3 2 2 3 total 0.106768 0.015107 -3 3 2 2 4 total 0.116300 0.014515 -4 3 2 2 5 total 0.129646 0.017242 -5 3 2 2 6 total 0.170637 0.024765 -6 3 2 2 7 total 0.176834 0.020997 -7 3 2 2 8 total 0.218778 0.034093 -8 3 2 2 9 total 0.248807 0.028656 -9 3 2 2 10 total 0.301714 0.039263 -10 3 2 2 11 total 0.353191 0.038577 +21 3 2 1 11 total 0.000000 0.000000 +0 3 2 2 1 total 0.086966 0.006257 +1 3 2 2 2 total 0.088931 0.009752 +2 3 2 2 3 total 0.109076 0.010309 +3 3 2 2 4 total 0.115955 0.008241 +4 3 2 2 5 total 0.140521 0.014528 +5 3 2 2 6 total 0.153787 0.009249 +6 3 2 2 7 total 0.184250 0.011645 +7 3 2 2 8 total 0.204395 0.017916 +8 3 2 2 9 total 0.270233 0.023844 +9 3 2 2 10 total 0.296274 0.021418 +10 3 2 2 11 total 0.356708 0.021633 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.007759 0.001091 -34 3 1 1 2 total 0.005703 0.000746 -35 3 1 1 3 total 0.007479 0.000619 -36 3 1 1 4 total 0.007946 0.000592 -37 3 1 1 5 total 0.007666 0.000598 -38 3 1 1 6 total 0.011312 0.001616 -39 3 1 1 7 total 0.040106 0.002941 -40 3 1 1 8 total 0.076753 0.003373 -41 3 1 1 9 total 0.113680 0.005540 -42 3 1 1 10 total 0.168370 0.007913 -43 3 1 1 11 total 0.212589 0.009578 -22 3 1 2 1 total 0.000467 0.000211 -23 3 1 2 2 total 0.000561 0.000232 -24 3 1 2 3 total 0.000748 0.000436 -25 3 1 2 4 total 0.001122 0.000250 -26 3 1 2 5 total 0.002150 0.000653 -27 3 1 2 6 total 0.003179 0.000684 -28 3 1 2 7 total 0.004955 0.000654 -29 3 1 2 8 total 0.005796 0.000841 -30 3 1 2 9 total 0.005142 0.000759 -31 3 1 2 10 total 0.005422 0.000670 -32 3 1 2 11 total 0.002431 0.000620 +33 3 1 1 1 total 0.008807 0.001597 +34 3 1 1 2 total 0.006381 0.000625 +35 3 1 1 3 total 0.007279 0.000790 +36 3 1 1 4 total 0.007998 0.001123 +37 3 1 1 5 total 0.007818 0.000482 +38 3 1 1 6 total 0.011233 0.000531 +39 3 1 1 7 total 0.039362 0.002274 +40 3 1 1 8 total 0.071354 0.002589 +41 3 1 1 9 total 0.115569 0.004852 +42 3 1 1 10 total 0.164456 0.006526 +43 3 1 1 11 total 0.213793 0.007718 +22 3 1 2 1 total 0.000359 0.000092 +23 3 1 2 2 total 0.000809 0.000174 +24 3 1 2 3 total 0.000809 0.000333 +25 3 1 2 4 total 0.001438 0.000340 +26 3 1 2 5 total 0.002337 0.000295 +27 3 1 2 6 total 0.003145 0.000306 +28 3 1 2 7 total 0.004403 0.000645 +29 3 1 2 8 total 0.004134 0.000454 +30 3 1 2 9 total 0.004763 0.000686 +31 3 1 2 10 total 0.004763 0.000519 +32 3 1 2 11 total 0.002786 0.000646 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -526,15 +526,15 @@ 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 20 3 2 1 10 total 0.000000 0.000000 -21 3 2 1 11 total 0.000477 0.000827 -0 3 2 2 1 total 0.074833 0.011051 -1 3 2 2 2 total 0.104384 0.014150 -2 3 2 2 3 total 0.106768 0.016908 -3 3 2 2 4 total 0.116300 0.016707 -4 3 2 2 5 total 0.129646 0.019553 -5 3 2 2 6 total 0.170637 0.027579 -6 3 2 2 7 total 0.176834 0.024476 -7 3 2 2 8 total 0.218778 0.037476 -8 3 2 2 9 total 0.248807 0.033680 -9 3 2 2 10 total 0.301714 0.044745 -10 3 2 2 11 total 0.353191 0.046035 +21 3 2 1 11 total 0.000000 0.000000 +0 3 2 2 1 total 0.086966 0.007070 +1 3 2 2 2 total 0.088931 0.010317 +2 3 2 2 3 total 0.109076 0.011105 +3 3 2 2 4 total 0.115955 0.009338 +4 3 2 2 5 total 0.140521 0.015472 +5 3 2 2 6 total 0.153787 0.010930 +6 3 2 2 7 total 0.184250 0.013575 +7 3 2 2 8 total 0.204395 0.019516 +8 3 2 2 9 total 0.270233 0.025947 +9 3 2 2 10 total 0.296274 0.024178 +10 3 2 2 11 total 0.356708 0.025503 diff --git a/tests/regression_tests/mgxs_library_histogram/test.py b/tests/regression_tests/mgxs_library_histogram/test.py index 42fc1957a..b9905910a 100644 --- a/tests/regression_tests/mgxs_library_histogram/test.py +++ b/tests/regression_tests/mgxs_library_histogram/test.py @@ -30,7 +30,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _get_results(self, hash_output=False): """Digest info in the statepoint and return as a string.""" diff --git a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat index 5a6e8a20a..ac2ff0c81 100644 --- a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat @@ -1,511 +1,512 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 2 2 - -100.0 -100.0 - 100.0 100.0 - - - 1 - - - 0.0 20000000.0 - - - 0.0 20000000.0 - - - 1 - - - 3 - - - 1 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - (n,3n) - tracklength - - - 1 2 - total - (n,4n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 2 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 68 2 - total - current - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 79 2 - total - delayed-nu-fission - tracklength - - - 1 79 2 - total - delayed-nu-fission - analog - - - 1 79 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 79 2 - total - delayed-nu-fission - tracklength - - - 1 79 - total - delayed-nu-fission - tracklength - - - 1 79 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 79 2 5 - total - delayed-nu-fission - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + + 2 2 + -100.0 -100.0 + 100.0 100.0 + + + 1 + + + 0.0 20000000.0 + + + 0.0 20000000.0 + + + 1 + + + 3 + + + 1 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 2 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 68 2 + total + current + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + analog + + + 1 79 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 + total + delayed-nu-fission + tracklength + + + 1 79 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 79 2 5 + total + delayed-nu-fission + analog + + diff --git a/tests/regression_tests/mgxs_library_mesh/results_true.dat b/tests/regression_tests/mgxs_library_mesh/results_true.dat index ec7620c5c..390b5c453 100644 --- a/tests/regression_tests/mgxs_library_mesh/results_true.dat +++ b/tests/regression_tests/mgxs_library_mesh/results_true.dat @@ -1,362 +1,362 @@ - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.103374 0.004981 -2 1 2 1 total 0.103852 0.004752 -1 2 1 1 total 0.103322 0.003613 -3 2 2 1 total 0.102889 0.003387 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.072760 0.005235 -2 1 2 1 total 0.074856 0.004972 -1 2 1 1 total 0.074583 0.004000 -3 2 2 1 total 0.072925 0.003485 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.072768 0.005236 -2 1 2 1 total 0.074864 0.004972 -1 2 1 1 total 0.074603 0.004002 -3 2 2 1 total 0.072881 0.003491 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.013309 0.000729 -2 1 2 1 total 0.013223 0.000707 -1 2 1 1 total 0.013222 0.000596 -3 2 2 1 total 0.013282 0.000564 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.013241 0.000728 -2 1 2 1 total 0.013142 0.000705 -1 2 1 1 total 0.013137 0.000596 -3 2 2 1 total 0.013221 0.000564 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.001281 0.000874 -2 1 2 1 total 0.001297 0.000731 -1 2 1 1 total 0.001281 0.000744 -3 2 2 1 total 0.001288 0.000719 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.012029 0.000664 -2 1 2 1 total 0.011926 0.000639 -1 2 1 1 total 0.011941 0.000545 -3 2 2 1 total 0.011994 0.000515 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.031361 0.001735 -2 1 2 1 total 0.031091 0.001675 -1 2 1 1 total 0.031169 0.001418 -3 2 2 1 total 0.031255 0.001366 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 2.326447e+06 128504.886535 -2 1 2 1 total 2.306518e+06 123638.096130 -1 2 1 1 total 2.309435e+06 105395.059055 -3 2 2 1 total 2.319667e+06 99692.620001 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.090065 0.004262 -2 1 2 1 total 0.090629 0.004086 -1 2 1 1 total 0.090100 0.003045 -3 2 2 1 total 0.089607 0.002828 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.090188 0.005151 -2 1 2 1 total 0.094339 0.004349 -1 2 1 1 total 0.088294 0.003953 -3 2 2 1 total 0.089633 0.002592 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.090122 0.005149 -1 1 1 1 1 P1 total 0.030614 0.001612 -2 1 1 1 1 P2 total 0.016490 0.000897 -3 1 1 1 1 P3 total 0.010163 0.000829 -8 1 2 1 1 P0 total 0.094307 0.004337 -9 1 2 1 1 P1 total 0.028996 0.001462 -10 1 2 1 1 P2 total 0.017486 0.000808 -11 1 2 1 1 P3 total 0.009753 0.000742 -4 2 1 1 1 P0 total 0.088198 0.003959 -5 2 1 1 1 P1 total 0.028739 0.001715 -6 2 1 1 1 P2 total 0.015608 0.000680 -7 2 1 1 1 P3 total 0.008232 0.000363 -12 2 2 1 1 P0 total 0.089536 0.002551 -13 2 2 1 1 P1 total 0.029964 0.000821 -14 2 2 1 1 P2 total 0.015742 0.001260 -15 2 2 1 1 P3 total 0.008944 0.000385 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.090188 0.005151 -1 1 1 1 1 P1 total 0.030606 0.001614 -2 1 1 1 1 P2 total 0.016462 0.000898 -3 1 1 1 1 P3 total 0.010173 0.000824 -8 1 2 1 1 P0 total 0.094339 0.004349 -9 1 2 1 1 P1 total 0.028988 0.001462 -10 1 2 1 1 P2 total 0.017473 0.000811 -11 1 2 1 1 P3 total 0.009763 0.000749 -4 2 1 1 1 P0 total 0.088294 0.003953 -5 2 1 1 1 P1 total 0.028719 0.001720 -6 2 1 1 1 P2 total 0.015571 0.000691 -7 2 1 1 1 P3 total 0.008255 0.000361 -12 2 2 1 1 P0 total 0.089633 0.002592 -13 2 2 1 1 P1 total 0.030008 0.000847 -14 2 2 1 1 P2 total 0.015748 0.001284 -15 2 2 1 1 P3 total 0.008951 0.000387 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 1.000736 0.060260 -2 1 2 1 1 total 1.000346 0.042656 -1 2 1 1 1 total 1.001091 0.052736 -3 2 2 1 1 total 1.001078 0.038212 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 0.031890 0.002523 -2 1 2 1 1 total 0.032714 0.001502 -1 2 1 1 1 total 0.030414 0.002369 -3 2 2 1 1 total 0.031051 0.001521 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 1.0 0.060234 -2 1 2 1 1 total 1.0 0.042523 -1 2 1 1 1 total 1.0 0.052777 -3 2 2 1 1 total 1.0 0.037842 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.090065 0.006899 -1 1 1 1 1 P1 total 0.030595 0.002243 -2 1 1 1 1 P2 total 0.016480 0.001229 -3 1 1 1 1 P3 total 0.010157 0.000977 -8 1 2 1 1 P0 total 0.090629 0.005616 -9 1 2 1 1 P1 total 0.027865 0.001820 -10 1 2 1 1 P2 total 0.016804 0.001044 -11 1 2 1 1 P3 total 0.009373 0.000813 -4 2 1 1 1 P0 total 0.090100 0.005647 -5 2 1 1 1 P1 total 0.029359 0.002172 -6 2 1 1 1 P2 total 0.015944 0.000984 -7 2 1 1 1 P3 total 0.008410 0.000523 -12 2 2 1 1 P0 total 0.089607 0.004415 -13 2 2 1 1 P1 total 0.029988 0.001459 -14 2 2 1 1 P2 total 0.015755 0.001411 -15 2 2 1 1 P3 total 0.008951 0.000528 - mesh 1 group in group out legendre nuclide mean std. dev. - x y -0 1 1 1 1 P0 total 0.090131 0.008782 -1 1 1 1 1 P1 total 0.030617 0.002905 -2 1 1 1 1 P2 total 0.016492 0.001581 -3 1 1 1 1 P3 total 0.010164 0.001154 -8 1 2 1 1 P0 total 0.090661 0.006820 -9 1 2 1 1 P1 total 0.027875 0.002174 -10 1 2 1 1 P2 total 0.016810 0.001267 -11 1 2 1 1 P3 total 0.009376 0.000906 -4 2 1 1 1 P0 total 0.090199 0.007385 -5 2 1 1 1 P1 total 0.029391 0.002669 -6 2 1 1 1 P2 total 0.015962 0.001295 -7 2 1 1 1 P3 total 0.008419 0.000686 -12 2 2 1 1 P0 total 0.089704 0.005591 -13 2 2 1 1 P1 total 0.030020 0.001856 -14 2 2 1 1 P2 total 0.015772 0.001536 -15 2 2 1 1 P3 total 0.008961 0.000629 - mesh 1 group out nuclide mean std. dev. - x y -0 1 1 1 total 1.0 0.098093 -2 1 2 1 total 1.0 0.042346 -1 2 1 1 total 1.0 0.104352 -3 2 2 1 total 1.0 0.067889 - mesh 1 group out nuclide mean std. dev. - x y -0 1 1 1 total 1.0 0.099401 -2 1 2 1 total 1.0 0.042085 -1 2 1 1 total 1.0 0.104135 -3 2 2 1 total 1.0 0.067307 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 8.547713e-10 3.477664e-11 -2 1 2 1 total 9.057083e-10 4.171858e-11 -1 2 1 1 total 8.666731e-10 2.371072e-11 -3 2 2 1 total 8.532016e-10 1.638929e-11 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 0.031163 0.001724 -2 1 2 1 total 0.030895 0.001664 -1 2 1 1 total 0.030973 0.001409 -3 2 2 1 total 0.031058 0.001358 - mesh 1 group in group out nuclide mean std. dev. - x y -0 1 1 1 1 total 0.031781 0.002541 -2 1 2 1 1 total 0.032490 0.001487 -1 2 1 1 1 total 0.030274 0.002354 -3 2 2 1 1 total 0.030882 0.001500 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.102319 0.005483 +2 1 2 1 1 total 0.104659 0.002878 +1 2 1 1 1 total 0.107122 0.005105 +3 2 2 1 1 total 0.103856 0.003459 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.072455 0.005799 +2 1 2 1 1 total 0.072899 0.003254 +1 2 1 1 1 total 0.074187 0.005441 +3 2 2 1 1 total 0.074241 0.003779 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.072455 0.005799 +2 1 2 1 1 total 0.072912 0.003251 +1 2 1 1 1 total 0.074140 0.005442 +3 2 2 1 1 total 0.074192 0.003783 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.012943 0.000836 +2 1 2 1 1 total 0.013363 0.000553 +1 2 1 1 1 total 0.013980 0.000715 +3 2 2 1 1 total 0.013286 0.000621 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.012881 0.000835 +2 1 2 1 1 total 0.013282 0.000552 +1 2 1 1 1 total 0.013896 0.000714 +3 2 2 1 1 total 0.013180 0.000621 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.001231 0.000979 +2 1 2 1 1 total 0.001332 0.000691 +1 2 1 1 1 total 0.001346 0.000770 +3 2 2 1 1 total 0.001258 0.000815 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.011712 0.000762 +2 1 2 1 1 total 0.012031 0.000468 +1 2 1 1 1 total 0.012635 0.000646 +3 2 2 1 1 total 0.012028 0.000556 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.030549 0.001995 +2 1 2 1 1 total 0.031338 0.001160 +1 2 1 1 1 total 0.032944 0.001703 +3 2 2 1 1 total 0.031480 0.001423 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 2.265259e+06 147469.851100 +2 1 2 1 1 total 2.326873e+06 90605.035909 +1 2 1 1 1 total 2.443628e+06 124917.160682 +3 2 2 1 1 total 2.326322e+06 107513.428248 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.089376 0.004670 +2 1 2 1 1 total 0.091296 0.002370 +1 2 1 1 1 total 0.093142 0.004401 +3 2 2 1 1 total 0.090570 0.002842 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.089670 0.005421 +2 1 2 1 1 total 0.094557 0.003843 +1 2 1 1 1 total 0.094972 0.005963 +3 2 2 1 1 total 0.088538 0.002530 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.089670 0.005421 +1 1 1 1 1 1 P1 total 0.029864 0.001887 +2 1 1 1 1 1 P2 total 0.015945 0.001296 +3 1 1 1 1 1 P3 total 0.009511 0.000946 +8 1 2 1 1 1 P0 total 0.094524 0.003835 +9 1 2 1 1 1 P1 total 0.031760 0.001520 +10 1 2 1 1 1 P2 total 0.017210 0.000821 +11 1 2 1 1 1 P3 total 0.009315 0.000631 +4 2 1 1 1 1 P0 total 0.094835 0.005973 +5 2 1 1 1 1 P1 total 0.032936 0.001884 +6 2 1 1 1 1 P2 total 0.017196 0.001626 +7 2 1 1 1 1 P3 total 0.010278 0.001345 +12 2 2 1 1 1 P0 total 0.088412 0.002491 +13 2 2 1 1 1 P1 total 0.029615 0.001524 +14 2 2 1 1 1 P2 total 0.016925 0.000613 +15 2 2 1 1 1 P3 total 0.009759 0.000466 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.089670 0.005421 +1 1 1 1 1 1 P1 total 0.029864 0.001887 +2 1 1 1 1 1 P2 total 0.015945 0.001296 +3 1 1 1 1 1 P3 total 0.009511 0.000946 +8 1 2 1 1 1 P0 total 0.094557 0.003843 +9 1 2 1 1 1 P1 total 0.031747 0.001512 +10 1 2 1 1 1 P2 total 0.017201 0.000817 +11 1 2 1 1 1 P3 total 0.009329 0.000635 +4 2 1 1 1 1 P0 total 0.094972 0.005963 +5 2 1 1 1 1 P1 total 0.032983 0.001886 +6 2 1 1 1 1 P2 total 0.017162 0.001631 +7 2 1 1 1 1 P3 total 0.010240 0.001336 +12 2 2 1 1 1 P0 total 0.088538 0.002530 +13 2 2 1 1 1 P1 total 0.029663 0.001532 +14 2 2 1 1 1 P2 total 0.016931 0.000627 +15 2 2 1 1 1 P3 total 0.009762 0.000466 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.000000 0.056046 +2 1 2 1 1 1 total 1.000346 0.042442 +1 2 1 1 1 1 total 1.001447 0.056345 +3 2 2 1 1 1 total 1.001422 0.026106 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.031401 0.002755 +2 1 2 1 1 1 total 0.033268 0.001692 +1 2 1 1 1 1 total 0.033756 0.002609 +3 2 2 1 1 1 total 0.030234 0.001308 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.0 0.056046 +2 1 2 1 1 1 total 1.0 0.042360 +1 2 1 1 1 1 total 1.0 0.056488 +3 2 2 1 1 1 total 1.0 0.025630 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.089376 0.006848 +1 1 1 1 1 1 P1 total 0.029766 0.002346 +2 1 1 1 1 1 P2 total 0.015893 0.001493 +3 1 1 1 1 1 P3 total 0.009480 0.001043 +8 1 2 1 1 1 P0 total 0.091296 0.004536 +9 1 2 1 1 1 P1 total 0.030675 0.001712 +10 1 2 1 1 1 P2 total 0.016622 0.000925 +11 1 2 1 1 1 P3 total 0.008997 0.000662 +4 2 1 1 1 1 P0 total 0.093142 0.006860 +5 2 1 1 1 1 P1 total 0.032348 0.002224 +6 2 1 1 1 1 P2 total 0.016889 0.001722 +7 2 1 1 1 1 P3 total 0.010094 0.001376 +12 2 2 1 1 1 P0 total 0.090570 0.003669 +13 2 2 1 1 1 P1 total 0.030338 0.001794 +14 2 2 1 1 1 P2 total 0.017338 0.000806 +15 2 2 1 1 1 P3 total 0.009997 0.000559 + mesh 1 group in group out legendre nuclide mean std. dev. + x y z +0 1 1 1 1 1 P0 total 0.089376 0.008485 +1 1 1 1 1 1 P1 total 0.029766 0.002878 +2 1 1 1 1 1 P2 total 0.015893 0.001738 +3 1 1 1 1 1 P3 total 0.009480 0.001171 +8 1 2 1 1 1 P0 total 0.091328 0.005967 +9 1 2 1 1 1 P1 total 0.030686 0.002151 +10 1 2 1 1 1 P2 total 0.016628 0.001164 +11 1 2 1 1 1 P3 total 0.009000 0.000764 +4 2 1 1 1 1 P0 total 0.093277 0.008645 +5 2 1 1 1 1 P1 total 0.032394 0.002878 +6 2 1 1 1 1 P2 total 0.016913 0.001969 +7 2 1 1 1 1 P3 total 0.010109 0.001491 +12 2 2 1 1 1 P0 total 0.090699 0.004369 +13 2 2 1 1 1 P1 total 0.030381 0.001963 +14 2 2 1 1 1 P2 total 0.017362 0.000925 +15 2 2 1 1 1 P3 total 0.010011 0.000618 + mesh 1 group out nuclide mean std. dev. + x y z +0 1 1 1 1 total 1.0 0.105972 +2 1 2 1 1 total 1.0 0.060624 +1 2 1 1 1 total 1.0 0.084855 +3 2 2 1 1 total 1.0 0.053024 + mesh 1 group out nuclide mean std. dev. + x y z +0 1 1 1 1 total 1.0 0.108202 +2 1 2 1 1 total 1.0 0.058908 +1 2 1 1 1 total 1.0 0.085583 +3 2 2 1 1 total 1.0 0.052287 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 8.529639e-10 3.484230e-11 +2 1 2 1 1 total 9.050800e-10 2.850752e-11 +1 2 1 1 1 total 8.650057e-10 4.049297e-11 +3 2 2 1 1 total 8.673543e-10 1.753754e-11 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.030356 0.001982 +2 1 2 1 1 total 0.031140 0.001152 +1 2 1 1 1 total 0.032736 0.001693 +3 2 2 1 1 total 0.031283 0.001414 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.031233 0.002783 +2 1 2 1 1 1 total 0.033040 0.001647 +1 2 1 1 1 1 total 0.033581 0.002609 +3 2 2 1 1 1 total 0.030070 0.001287 mesh 1 group in nuclide mean std. dev. x y surf -3 1 1 x-max in 1 total 0.1888 0.008218 -2 1 1 x-max out 1 total 0.1828 0.008212 +3 1 1 x-max in 1 total 0.1816 0.006129 +2 1 1 x-max out 1 total 0.1730 0.004382 1 1 1 x-min in 1 total 0.0000 0.000000 0 1 1 x-min out 1 total 0.0000 0.000000 -7 1 1 y-max in 1 total 0.1820 0.012534 -6 1 1 y-max out 1 total 0.1794 0.015302 +7 1 1 y-max in 1 total 0.1790 0.011921 +6 1 1 y-max out 1 total 0.1802 0.016599 5 1 1 y-min in 1 total 0.0000 0.000000 4 1 1 y-min out 1 total 0.0000 0.000000 -19 1 2 x-max in 1 total 0.1870 0.011696 -18 1 2 x-max out 1 total 0.1850 0.012919 +19 1 2 x-max in 1 total 0.1872 0.012447 +18 1 2 x-max out 1 total 0.1952 0.015948 17 1 2 x-min in 1 total 0.0000 0.000000 16 1 2 x-min out 1 total 0.0000 0.000000 23 1 2 y-max in 1 total 0.0000 0.000000 22 1 2 y-max out 1 total 0.0000 0.000000 -21 1 2 y-min in 1 total 0.1794 0.015302 -20 1 2 y-min out 1 total 0.1820 0.012534 +21 1 2 y-min in 1 total 0.1802 0.016599 +20 1 2 y-min out 1 total 0.1790 0.011921 11 2 1 x-max in 1 total 0.0000 0.000000 10 2 1 x-max out 1 total 0.0000 0.000000 -9 2 1 x-min in 1 total 0.1828 0.008212 -8 2 1 x-min out 1 total 0.1888 0.008218 -15 2 1 y-max in 1 total 0.1850 0.011256 -14 2 1 y-max out 1 total 0.1870 0.009597 +9 2 1 x-min in 1 total 0.1730 0.004382 +8 2 1 x-min out 1 total 0.1816 0.006129 +15 2 1 y-max in 1 total 0.1778 0.009484 +14 2 1 y-max out 1 total 0.1822 0.010077 13 2 1 y-min in 1 total 0.0000 0.000000 12 2 1 y-min out 1 total 0.0000 0.000000 27 2 2 x-max in 1 total 0.0000 0.000000 26 2 2 x-max out 1 total 0.0000 0.000000 -25 2 2 x-min in 1 total 0.1850 0.012919 -24 2 2 x-min out 1 total 0.1870 0.011696 +25 2 2 x-min in 1 total 0.1952 0.015948 +24 2 2 x-min out 1 total 0.1872 0.012447 31 2 2 y-max in 1 total 0.0000 0.000000 30 2 2 y-max out 1 total 0.0000 0.000000 -29 2 2 y-min in 1 total 0.1870 0.009597 -28 2 2 y-min out 1 total 0.1850 0.011256 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 4.581283 0.329623 -2 1 2 1 total 4.452968 0.295762 -1 2 1 1 total 4.469295 0.239674 -3 2 2 1 total 4.570894 0.218416 - mesh 1 group in nuclide mean std. dev. - x y -0 1 1 1 total 4.580746 0.329583 -2 1 2 1 total 4.452519 0.295716 -1 2 1 1 total 4.468066 0.239680 -3 2 2 1 total 4.573657 0.219069 - mesh 1 delayedgroup group in nuclide mean std. dev. - x y -0 1 1 1 1 total 0.000007 3.812309e-07 -1 1 1 2 1 total 0.000036 1.967797e-06 -2 1 1 3 1 total 0.000034 1.878630e-06 -3 1 1 4 1 total 0.000077 4.212043e-06 -4 1 1 5 1 total 0.000031 1.726878e-06 -5 1 1 6 1 total 0.000013 7.233832e-07 -12 1 2 1 1 total 0.000007 3.663985e-07 -13 1 2 2 1 total 0.000035 1.891236e-06 -14 1 2 3 1 total 0.000034 1.805539e-06 -15 1 2 4 1 total 0.000076 4.048166e-06 -16 1 2 5 1 total 0.000031 1.659691e-06 -17 1 2 6 1 total 0.000013 6.952388e-07 -6 2 1 1 1 total 0.000007 3.123173e-07 -7 2 1 2 1 total 0.000035 1.612086e-06 -8 2 1 3 1 total 0.000034 1.539037e-06 -9 2 1 4 1 total 0.000076 3.450649e-06 -10 2 1 5 1 total 0.000031 1.414717e-06 -11 2 1 6 1 total 0.000013 5.926201e-07 -18 2 2 1 1 total 0.000007 2.946716e-07 -19 2 2 2 1 total 0.000036 1.521004e-06 -20 2 2 3 1 total 0.000034 1.452083e-06 -21 2 2 4 1 total 0.000076 3.255689e-06 -22 2 2 5 1 total 0.000031 1.334787e-06 -23 2 2 6 1 total 0.000013 5.591374e-07 - mesh 1 delayedgroup group out nuclide mean std. dev. - x y -0 1 1 1 1 total 1.0 1.414214 -1 1 1 2 1 total 0.0 0.000000 -2 1 1 3 1 total 0.0 0.000000 -3 1 1 4 1 total 1.0 0.578922 -4 1 1 5 1 total 0.0 0.000000 -5 1 1 6 1 total 0.0 0.000000 -12 1 2 1 1 total 0.0 0.000000 -13 1 2 2 1 total 1.0 0.578922 -14 1 2 3 1 total 1.0 1.414214 -15 1 2 4 1 total 1.0 1.414214 -16 1 2 5 1 total 1.0 0.875472 -17 1 2 6 1 total 1.0 1.414214 -6 2 1 1 1 total 0.0 0.000000 -7 2 1 2 1 total 0.0 0.000000 -8 2 1 3 1 total 1.0 1.414214 -9 2 1 4 1 total 1.0 0.579392 -10 2 1 5 1 total 1.0 1.414214 -11 2 1 6 1 total 0.0 0.000000 -18 2 2 1 1 total 1.0 0.868163 -19 2 2 2 1 total 1.0 1.414214 -20 2 2 3 1 total 0.0 0.000000 -21 2 2 4 1 total 1.0 0.868969 -22 2 2 5 1 total 1.0 1.414214 -23 2 2 6 1 total 0.0 0.000000 - mesh 1 delayedgroup group in nuclide mean std. dev. - x y -0 1 1 1 1 total 0.000221 0.000015 -1 1 1 2 1 total 0.001140 0.000079 -2 1 1 3 1 total 0.001088 0.000075 -3 1 1 4 1 total 0.002440 0.000169 -4 1 1 5 1 total 0.001001 0.000069 -5 1 1 6 1 total 0.000419 0.000029 -12 1 2 1 1 total 0.000221 0.000013 -13 1 2 2 1 total 0.001139 0.000066 -14 1 2 3 1 total 0.001088 0.000063 -15 1 2 4 1 total 0.002439 0.000142 -16 1 2 5 1 total 0.001000 0.000058 -17 1 2 6 1 total 0.000419 0.000024 -6 2 1 1 1 total 0.000220 0.000013 -7 2 1 2 1 total 0.001138 0.000067 -8 2 1 3 1 total 0.001086 0.000064 -9 2 1 4 1 total 0.002435 0.000144 -10 2 1 5 1 total 0.000998 0.000059 -11 2 1 6 1 total 0.000418 0.000025 -18 2 2 1 1 total 0.000221 0.000013 -19 2 2 2 1 total 0.001141 0.000066 -20 2 2 3 1 total 0.001090 0.000063 -21 2 2 4 1 total 0.002443 0.000141 -22 2 2 5 1 total 0.001002 0.000058 -23 2 2 6 1 total 0.000420 0.000024 - mesh 1 delayedgroup nuclide mean std. dev. - x y -0 1 1 1 total 0.013336 0.000919 -1 1 1 2 total 0.032739 0.002257 -2 1 1 3 total 0.120780 0.008325 -3 1 1 4 total 0.302780 0.020871 -4 1 1 5 total 0.849490 0.058555 -5 1 1 6 total 2.853000 0.196656 -12 1 2 1 total 0.013336 0.000770 -13 1 2 2 total 0.032739 0.001891 -14 1 2 3 total 0.120780 0.006977 -15 1 2 4 total 0.302780 0.017490 -16 1 2 5 total 0.849490 0.049071 -17 1 2 6 total 2.853000 0.164804 -6 2 1 1 total 0.013336 0.000790 -7 2 1 2 total 0.032739 0.001940 -8 2 1 3 total 0.120780 0.007157 -9 2 1 4 total 0.302780 0.017942 -10 2 1 5 total 0.849490 0.050338 -11 2 1 6 total 2.853000 0.169061 -18 2 2 1 total 0.013336 0.000757 -19 2 2 2 total 0.032739 0.001858 -20 2 2 3 total 0.120780 0.006855 -21 2 2 4 total 0.302780 0.017186 -22 2 2 5 total 0.849490 0.048217 -23 2 2 6 total 2.853000 0.161935 - mesh 1 delayedgroup group in group out nuclide mean std. dev. - x y -0 1 1 1 1 1 total 0.000026 0.000026 -1 1 1 2 1 1 total 0.000000 0.000000 -2 1 1 3 1 1 total 0.000000 0.000000 -3 1 1 4 1 1 total 0.000083 0.000034 -4 1 1 5 1 1 total 0.000000 0.000000 -5 1 1 6 1 1 total 0.000000 0.000000 -12 1 2 1 1 1 total 0.000000 0.000000 -13 1 2 2 1 1 total 0.000081 0.000033 -14 1 2 3 1 1 total 0.000026 0.000026 -15 1 2 4 1 1 total 0.000026 0.000026 -16 1 2 5 1 1 total 0.000059 0.000036 -17 1 2 6 1 1 total 0.000033 0.000033 -6 2 1 1 1 1 total 0.000000 0.000000 -7 2 1 2 1 1 total 0.000000 0.000000 -8 2 1 3 1 1 total 0.000032 0.000032 -9 2 1 4 1 1 total 0.000080 0.000033 -10 2 1 5 1 1 total 0.000028 0.000028 -11 2 1 6 1 1 total 0.000000 0.000000 -18 2 2 1 1 1 total 0.000054 0.000033 -19 2 2 2 1 1 total 0.000029 0.000029 -20 2 2 3 1 1 total 0.000000 0.000000 -21 2 2 4 1 1 total 0.000054 0.000033 -22 2 2 5 1 1 total 0.000032 0.000032 -23 2 2 6 1 1 total 0.000000 0.000000 +29 2 2 y-min in 1 total 0.1822 0.010077 +28 2 2 y-min out 1 total 0.1778 0.009484 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 4.600555 0.368212 +2 1 2 1 1 total 4.572518 0.204129 +1 2 1 1 1 total 4.493168 0.329560 +3 2 2 1 1 total 4.489908 0.228574 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 4.600555 0.368212 +2 1 2 1 1 total 4.571696 0.203824 +1 2 1 1 1 total 4.496020 0.330019 +3 2 2 1 1 total 4.492825 0.229077 + mesh 1 delayedgroup group in nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.000007 4.371033e-07 +1 1 1 1 2 1 total 0.000035 2.256193e-06 +2 1 1 1 3 1 total 0.000033 2.153958e-06 +3 1 1 1 4 1 total 0.000075 4.829351e-06 +4 1 1 1 5 1 total 0.000031 1.979966e-06 +5 1 1 1 6 1 total 0.000013 8.294008e-07 +12 1 2 1 1 1 total 0.000007 2.763697e-07 +13 1 2 1 2 1 total 0.000036 1.426535e-06 +14 1 2 1 3 1 total 0.000034 1.361895e-06 +15 1 2 1 4 1 total 0.000077 3.053480e-06 +16 1 2 1 5 1 total 0.000031 1.251884e-06 +17 1 2 1 6 1 total 0.000013 5.244097e-07 +6 2 1 1 1 1 total 0.000007 3.644103e-07 +7 2 1 1 2 1 total 0.000038 1.880974e-06 +8 2 1 1 3 1 total 0.000036 1.795741e-06 +9 2 1 1 4 1 total 0.000080 4.026199e-06 +10 2 1 1 5 1 total 0.000033 1.650685e-06 +11 2 1 1 6 1 total 0.000014 6.914661e-07 +18 2 2 1 1 1 total 0.000007 3.263844e-07 +19 2 2 1 2 1 total 0.000036 1.684696e-06 +20 2 2 1 3 1 total 0.000034 1.608357e-06 +21 2 2 1 4 1 total 0.000076 3.606069e-06 +22 2 2 1 5 1 total 0.000031 1.478437e-06 +23 2 2 1 6 1 total 0.000013 6.193123e-07 + mesh 1 delayedgroup group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.0 0.000000 +1 1 1 1 2 1 total 1.0 1.414214 +2 1 1 1 3 1 total 1.0 1.414214 +3 1 1 1 4 1 total 1.0 0.579241 +4 1 1 1 5 1 total 1.0 1.414214 +5 1 1 1 6 1 total 0.0 0.000000 +12 1 2 1 1 1 total 1.0 1.414214 +13 1 2 1 2 1 total 0.0 0.000000 +14 1 2 1 3 1 total 1.0 0.866166 +15 1 2 1 4 1 total 1.0 0.868547 +16 1 2 1 5 1 total 1.0 0.873899 +17 1 2 1 6 1 total 1.0 1.414214 +6 2 1 1 1 1 total 0.0 0.000000 +7 2 1 1 2 1 total 1.0 0.654642 +8 2 1 1 3 1 total 1.0 1.414214 +9 2 1 1 4 1 total 1.0 1.414214 +10 2 1 1 5 1 total 0.0 0.000000 +11 2 1 1 6 1 total 0.0 0.000000 +18 2 2 1 1 1 total 1.0 0.867501 +19 2 2 1 2 1 total 0.0 0.000000 +20 2 2 1 3 1 total 0.0 0.000000 +21 2 2 1 4 1 total 1.0 0.867501 +22 2 2 1 5 1 total 1.0 1.414214 +23 2 2 1 6 1 total 1.0 1.414214 + mesh 1 delayedgroup group in nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.000221 0.000018 +1 1 1 1 2 1 total 0.001141 0.000091 +2 1 1 1 3 1 total 0.001090 0.000087 +3 1 1 1 4 1 total 0.002443 0.000194 +4 1 1 1 5 1 total 0.001002 0.000080 +5 1 1 1 6 1 total 0.000420 0.000033 +12 1 2 1 1 1 total 0.000221 0.000011 +13 1 2 1 2 1 total 0.001142 0.000059 +14 1 2 1 3 1 total 0.001090 0.000056 +15 1 2 1 4 1 total 0.002444 0.000126 +16 1 2 1 5 1 total 0.001002 0.000052 +17 1 2 1 6 1 total 0.000420 0.000022 +6 2 1 1 1 1 total 0.000221 0.000013 +7 2 1 1 2 1 total 0.001140 0.000065 +8 2 1 1 3 1 total 0.001088 0.000062 +9 2 1 1 4 1 total 0.002440 0.000140 +10 2 1 1 5 1 total 0.001000 0.000057 +11 2 1 1 6 1 total 0.000419 0.000024 +18 2 2 1 1 1 total 0.000219 0.000014 +19 2 2 1 2 1 total 0.001132 0.000072 +20 2 2 1 3 1 total 0.001081 0.000069 +21 2 2 1 4 1 total 0.002424 0.000155 +22 2 2 1 5 1 total 0.000994 0.000064 +23 2 2 1 6 1 total 0.000416 0.000027 + mesh 1 delayedgroup nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.013336 0.001054 +1 1 1 1 2 total 0.032739 0.002588 +2 1 1 1 3 total 0.120780 0.009548 +3 1 1 1 4 total 0.302780 0.023936 +4 1 1 1 5 total 0.849490 0.067157 +5 1 1 1 6 total 2.853000 0.225544 +12 1 2 1 1 total 0.013336 0.000716 +13 1 2 1 2 total 0.032739 0.001758 +14 1 2 1 3 total 0.120780 0.006485 +15 1 2 1 4 total 0.302780 0.016257 +16 1 2 1 5 total 0.849490 0.045611 +17 1 2 1 6 total 2.853000 0.153186 +6 2 1 1 1 total 0.013336 0.000744 +7 2 1 1 2 total 0.032739 0.001827 +8 2 1 1 3 total 0.120780 0.006740 +9 2 1 1 4 total 0.302780 0.016897 +10 2 1 1 5 total 0.849490 0.047407 +11 2 1 1 6 total 2.853000 0.159216 +18 2 2 1 1 total 0.013336 0.000872 +19 2 2 1 2 total 0.032739 0.002141 +20 2 2 1 3 total 0.120780 0.007899 +21 2 2 1 4 total 0.302780 0.019803 +22 2 2 1 5 total 0.849490 0.055560 +23 2 2 1 6 total 2.853000 0.186598 + mesh 1 delayedgroup group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 1 total 0.000000 0.000000 +1 1 1 1 2 1 1 total 0.000029 0.000030 +2 1 1 1 3 1 1 total 0.000028 0.000028 +3 1 1 1 4 1 1 total 0.000083 0.000034 +4 1 1 1 5 1 1 total 0.000028 0.000028 +5 1 1 1 6 1 1 total 0.000000 0.000000 +12 1 2 1 1 1 1 total 0.000029 0.000029 +13 1 2 1 2 1 1 total 0.000000 0.000000 +14 1 2 1 3 1 1 total 0.000052 0.000032 +15 1 2 1 4 1 1 total 0.000055 0.000034 +16 1 2 1 5 1 1 total 0.000059 0.000037 +17 1 2 1 6 1 1 total 0.000033 0.000033 +6 2 1 1 1 1 1 total 0.000000 0.000000 +7 2 1 1 2 1 1 total 0.000113 0.000053 +8 2 1 1 3 1 1 total 0.000034 0.000034 +9 2 1 1 4 1 1 total 0.000029 0.000029 +10 2 1 1 5 1 1 total 0.000000 0.000000 +11 2 1 1 6 1 1 total 0.000000 0.000000 +18 2 2 1 1 1 1 total 0.000053 0.000033 +19 2 2 1 2 1 1 total 0.000000 0.000000 +20 2 2 1 3 1 1 total 0.000000 0.000000 +21 2 2 1 4 1 1 total 0.000053 0.000033 +22 2 2 1 5 1 1 total 0.000031 0.000031 +23 2 2 1 6 1 1 total 0.000025 0.000025 diff --git a/tests/regression_tests/mgxs_library_mesh/test.py b/tests/regression_tests/mgxs_library_mesh/test.py index c1a5980b5..3660d3eb7 100644 --- a/tests/regression_tests/mgxs_library_mesh/test.py +++ b/tests/regression_tests/mgxs_library_mesh/test.py @@ -19,12 +19,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.RectangularPrism(10.0, 10.0) - box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.rectangular_prism(10.0, 10.0) + box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 @@ -57,7 +57,7 @@ def model(): model.mgxs_lib.build_library() # Add tallies - model.mgxs_lib.add_to_tallies(model.tallies, merge=False) + model.mgxs_lib.add_to_tallies_file(model.tallies, merge=False) return model diff --git a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat index af09268cd..59cbddec4 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat @@ -1,1954 +1,1952 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 1 2 3 4 5 6 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - (n,3n) - tracklength - - - 1 2 - total - (n,4n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 30 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 54 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 54 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,elastic) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,level) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,na) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,nc) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,gamma) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,a) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,Xa) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - heating - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - damage-energy - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,n1) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,a0) - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - (n,nc) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - (n,n1) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - (n,2n) - analog - - - 1 2 - total - flux - tracklength - - - 1 108 2 - total - delayed-nu-fission - tracklength - - - 1 108 54 - total - delayed-nu-fission - analog - - - 1 108 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 108 2 - total - delayed-nu-fission - tracklength - - - 1 108 - total - delayed-nu-fission - tracklength - - - 1 108 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 108 2 5 - total - delayed-nu-fission - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - total - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - total - tracklength - - - 122 2 - total - flux - analog - - - 122 5 6 - total - scatter - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - total - tracklength - - - 122 2 - total - flux - analog - - - 122 5 6 - total - nu-scatter - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - absorption - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - absorption - tracklength - - - 122 2 - total - (n,2n) - tracklength - - - 122 2 - total - (n,3n) - tracklength - - - 122 2 - total - (n,4n) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - absorption - tracklength - - - 122 2 - total - fission - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - fission - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - nu-fission - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - kappa-fission - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - scatter - tracklength - - - 122 2 - total - flux - analog - - - 122 2 - total - nu-scatter - analog - - - 122 2 - total - flux - analog - - - 122 2 5 30 - total - scatter - analog - - - 122 2 - total - flux - analog - - - 122 2 5 30 - total - nu-scatter - analog - - - 122 2 5 - total - nu-scatter - analog - - - 122 2 5 - total - scatter - analog - - - 122 2 - total - flux - analog - - - 122 2 5 - total - nu-fission - analog - - - 122 2 5 - total - scatter - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - scatter - tracklength - - - 122 2 5 30 - total - scatter - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - scatter - tracklength - - - 122 2 5 30 - total - scatter - analog - - - 122 2 5 - total - nu-scatter - analog - - - 122 54 - total - nu-fission - analog - - - 122 5 - total - nu-fission - analog - - - 122 54 - total - prompt-nu-fission - analog - - - 122 5 - total - prompt-nu-fission - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - inverse-velocity - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - prompt-nu-fission - tracklength - - - 122 2 - total - flux - analog - - - 122 2 5 - total - prompt-nu-fission - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - total - tracklength - - - 122 2 - total - flux - analog - - - 122 5 6 - total - scatter - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - total - tracklength - - - 122 2 - total - flux - analog - - - 122 5 6 - total - nu-scatter - analog - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,elastic) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,level) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,2n) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,na) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,nc) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,gamma) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,a) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,Xa) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - heating - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - damage-energy - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,n1) - tracklength - - - 122 2 - total - flux - tracklength - - - 122 2 - total - (n,a0) - tracklength - - - 122 2 - total - flux - analog - - - 122 2 5 - total - (n,nc) - analog - - - 122 2 - total - flux - analog - - - 122 2 5 - total - (n,n1) - analog - - - 122 2 - total - flux - analog - - - 122 2 5 - total - (n,2n) - analog - - - 122 2 - total - flux - tracklength - - - 122 108 2 - total - delayed-nu-fission - tracklength - - - 122 108 54 - total - delayed-nu-fission - analog - - - 122 108 5 - total - delayed-nu-fission - analog - - - 122 2 - total - nu-fission - tracklength - - - 122 108 2 - total - delayed-nu-fission - tracklength - - - 122 108 - total - delayed-nu-fission - tracklength - - - 122 108 - total - decay-rate - tracklength - - - 122 2 - total - flux - analog - - - 122 108 2 5 - total - delayed-nu-fission - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - total - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - total - tracklength - - - 243 2 - total - flux - analog - - - 243 5 6 - total - scatter - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - total - tracklength - - - 243 2 - total - flux - analog - - - 243 5 6 - total - nu-scatter - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - absorption - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - absorption - tracklength - - - 243 2 - total - (n,2n) - tracklength - - - 243 2 - total - (n,3n) - tracklength - - - 243 2 - total - (n,4n) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - absorption - tracklength - - - 243 2 - total - fission - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - fission - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - nu-fission - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - kappa-fission - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - scatter - tracklength - - - 243 2 - total - flux - analog - - - 243 2 - total - nu-scatter - analog - - - 243 2 - total - flux - analog - - - 243 2 5 30 - total - scatter - analog - - - 243 2 - total - flux - analog - - - 243 2 5 30 - total - nu-scatter - analog - - - 243 2 5 - total - nu-scatter - analog - - - 243 2 5 - total - scatter - analog - - - 243 2 - total - flux - analog - - - 243 2 5 - total - nu-fission - analog - - - 243 2 5 - total - scatter - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - scatter - tracklength - - - 243 2 5 30 - total - scatter - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - scatter - tracklength - - - 243 2 5 30 - total - scatter - analog - - - 243 2 5 - total - nu-scatter - analog - - - 243 54 - total - nu-fission - analog - - - 243 5 - total - nu-fission - analog - - - 243 54 - total - prompt-nu-fission - analog - - - 243 5 - total - prompt-nu-fission - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - inverse-velocity - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - prompt-nu-fission - tracklength - - - 243 2 - total - flux - analog - - - 243 2 5 - total - prompt-nu-fission - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - total - tracklength - - - 243 2 - total - flux - analog - - - 243 5 6 - total - scatter - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - total - tracklength - - - 243 2 - total - flux - analog - - - 243 5 6 - total - nu-scatter - analog - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,elastic) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,level) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,2n) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,na) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,nc) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,gamma) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,a) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,Xa) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - heating - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - damage-energy - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,n1) - tracklength - - - 243 2 - total - flux - tracklength - - - 243 2 - total - (n,a0) - tracklength - - - 243 2 - total - flux - analog - - - 243 2 5 - total - (n,nc) - analog - - - 243 2 - total - flux - analog - - - 243 2 5 - total - (n,n1) - analog - - - 243 2 - total - flux - analog - - - 243 2 5 - total - (n,2n) - analog - - - 243 2 - total - flux - tracklength - - - 243 108 2 - total - delayed-nu-fission - tracklength - - - 243 108 54 - total - delayed-nu-fission - analog - - - 243 108 5 - total - delayed-nu-fission - analog - - - 243 2 - total - nu-fission - tracklength - - - 243 108 2 - total - delayed-nu-fission - tracklength - - - 243 108 - total - delayed-nu-fission - tracklength - - - 243 108 - total - decay-rate - tracklength - - - 243 2 - total - flux - analog - - - 243 108 2 5 - total - delayed-nu-fission - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 1 2 3 4 5 6 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 54 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 54 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,elastic) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,level) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,na) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,nc) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,gamma) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,a) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,Xa) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + heating + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + damage-energy + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,n1) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,a0) + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + (n,nc) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + (n,n1) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + (n,2n) + analog + + + 1 2 + total + flux + tracklength + + + 1 108 2 + total + delayed-nu-fission + tracklength + + + 1 108 54 + total + delayed-nu-fission + analog + + + 1 108 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 108 2 + total + delayed-nu-fission + tracklength + + + 1 108 + total + delayed-nu-fission + tracklength + + + 1 108 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 108 2 5 + total + delayed-nu-fission + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + nu-scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + absorption + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + absorption + tracklength + + + 122 2 + total + (n,2n) + tracklength + + + 122 2 + total + (n,3n) + tracklength + + + 122 2 + total + (n,4n) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + absorption + tracklength + + + 122 2 + total + fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + nu-fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + kappa-fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + scatter + tracklength + + + 122 2 + total + flux + analog + + + 122 2 + total + nu-scatter + analog + + + 122 2 + total + flux + analog + + + 122 2 5 30 + total + scatter + analog + + + 122 2 + total + flux + analog + + + 122 2 5 30 + total + nu-scatter + analog + + + 122 2 5 + total + nu-scatter + analog + + + 122 2 5 + total + scatter + analog + + + 122 2 + total + flux + analog + + + 122 2 5 + total + nu-fission + analog + + + 122 2 5 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + scatter + tracklength + + + 122 2 5 30 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + scatter + tracklength + + + 122 2 5 30 + total + scatter + analog + + + 122 2 5 + total + nu-scatter + analog + + + 122 54 + total + nu-fission + analog + + + 122 5 + total + nu-fission + analog + + + 122 54 + total + prompt-nu-fission + analog + + + 122 5 + total + prompt-nu-fission + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + inverse-velocity + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + prompt-nu-fission + tracklength + + + 122 2 + total + flux + analog + + + 122 2 5 + total + prompt-nu-fission + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + nu-scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,elastic) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,level) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,2n) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,na) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,nc) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,gamma) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,a) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,Xa) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + heating + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + damage-energy + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,n1) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,a0) + tracklength + + + 122 2 + total + flux + analog + + + 122 2 5 + total + (n,nc) + analog + + + 122 2 + total + flux + analog + + + 122 2 5 + total + (n,n1) + analog + + + 122 2 + total + flux + analog + + + 122 2 5 + total + (n,2n) + analog + + + 122 2 + total + flux + tracklength + + + 122 108 2 + total + delayed-nu-fission + tracklength + + + 122 108 54 + total + delayed-nu-fission + analog + + + 122 108 5 + total + delayed-nu-fission + analog + + + 122 2 + total + nu-fission + tracklength + + + 122 108 2 + total + delayed-nu-fission + tracklength + + + 122 108 + total + delayed-nu-fission + tracklength + + + 122 108 + total + decay-rate + tracklength + + + 122 2 + total + flux + analog + + + 122 108 2 5 + total + delayed-nu-fission + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + nu-scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + absorption + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + absorption + tracklength + + + 243 2 + total + (n,2n) + tracklength + + + 243 2 + total + (n,3n) + tracklength + + + 243 2 + total + (n,4n) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + absorption + tracklength + + + 243 2 + total + fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + nu-fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + kappa-fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + scatter + tracklength + + + 243 2 + total + flux + analog + + + 243 2 + total + nu-scatter + analog + + + 243 2 + total + flux + analog + + + 243 2 5 30 + total + scatter + analog + + + 243 2 + total + flux + analog + + + 243 2 5 30 + total + nu-scatter + analog + + + 243 2 5 + total + nu-scatter + analog + + + 243 2 5 + total + scatter + analog + + + 243 2 + total + flux + analog + + + 243 2 5 + total + nu-fission + analog + + + 243 2 5 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + scatter + tracklength + + + 243 2 5 30 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + scatter + tracklength + + + 243 2 5 30 + total + scatter + analog + + + 243 2 5 + total + nu-scatter + analog + + + 243 54 + total + nu-fission + analog + + + 243 5 + total + nu-fission + analog + + + 243 54 + total + prompt-nu-fission + analog + + + 243 5 + total + prompt-nu-fission + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + inverse-velocity + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + prompt-nu-fission + tracklength + + + 243 2 + total + flux + analog + + + 243 2 5 + total + prompt-nu-fission + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + nu-scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,elastic) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,level) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,2n) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,na) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,nc) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,gamma) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,a) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,Xa) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + heating + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + damage-energy + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,n1) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,a0) + tracklength + + + 243 2 + total + flux + analog + + + 243 2 5 + total + (n,nc) + analog + + + 243 2 + total + flux + analog + + + 243 2 5 + total + (n,n1) + analog + + + 243 2 + total + flux + analog + + + 243 2 5 + total + (n,2n) + analog + + + 243 2 + total + flux + tracklength + + + 243 108 2 + total + delayed-nu-fission + tracklength + + + 243 108 54 + total + delayed-nu-fission + analog + + + 243 108 5 + total + delayed-nu-fission + analog + + + 243 2 + total + nu-fission + tracklength + + + 243 108 2 + total + delayed-nu-fission + tracklength + + + 243 108 + total + delayed-nu-fission + tracklength + + + 243 108 + total + decay-rate + tracklength + + + 243 2 + total + flux + analog + + + 243 108 2 5 + total + delayed-nu-fission + analog + + diff --git a/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat index aec8e8bbc..dfbd183d4 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat +++ b/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat @@ -1,254 +1,254 @@ total material group in nuclide mean std. dev. -1 1 1 total 0.422772 0.014069 -0 1 2 total 0.661309 0.049458 +1 1 1 total 0.416386 0.014741 +0 1 2 total 0.658651 0.060521 transport material group in nuclide mean std. dev. -1 1 1 total 0.383831 0.015331 -0 1 2 total 0.679181 0.050786 +1 1 1 total 0.378343 0.016533 +0 1 2 total 0.641137 0.060797 nu-transport material group in nuclide mean std. dev. -1 1 1 total 0.383831 0.015331 -0 1 2 total 0.679181 0.050786 +1 1 1 total 0.378437 0.016556 +0 1 2 total 0.641137 0.060797 absorption material group in nuclide mean std. dev. -1 1 1 total 0.027181 0.001539 -0 1 2 total 0.265559 0.020699 +1 1 1 total 0.027335 0.002038 +0 1 2 total 0.263007 0.029616 reduced absorption material group in nuclide mean std. dev. -1 1 1 total 0.027162 0.001538 -0 1 2 total 0.265559 0.020699 +1 1 1 total 0.027278 0.002038 +0 1 2 total 0.263007 0.029616 capture material group in nuclide mean std. dev. -1 1 1 total 0.019717 0.001492 -0 1 2 total 0.072029 0.019378 +1 1 1 total 0.019722 0.001980 +0 1 2 total 0.071284 0.032059 fission material group in nuclide mean std. dev. -1 1 1 total 0.007464 0.000222 -0 1 2 total 0.193530 0.015119 +1 1 1 total 0.007613 0.000245 +0 1 2 total 0.191723 0.021698 nu-fission material group in nuclide mean std. dev. -1 1 1 total 0.018925 0.000543 -0 1 2 total 0.471574 0.036840 +1 1 1 total 0.019339 0.000628 +0 1 2 total 0.467173 0.052872 kappa-fission material group in nuclide mean std. dev. -1 1 1 total 1.453014e+06 4.287190e+04 -0 1 2 total 3.742974e+07 2.924022e+06 +1 1 1 total 1.482697e+06 4.755501e+04 +0 1 2 total 3.708035e+07 4.196524e+06 scatter material group in nuclide mean std. dev. -1 1 1 total 0.395591 0.013417 -0 1 2 total 0.395750 0.029309 +1 1 1 total 0.389051 0.013216 +0 1 2 total 0.395644 0.031715 nu-scatter material group in nuclide mean std. dev. -1 1 1 total 0.392941 0.019689 -0 1 2 total 0.396262 0.027471 +1 1 1 total 0.392313 0.009662 +0 1 2 total 0.385086 0.024132 scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.392419 0.019837 -13 1 1 1 P1 total 0.038941 0.006089 -14 1 1 1 P2 total 0.019512 0.003548 -15 1 1 1 P3 total 0.012951 0.002399 -8 1 1 2 P0 total 0.000522 0.000349 -9 1 1 2 P1 total -0.000301 0.000185 -10 1 1 2 P2 total 0.000045 0.000147 -11 1 1 2 P3 total 0.000069 0.000162 +12 1 1 1 P0 total 0.391262 0.009858 +13 1 1 1 P1 total 0.038043 0.007486 +14 1 1 1 P2 total 0.019717 0.003619 +15 1 1 1 P3 total 0.018917 0.001007 +8 1 1 2 P0 total 0.000876 0.000554 +9 1 1 2 P1 total -0.000275 0.000386 +10 1 1 2 P2 total 0.000074 0.000114 +11 1 1 2 P3 total 0.000141 0.000113 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.396262 0.027471 -1 1 2 2 P1 total -0.016133 0.010911 -2 1 2 2 P2 total -0.001147 0.010536 -3 1 2 2 P3 total 0.005359 0.008143 +0 1 2 2 P0 total 0.385086 0.024132 +1 1 2 2 P1 total 0.019196 0.005279 +2 1 2 2 P2 total -0.005654 0.006088 +3 1 2 2 P3 total 0.002768 0.007045 nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.392419 0.019837 -13 1 1 1 P1 total 0.038941 0.006089 -14 1 1 1 P2 total 0.019512 0.003548 -15 1 1 1 P3 total 0.012951 0.002399 -8 1 1 2 P0 total 0.000522 0.000349 -9 1 1 2 P1 total -0.000301 0.000185 -10 1 1 2 P2 total 0.000045 0.000147 -11 1 1 2 P3 total 0.000069 0.000162 +12 1 1 1 P0 total 0.391437 0.009813 +13 1 1 1 P1 total 0.037949 0.007537 +14 1 1 1 P2 total 0.019705 0.003623 +15 1 1 1 P3 total 0.018991 0.001065 +8 1 1 2 P0 total 0.000876 0.000554 +9 1 1 2 P1 total -0.000275 0.000386 +10 1 1 2 P2 total 0.000074 0.000114 +11 1 1 2 P3 total 0.000141 0.000113 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.396262 0.027471 -1 1 2 2 P1 total -0.016133 0.010911 -2 1 2 2 P2 total -0.001147 0.010536 -3 1 2 2 P3 total 0.005359 0.008143 +0 1 2 2 P0 total 0.385086 0.024132 +1 1 2 2 P1 total 0.019196 0.005279 +2 1 2 2 P2 total -0.005654 0.006088 +3 1 2 2 P3 total 0.002768 0.007045 multiplicity matrix - material group in group out nuclide mean std. dev. -3 1 1 1 total 1.0 0.054620 -2 1 1 2 total 1.0 0.942809 -1 1 2 1 total 0.0 0.000000 -0 1 2 2 total 1.0 0.080341 + material group in group out nuclide mean std. dev. +3 1 1 1 total 1.000448 0.020416 +2 1 1 2 total 1.000000 0.894427 +1 1 2 1 total 0.000000 0.000000 +0 1 2 2 total 1.000000 0.085266 nu-fission matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.019257 0.001831 +3 1 1 1 total 0.017516 0.001935 2 1 1 2 total 0.000000 0.000000 -1 1 2 1 total 0.459401 0.022054 +1 1 2 1 total 0.498681 0.013398 0 1 2 2 total 0.000000 0.000000 scatter probability matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.998671 0.054518 -2 1 1 2 total 0.001329 0.000888 +3 1 1 1 total 0.997766 0.020541 +2 1 1 2 total 0.002234 0.001413 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 1.000000 0.080341 +0 1 2 2 total 1.000000 0.085266 consistent scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.395065 0.025390 -13 1 1 1 P1 total 0.039204 0.006325 -14 1 1 1 P2 total 0.019644 0.003656 -15 1 1 1 P3 total 0.013039 0.002470 -8 1 1 2 P0 total 0.000526 0.000352 -9 1 1 2 P1 total -0.000303 0.000186 -10 1 1 2 P2 total 0.000045 0.000148 -11 1 1 2 P3 total 0.000069 0.000163 +12 1 1 1 P0 total 0.388182 0.015419 +13 1 1 1 P1 total 0.037744 0.007517 +14 1 1 1 P2 total 0.019562 0.003641 +15 1 1 1 P3 total 0.018769 0.001154 +8 1 1 2 P0 total 0.000869 0.000551 +9 1 1 2 P1 total -0.000273 0.000383 +10 1 1 2 P2 total 0.000073 0.000113 +11 1 1 2 P3 total 0.000140 0.000112 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.395750 0.043243 -1 1 2 2 P1 total -0.016112 0.010982 -2 1 2 2 P2 total -0.001146 0.010523 -3 1 2 2 P3 total 0.005353 0.008145 +0 1 2 2 P0 total 0.395644 0.046302 +1 1 2 2 P1 total 0.019723 0.005763 +2 1 2 2 P2 total -0.005809 0.006281 +3 1 2 2 P3 total 0.002843 0.007244 consistent nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.395065 0.033321 -13 1 1 1 P1 total 0.039204 0.006677 -14 1 1 1 P2 total 0.019644 0.003810 -15 1 1 1 P3 total 0.013039 0.002571 -8 1 1 2 P0 total 0.000526 0.000608 -9 1 1 2 P1 total -0.000303 0.000341 -10 1 1 2 P2 total 0.000045 0.000154 -11 1 1 2 P3 total 0.000069 0.000175 +12 1 1 1 P0 total 0.388355 0.017343 +13 1 1 1 P1 total 0.037760 0.007560 +14 1 1 1 P2 total 0.019571 0.003664 +15 1 1 1 P3 total 0.018777 0.001216 +8 1 1 2 P0 total 0.000869 0.000953 +9 1 1 2 P1 total -0.000273 0.000454 +10 1 1 2 P2 total 0.000073 0.000131 +11 1 1 2 P3 total 0.000140 0.000168 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.395750 0.053673 -1 1 2 2 P1 total -0.016112 0.011058 -2 1 2 2 P2 total -0.001146 0.010523 -3 1 2 2 P3 total 0.005353 0.008157 +0 1 2 2 P0 total 0.395644 0.057288 +1 1 2 2 P1 total 0.019723 0.006004 +2 1 2 2 P2 total -0.005809 0.006300 +3 1 2 2 P3 total 0.002843 0.007248 chi material group out nuclide mean std. dev. -1 1 1 total 1.0 0.015644 +1 1 1 total 1.0 0.029903 0 1 2 total 0.0 0.000000 chi-prompt material group out nuclide mean std. dev. -1 1 1 total 1.0 0.017529 +1 1 1 total 1.0 0.028494 0 1 2 total 0.0 0.000000 inverse-velocity material group in nuclide mean std. dev. -1 1 1 total 6.047675e-08 4.367288e-09 -0 1 2 total 2.861927e-06 2.241423e-07 +1 1 1 total 6.148661e-08 3.647428e-09 +0 1 2 total 2.844242e-06 3.098230e-07 prompt-nu-fission material group in nuclide mean std. dev. -1 1 1 total 0.018748 0.00054 -0 1 2 total 0.468507 0.03660 +1 1 1 total 0.019154 0.000623 +0 1 2 total 0.464134 0.052528 prompt-nu-fission matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.019049 0.001675 +3 1 1 1 total 0.017516 0.001935 2 1 1 2 total 0.000000 0.000000 -1 1 2 1 total 0.454399 0.022578 +1 1 2 1 total 0.495450 0.012592 0 1 2 2 total 0.000000 0.000000 diffusion-coefficient material group in nuclide mean std. dev. -1 1 1 total 0.868438 0.034686 -0 1 2 total 0.490787 0.036698 +1 1 1 total 0.881035 0.038500 +0 1 2 total 0.519910 0.049301 nu-diffusion-coefficient material group in nuclide mean std. dev. -1 1 1 total 0.868438 0.034686 -0 1 2 total 0.490787 0.036698 +1 1 1 total 0.880816 0.038534 +0 1 2 total 0.519910 0.049301 (n,elastic) material group in nuclide mean std. dev. -1 1 1 total 0.368341 0.013033 -0 1 2 total 0.395750 0.029309 +1 1 1 total 0.361427 0.011879 +0 1 2 total 0.395644 0.031715 (n,level) material group in nuclide mean std. dev. -1 1 1 total 0.000518 0.000016 +1 1 1 total 0.000549 0.000035 0 1 2 total 0.000000 0.000000 (n,2n) material group in nuclide mean std. dev. -1 1 1 total 0.000019 0.000012 +1 1 1 total 0.000058 0.000012 0 1 2 total 0.000000 0.000000 (n,na) - material group in nuclide mean std. dev. -1 1 1 total 0.0 0.0 -0 1 2 total 0.0 0.0 + material group in nuclide mean std. dev. +1 1 1 total 4.608391e-11 2.324841e-11 +0 1 2 total 0.000000e+00 0.000000e+00 (n,nc) material group in nuclide mean std. dev. -1 1 1 total 0.007599 0.000559 +1 1 1 total 0.008349 0.000869 0 1 2 total 0.000000 0.000000 (n,gamma) material group in nuclide mean std. dev. -1 1 1 total 0.019608 0.001470 -0 1 2 total 0.072029 0.005584 +1 1 1 total 0.019640 0.001935 +0 1 2 total 0.071284 0.007918 (n,a) material group in nuclide mean std. dev. -1 1 1 total 0.000109 0.00002 -0 1 2 total 0.000000 0.00000 +1 1 1 total 0.000082 0.000016 +0 1 2 total 0.000000 0.000000 (n,Xa) material group in nuclide mean std. dev. -1 1 1 total 0.000109 0.00002 -0 1 2 total 0.000000 0.00000 +1 1 1 total 0.000082 0.000016 +0 1 2 total 0.000000 0.000000 heating material group in nuclide mean std. dev. -1 1 1 total 1.270644e+06 3.732629e+04 -0 1 2 total 3.241569e+07 2.530346e+06 +1 1 1 total 1.302118e+06 4.240633e+04 +0 1 2 total 3.235834e+07 3.683247e+06 damage-energy material group in nuclide mean std. dev. -1 1 1 total 2405.735342 79.042000 -0 1 2 total 1362.470597 106.435803 +1 1 1 total 2323.848080 106.914413 +0 1 2 total 1349.749682 152.756195 (n,n1) material group in nuclide mean std. dev. -1 1 1 total 0.011931 0.000455 +1 1 1 total 0.011709 0.000412 0 1 2 total 0.000000 0.000000 (n,a0) material group in nuclide mean std. dev. -1 1 1 total 0.000108 0.00002 -0 1 2 total 0.000000 0.00000 +1 1 1 total 0.000076 0.000018 +0 1 2 total 0.000000 0.000000 (n,nc) matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.005745 0.001068 +3 1 1 1 total 0.007009 0.000797 2 1 1 2 total 0.000000 0.000000 1 1 2 1 total 0.000000 0.000000 0 1 2 2 total 0.000000 0.000000 (n,n1) matrix + material group in group out nuclide mean std. dev. +3 1 1 1 total 0.01209 0.00108 +2 1 1 2 total 0.00000 0.00000 +1 1 2 1 total 0.00000 0.00000 +0 1 2 2 total 0.00000 0.00000 +(n,2n) matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.013232 0.001025 +3 1 1 1 total 0.000175 0.000175 2 1 1 2 total 0.000000 0.000000 1 1 2 1 total 0.000000 0.000000 0 1 2 2 total 0.000000 0.000000 -(n,2n) matrix - material group in group out nuclide mean std. dev. -3 1 1 1 total 0.0 0.0 -2 1 1 2 total 0.0 0.0 -1 1 2 1 total 0.0 0.0 -0 1 2 2 total 0.0 0.0 delayed-nu-fission material delayedgroup group in nuclide mean std. dev. -1 1 1 1 total 0.000004 1.226367e-07 -3 1 2 1 total 0.000026 6.725093e-07 -5 1 3 1 total 0.000027 7.028316e-07 -7 1 4 1 total 0.000068 1.919534e-06 -9 1 5 1 total 0.000037 1.268939e-06 -11 1 6 1 total 0.000015 5.136452e-07 -0 1 1 2 total 0.000107 8.388866e-06 -2 1 2 2 total 0.000554 4.330076e-05 -4 1 3 2 total 0.000529 4.133869e-05 -6 1 4 2 total 0.001186 9.268481e-05 -8 1 5 2 total 0.000486 3.799954e-05 -10 1 6 2 total 0.000204 1.591787e-05 +1 1 1 1 total 0.000004 1.358228e-07 +3 1 2 1 total 0.000027 8.873679e-07 +5 1 3 1 total 0.000028 1.017223e-06 +7 1 4 1 total 0.000071 3.064066e-06 +9 1 5 1 total 0.000039 2.180731e-06 +11 1 6 1 total 0.000016 8.808101e-07 +0 1 1 2 total 0.000106 1.203961e-05 +2 1 2 2 total 0.000549 6.214477e-05 +4 1 3 2 total 0.000524 5.932882e-05 +6 1 4 2 total 0.001175 1.330202e-04 +8 1 5 2 total 0.000482 5.453651e-05 +10 1 6 2 total 0.000202 2.284515e-05 chi-delayed material delayedgroup group out nuclide mean std. dev. 1 1 1 1 total 0.0 0.000000 -3 1 2 1 total 0.0 0.000000 +3 1 2 1 total 1.0 1.414214 5 1 3 1 total 0.0 0.000000 -7 1 4 1 total 1.0 0.433956 -9 1 5 1 total 0.0 0.000000 +7 1 4 1 total 1.0 1.414214 +9 1 5 1 total 1.0 1.414214 11 1 6 1 total 0.0 0.000000 0 1 1 2 total 0.0 0.000000 2 1 2 2 total 0.0 0.000000 @@ -259,31 +259,31 @@ chi-delayed beta material delayedgroup group in nuclide mean std. dev. 1 1 1 1 total 0.000225 0.000006 -3 1 2 1 total 0.001359 0.000033 -5 1 3 1 total 0.001412 0.000034 -7 1 4 1 total 0.003611 0.000094 -9 1 5 1 total 0.001950 0.000064 -11 1 6 1 total 0.000801 0.000026 -0 1 1 2 total 0.000228 0.000019 -2 1 2 2 total 0.001175 0.000096 -4 1 3 2 total 0.001122 0.000092 -6 1 4 2 total 0.002516 0.000206 -8 1 5 2 total 0.001031 0.000085 -10 1 6 2 total 0.000432 0.000035 +3 1 2 1 total 0.001373 0.000038 +5 1 3 1 total 0.001433 0.000045 +7 1 4 1 total 0.003692 0.000142 +9 1 5 1 total 0.002016 0.000106 +11 1 6 1 total 0.000827 0.000043 +0 1 1 2 total 0.000228 0.000032 +2 1 2 2 total 0.001175 0.000163 +4 1 3 2 total 0.001122 0.000156 +6 1 4 2 total 0.002516 0.000349 +8 1 5 2 total 0.001031 0.000143 +10 1 6 2 total 0.000432 0.000060 decay-rate material delayedgroup nuclide mean std. dev. -0 1 1 total 0.013352 0.000905 -1 1 2 total 0.032619 0.002094 -2 1 3 total 0.121041 0.007464 -3 1 4 total 0.305491 0.017639 -4 1 5 total 0.860388 0.042833 -5 1 6 total 2.889807 0.145503 +0 1 1 total 0.013356 0.001466 +1 1 2 total 0.032598 0.003432 +2 1 3 total 0.121086 0.012382 +3 1 4 total 0.305945 0.029907 +4 1 5 total 0.862061 0.077144 +5 1 6 total 2.895499 0.260691 delayed-nu-fission matrix material delayedgroup group in group out nuclide mean std. dev. 3 1 1 1 1 total 0.000000 0.000000 7 1 2 1 1 total 0.000000 0.000000 11 1 3 1 1 total 0.000000 0.000000 -15 1 4 1 1 total 0.000207 0.000207 +15 1 4 1 1 total 0.000000 0.000000 19 1 5 1 1 total 0.000000 0.000000 23 1 6 1 1 total 0.000000 0.000000 2 1 1 1 2 total 0.000000 0.000000 @@ -293,10 +293,10 @@ delayed-nu-fission matrix 18 1 5 1 2 total 0.000000 0.000000 22 1 6 1 2 total 0.000000 0.000000 1 1 1 2 1 total 0.000000 0.000000 -5 1 2 2 1 total 0.000000 0.000000 +5 1 2 2 1 total 0.001133 0.001133 9 1 3 2 1 total 0.000000 0.000000 -13 1 4 2 1 total 0.005002 0.001278 -17 1 5 2 1 total 0.000000 0.000000 +13 1 4 2 1 total 0.000988 0.000989 +17 1 5 2 1 total 0.001109 0.001109 21 1 6 2 1 total 0.000000 0.000000 0 1 1 2 2 total 0.000000 0.000000 4 1 2 2 2 total 0.000000 0.000000 @@ -306,28 +306,28 @@ delayed-nu-fission matrix 20 1 6 2 2 total 0.000000 0.000000 total material group in nuclide mean std. dev. -1 2 1 total 0.320478 0.012201 -0 2 2 total 0.300681 0.029685 +1 2 1 total 0.312441 0.009893 +0 2 2 total 0.300527 0.023155 transport material group in nuclide mean std. dev. -1 2 1 total 0.267653 0.015887 -0 2 2 total 0.327250 0.035614 +1 2 1 total 0.275347 0.016021 +0 2 2 total 0.300167 0.026917 nu-transport material group in nuclide mean std. dev. -1 2 1 total 0.267653 0.015887 -0 2 2 total 0.327250 0.035614 +1 2 1 total 0.275347 0.016021 +0 2 2 total 0.300167 0.026917 absorption material group in nuclide mean std. dev. -1 2 1 total 0.001040 0.000121 -0 2 2 total 0.005284 0.000548 +1 2 1 total 0.001395 0.000129 +0 2 2 total 0.005202 0.000498 reduced absorption material group in nuclide mean std. dev. -1 2 1 total 0.001040 0.000121 -0 2 2 total 0.005284 0.000548 +1 2 1 total 0.001390 0.000129 +0 2 2 total 0.005202 0.000498 capture material group in nuclide mean std. dev. -1 2 1 total 0.001040 0.000121 -0 2 2 total 0.005284 0.000548 +1 2 1 total 0.001395 0.000129 +0 2 2 total 0.005202 0.000498 fission material group in nuclide mean std. dev. 1 2 1 total 0.0 0.0 @@ -342,54 +342,54 @@ kappa-fission 0 2 2 total 0.0 0.0 scatter material group in nuclide mean std. dev. -1 2 1 total 0.319438 0.012181 -0 2 2 total 0.295397 0.029142 +1 2 1 total 0.311046 0.009880 +0 2 2 total 0.295325 0.022678 nu-scatter material group in nuclide mean std. dev. -1 2 1 total 0.314727 0.014272 -0 2 2 total 0.295807 0.038170 +1 2 1 total 0.310433 0.013519 +0 2 2 total 0.287667 0.061288 scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 0.314727 0.014272 -13 2 1 1 P1 total 0.052826 0.010175 -14 2 1 1 P2 total 0.033176 0.002264 -15 2 1 1 P3 total 0.006129 0.004317 -8 2 1 2 P0 total 0.000000 0.000000 -9 2 1 2 P1 total 0.000000 0.000000 -10 2 1 2 P2 total 0.000000 0.000000 -11 2 1 2 P3 total 0.000000 0.000000 -4 2 2 1 P0 total 0.000000 0.000000 -5 2 2 1 P1 total 0.000000 0.000000 -6 2 2 1 P2 total 0.000000 0.000000 -7 2 2 1 P3 total 0.000000 0.000000 -0 2 2 2 P0 total 0.295807 0.038170 -1 2 2 2 P1 total -0.026569 0.019676 -2 2 2 2 P2 total -0.005395 0.007578 -3 2 2 2 P3 total -0.005680 0.012737 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 3.099468e-01 1.368691e-02 +13 2 1 1 P1 total 3.709418e-02 1.260219e-02 +14 2 1 1 P2 total 2.620103e-02 2.237097e-03 +15 2 1 1 P3 total 1.039112e-02 2.917283e-03 +8 2 1 2 P0 total 4.858100e-04 4.860246e-04 +9 2 1 2 P1 total 3.762752e-04 3.764414e-04 +10 2 1 2 P2 total 1.942506e-04 1.943364e-04 +11 2 1 2 P3 total -9.482181e-08 9.486370e-08 +4 2 2 1 P0 total 0.000000e+00 0.000000e+00 +5 2 2 1 P1 total 0.000000e+00 0.000000e+00 +6 2 2 1 P2 total 0.000000e+00 0.000000e+00 +7 2 2 1 P3 total 0.000000e+00 0.000000e+00 +0 2 2 2 P0 total 2.876667e-01 6.128794e-02 +1 2 2 2 P1 total -2.172735e-03 1.616275e-02 +2 2 2 2 P2 total 9.596560e-03 1.756046e-02 +3 2 2 2 P3 total -5.006322e-03 1.249952e-02 nu-scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 0.314727 0.014272 -13 2 1 1 P1 total 0.052826 0.010175 -14 2 1 1 P2 total 0.033176 0.002264 -15 2 1 1 P3 total 0.006129 0.004317 -8 2 1 2 P0 total 0.000000 0.000000 -9 2 1 2 P1 total 0.000000 0.000000 -10 2 1 2 P2 total 0.000000 0.000000 -11 2 1 2 P3 total 0.000000 0.000000 -4 2 2 1 P0 total 0.000000 0.000000 -5 2 2 1 P1 total 0.000000 0.000000 -6 2 2 1 P2 total 0.000000 0.000000 -7 2 2 1 P3 total 0.000000 0.000000 -0 2 2 2 P0 total 0.295807 0.038170 -1 2 2 2 P1 total -0.026569 0.019676 -2 2 2 2 P2 total -0.005395 0.007578 -3 2 2 2 P3 total -0.005680 0.012737 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 3.099468e-01 1.368691e-02 +13 2 1 1 P1 total 3.709418e-02 1.260219e-02 +14 2 1 1 P2 total 2.620103e-02 2.237097e-03 +15 2 1 1 P3 total 1.039112e-02 2.917283e-03 +8 2 1 2 P0 total 4.858100e-04 4.860246e-04 +9 2 1 2 P1 total 3.762752e-04 3.764414e-04 +10 2 1 2 P2 total 1.942506e-04 1.943364e-04 +11 2 1 2 P3 total -9.482181e-08 9.486370e-08 +4 2 2 1 P0 total 0.000000e+00 0.000000e+00 +5 2 2 1 P1 total 0.000000e+00 0.000000e+00 +6 2 2 1 P2 total 0.000000e+00 0.000000e+00 +7 2 2 1 P3 total 0.000000e+00 0.000000e+00 +0 2 2 2 P0 total 2.876667e-01 6.128794e-02 +1 2 2 2 P1 total -2.172735e-03 1.616275e-02 +2 2 2 2 P2 total 9.596560e-03 1.756046e-02 +3 2 2 2 P3 total -5.006322e-03 1.249952e-02 multiplicity matrix material group in group out nuclide mean std. dev. -3 2 1 1 total 1.0 0.043852 -2 2 1 2 total 0.0 0.000000 +3 2 1 1 total 1.0 0.046178 +2 2 1 2 total 1.0 1.414214 1 2 2 1 total 0.0 0.000000 -0 2 2 2 total 1.0 0.139361 +0 2 2 2 total 1.0 0.204230 nu-fission matrix material group in group out nuclide mean std. dev. 3 2 1 1 total 0.0 0.0 @@ -397,47 +397,47 @@ nu-fission matrix 1 2 2 1 total 0.0 0.0 0 2 2 2 total 0.0 0.0 scatter probability matrix - material group in group out nuclide mean std. dev. -3 2 1 1 total 1.0 0.043852 -2 2 1 2 total 0.0 0.000000 -1 2 2 1 total 0.0 0.000000 -0 2 2 2 total 1.0 0.139361 + material group in group out nuclide mean std. dev. +3 2 1 1 total 0.998435 0.046097 +2 2 1 2 total 0.001565 0.001566 +1 2 2 1 total 0.000000 0.000000 +0 2 2 2 total 1.000000 0.204230 consistent scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 0.319438 0.018563 -13 2 1 1 P1 total 0.053616 0.010510 -14 2 1 1 P2 total 0.033673 0.002604 -15 2 1 1 P3 total 0.006221 0.004387 -8 2 1 2 P0 total 0.000000 0.000000 -9 2 1 2 P1 total 0.000000 0.000000 -10 2 1 2 P2 total 0.000000 0.000000 -11 2 1 2 P3 total 0.000000 0.000000 -4 2 2 1 P0 total 0.000000 0.000000 -5 2 2 1 P1 total 0.000000 0.000000 -6 2 2 1 P2 total 0.000000 0.000000 -7 2 2 1 P3 total 0.000000 0.000000 -0 2 2 2 P0 total 0.295397 0.050438 -1 2 2 2 P1 total -0.026532 0.019872 -2 2 2 2 P2 total -0.005388 0.007591 -3 2 2 2 P3 total -0.005672 0.012735 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 3.105594e-01 1.740367e-02 +13 2 1 1 P1 total 3.716750e-02 1.269205e-02 +14 2 1 1 P2 total 2.625282e-02 2.417618e-03 +15 2 1 1 P3 total 1.041166e-02 2.945041e-03 +8 2 1 2 P0 total 4.867703e-04 4.872749e-04 +9 2 1 2 P1 total 3.770190e-04 3.774098e-04 +10 2 1 2 P2 total 1.946345e-04 1.948363e-04 +11 2 1 2 P3 total -9.500924e-08 9.510772e-08 +4 2 2 1 P0 total 0.000000e+00 0.000000e+00 +5 2 2 1 P1 total 0.000000e+00 0.000000e+00 +6 2 2 1 P2 total 0.000000e+00 0.000000e+00 +7 2 2 1 P3 total 0.000000e+00 0.000000e+00 +0 2 2 2 P0 total 2.953250e-01 6.443681e-02 +1 2 2 2 P1 total -2.230578e-03 1.659337e-02 +2 2 2 2 P2 total 9.852041e-03 1.803392e-02 +3 2 2 2 P3 total -5.139601e-03 1.283456e-02 consistent nu-scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 0.319438 0.023255 -13 2 1 1 P1 total 0.053616 0.010769 -14 2 1 1 P2 total 0.033673 0.002993 -15 2 1 1 P3 total 0.006221 0.004396 -8 2 1 2 P0 total 0.000000 0.000000 -9 2 1 2 P1 total 0.000000 0.000000 -10 2 1 2 P2 total 0.000000 0.000000 -11 2 1 2 P3 total 0.000000 0.000000 -4 2 2 1 P0 total 0.000000 0.000000 -5 2 2 1 P1 total 0.000000 0.000000 -6 2 2 1 P2 total 0.000000 0.000000 -7 2 2 1 P3 total 0.000000 0.000000 -0 2 2 2 P0 total 0.295397 0.065105 -1 2 2 2 P1 total -0.026532 0.020213 -2 2 2 2 P2 total -0.005388 0.007628 -3 2 2 2 P3 total -0.005672 0.012759 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 3.105594e-01 2.255119e-02 +13 2 1 1 P1 total 3.716750e-02 1.280757e-02 +14 2 1 1 P2 total 2.625282e-02 2.704548e-03 +15 2 1 1 P3 total 1.041166e-02 2.984029e-03 +8 2 1 2 P0 total 4.867703e-04 8.434023e-04 +9 2 1 2 P1 total 3.770190e-04 6.532417e-04 +10 2 1 2 P2 total 1.946345e-04 3.372334e-04 +11 2 1 2 P3 total -9.500924e-08 1.646177e-07 +4 2 2 1 P0 total 0.000000e+00 0.000000e+00 +5 2 2 1 P1 total 0.000000e+00 0.000000e+00 +6 2 2 1 P2 total 0.000000e+00 0.000000e+00 +7 2 2 1 P3 total 0.000000e+00 0.000000e+00 +0 2 2 2 P0 total 2.953250e-01 8.826037e-02 +1 2 2 2 P1 total -2.230578e-03 1.659963e-02 +2 2 2 2 P2 total 9.852041e-03 1.814582e-02 +3 2 2 2 P3 total -5.139601e-03 1.287741e-02 chi material group out nuclide mean std. dev. 1 2 1 total 0.0 0.0 @@ -448,8 +448,8 @@ chi-prompt 0 2 2 total 0.0 0.0 inverse-velocity material group in nuclide mean std. dev. -1 2 1 total 6.068670e-08 4.861582e-09 -0 2 2 total 2.921021e-06 3.028269e-07 +1 2 1 total 6.397205e-08 3.117085e-09 +0 2 2 total 2.875630e-06 2.751728e-07 prompt-nu-fission material group in nuclide mean std. dev. 1 2 1 total 0.0 0.0 @@ -462,72 +462,72 @@ prompt-nu-fission matrix 0 2 2 2 total 0.0 0.0 diffusion-coefficient material group in nuclide mean std. dev. -1 2 1 total 1.245396 0.073923 -0 2 2 total 1.018589 0.110853 +1 2 1 total 1.210594 0.070439 +0 2 2 total 1.110491 0.099580 nu-diffusion-coefficient material group in nuclide mean std. dev. -1 2 1 total 1.245396 0.073923 -0 2 2 total 1.018589 0.110853 +1 2 1 total 1.210594 0.070439 +0 2 2 total 1.110491 0.099580 (n,elastic) material group in nuclide mean std. dev. -1 2 1 total 0.310592 0.012188 -0 2 2 total 0.295397 0.029142 +1 2 1 total 0.301494 0.009403 +0 2 2 total 0.295325 0.022678 (n,level) material group in nuclide mean std. dev. 1 2 1 total 0.0 0.0 0 2 2 total 0.0 0.0 (n,2n) - material group in nuclide mean std. dev. -1 2 1 total 0.0 0.0 -0 2 2 total 0.0 0.0 + material group in nuclide mean std. dev. +1 2 1 total 0.000005 0.000003 +0 2 2 total 0.000000 0.000000 (n,na) material group in nuclide mean std. dev. -1 2 1 total 2.157338e-13 1.864239e-13 +1 2 1 total 1.085156e-09 6.357350e-10 0 2 2 total 0.000000e+00 0.000000e+00 (n,nc) - material group in nuclide mean std. dev. -1 2 1 total 0.00187 0.000152 -0 2 2 total 0.00000 0.000000 + material group in nuclide mean std. dev. +1 2 1 total 0.001947 0.000276 +0 2 2 total 0.000000 0.000000 (n,gamma) material group in nuclide mean std. dev. -1 2 1 total 0.001038 0.000121 -0 2 2 total 0.005283 0.000548 +1 2 1 total 0.001392 0.000128 +0 2 2 total 0.005201 0.000498 (n,a) material group in nuclide mean std. dev. -1 2 1 total 7.402079e-07 3.197538e-08 -0 2 2 total 2.735682e-07 2.698845e-08 +1 2 1 total 8.373873e-07 5.295954e-08 +0 2 2 total 2.735007e-07 2.100237e-08 (n,Xa) material group in nuclide mean std. dev. -1 2 1 total 7.402081e-07 3.197534e-08 -0 2 2 total 2.735682e-07 2.698845e-08 +1 2 1 total 8.384725e-07 5.277215e-08 +0 2 2 total 2.735007e-07 2.100237e-08 heating material group in nuclide mean std. dev. -1 2 1 total 2479.710231 157.161879 -0 2 2 total 2.314706 0.265682 +1 2 1 total 2151.700349 142.319459 +0 2 2 total 1.947222 0.155279 damage-energy material group in nuclide mean std. dev. -1 2 1 total 1566.139383 61.602407 -0 2 2 total 0.288739 0.029698 +1 2 1 total 1591.760682 90.145807 +0 2 2 total 0.284888 0.026354 (n,n1) material group in nuclide mean std. dev. -1 2 1 total 0.002897 0.000181 -0 2 2 total 0.000000 0.000000 +1 2 1 total 0.002962 0.00032 +0 2 2 total 0.000000 0.00000 (n,a0) material group in nuclide mean std. dev. -1 2 1 total 6.646569e-07 2.959064e-08 -0 2 2 total 2.732927e-07 2.696126e-08 +1 2 1 total 7.199126e-07 5.011215e-08 +0 2 2 total 2.732253e-07 2.098122e-08 (n,nc) matrix material group in group out nuclide mean std. dev. -3 2 1 1 total 0.000488 0.000488 +3 2 1 1 total 0.002915 0.000493 2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 0 2 2 2 total 0.000000 0.000000 (n,n1) matrix - material group in group out nuclide mean std. dev. -3 2 1 1 total 0.00244 0.001094 -2 2 1 2 total 0.00000 0.000000 -1 2 2 1 total 0.00000 0.000000 -0 2 2 2 total 0.00000 0.000000 + material group in group out nuclide mean std. dev. +3 2 1 1 total 0.002429 0.001332 +2 2 1 2 total 0.000000 0.000000 +1 2 2 1 total 0.000000 0.000000 +0 2 2 2 total 0.000000 0.000000 (n,2n) matrix material group in group out nuclide mean std. dev. 3 2 1 1 total 0.0 0.0 @@ -612,28 +612,28 @@ delayed-nu-fission matrix 20 2 6 2 2 total 0.0 0.0 total material group in nuclide mean std. dev. -1 3 1 total 0.692034 0.019973 -0 3 2 total 2.033425 0.189463 +1 3 1 total 0.684512 0.015513 +0 3 2 total 2.038387 0.113839 transport material group in nuclide mean std. dev. -1 3 1 total 0.298754 0.021602 -0 3 2 total 1.459465 0.197868 +1 3 1 total 0.291947 0.019086 +0 3 2 total 1.464248 0.116005 nu-transport material group in nuclide mean std. dev. -1 3 1 total 0.298754 0.021602 -0 3 2 total 1.459465 0.197868 +1 3 1 total 0.291947 0.019086 +0 3 2 total 1.464248 0.116005 absorption material group in nuclide mean std. dev. -1 3 1 total 0.000699 0.000035 -0 3 2 total 0.031056 0.003017 +1 3 1 total 0.000715 0.000032 +0 3 2 total 0.031290 0.001882 reduced absorption material group in nuclide mean std. dev. -1 3 1 total 0.000699 0.000035 -0 3 2 total 0.031056 0.003017 +1 3 1 total 0.000715 0.000032 +0 3 2 total 0.031290 0.001882 capture material group in nuclide mean std. dev. -1 3 1 total 0.000699 0.000035 -0 3 2 total 0.031056 0.003017 +1 3 1 total 0.000715 0.000032 +0 3 2 total 0.031290 0.001882 fission material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 @@ -648,54 +648,54 @@ kappa-fission 0 3 2 total 0.0 0.0 scatter material group in nuclide mean std. dev. -1 3 1 total 0.691336 0.019945 -0 3 2 total 2.002368 0.186454 +1 3 1 total 0.683797 0.015496 +0 3 2 total 2.007097 0.111979 nu-scatter material group in nuclide mean std. dev. -1 3 1 total 0.684356 0.011639 -0 3 2 total 1.990840 0.178205 +1 3 1 total 0.684650 0.017888 +0 3 2 total 1.992357 0.090997 scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.652706 0.011111 -13 3 1 1 P1 total 0.393203 0.008164 -14 3 1 1 P2 total 0.162146 0.003332 -15 3 1 1 P3 total 0.014967 0.004773 -8 3 1 2 P0 total 0.031650 0.000613 -9 3 1 2 P1 total 0.009845 0.000647 -10 3 1 2 P2 total -0.003284 0.000758 -11 3 1 2 P3 total -0.003971 0.000187 -4 3 2 1 P0 total 0.000474 0.000475 -5 3 2 1 P1 total 0.000396 0.000397 -6 3 2 1 P2 total 0.000260 0.000261 -7 3 2 1 P3 total 0.000099 0.000099 -0 3 2 2 P0 total 1.990366 0.178042 -1 3 2 2 P1 total 0.523546 0.053239 -2 3 2 2 P2 total 0.101180 0.015832 -3 3 2 2 P3 total 0.017873 0.005685 +12 3 1 1 P0 total 0.654867 0.017215 +13 3 1 1 P1 total 0.392566 0.011118 +14 3 1 1 P2 total 0.165345 0.005121 +15 3 1 1 P3 total 0.016963 0.003137 +8 3 1 2 P0 total 0.029783 0.000974 +9 3 1 2 P1 total 0.008810 0.000479 +10 3 1 2 P2 total -0.002652 0.000630 +11 3 1 2 P3 total -0.002872 0.000517 +4 3 2 1 P0 total 0.000000 0.000000 +5 3 2 1 P1 total 0.000000 0.000000 +6 3 2 1 P2 total 0.000000 0.000000 +7 3 2 1 P3 total 0.000000 0.000000 +0 3 2 2 P0 total 1.992357 0.090997 +1 3 2 2 P1 total 0.526383 0.022569 +2 3 2 2 P2 total 0.108016 0.009047 +3 3 2 2 P3 total 0.016856 0.010707 nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.652706 0.011111 -13 3 1 1 P1 total 0.393203 0.008164 -14 3 1 1 P2 total 0.162146 0.003332 -15 3 1 1 P3 total 0.014967 0.004773 -8 3 1 2 P0 total 0.031650 0.000613 -9 3 1 2 P1 total 0.009845 0.000647 -10 3 1 2 P2 total -0.003284 0.000758 -11 3 1 2 P3 total -0.003971 0.000187 -4 3 2 1 P0 total 0.000474 0.000475 -5 3 2 1 P1 total 0.000396 0.000397 -6 3 2 1 P2 total 0.000260 0.000261 -7 3 2 1 P3 total 0.000099 0.000099 -0 3 2 2 P0 total 1.990366 0.178042 -1 3 2 2 P1 total 0.523546 0.053239 -2 3 2 2 P2 total 0.101180 0.015832 -3 3 2 2 P3 total 0.017873 0.005685 +12 3 1 1 P0 total 0.654867 0.017215 +13 3 1 1 P1 total 0.392566 0.011118 +14 3 1 1 P2 total 0.165345 0.005121 +15 3 1 1 P3 total 0.016963 0.003137 +8 3 1 2 P0 total 0.029783 0.000974 +9 3 1 2 P1 total 0.008810 0.000479 +10 3 1 2 P2 total -0.002652 0.000630 +11 3 1 2 P3 total -0.002872 0.000517 +4 3 2 1 P0 total 0.000000 0.000000 +5 3 2 1 P1 total 0.000000 0.000000 +6 3 2 1 P2 total 0.000000 0.000000 +7 3 2 1 P3 total 0.000000 0.000000 +0 3 2 2 P0 total 1.992357 0.090997 +1 3 2 2 P1 total 0.526383 0.022569 +2 3 2 2 P2 total 0.108016 0.009047 +3 3 2 2 P3 total 0.016856 0.010707 multiplicity matrix material group in group out nuclide mean std. dev. -3 3 1 1 total 1.0 0.020267 -2 3 1 2 total 1.0 0.024112 -1 3 2 1 total 1.0 1.414214 -0 3 2 2 total 1.0 0.093189 +3 3 1 1 total 1.0 0.020014 +2 3 1 2 total 1.0 0.034047 +1 3 2 1 total 0.0 0.000000 +0 3 2 2 total 1.0 0.048455 nu-fission matrix material group in group out nuclide mean std. dev. 3 3 1 1 total 0.0 0.0 @@ -704,46 +704,46 @@ nu-fission matrix 0 3 2 2 total 0.0 0.0 scatter probability matrix material group in group out nuclide mean std. dev. -3 3 1 1 total 0.953753 0.018903 -2 3 1 2 total 0.046247 0.001011 -1 3 2 1 total 0.000238 0.000239 -0 3 2 2 total 0.999762 0.093156 +3 3 1 1 total 0.956499 0.018759 +2 3 1 2 total 0.043501 0.001202 +1 3 2 1 total 0.000000 0.000000 +0 3 2 2 total 1.000000 0.048455 consistent scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.659363 0.023079 -13 3 1 1 P1 total 0.397213 0.014683 -14 3 1 1 P2 total 0.163800 0.006035 -15 3 1 1 P3 total 0.015120 0.004843 -8 3 1 2 P0 total 0.031973 0.001157 -9 3 1 2 P1 total 0.009945 0.000721 -10 3 1 2 P2 total -0.003318 0.000772 -11 3 1 2 P3 total -0.004011 0.000225 -4 3 2 1 P0 total 0.000477 0.000480 -5 3 2 1 P1 total 0.000399 0.000401 -6 3 2 1 P2 total 0.000262 0.000264 -7 3 2 1 P3 total 0.000099 0.000100 -0 3 2 2 P0 total 2.001892 0.263710 -1 3 2 2 P1 total 0.526577 0.073894 -2 3 2 2 P2 total 0.101766 0.018719 -3 3 2 2 P3 total 0.017976 0.005976 +12 3 1 1 P0 total 0.654051 0.019602 +13 3 1 1 P1 total 0.392076 0.012456 +14 3 1 1 P2 total 0.165139 0.005640 +15 3 1 1 P3 total 0.016942 0.003143 +8 3 1 2 P0 total 0.029746 0.001063 +9 3 1 2 P1 total 0.008799 0.000495 +10 3 1 2 P2 total -0.002648 0.000631 +11 3 1 2 P3 total -0.002868 0.000518 +4 3 2 1 P0 total 0.000000 0.000000 +5 3 2 1 P1 total 0.000000 0.000000 +6 3 2 1 P2 total 0.000000 0.000000 +7 3 2 1 P3 total 0.000000 0.000000 +0 3 2 2 P0 total 2.007097 0.148316 +1 3 2 2 P1 total 0.530278 0.038286 +2 3 2 2 P2 total 0.108815 0.011091 +3 3 2 2 P3 total 0.016981 0.010831 consistent nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.659363 0.026669 -13 3 1 1 P1 total 0.397213 0.016746 -14 3 1 1 P2 total 0.163800 0.006888 -15 3 1 1 P3 total 0.015120 0.004853 -8 3 1 2 P0 total 0.031973 0.001391 -9 3 1 2 P1 total 0.009945 0.000759 -10 3 1 2 P2 total -0.003318 0.000776 -11 3 1 2 P3 total -0.004011 0.000245 -4 3 2 1 P0 total 0.000477 0.000827 -5 3 2 1 P1 total 0.000399 0.000692 -6 3 2 1 P2 total 0.000262 0.000455 -7 3 2 1 P3 total 0.000099 0.000172 -0 3 2 2 P0 total 2.001892 0.323026 -1 3 2 2 P1 total 0.526577 0.088703 -2 3 2 2 P2 total 0.101766 0.020985 -3 3 2 2 P3 total 0.017976 0.006207 +12 3 1 1 P0 total 0.654051 0.023571 +13 3 1 1 P1 total 0.392076 0.014722 +14 3 1 1 P2 total 0.165139 0.006537 +15 3 1 1 P3 total 0.016942 0.003161 +8 3 1 2 P0 total 0.029746 0.001468 +9 3 1 2 P1 total 0.008799 0.000579 +10 3 1 2 P2 total -0.002648 0.000637 +11 3 1 2 P3 total -0.002868 0.000528 +4 3 2 1 P0 total 0.000000 0.000000 +5 3 2 1 P1 total 0.000000 0.000000 +6 3 2 1 P2 total 0.000000 0.000000 +7 3 2 1 P3 total 0.000000 0.000000 +0 3 2 2 P0 total 2.007097 0.177359 +1 3 2 2 P1 total 0.530278 0.046109 +2 3 2 2 P2 total 0.108815 0.012281 +3 3 2 2 P3 total 0.016981 0.010862 chi material group out nuclide mean std. dev. 1 3 1 total 0.0 0.0 @@ -754,8 +754,8 @@ chi-prompt 0 3 2 total 0.0 0.0 inverse-velocity material group in nuclide mean std. dev. -1 3 1 total 6.187551e-08 3.945367e-09 -0 3 2 total 2.984343e-06 2.898715e-07 +1 3 1 total 6.447429e-08 2.866173e-09 +0 3 2 total 3.006810e-06 1.808750e-07 prompt-nu-fission material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 @@ -768,60 +768,60 @@ prompt-nu-fission matrix 0 3 2 2 total 0.0 0.0 diffusion-coefficient material group in nuclide mean std. dev. -1 3 1 total 1.115746 0.080676 -0 3 2 total 0.228394 0.030965 +1 3 1 total 1.141761 0.074641 +0 3 2 total 0.227648 0.018035 nu-diffusion-coefficient material group in nuclide mean std. dev. -1 3 1 total 1.115746 0.080676 -0 3 2 total 0.228394 0.030965 +1 3 1 total 1.141761 0.074641 +0 3 2 total 0.227648 0.018035 (n,elastic) material group in nuclide mean std. dev. -1 3 1 total 0.691333 0.019945 -0 3 2 total 2.002368 0.186454 +1 3 1 total 0.683777 0.015496 +0 3 2 total 2.007097 0.111979 (n,level) - material group in nuclide mean std. dev. -1 3 1 total 0.000003 0.000002 -0 3 2 total 0.000000 0.000000 + material group in nuclide mean std. dev. +1 3 1 total 0.00002 0.000006 +0 3 2 total 0.00000 0.000000 (n,2n) material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 0 3 2 total 0.0 0.0 (n,na) - material group in nuclide mean std. dev. -1 3 1 total 0.0 0.0 -0 3 2 total 0.0 0.0 + material group in nuclide mean std. dev. +1 3 1 total 3.714897e-11 2.058007e-11 +0 3 2 total 0.000000e+00 0.000000e+00 (n,nc) material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 0 3 2 total 0.0 0.0 (n,gamma) material group in nuclide mean std. dev. -1 3 1 total 0.000225 0.000014 -0 3 2 total 0.010815 0.001050 +1 3 1 total 0.000234 0.000010 +0 3 2 total 0.010896 0.000655 (n,a) material group in nuclide mean std. dev. -1 3 1 total 0.000474 0.000021 -0 3 2 total 0.020241 0.001966 +1 3 1 total 0.000481 0.000022 +0 3 2 total 0.020394 0.001227 (n,Xa) material group in nuclide mean std. dev. -1 3 1 total 0.000474 0.000021 -0 3 2 total 0.020242 0.001966 +1 3 1 total 0.000481 0.000022 +0 3 2 total 0.020394 0.001227 heating material group in nuclide mean std. dev. -1 3 1 total 74978.139095 3970.725596 -0 3 2 total 58539.697122 6443.645451 +1 3 1 total 64982.284489 3654.924951 +0 3 2 total 49786.819570 2967.698779 damage-energy material group in nuclide mean std. dev. -1 3 1 total 1161.596397 41.187452 -0 3 2 total 330.473159 32.100259 +1 3 1 total 1147.965123 36.313921 +0 3 2 total 332.961479 20.030541 (n,n1) material group in nuclide mean std. dev. -1 3 1 total 2.912377e-07 3.897408e-08 +1 3 1 total 7.030461e-07 2.133325e-07 0 3 2 total 0.000000e+00 0.000000e+00 (n,a0) material group in nuclide mean std. dev. -1 3 1 total 0.000082 0.000009 -0 3 2 total 0.001273 0.000124 +1 3 1 total 0.000068 0.000011 +0 3 2 total 0.001283 0.000077 (n,nc) matrix material group in group out nuclide mean std. dev. 3 3 1 1 total 0.0 0.0 diff --git a/tests/regression_tests/mgxs_library_no_nuclides/test.py b/tests/regression_tests/mgxs_library_no_nuclides/test.py index a02086af3..af14a5dc8 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_no_nuclides/test.py @@ -39,7 +39,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _get_results(self, hash_output=False): """Digest info in the statepoint and return as a string.""" diff --git a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat index c35e57f0e..e45fe389e 100644 --- a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat @@ -1,1771 +1,1769 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,2n) - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,3n) - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,4n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - U234 U235 U238 O16 - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 30 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 5 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 5 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - nu-fission - analog - - - 1 2 5 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - scatter - tracklength - - - 1 2 5 30 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - scatter - tracklength - - - 1 2 5 30 - U234 U235 U238 O16 - scatter - analog - - - 1 2 5 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 54 - U234 U235 U238 O16 - nu-fission - analog - - - 1 5 - U234 U235 U238 O16 - nu-fission - analog - - - 1 54 - U234 U235 U238 O16 - prompt-nu-fission - analog - - - 1 5 - U234 U235 U238 O16 - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,elastic) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,level) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,2n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,na) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,nc) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,gamma) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,a) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,Xa) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - heating - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - damage-energy - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,n1) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,a0) - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - (n,nc) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - (n,n1) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - (n,2n) - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 106 2 - total - flux - analog - - - 106 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 106 2 - total - flux - analog - - - 106 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,2n) - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,3n) - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,4n) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - fission - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - fission - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - kappa-fission - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - tracklength - - - 106 2 - total - flux - analog - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 106 2 - total - flux - analog - - - 106 2 5 30 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 - total - flux - analog - - - 106 2 5 30 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 - total - flux - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - tracklength - - - 106 2 5 30 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - tracklength - - - 106 2 5 30 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 106 54 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 106 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 106 54 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - analog - - - 106 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - inverse-velocity - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - tracklength - - - 106 2 - total - flux - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 106 2 - total - flux - analog - - - 106 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 106 2 - total - flux - analog - - - 106 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,elastic) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,level) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,2n) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,na) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,nc) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,gamma) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,a) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,Xa) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - heating - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - damage-energy - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,n1) - tracklength - - - 106 2 - total - flux - tracklength - - - 106 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,a0) - tracklength - - - 106 2 - total - flux - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,nc) - analog - - - 106 2 - total - flux - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,n1) - analog - - - 106 2 - total - flux - analog - - - 106 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,2n) - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - total - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - total - tracklength - - - 211 2 - total - flux - analog - - - 211 5 6 - H1 O16 B10 B11 - scatter - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - total - tracklength - - - 211 2 - total - flux - analog - - - 211 5 6 - H1 O16 B10 B11 - nu-scatter - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - absorption - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - absorption - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,2n) - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,3n) - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,4n) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - absorption - tracklength - - - 211 2 - H1 O16 B10 B11 - fission - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - fission - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - nu-fission - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - kappa-fission - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - scatter - tracklength - - - 211 2 - total - flux - analog - - - 211 2 - H1 O16 B10 B11 - nu-scatter - analog - - - 211 2 - total - flux - analog - - - 211 2 5 30 - H1 O16 B10 B11 - scatter - analog - - - 211 2 - total - flux - analog - - - 211 2 5 30 - H1 O16 B10 B11 - nu-scatter - analog - - - 211 2 5 - H1 O16 B10 B11 - nu-scatter - analog - - - 211 2 5 - H1 O16 B10 B11 - scatter - analog - - - 211 2 - total - flux - analog - - - 211 2 5 - H1 O16 B10 B11 - nu-fission - analog - - - 211 2 5 - H1 O16 B10 B11 - scatter - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - scatter - tracklength - - - 211 2 5 30 - H1 O16 B10 B11 - scatter - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - scatter - tracklength - - - 211 2 5 30 - H1 O16 B10 B11 - scatter - analog - - - 211 2 5 - H1 O16 B10 B11 - nu-scatter - analog - - - 211 54 - H1 O16 B10 B11 - nu-fission - analog - - - 211 5 - H1 O16 B10 B11 - nu-fission - analog - - - 211 54 - H1 O16 B10 B11 - prompt-nu-fission - analog - - - 211 5 - H1 O16 B10 B11 - prompt-nu-fission - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - inverse-velocity - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - prompt-nu-fission - tracklength - - - 211 2 - total - flux - analog - - - 211 2 5 - H1 O16 B10 B11 - prompt-nu-fission - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - total - tracklength - - - 211 2 - total - flux - analog - - - 211 5 6 - H1 O16 B10 B11 - scatter - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - total - tracklength - - - 211 2 - total - flux - analog - - - 211 5 6 - H1 O16 B10 B11 - nu-scatter - analog - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,elastic) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,level) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,2n) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,na) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,nc) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,gamma) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,a) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,Xa) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - heating - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - damage-energy - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,n1) - tracklength - - - 211 2 - total - flux - tracklength - - - 211 2 - H1 O16 B10 B11 - (n,a0) - tracklength - - - 211 2 - total - flux - analog - - - 211 2 5 - H1 O16 B10 B11 - (n,nc) - analog - - - 211 2 - total - flux - analog - - - 211 2 5 - H1 O16 B10 B11 - (n,n1) - analog - - - 211 2 - total - flux - analog - - - 211 2 5 - H1 O16 B10 B11 - (n,2n) - analog - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,2n) + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,3n) + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + U234 U235 U238 O16 + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 5 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 5 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + nu-fission + analog + + + 1 2 5 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + scatter + tracklength + + + 1 2 5 30 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + scatter + tracklength + + + 1 2 5 30 + U234 U235 U238 O16 + scatter + analog + + + 1 2 5 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 54 + U234 U235 U238 O16 + nu-fission + analog + + + 1 5 + U234 U235 U238 O16 + nu-fission + analog + + + 1 54 + U234 U235 U238 O16 + prompt-nu-fission + analog + + + 1 5 + U234 U235 U238 O16 + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,elastic) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,level) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,2n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,na) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,nc) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,gamma) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,a) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,Xa) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + heating + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + damage-energy + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,n1) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,a0) + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + (n,nc) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + (n,n1) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + (n,2n) + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,2n) + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,3n) + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,4n) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + kappa-fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + tracklength + + + 106 2 + total + flux + analog + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 + total + flux + analog + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + analog + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + tracklength + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + tracklength + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 54 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 106 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 106 54 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + analog + + + 106 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + inverse-velocity + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + tracklength + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,elastic) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,level) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,2n) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,na) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,nc) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,gamma) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,a) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,Xa) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + heating + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + damage-energy + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,n1) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,a0) + tracklength + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,nc) + analog + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,n1) + analog + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,2n) + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + absorption + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + absorption + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,2n) + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,3n) + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,4n) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + absorption + tracklength + + + 211 2 + H1 O16 B10 B11 + fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + nu-fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + kappa-fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + scatter + tracklength + + + 211 2 + total + flux + analog + + + 211 2 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 + total + flux + analog + + + 211 2 5 30 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + analog + + + 211 2 5 30 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 5 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 5 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + nu-fission + analog + + + 211 2 5 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + scatter + tracklength + + + 211 2 5 30 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + scatter + tracklength + + + 211 2 5 30 + H1 O16 B10 B11 + scatter + analog + + + 211 2 5 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 54 + H1 O16 B10 B11 + nu-fission + analog + + + 211 5 + H1 O16 B10 B11 + nu-fission + analog + + + 211 54 + H1 O16 B10 B11 + prompt-nu-fission + analog + + + 211 5 + H1 O16 B10 B11 + prompt-nu-fission + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + inverse-velocity + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + prompt-nu-fission + tracklength + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + prompt-nu-fission + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,elastic) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,level) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,2n) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,na) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,nc) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,gamma) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,a) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,Xa) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + heating + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + damage-energy + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,n1) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,a0) + tracklength + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + (n,nc) + analog + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + (n,n1) + analog + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + (n,2n) + analog + + diff --git a/tests/regression_tests/mgxs_library_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_nuclides/results_true.dat index c05ec9b48..7825aba3f 100644 --- a/tests/regression_tests/mgxs_library_nuclides/results_true.dat +++ b/tests/regression_tests/mgxs_library_nuclides/results_true.dat @@ -1 +1 @@ -d1e4ab2c0d85bb5da617db9c7a3731494114e2fd3ba75ae8eaa1f0a36648f73fcbcfb487390789b0124719cabdcbfa84af4bb118f11bdc548d1065e1b5af836a \ No newline at end of file +93ad567f1b36461a68d4ead0ff5cfa4a2003b05cf5241a232544545001a94a33fc7b99f21af277ea3a24861d38aac3a9ac36c8b1706c4b3b33caec589df2c90c \ No newline at end of file diff --git a/tests/regression_tests/mgxs_library_nuclides/test.py b/tests/regression_tests/mgxs_library_nuclides/test.py index a10070358..8a7673565 100644 --- a/tests/regression_tests/mgxs_library_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_nuclides/test.py @@ -36,7 +36,7 @@ class MGXSTestHarness(PyAPITestHarness): self.mgxs_lib.build_library() # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=False) + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) def _get_results(self, hash_output=True): """Digest info in the statepoint and return as a string.""" diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/__init__.py b/tests/regression_tests/mgxs_library_specific_nuclides/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat deleted file mode 100644 index dd9d1ceb0..000000000 --- a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - - - - 1 2 3 - - - 0.0 0.625 20000000.0 - - - 1 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 2 - - - 3 - - - 383 2 - total - flux - tracklength - - - 1 2 - U235 total - total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) - tracklength - - - 383 2 - total - flux - analog - - - 1 5 6 - U235 total - scatter nu-scatter - analog - - - 1 2 - U235 total - nu-scatter - analog - - - 1 2 5 30 - U235 total - scatter nu-scatter - analog - - - 1 2 5 - U235 total - nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) - analog - - - 1 54 - U235 total - nu-fission prompt-nu-fission - analog - - - 1 5 - U235 total - nu-fission prompt-nu-fission - analog - - - 106 2 - Zr90 total - total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) - tracklength - - - 106 5 6 - Zr90 total - scatter nu-scatter - analog - - - 106 2 - Zr90 total - nu-scatter - analog - - - 106 2 5 30 - Zr90 total - scatter nu-scatter - analog - - - 106 2 5 - Zr90 total - nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) - analog - - - 106 54 - Zr90 total - nu-fission prompt-nu-fission - analog - - - 106 5 - Zr90 total - nu-fission prompt-nu-fission - analog - - - 251 2 - H1 total - total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) - tracklength - - - 251 5 6 - H1 total - scatter nu-scatter - analog - - - 251 2 - H1 total - nu-scatter - analog - - - 251 2 5 30 - H1 total - scatter nu-scatter - analog - - - 251 2 5 - H1 total - nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) - analog - - - 251 54 - H1 total - nu-fission prompt-nu-fission - analog - - - 251 5 - H1 total - nu-fission prompt-nu-fission - analog - - - diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat deleted file mode 100644 index 0c44eb132..000000000 --- a/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat +++ /dev/null @@ -1 +0,0 @@ -efcd9fd6be2ed6c98bbe5279cbacdb287597fcbbc4ed49e164b07e0861f28877b1bef2ad82d70fdac95965f7ed0d0990f77c8545718836b1b55a16b4243208d0 \ No newline at end of file diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/test.py b/tests/regression_tests/mgxs_library_specific_nuclides/test.py deleted file mode 100644 index 0ccbb83bd..000000000 --- a/tests/regression_tests/mgxs_library_specific_nuclides/test.py +++ /dev/null @@ -1,71 +0,0 @@ -import hashlib - -import openmc -import openmc.mgxs -from openmc.examples import pwr_pin_cell - -from tests.testing_harness import PyAPITestHarness - - -class MGXSTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) - - # Initialize MGXS Library for a few cross section types - self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) - self.mgxs_lib.by_nuclide = True - - # Test relevant MGXS types - relevant_MGXS_TYPES = [item for item in openmc.mgxs.MGXS_TYPES - if item != 'current'] - # Add in a subset of openmc.mgxs.ARBITRARY_VECTOR_TYPES and - # openmc.mgxs.ARBITRARY_MATRIX_TYPES so we can see the code works, - # but not use too much resources - relevant_MGXS_TYPES += [ - "(n,elastic)", "(n,level)", "(n,2n)", "(n,na)", "(n,nc)", - "(n,gamma)", "(n,a)", "(n,Xa)", "heating", "damage-energy", - "(n,n1)", "(n,a0)", "(n,nc) matrix", "(n,n1) matrix", - "(n,2n) matrix"] - self.mgxs_lib.mgxs_types = tuple(relevant_MGXS_TYPES) - self.mgxs_lib.energy_groups = energy_groups - self.mgxs_lib.legendre_order = 3 - self.mgxs_lib.domain_type = 'material' - self.mgxs_lib.nuclides = ['U235', 'Zr90', 'H1'] - self.mgxs_lib.build_library() - - # Add tallies - self.mgxs_lib.add_to_tallies(self._model.tallies, merge=True) - - def _get_results(self, hash_output=True): - """Digest info in the statepoint and return as a string.""" - - # Read the statepoint file. - sp = openmc.StatePoint(self._sp_name) - - # Load the MGXS library from the statepoint - self.mgxs_lib.load_from_statepoint(sp) - - # Build a string from Pandas Dataframe for each MGXS - outstr = '' - for domain in self.mgxs_lib.domains: - for mgxs_type in self.mgxs_lib.mgxs_types: - mgxs = self.mgxs_lib.get_mgxs(domain, mgxs_type) - df = mgxs.get_pandas_dataframe() - outstr += df.to_string() + '\n' - - # Hash the results if necessary - if hash_output: - sha512 = hashlib.sha512() - sha512.update(outstr.encode('utf-8')) - outstr = sha512.hexdigest() - - return outstr - - -def test_mgxs_library_specific_nuclides(): - model = pwr_pin_cell() - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/microxs/test.py b/tests/regression_tests/microxs/test.py index 781be3ef7..dbfe3357b 100644 --- a/tests/regression_tests/microxs/test.py +++ b/tests/regression_tests/microxs/test.py @@ -4,75 +4,49 @@ from pathlib import Path import numpy as np import pytest import openmc -from openmc.deplete import MicroXS, get_microxs_and_flux -from tests.regression_tests import config +from openmc.deplete import MicroXS CHAIN_FILE = Path(__file__).parents[2] / "chain_simple.xml" @pytest.fixture(scope="module") def model(): fuel = openmc.Material(name="uo2") - fuel.add_nuclide("U235", 1.0) - fuel.add_nuclide("O16", 2.0) + fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) + fuel.add_element("O", 2) fuel.set_density("g/cc", 10.4) - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere, fill=fuel) - geometry = openmc.Geometry([cell]) + clad = openmc.Material(name="clad") + clad.add_element("Zr", 1) + clad.set_density("g/cc", 6) + + water = openmc.Material(name="water") + water.add_element("O", 1) + water.add_element("H", 2) + water.set_density("g/cc", 1.0) + water.add_s_alpha_beta("c_H_in_H2O") + + radii = [0.42, 0.45] + fuel.volume = np.pi * radii[0] ** 2 + + materials = openmc.Materials([fuel, clad, water]) + + pin_surfaces = [openmc.ZCylinder(r=r) for r in radii] + pin_univ = openmc.model.pin(pin_surfaces, materials) + bound_box = openmc.rectangular_prism(1.24, 1.24, boundary_type="reflective") + root_cell = openmc.Cell(fill=pin_univ, region=bound_box) + geometry = openmc.Geometry([root_cell]) settings = openmc.Settings() settings.particles = 1000 - settings.inactive = 5 - settings.batches = 10 + settings.inactive = 10 + settings.batches = 50 - return openmc.Model(geometry, settings=settings) + return openmc.Model(geometry, materials, settings) -@pytest.mark.parametrize( - "domain_type, rr_mode", - [ - ("materials", "direct"), - ("materials", "flux"), - ("materials", "hybrid"), - ("mesh", "direct"), - ("mesh", "flux"), - ] -) -def test_from_model(model, domain_type, rr_mode): - if domain_type == 'materials': - domains = list(model.geometry.get_all_materials().values()) - elif domain_type == 'mesh': - mesh = openmc.RegularMesh() - mesh.lower_left = (-10., -10.) - mesh.upper_right = (10., 10.) - mesh.dimension = (1, 1) - domains = mesh - nuclides = ['U235', 'O16', 'Xe135'] - kwargs = { - 'chain_file': CHAIN_FILE, - 'path_statepoint': 'neutron_transport.h5', - } - if rr_mode == 'flux': - kwargs['reaction_rate_mode'] = 'flux' - kwargs['energies'] = 'CASMO-40' - elif rr_mode == 'hybrid': - kwargs['reaction_rate_mode'] = 'flux' - kwargs['energies'] = 'CASMO-40' - kwargs['reaction_rate_opts'] = { - 'nuclides': ['U235'], - 'reactions': ['fission'], - } - else: - kwargs['reaction_rate_mode'] = rr_mode - _, test_xs = get_microxs_and_flux(model, domains, nuclides, **kwargs) - if config['update']: - test_xs[0].to_csv(f'test_reference_{domain_type}_{rr_mode}.csv') +def test_from_model(model): + ref_xs = MicroXS.from_csv('test_reference.csv') + test_xs = MicroXS.from_model(model, model.materials[0], CHAIN_FILE) - # Make sure results match reference results - ref_xs = MicroXS.from_csv(f'test_reference_{domain_type}_{rr_mode}.csv') - np.testing.assert_allclose(test_xs[0].data, ref_xs.data, rtol=1e-11) - - # Make sure statepoint file was saved - assert Path('neutron_transport.h5').exists() - Path('neutron_transport.h5').unlink() + np.testing.assert_allclose(test_xs, ref_xs, rtol=1e-11) diff --git a/tests/regression_tests/microxs/test_reference.csv b/tests/regression_tests/microxs/test_reference.csv new file mode 100644 index 000000000..787ce74c3 --- /dev/null +++ b/tests/regression_tests/microxs/test_reference.csv @@ -0,0 +1,13 @@ +nuclide,"(n,gamma)",fission +U234,22.231989822002465,0.49620744663749855 +U235,10.479008971197121,48.41787337164604 +U238,0.8673334105437324,0.10467880588762352 +U236,8.65171044607122,0.31948392400019293 +O16,7.497851000107524e-05,0.0 +O17,0.0004079227797153371,0.0 +I135,6.842395323713927,0.0 +Xe135,227463.86426990604,0.0 +Xe136,0.02317896034753588,0.0 +Cs135,2.1721665580713623,0.0 +Gd157,12786.09939237018,0.0 +Gd156,3.4006085445846983,0.0 diff --git a/tests/regression_tests/microxs/test_reference_materials_direct.csv b/tests/regression_tests/microxs/test_reference_materials_direct.csv deleted file mode 100644 index 4a63fed85..000000000 --- a/tests/regression_tests/microxs/test_reference_materials_direct.csv +++ /dev/null @@ -1,7 +0,0 @@ -nuclides,reactions,groups,xs -U235,"(n,gamma)",1,0.1475718536187164 -U235,fission,1,1.2504996049257149 -O16,"(n,gamma)",1,0.00010981236259441559 -O16,fission,1,0.0 -Xe135,"(n,gamma)",1,0.014570546772870611 -Xe135,fission,1,0.0 diff --git a/tests/regression_tests/microxs/test_reference_materials_flux.csv b/tests/regression_tests/microxs/test_reference_materials_flux.csv deleted file mode 100644 index 5eb29902e..000000000 --- a/tests/regression_tests/microxs/test_reference_materials_flux.csv +++ /dev/null @@ -1,7 +0,0 @@ -nuclides,reactions,groups,xs -U235,"(n,gamma)",1,0.15003016703758473 -U235,fission,1,1.2646269005413537 -O16,"(n,gamma)",1,0.00012069778439640301 -O16,fission,1,0.0 -Xe135,"(n,gamma)",1,0.014820264774863562 -Xe135,fission,1,0.0 diff --git a/tests/regression_tests/microxs/test_reference_materials_hybrid.csv b/tests/regression_tests/microxs/test_reference_materials_hybrid.csv deleted file mode 100644 index 6d17a5e2b..000000000 --- a/tests/regression_tests/microxs/test_reference_materials_hybrid.csv +++ /dev/null @@ -1,7 +0,0 @@ -nuclides,reactions,groups,xs -U235,"(n,gamma)",1,0.1500301670375847 -U235,fission,1,1.2578145727734291 -O16,"(n,gamma)",1,0.00012069778439640312 -O16,fission,1,0.0 -Xe135,"(n,gamma)",1,0.014820264774863558 -Xe135,fission,1,0.0 diff --git a/tests/regression_tests/microxs/test_reference_mesh_direct.csv b/tests/regression_tests/microxs/test_reference_mesh_direct.csv deleted file mode 100644 index 60160ee51..000000000 --- a/tests/regression_tests/microxs/test_reference_mesh_direct.csv +++ /dev/null @@ -1,7 +0,0 @@ -nuclides,reactions,groups,xs -U235,"(n,gamma)",1,0.14757185361871633 -U235,fission,1,1.2504996049257142 -O16,"(n,gamma)",1,0.0001098123625944155 -O16,fission,1,0.0 -Xe135,"(n,gamma)",1,0.0145705467728706 -Xe135,fission,1,0.0 diff --git a/tests/regression_tests/microxs/test_reference_mesh_flux.csv b/tests/regression_tests/microxs/test_reference_mesh_flux.csv deleted file mode 100644 index 5eb29902e..000000000 --- a/tests/regression_tests/microxs/test_reference_mesh_flux.csv +++ /dev/null @@ -1,7 +0,0 @@ -nuclides,reactions,groups,xs -U235,"(n,gamma)",1,0.15003016703758473 -U235,fission,1,1.2646269005413537 -O16,"(n,gamma)",1,0.00012069778439640301 -O16,fission,1,0.0 -Xe135,"(n,gamma)",1,0.014820264774863562 -Xe135,fission,1,0.0 diff --git a/tests/regression_tests/model_xml/__init__.py b/tests/regression_tests/model_xml/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat deleted file mode 100644 index 18c0552ce..000000000 --- a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 10000 - 10 - 5 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - diff --git a/tests/regression_tests/model_xml/energy_laws_inputs_true.dat b/tests/regression_tests/model_xml/energy_laws_inputs_true.dat deleted file mode 100644 index 8c5191217..000000000 --- a/tests/regression_tests/model_xml/energy_laws_inputs_true.dat +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - diff --git a/tests/regression_tests/model_xml/inputs_true.dat b/tests/regression_tests/model_xml/inputs_true.dat deleted file mode 100644 index c1ef13665..000000000 --- a/tests/regression_tests/model_xml/inputs_true.dat +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 0 0 0 - - - - 14000000.0 1.0 - - - ttb - true - - 1000.0 - - - - - 16 - - - neutron photon electron positron - - - 1 2 - current - - - 2 - Al27 total - total (n,gamma) - tracklength - - - 2 - Al27 total - total heating (n,gamma) - collision - - - 2 - Al27 total - total heating (n,gamma) - analog - - - diff --git a/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat b/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat deleted file mode 100644 index 06abef582..000000000 --- a/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 1.2 1.2 - 1 - 2 2 - -1.2 -1.2 - -2 1 -1 1 - - - 2.4 2.4 - 2 2 - -2.4 -2.4 - -4 4 -4 4 - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - diff --git a/tests/regression_tests/model_xml/photon_production_inputs_true.dat b/tests/regression_tests/model_xml/photon_production_inputs_true.dat deleted file mode 100644 index 0ae0079f4..000000000 --- a/tests/regression_tests/model_xml/photon_production_inputs_true.dat +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 0 0 0 - - - - 14000000.0 1.0 - - - ttb - true - - 1000.0 - - - - - 1 - - - neutron photon electron positron - - - neutron - - - 0.0 20000000.0 - - - neutron photon - 0.0 100000.0 300000.0 500000.0 2000000.0 20000000.0 - - - 1 2 - current - - - 2 - Al27 total - total (n,gamma) - tracklength - - - 2 - Al27 total - total heating (n,gamma) - collision - - - 2 - Al27 total - total heating (n,gamma) - analog - - - 5 3 4 - events - analog - - - diff --git a/tests/regression_tests/model_xml/test.py b/tests/regression_tests/model_xml/test.py deleted file mode 100644 index c67a72ed3..000000000 --- a/tests/regression_tests/model_xml/test.py +++ /dev/null @@ -1,100 +0,0 @@ -from difflib import unified_diff -import glob -import filecmp -import os -from pathlib import Path - -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness, colorize - -# use a few models from other tests to make sure the same results are -# produced when using a single model.xml file as input -from ..adj_cell_rotation.test import model as adj_cell_rotation_model -from ..lattice_multiple.test import model as lattice_multiple_model -from ..energy_laws.test import model as energy_laws_model -from ..photon_production.test import model as photon_production_model - - -class ModelXMLTestHarness(PyAPITestHarness): - """Accept a results file to check against and assume inputs_true is the contents of a model.xml file. - """ - def __init__(self, model=None, inputs_true=None, results_true=None): - statepoint_name = f'statepoint.{model.settings.batches}.h5' - super().__init__(statepoint_name, model, inputs_true) - - self.results_true = 'results_true.dat' if results_true is None else results_true - - def _build_inputs(self): - self._model.export_to_model_xml() - - def _get_inputs(self): - return open('model.xml').read() - - def _compare_results(self): - """Make sure the current results agree with the reference.""" - compare = filecmp.cmp('results_test.dat', self.results_true) - if not compare: - expected = open(self.results_true).readlines() - actual = open('results_test.dat').readlines() - diff = unified_diff(expected, actual, self.results_true, - 'results_test.dat') - print('Result differences:') - print(''.join(colorize(diff))) - os.rename('results_test.dat', 'results_error.dat') - assert compare, 'Results do not agree' - - def _cleanup(self): - super()._cleanup() - if os.path.exists('model.xml'): - os.remove('model.xml') - - -test_names = [ - 'adj_cell_rotation', - 'lattice_multiple', - 'energy_laws', - 'photon_production' -] - - -@pytest.mark.parametrize("test_name", test_names, ids=lambda test: test) -def test_model_xml(test_name, request): - openmc.reset_auto_ids() - - test_path = '../' + test_name - results = test_path + "/results_true.dat" - inputs = test_name + "_inputs_true.dat" - model_name = test_name + "_model" - harness = ModelXMLTestHarness(request.getfixturevalue(model_name), inputs, results) - harness.main() - -def test_input_arg(run_in_tmpdir): - - pincell = openmc.examples.pwr_pin_cell() - - pincell.settings.particles = 100 - - # export to separate XML files and run - pincell.export_to_xml() - openmc.run() - - # make sure the executable isn't falling back on the separate XMLs - for f in glob.glob('*.xml'): - os.remove(f) - # now export to a single XML file with a custom name - pincell.export_to_model_xml('pincell.xml') - assert Path('pincell.xml').exists() - - # run by specifying that single file - openmc.run(path_input='pincell.xml') - - # check that this works for plotting too - openmc.plot_geometry(path_input='pincell.xml') - - # now ensure we get an error for an incorrect filename, - # even in the presence of other, valid XML files - pincell.export_to_model_xml() - with pytest.raises(RuntimeError, match='ex-em-ell.xml'): - openmc.run(path_input='ex-em-ell.xml') \ No newline at end of file diff --git a/tests/regression_tests/multipole/inputs_true.dat b/tests/regression_tests/multipole/inputs_true.dat index 3b78db77b..3bbcc2024 100644 --- a/tests/regression_tests/multipole/inputs_true.dat +++ b/tests/regression_tests/multipole/inputs_true.dat @@ -1,56 +1,55 @@ - - - - - - - - - - - - - - - - - 500 700 0 800 - - - - - 2.0 2.0 - 1 - 2 2 - -2.0 -2.0 - + + + + + + + 2.0 2.0 + 1 + 2 2 + -2.0 -2.0 + 11 11 11 11 - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - -1 -1 -1 1 1 1 - - - true - 1000 - - - - U235 O16 total - total fission (n,gamma) elastic (n,p) - - - + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + -1 -1 -1 1 1 1 + + + true + 1000 + + + + + U235 O16 total + total fission (n,gamma) elastic (n,p) + + diff --git a/tests/regression_tests/multipole/results_true.dat b/tests/regression_tests/multipole/results_true.dat index 40b42b1a0..955f88a4a 100644 --- a/tests/regression_tests/multipole/results_true.dat +++ b/tests/regression_tests/multipole/results_true.dat @@ -1,36 +1,36 @@ k-combined: -1.315804E+00 7.070811E-02 +1.377711E+00 1.297376E-02 tally 1: -3.840178E+00 -2.953217E+00 -2.769369E+00 -1.535605E+00 -5.400560E-01 -5.840168E-02 -4.595308E-01 -4.237758E-02 +3.861112E+00 +2.991150E+00 +2.787756E+00 +1.559383E+00 +5.422517E-01 +5.899488E-02 +4.575965E-01 +4.201819E-02 0.000000E+00 0.000000E+00 -2.283789E+01 -1.044032E+02 +2.250654E+01 +1.013609E+02 0.000000E+00 0.000000E+00 -6.960971E-04 -9.704386E-08 -2.281620E+01 -1.042051E+02 -3.667073E-05 -1.048567E-09 -3.655557E+02 -2.676173E+04 -2.769369E+00 -1.535605E+00 -2.199058E+00 -9.681253E-01 -3.604950E+02 -2.602657E+04 -3.667073E-05 -1.048567E-09 +6.830189E-04 +9.338756E-08 +2.248753E+01 +1.011895E+02 +1.147267E-05 +4.624497E-11 +3.580777E+02 +2.567385E+04 +2.787756E+00 +1.559383E+00 +2.157976E+00 +9.322753E-01 +3.530401E+02 +2.495723E+04 +1.147267E-05 +4.624497E-11 Cell ID = 11 Name = @@ -38,6 +38,5 @@ Cell Region = -1 Rotation = None Temperature = [500. 700. 0. 800.] - Density = None Translation = None Volume = None diff --git a/tests/regression_tests/multipole/test.py b/tests/regression_tests/multipole/test.py index 2f7369a9d..4c4353c84 100644 --- a/tests/regression_tests/multipole/test.py +++ b/tests/regression_tests/multipole/test.py @@ -53,7 +53,7 @@ def make_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + model.settings.source = openmc.Source(space=openmc.stats.Box( [-1, -1, -1], [1, 1, 1])) model.settings.temperature = {'tolerance': 1000, 'multipole': True} diff --git a/tests/regression_tests/ncrystal/__init__.py b/tests/regression_tests/ncrystal/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/ncrystal/inputs_true.dat b/tests/regression_tests/ncrystal/inputs_true.dat deleted file mode 100644 index 81ee2e312..000000000 --- a/tests/regression_tests/ncrystal/inputs_true.dat +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - fixed source - 100000 - 10 - - - 0 0 -20 - - - - 0.012 1.0 - - - - - - 1 - - - 0.0 0.017453292519943295 0.03490658503988659 0.05235987755982989 0.06981317007977318 0.08726646259971647 0.10471975511965978 0.12217304763960307 0.13962634015954636 0.15707963267948966 0.17453292519943295 0.19198621771937624 0.20943951023931956 0.22689280275926285 0.24434609527920614 0.2617993877991494 0.2792526803190927 0.29670597283903605 0.3141592653589793 0.33161255787892263 0.3490658503988659 0.3665191429188092 0.3839724354387525 0.4014257279586958 0.4188790204786391 0.4363323129985824 0.4537856055185257 0.47123889803846897 0.4886921905584123 0.5061454830783556 0.5235987755982988 0.5410520681182421 0.5585053606381855 0.5759586531581288 0.5934119456780721 0.6108652381980153 0.6283185307179586 0.6457718232379019 0.6632251157578453 0.6806784082777885 0.6981317007977318 0.7155849933176751 0.7330382858376184 0.7504915783575618 0.767944870877505 0.7853981633974483 0.8028514559173916 0.8203047484373349 0.8377580409572782 0.8552113334772214 0.8726646259971648 0.8901179185171081 0.9075712110370514 0.9250245035569946 0.9424777960769379 0.9599310885968813 0.9773843811168246 0.9948376736367679 1.0122909661567112 1.0297442586766545 1.0471975511965976 1.064650843716541 1.0821041362364843 1.0995574287564276 1.117010721276371 1.1344640137963142 1.1519173063162575 1.1693705988362009 1.1868238913561442 1.2042771838760873 1.2217304763960306 1.239183768915974 1.2566370614359172 1.2740903539558606 1.2915436464758039 1.3089969389957472 1.3264502315156905 1.3439035240356338 1.361356816555577 1.3788101090755203 1.3962634015954636 1.413716694115407 1.4311699866353502 1.4486232791552935 1.4660765716752369 1.4835298641951802 1.5009831567151235 1.5184364492350666 1.53588974175501 1.5533430342749532 1.5707963267948966 1.5882496193148399 1.6057029118347832 1.6231562043547265 1.6406094968746698 1.6580627893946132 1.6755160819145565 1.6929693744344996 1.710422666954443 1.7278759594743862 1.7453292519943295 1.7627825445142729 1.7802358370342162 1.7976891295541595 1.8151424220741028 1.8325957145940461 1.8500490071139892 1.8675022996339325 1.8849555921538759 1.9024088846738192 1.9198621771937625 1.9373154697137058 1.9547687622336491 1.9722220547535925 1.9896753472735358 2.007128639793479 2.0245819323134224 2.0420352248333655 2.059488517353309 2.076941809873252 2.0943951023931953 2.111848394913139 2.129301687433082 2.1467549799530254 2.1642082724729685 2.181661564992912 2.199114857512855 2.2165681500327987 2.234021442552742 2.251474735072685 2.2689280275926285 2.2863813201125716 2.303834612632515 2.321287905152458 2.3387411976724017 2.356194490192345 2.3736477827122884 2.3911010752322315 2.4085543677521746 2.426007660272118 2.443460952792061 2.4609142453120048 2.478367537831948 2.4958208303518914 2.5132741228718345 2.530727415391778 2.548180707911721 2.5656340004316642 2.5830872929516078 2.600540585471551 2.6179938779914944 2.6354471705114375 2.652900463031381 2.670353755551324 2.6878070480712677 2.705260340591211 2.722713633111154 2.7401669256310974 2.7576202181510405 2.775073510670984 2.792526803190927 2.8099800957108707 2.827433388230814 2.8448866807507573 2.8623399732707004 2.8797932657906435 2.897246558310587 2.91469985083053 2.9321531433504737 2.949606435870417 2.9670597283903604 2.9845130209103035 3.001966313430247 3.01941960595019 3.036872898470133 3.0543261909900767 3.07177948351002 3.0892327760299634 3.1066860685499065 3.12413936106985 3.141592653589793 - - - 1 - - - 1 2 3 - current - - - diff --git a/tests/regression_tests/ncrystal/results_true.dat b/tests/regression_tests/ncrystal/results_true.dat deleted file mode 100644 index 28c02c51c..000000000 --- a/tests/regression_tests/ncrystal/results_true.dat +++ /dev/null @@ -1,181 +0,0 @@ - surface polar low [rad] polar high [rad] cellfrom nuclide score mean std. dev. -0 1 0.00e+00 1.75e-02 1 total current 9.82e-01 1.43e-04 -1 1 1.75e-02 3.49e-02 1 total current 0.00e+00 0.00e+00 -2 1 3.49e-02 5.24e-02 1 total current 1.00e-06 1.00e-06 -3 1 5.24e-02 6.98e-02 1 total current 0.00e+00 0.00e+00 -4 1 6.98e-02 8.73e-02 1 total current 0.00e+00 0.00e+00 -5 1 8.73e-02 1.05e-01 1 total current 1.00e-06 1.00e-06 -6 1 1.05e-01 1.22e-01 1 total current 0.00e+00 0.00e+00 -7 1 1.22e-01 1.40e-01 1 total current 1.00e-06 1.00e-06 -8 1 1.40e-01 1.57e-01 1 total current 1.00e-06 1.00e-06 -9 1 1.57e-01 1.75e-01 1 total current 1.00e-06 1.00e-06 -10 1 1.75e-01 1.92e-01 1 total current 0.00e+00 0.00e+00 -11 1 1.92e-01 2.09e-01 1 total current 2.00e-06 1.33e-06 -12 1 2.09e-01 2.27e-01 1 total current 0.00e+00 0.00e+00 -13 1 2.27e-01 2.44e-01 1 total current 1.00e-06 1.00e-06 -14 1 2.44e-01 2.62e-01 1 total current 1.00e-06 1.00e-06 -15 1 2.62e-01 2.79e-01 1 total current 2.00e-06 1.33e-06 -16 1 2.79e-01 2.97e-01 1 total current 0.00e+00 0.00e+00 -17 1 2.97e-01 3.14e-01 1 total current 2.00e-06 2.00e-06 -18 1 3.14e-01 3.32e-01 1 total current 1.00e-06 1.00e-06 -19 1 3.32e-01 3.49e-01 1 total current 1.00e-06 1.00e-06 -20 1 3.49e-01 3.67e-01 1 total current 2.00e-06 1.33e-06 -21 1 3.67e-01 3.84e-01 1 total current 0.00e+00 0.00e+00 -22 1 3.84e-01 4.01e-01 1 total current 2.00e-06 1.33e-06 -23 1 4.01e-01 4.19e-01 1 total current 2.00e-06 1.33e-06 -24 1 4.19e-01 4.36e-01 1 total current 1.00e-06 1.00e-06 -25 1 4.36e-01 4.54e-01 1 total current 2.00e-06 2.00e-06 -26 1 4.54e-01 4.71e-01 1 total current 5.00e-06 2.24e-06 -27 1 4.71e-01 4.89e-01 1 total current 4.00e-06 1.63e-06 -28 1 4.89e-01 5.06e-01 1 total current 3.00e-06 1.53e-06 -29 1 5.06e-01 5.24e-01 1 total current 3.00e-06 1.53e-06 -30 1 5.24e-01 5.41e-01 1 total current 3.00e-06 1.53e-06 -31 1 5.41e-01 5.59e-01 1 total current 7.00e-06 2.13e-06 -32 1 5.59e-01 5.76e-01 1 total current 3.00e-06 1.53e-06 -33 1 5.76e-01 5.93e-01 1 total current 3.00e-06 1.53e-06 -34 1 5.93e-01 6.11e-01 1 total current 2.00e-06 1.33e-06 -35 1 6.11e-01 6.28e-01 1 total current 2.00e-06 1.33e-06 -36 1 6.28e-01 6.46e-01 1 total current 3.00e-06 2.13e-06 -37 1 6.46e-01 6.63e-01 1 total current 3.00e-06 1.53e-06 -38 1 6.63e-01 6.81e-01 1 total current 2.00e-06 1.33e-06 -39 1 6.81e-01 6.98e-01 1 total current 3.00e-06 1.53e-06 -40 1 6.98e-01 7.16e-01 1 total current 1.00e-06 1.00e-06 -41 1 7.16e-01 7.33e-01 1 total current 6.00e-06 2.67e-06 -42 1 7.33e-01 7.50e-01 1 total current 6.00e-06 2.21e-06 -43 1 7.50e-01 7.68e-01 1 total current 7.00e-06 3.35e-06 -44 1 7.68e-01 7.85e-01 1 total current 6.00e-06 2.67e-06 -45 1 7.85e-01 8.03e-01 1 total current 6.00e-06 2.21e-06 -46 1 8.03e-01 8.20e-01 1 total current 7.00e-06 2.13e-06 -47 1 8.20e-01 8.38e-01 1 total current 5.00e-06 2.24e-06 -48 1 8.38e-01 8.55e-01 1 total current 3.00e-06 1.53e-06 -49 1 8.55e-01 8.73e-01 1 total current 8.00e-06 3.27e-06 -50 1 8.73e-01 8.90e-01 1 total current 7.00e-06 2.13e-06 -51 1 8.90e-01 9.08e-01 1 total current 6.00e-06 2.21e-06 -52 1 9.08e-01 9.25e-01 1 total current 4.00e-06 2.21e-06 -53 1 9.25e-01 9.42e-01 1 total current 1.20e-05 3.27e-06 -54 1 9.42e-01 9.60e-01 1 total current 8.00e-06 3.89e-06 -55 1 9.60e-01 9.77e-01 1 total current 1.20e-05 4.42e-06 -56 1 9.77e-01 9.95e-01 1 total current 7.00e-06 3.67e-06 -57 1 9.95e-01 1.01e+00 1 total current 1.20e-05 3.89e-06 -58 1 1.01e+00 1.03e+00 1 total current 9.00e-06 2.33e-06 -59 1 1.03e+00 1.05e+00 1 total current 6.00e-06 2.67e-06 -60 1 1.05e+00 1.06e+00 1 total current 7.00e-06 2.13e-06 -61 1 1.06e+00 1.08e+00 1 total current 5.00e-06 2.24e-06 -62 1 1.08e+00 1.10e+00 1 total current 1.20e-05 2.91e-06 -63 1 1.10e+00 1.12e+00 1 total current 1.30e-05 3.35e-06 -64 1 1.12e+00 1.13e+00 1 total current 9.00e-06 3.14e-06 -65 1 1.13e+00 1.15e+00 1 total current 1.20e-05 3.89e-06 -66 1 1.15e+00 1.17e+00 1 total current 6.00e-06 2.21e-06 -67 1 1.17e+00 1.19e+00 1 total current 5.11e-03 4.20e-05 -68 1 1.19e+00 1.20e+00 1 total current 8.00e-06 3.27e-06 -69 1 1.20e+00 1.22e+00 1 total current 1.30e-05 4.48e-06 -70 1 1.22e+00 1.24e+00 1 total current 1.20e-05 3.89e-06 -71 1 1.24e+00 1.26e+00 1 total current 1.50e-05 4.28e-06 -72 1 1.26e+00 1.27e+00 1 total current 7.00e-06 3.00e-06 -73 1 1.27e+00 1.29e+00 1 total current 1.60e-05 3.71e-06 -74 1 1.29e+00 1.31e+00 1 total current 9.00e-06 3.79e-06 -75 1 1.31e+00 1.33e+00 1 total current 1.30e-05 2.60e-06 -76 1 1.33e+00 1.34e+00 1 total current 1.60e-05 3.06e-06 -77 1 1.34e+00 1.36e+00 1 total current 1.40e-05 2.67e-06 -78 1 1.36e+00 1.38e+00 1 total current 1.40e-05 6.86e-06 -79 1 1.38e+00 1.40e+00 1 total current 1.50e-05 4.28e-06 -80 1 1.40e+00 1.41e+00 1 total current 3.26e-03 6.93e-05 -81 1 1.41e+00 1.43e+00 1 total current 1.40e-05 3.71e-06 -82 1 1.43e+00 1.45e+00 1 total current 1.30e-05 3.00e-06 -83 1 1.45e+00 1.47e+00 1 total current 1.30e-05 3.67e-06 -84 1 1.47e+00 1.48e+00 1 total current 1.70e-05 5.59e-06 -85 1 1.48e+00 1.50e+00 1 total current 1.70e-05 3.67e-06 -86 1 1.50e+00 1.52e+00 1 total current 1.40e-05 3.40e-06 -87 1 1.52e+00 1.54e+00 1 total current 2.50e-05 4.53e-06 -88 1 1.54e+00 1.55e+00 1 total current 1.30e-05 5.39e-06 -89 1 1.55e+00 1.57e+00 1 total current 1.80e-05 4.67e-06 -90 1 1.57e+00 1.59e+00 1 total current 1.40e-05 4.52e-06 -91 1 1.59e+00 1.61e+00 1 total current 1.70e-05 4.23e-06 -92 1 1.61e+00 1.62e+00 1 total current 1.40e-05 3.71e-06 -93 1 1.62e+00 1.64e+00 1 total current 1.00e-05 2.11e-06 -94 1 1.64e+00 1.66e+00 1 total current 2.00e-05 4.22e-06 -95 1 1.66e+00 1.68e+00 1 total current 2.30e-05 5.59e-06 -96 1 1.68e+00 1.69e+00 1 total current 1.70e-05 6.51e-06 -97 1 1.69e+00 1.71e+00 1 total current 1.30e-05 3.00e-06 -98 1 1.71e+00 1.73e+00 1 total current 1.50e-05 4.01e-06 -99 1 1.73e+00 1.75e+00 1 total current 1.70e-05 3.96e-06 -100 1 1.75e+00 1.76e+00 1 total current 1.80e-05 5.12e-06 -101 1 1.76e+00 1.78e+00 1 total current 2.50e-05 6.54e-06 -102 1 1.78e+00 1.80e+00 1 total current 1.80e-05 3.59e-06 -103 1 1.80e+00 1.82e+00 1 total current 1.50e-05 4.01e-06 -104 1 1.82e+00 1.83e+00 1 total current 1.10e-05 4.07e-06 -105 1 1.83e+00 1.85e+00 1 total current 1.50e-05 4.01e-06 -106 1 1.85e+00 1.87e+00 1 total current 1.90e-05 4.82e-06 -107 1 1.87e+00 1.88e+00 1 total current 2.30e-05 3.96e-06 -108 1 1.88e+00 1.90e+00 1 total current 2.00e-05 3.94e-06 -109 1 1.90e+00 1.92e+00 1 total current 1.50e-05 3.42e-06 -110 1 1.92e+00 1.94e+00 1 total current 2.20e-05 5.12e-06 -111 1 1.94e+00 1.95e+00 1 total current 2.10e-05 5.86e-06 -112 1 1.95e+00 1.97e+00 1 total current 2.60e-05 4.27e-06 -113 1 1.97e+00 1.99e+00 1 total current 2.20e-05 4.16e-06 -114 1 1.99e+00 2.01e+00 1 total current 2.40e-05 5.42e-06 -115 1 2.01e+00 2.02e+00 1 total current 1.60e-05 4.52e-06 -116 1 2.02e+00 2.04e+00 1 total current 1.30e-05 3.35e-06 -117 1 2.04e+00 2.06e+00 1 total current 1.90e-05 4.07e-06 -118 1 2.06e+00 2.08e+00 1 total current 1.30e-05 3.00e-06 -119 1 2.08e+00 2.09e+00 1 total current 1.50e-05 4.28e-06 -120 1 2.09e+00 2.11e+00 1 total current 3.00e-05 4.94e-06 -121 1 2.11e+00 2.13e+00 1 total current 2.30e-05 5.39e-06 -122 1 2.13e+00 2.15e+00 1 total current 2.20e-05 4.67e-06 -123 1 2.15e+00 2.16e+00 1 total current 1.80e-05 4.67e-06 -124 1 2.16e+00 2.18e+00 1 total current 1.50e-05 4.01e-06 -125 1 2.18e+00 2.20e+00 1 total current 1.80e-05 4.16e-06 -126 1 2.20e+00 2.22e+00 1 total current 1.80e-05 4.42e-06 -127 1 2.22e+00 2.23e+00 1 total current 1.80e-05 5.54e-06 -128 1 2.23e+00 2.25e+00 1 total current 1.90e-05 4.33e-06 -129 1 2.25e+00 2.27e+00 1 total current 1.00e-05 3.33e-06 -130 1 2.27e+00 2.29e+00 1 total current 1.80e-05 4.42e-06 -131 1 2.29e+00 2.30e+00 1 total current 4.15e-03 5.40e-05 -132 1 2.30e+00 2.32e+00 1 total current 1.90e-05 2.33e-06 -133 1 2.32e+00 2.34e+00 1 total current 2.30e-05 3.96e-06 -134 1 2.34e+00 2.36e+00 1 total current 1.90e-05 3.48e-06 -135 1 2.36e+00 2.37e+00 1 total current 1.60e-05 3.71e-06 -136 1 2.37e+00 2.39e+00 1 total current 1.70e-05 4.48e-06 -137 1 2.39e+00 2.41e+00 1 total current 2.30e-05 4.48e-06 -138 1 2.41e+00 2.43e+00 1 total current 2.10e-05 3.48e-06 -139 1 2.43e+00 2.44e+00 1 total current 1.60e-05 2.21e-06 -140 1 2.44e+00 2.46e+00 1 total current 9.00e-06 2.77e-06 -141 1 2.46e+00 2.48e+00 1 total current 1.30e-05 3.00e-06 -142 1 2.48e+00 2.50e+00 1 total current 2.70e-05 3.67e-06 -143 1 2.50e+00 2.51e+00 1 total current 1.90e-05 4.07e-06 -144 1 2.51e+00 2.53e+00 1 total current 1.20e-05 4.16e-06 -145 1 2.53e+00 2.55e+00 1 total current 1.30e-05 2.13e-06 -146 1 2.55e+00 2.57e+00 1 total current 1.10e-05 2.33e-06 -147 1 2.57e+00 2.58e+00 1 total current 1.50e-05 3.07e-06 -148 1 2.58e+00 2.60e+00 1 total current 1.20e-05 2.49e-06 -149 1 2.60e+00 2.62e+00 1 total current 1.80e-05 5.54e-06 -150 1 2.62e+00 2.64e+00 1 total current 1.30e-05 3.67e-06 -151 1 2.64e+00 2.65e+00 1 total current 1.60e-05 3.40e-06 -152 1 2.65e+00 2.67e+00 1 total current 7.00e-06 3.35e-06 -153 1 2.67e+00 2.69e+00 1 total current 1.00e-05 2.98e-06 -154 1 2.69e+00 2.71e+00 1 total current 7.00e-06 3.35e-06 -155 1 2.71e+00 2.72e+00 1 total current 1.20e-05 2.91e-06 -156 1 2.72e+00 2.74e+00 1 total current 9.00e-06 2.33e-06 -157 1 2.74e+00 2.76e+00 1 total current 1.00e-05 3.33e-06 -158 1 2.76e+00 2.78e+00 1 total current 1.10e-05 3.14e-06 -159 1 2.78e+00 2.79e+00 1 total current 1.00e-05 3.33e-06 -160 1 2.79e+00 2.81e+00 1 total current 1.40e-05 4.76e-06 -161 1 2.81e+00 2.83e+00 1 total current 8.00e-06 2.91e-06 -162 1 2.83e+00 2.84e+00 1 total current 5.00e-06 2.69e-06 -163 1 2.84e+00 2.86e+00 1 total current 6.00e-06 2.21e-06 -164 1 2.86e+00 2.88e+00 1 total current 5.00e-06 1.67e-06 -165 1 2.88e+00 2.90e+00 1 total current 4.00e-06 2.21e-06 -166 1 2.90e+00 2.91e+00 1 total current 7.00e-06 2.13e-06 -167 1 2.91e+00 2.93e+00 1 total current 6.00e-06 2.67e-06 -168 1 2.93e+00 2.95e+00 1 total current 7.00e-06 2.13e-06 -169 1 2.95e+00 2.97e+00 1 total current 5.00e-06 1.67e-06 -170 1 2.97e+00 2.98e+00 1 total current 3.00e-06 1.53e-06 -171 1 2.98e+00 3.00e+00 1 total current 6.00e-06 2.21e-06 -172 1 3.00e+00 3.02e+00 1 total current 3.00e-06 1.53e-06 -173 1 3.02e+00 3.04e+00 1 total current 1.00e-05 2.98e-06 -174 1 3.04e+00 3.05e+00 1 total current 2.00e-06 1.33e-06 -175 1 3.05e+00 3.07e+00 1 total current 1.00e-06 1.00e-06 -176 1 3.07e+00 3.09e+00 1 total current 2.00e-06 1.33e-06 -177 1 3.09e+00 3.11e+00 1 total current 0.00e+00 0.00e+00 -178 1 3.11e+00 3.12e+00 1 total current 1.00e-06 1.00e-06 -179 1 3.12e+00 3.14e+00 1 total current 0.00e+00 0.00e+00 \ No newline at end of file diff --git a/tests/regression_tests/ncrystal/test.py b/tests/regression_tests/ncrystal/test.py deleted file mode 100644 index 8da05e1cf..000000000 --- a/tests/regression_tests/ncrystal/test.py +++ /dev/null @@ -1,106 +0,0 @@ -from math import pi -import filecmp -from difflib import unified_diff - -import numpy as np -import openmc -import openmc.lib -import pytest -import shutil - -from tests.testing_harness import PyAPITestHarness - -pytestmark = pytest.mark.skipif( - not shutil.which('ncrystal-config'), - reason="NCrystal is not installed.") - - -def pencil_beam_model(cfg, E0, N): - """Return an openmc.Model() object for a monoenergetic pencil - beam hitting a 1 mm sphere filled with the material defined by - the cfg string, and compute the angular distribution""" - - # Material definition - - m1 = openmc.Material.from_ncrystal(cfg) - materials = openmc.Materials([m1]) - - # Geometry definition - - sample_sphere = openmc.Sphere(r=0.1) - outer_sphere = openmc.Sphere(r=100, boundary_type="vacuum") - cell1 = openmc.Cell(region=-sample_sphere, fill=m1) - cell2_region = +sample_sphere & -outer_sphere - cell2 = openmc.Cell(region=cell2_region, fill=None) - geometry = openmc.Geometry([cell1, cell2]) - - # Source definition - - source = openmc.IndependentSource() - source.space = openmc.stats.Point((0, 0, -20)) - source.angle = openmc.stats.Monodirectional(reference_uvw=(0, 0, 1)) - source.energy = openmc.stats.Discrete([E0], [1.0]) - - # Execution settings - - settings = openmc.Settings() - settings.source = source - settings.run_mode = "fixed source" - settings.batches = 10 - settings.particles = N - - # Tally definition - - tally1 = openmc.Tally(name="angular distribution") - tally1.scores = ["current"] - filter1 = openmc.SurfaceFilter(sample_sphere) - filter2 = openmc.PolarFilter(np.linspace(0, pi, 180+1)) - filter3 = openmc.CellFromFilter(cell1) - tally1.filters = [filter1, filter2, filter3] - tallies = openmc.Tallies([tally1]) - - return openmc.Model(geometry, materials, settings, tallies) - - -class NCrystalTest(PyAPITestHarness): - def _get_results(self): - """Digest info in the statepoint and return as a string.""" - - # Read the statepoint file. - with openmc.StatePoint(self._sp_name) as sp: - tal = sp.get_tally(name='angular distribution') - df = tal.get_pandas_dataframe() - return df.to_string() - - -def test_ncrystal(): - n_particles = 100000 - T = 293.6 # K - E0 = 0.012 # eV - cfg = 'Al_sg225.ncmat' - test = pencil_beam_model(cfg, E0, n_particles) - harness = NCrystalTest('statepoint.10.h5', model=test) - harness.main() - - -def test_cfg_from_xml(): - """Make sure the cfg string is read by from_xml method""" - n_particles = 100000 - E0 = 0.012 # eV - cfg = 'Al_sg225.ncmat' - model = pencil_beam_model(cfg, E0, n_particles) - #export the original material generated with cfg string - model.materials.export_to_xml('materials.xml.orig') - expected = open('materials.xml.orig', 'r').readlines() - #read back the original material - mats_from_xml = openmc.Materials.from_xml('materials.xml.orig') - #export again - mats_from_xml.export_to_xml('materials.xml.after') - actual = open('materials.xml.after', 'r').readlines() - compare = filecmp.cmp('materials.xml.orig','materials.xml.after') - if not compare: - diff = unified_diff(expected, actual, 'materials.xml.orig', - 'materials.xml.after') - print('Input differences:') - print(''.join(diff)) - assert compare, 'Materials not read correctly from XML' diff --git a/tests/regression_tests/output/results_true.dat b/tests/regression_tests/output/results_true.dat index 97b997ae6..fe46748c8 100644 --- a/tests/regression_tests/output/results_true.dat +++ b/tests/regression_tests/output/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 diff --git a/tests/regression_tests/particle_production_fission/__init__.py b/tests/regression_tests/particle_production_fission/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/particle_production_fission/local/inputs_true.dat b/tests/regression_tests/particle_production_fission/local/inputs_true.dat deleted file mode 100644 index e93dfc36e..000000000 --- a/tests/regression_tests/particle_production_fission/local/inputs_true.dat +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - fixed source - 100 - 2 - - - 1000000.0 1.0 - - - true - false - - - - neutron - - - neutron - - - 2 1 - events - analog - - - diff --git a/tests/regression_tests/particle_production_fission/local/results_true.dat b/tests/regression_tests/particle_production_fission/local/results_true.dat deleted file mode 100644 index 2f5288eba..000000000 --- a/tests/regression_tests/particle_production_fission/local/results_true.dat +++ /dev/null @@ -1,3 +0,0 @@ -tally 1: -4.570000E+00 -1.047890E+01 diff --git a/tests/regression_tests/particle_production_fission/shared/inputs_true.dat b/tests/regression_tests/particle_production_fission/shared/inputs_true.dat deleted file mode 100644 index b50a39cd0..000000000 --- a/tests/regression_tests/particle_production_fission/shared/inputs_true.dat +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - fixed source - 100 - 2 - - - 1000000.0 1.0 - - - true - true - - - - neutron - - - neutron - - - 2 1 - events - analog - - - diff --git a/tests/regression_tests/particle_production_fission/shared/results_true.dat b/tests/regression_tests/particle_production_fission/shared/results_true.dat deleted file mode 100644 index 5a4dfc516..000000000 --- a/tests/regression_tests/particle_production_fission/shared/results_true.dat +++ /dev/null @@ -1,3 +0,0 @@ -tally 1: -5.180000E+00 -1.355140E+01 diff --git a/tests/regression_tests/particle_production_fission/test.py b/tests/regression_tests/particle_production_fission/test.py deleted file mode 100644 index 2ad6ca515..000000000 --- a/tests/regression_tests/particle_production_fission/test.py +++ /dev/null @@ -1,49 +0,0 @@ -import openmc -import pytest -from openmc.utility_funcs import change_directory - -from tests.testing_harness import PyAPITestHarness - - -@pytest.mark.parametrize("shared_secondary,subdir", [ - (False, "local"), - (True, "shared"), -]) -def test_particle_production_fission(shared_secondary, subdir): - """Fixed-source model with fissionable material to test that - ParticleProductionFilter correctly counts fission-born neutrons, - with both local and shared secondary bank modes.""" - with change_directory(subdir): - openmc.reset_auto_ids() - model = openmc.Model() - - mat = openmc.Material() - mat.set_density('g/cm3', 18.0) - mat.add_nuclide('U235', 1.0) - model.materials.append(mat) - - sph = openmc.Sphere(r=5.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sph) - model.geometry = openmc.Geometry([cell]) - - source = openmc.IndependentSource() - source.energy = openmc.stats.delta_function(1.0e6) - - model.settings.particles = 100 - model.settings.run_mode = 'fixed source' - model.settings.batches = 2 - model.settings.source = source - model.settings.create_fission_neutrons = True - model.settings.shared_secondary_bank = shared_secondary - - # ParticleProductionFilter tracking fission neutron production - ppf = openmc.ParticleProductionFilter(['neutron']) - neutron_filter = openmc.ParticleFilter(['neutron']) - tally = openmc.Tally() - tally.filters = [neutron_filter, ppf] - tally.scores = ['events'] - tally.estimator = 'analog' - model.tallies = [tally] - - harness = PyAPITestHarness('statepoint.2.h5', model) - harness.main() diff --git a/tests/regression_tests/particle_restart_eigval/results_true.dat b/tests/regression_tests/particle_restart_eigval/results_true.dat index 3feeb5e74..64101d770 100644 --- a/tests/regression_tests/particle_restart_eigval/results_true.dat +++ b/tests/regression_tests/particle_restart_eigval/results_true.dat @@ -1,16 +1,16 @@ current batch: -8.000000E+00 +1.100000E+01 current generation: 1.000000E+00 particle id: -6.000000E+01 +9.020000E+02 run mode: eigenvalue particle weight: 1.000000E+00 particle energy: -2.028153E+06 +3.691964E+06 particle xyz: --3.678172E+01 -6.073321E+01 2.756488E+01 +-5.047439E+01 2.730535E+01 -2.619863E+01 particle uvw: --3.284774E-01 -8.920284E-01 3.104639E-01 +-6.278670E-01 1.419818E-01 -7.652609E-01 diff --git a/tests/regression_tests/particle_restart_eigval/settings.xml b/tests/regression_tests/particle_restart_eigval/settings.xml index de580e4c4..64b1a4dd4 100644 --- a/tests/regression_tests/particle_restart_eigval/settings.xml +++ b/tests/regression_tests/particle_restart_eigval/settings.xml @@ -6,7 +6,7 @@ 12 5 1200 - 1000000 + -10 -10 -5 10 10 5 diff --git a/tests/regression_tests/particle_restart_eigval/test.py b/tests/regression_tests/particle_restart_eigval/test.py index bad3f158c..e526e5003 100644 --- a/tests/regression_tests/particle_restart_eigval/test.py +++ b/tests/regression_tests/particle_restart_eigval/test.py @@ -2,5 +2,5 @@ from tests.testing_harness import ParticleRestartTestHarness def test_particle_restart_eigval(): - harness = ParticleRestartTestHarness('particle_8_60.h5') + harness = ParticleRestartTestHarness('particle_11_902.h5') harness.main() diff --git a/tests/regression_tests/particle_restart_fixed_shared_secondary/__init__.py b/tests/regression_tests/particle_restart_fixed_shared_secondary/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/particle_restart_fixed_shared_secondary/geometry.xml b/tests/regression_tests/particle_restart_fixed_shared_secondary/geometry.xml deleted file mode 100644 index c86e016c6..000000000 --- a/tests/regression_tests/particle_restart_fixed_shared_secondary/geometry.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/tests/regression_tests/particle_restart_fixed_shared_secondary/materials.xml b/tests/regression_tests/particle_restart_fixed_shared_secondary/materials.xml deleted file mode 100644 index f3851d7ef..000000000 --- a/tests/regression_tests/particle_restart_fixed_shared_secondary/materials.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/tests/regression_tests/particle_restart_fixed_shared_secondary/results_true.dat b/tests/regression_tests/particle_restart_fixed_shared_secondary/results_true.dat deleted file mode 100644 index 0c84541f9..000000000 --- a/tests/regression_tests/particle_restart_fixed_shared_secondary/results_true.dat +++ /dev/null @@ -1,16 +0,0 @@ -current batch: -4.000000E+00 -current generation: -1.000000E+00 -particle id: -3.241000E+03 -run mode: -fixed source -particle weight: -1.000000E+00 -particle energy: -3.896365E+06 -particle xyz: -8.710681E-01 3.698823E+00 -2.286229E+00 -particle uvw: --5.882735E-01 4.665422E-01 -6.605093E-01 diff --git a/tests/regression_tests/particle_restart_fixed_shared_secondary/settings.xml b/tests/regression_tests/particle_restart_fixed_shared_secondary/settings.xml deleted file mode 100644 index 3a80fb17b..000000000 --- a/tests/regression_tests/particle_restart_fixed_shared_secondary/settings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - fixed source - 12 - 1000 - true - - - - -10 -10 -5 10 10 5 - - - - diff --git a/tests/regression_tests/particle_restart_fixed_shared_secondary/test.py b/tests/regression_tests/particle_restart_fixed_shared_secondary/test.py deleted file mode 100644 index 770010900..000000000 --- a/tests/regression_tests/particle_restart_fixed_shared_secondary/test.py +++ /dev/null @@ -1,6 +0,0 @@ -from tests.testing_harness import ParticleRestartTestHarness - - -def test_particle_restart_fixed_shared_secondary(): - harness = ParticleRestartTestHarness('particle_4_3241.h5') - harness.main() diff --git a/tests/regression_tests/periodic/inputs_true.dat b/tests/regression_tests/periodic/inputs_true.dat index 9183db3c4..c1f6d1563 100644 --- a/tests/regression_tests/periodic/inputs_true.dat +++ b/tests/regression_tests/periodic/inputs_true.dat @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 4 + 0 + + + 0 0 0 5 5 0 + + + diff --git a/tests/regression_tests/periodic/results_true.dat b/tests/regression_tests/periodic/results_true.dat index 626004b16..6d58baccb 100644 --- a/tests/regression_tests/periodic/results_true.dat +++ b/tests/regression_tests/periodic/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.624889E+00 1.108153E-02 +1.654583E+00 1.501286E-02 diff --git a/tests/regression_tests/periodic/test.py b/tests/regression_tests/periodic/test.py index 73fe8a83e..51a70a6aa 100644 --- a/tests/regression_tests/periodic/test.py +++ b/tests/regression_tests/periodic/test.py @@ -42,7 +42,7 @@ def box_model(): model.settings.particles = 1000 model.settings.batches = 4 model.settings.inactive = 0 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + model.settings.source = openmc.Source(space=openmc.stats.Box( (0, 0, 0), (5, 5, 0)) ) return model diff --git a/tests/regression_tests/periodic_6fold/False-False/inputs_true.dat b/tests/regression_tests/periodic_6fold/False-False/inputs_true.dat deleted file mode 100644 index 075cffc12..000000000 --- a/tests/regression_tests/periodic_6fold/False-False/inputs_true.dat +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - - diff --git a/tests/regression_tests/periodic_6fold/False-False/results_true.dat b/tests/regression_tests/periodic_6fold/False-False/results_true.dat deleted file mode 100644 index 04aa30878..000000000 --- a/tests/regression_tests/periodic_6fold/False-False/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.848492E+00 2.933785E-03 diff --git a/tests/regression_tests/periodic_6fold/False-True/inputs_true.dat b/tests/regression_tests/periodic_6fold/False-True/inputs_true.dat deleted file mode 100644 index cbc1e9100..000000000 --- a/tests/regression_tests/periodic_6fold/False-True/inputs_true.dat +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - - diff --git a/tests/regression_tests/periodic_6fold/False-True/results_true.dat b/tests/regression_tests/periodic_6fold/False-True/results_true.dat deleted file mode 100644 index 04aa30878..000000000 --- a/tests/regression_tests/periodic_6fold/False-True/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.848492E+00 2.933785E-03 diff --git a/tests/regression_tests/periodic_6fold/True-False/inputs_true.dat b/tests/regression_tests/periodic_6fold/True-False/inputs_true.dat deleted file mode 100644 index 675a8b300..000000000 --- a/tests/regression_tests/periodic_6fold/True-False/inputs_true.dat +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - - diff --git a/tests/regression_tests/periodic_6fold/True-False/results_true.dat b/tests/regression_tests/periodic_6fold/True-False/results_true.dat deleted file mode 100644 index 04aa30878..000000000 --- a/tests/regression_tests/periodic_6fold/True-False/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.848492E+00 2.933785E-03 diff --git a/tests/regression_tests/periodic_6fold/True-True/inputs_true.dat b/tests/regression_tests/periodic_6fold/True-True/inputs_true.dat deleted file mode 100644 index e5ac03b48..000000000 --- a/tests/regression_tests/periodic_6fold/True-True/inputs_true.dat +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - - diff --git a/tests/regression_tests/periodic_6fold/True-True/results_true.dat b/tests/regression_tests/periodic_6fold/True-True/results_true.dat deleted file mode 100644 index 04aa30878..000000000 --- a/tests/regression_tests/periodic_6fold/True-True/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.848492E+00 2.933785E-03 diff --git a/tests/regression_tests/periodic_6fold/inputs_true.dat b/tests/regression_tests/periodic_6fold/inputs_true.dat new file mode 100644 index 000000000..35bbcc047 --- /dev/null +++ b/tests/regression_tests/periodic_6fold/inputs_true.dat @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 4 + 0 + + + 0 0 0 5 5 0 + + + diff --git a/tests/regression_tests/periodic_6fold/results_true.dat b/tests/regression_tests/periodic_6fold/results_true.dat new file mode 100644 index 000000000..def4d0c7a --- /dev/null +++ b/tests/regression_tests/periodic_6fold/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +1.845885E+00 1.472487E-02 diff --git a/tests/regression_tests/periodic_6fold/test.py b/tests/regression_tests/periodic_6fold/test.py index bded1c465..555ab24f9 100644 --- a/tests/regression_tests/periodic_6fold/test.py +++ b/tests/regression_tests/periodic_6fold/test.py @@ -1,16 +1,13 @@ -from math import sin, cos, pi - import openmc -from openmc.utility_funcs import change_directory +import numpy as np import pytest from tests.testing_harness import PyAPITestHarness -@pytest.mark.parametrize("flip1", [False, True]) -@pytest.mark.parametrize("flip2", [False, True]) -def test_periodic(flip1, flip2): - model = openmc.Model() +@pytest.fixture +def model(): + model = openmc.model.Model() # Define materials water = openmc.Material() @@ -27,54 +24,36 @@ def test_periodic(flip1, flip2): # (it essentially defines a circle of half-cylinders), but it is # designed so that periodic and reflective BCs will give different # answers. - theta1 = (-1/6 + 1/2) * pi - theta2 = (1/6 - 1/2) * pi - if flip1: - plane1 = openmc.Plane(a=-cos(theta1), b=-sin(theta1), boundary_type='periodic') - else: - plane1 = openmc.Plane(a=cos(theta1), b=sin(theta1), boundary_type='periodic') - if flip2: - plane2 = openmc.Plane(a=-cos(theta2), b=-sin(theta2), boundary_type='periodic') - else: - plane2 = openmc.Plane(a=cos(theta2), b=sin(theta2), boundary_type='periodic') + theta1 = (-1/6 + 1/2) * np.pi + theta2 = (1/6 - 1/2) * np.pi + plane1 = openmc.Plane(a=np.cos(theta1), b=np.sin(theta1), + boundary_type='periodic') + plane2 = openmc.Plane(a=np.cos(theta2), b=np.sin(theta2), + boundary_type='periodic') - x_max = openmc.XPlane(5., boundary_type='reflective') + x_max = openmc.XPlane(x0=5., boundary_type='reflective') - z_cyl = openmc.ZCylinder(x0=3*cos(pi/6), y0=3*sin(pi/6), r=2.0) + z_cyl = openmc.ZCylinder(x0=3*np.cos(np.pi/6), y0=3*np.sin(np.pi/6), + r=2.0) - match (flip1, flip2): - case (False, False): - outside_cyl = openmc.Cell(1, fill=water, region=( - +plane1 & +plane2 & -x_max & +z_cyl)) - inside_cyl = openmc.Cell(2, fill=fuel, region=( - +plane1 & +plane2 & -z_cyl)) - case (False, True): - outside_cyl = openmc.Cell(1, fill=water, region=( - +plane1 & -plane2 & -x_max & +z_cyl)) - inside_cyl = openmc.Cell(2, fill=fuel, region=( - +plane1 & -plane2 & -z_cyl)) - case (True, False): - outside_cyl = openmc.Cell(1, fill=water, region=( - -plane1 & +plane2 & -x_max & +z_cyl)) - inside_cyl = openmc.Cell(2, fill=fuel, region=( - -plane1 & +plane2 & -z_cyl)) - case (True, True): - outside_cyl = openmc.Cell(1, fill=water, region=( - -plane1 & -plane2 & -x_max & +z_cyl)) - inside_cyl = openmc.Cell(2, fill=fuel, region=( - -plane1 & -plane2 & -z_cyl)) + outside_cyl = openmc.Cell(1, fill=water, region=( + +plane1 & +plane2 & -x_max & +z_cyl)) + inside_cyl = openmc.Cell(2, fill=fuel, region=( + +plane1 & +plane2 & -z_cyl)) root_universe = openmc.Universe(0, cells=(outside_cyl, inside_cyl)) model.geometry = openmc.Geometry(root_universe) # Define settings + model.settings = openmc.Settings() model.settings.particles = 1000 model.settings.batches = 4 model.settings.inactive = 0 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box((0, 0, 0), (5, 5, 0)) + model.settings.source = openmc.Source(space=openmc.stats.Box( + (0, 0, 0), (5, 5, 0)) ) + return model - with change_directory(f'{flip1}-{flip2}'): - harness = PyAPITestHarness('statepoint.4.h5', model) - harness.main() +def test_periodic(model): + harness = PyAPITestHarness('statepoint.4.h5', model) + harness.main() diff --git a/tests/regression_tests/periodic_cyls/__init__.py b/tests/regression_tests/periodic_cyls/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/periodic_cyls/test.py b/tests/regression_tests/periodic_cyls/test.py deleted file mode 100644 index a341e3799..000000000 --- a/tests/regression_tests/periodic_cyls/test.py +++ /dev/null @@ -1,91 +0,0 @@ -import openmc -import numpy as np -import pytest -from openmc.utility_funcs import change_directory -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def xcyl_model(): - model = openmc.Model() - # Define materials - fuel = openmc.Material() - fuel.add_nuclide('U235', 0.2) - fuel.add_nuclide('U238', 0.8) - fuel.set_density('g/cc', 19.1) - model.materials = openmc.Materials([fuel]) - - # Define geometry - # finite cylinder - x_min = openmc.XPlane(x0=0.0, boundary_type='reflective') - x_max = openmc.XPlane(x0=20.0, boundary_type='reflective') - x_cyl = openmc.XCylinder(r=20.0,boundary_type='vacuum') - # slice cylinder for periodic BC - periodic_bounding_yplane = openmc.YPlane(y0=0, boundary_type='periodic') - periodic_bounding_plane = openmc.Plane( - a=0.0, b=-np.sqrt(3) / 3, c=1, boundary_type='periodic', - ) - sixth_cyl_cell = openmc.Cell(1, fill=fuel, region = - +x_min &- x_max & -x_cyl & +periodic_bounding_yplane & +periodic_bounding_plane) - periodic_bounding_yplane.periodic_surface = periodic_bounding_plane - periodic_bounding_plane.periodic_surface = periodic_bounding_yplane - - model.geometry = openmc.Geometry([sixth_cyl_cell]) - - - # Define settings - model.settings.particles = 1000 - model.settings.batches = 4 - model.settings.inactive = 0 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( - (0, 0, 0), (20, 20, 20)) - ) - return model - -@pytest.fixture -def ycyl_model(): - model = openmc.Model() - # Define materials - fuel = openmc.Material() - fuel.add_nuclide('U235', 0.2) - fuel.add_nuclide('U238', 0.8) - fuel.set_density('g/cc', 19.1) - model.materials = openmc.Materials([fuel]) - - # Define geometry - # finite cylinder - y_min = openmc.YPlane(y0=0.0, boundary_type='reflective') - y_max = openmc.YPlane(y0=20.0, boundary_type='reflective') - y_cyl = openmc.YCylinder(r=20.0,boundary_type='vacuum') - # slice cylinder for periodic BC - periodic_bounding_xplane = openmc.XPlane(x0=0, boundary_type='periodic') - periodic_bounding_plane = openmc.Plane( - a=-np.sqrt(3) / 3, b=0.0, c=1, boundary_type='periodic', - ) - sixth_cyl_cell = openmc.Cell(1, fill=fuel, region = - +y_min &- y_max & -y_cyl & +periodic_bounding_xplane & +periodic_bounding_plane) - periodic_bounding_xplane.periodic_surface = periodic_bounding_plane - periodic_bounding_plane.periodic_surface = periodic_bounding_xplane - model.geometry = openmc.Geometry([sixth_cyl_cell]) - - - # Define settings - model.settings.particles = 1000 - model.settings.batches = 4 - model.settings.inactive = 0 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( - (0, 0, 0), (20, 20, 20)) - ) - return model - -def test_xcyl(xcyl_model): - with change_directory("xcyl_model"): - openmc.reset_auto_ids() - harness = PyAPITestHarness('statepoint.4.h5', xcyl_model) - harness.main() - -def test_ycyl(ycyl_model): - with change_directory("ycyl_model"): - openmc.reset_auto_ids() - harness = PyAPITestHarness('statepoint.4.h5', ycyl_model) - harness.main() \ No newline at end of file diff --git a/tests/regression_tests/periodic_cyls/xcyl_model/inputs_true.dat b/tests/regression_tests/periodic_cyls/xcyl_model/inputs_true.dat deleted file mode 100644 index 7d1ecf426..000000000 --- a/tests/regression_tests/periodic_cyls/xcyl_model/inputs_true.dat +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 20 20 20 - - - - diff --git a/tests/regression_tests/periodic_cyls/xcyl_model/results_true.dat b/tests/regression_tests/periodic_cyls/xcyl_model/results_true.dat deleted file mode 100644 index c7e3eb670..000000000 --- a/tests/regression_tests/periodic_cyls/xcyl_model/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.082283E+00 6.676373E-02 diff --git a/tests/regression_tests/periodic_cyls/ycyl_model/inputs_true.dat b/tests/regression_tests/periodic_cyls/ycyl_model/inputs_true.dat deleted file mode 100644 index f3ca7e0f4..000000000 --- a/tests/regression_tests/periodic_cyls/ycyl_model/inputs_true.dat +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 20 20 20 - - - - diff --git a/tests/regression_tests/periodic_cyls/ycyl_model/results_true.dat b/tests/regression_tests/periodic_cyls/ycyl_model/results_true.dat deleted file mode 100644 index 562467f2c..000000000 --- a/tests/regression_tests/periodic_cyls/ycyl_model/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.082652E+00 3.316031E-02 diff --git a/tests/regression_tests/periodic_hex/inputs_true.dat b/tests/regression_tests/periodic_hex/inputs_true.dat index e65af3d94..00e539d4b 100644 --- a/tests/regression_tests/periodic_hex/inputs_true.dat +++ b/tests/regression_tests/periodic_hex/inputs_true.dat @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + diff --git a/tests/regression_tests/periodic_hex/results_true.dat b/tests/regression_tests/periodic_hex/results_true.dat index eff00b6e1..16512ec23 100644 --- a/tests/regression_tests/periodic_hex/results_true.dat +++ b/tests/regression_tests/periodic_hex/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.285622E+00 2.576768E-03 +2.271604E+00 1.159996E-02 diff --git a/tests/regression_tests/periodic_hex/test.py b/tests/regression_tests/periodic_hex/test.py index db9f6cfd5..a21819b1a 100644 --- a/tests/regression_tests/periodic_hex/test.py +++ b/tests/regression_tests/periodic_hex/test.py @@ -12,8 +12,8 @@ def hex_model(): fuel.add_nuclide('U235', 1.0) fuel.set_density('g/cc', 4.5) - hex_prism = openmc.model.HexagonalPrism(10.0, boundary_type='periodic') - cell = openmc.Cell(fill=fuel, region=-hex_prism) + hex_region = openmc.model.hexagonal_prism(10.0, boundary_type='periodic') + cell = openmc.Cell(fill=fuel, region=hex_region) model.geometry = openmc.Geometry([cell]) # Define settings diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index 0ae0079f4..09f1fd290 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -1,82 +1,68 @@ - - - - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 0 0 0 - - - - 14000000.0 1.0 - - - ttb - true - - 1000.0 - - - - - 1 - - - neutron photon electron positron - - - neutron - - - 0.0 20000000.0 - - - neutron photon - 0.0 100000.0 300000.0 500000.0 2000000.0 20000000.0 - - - 1 2 - current - - - 2 - Al27 total - total (n,gamma) - tracklength - - - 2 - Al27 total - total heating (n,gamma) - collision - - - 2 - Al27 total - total heating (n,gamma) - analog - - - 5 3 4 - events - analog - - - + + + + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 14000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + + 1 + + + neutron photon electron positron + + + 1 2 + current + + + 2 + Al27 total + total (n,gamma) + tracklength + + + 2 + Al27 total + total heating (n,gamma) + collision + + + 2 + Al27 total + total heating (n,gamma) + analog + + diff --git a/tests/regression_tests/photon_production/results_true.dat b/tests/regression_tests/photon_production/results_true.dat index c4f5fafa2..398deeed8 100644 --- a/tests/regression_tests/photon_production/results_true.dat +++ b/tests/regression_tests/photon_production/results_true.dat @@ -1,8 +1,8 @@ tally 1: 8.610000E-01 7.413210E-01 -9.491000E-01 -9.007908E-01 +9.493000E-01 +9.011705E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -16,12 +16,12 @@ tally 2: 1.573004E+00 4.296434E-04 1.845934E-07 -2.350047E-01 -5.522722E-02 +2.337049E-01 +5.461796E-02 0.000000E+00 0.000000E+00 -2.350047E-01 -5.522722E-02 +2.337049E-01 +5.461796E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -53,40 +53,40 @@ tally 3: 4.104374E+12 4.296582E-04 1.846062E-07 -2.297000E-01 -5.276209E-02 -4.196651E+00 -1.761188E+01 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 -2.297000E-01 -5.276209E-02 -4.196651E+00 -1.761188E+01 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.774484E+05 -3.148794E+10 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.774484E+05 -3.148794E+10 +0.000000E+00 +0.000000E+00 +1.764573E+05 +3.113718E+10 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.474427E+04 -2.173936E+08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.474427E+04 -2.173936E+08 +0.000000E+00 +0.000000E+00 +7.691658E+03 +5.916160E+07 0.000000E+00 0.000000E+00 tally 4: @@ -102,16 +102,16 @@ tally 4: 4.104374E+12 0.000000E+00 0.000000E+00 -2.297000E-01 -5.276209E-02 -4.196651E+00 -1.761188E+01 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 -2.297000E-01 -5.276209E-02 -4.196651E+00 -1.761188E+01 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -122,8 +122,8 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.774484E+05 -3.148794E+10 +1.764573E+05 +3.113718E+10 0.000000E+00 0.000000E+00 0.000000E+00 @@ -134,28 +134,7 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.474427E+04 -2.173936E+08 +7.691658E+03 +5.916160E+07 0.000000E+00 0.000000E+00 -tally 5: -5.000000E-04 -2.500000E-07 -1.300000E-03 -1.690000E-06 -8.000000E-04 -6.400000E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -4.000000E-04 -8.200000E-03 -6.724000E-05 -5.280000E-02 -2.787840E-03 -3.546000E-01 -1.257412E-01 -5.063000E-01 -2.563397E-01 diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 5ed5c5ecf..107b53bbb 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -25,10 +25,9 @@ def model(): inner_cyl_right.region = -cyl & +x_plane_center & -x_plane_right outer_cyl.region = ~(-cyl & +x_plane_left & -x_plane_right) inner_cyl_right.fill = mat - model.geometry = openmc.Geometry( - [inner_cyl_left, inner_cyl_right, outer_cyl]) + model.geometry = openmc.Geometry([inner_cyl_left, inner_cyl_right, outer_cyl]) - source = openmc.IndependentSource() + source = openmc.Source() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Monodirectional() source.energy = openmc.stats.Discrete([14.0e6], [1.0]) @@ -39,19 +38,17 @@ def model(): model.settings.batches = 1 model.settings.photon_transport = True model.settings.electron_treatment = 'ttb' - model.settings.cutoff = {'energy_photon': 1000.0} + model.settings.cutoff = {'energy_photon' : 1000.0} model.settings.source = source surface_filter = openmc.SurfaceFilter(cyl) - particle_filter = openmc.ParticleFilter( - ['neutron', 'photon', 'electron', 'positron']) + particle_filter = openmc.ParticleFilter(['neutron', 'photon', 'electron', 'positron']) current_tally = openmc.Tally() current_tally.filters = [surface_filter, particle_filter] current_tally.scores = ['current'] tally_tracklength = openmc.Tally() tally_tracklength.filters = [particle_filter] - # heating doesn't work with tracklength - tally_tracklength.scores = ['total', '(n,gamma)'] + tally_tracklength.scores = ['total', '(n,gamma)'] # heating doesn't work with tracklength tally_tracklength.nuclides = ['Al27', 'total'] tally_tracklength.estimator = 'tracklength' tally_collision = openmc.Tally() @@ -64,25 +61,8 @@ def model(): tally_analog.scores = ['total', 'heating', '(n,gamma)'] tally_analog.nuclides = ['Al27', 'total'] tally_analog.estimator = 'analog' - - # This is an analog tally tracking the energy distribution of photons - # generated by neutrons. The sum of the tally should give the total - # number of photons generated per source neutron. - ene_filter = openmc.EnergyFilter([0.0, 20e6]) # incident neutron energy - - # Track source energies of secondary gammas - ene2_filter = openmc.ParticleProductionFilter( - ['neutron', 'photon'], [0.0, 100e3, 300e3, 500e3, 2e6, 20e6]) - - neutron_only = openmc.ParticleFilter(['neutron']) - tally_gam_ene = openmc.Tally() - tally_gam_ene.filters = [neutron_only, ene_filter, ene2_filter] - tally_gam_ene.scores = ['events'] - tally_gam_ene.estimator = 'analog' - model.tallies.extend([current_tally, tally_tracklength, - tally_collision, tally_analog, - tally_gam_ene]) + tally_collision, tally_analog]) return model diff --git a/tests/regression_tests/photon_production_fission/inputs_true.dat b/tests/regression_tests/photon_production_fission/inputs_true.dat index 11a194e3c..c317f6273 100644 --- a/tests/regression_tests/photon_production_fission/inputs_true.dat +++ b/tests/regression_tests/photon_production_fission/inputs_true.dat @@ -1,48 +1,49 @@ - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 2 - - - 0 0 0 - - - true - - - - neutron photon - - - 1 - U235 total - fission heating-local - tracklength - - - 1 - U235 total - fission heating heating-local - collision - - - 1 - U235 total - fission heating heating-local - analog - - - + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 2 + + + 0 0 0 + + + true + + + + + neutron photon + + + 1 + U235 total + fission heating-local + tracklength + + + 1 + U235 total + fission heating heating-local + collision + + + 1 + U235 total + fission heating heating-local + analog + + diff --git a/tests/regression_tests/photon_production_fission/results_true.dat b/tests/regression_tests/photon_production_fission/results_true.dat index af325d4b0..ac91b63a1 100644 --- a/tests/regression_tests/photon_production_fission/results_true.dat +++ b/tests/regression_tests/photon_production_fission/results_true.dat @@ -1,12 +1,12 @@ k-combined: -2.297165E+00 1.955494E-02 +2.294874E+00 2.454640E-02 tally 1: -2.696393E+00 -2.423937E+00 +2.691351E+00 +2.415076E+00 0.000000E+00 0.000000E+00 -2.696393E+00 -2.423937E+00 +2.691351E+00 +2.415076E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -18,52 +18,52 @@ tally 1: 0.000000E+00 0.000000E+00 tally 2: -2.672029E+00 -2.380251E+00 -4.288244E+08 -6.130569E+16 +2.654218E+00 +2.348806E+00 +4.260252E+08 +6.051306E+16 0.000000E+00 0.000000E+00 -2.672029E+00 -2.380251E+00 -4.288244E+08 -6.130569E+16 +2.654218E+00 +2.348806E+00 +4.260252E+08 +6.051306E+16 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.711908E+05 -9.769096E+09 +2.507232E+06 +2.096890E+12 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.711908E+05 -9.769096E+09 +2.507232E+06 +2.096890E+12 0.000000E+00 0.000000E+00 tally 3: -2.649127E+00 -2.339294E+00 -4.288244E+08 -6.130569E+16 +2.656221E+00 +2.351840E+00 +4.260252E+08 +6.051306E+16 0.000000E+00 0.000000E+00 -2.649127E+00 -2.339294E+00 -4.288244E+08 -6.130569E+16 +2.656221E+00 +2.351840E+00 +4.260252E+08 +6.051306E+16 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.711908E+05 -9.769096E+09 +2.507232E+06 +2.096890E+12 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.711908E+05 -9.769096E+09 +2.507232E+06 +2.096890E+12 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/photon_production_fission/test.py b/tests/regression_tests/photon_production_fission/test.py index 96665b308..595d3c2d6 100644 --- a/tests/regression_tests/photon_production_fission/test.py +++ b/tests/regression_tests/photon_production_fission/test.py @@ -20,7 +20,7 @@ def model(): model.settings.batches = 5 model.settings.inactive = 2 model.settings.photon_transport = True - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point((0, 0, 0))) + model.settings.source = openmc.Source(space=openmc.stats.Point((0, 0, 0))) particle_filter = openmc.ParticleFilter(['neutron', 'photon']) tally_tracklength = openmc.Tally() diff --git a/tests/regression_tests/photon_source/inputs_true.dat b/tests/regression_tests/photon_source/inputs_true.dat index adaa5fb42..f7c9c24b4 100644 --- a/tests/regression_tests/photon_source/inputs_true.dat +++ b/tests/regression_tests/photon_source/inputs_true.dat @@ -1,44 +1,45 @@ - - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 0 0 0 - - - - 10000000.0 1.0 - - - ttb - true - - 1000.0 - - - - - photon - - - 1 - flux (n,gamma) - - - + + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 10000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + + photon + + + 1 + flux (n,gamma) + + diff --git a/tests/regression_tests/photon_source/results_true.dat b/tests/regression_tests/photon_source/results_true.dat index 8d934afc6..fcc75cbca 100644 --- a/tests/regression_tests/photon_source/results_true.dat +++ b/tests/regression_tests/photon_source/results_true.dat @@ -1,5 +1,5 @@ tally 1: -2.263761E+02 -5.124615E+04 +2.263938E+02 +5.125417E+04 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/photon_source/test.py b/tests/regression_tests/photon_source/test.py index c2eb1476d..a2bfb9038 100644 --- a/tests/regression_tests/photon_source/test.py +++ b/tests/regression_tests/photon_source/test.py @@ -7,21 +7,22 @@ from tests.testing_harness import PyAPITestHarness class SourceTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): mat = openmc.Material() mat.set_density('g/cm3', 0.998207) mat.add_element('H', 0.111894) mat.add_element('O', 0.888106) - self._model.materials = openmc.Materials([mat]) + materials = openmc.Materials([mat]) + materials.export_to_xml() sphere = openmc.Sphere(r=1.0e9, boundary_type='reflective') inside_sphere = openmc.Cell() inside_sphere.region = -sphere inside_sphere.fill = mat - self._model.geometry = openmc.Geometry([inside_sphere]) + geometry = openmc.Geometry([inside_sphere]) + geometry.export_to_xml() - source = openmc.IndependentSource() + source = openmc.Source() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([10.0e6], [1.0]) @@ -35,16 +36,16 @@ class SourceTestHarness(PyAPITestHarness): settings.cutoff = {'energy_photon' : 1000.0} settings.run_mode = 'fixed source' settings.source = source - self._model.settings = settings + settings.export_to_xml() particle_filter = openmc.ParticleFilter('photon') tally = openmc.Tally() tally.filters = [particle_filter] tally.scores = ['flux', '(n,gamma)'] tallies = openmc.Tallies([tally]) - self._model.tallies = tallies + tallies.export_to_xml() def test_photon_source(): - harness = SourceTestHarness('statepoint.1.h5', model=openmc.Model()) + harness = SourceTestHarness('statepoint.1.h5') harness.main() diff --git a/tests/regression_tests/plot/geometry.xml b/tests/regression_tests/plot/geometry.xml new file mode 100644 index 000000000..83619d9f7 --- /dev/null +++ b/tests/regression_tests/plot/geometry.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/regression_tests/plot_projections/materials.xml b/tests/regression_tests/plot/materials.xml similarity index 80% rename from tests/regression_tests/plot_projections/materials.xml rename to tests/regression_tests/plot/materials.xml index 35f0de312..90b354267 100644 --- a/tests/regression_tests/plot_projections/materials.xml +++ b/tests/regression_tests/plot/materials.xml @@ -8,12 +8,12 @@ - + - + diff --git a/tests/regression_tests/plot/model.xml b/tests/regression_tests/plot/model.xml deleted file mode 100644 index a63ff95da..000000000 --- a/tests/regression_tests/plot/model.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - plot - 1 - - 5 4 3 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - - - -10.0 10.0 - -10.0 10.0 - -10.0 0.0 5.0 7.5 8.75 10.0 - - - 2 - - - 1 - total - - - - - 0.0 0.0 0.0 - 25.0 25.0 - 200 200 - - - - - 0.0 0.0 0.0 - 25.0 25.0 - 200 200 - - - - - 0.0 0.0 0.0 - 25.0 25.0 - 200 200 - 0 0 0 - - - 0.0 0.0 0.0 - 20.0 20.0 10.0 - 100 100 10 - - - diff --git a/tests/regression_tests/plot/plots.xml b/tests/regression_tests/plot/plots.xml new file mode 100644 index 000000000..ce63da144 --- /dev/null +++ b/tests/regression_tests/plot/plots.xml @@ -0,0 +1,33 @@ + + + + + 0. 0. 0. + 25 25 + 200 200 + + + + + + 0. 0. 0. + 25 25 + 200 200 + + + + + + 0. 0. 0. + 25 25 + 200 200 + 0 0 0 + + + + 100 100 10 + 0. 0. 0. + 20 20 10 + + + diff --git a/tests/regression_tests/plot/results_true.dat b/tests/regression_tests/plot/results_true.dat index 1be60ad4f..9174202fb 100644 --- a/tests/regression_tests/plot/results_true.dat +++ b/tests/regression_tests/plot/results_true.dat @@ -1 +1 @@ -6385d2969ed54d47a09f75112595fc034a16f551346c92d87ed9e7841881baaee8e56190c347e97c3f919ef677bb5b858960d60fe985a00e2848a3bfbef7a12b \ No newline at end of file +f85c20735a0c08525fe48b19a8e075c074539ee6c8860268fa0cb515d842496b7086e5b94305ef78dcf2106bb193abdf438259ac8ff1d0245a2782eb6f5af873 \ No newline at end of file diff --git a/tests/regression_tests/plot_projections/settings.xml b/tests/regression_tests/plot/settings.xml similarity index 100% rename from tests/regression_tests/plot_projections/settings.xml rename to tests/regression_tests/plot/settings.xml diff --git a/tests/regression_tests/plot_projections/tallies.xml b/tests/regression_tests/plot/tallies.xml similarity index 100% rename from tests/regression_tests/plot_projections/tallies.xml rename to tests/regression_tests/plot/tallies.xml diff --git a/tests/regression_tests/plot/test.py b/tests/regression_tests/plot/test.py index 30d9ab0d0..2fd6a5b79 100644 --- a/tests/regression_tests/plot/test.py +++ b/tests/regression_tests/plot/test.py @@ -1,7 +1,60 @@ -from tests.testing_harness import PlotTestHarness +import glob +import hashlib +import os + +import h5py +import openmc + +from tests.testing_harness import TestHarness from tests.regression_tests import config +class PlotTestHarness(TestHarness): + """Specialized TestHarness for running OpenMC plotting tests.""" + def __init__(self, plot_names): + super().__init__(None) + self._plot_names = plot_names + + def _run_openmc(self): + openmc.plot_geometry(openmc_exec=config['exe']) + + def _test_output_created(self): + """Make sure *.png has been created.""" + for fname in self._plot_names: + assert os.path.exists(fname), 'Plot output file does not exist.' + + def _cleanup(self): + super()._cleanup() + for fname in self._plot_names: + if os.path.exists(fname): + os.remove(fname) + + def _get_results(self): + """Return a string hash of the plot files.""" + outstr = bytes() + + for fname in self._plot_names: + if fname.endswith('.png'): + # Add PNG output to results + with open(fname, 'rb') as fh: + outstr += fh.read() + elif fname.endswith('.h5'): + # Add voxel data to results + with h5py.File(fname, 'r') as fh: + outstr += fh.attrs['filetype'] + outstr += fh.attrs['num_voxels'].tobytes() + outstr += fh.attrs['lower_left'].tobytes() + outstr += fh.attrs['voxel_width'].tobytes() + outstr += fh['data'][()].tobytes() + + # Hash the information and return. + sha512 = hashlib.sha512() + sha512.update(outstr) + outstr = sha512.hexdigest() + + return outstr + + def test_plot(): harness = PlotTestHarness(('plot_1.png', 'plot_2.png', 'plot_3.png', 'plot_4.h5')) diff --git a/tests/regression_tests/plot_overlaps/geometry.xml b/tests/regression_tests/plot_overlaps/geometry.xml new file mode 100644 index 000000000..7a9f1fb41 --- /dev/null +++ b/tests/regression_tests/plot_overlaps/geometry.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/tests/regression_tests/plot_overlaps/materials.xml b/tests/regression_tests/plot_overlaps/materials.xml new file mode 100644 index 000000000..90b354267 --- /dev/null +++ b/tests/regression_tests/plot_overlaps/materials.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/plot_overlaps/model.xml b/tests/regression_tests/plot_overlaps/model.xml deleted file mode 100644 index e3b65d45d..000000000 --- a/tests/regression_tests/plot_overlaps/model.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - plot - 1 - - 5 4 3 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - - - 0.0 0.0 0.0 - 25.0 25.0 - 200 200 - - true - - - - 0.0 0.0 0.0 - 25.0 25.0 - 200 200 - - true - 255 211 0 - - - 0.0 0.0 0.0 - 25.0 25.0 - 200 200 - 0 0 0 - - - 0.0 0.0 0.0 - 20.0 20.0 10.0 - 100 100 10 - - - diff --git a/tests/regression_tests/plot_overlaps/plots.xml b/tests/regression_tests/plot_overlaps/plots.xml new file mode 100644 index 000000000..28064f58f --- /dev/null +++ b/tests/regression_tests/plot_overlaps/plots.xml @@ -0,0 +1,35 @@ + + + + + 0. 0. 0. + 25 25 + 200 200 + + + true + + + + 0. 0. 0. + 25 25 + 200 200 + + true + 255 211 0 + + + + 0. 0. 0. + 25 25 + 200 200 + 0 0 0 + + + + 100 100 10 + 0. 0. 0. + 20 20 10 + + + diff --git a/tests/regression_tests/plot_overlaps/results_true.dat b/tests/regression_tests/plot_overlaps/results_true.dat index 93ee6769f..cb04daaa4 100644 --- a/tests/regression_tests/plot_overlaps/results_true.dat +++ b/tests/regression_tests/plot_overlaps/results_true.dat @@ -1 +1 @@ -125ce40fbff3e02e7f5f36a92a2e37abce9407154c825b6617242a4685dfc33c63041145b1f3114334338fbb86188331195ddc319ffce58fab2943d8e60f6da3 \ No newline at end of file +926065ceb2a9b8292fe6270317c38c4373473cfea19d2a8392a32e5ece8e314c04b9f032921d987bd195ae4b6f674d359b0e38302e6ae4c93b4ac9573a384ac6 \ No newline at end of file diff --git a/tests/regression_tests/plot_overlaps/settings.xml b/tests/regression_tests/plot_overlaps/settings.xml new file mode 100644 index 000000000..adf256d2d --- /dev/null +++ b/tests/regression_tests/plot_overlaps/settings.xml @@ -0,0 +1,13 @@ + + + + plot + + + 5 4 3 + -10 -10 -10 + 10 10 10 + + 1 + + diff --git a/tests/regression_tests/plot_overlaps/test.py b/tests/regression_tests/plot_overlaps/test.py index 0828c6e25..cf23abc27 100644 --- a/tests/regression_tests/plot_overlaps/test.py +++ b/tests/regression_tests/plot_overlaps/test.py @@ -1,7 +1,60 @@ -from tests.testing_harness import PlotTestHarness +import glob +import hashlib +import os + +import h5py +import openmc + +from tests.testing_harness import TestHarness from tests.regression_tests import config +class PlotTestHarness(TestHarness): + """Specialized TestHarness for running OpenMC plotting tests.""" + def __init__(self, plot_names): + super().__init__(None) + self._plot_names = plot_names + + def _run_openmc(self): + openmc.plot_geometry(openmc_exec=config['exe']) + + def _test_output_created(self): + """Make sure *.png has been created.""" + for fname in self._plot_names: + assert os.path.exists(fname), 'Plot output file does not exist.' + + def _cleanup(self): + super()._cleanup() + for fname in self._plot_names: + if os.path.exists(fname): + os.remove(fname) + + def _get_results(self): + """Return a string hash of the plot files.""" + outstr = bytes() + + for fname in self._plot_names: + if fname.endswith('.png'): + # Add PNG output to results + with open(fname, 'rb') as fh: + outstr += fh.read() + elif fname.endswith('.h5'): + # Add voxel data to results + with h5py.File(fname, 'r') as fh: + outstr += fh.attrs['filetype'] + outstr += fh.attrs['num_voxels'].tobytes() + outstr += fh.attrs['lower_left'].tobytes() + outstr += fh.attrs['voxel_width'].tobytes() + outstr += fh['data'][()].tobytes() + + # Hash the information and return. + sha512 = hashlib.sha512() + sha512.update(outstr) + outstr = sha512.hexdigest() + + return outstr + + def test_plot_overlap(): harness = PlotTestHarness(('plot_1.png', 'plot_2.png', 'plot_3.png', 'plot_4.h5')) diff --git a/tests/regression_tests/plot_projections/__init__.py b/tests/regression_tests/plot_projections/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/plot_projections/geometry.xml b/tests/regression_tests/plot_projections/geometry.xml deleted file mode 100644 index a648dfe92..000000000 --- a/tests/regression_tests/plot_projections/geometry.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/plot_projections/plots.xml b/tests/regression_tests/plot_projections/plots.xml deleted file mode 100644 index 50d129cd9..000000000 --- a/tests/regression_tests/plot_projections/plots.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - 0. 0. 0. - 20. 20. 20. - 200 200 - - - - 70 - - - - 0. 0. 0. - 10. 10. 0. - 25 25 - 200 200 - - 90 - 4 - example1 - - - - 0. 0. 0. - 20. 20. 20. - 200 200 - 240 240 240 - example2.png - 2 - - - - 0. 0. 0. - 0. 10.0 20. - 200 200 - 110 240 240 - example3.png - - - - 0. 0. 0. - 10. 10. 10. - 25 25 - 200 200 - 25.0 - 2 - orthographic_example1 - - - - - - - 0. 0. 0. - 10. 10. 10. - 200 200 - phong.png - 1 3 - - - - - - - 0. 0. 0. - 10. 10. 10. - 0.5 - 200 200 - phong_diffuse.png - 1 3 - - - - - - - 0. 0. 0. - 10. 10. 10. - 0. 10. 10. - 200 200 - phong_move_light.png - 1 3 - - - - - - diff --git a/tests/regression_tests/plot_projections/results_true.dat b/tests/regression_tests/plot_projections/results_true.dat deleted file mode 100644 index d5c6a7a58..000000000 --- a/tests/regression_tests/plot_projections/results_true.dat +++ /dev/null @@ -1 +0,0 @@ -6b90dfcf3059f86d623bb6496bb92d5b6ea2788b79639b61f865b31b503b84df9af64e59eacb04ccb02a225cfdb51bb7fa4b4f71e8e6ea20b2714266b34886ce \ No newline at end of file diff --git a/tests/regression_tests/plot_projections/test.py b/tests/regression_tests/plot_projections/test.py deleted file mode 100644 index 37a6ecf28..000000000 --- a/tests/regression_tests/plot_projections/test.py +++ /dev/null @@ -1,9 +0,0 @@ -from tests.testing_harness import PlotTestHarness -from tests.regression_tests import config - -def test_plot(): - harness = PlotTestHarness(('plot_1.png', 'example1.png', 'example2.png', - 'example3.png', 'orthographic_example1.png', - 'phong.png', 'phong_diffuse.png', - 'phong_move_light.png')) - harness.main() diff --git a/tests/regression_tests/plot_voxel/geometry.xml b/tests/regression_tests/plot_voxel/geometry.xml new file mode 100644 index 000000000..83619d9f7 --- /dev/null +++ b/tests/regression_tests/plot_voxel/geometry.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/regression_tests/plot_voxel/materials.xml b/tests/regression_tests/plot_voxel/materials.xml new file mode 100644 index 000000000..90b354267 --- /dev/null +++ b/tests/regression_tests/plot_voxel/materials.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/plot_voxel/model.xml b/tests/regression_tests/plot_voxel/model.xml deleted file mode 100644 index 7b0e854c5..000000000 --- a/tests/regression_tests/plot_voxel/model.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - plot - 1 - - 5 4 3 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - - - 0.0 0.0 0.0 - 20.0 20.0 10.0 - 50 50 10 - - - diff --git a/tests/regression_tests/plot_voxel/plots.xml b/tests/regression_tests/plot_voxel/plots.xml new file mode 100644 index 000000000..833329b42 --- /dev/null +++ b/tests/regression_tests/plot_voxel/plots.xml @@ -0,0 +1,10 @@ + + + + + 50 50 10 + 0. 0. 0. + 20 20 10 + + + diff --git a/tests/regression_tests/plot_voxel/settings.xml b/tests/regression_tests/plot_voxel/settings.xml new file mode 100644 index 000000000..adf256d2d --- /dev/null +++ b/tests/regression_tests/plot_voxel/settings.xml @@ -0,0 +1,13 @@ + + + + plot + + + 5 4 3 + -10 -10 -10 + 10 10 10 + + 1 + + diff --git a/tests/regression_tests/plot_voxel/test.py b/tests/regression_tests/plot_voxel/test.py index e034decf7..c4fa20c80 100644 --- a/tests/regression_tests/plot_voxel/test.py +++ b/tests/regression_tests/plot_voxel/test.py @@ -1,11 +1,62 @@ +import glob +import hashlib +import os +from subprocess import check_call + +import h5py +import openmc import pytest -from tests.testing_harness import PlotTestHarness +from tests.testing_harness import TestHarness from tests.regression_tests import config vtk = pytest.importorskip('vtk') +class PlotVoxelTestHarness(TestHarness): + """Specialized TestHarness for running OpenMC voxel plot tests.""" + def __init__(self, plot_names): + super().__init__(None) + self._plot_names = plot_names + + def _run_openmc(self): + openmc.plot_geometry(openmc_exec=config['exe']) + + check_call(['../../../scripts/openmc-voxel-to-vtk'] + + glob.glob('plot_4.h5')) + + def _test_output_created(self): + """Make sure plots have been created.""" + for fname in self._plot_names: + assert os.path.exists(fname), 'Plot output file does not exist.' + + def _cleanup(self): + super()._cleanup() + for fname in self._plot_names: + if os.path.exists(fname): + os.remove(fname) + + def _get_results(self): + """Return a string hash of the plot files.""" + outstr = bytes() + + for fname in self._plot_names: + if fname.endswith('.h5'): + # Add voxel data to results + with h5py.File(fname, 'r') as fh: + outstr += fh.attrs['filetype'] + outstr += fh.attrs['num_voxels'].tobytes() + outstr += fh.attrs['lower_left'].tobytes() + outstr += fh.attrs['voxel_width'].tobytes() + outstr += fh['data'][()].tobytes() + + # Hash the information and return. + sha512 = hashlib.sha512() + sha512.update(outstr) + outstr = sha512.hexdigest() + + return outstr + def test_plot_voxel(): - harness = PlotTestHarness(('plot_4.h5', 'plot.vti'), voxel_convert_checks=['plot_4.h5']) + harness = PlotVoxelTestHarness(('plot_4.h5', 'plot.vti')) harness.main() diff --git a/tests/regression_tests/ptables_off/results_true.dat b/tests/regression_tests/ptables_off/results_true.dat index 374274862..7c1d187bb 100644 --- a/tests/regression_tests/ptables_off/results_true.dat +++ b/tests/regression_tests/ptables_off/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.968228E-01 1.770320E-03 +3.042885E-01 1.073889E-02 diff --git a/tests/regression_tests/pulse_height/__init__.py b/tests/regression_tests/pulse_height/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/pulse_height/local_neutron/inputs_true.dat b/tests/regression_tests/pulse_height/local_neutron/inputs_true.dat deleted file mode 100644 index e25de58b0..000000000 --- a/tests/regression_tests/pulse_height/local_neutron/inputs_true.dat +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - fixed source - 100 - 5 - - - 1000000.0 1.0 - - - true - false - - - - 1 - - - 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 - - - 1 2 - pulse-height - - - diff --git a/tests/regression_tests/pulse_height/local_neutron/results_true.dat b/tests/regression_tests/pulse_height/local_neutron/results_true.dat deleted file mode 100644 index ffa284d92..000000000 --- a/tests/regression_tests/pulse_height/local_neutron/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -4.890000E+00 -4.784900E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -6.000000E-02 -1.800000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/pulse_height/local_photon/inputs_true.dat b/tests/regression_tests/pulse_height/local_photon/inputs_true.dat deleted file mode 100644 index 84d033d85..000000000 --- a/tests/regression_tests/pulse_height/local_photon/inputs_true.dat +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - fixed source - 100 - 5 - - - 1000000.0 1.0 - - - true - false - - - - 1 - - - 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 - - - 1 2 - pulse-height - - - diff --git a/tests/regression_tests/pulse_height/local_photon/results_true.dat b/tests/regression_tests/pulse_height/local_photon/results_true.dat deleted file mode 100644 index c57e8ff1c..000000000 --- a/tests/regression_tests/pulse_height/local_photon/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -4.140000E+00 -3.443000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -2.000000E-02 -4.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.000000E-02 -3.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.000000E-02 -6.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.600000E-03 diff --git a/tests/regression_tests/pulse_height/shared_neutron/inputs_true.dat b/tests/regression_tests/pulse_height/shared_neutron/inputs_true.dat deleted file mode 100644 index b13c53ef8..000000000 --- a/tests/regression_tests/pulse_height/shared_neutron/inputs_true.dat +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - fixed source - 100 - 5 - - - 1000000.0 1.0 - - - true - true - - - - 1 - - - 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 - - - 1 2 - pulse-height - - - diff --git a/tests/regression_tests/pulse_height/shared_neutron/results_true.dat b/tests/regression_tests/pulse_height/shared_neutron/results_true.dat deleted file mode 100644 index ffa284d92..000000000 --- a/tests/regression_tests/pulse_height/shared_neutron/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -4.890000E+00 -4.784900E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -6.000000E-02 -1.800000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/pulse_height/shared_photon/inputs_true.dat b/tests/regression_tests/pulse_height/shared_photon/inputs_true.dat deleted file mode 100644 index 608410c50..000000000 --- a/tests/regression_tests/pulse_height/shared_photon/inputs_true.dat +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - fixed source - 100 - 5 - - - 1000000.0 1.0 - - - true - true - - - - 1 - - - 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 - - - 1 2 - pulse-height - - - diff --git a/tests/regression_tests/pulse_height/shared_photon/results_true.dat b/tests/regression_tests/pulse_height/shared_photon/results_true.dat deleted file mode 100644 index c57e8ff1c..000000000 --- a/tests/regression_tests/pulse_height/shared_photon/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -4.140000E+00 -3.443000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -2.000000E-02 -4.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.000000E-02 -3.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.000000E-02 -6.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.600000E-03 diff --git a/tests/regression_tests/pulse_height/test.py b/tests/regression_tests/pulse_height/test.py deleted file mode 100644 index 371fcbd0f..000000000 --- a/tests/regression_tests/pulse_height/test.py +++ /dev/null @@ -1,54 +0,0 @@ -import numpy as np -import openmc -import pytest -from openmc.utility_funcs import change_directory - -from tests.testing_harness import PyAPITestHarness - - -@pytest.mark.parametrize("shared_secondary,particle", [ - (False, "photon"), - (False, "neutron"), - (True, "photon"), - (True, "neutron") -]) -def test_pulse_height(shared_secondary, particle): - subdir = f"shared_{particle}" if shared_secondary else f"local_{particle}" - with change_directory(subdir): - openmc.reset_auto_ids() - model = openmc.Model() - - # Define materials - NaI = openmc.Material() - NaI.set_density('g/cm3', 3.7) - NaI.add_element('Na', 1.0) - NaI.add_element('I', 1.0) - - # Define geometry: two spheres in each other - s1 = openmc.Sphere(r=1) - s2 = openmc.Sphere(r=2, boundary_type='vacuum') - inner_sphere = openmc.Cell(name='inner sphere', fill=NaI, region=-s1) - outer_sphere = openmc.Cell(name='outer sphere', region=+s1 & -s2) - model.geometry = openmc.Geometry([inner_sphere, outer_sphere]) - - # Define settings - model.settings.run_mode = 'fixed source' - model.settings.batches = 5 - model.settings.particles = 100 - model.settings.photon_transport = True - model.settings.shared_secondary_bank = shared_secondary - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(1e6), - particle=particle - ) - - # Define tallies - tally = openmc.Tally(name="pht tally") - tally.scores = ['pulse-height'] - cell_filter = openmc.CellFilter(inner_sphere) - energy_filter = openmc.EnergyFilter(np.linspace(0, 1e6, 101)) - tally.filters = [cell_filter, energy_filter] - model.tallies = [tally] - - harness = PyAPITestHarness('statepoint.5.h5', model) - harness.main() diff --git a/tests/regression_tests/quadric_surfaces/results_true.dat b/tests/regression_tests/quadric_surfaces/results_true.dat index 6fb569f52..8dc59df02 100644 --- a/tests/regression_tests/quadric_surfaces/results_true.dat +++ b/tests/regression_tests/quadric_surfaces/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.216213E+00 2.789559E-02 +1.213534E+00 1.386061E-02 diff --git a/tests/regression_tests/random_ray_adjoint_fixed_source/__init__.py b/tests/regression_tests/random_ray_adjoint_fixed_source/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat b/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat deleted file mode 100644 index 94e270976..000000000 --- a/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat +++ /dev/null @@ -1,248 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 500 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - true - naive - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_adjoint_fixed_source/results_true.dat b/tests/regression_tests/random_ray_adjoint_fixed_source/results_true.dat deleted file mode 100644 index e9aa9015b..000000000 --- a/tests/regression_tests/random_ray_adjoint_fixed_source/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.790516E+04 -6.740859E+08 -tally 2: -6.885455E+04 -9.482551E+08 -tally 3: -1.956327E+05 -7.654468E+09 diff --git a/tests/regression_tests/random_ray_adjoint_fixed_source/test.py b/tests/regression_tests/random_ray_adjoint_fixed_source/test.py deleted file mode 100644 index 6c2790fa0..000000000 --- a/tests/regression_tests/random_ray_adjoint_fixed_source/test.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - -from openmc.examples import random_ray_three_region_cube - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_adjoint_fixed_source(): - model = random_ray_three_region_cube() - model.settings.random_ray['adjoint'] = True - model.settings.random_ray['volume_estimator'] = 'naive' - model.settings.particles = 500 - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_adjoint_k_eff/__init__.py b/tests/regression_tests/random_ray_adjoint_k_eff/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_adjoint_k_eff/inputs_true.dat b/tests/regression_tests/random_ray_adjoint_k_eff/inputs_true.dat deleted file mode 100644 index 755afd6c4..000000000 --- a/tests/regression_tests/random_ray_adjoint_k_eff/inputs_true.dat +++ /dev/null @@ -1,112 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - true - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_adjoint_k_eff/results_true.dat b/tests/regression_tests/random_ray_adjoint_k_eff/results_true.dat deleted file mode 100644 index dfef53cd2..000000000 --- a/tests/regression_tests/random_ray_adjoint_k_eff/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -1.006640E+00 1.812969E-03 -tally 1: -1.208044E+00 -2.920182E-01 -4.854426E-01 -4.715453E-02 -0.000000E+00 -0.000000E+00 -1.149242E+00 -2.643067E-01 -1.750801E-01 -6.134563E-03 -0.000000E+00 -0.000000E+00 -1.077743E+00 -2.324814E-01 -3.492371E-02 -2.441363E-04 -0.000000E+00 -0.000000E+00 -9.285362E-01 -1.725808E-01 -3.098889E-02 -1.922297E-04 -1.963161E-07 -7.714727E-15 -8.778641E-01 -1.541719E-01 -1.028293E-02 -2.115448E-05 -5.402741E-04 -5.839789E-08 -8.730274E-01 -1.524358E-01 -1.301813E-03 -3.389450E-07 -6.542525E-01 -8.560964E-02 -9.328247E-01 -1.740366E-01 -1.226491E-02 -3.008584E-05 -9.997969E-01 -1.999204E-01 -9.784958E-01 -1.915688E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.017952E+00 -2.073461E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.027039E+00 -2.110955E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.598240E-01 -1.844004E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.937969E-01 -1.598332E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.752275E-01 -1.532052E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.248400E-01 -1.710699E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.254054E+00 -3.146708E-01 -5.124223E-01 -5.253093E-02 -0.000000E+00 -0.000000E+00 -1.183712E+00 -2.803961E-01 -1.834683E-01 -6.735381E-03 -0.000000E+00 -0.000000E+00 -1.093555E+00 -2.393604E-01 -3.601678E-02 -2.596341E-04 -0.000000E+00 -0.000000E+00 -9.242694E-01 -1.709967E-01 -3.130894E-02 -1.962084E-04 -1.983437E-07 -7.874400E-15 -8.742100E-01 -1.528879E-01 -1.041026E-02 -2.167970E-05 -5.469644E-04 -5.984780E-08 -8.724009E-01 -1.522171E-01 -1.322938E-03 -3.500386E-07 -6.648691E-01 -8.841161E-02 -9.353464E-01 -1.749781E-01 -1.251209E-02 -3.131171E-05 -1.019947E+00 -2.080664E-01 -1.209708E+00 -2.928214E-01 -4.976146E-01 -4.954258E-02 -0.000000E+00 -0.000000E+00 -1.149174E+00 -2.642694E-01 -1.791431E-01 -6.421530E-03 -0.000000E+00 -0.000000E+00 -1.076718E+00 -2.320295E-01 -3.567737E-02 -2.547314E-04 -0.000000E+00 -0.000000E+00 -9.272977E-01 -1.721077E-01 -3.161443E-02 -2.000179E-04 -2.002789E-07 -8.027290E-15 -8.778794E-01 -1.541769E-01 -1.051257E-02 -2.210729E-05 -5.523400E-04 -6.102818E-08 -8.730477E-01 -1.524429E-01 -1.331320E-03 -3.544869E-07 -6.690816E-01 -8.953516E-02 -9.334544E-01 -1.742707E-01 -1.255707E-02 -3.153710E-05 -1.023613E+00 -2.095641E-01 diff --git a/tests/regression_tests/random_ray_adjoint_k_eff/test.py b/tests/regression_tests/random_ray_adjoint_k_eff/test.py deleted file mode 100644 index 44cf1182a..000000000 --- a/tests/regression_tests/random_ray_adjoint_k_eff/test.py +++ /dev/null @@ -1,20 +0,0 @@ -import os - -from openmc.examples import random_ray_lattice - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_basic(): - model = random_ray_lattice() - model.settings.random_ray['adjoint'] = True - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_adjoint_local/__init__.py b/tests/regression_tests/random_ray_adjoint_local/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_adjoint_local/inputs_true.dat b/tests/regression_tests/random_ray_adjoint_local/inputs_true.dat deleted file mode 100644 index 9021d1675..000000000 --- a/tests/regression_tests/random_ray_adjoint_local/inputs_true.dat +++ /dev/null @@ -1,293 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - - - - - - fixed source - 500 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 800.0 - 100.0 - - - - 0.0 0.0 0.0 35.0 35.0 35.0 - - - - true - - - - - - true - - - - 100.0 1.0 - - - cell - 6 7 - - - - naive - - - 14 14 14 - 0.0 0.0 0.0 - 35.0 35.0 35.0 - - - - - 6 - - - 7 - - - 3 - - - 2 - - - 1 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - 3 - flux - tracklength - - - 4 - flux - tracklength - - - 5 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_adjoint_local/results_true.dat b/tests/regression_tests/random_ray_adjoint_local/results_true.dat deleted file mode 100644 index daa948565..000000000 --- a/tests/regression_tests/random_ray_adjoint_local/results_true.dat +++ /dev/null @@ -1,15 +0,0 @@ -tally 1: -2.215273E+01 -9.815738E+01 -tally 2: -1.873933E+01 -7.023420E+01 -tally 3: -4.802282E-01 -4.612707E-02 -tally 4: -2.516720E-01 -1.271063E-02 -tally 5: -1.169938E-02 -3.277334E-05 diff --git a/tests/regression_tests/random_ray_adjoint_local/test.py b/tests/regression_tests/random_ray_adjoint_local/test.py deleted file mode 100644 index c11b8e847..000000000 --- a/tests/regression_tests/random_ray_adjoint_local/test.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -import openmc - -from openmc.examples import random_ray_three_region_cube_with_detectors - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_adjoint_local(): - model = random_ray_three_region_cube_with_detectors() - - detector1_cells = model.geometry.get_cells_by_name("detector 1") - detector2_cells = model.geometry.get_cells_by_name("detector 2") - detector_cells = detector1_cells + detector2_cells - - strengths = [1.0] - midpoints = [100.0] - energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths) - - adj_source = openmc.IndependentSource(energy=energy_distribution, constraints={ - 'domains': detector_cells}, strength=3.14) - - model.settings.random_ray['adjoint'] = True - model.settings.random_ray['adjoint_source'] = adj_source - model.settings.random_ray['volume_estimator'] = 'naive' - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_auto_convert/__init__.py b/tests/regression_tests/random_ray_auto_convert/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_auto_convert/infinite_medium/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert/infinite_medium/inputs_true.dat deleted file mode 100644 index 81f8c98ca..000000000 --- a/tests/regression_tests/random_ray_auto_convert/infinite_medium/inputs_true.dat +++ /dev/null @@ -1,66 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert/infinite_medium/results_true.dat b/tests/regression_tests/random_ray_auto_convert/infinite_medium/results_true.dat deleted file mode 100644 index f984f3718..000000000 --- a/tests/regression_tests/random_ray_auto_convert/infinite_medium/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.479770E-01 1.624548E-02 diff --git a/tests/regression_tests/random_ray_auto_convert/material_wise/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert/material_wise/inputs_true.dat deleted file mode 100644 index 81f8c98ca..000000000 --- a/tests/regression_tests/random_ray_auto_convert/material_wise/inputs_true.dat +++ /dev/null @@ -1,66 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert/material_wise/results_true.dat b/tests/regression_tests/random_ray_auto_convert/material_wise/results_true.dat deleted file mode 100644 index 3bade01e0..000000000 --- a/tests/regression_tests/random_ray_auto_convert/material_wise/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.372542E-01 6.967831E-03 diff --git a/tests/regression_tests/random_ray_auto_convert/stochastic_slab/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert/stochastic_slab/inputs_true.dat deleted file mode 100644 index 81f8c98ca..000000000 --- a/tests/regression_tests/random_ray_auto_convert/stochastic_slab/inputs_true.dat +++ /dev/null @@ -1,66 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert/stochastic_slab/results_true.dat b/tests/regression_tests/random_ray_auto_convert/stochastic_slab/results_true.dat deleted file mode 100644 index 674dee4aa..000000000 --- a/tests/regression_tests/random_ray_auto_convert/stochastic_slab/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -6.413334E-01 2.083132E-02 diff --git a/tests/regression_tests/random_ray_auto_convert/test.py b/tests/regression_tests/random_ray_auto_convert/test.py deleted file mode 100644 index 99a931dce..000000000 --- a/tests/regression_tests/random_ray_auto_convert/test.py +++ /dev/null @@ -1,54 +0,0 @@ -import os - -import openmc -from openmc.examples import pwr_pin_cell -from openmc import RegularMesh -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("method", ["material_wise", "stochastic_slab", "infinite_medium"]) -def test_random_ray_auto_convert(method): - with change_directory(method): - openmc.reset_auto_ids() - - # Start with a normal continuous energy model - model = pwr_pin_cell() - - # Convert to a multi-group model - model.convert_to_multigroup( - method=method, groups='CASMO-2', nparticles=100, - overwrite_mgxs_library=False, mgxs_path="mgxs.h5" - ) - - # Convert to a random ray model - model.convert_to_random_ray() - - # Set the number of particles - model.settings.particles = 100 - - # Overlay a basic 2x2 mesh - n = 2 - mesh = RegularMesh() - mesh.dimension = (n, n) - bbox = model.geometry.bounding_box - mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) - mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) - model.settings.random_ray['source_region_meshes'] = [ - (mesh, [model.geometry.root_universe])] - - # Set the source shape to linear - model.settings.random_ray['source_shape'] = 'linear' - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/__init__.py b/tests/regression_tests/random_ray_auto_convert_kappa_fission/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/infinite_medium/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kappa_fission/infinite_medium/inputs_true.dat deleted file mode 100644 index 48b0e8256..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/infinite_medium/inputs_true.dat +++ /dev/null @@ -1,75 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - - - 1 - - - 61 - kappa-fission - - - diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/infinite_medium/results_true.dat b/tests/regression_tests/random_ray_auto_convert_kappa_fission/infinite_medium/results_true.dat deleted file mode 100644 index 27b32d787..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/infinite_medium/results_true.dat +++ /dev/null @@ -1,5 +0,0 @@ -k-combined: -7.479770E-01 1.624548E-02 -tally 1: -2.965503E+08 -1.762157E+16 diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/material_wise/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kappa_fission/material_wise/inputs_true.dat deleted file mode 100644 index be738c3e0..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/material_wise/inputs_true.dat +++ /dev/null @@ -1,75 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - - - 1 - - - 97 - kappa-fission - - - diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/material_wise/results_true.dat b/tests/regression_tests/random_ray_auto_convert_kappa_fission/material_wise/results_true.dat deleted file mode 100644 index 5a379db7e..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/material_wise/results_true.dat +++ /dev/null @@ -1,5 +0,0 @@ -k-combined: -7.372542E-01 6.967831E-03 -tally 1: -2.909255E+08 -1.693395E+16 diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/stochastic_slab/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kappa_fission/stochastic_slab/inputs_true.dat deleted file mode 100644 index be738c3e0..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/stochastic_slab/inputs_true.dat +++ /dev/null @@ -1,75 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - - - 1 - - - 97 - kappa-fission - - - diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/stochastic_slab/results_true.dat b/tests/regression_tests/random_ray_auto_convert_kappa_fission/stochastic_slab/results_true.dat deleted file mode 100644 index a60e5aa3c..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/stochastic_slab/results_true.dat +++ /dev/null @@ -1,5 +0,0 @@ -k-combined: -6.413334E-01 2.083132E-02 -tally 1: -2.541463E+08 -1.297259E+16 diff --git a/tests/regression_tests/random_ray_auto_convert_kappa_fission/test.py b/tests/regression_tests/random_ray_auto_convert_kappa_fission/test.py deleted file mode 100644 index 6decf165a..000000000 --- a/tests/regression_tests/random_ray_auto_convert_kappa_fission/test.py +++ /dev/null @@ -1,60 +0,0 @@ -import os - -import openmc -from openmc.examples import pwr_pin_cell -from openmc import RegularMesh -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("method", ["material_wise", "stochastic_slab", "infinite_medium"]) -def test_random_ray_auto_convert(method): - with change_directory(method): - openmc.reset_auto_ids() - - # Start with a normal continuous energy model - model = pwr_pin_cell() - - # Convert to a multi-group model - model.convert_to_multigroup( - method=method, groups='CASMO-2', nparticles=100, - overwrite_mgxs_library=False, mgxs_path="mgxs.h5" - ) - - # Convert to a random ray model - model.convert_to_random_ray() - - # Set the number of particles - model.settings.particles = 100 - - # Overlay a basic 2x2 mesh - n = 2 - mesh = RegularMesh() - mesh.dimension = (n, n) - bbox = model.geometry.bounding_box - mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) - mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) - model.settings.random_ray['source_region_meshes'] = [ - (mesh, [model.geometry.root_universe])] - - # Set the source shape to linear - model.settings.random_ray['source_shape'] = 'linear' - - # Set a material tally - t = openmc.Tally(name = 'KF Tally') - t.filters = [openmc.MaterialFilter(bins=1)] - t.scores = ['kappa-fission'] - model.tallies.append(t) - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/__init__.py b/tests/regression_tests/random_ray_auto_convert_source_energy/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/model/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/model/inputs_true.dat deleted file mode 100644 index d2d8289ff..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/model/inputs_true.dat +++ /dev/null @@ -1,63 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - 7000000.0 1.0 - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/model/results_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/model/results_true.dat deleted file mode 100644 index 1fb09fd68..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/model/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.657815E-01 2.317564E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/user/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/user/inputs_true.dat deleted file mode 100644 index 81f8c98ca..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/user/inputs_true.dat +++ /dev/null @@ -1,66 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/user/results_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/user/results_true.dat deleted file mode 100644 index 073c5c99f..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/infinite_medium/user/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.827784E-01 2.062954E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/model/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/model/inputs_true.dat deleted file mode 100644 index d2d8289ff..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/model/inputs_true.dat +++ /dev/null @@ -1,63 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - 7000000.0 1.0 - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/model/results_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/model/results_true.dat deleted file mode 100644 index c5cdf8e29..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/model/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.479571E-01 2.398563E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/user/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/user/inputs_true.dat deleted file mode 100644 index 81f8c98ca..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/user/inputs_true.dat +++ /dev/null @@ -1,66 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/user/results_true.dat b/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/user/results_true.dat deleted file mode 100644 index c6cce2e39..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/stochastic_slab/user/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.620306E-01 2.175179E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/test.py b/tests/regression_tests/random_ray_auto_convert_source_energy/test.py deleted file mode 100644 index bb9119d89..000000000 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/test.py +++ /dev/null @@ -1,66 +0,0 @@ -import os - -import openmc -from openmc.examples import pwr_pin_cell -from openmc import RegularMesh -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("source_type", ["model", "user"]) -@pytest.mark.parametrize("method", ["stochastic_slab", "infinite_medium"]) -def test_random_ray_auto_convert_source_energy(method, source_type): - dirname = f"{method}/{source_type}" - with change_directory(dirname): - openmc.reset_auto_ids() - - # Start with a normal continuous energy model - model = pwr_pin_cell() - - # Define the source energy distribution, using different methods - source_energy = None - if source_type == "model": - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(7.0e6) - ) - elif source_type == "user": - source_energy = openmc.stats.delta_function(1.0e4) - - # Convert to a multi-group model - model.convert_to_multigroup( - method=method, groups='CASMO-8', nparticles=100, - overwrite_mgxs_library=False, mgxs_path="mgxs.h5", - source_energy=source_energy - ) - - # Convert to a random ray model - model.convert_to_random_ray() - - # Set the number of particles - model.settings.particles = 100 - - # Overlay a basic 2x2 mesh - n = 2 - mesh = RegularMesh() - mesh.dimension = (n, n) - bbox = model.geometry.bounding_box - mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) - mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) - model.settings.random_ray['source_region_meshes'] = [ - (mesh, [model.geometry.root_universe])] - - # Set the source shape to linear - model.settings.random_ray['source_shape'] = 'linear' - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/__init__.py b/tests/regression_tests/random_ray_auto_convert_temperature/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/infinite_medium/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_temperature/infinite_medium/inputs_true.dat deleted file mode 100644 index c49020d55..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/infinite_medium/inputs_true.dat +++ /dev/null @@ -1,72 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - 395.0 - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - nearest - true - 200.0 400.0 - 200.0 - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/infinite_medium/results_true.dat b/tests/regression_tests/random_ray_auto_convert_temperature/infinite_medium/results_true.dat deleted file mode 100644 index fee8bf670..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/infinite_medium/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.499800E-01 1.615317E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/material_wise/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_temperature/material_wise/inputs_true.dat deleted file mode 100644 index c49020d55..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/material_wise/inputs_true.dat +++ /dev/null @@ -1,72 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - 395.0 - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - nearest - true - 200.0 400.0 - 200.0 - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/material_wise/results_true.dat b/tests/regression_tests/random_ray_auto_convert_temperature/material_wise/results_true.dat deleted file mode 100644 index ef0a4b87a..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/material_wise/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.367927E-01 6.850805E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/stochastic_slab/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_temperature/stochastic_slab/inputs_true.dat deleted file mode 100644 index c49020d55..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/stochastic_slab/inputs_true.dat +++ /dev/null @@ -1,72 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - 395.0 - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - nearest - true - 200.0 400.0 - 200.0 - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/stochastic_slab/results_true.dat b/tests/regression_tests/random_ray_auto_convert_temperature/stochastic_slab/results_true.dat deleted file mode 100644 index a702ec851..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/stochastic_slab/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -6.431774E-01 2.076589E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_temperature/test.py b/tests/regression_tests/random_ray_auto_convert_temperature/test.py deleted file mode 100644 index 99c99e614..000000000 --- a/tests/regression_tests/random_ray_auto_convert_temperature/test.py +++ /dev/null @@ -1,73 +0,0 @@ -import os - -import openmc -from openmc.examples import pwr_pin_cell -from openmc import RegularMesh -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("method", ["material_wise", "stochastic_slab", "infinite_medium"]) -def test_random_ray_auto_convert(method): - with change_directory(method): - openmc.reset_auto_ids() - - # Start with a normal continuous energy model - model = pwr_pin_cell() - - temp_settings = { - 'method' : 'nearest', - 'tolerance' : 200.0, - 'range' : (200.0, 400.0), - 'multipole' : True - } - - # Convert to a multi-group model - model.convert_to_multigroup( - method=method, groups='CASMO-2', nparticles=100, - overwrite_mgxs_library=False, mgxs_path="mgxs.h5", - temperatures=[294.0, 394.0], temperature_settings=temp_settings - ) - - # Convert to a random ray model - model.convert_to_random_ray() - model.settings.temperature = temp_settings - - # Set all material temperatures to room temperature - for mat in model.geometry.get_all_materials().values(): - mat.temperature = 294.0 - - # Set the cell temperature of the fuel such that it moves up to the next - # temperature bin. - for cell in model.geometry.get_all_cells().values(): - if cell.name == "Fuel": - cell.temperature = [395.0] - - # Set the number of particles - model.settings.particles = 100 - - # Overlay a basic 2x2 mesh - n = 2 - mesh = RegularMesh() - mesh.dimension = (n, n) - bbox = model.geometry.bounding_box - mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) - mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) - model.settings.random_ray['source_region_meshes'] = [ - (mesh, [model.geometry.root_universe])] - - # Set the source shape to linear - model.settings.random_ray['source_shape'] = 'linear' - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_cell_density/__init__.py b/tests/regression_tests/random_ray_cell_density/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_cell_density/eigen/inputs_true.dat b/tests/regression_tests/random_ray_cell_density/eigen/inputs_true.dat deleted file mode 100644 index eacd54f83..000000000 --- a/tests/regression_tests/random_ray_cell_density/eigen/inputs_true.dat +++ /dev/null @@ -1,117 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_cell_density/eigen/results_true.dat b/tests/regression_tests/random_ray_cell_density/eigen/results_true.dat deleted file mode 100644 index 3e6ce4039..000000000 --- a/tests/regression_tests/random_ray_cell_density/eigen/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -7.606488E-01 9.025978E-03 -tally 1: -6.209503E-01 -7.732732E-02 -4.335729E-01 -3.769026E-02 -1.055230E+00 -2.232538E-01 -4.077492E-01 -3.335434E-02 -1.188353E-01 -2.833644E-03 -2.892214E-01 -1.678476E-02 -2.715245E-01 -1.488194E-02 -1.736084E-02 -6.079207E-05 -4.225281E-02 -3.600946E-04 -3.700491E-01 -2.796457E-02 -2.369715E-02 -1.145314E-04 -5.767413E-02 -6.784132E-04 -1.223083E+00 -3.058118E-01 -2.790791E-02 -1.593458E-04 -6.792309E-02 -9.438893E-04 -4.095779E+00 -3.377358E+00 -1.251201E-02 -3.153331E-05 -3.096010E-02 -1.930723E-04 -2.608638E+00 -1.361111E+00 -7.059742E-02 -9.968342E-04 -1.963632E-01 -7.711968E-03 -1.164050E+00 -2.710289E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.325486E-01 -5.675375E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.058117E-01 -1.905099E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.645650E-01 -4.428410E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.350036E+00 -3.718611E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.538916E+00 -2.521670E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.201812E+00 -9.698678E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.776093E-01 -9.211106E-02 -2.527022E-01 -1.280619E-02 -6.150266E-01 -7.585593E-02 -4.194143E-01 -3.528585E-02 -6.303447E-02 -7.972233E-04 -1.534133E-01 -4.722259E-03 -2.743408E-01 -1.520611E-02 -8.961769E-03 -1.621446E-05 -2.181115E-02 -9.604444E-05 -3.871710E-01 -3.063162E-02 -1.288801E-02 -3.392550E-05 -3.136683E-02 -2.009537E-04 -1.259769E+00 -3.241545E-01 -1.478360E-02 -4.466102E-05 -3.598077E-02 -2.645508E-04 -4.032169E+00 -3.273866E+00 -6.215187E-03 -7.776862E-06 -1.537904E-02 -4.761620E-05 -2.583647E+00 -1.335275E+00 -3.533526E-02 -2.498005E-04 -9.828323E-02 -1.932572E-03 -7.851145E-01 -1.234783E-01 -2.966638E-01 -1.763751E-02 -7.220204E-01 -1.044737E-01 -4.505673E-01 -4.067697E-02 -6.823342E-02 -9.332472E-04 -1.660665E-01 -5.527980E-03 -2.832534E-01 -1.626181E-02 -9.297014E-03 -1.749663E-05 -2.262707E-02 -1.036392E-04 -4.056699E-01 -3.370803E-02 -1.358439E-02 -3.774180E-05 -3.306168E-02 -2.235591E-04 -1.279744E+00 -3.345476E-01 -1.512005E-02 -4.668112E-05 -3.679962E-02 -2.765169E-04 -3.917888E+00 -3.090981E+00 -6.082371E-03 -7.449625E-06 -1.505040E-02 -4.561259E-05 -2.520906E+00 -1.271106E+00 -3.477796E-02 -2.419730E-04 -9.673314E-02 -1.872015E-03 diff --git a/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat b/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat deleted file mode 100644 index f369bae89..000000000 --- a/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_cell_density/fs/results_true.dat b/tests/regression_tests/random_ray_cell_density/fs/results_true.dat deleted file mode 100644 index e12f476e0..000000000 --- a/tests/regression_tests/random_ray_cell_density/fs/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -6.203077E-01 -7.706659E-02 -tally 2: -3.203448E-02 -2.058679E-04 -tally 3: -2.091970E-03 -8.765168E-07 diff --git a/tests/regression_tests/random_ray_cell_density/test.py b/tests/regression_tests/random_ray_cell_density/test.py deleted file mode 100644 index 48ebe0baa..000000000 --- a/tests/regression_tests/random_ray_cell_density/test.py +++ /dev/null @@ -1,43 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_lattice, random_ray_three_region_cube -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("run_mode", ["eigen", "fs"]) -def test_random_ray_basic(run_mode): - with change_directory(run_mode): - if run_mode == "eigen": - openmc.reset_auto_ids() - model = random_ray_lattice() - # Double the densities of the lower-left fuel pin -> cell instances [0, 8). - for id, cell in model.geometry.get_all_cells().items(): - if cell.fill.name == "UO2 fuel": - cell.density = [((i < 8) + 1.0) for i in range(24)] - - # Gold file was generated with manually scaled fuel cross sections. - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() - else: - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - # Increase the density in the source region. - for id, cell in model.geometry.get_all_cells().items(): - if cell.fill.name == "source": - cell.density = 1e3 - - # Gold file was generated with manually scaled source cross sections. - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_cell_temperature/__init__.py b/tests/regression_tests/random_ray_cell_temperature/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_cell_temperature/inputs_true.dat b/tests/regression_tests/random_ray_cell_temperature/inputs_true.dat deleted file mode 100644 index 99363ed87..000000000 --- a/tests/regression_tests/random_ray_cell_temperature/inputs_true.dat +++ /dev/null @@ -1,120 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - 395.0 395.0 395.0 395.0 395.0 395.0 395.0 395.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 - - - 395.0 395.0 395.0 395.0 395.0 395.0 395.0 395.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 - - - 395.0 395.0 395.0 395.0 395.0 395.0 395.0 395.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 295.0 - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - multi-group - nearest - 200.0 400.0 - 10.0 - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_cell_temperature/results_true.dat b/tests/regression_tests/random_ray_cell_temperature/results_true.dat deleted file mode 100644 index 50476beb6..000000000 --- a/tests/regression_tests/random_ray_cell_temperature/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -8.721099E-01 6.686066E-03 -tally 1: -1.530055E+00 -4.684582E-01 -2.918032E-01 -1.703772E-02 -7.101906E-01 -1.009209E-01 -7.732582E-01 -1.197247E-01 -5.787213E-02 -6.705930E-04 -1.408492E-01 -3.972179E-03 -4.223488E-01 -3.605283E-02 -6.818063E-03 -9.396342E-06 -1.659380E-02 -5.565812E-05 -5.958551E-01 -7.215230E-02 -9.932163E-03 -2.004773E-05 -2.417290E-02 -1.187504E-04 -1.685106E+00 -5.752729E-01 -9.834826E-03 -1.960236E-05 -2.393629E-02 -1.161151E-04 -4.400457E+00 -3.886563E+00 -3.318560E-03 -2.211175E-06 -8.211544E-03 -1.353859E-05 -2.814971E+00 -1.585202E+00 -1.876190E-02 -7.040316E-05 -5.218528E-02 -5.446713E-04 -1.970406E+00 -7.765020E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.643086E-01 -1.494764E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.421562E-01 -3.961223E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.421077E-01 -8.385255E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.717683E+00 -5.974687E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.024715E+00 -3.251629E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.507885E+00 -1.258277E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.237600E+00 -3.066006E-01 -4.632318E-01 -4.294997E-02 -1.127413E+00 -2.544090E-01 -7.085300E-01 -1.005838E-01 -1.066845E-01 -2.280854E-03 -2.596486E-01 -1.351037E-02 -4.080999E-01 -3.359223E-02 -1.334606E-02 -3.590848E-05 -3.248163E-02 -2.126996E-04 -5.587686E-01 -6.339264E-02 -1.868162E-02 -7.084921E-05 -4.546734E-02 -4.196670E-04 -1.647852E+00 -5.503007E-01 -1.940765E-02 -7.635704E-05 -4.723492E-02 -4.523030E-04 -4.672431E+00 -4.381400E+00 -7.228567E-03 -1.048470E-05 -1.788658E-02 -6.419579E-05 -3.054158E+00 -1.866081E+00 -4.202691E-02 -3.534383E-04 -1.168957E-01 -2.734362E-03 -1.313678E+00 -3.454374E-01 -4.964081E-01 -4.934325E-02 -1.208158E+00 -2.922789E-01 -7.298176E-01 -1.067017E-01 -1.106319E-01 -2.452869E-03 -2.692559E-01 -1.452928E-02 -4.129038E-01 -3.441066E-02 -1.357107E-02 -3.713729E-05 -3.302926E-02 -2.199783E-04 -5.677464E-01 -6.543807E-02 -1.908992E-02 -7.390190E-05 -4.646105E-02 -4.377492E-04 -1.651067E+00 -5.522453E-01 -1.956802E-02 -7.754346E-05 -4.762523E-02 -4.593308E-04 -4.583305E+00 -4.217589E+00 -7.135836E-03 -1.022408E-05 -1.765713E-02 -6.260005E-05 -2.988394E+00 -1.786305E+00 -4.141550E-02 -3.431964E-04 -1.151951E-01 -2.655125E-03 diff --git a/tests/regression_tests/random_ray_cell_temperature/test.py b/tests/regression_tests/random_ray_cell_temperature/test.py deleted file mode 100644 index ef36d9238..000000000 --- a/tests/regression_tests/random_ray_cell_temperature/test.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_lattice, random_ray_three_region_cube -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_basic(): - openmc.reset_auto_ids() - model = random_ray_lattice(second_temp=True) - # Set the temperature of the lower-left pin to 395 K -> cell instances [0, 8). - # All other pins are set to 295. - for id, cell in model.geometry.get_all_cells().items(): - if cell.fill.name == "UO2 fuel": - cell.temperature = [(100.0 * (i < 8) + 295.0) for i in range(24)] - - model.settings.temperature = { - 'method' : 'nearest', - 'tolerance' : 10.0, - 'range' : (200.0, 400.0) - } - - # Gold file was generated with manually scaled fuel cross sections. - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_diagonal_stabilization/__init__.py b/tests/regression_tests/random_ray_diagonal_stabilization/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization/inputs_true.dat b/tests/regression_tests/random_ray_diagonal_stabilization/inputs_true.dat deleted file mode 100644 index 0ea8c0177..000000000 --- a/tests/regression_tests/random_ray_diagonal_stabilization/inputs_true.dat +++ /dev/null @@ -1,67 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 20 - 15 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - true - - - multi-group - - - - - -0.63 -0.63 -1.0 0.63 0.63 1.0 - - - - 30.0 - 150.0 - - - - - - linear - 0.5 - - - 2 2 - -0.63 -0.63 - 0.63 0.63 - - - diff --git a/tests/regression_tests/random_ray_diagonal_stabilization/results_true.dat b/tests/regression_tests/random_ray_diagonal_stabilization/results_true.dat deleted file mode 100644 index 034d7f7c6..000000000 --- a/tests/regression_tests/random_ray_diagonal_stabilization/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -7.134473E-01 1.422763E-02 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization/test.py b/tests/regression_tests/random_ray_diagonal_stabilization/test.py deleted file mode 100644 index 8d36e1d25..000000000 --- a/tests/regression_tests/random_ray_diagonal_stabilization/test.py +++ /dev/null @@ -1,61 +0,0 @@ -import os - -from openmc.examples import pwr_pin_cell -from openmc import RegularMesh - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_diagonal_stabilization(): - # Start with a normal continuous energy model - model = pwr_pin_cell() - - # Convert to a multi-group model, with 70 group XS - # and transport correction enabled. This will generate - # MGXS data with some negatives on the diagonal, in order - # to trigger diagonal correction. - model.convert_to_multigroup( - method='material_wise', groups='CASMO-70', nparticles=13, - overwrite_mgxs_library=True, mgxs_path="mgxs.h5", correction='P0' - ) - - # Convert to a random ray model - model.convert_to_random_ray() - - # Set the number of particles - model.settings.particles = 100 - - # Overlay a basic 2x2 mesh - n = 2 - mesh = RegularMesh() - mesh.dimension = (n, n) - bbox = model.geometry.bounding_box - mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) - mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) - model.settings.random_ray['source_region_meshes'] = [ - (mesh, [model.geometry.root_universe])] - - # Set the source shape to linear - model.settings.random_ray['source_shape'] = 'linear' - - # Explicitly set the diagonal stabilization rho (default is otherwise 1.0). - # Note that if we set this to 0.0 (thus distabling stabilization), the - # problem should fail due to instability, so this is actually a good test - # problem. - model.settings.random_ray['diagonal_stabilization_rho'] = 0.5 - - # If rho was 0.0, the instability would cause failure after iteration 14, - # so we go a little past that. - model.settings.inactive = 15 - model.settings.batches = 20 - - harness = MGXSTestHarness('statepoint.20.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_entropy/__init__.py b/tests/regression_tests/random_ray_entropy/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_entropy/geometry.xml b/tests/regression_tests/random_ray_entropy/geometry.xml deleted file mode 100644 index 4c87bbbfb..000000000 --- a/tests/regression_tests/random_ray_entropy/geometry.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - 12.5 12.5 12.5 - 8 8 8 - 0.0 0.0 0.0 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 - - - - - - - - diff --git a/tests/regression_tests/random_ray_entropy/materials.xml b/tests/regression_tests/random_ray_entropy/materials.xml deleted file mode 100644 index 5a6f93414..000000000 --- a/tests/regression_tests/random_ray_entropy/materials.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - mgxs.h5 - - - - - diff --git a/tests/regression_tests/random_ray_entropy/mgxs.h5 b/tests/regression_tests/random_ray_entropy/mgxs.h5 deleted file mode 100644 index 6ce80bf71..000000000 Binary files a/tests/regression_tests/random_ray_entropy/mgxs.h5 and /dev/null differ diff --git a/tests/regression_tests/random_ray_entropy/results_true.dat b/tests/regression_tests/random_ray_entropy/results_true.dat deleted file mode 100644 index 254254538..000000000 --- a/tests/regression_tests/random_ray_entropy/results_true.dat +++ /dev/null @@ -1,13 +0,0 @@ -k-combined: -1.000000E+00 0.000000E+00 -entropy: -8.863421E+00 -8.933584E+00 -8.960553E+00 -8.967921E+00 -8.976016E+00 -8.981856E+00 -8.983670E+00 -8.986584E+00 -8.987732E+00 -8.988186E+00 diff --git a/tests/regression_tests/random_ray_entropy/settings.xml b/tests/regression_tests/random_ray_entropy/settings.xml deleted file mode 100644 index 0d830417b..000000000 --- a/tests/regression_tests/random_ray_entropy/settings.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - eigenvalue - 100 - 10 - 5 - multi-group - - - - - 0.0 0.0 0.0 100.0 100.0 100.0 - - - - 40.0 - 400.0 - - diff --git a/tests/regression_tests/random_ray_entropy/test.py b/tests/regression_tests/random_ray_entropy/test.py deleted file mode 100644 index a3cba65ad..000000000 --- a/tests/regression_tests/random_ray_entropy/test.py +++ /dev/null @@ -1,33 +0,0 @@ -import glob -import os - -from openmc import StatePoint - -from tests.testing_harness import TestHarness - - -class EntropyTestHarness(TestHarness): - def _get_results(self): - """Digest info in the statepoint and return as a string.""" - # Read the statepoint file. - statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] - with StatePoint(statepoint) as sp: - # Write out k-combined. - outstr = 'k-combined:\n' - outstr += '{:12.6E} {:12.6E}\n'.format(sp.keff.n, sp.keff.s) - - # Write out entropy data. - outstr += 'entropy:\n' - results = ['{:12.6E}'.format(x) for x in sp.entropy] - outstr += '\n'.join(results) + '\n' - - return outstr - -''' -# This test is adapted from "Monte Carlo power iteration: Entropy and spatial correlations," -M. Nowak et al. The cross sections are defined explicitly so that the value for entropy -is exactly 9 and the eigenvalue is exactly 1. -''' -def test_entropy(): - harness = EntropyTestHarness('statepoint.10.h5') - harness.main() diff --git a/tests/regression_tests/random_ray_fixed_source_domain/__init__.py b/tests/regression_tests/random_ray_fixed_source_domain/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat deleted file mode 100644 index d650bbaf9..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - cell - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_domain/cell/results_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/cell/results_true.dat deleted file mode 100644 index 6da51a711..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/cell/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.934460E-01 -7.058894E-02 -tally 2: -3.206214E-02 -2.063370E-04 -tally 3: -2.096411E-03 -8.804924E-07 diff --git a/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat deleted file mode 100644 index 98a51add1..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - material - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_domain/material/results_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/material/results_true.dat deleted file mode 100644 index 6da51a711..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/material/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.934460E-01 -7.058894E-02 -tally 2: -3.206214E-02 -2.063370E-04 -tally 3: -2.096411E-03 -8.804924E-07 diff --git a/tests/regression_tests/random_ray_fixed_source_domain/test.py b/tests/regression_tests/random_ray_fixed_source_domain/test.py deleted file mode 100644 index 5885a9200..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/test.py +++ /dev/null @@ -1,51 +0,0 @@ -import os - -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("domain_type", ["cell", "material", "universe"]) -def test_random_ray_fixed_source(domain_type): - with change_directory(domain_type): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - - # Based on the parameter, we need to adjust - # the particle source constraints - source = model.settings.source[0] - constraints = source.constraints - - if domain_type == 'cell': - cells = model.geometry.get_all_cells() - for key, cell in cells.items(): - print(cell.name) - if cell.name == 'infinite source region': - constraints['domain_type'] = 'cell' - constraints['domain_ids'] = [cell.id] - elif domain_type == 'material': - materials = model.materials - for material in materials: - if material.name == 'source': - constraints['domain_type'] = 'material' - constraints['domain_ids'] = [material.id] - elif domain_type == 'universe': - universes = model.geometry.get_all_universes() - for key, universe in universes.items(): - if universe.name == 'source universe': - constraints['domain_type'] = 'universe' - constraints['domain_ids'] = [universe.id] - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat deleted file mode 100644 index 20deba664..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_domain/universe/results_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/universe/results_true.dat deleted file mode 100644 index 6da51a711..000000000 --- a/tests/regression_tests/random_ray_fixed_source_domain/universe/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.934460E-01 -7.058894E-02 -tally 2: -3.206214E-02 -2.063370E-04 -tally 3: -2.096411E-03 -8.804924E-07 diff --git a/tests/regression_tests/random_ray_fixed_source_linear/__init__.py b/tests/regression_tests/random_ray_fixed_source_linear/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat deleted file mode 100644 index 2268d82c3..000000000 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - linear - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear/results_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear/results_true.dat deleted file mode 100644 index e90d6bfdc..000000000 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.339086E+00 -2.747305E-01 -tally 2: -1.089827E-01 -6.069324E-04 -tally 3: -7.300831E-03 -2.715940E-06 diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat deleted file mode 100644 index fe95baa7b..000000000 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - linear_xy - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/results_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/results_true.dat deleted file mode 100644 index f4c8546aa..000000000 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.335703E+00 -2.742866E-01 -tally 2: -1.081884E-01 -5.983316E-04 -tally 3: -7.295389E-03 -2.711859E-06 diff --git a/tests/regression_tests/random_ray_fixed_source_linear/test.py b/tests/regression_tests/random_ray_fixed_source_linear/test.py deleted file mode 100644 index 99211024e..000000000 --- a/tests/regression_tests/random_ray_fixed_source_linear/test.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -import numpy as np -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("shape", ["linear", "linear_xy"]) -def test_random_ray_fixed_source_linear(shape): - with change_directory(shape): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - model.settings.random_ray['source_shape'] = shape - model.settings.inactive = 20 - model.settings.batches = 40 - harness = MGXSTestHarness('statepoint.40.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/__init__.py b/tests/regression_tests/random_ray_fixed_source_mesh/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat deleted file mode 100644 index a5632ece9..000000000 --- a/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat +++ /dev/null @@ -1,273 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 30 - 15 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - - - - - - - - flat - - - 24 24 24 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 36 36 36 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 30 30 30 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/flat/results_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/flat/results_true.dat deleted file mode 100644 index 0b0eaa447..000000000 --- a/tests/regression_tests/random_ray_fixed_source_mesh/flat/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -1.750296E+00 -2.051829E-01 -tally 2: -8.045199E-02 -4.384408E-04 -tally 3: -5.216828E-03 -1.840861E-06 diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat deleted file mode 100644 index 9d22603c6..000000000 --- a/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat +++ /dev/null @@ -1,273 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 30 - 15 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - - - - - - - - linear - - - 24 24 24 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 36 36 36 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 30 30 30 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/linear/results_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/linear/results_true.dat deleted file mode 100644 index 23754a157..000000000 --- a/tests/regression_tests/random_ray_fixed_source_mesh/linear/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -1.780361E+00 -2.137912E-01 -tally 2: -8.230400E-02 -4.596391E-04 -tally 3: -5.207797E-03 -1.834531E-06 diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/test.py b/tests/regression_tests/random_ray_fixed_source_mesh/test.py deleted file mode 100644 index 0b93b2a7a..000000000 --- a/tests/regression_tests/random_ray_fixed_source_mesh/test.py +++ /dev/null @@ -1,53 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_three_region_cube -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def make_mesh(dim): - width = 30.0 - mesh = openmc.RegularMesh() - mesh.dimension = (dim, dim, dim) - mesh.lower_left = (0.0, 0.0, 0.0) - mesh.upper_right = (width, width, width) - return mesh - - -@pytest.mark.parametrize("shape", ["flat", "linear"]) -def test_random_ray_fixed_source_mesh(shape): - with change_directory(shape): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - - # We will apply three different mesh resolutions to three different domain types - source_universe = model.geometry.get_universes_by_name('source universe')[0] - void_cell = model.geometry.get_cells_by_name('infinite void region')[0] - absorber_mat = model.geometry.get_materials_by_name('absorber')[0] - - model.settings.random_ray['source_region_meshes'] = [ - (make_mesh(24), [source_universe]), - (make_mesh(36), [void_cell]), - (make_mesh(30), [absorber_mat]) - ] - - # We also test flat/linear source shapes to ensure they are both - # working correctly with the mesh overlay logic - model.settings.random_ray['source_shape'] = shape - - model.settings.inactive = 15 - model.settings.batches = 30 - - harness = MGXSTestHarness('statepoint.30.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat deleted file mode 100644 index de941f10f..000000000 --- a/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - false - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/False/results_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/False/results_true.dat deleted file mode 100644 index d8f78493c..000000000 --- a/tests/regression_tests/random_ray_fixed_source_normalization/False/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -6.840321E+01 -9.376316E+02 -tally 2: -4.976182E+02 -4.970407E+04 -tally 3: -2.382441E+01 -1.137148E+02 diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat deleted file mode 100644 index 20deba664..000000000 --- a/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/True/results_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/True/results_true.dat deleted file mode 100644 index 6da51a711..000000000 --- a/tests/regression_tests/random_ray_fixed_source_normalization/True/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.934460E-01 -7.058894E-02 -tally 2: -3.206214E-02 -2.063370E-04 -tally 3: -2.096411E-03 -8.804924E-07 diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/__init__.py b/tests/regression_tests/random_ray_fixed_source_normalization/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/test.py b/tests/regression_tests/random_ray_fixed_source_normalization/test.py deleted file mode 100644 index 3fa4ba2a6..000000000 --- a/tests/regression_tests/random_ray_fixed_source_normalization/test.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("normalize", [True, False]) -def test_random_ray_fixed_source(normalize): - with change_directory(str(normalize)): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - model.settings.random_ray['volume_normalized_flux_tallies'] = normalize - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_fixed_source_subcritical/__init__.py b/tests/regression_tests/random_ray_fixed_source_subcritical/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_fixed_source_subcritical/flat/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_subcritical/flat/inputs_true.dat deleted file mode 100644 index 943468a10..000000000 --- a/tests/regression_tests/random_ray_fixed_source_subcritical/flat/inputs_true.dat +++ /dev/null @@ -1,142 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 9 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 12 -12 13 - - - - - - - - - - - - - - - - - - - - - fixed source - 30 - 125 - 100 - - - 1.134 -1.26 -1.0 1.26 -1.134 1.0 - - - 2e-05 0.0735 20.0 200.0 2000.0 750000.0 2000000.0 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 - - - universe - 9 - - - multi-group - - 40.0 - 40.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - false - flat - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_fixed_source_subcritical/flat/results_true.dat b/tests/regression_tests/random_ray_fixed_source_subcritical/flat/results_true.dat deleted file mode 100644 index 4d2fb6c57..000000000 --- a/tests/regression_tests/random_ray_fixed_source_subcritical/flat/results_true.dat +++ /dev/null @@ -1,169 +0,0 @@ -tally 1: -1.591301E+02 -1.016825E+03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.916980E+01 -1.404518E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.036992E+01 -1.662864E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.464728E+01 -2.434669E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.260923E+01 -1.109616E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.443775E+01 -3.580658E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.708323E+01 -1.318058E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.004495E+02 -1.610586E+03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -7.321594E+01 -2.147152E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.573858E+01 -2.655227E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.944079E+01 -3.474938E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.758548E+01 -1.328297E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.536577E+01 -3.644652E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.824884E+01 -1.368347E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.073355E+02 -4.630895E+02 -1.263975E+01 -6.427678E+00 -3.076263E+01 -3.807359E+01 -4.995302E+01 -1.001379E+02 -2.355060E+00 -2.226283E-01 -5.731746E+00 -1.318712E+00 -1.959843E+01 -1.538887E+01 -2.005479E-01 -1.611455E-03 -4.880935E-01 -9.545263E-03 -2.315398E+01 -2.148264E+01 -2.441408E-01 -2.388612E-03 -5.941898E-01 -1.414866E-02 -5.319554E+01 -1.134034E+02 -1.967517E-01 -1.551313E-03 -4.788601E-01 -9.189243E-03 -1.192041E+02 -5.698491E+02 -5.811654E-02 -1.356369E-04 -1.438053E-01 -8.304781E-04 -8.044764E+01 -2.602455E+02 -3.474828E-01 -4.908566E-03 -9.665057E-01 -3.797493E-02 -1.561720E+02 -9.788256E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.840869E+01 -1.368656E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.029506E+01 -1.650985E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.467632E+01 -2.440891E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.301033E+01 -1.126277E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.608414E+01 -3.702737E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.881578E+01 -1.396463E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/random_ray_fixed_source_subcritical/linear_xy/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_subcritical/linear_xy/inputs_true.dat deleted file mode 100644 index 650953c4b..000000000 --- a/tests/regression_tests/random_ray_fixed_source_subcritical/linear_xy/inputs_true.dat +++ /dev/null @@ -1,142 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 8 -8 8 8 8 8 8 8 8 8 9 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 12 -12 13 - - - - - - - - - - - - - - - - - - - - - fixed source - 30 - 125 - 100 - - - 1.134 -1.26 -1.0 1.26 -1.134 1.0 - - - 2e-05 0.0735 20.0 200.0 2000.0 750000.0 2000000.0 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 0.14285714285714285 - - - universe - 9 - - - multi-group - - 40.0 - 40.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - false - linear_xy - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_fixed_source_subcritical/linear_xy/results_true.dat b/tests/regression_tests/random_ray_fixed_source_subcritical/linear_xy/results_true.dat deleted file mode 100644 index bf602d3e2..000000000 --- a/tests/regression_tests/random_ray_fixed_source_subcritical/linear_xy/results_true.dat +++ /dev/null @@ -1,169 +0,0 @@ -tally 1: -1.583465E+02 -1.007029E+03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.891526E+01 -1.392807E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.028338E+01 -1.649224E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.453687E+01 -2.413498E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.235813E+01 -1.099243E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.394406E+01 -3.543513E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.676284E+01 -1.303104E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.007858E+02 -1.616216E+03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -7.319709E+01 -2.146301E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.566730E+01 -2.640697E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.934703E+01 -3.453026E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.737215E+01 -1.318580E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.495275E+01 -3.613373E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.799251E+01 -1.356178E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.066414E+02 -4.570291E+02 -1.254014E+01 -6.325641E+00 -3.052020E+01 -3.746918E+01 -4.977302E+01 -9.940548E+01 -2.345790E+00 -2.208444E-01 -5.709184E+00 -1.308146E+00 -1.953082E+01 -1.528292E+01 -1.998234E-01 -1.599792E-03 -4.863302E-01 -9.476180E-03 -2.307196E+01 -2.133059E+01 -2.432481E-01 -2.371074E-03 -5.920173E-01 -1.404478E-02 -5.299863E+01 -1.125576E+02 -1.959914E-01 -1.539191E-03 -4.770098E-01 -9.117441E-03 -1.186133E+02 -5.641060E+02 -5.781230E-02 -1.341759E-04 -1.430525E-01 -8.215327E-04 -7.995734E+01 -2.570099E+02 -3.452934E-01 -4.844059E-03 -9.604162E-01 -3.747587E-02 -1.556795E+02 -9.726232E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.816726E+01 -1.357531E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.018480E+01 -1.633551E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.453476E+01 -2.413615E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.269380E+01 -1.113102E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.550216E+01 -3.658264E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.846320E+01 -1.379625E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/random_ray_fixed_source_subcritical/test.py b/tests/regression_tests/random_ray_fixed_source_subcritical/test.py deleted file mode 100644 index e2f3cf175..000000000 --- a/tests/regression_tests/random_ray_fixed_source_subcritical/test.py +++ /dev/null @@ -1,133 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_lattice -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("shape", ["flat", "linear_xy"]) -def test_random_ray_fixed_source_subcritical(shape): - with change_directory(shape): - openmc.reset_auto_ids() - - # The general strategy is to reuse the random_ray_lattice model, - # but redfine some of the geometry to make it a good - # subcritical multiplication problem. We then also add in - # a fixed source term. - - model = random_ray_lattice() - - # Begin by updating the random ray settings for fixed source - settings = model.settings - settings.random_ray['source_shape'] = shape - settings.run_mode = 'fixed source' - settings.particles = 30 - settings.random_ray['distance_active'] = 40.0 - settings.random_ray['distance_inactive'] = 40.0 - settings.random_ray['volume_normalized_flux_tallies'] = False - - # This problem needs about 2k iterations to converge, - # but for regression testing we only need a few hundred - # to ensure things are working as expected. With - # only 100 inactive batches, tallies will still be off - # by 3x or more. For validation against MGMC, be sure - # to increase the batch counts. - settings.batches = 125 - settings.inactive = 100 - - ######################################## - # Define the alternative geometry - - pitch = 1.26 - - for material in model.materials: - if material.name == 'Water': - water = material - - # The new geometry replaces two of the fuel pins with - # moderator, reducing k-eff to around 0.84. We also - # add a special universe in the corner of one of the moderator - # regions to use as a domain constraint for the source - moderator_infinite = openmc.Cell(fill=water, name='moderator infinite') - mu = openmc.Universe(cells=[moderator_infinite]) - - moderator_infinite2 = openmc.Cell(fill=water, name='moderator infinite 2') - mu2 = openmc.Universe(cells=[moderator_infinite2]) - - n_sub = 10 - - lattice = openmc.RectLattice() - lattice.lower_left = [-pitch/2.0, -pitch/2.0] - lattice.pitch = [pitch/n_sub, pitch/n_sub] - lattice.universes = [[mu] * n_sub for _ in range(n_sub)] - - lattice2 = openmc.RectLattice() - lattice2.lower_left = [-pitch/2.0, -pitch/2.0] - lattice2.pitch = [pitch/n_sub, pitch/n_sub] - lattice2.universes = [[mu] * n_sub for _ in range(n_sub)] - lattice2.universes[n_sub-1][n_sub-1] = mu2 - - mod_lattice_cell = openmc.Cell(fill=lattice) - mod_lattice_uni = openmc.Universe(cells=[mod_lattice_cell]) - - mod_lattice_cell2 = openmc.Cell(fill=lattice2) - mod_lattice_uni2 = openmc.Universe(cells=[mod_lattice_cell2]) - - lattice2x2 = openmc.RectLattice() - lattice2x2.lower_left = [-pitch, -pitch] - lattice2x2.pitch = [pitch, pitch] - - universes = model.geometry.get_all_universes() - for universe in universes.values(): - if universe.name == 'pincell': - pincell = universe - - lattice2x2.universes = [ - [pincell, mod_lattice_uni], - [mod_lattice_uni, mod_lattice_uni2] - ] - - box = openmc.model.RectangularPrism( - pitch*2, pitch*2, boundary_type='reflective') - - assembly = openmc.Cell(fill=lattice2x2, region=-box, name='assembly') - - root = openmc.Universe(name='root universe', cells=[assembly]) - model.geometry = openmc.Geometry(root) - - ######################################## - # Define the fixed source term - - s = 1.0 / 7.0 - strengths = [s, s, s, s, s, s, s] - midpoints = [2.0e-5, 0.0735, 20.0, 2.0e2, 2.0e3, 0.75e6, 2.0e6] - energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths) - - lower_left_src = [pitch - pitch/10.0, -pitch, -1.0] - upper_right_src = [pitch, -pitch + pitch/10.0, 1.0] - spatial_distribution = openmc.stats.Box( - lower_left_src, upper_right_src, only_fissionable=False) - - settings.source = openmc.IndependentSource( - space=spatial_distribution, - energy=energy_distribution, - constraints={'domains': [mu2]}, - strength=1.0 - ) - - ######################################## - # Run test - - harness = MGXSTestHarness('statepoint.125.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_halton_samples/__init__.py b/tests/regression_tests/random_ray_halton_samples/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_halton_samples/inputs_true.dat b/tests/regression_tests/random_ray_halton_samples/inputs_true.dat deleted file mode 100644 index 1b86d2dae..000000000 --- a/tests/regression_tests/random_ray_halton_samples/inputs_true.dat +++ /dev/null @@ -1,112 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - halton - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_halton_samples/results_true.dat b/tests/regression_tests/random_ray_halton_samples/results_true.dat deleted file mode 100644 index 256f8a744..000000000 --- a/tests/regression_tests/random_ray_halton_samples/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -8.388051E-01 7.383265E-03 -tally 1: -1.065839E+00 -2.274384E-01 -4.060094E-01 -3.300592E-02 -9.881457E-01 -1.955066E-01 -6.038893E-01 -7.306038E-02 -9.244411E-02 -1.712380E-03 -2.249905E-01 -1.014308E-02 -3.594916E-01 -2.614145E-02 -1.194318E-02 -2.882412E-05 -2.906731E-02 -1.707363E-04 -5.032954E-01 -5.161897E-02 -1.707007E-02 -5.933921E-05 -4.154514E-02 -3.514889E-04 -1.513147E+00 -4.652938E-01 -1.810962E-02 -6.665306E-05 -4.407572E-02 -3.948212E-04 -4.347893E+00 -3.798064E+00 -6.851785E-03 -9.430195E-06 -1.695426E-02 -5.773923E-05 -2.809071E+00 -1.578195E+00 -3.954523E-02 -3.127754E-04 -1.099931E-01 -2.419775E-03 -1.600493E+00 -5.123291E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -7.170555E-01 -1.028835E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.869491E-01 -3.041553E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.723683E-01 -6.680970E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.583046E+00 -5.085372E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.872447E+00 -3.013344E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.421670E+00 -1.172938E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.721128E-01 -1.894086E-01 -3.612242E-01 -2.615053E-02 -8.791475E-01 -1.548996E-01 -5.782742E-01 -6.705354E-02 -8.624040E-02 -1.491336E-03 -2.098919E-01 -8.833753E-03 -3.525265E-01 -2.510689E-02 -1.140473E-02 -2.627142E-05 -2.775683E-02 -1.556157E-04 -4.896481E-01 -4.881407E-02 -1.622698E-02 -5.360976E-05 -3.949322E-02 -3.175511E-04 -1.504743E+00 -4.601003E-01 -1.754995E-02 -6.262618E-05 -4.271358E-02 -3.709679E-04 -4.444922E+00 -3.970609E+00 -6.759184E-03 -9.185746E-06 -1.672513E-02 -5.624252E-05 -2.871068E+00 -1.648778E+00 -3.843643E-02 -2.955428E-04 -1.069090E-01 -2.286455E-03 -1.078620E+00 -2.328291E-01 -3.969671E-01 -3.153110E-02 -9.661384E-01 -1.867708E-01 -6.077864E-01 -7.399164E-02 -8.987086E-02 -1.618157E-03 -2.187277E-01 -9.584966E-03 -3.607158E-01 -2.633746E-02 -1.157185E-02 -2.709895E-05 -2.816358E-02 -1.605174E-04 -5.059289E-01 -5.218618E-02 -1.658585E-02 -5.611375E-05 -4.036663E-02 -3.323832E-04 -1.516801E+00 -4.675245E-01 -1.752096E-02 -6.241641E-05 -4.264304E-02 -3.697253E-04 -4.326588E+00 -3.759517E+00 -6.556454E-03 -8.628460E-06 -1.622349E-02 -5.283037E-05 -2.782815E+00 -1.548888E+00 -3.751781E-02 -2.815972E-04 -1.043539E-01 -2.178566E-03 diff --git a/tests/regression_tests/random_ray_halton_samples/test.py b/tests/regression_tests/random_ray_halton_samples/test.py deleted file mode 100644 index 478b65026..000000000 --- a/tests/regression_tests/random_ray_halton_samples/test.py +++ /dev/null @@ -1,19 +0,0 @@ -import os - -from openmc.examples import random_ray_lattice - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - -def test_random_ray_halton_samples(): - model = random_ray_lattice() - model.settings.random_ray['sample_method'] = 'halton' - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_k_eff/__init__.py b/tests/regression_tests/random_ray_k_eff/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_k_eff/inputs_true.dat b/tests/regression_tests/random_ray_k_eff/inputs_true.dat deleted file mode 100644 index 72b783344..000000000 --- a/tests/regression_tests/random_ray_k_eff/inputs_true.dat +++ /dev/null @@ -1,111 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_k_eff/results_true.dat b/tests/regression_tests/random_ray_k_eff/results_true.dat deleted file mode 100644 index ace18df8c..000000000 --- a/tests/regression_tests/random_ray_k_eff/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -8.400321E-01 8.023357E-03 -tally 1: -1.075769E+00 -2.317354E-01 -3.986991E-01 -3.182682E-02 -9.703538E-01 -1.885224E-01 -6.049423E-01 -7.331941E-02 -8.978161E-02 -1.614997E-03 -2.185105E-01 -9.566247E-03 -3.579852E-01 -2.591721E-02 -1.151770E-02 -2.682363E-05 -2.803176E-02 -1.588866E-04 -5.017326E-01 -5.130808E-02 -1.651428E-02 -5.557274E-05 -4.019245E-02 -3.291786E-04 -1.509054E+00 -4.629325E-01 -1.749679E-02 -6.226587E-05 -4.258421E-02 -3.688336E-04 -4.322054E+00 -3.753085E+00 -6.555113E-03 -8.636537E-06 -1.622017E-02 -5.287982E-05 -2.777351E+00 -1.542942E+00 -3.731363E-02 -2.784662E-04 -1.037860E-01 -2.154343E-03 -1.600522E+00 -5.123477E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -7.155116E-01 -1.024445E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.848568E-01 -3.008769E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.697160E-01 -6.624996E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.576480E+00 -5.046890E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.856827E+00 -2.989000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.405807E+00 -1.157889E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.732717E-01 -1.897670E-01 -3.637108E-01 -2.649544E-02 -8.851992E-01 -1.569426E-01 -5.774286E-01 -6.683395E-02 -8.688408E-02 -1.513473E-03 -2.114585E-01 -8.964883E-03 -3.512640E-01 -2.491729E-02 -1.148149E-02 -2.660532E-05 -2.794365E-02 -1.575935E-04 -4.877362E-01 -4.844138E-02 -1.627932E-02 -5.395212E-05 -3.962062E-02 -3.195790E-04 -1.496416E+00 -4.551920E-01 -1.760130E-02 -6.300084E-05 -4.283856E-02 -3.731872E-04 -4.430519E+00 -3.943947E+00 -6.841363E-03 -9.402132E-06 -1.692847E-02 -5.756741E-05 -2.870816E+00 -1.648662E+00 -3.937267E-02 -3.101707E-04 -1.095131E-01 -2.399624E-03 -1.072714E+00 -2.304093E-01 -4.053505E-01 -3.291277E-02 -9.865420E-01 -1.949549E-01 -6.047420E-01 -7.327008E-02 -9.163611E-02 -1.683034E-03 -2.230240E-01 -9.969255E-03 -3.580639E-01 -2.592902E-02 -1.176143E-02 -2.794541E-05 -2.862497E-02 -1.655313E-04 -5.010143E-01 -5.114429E-02 -1.681803E-02 -5.755790E-05 -4.093173E-02 -3.409375E-04 -1.505803E+00 -4.607828E-01 -1.782566E-02 -6.454911E-05 -4.338462E-02 -3.823584E-04 -4.328879E+00 -3.766055E+00 -6.729800E-03 -9.102372E-06 -1.665242E-02 -5.573204E-05 -2.804070E+00 -1.572690E+00 -3.876396E-02 -3.006259E-04 -1.078200E-01 -2.325780E-03 diff --git a/tests/regression_tests/random_ray_k_eff/test.py b/tests/regression_tests/random_ray_k_eff/test.py deleted file mode 100644 index 8dd0dd915..000000000 --- a/tests/regression_tests/random_ray_k_eff/test.py +++ /dev/null @@ -1,19 +0,0 @@ -import os - -from openmc.examples import random_ray_lattice - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_basic(): - model = random_ray_lattice() - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_k_eff_mesh/__init__.py b/tests/regression_tests/random_ray_k_eff_mesh/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_k_eff_mesh/inputs_true.dat b/tests/regression_tests/random_ray_k_eff_mesh/inputs_true.dat deleted file mode 100644 index f6e9c8e3e..000000000 --- a/tests/regression_tests/random_ray_k_eff_mesh/inputs_true.dat +++ /dev/null @@ -1,121 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - - - - - - - - 40 40 - -1.26 -1.26 - 1.26 1.26 - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_k_eff_mesh/results_true.dat b/tests/regression_tests/random_ray_k_eff_mesh/results_true.dat deleted file mode 100644 index 2ae8fad85..000000000 --- a/tests/regression_tests/random_ray_k_eff_mesh/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -8.379203E-01 8.057199E-03 -tally 1: -1.073897E+00 -2.309328E-01 -3.974859E-01 -3.163415E-02 -9.674011E-01 -1.873811E-01 -6.045463E-01 -7.322367E-02 -8.969819E-02 -1.612011E-03 -2.183075E-01 -9.548557E-03 -3.578121E-01 -2.589198E-02 -1.151076E-02 -2.679073E-05 -2.801489E-02 -1.586917E-04 -5.015038E-01 -5.126076E-02 -1.650453E-02 -5.550572E-05 -4.016872E-02 -3.287816E-04 -1.508456E+00 -4.625615E-01 -1.748939E-02 -6.221267E-05 -4.256620E-02 -3.685184E-04 -4.320984E+00 -3.751237E+00 -6.554265E-03 -8.634389E-06 -1.621807E-02 -5.286667E-05 -2.776930E+00 -1.542475E+00 -3.730995E-02 -2.784113E-04 -1.037757E-01 -2.153918E-03 -1.603583E+00 -5.143065E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -7.159242E-01 -1.025623E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.847488E-01 -3.007151E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.695050E-01 -6.620177E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.575716E+00 -5.042003E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.855109E+00 -2.986316E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.405453E+00 -1.157547E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.701818E-01 -1.885724E-01 -3.619962E-01 -2.624740E-02 -8.810264E-01 -1.554734E-01 -5.767221E-01 -6.667165E-02 -8.675429E-02 -1.508976E-03 -2.111426E-01 -8.938242E-03 -3.510185E-01 -2.488161E-02 -1.147307E-02 -2.656498E-05 -2.792316E-02 -1.573545E-04 -4.874578E-01 -4.838573E-02 -1.626869E-02 -5.388082E-05 -3.959473E-02 -3.191567E-04 -1.495984E+00 -4.549294E-01 -1.759493E-02 -6.295564E-05 -4.282306E-02 -3.729194E-04 -4.430601E+00 -3.944093E+00 -6.841763E-03 -9.403281E-06 -1.692946E-02 -5.757445E-05 -2.870670E+00 -1.648496E+00 -3.937215E-02 -3.101637E-04 -1.095116E-01 -2.399569E-03 -1.071187E+00 -2.297540E-01 -4.043214E-01 -3.274592E-02 -9.840375E-01 -1.939666E-01 -6.043491E-01 -7.317500E-02 -9.155169E-02 -1.679939E-03 -2.228185E-01 -9.950920E-03 -3.578809E-01 -2.590208E-02 -1.175437E-02 -2.791136E-05 -2.860779E-02 -1.653296E-04 -5.007414E-01 -5.108824E-02 -1.680608E-02 -5.747571E-05 -4.090264E-02 -3.404506E-04 -1.505100E+00 -4.603562E-01 -1.781573E-02 -6.447733E-05 -4.336044E-02 -3.819332E-04 -4.328647E+00 -3.765700E+00 -6.730396E-03 -9.104085E-06 -1.665389E-02 -5.574253E-05 -2.803934E+00 -1.572540E+00 -3.876306E-02 -3.006136E-04 -1.078175E-01 -2.325685E-03 diff --git a/tests/regression_tests/random_ray_k_eff_mesh/test.py b/tests/regression_tests/random_ray_k_eff_mesh/test.py deleted file mode 100644 index cffdaf8bb..000000000 --- a/tests/regression_tests/random_ray_k_eff_mesh/test.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_lattice - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_k_eff_mesh(): - model = random_ray_lattice() - - # The model already has some geometrical subdivisions - # up to a 10x10 grid in the moderator region. So, we - # increase the resolution 40x40 applied over the full - # 2x2 lattice. - pitch = 1.26 - dim = 40 - mesh = openmc.RegularMesh() - mesh.dimension = (dim, dim) - mesh.lower_left = (-pitch, -pitch) - mesh.upper_right = (pitch, pitch) - - root = model.geometry.root_universe - - model.settings.random_ray['source_region_meshes'] = [(mesh, [root])] - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_linear/__init__.py b/tests/regression_tests/random_ray_linear/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_linear/linear/inputs_true.dat b/tests/regression_tests/random_ray_linear/linear/inputs_true.dat deleted file mode 100644 index 269d9892e..000000000 --- a/tests/regression_tests/random_ray_linear/linear/inputs_true.dat +++ /dev/null @@ -1,112 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 40 - 20 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - linear - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_linear/linear/results_true.dat b/tests/regression_tests/random_ray_linear/linear/results_true.dat deleted file mode 100644 index 77d41f373..000000000 --- a/tests/regression_tests/random_ray_linear/linear/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -1.095967E+00 1.543581E-02 -tally 1: -5.425537E+00 -1.482137E+00 -1.974189E+00 -1.961888E-01 -4.804781E+00 -1.162101E+00 -3.866915E+00 -7.496163E-01 -5.662059E-01 -1.607180E-02 -1.378032E+00 -9.519943E-02 -2.904666E+00 -4.220197E-01 -9.289413E-02 -4.316514E-04 -2.260857E-01 -2.556836E-03 -3.717829E+00 -6.912286E-01 -1.220682E-01 -7.451721E-04 -2.970897E-01 -4.413940E-03 -9.665773E+00 -4.671720E+00 -1.120617E-01 -6.279393E-04 -2.727390E-01 -3.719615E-03 -2.117656E+01 -2.242614E+01 -3.204951E-02 -5.138445E-05 -7.930426E-02 -3.146169E-04 -1.133784E+01 -6.432186E+00 -1.537206E-01 -1.185474E-03 -4.275660E-01 -9.171376E-03 -8.917756E+00 -4.009380E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.736166E+00 -1.124858E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.057755E+00 -4.676344E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.048156E+00 -8.195089E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.707791E+00 -4.712281E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.874344E+01 -1.756722E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.595520E+00 -4.608366E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.701002E+00 -1.113069E+00 -1.733152E+00 -1.513360E-01 -4.218145E+00 -8.964208E-01 -3.641849E+00 -6.649342E-01 -5.413112E-01 -1.469131E-02 -1.317443E+00 -8.702223E-02 -2.858878E+00 -4.088359E-01 -9.288202E-02 -4.315389E-04 -2.260562E-01 -2.556170E-03 -3.649312E+00 -6.660131E-01 -1.216639E-01 -7.402611E-04 -2.961057E-01 -4.384849E-03 -9.664912E+00 -4.671059E+00 -1.138118E-01 -6.477188E-04 -2.769985E-01 -3.836780E-03 -2.157464E+01 -2.327600E+01 -3.312018E-02 -5.486221E-05 -8.195357E-02 -3.359106E-04 -1.145052E+01 -6.557893E+00 -1.570084E-01 -1.234420E-03 -4.367109E-01 -9.550040E-03 -5.371474E+00 -1.451702E+00 -1.994382E+00 -2.000414E-01 -4.853928E+00 -1.184921E+00 -3.839778E+00 -7.388780E-01 -5.741437E-01 -1.651648E-02 -1.397351E+00 -9.783345E-02 -2.890296E+00 -4.178220E-01 -9.447974E-02 -4.464346E-04 -2.299448E-01 -2.644403E-03 -3.695989E+00 -6.831063E-01 -1.240303E-01 -7.692555E-04 -3.018649E-01 -4.556594E-03 -9.622545E+00 -4.630042E+00 -1.140770E-01 -6.507108E-04 -2.776440E-01 -3.854503E-03 -2.115266E+01 -2.237450E+01 -3.276343E-02 -5.368742E-05 -8.107083E-02 -3.287176E-04 -1.136109E+01 -6.456700E+00 -1.576636E-01 -1.245524E-03 -4.385334E-01 -9.635950E-03 diff --git a/tests/regression_tests/random_ray_linear/linear_xy/inputs_true.dat b/tests/regression_tests/random_ray_linear/linear_xy/inputs_true.dat deleted file mode 100644 index 217e95516..000000000 --- a/tests/regression_tests/random_ray_linear/linear_xy/inputs_true.dat +++ /dev/null @@ -1,112 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.126 0.126 - 10 10 - -0.63 -0.63 - -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 - - - 1.26 1.26 - 2 2 - -1.26 -1.26 - -2 2 -2 5 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 40 - 20 - multi-group - - 100.0 - 20.0 - - - - -1.26 -1.26 -1 1.26 1.26 1 - - - - true - linear_xy - - - - - 2 2 - -1.26 -1.26 - 1.26 1.26 - - - 1 - - - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 - - - 1 2 - flux fission nu-fission - analog - - - diff --git a/tests/regression_tests/random_ray_linear/linear_xy/results_true.dat b/tests/regression_tests/random_ray_linear/linear_xy/results_true.dat deleted file mode 100644 index 052608b42..000000000 --- a/tests/regression_tests/random_ray_linear/linear_xy/results_true.dat +++ /dev/null @@ -1,171 +0,0 @@ -k-combined: -1.104727E+00 1.593303E-02 -tally 1: -5.465547E+00 -1.504031E+00 -2.005120E+00 -2.024490E-01 -4.880060E+00 -1.199182E+00 -3.883466E+00 -7.559482E-01 -5.706123E-01 -1.632280E-02 -1.388756E+00 -9.668619E-02 -2.907681E+00 -4.228621E-01 -9.306046E-02 -4.331768E-04 -2.264905E-01 -2.565871E-03 -3.727441E+00 -6.948089E-01 -1.227027E-01 -7.529631E-04 -2.986338E-01 -4.460088E-03 -9.674219E+00 -4.679846E+00 -1.122358E-01 -6.299070E-04 -2.731629E-01 -3.731271E-03 -2.103996E+01 -2.213497E+01 -3.167421E-02 -5.016895E-05 -7.837561E-02 -3.071747E-04 -1.120119E+01 -6.274853E+00 -1.494396E-01 -1.117486E-03 -4.156586E-01 -8.645390E-03 -8.910289E+00 -4.001626E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.741600E+00 -1.127303E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.068401E+00 -4.708885E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.065045E+00 -8.263510E-01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.750251E+00 -4.753623E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.880773E+01 -1.768690E+01 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.642921E+00 -4.650165E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.723189E+00 -1.123179E+00 -1.746692E+00 -1.536860E-01 -4.251098E+00 -9.103405E-01 -3.651202E+00 -6.682179E-01 -5.431675E-01 -1.479058E-02 -1.321961E+00 -8.761024E-02 -2.860513E+00 -4.092640E-01 -9.290237E-02 -4.316867E-04 -2.261058E-01 -2.557045E-03 -3.655900E+00 -6.684112E-01 -1.219969E-01 -7.443277E-04 -2.969160E-01 -4.408937E-03 -9.672316E+00 -4.678082E+00 -1.138719E-01 -6.483917E-04 -2.771448E-01 -3.840766E-03 -2.148514E+01 -2.308100E+01 -3.286501E-02 -5.400774E-05 -8.132216E-02 -3.306788E-04 -1.137571E+01 -6.471140E+00 -1.544841E-01 -1.193653E-03 -4.296897E-01 -9.234647E-03 -5.408307E+00 -1.472183E+00 -2.019332E+00 -2.052123E-01 -4.914651E+00 -1.215551E+00 -3.859737E+00 -7.466141E-01 -5.785840E-01 -1.677554E-02 -1.408158E+00 -9.936796E-02 -2.901397E+00 -4.210234E-01 -9.492573E-02 -4.506531E-04 -2.310302E-01 -2.669390E-03 -3.714401E+00 -6.899411E-01 -1.249118E-01 -7.802521E-04 -3.040104E-01 -4.621732E-03 -9.663183E+00 -4.669215E+00 -1.146768E-01 -6.575767E-04 -2.791038E-01 -3.895173E-03 -2.112461E+01 -2.231346E+01 -3.262864E-02 -5.323508E-05 -8.073730E-02 -3.259479E-04 -1.128817E+01 -6.372070E+00 -1.551272E-01 -1.203670E-03 -4.314785E-01 -9.312148E-03 diff --git a/tests/regression_tests/random_ray_linear/test.py b/tests/regression_tests/random_ray_linear/test.py deleted file mode 100644 index 510c57de8..000000000 --- a/tests/regression_tests/random_ray_linear/test.py +++ /dev/null @@ -1,28 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_lattice -from openmc.utility_funcs import change_directory -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("shape", ["linear", "linear_xy"]) -def test_random_ray_source(shape): - with change_directory(shape): - openmc.reset_auto_ids() - model = random_ray_lattice() - model.settings.random_ray['source_shape'] = shape - model.settings.inactive = 20 - model.settings.batches = 40 - harness = MGXSTestHarness('statepoint.40.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_low_density/__init__.py b/tests/regression_tests/random_ray_low_density/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_low_density/inputs_true.dat b/tests/regression_tests/random_ray_low_density/inputs_true.dat deleted file mode 100644 index 20deba664..000000000 --- a/tests/regression_tests/random_ray_low_density/inputs_true.dat +++ /dev/null @@ -1,246 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_low_density/results_true.dat b/tests/regression_tests/random_ray_low_density/results_true.dat deleted file mode 100644 index a4b3ee1bc..000000000 --- a/tests/regression_tests/random_ray_low_density/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.973607E-01 -7.155477E-02 -tally 2: -3.206216E-02 -2.063375E-04 -tally 3: -2.096415E-03 -8.804963E-07 diff --git a/tests/regression_tests/random_ray_low_density/test.py b/tests/regression_tests/random_ray_low_density/test.py deleted file mode 100644 index 1b4ffb781..000000000 --- a/tests/regression_tests/random_ray_low_density/test.py +++ /dev/null @@ -1,60 +0,0 @@ -import os - -import numpy as np -import openmc -from openmc.examples import random_ray_three_region_cube - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_low_density(): - model = random_ray_three_region_cube() - - # Rebuild the MGXS library to have a material with very - # low macroscopic cross sections - ebins = [1e-5, 20.0e6] - groups = openmc.mgxs.EnergyGroups(group_edges=ebins) - - void_sigma_a = 4.0e-6 - void_sigma_s = 3.0e-4 - void_mat_data = openmc.XSdata('void', groups) - void_mat_data.order = 0 - void_mat_data.set_total([void_sigma_a + void_sigma_s]) - void_mat_data.set_absorption([void_sigma_a]) - void_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[void_sigma_s]]]), 0, 3)) - - absorber_sigma_a = 0.75 - absorber_sigma_s = 0.25 - absorber_mat_data = openmc.XSdata('absorber', groups) - absorber_mat_data.order = 0 - absorber_mat_data.set_total([absorber_sigma_a + absorber_sigma_s]) - absorber_mat_data.set_absorption([absorber_sigma_a]) - absorber_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[absorber_sigma_s]]]), 0, 3)) - - multiplier = 0.0000001 - source_sigma_a = void_sigma_a * multiplier - source_sigma_s = void_sigma_s * multiplier - source_mat_data = openmc.XSdata('source', groups) - source_mat_data.order = 0 - source_mat_data.set_total([source_sigma_a + source_sigma_s]) - source_mat_data.set_absorption([source_sigma_a]) - source_mat_data.set_scatter_matrix( - np.rollaxis(np.array([[[source_sigma_s]]]), 0, 3)) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - mg_cross_sections_file.add_xsdatas( - [source_mat_data, void_mat_data, absorber_mat_data]) - mg_cross_sections_file.export_to_hdf5() - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_point_source_locator/__init__.py b/tests/regression_tests/random_ray_point_source_locator/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat b/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat deleted file mode 100644 index b4bd263f5..000000000 --- a/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat +++ /dev/null @@ -1,255 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 30 - 15 - - - 2.5 2.5 2.5 - - - 100.0 1.0 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - - - - 30 30 30 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_point_source_locator/results_true.dat b/tests/regression_tests/random_ray_point_source_locator/results_true.dat deleted file mode 100644 index 8c6f358dd..000000000 --- a/tests/regression_tests/random_ray_point_source_locator/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.633923E+00 -2.948228E+00 -tally 2: -1.440456E-01 -3.293984E-03 -tally 3: -9.425207E-03 -1.089748E-05 diff --git a/tests/regression_tests/random_ray_point_source_locator/test.py b/tests/regression_tests/random_ray_point_source_locator/test.py deleted file mode 100644 index fd3d8a18f..000000000 --- a/tests/regression_tests/random_ray_point_source_locator/test.py +++ /dev/null @@ -1,44 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_three_region_cube - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_point_source_locator(): - model = random_ray_three_region_cube() - - # Overlay subdivided SR mesh to reduce resolution from 2.5cm -> 1cm - width = 30.0 - mesh = openmc.RegularMesh() - mesh.dimension = (30, 30, 30) - mesh.lower_left = (0.0, 0.0, 0.0) - mesh.upper_right = (width, width, width) - model.settings.random_ray['source_region_meshes'] = [ - (mesh, [model.geometry.root_universe]), - ] - - # Define a point source - strengths = [1.0] - midpoints = [100.0] - energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths) - spatial_distribution = openmc.stats.Point([2.5, 2.5, 2.5]) - source = openmc.IndependentSource( - energy=energy_distribution, space=spatial_distribution, strength=3.14) - model.settings.source = [source] - - # Settings - model.settings.inactive = 15 - model.settings.batches = 30 - - harness = MGXSTestHarness('statepoint.30.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_s2/__init__.py b/tests/regression_tests/random_ray_s2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_s2/inputs_true.dat b/tests/regression_tests/random_ray_s2/inputs_true.dat deleted file mode 100644 index c0dc6292f..000000000 --- a/tests/regression_tests/random_ray_s2/inputs_true.dat +++ /dev/null @@ -1,71 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - fixed source - 100 - 30 - 10 - - - 0.0 -5.0 -5.0 40.0 5.0 5.0 - - - 1000.0 1.0 - - - material - 1 - - - multi-group - - 100.0 - 400.0 - - - - 0.0 -5.0 -5.0 40.0 5.0 5.0 - - - - flat - s2 - - - - - - - - 10 1 1 - 0.0 -5.0 -5.0 - 40.0 5.0 5.0 - - - - - 1 - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_s2/results_true.dat b/tests/regression_tests/random_ray_s2/results_true.dat deleted file mode 100644 index 5fb6f7904..000000000 --- a/tests/regression_tests/random_ray_s2/results_true.dat +++ /dev/null @@ -1,21 +0,0 @@ -tally 1: -1.153280E+01 -6.650271E+00 -1.413926E+01 -9.995935E+00 -1.579543E+01 -1.247479E+01 -1.676986E+01 -1.406141E+01 -1.722054E+01 -1.482734E+01 -1.722054E+01 -1.482734E+01 -1.676986E+01 -1.406141E+01 -1.579543E+01 -1.247479E+01 -1.413926E+01 -9.995935E+00 -1.153280E+01 -6.650271E+00 diff --git a/tests/regression_tests/random_ray_s2/test.py b/tests/regression_tests/random_ray_s2/test.py deleted file mode 100644 index 712d9c124..000000000 --- a/tests/regression_tests/random_ray_s2/test.py +++ /dev/null @@ -1,82 +0,0 @@ -import os - -import openmc -import openmc.model -import numpy as np - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_s2(): - NUM_SOURCE_REGIONS = 10 - L = 40.0 - - # Make the simple MGXS library and material. - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 20.0e6]) - - domain_mat_data = openmc.XSdata('domain', groups) - domain_mat_data.order = 0 - domain_mat_data.set_total([0.1]) - domain_mat_data.set_absorption([0.1]) - domain_mat_data.set_scatter_matrix(np.rollaxis(np.array([[[0.0]]]), 0, 3)) - mg_cross_sections_file = openmc.MGXSLibrary(groups) - mg_cross_sections_file.add_xsdatas([domain_mat_data]) - mg_cross_sections_file.export_to_hdf5() - - domain_data = openmc.Macroscopic('domain') - domain_mat = openmc.Material(name='domain') - domain_mat.set_density('macro', 1.0) - domain_mat.add_macroscopic(domain_data) - - container = openmc.model.RectangularPrism(width=10.0, height=10.0, axis='x', - origin=(0.0, 0.0), boundary_type='reflective') - left = openmc.XPlane(x0 = 0.0, boundary_type='vacuum') - right = openmc.XPlane(x0 = L, boundary_type='vacuum') - cell = [openmc.Cell(region = +left & -right & -container, fill = domain_mat)] - - model = openmc.model.Model() - model.geometry = openmc.Geometry(root=openmc.Universe(cells=cell)) - model.materials = openmc.Materials([domain_mat]) - model.materials.cross_sections = './mgxs.h5' - - mesh = openmc.RegularMesh() - mesh.dimension = (NUM_SOURCE_REGIONS, 1, 1) - mesh.lower_left = (0.0, -5.0, -5.0) - mesh.upper_right = (L, 5.0, 5.0) - - tally = openmc.Tally(name="LR") - tally.filters = [openmc.MeshFilter(mesh)] - tally.scores = ['flux'] - tally.estimator = 'tracklength' - model.tallies.append(tally) - - uniform_dist = openmc.stats.Box((0.0, -5.0, -5.0), (L, 5.0, 5.0)) - model.settings.source = [ - openmc.IndependentSource(space=uniform_dist, - energy=openmc.stats.Discrete(x = 1e3, p = 1.0), - constraints={'domains' : [domain_mat]}) - ] - model.settings.energy_mode = "multi-group" - model.settings.batches = 30 - model.settings.inactive = 10 - model.settings.particles = 100 - model.settings.run_mode = 'fixed source' - model.settings.random_ray['distance_inactive'] = 100.0 - model.settings.random_ray['distance_active'] = 400.0 - model.settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) - model.settings.random_ray['source_shape'] = 'flat' - model.settings.random_ray['sample_method'] = 's2' - model.settings.random_ray['source_region_meshes'] = [(mesh, [model.geometry.root_universe])] - - model.export_to_model_xml() - - harness = MGXSTestHarness('statepoint.30.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_void/__init__.py b/tests/regression_tests/random_ray_void/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_void/flat/inputs_true.dat b/tests/regression_tests/random_ray_void/flat/inputs_true.dat deleted file mode 100644 index 66390c766..000000000 --- a/tests/regression_tests/random_ray_void/flat/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - flat - - - - - 1 - - - 2 - - - 3 - - - 6 - flux - tracklength - - - 5 - flux - tracklength - - - 4 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_void/flat/results_true.dat b/tests/regression_tests/random_ray_void/flat/results_true.dat deleted file mode 100644 index bd2f2d3b4..000000000 --- a/tests/regression_tests/random_ray_void/flat/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.354630E+00 -2.777456E-01 -tally 2: -1.056204E-01 -5.741779E-04 -tally 3: -7.286803E-03 -2.706427E-06 diff --git a/tests/regression_tests/random_ray_void/linear/inputs_true.dat b/tests/regression_tests/random_ray_void/linear/inputs_true.dat deleted file mode 100644 index 45228a039..000000000 --- a/tests/regression_tests/random_ray_void/linear/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - linear - - - - - 1 - - - 2 - - - 3 - - - 6 - flux - tracklength - - - 5 - flux - tracklength - - - 4 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_void/linear/results_true.dat b/tests/regression_tests/random_ray_void/linear/results_true.dat deleted file mode 100644 index befa507a5..000000000 --- a/tests/regression_tests/random_ray_void/linear/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.356818E+00 -2.782542E-01 -tally 2: -1.082843E-01 -6.028734E-04 -tally 3: -7.302705E-03 -2.718076E-06 diff --git a/tests/regression_tests/random_ray_void/test.py b/tests/regression_tests/random_ray_void/test.py deleted file mode 100644 index b48a7794d..000000000 --- a/tests/regression_tests/random_ray_void/test.py +++ /dev/null @@ -1,72 +0,0 @@ -import os - -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("shape", ["flat", "linear"]) -def test_random_ray_void(shape): - with change_directory(shape): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - - # There is some different logic for void depending on linear - # vs. flat, so we test both - model.settings.random_ray['source_shape'] = shape - - # As we are testing linear sources, need to have more than - # 10 inactive batches so the moments start getting computed - model.settings.inactive = 20 - model.settings.batches = 40 - - # Begin by getting handles to the cells, and setting the - # source and void areas to have no fill. We leave the absorber - # as solid. - absorber_cell = model.geometry.get_cells_by_name( - 'infinite absorber region', matching=True)[0] - void_cell = model.geometry.get_cells_by_name( - 'infinite void region', matching=True)[0] - source_cell = model.geometry.get_cells_by_name( - 'infinite source region', matching=True)[0] - - void_cell.fill = None - source_cell.fill = None - - # We also need to redefine all three tallies to use cell - # filters instead of material ones - estimator = 'tracklength' - absorber_filter = openmc.CellFilter(absorber_cell) - absorber_tally = openmc.Tally(name="Absorber Tally") - absorber_tally.filters = [absorber_filter] - absorber_tally.scores = ['flux'] - absorber_tally.estimator = estimator - - void_filter = openmc.CellFilter(void_cell) - void_tally = openmc.Tally(name="Void Tally") - void_tally.filters = [void_filter] - void_tally.scores = ['flux'] - void_tally.estimator = estimator - - source_filter = openmc.CellFilter(source_cell) - source_tally = openmc.Tally(name="Source Tally") - source_tally.filters = [source_filter] - source_tally.scores = ['flux'] - source_tally.estimator = estimator - - tallies = openmc.Tallies([source_tally, void_tally, absorber_tally]) - model.tallies = tallies - - harness = MGXSTestHarness('statepoint.40.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_volume_estimator/__init__.py b/tests/regression_tests/random_ray_volume_estimator/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat deleted file mode 100644 index 4d1af46b1..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - hybrid - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_volume_estimator/hybrid/results_true.dat b/tests/regression_tests/random_ray_volume_estimator/hybrid/results_true.dat deleted file mode 100644 index 6da51a711..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/hybrid/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.934460E-01 -7.058894E-02 -tally 2: -3.206214E-02 -2.063370E-04 -tally 3: -2.096411E-03 -8.804924E-07 diff --git a/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat deleted file mode 100644 index a268d55d0..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - naive - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_volume_estimator/naive/results_true.dat b/tests/regression_tests/random_ray_volume_estimator/naive/results_true.dat deleted file mode 100644 index f8d6d10b0..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/naive/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -5.935538E-01 -7.061433E-02 -tally 2: -3.263210E-02 -2.134164E-04 -tally 3: -2.107977E-03 -8.905227E-07 diff --git a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat deleted file mode 100644 index 777ccaea5..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat +++ /dev/null @@ -1,247 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - simulation_averaged - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/results_true.dat b/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/results_true.dat deleted file mode 100644 index 5f2975860..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: --5.745886E+02 -9.758367E+04 -tally 2: -2.971927E-02 -1.827222E-04 -tally 3: -1.978393E-03 -7.951531E-07 diff --git a/tests/regression_tests/random_ray_volume_estimator/test.py b/tests/regression_tests/random_ray_volume_estimator/test.py deleted file mode 100644 index fba4bbbbe..000000000 --- a/tests/regression_tests/random_ray_volume_estimator/test.py +++ /dev/null @@ -1,30 +0,0 @@ -import os - -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("estimator", ["hybrid", - "simulation_averaged", - "naive" - ]) -def test_random_ray_volume_estimator(estimator): - with change_directory(estimator): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - model.settings.random_ray['volume_estimator'] = estimator - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/__init__.py b/tests/regression_tests/random_ray_volume_estimator_linear/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat deleted file mode 100644 index dd11567f6..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat +++ /dev/null @@ -1,248 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - linear - hybrid - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/results_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/results_true.dat deleted file mode 100644 index e90d6bfdc..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.339086E+00 -2.747305E-01 -tally 2: -1.089827E-01 -6.069324E-04 -tally 3: -7.300831E-03 -2.715940E-06 diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat deleted file mode 100644 index 6933fba43..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat +++ /dev/null @@ -1,248 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - linear - naive - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/naive/results_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/naive/results_true.dat deleted file mode 100644 index 5258ffd9c..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/naive/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.339567E+00 -2.748423E-01 -tally 2: -1.085878E-01 -6.024509E-04 -tally 3: -7.299803E-03 -2.741867E-06 diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat deleted file mode 100644 index 3ccab1d21..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat +++ /dev/null @@ -1,248 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 40 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - linear - simulation_averaged - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/results_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/results_true.dat deleted file mode 100644 index 1e8aa9fb7..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/results_true.dat +++ /dev/null @@ -1,9 +0,0 @@ -tally 1: -2.670850E+02 -4.432939E+05 -tally 2: -1.116994E-01 -6.491358E-04 -tally 3: -7.564527E-03 -2.947794E-06 diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/test.py b/tests/regression_tests/random_ray_volume_estimator_linear/test.py deleted file mode 100644 index 94a14f3ad..000000000 --- a/tests/regression_tests/random_ray_volume_estimator_linear/test.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import TolerantPyAPITestHarness - - -class MGXSTestHarness(TolerantPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("estimator", ["hybrid", - "simulation_averaged", - "naive" - ]) -def test_random_ray_volume_estimator_linear(estimator): - with change_directory(estimator): - openmc.reset_auto_ids() - model = random_ray_three_region_cube() - model.settings.random_ray['source_shape'] = 'linear' - model.settings.random_ray['volume_estimator'] = estimator - model.settings.inactive = 20 - model.settings.batches = 40 - harness = MGXSTestHarness('statepoint.40.h5', model) - harness.main() diff --git a/tests/regression_tests/reflective_plane/results_true.dat b/tests/regression_tests/reflective_plane/results_true.dat index a4d6edb67..a55747acc 100644 --- a/tests/regression_tests/reflective_plane/results_true.dat +++ b/tests/regression_tests/reflective_plane/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.279066E+00 4.793565E-03 +2.275423E+00 4.746681E-03 diff --git a/tests/regression_tests/resonance_scattering/inputs_true.dat b/tests/regression_tests/resonance_scattering/inputs_true.dat index ebe6a5dbe..57a5e1a4b 100644 --- a/tests/regression_tests/resonance_scattering/inputs_true.dat +++ b/tests/regression_tests/resonance_scattering/inputs_true.dat @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - -4 -4 -4 4 4 4 - - - - true - rvs - 1.0 - 210.0 - U238 U235 Pu239 - - - + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -4 -4 -4 4 4 4 + + + + true + rvs + 1.0 + 210.0 + U238 U235 Pu239 + + diff --git a/tests/regression_tests/resonance_scattering/results_true.dat b/tests/regression_tests/resonance_scattering/results_true.dat index 72f0933b8..2535885fb 100644 --- a/tests/regression_tests/resonance_scattering/results_true.dat +++ b/tests/regression_tests/resonance_scattering/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.462428E+00 1.828903E-02 +1.463226E+00 1.142843E-02 diff --git a/tests/regression_tests/resonance_scattering/test.py b/tests/regression_tests/resonance_scattering/test.py index 24629b12b..e77dd9258 100644 --- a/tests/regression_tests/resonance_scattering/test.py +++ b/tests/regression_tests/resonance_scattering/test.py @@ -4,8 +4,7 @@ from tests.testing_harness import PyAPITestHarness class ResonanceScatteringTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): # Materials mat = openmc.Material(material_id=1) mat.set_density('g/cc', 1.0) @@ -14,13 +13,15 @@ class ResonanceScatteringTestHarness(PyAPITestHarness): mat.add_nuclide('Pu239', 0.02) mat.add_nuclide('H1', 20.0) - self._model.materials = openmc.Materials([mat]) + mats_file = openmc.Materials([mat]) + mats_file.export_to_xml() # Geometry dumb_surface = openmc.XPlane(100, boundary_type='reflective') c1 = openmc.Cell(cell_id=1, fill=mat, region=-dumb_surface) root_univ = openmc.Universe(universe_id=0, cells=[c1]) - self._model.geometry = openmc.Geometry(root_univ) + geometry = openmc.Geometry(root_univ) + geometry.export_to_xml() # Resonance elastic scattering settings res_scat_settings = { @@ -35,13 +36,12 @@ class ResonanceScatteringTestHarness(PyAPITestHarness): settings.batches = 10 settings.inactive = 5 settings.particles = 1000 - settings.source = openmc.IndependentSource( + settings.source = openmc.source.Source( space=openmc.stats.Box([-4, -4, -4], [4, 4, 4])) settings.resonance_scattering = res_scat_settings - self._model.settings = settings + settings.export_to_xml() def test_resonance_scattering(): - harness = ResonanceScatteringTestHarness('statepoint.10.h5', - model=openmc.Model()) + harness = ResonanceScatteringTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/rotation/results_true.dat b/tests/regression_tests/rotation/results_true.dat index 6db3d329a..f4a3cfccc 100644 --- a/tests/regression_tests/rotation/results_true.dat +++ b/tests/regression_tests/rotation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.459219E-01 1.899168E-02 +4.132181E-01 1.130226E-02 diff --git a/tests/regression_tests/salphabeta/inputs_true.dat b/tests/regression_tests/salphabeta/inputs_true.dat index 56f4be375..29d8065cf 100644 --- a/tests/regression_tests/salphabeta/inputs_true.dat +++ b/tests/regression_tests/salphabeta/inputs_true.dat @@ -1,60 +1,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 400 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 400 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + diff --git a/tests/regression_tests/salphabeta/results_true.dat b/tests/regression_tests/salphabeta/results_true.dat index 75a81075e..1c22db3a0 100644 --- a/tests/regression_tests/salphabeta/results_true.dat +++ b/tests/regression_tests/salphabeta/results_true.dat @@ -1,2 +1,2 @@ k-combined: -8.628529E-01 3.120924E-02 +8.214164E-01 2.262776E-02 diff --git a/tests/regression_tests/salphabeta/test.py b/tests/regression_tests/salphabeta/test.py index 11bf3bc84..fd0486118 100644 --- a/tests/regression_tests/salphabeta/test.py +++ b/tests/regression_tests/salphabeta/test.py @@ -67,7 +67,7 @@ def make_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 400 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + model.settings.source = openmc.Source(space=openmc.stats.Box( [-4, -4, -4], [4, 4, 4])) return model diff --git a/tests/regression_tests/score_current/inputs_true.dat b/tests/regression_tests/score_current/inputs_true.dat index 42c2d3df2..2b81f508f 100644 --- a/tests/regression_tests/score_current/inputs_true.dat +++ b/tests/regression_tests/score_current/inputs_true.dat @@ -1,54 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 3 3 3 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - 1 - - - 0.0 0.253 20000000.0 - - - 1 - current - - - 1 2 - current - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + + 3 3 3 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + 1 + + + 0.0 0.253 20000000.0 + + + 1 + current + + + 1 2 + current + + diff --git a/tests/regression_tests/score_current/results_true.dat b/tests/regression_tests/score_current/results_true.dat index 6bb74445c..679346695 100644 --- a/tests/regression_tests/score_current/results_true.dat +++ b/tests/regression_tests/score_current/results_true.dat @@ -1,652 +1,652 @@ k-combined: -7.729082E-01 3.775399E-02 +7.952381E-01 3.714273E-02 tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.200000E-01 -2.924000E-03 -1.740000E-01 -6.270000E-03 +1.400000E-01 +4.016000E-03 +1.760000E-01 +6.368000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.200000E-01 -3.044000E-03 -1.510000E-01 -4.615000E-03 -1.710000E-01 -6.067000E-03 -0.000000E+00 -0.000000E+00 -6.500000E-02 -9.390000E-04 -1.410000E-01 -4.001000E-03 -1.740000E-01 -6.270000E-03 -1.200000E-01 -2.924000E-03 -1.830000E-01 -6.879000E-03 -1.310000E-01 -3.541000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.750000E-01 -6.659000E-03 -2.820000E-01 -1.605400E-02 -1.980000E-01 -7.932000E-03 -0.000000E+00 -0.000000E+00 -9.400000E-02 -1.912000E-03 -2.200000E-01 -9.958000E-03 -1.310000E-01 -3.541000E-03 -1.830000E-01 -6.879000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.110000E-01 -2.639000E-03 -1.360000E-01 -3.890000E-03 -1.770000E-01 -6.551000E-03 +1.140000E-01 +2.714000E-03 +1.590000E-01 +5.517000E-03 +1.800000E-01 +6.524000E-03 0.000000E+00 0.000000E+00 6.700000E-02 -9.310000E-04 +9.270000E-04 1.570000E-01 -4.975000E-03 +5.131000E-03 +1.760000E-01 +6.368000E-03 +1.400000E-01 +4.016000E-03 +1.570000E-01 +5.019000E-03 +1.210000E-01 +2.997000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.480000E-01 -4.910000E-03 -2.720000E-01 -1.490600E-02 -1.510000E-01 -4.615000E-03 -1.200000E-01 -3.044000E-03 -1.800000E-01 -6.720000E-03 -1.050000E-01 -2.285000E-03 -1.790000E-01 -6.499000E-03 +1.780000E-01 +6.838000E-03 +2.440000E-01 +1.203200E-02 +2.120000E-01 +9.028000E-03 0.000000E+00 0.000000E+00 -9.300000E-02 -1.927000E-03 -2.160000E-01 -9.418000E-03 -2.720000E-01 -1.490600E-02 -1.480000E-01 -4.910000E-03 -2.680000E-01 -1.445800E-02 -1.480000E-01 -4.488000E-03 -2.820000E-01 -1.605400E-02 -1.750000E-01 -6.659000E-03 -2.510000E-01 -1.283100E-02 -1.870000E-01 -7.731000E-03 -2.340000E-01 -1.105000E-02 -0.000000E+00 -0.000000E+00 -2.110000E-01 -9.215000E-03 -5.470000E-01 -7.228300E-02 -1.480000E-01 -4.488000E-03 -2.680000E-01 -1.445800E-02 +8.800000E-02 +1.644000E-03 +2.360000E-01 +1.139000E-02 +1.210000E-01 +2.997000E-03 +1.570000E-01 +5.019000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.360000E-01 -3.890000E-03 -1.110000E-01 -2.639000E-03 -1.540000E-01 -4.804000E-03 -1.280000E-01 -3.302000E-03 -2.200000E-01 -9.834000E-03 -0.000000E+00 -0.000000E+00 -9.900000E-02 -2.127000E-03 -1.860000E-01 -7.198000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.430000E-01 -4.337000E-03 -1.580000E-01 -5.104000E-03 -1.050000E-01 -2.285000E-03 -1.800000E-01 -6.720000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.860000E-01 -7.178000E-03 -0.000000E+00 -0.000000E+00 -7.000000E-02 -1.020000E-03 -1.610000E-01 -5.237000E-03 -1.580000E-01 -5.104000E-03 -1.430000E-01 -4.337000E-03 -1.580000E-01 -5.254000E-03 -1.230000E-01 -3.091000E-03 -1.870000E-01 -7.731000E-03 -2.510000E-01 -1.283100E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.980000E-01 -7.934000E-03 -0.000000E+00 -0.000000E+00 -9.500000E-02 -1.949000E-03 -2.150000E-01 -9.289000E-03 -1.230000E-01 -3.091000E-03 -1.580000E-01 -5.254000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.280000E-01 -3.302000E-03 -1.540000E-01 -4.804000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.070000E-01 +2.375000E-03 +1.490000E-01 +4.621000E-03 1.640000E-01 -5.424000E-03 +5.476000E-03 +0.000000E+00 +0.000000E+00 +5.800000E-02 +7.240000E-04 +1.290000E-01 +3.357000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.470000E-01 +4.583000E-03 +2.610000E-01 +1.376900E-02 +1.590000E-01 +5.517000E-03 +1.140000E-01 +2.714000E-03 +1.630000E-01 +5.645000E-03 +1.090000E-01 +2.419000E-03 +1.820000E-01 +6.750000E-03 +0.000000E+00 +0.000000E+00 +1.060000E-01 +2.530000E-03 +2.230000E-01 +1.002300E-02 +2.610000E-01 +1.376900E-02 +1.470000E-01 +4.583000E-03 +2.820000E-01 +1.613400E-02 +1.800000E-01 +6.690000E-03 +2.440000E-01 +1.203200E-02 +1.780000E-01 +6.838000E-03 +2.870000E-01 +1.696700E-02 +1.800000E-01 +6.556000E-03 +2.430000E-01 +1.211900E-02 +0.000000E+00 +0.000000E+00 +2.130000E-01 +9.451000E-03 +5.570000E-01 +7.415500E-02 +1.800000E-01 +6.690000E-03 +2.820000E-01 +1.613400E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.490000E-01 +4.621000E-03 +1.070000E-01 +2.375000E-03 +1.500000E-01 +4.604000E-03 +1.100000E-01 +2.552000E-03 +1.800000E-01 +6.518000E-03 +0.000000E+00 +0.000000E+00 +1.050000E-01 +2.345000E-03 +2.150000E-01 +9.355000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.340000E-01 +3.818000E-03 +1.690000E-01 +5.911000E-03 +1.090000E-01 +2.419000E-03 +1.630000E-01 +5.645000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.860000E-01 +6.998000E-03 +0.000000E+00 +0.000000E+00 +7.200000E-02 +1.090000E-03 +1.720000E-01 +6.062000E-03 +1.690000E-01 +5.911000E-03 +1.340000E-01 +3.818000E-03 +1.600000E-01 +5.454000E-03 +1.060000E-01 +2.328000E-03 +1.800000E-01 +6.556000E-03 +2.870000E-01 +1.696700E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.060000E-01 +8.670000E-03 +0.000000E+00 +0.000000E+00 +1.100000E-01 +2.558000E-03 +2.340000E-01 +1.113000E-02 +1.060000E-01 +2.328000E-03 +1.600000E-01 +5.454000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-01 +2.552000E-03 +1.500000E-01 +4.604000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.730000E-01 +6.077000E-03 0.000000E+00 0.000000E+00 6.200000E-02 -8.020000E-04 -1.500000E-01 -4.588000E-03 +8.400000E-04 +1.340000E-01 +3.634000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.700000E-01 -5.884000E-03 -2.280000E-01 -1.084800E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.856000E-03 -2.250000E-01 -1.047100E-02 -1.410000E-01 -4.001000E-03 -6.500000E-02 -9.390000E-04 -1.360000E-01 -3.852000E-03 -6.400000E-02 -8.700000E-04 -2.280000E-01 -1.084800E-02 -1.700000E-01 -5.884000E-03 -2.230000E-01 -1.001100E-02 -1.410000E-01 -4.185000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.980000E-01 -8.038000E-03 -5.030000E-01 -5.613900E-02 -2.200000E-01 -9.958000E-03 -9.400000E-02 -1.912000E-03 -2.140000E-01 -9.376000E-03 -7.300000E-02 -1.091000E-03 -1.410000E-01 -4.185000E-03 -2.230000E-01 -1.001100E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.808000E-03 -2.340000E-01 -1.119400E-02 -1.570000E-01 -4.975000E-03 -6.700000E-02 -9.310000E-04 1.600000E-01 -5.134000E-03 -5.300000E-02 -6.110000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.310000E-01 -1.084100E-02 -5.390000E-01 -6.215100E-02 -2.250000E-01 -1.047100E-02 -1.540000E-01 -4.856000E-03 -2.280000E-01 -1.059800E-02 -1.600000E-01 -5.214000E-03 -2.160000E-01 -9.418000E-03 -9.300000E-02 -1.927000E-03 -2.510000E-01 -1.271500E-02 -1.030000E-01 -2.229000E-03 -5.390000E-01 -6.215100E-02 -2.310000E-01 -1.084100E-02 -4.700000E-01 -4.972200E-02 -2.190000E-01 -9.821000E-03 -5.030000E-01 -5.613900E-02 -1.980000E-01 -8.038000E-03 -5.100000E-01 -5.929000E-02 -2.140000E-01 -9.406000E-03 -5.470000E-01 -7.228300E-02 -2.110000E-01 -9.215000E-03 -5.160000E-01 -5.892200E-02 -2.550000E-01 -1.480500E-02 -2.190000E-01 -9.821000E-03 -4.700000E-01 -4.972200E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.340000E-01 -1.119400E-02 -1.540000E-01 -4.808000E-03 +5.202000E-03 2.170000E-01 -9.509000E-03 +9.735000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.490000E-01 +4.565000E-03 +2.360000E-01 +1.145400E-02 +1.570000E-01 +5.131000E-03 +6.700000E-02 +9.270000E-04 +1.460000E-01 +4.382000E-03 +6.800000E-02 +1.030000E-03 +2.170000E-01 +9.735000E-03 1.600000E-01 -5.156000E-03 -1.860000E-01 -7.198000E-03 -9.900000E-02 -2.127000E-03 -2.290000E-01 -1.058700E-02 -9.000000E-02 -1.780000E-03 +5.202000E-03 +2.130000E-01 +9.111000E-03 +1.360000E-01 +4.056000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.070000E-01 +8.827000E-03 +4.970000E-01 +5.443700E-02 +2.360000E-01 +1.139000E-02 +8.800000E-02 +1.644000E-03 +1.890000E-01 +7.267000E-03 +1.000000E-01 +2.154000E-03 +1.360000E-01 +4.056000E-03 +2.130000E-01 +9.111000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.400000E-01 +3.972000E-03 +2.360000E-01 +1.118200E-02 +1.290000E-01 +3.357000E-03 +5.800000E-02 +7.240000E-04 +1.650000E-01 +5.497000E-03 +4.500000E-02 +4.390000E-04 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.550000E-01 -4.913000E-03 2.380000E-01 -1.153400E-02 -1.600000E-01 -5.214000E-03 +1.167000E-02 +5.080000E-01 +5.729800E-02 +2.360000E-01 +1.145400E-02 +1.490000E-01 +4.565000E-03 +2.400000E-01 +1.169000E-02 +1.700000E-01 +5.850000E-03 +2.230000E-01 +1.002300E-02 +1.060000E-01 +2.530000E-03 +2.020000E-01 +8.370000E-03 +1.010000E-01 +2.179000E-03 +5.080000E-01 +5.729800E-02 +2.380000E-01 +1.167000E-02 +4.940000E-01 +5.315400E-02 2.280000E-01 -1.059800E-02 +1.061000E-02 +4.970000E-01 +5.443700E-02 +2.070000E-01 +8.827000E-03 +5.320000E-01 +6.384600E-02 +2.240000E-01 +1.040600E-02 +5.570000E-01 +7.415500E-02 +2.130000E-01 +9.451000E-03 +5.020000E-01 +5.764600E-02 +2.250000E-01 +1.096300E-02 +2.280000E-01 +1.061000E-02 +4.940000E-01 +5.315400E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.360000E-01 +1.118200E-02 +1.400000E-01 +3.972000E-03 +2.130000E-01 +9.133000E-03 +1.660000E-01 +5.668000E-03 +2.150000E-01 +9.355000E-03 +1.050000E-01 +2.345000E-03 +2.110000E-01 +8.999000E-03 +1.030000E-01 +2.191000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.590000E-01 +5.087000E-03 +2.500000E-01 +1.274600E-02 +1.700000E-01 +5.850000E-03 +2.400000E-01 +1.169000E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.720000E-01 +6.062000E-03 +7.200000E-02 +1.090000E-03 +1.440000E-01 +4.264000E-03 +7.000000E-02 +1.284000E-03 +2.500000E-01 +1.274600E-02 +1.590000E-01 +5.087000E-03 +2.530000E-01 +1.284500E-02 +1.390000E-01 +4.087000E-03 +2.240000E-01 +1.040600E-02 +5.320000E-01 +6.384600E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.340000E-01 +1.113000E-02 +1.100000E-01 +2.558000E-03 +2.070000E-01 +8.695000E-03 +1.160000E-01 +3.278000E-03 +1.390000E-01 +4.087000E-03 +2.530000E-01 +1.284500E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.660000E-01 +5.668000E-03 +2.130000E-01 +9.133000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.340000E-01 +3.634000E-03 +6.200000E-02 +8.400000E-04 +1.600000E-01 +5.186000E-03 +5.400000E-02 +6.340000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.120000E-01 +2.592000E-03 +1.720000E-01 +6.066000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.220000E-01 +3.024000E-03 +1.370000E-01 +3.775000E-03 +6.800000E-02 +1.030000E-03 +1.460000E-01 +4.382000E-03 +1.600000E-01 +5.186000E-03 +0.000000E+00 +0.000000E+00 +1.720000E-01 +6.066000E-03 +1.120000E-01 +2.592000E-03 +1.260000E-01 +3.360000E-03 +1.250000E-01 +3.287000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.580000E-01 +5.108000E-03 +2.510000E-01 +1.270100E-02 +1.000000E-01 +2.154000E-03 +1.890000E-01 +7.267000E-03 +1.710000E-01 +5.975000E-03 +0.000000E+00 +0.000000E+00 +1.250000E-01 +3.287000E-03 +1.260000E-01 +3.360000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.230000E-01 +3.143000E-03 +1.300000E-01 +3.454000E-03 +4.500000E-02 +4.390000E-04 +1.650000E-01 +5.497000E-03 +1.380000E-01 +3.946000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.840000E-01 +6.872000E-03 +2.440000E-01 +1.221200E-02 +1.370000E-01 +3.775000E-03 +1.220000E-01 +3.024000E-03 +1.560000E-01 +4.952000E-03 +1.210000E-01 +3.039000E-03 +1.010000E-01 +2.179000E-03 +2.020000E-01 +8.370000E-03 +1.800000E-01 +6.542000E-03 +0.000000E+00 +0.000000E+00 +2.440000E-01 +1.221200E-02 +1.840000E-01 +6.872000E-03 +2.430000E-01 +1.197500E-02 +1.700000E-01 +6.050000E-03 +2.510000E-01 +1.270100E-02 +1.580000E-01 +5.108000E-03 +2.750000E-01 +1.589500E-02 +1.680000E-01 +5.858000E-03 +2.250000E-01 +1.096300E-02 +5.020000E-01 +5.764600E-02 +2.260000E-01 +1.039600E-02 +0.000000E+00 +0.000000E+00 +1.700000E-01 +6.050000E-03 +2.430000E-01 +1.197500E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.300000E-01 +3.454000E-03 +1.230000E-01 +3.143000E-03 +1.590000E-01 +5.219000E-03 +1.270000E-01 +3.447000E-03 +1.030000E-01 +2.191000E-03 +2.110000E-01 +8.999000E-03 +2.090000E-01 +9.091000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.150000E-01 +2.821000E-03 +1.610000E-01 +5.499000E-03 +1.210000E-01 +3.039000E-03 +1.560000E-01 +4.952000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.000000E-02 +1.284000E-03 +1.440000E-01 +4.264000E-03 +1.580000E-01 +5.002000E-03 +0.000000E+00 +0.000000E+00 1.610000E-01 -5.237000E-03 -7.000000E-02 -1.020000E-03 -1.410000E-01 -4.071000E-03 -6.100000E-02 -8.350000E-04 -2.380000E-01 -1.153400E-02 -1.550000E-01 -4.913000E-03 -2.320000E-01 -1.100400E-02 -1.460000E-01 -4.498000E-03 -2.140000E-01 -9.406000E-03 -5.100000E-01 -5.929000E-02 +5.499000E-03 +1.150000E-01 +2.821000E-03 +1.630000E-01 +5.583000E-03 +1.270000E-01 +3.315000E-03 +1.680000E-01 +5.858000E-03 +2.750000E-01 +1.589500E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.150000E-01 -9.289000E-03 -9.500000E-02 -1.949000E-03 -1.870000E-01 -7.267000E-03 -1.030000E-01 -2.543000E-03 -1.460000E-01 -4.498000E-03 -2.320000E-01 -1.100400E-02 +1.160000E-01 +3.278000E-03 +2.070000E-01 +8.695000E-03 +1.840000E-01 +6.908000E-03 +0.000000E+00 +0.000000E+00 +1.270000E-01 +3.315000E-03 +1.630000E-01 +5.583000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.270000E-01 +3.447000E-03 +1.590000E-01 +5.219000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.400000E-02 +6.340000E-04 1.600000E-01 -5.156000E-03 -2.170000E-01 -9.509000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.500000E-01 -4.588000E-03 -6.200000E-02 -8.020000E-04 -1.290000E-01 -3.487000E-03 -6.000000E-02 -8.060000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.090000E-01 -2.437000E-03 -1.650000E-01 -5.655000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.065000E-03 -1.570000E-01 -4.999000E-03 -6.400000E-02 -8.700000E-04 -1.360000E-01 -3.852000E-03 -1.750000E-01 -6.299000E-03 -0.000000E+00 -0.000000E+00 -1.650000E-01 -5.655000E-03 -1.090000E-01 -2.437000E-03 -1.480000E-01 -4.674000E-03 -1.320000E-01 -3.548000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.440000E-01 -4.282000E-03 -2.190000E-01 -9.683000E-03 -7.300000E-02 -1.091000E-03 -2.140000E-01 -9.376000E-03 -1.830000E-01 -6.803000E-03 -0.000000E+00 -0.000000E+00 -1.320000E-01 -3.548000E-03 -1.480000E-01 -4.674000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.350000E-01 -3.895000E-03 -1.430000E-01 -4.297000E-03 -5.300000E-02 -6.110000E-04 -1.600000E-01 -5.134000E-03 -1.380000E-01 -4.220000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.900000E-01 -7.412000E-03 -2.420000E-01 -1.208400E-02 -1.570000E-01 -4.999000E-03 -1.230000E-01 -3.065000E-03 -1.730000E-01 -6.279000E-03 -1.330000E-01 -3.621000E-03 -1.030000E-01 -2.229000E-03 -2.510000E-01 -1.271500E-02 -2.100000E-01 -8.970000E-03 -0.000000E+00 -0.000000E+00 -2.420000E-01 -1.208400E-02 -1.900000E-01 -7.412000E-03 -2.610000E-01 -1.399900E-02 -2.000000E-01 -8.410000E-03 -2.190000E-01 -9.683000E-03 -1.440000E-01 -4.282000E-03 -2.690000E-01 -1.478100E-02 -1.540000E-01 -4.986000E-03 -2.550000E-01 -1.480500E-02 -5.160000E-01 -5.892200E-02 -2.310000E-01 -1.098900E-02 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.410000E-03 -2.610000E-01 -1.399900E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.430000E-01 -4.297000E-03 -1.350000E-01 -3.895000E-03 -1.760000E-01 -6.534000E-03 -1.170000E-01 -2.807000E-03 -9.000000E-02 -1.780000E-03 -2.290000E-01 -1.058700E-02 -2.080000E-01 -8.854000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.305000E-03 -1.760000E-01 -6.598000E-03 -1.330000E-01 -3.621000E-03 -1.730000E-01 -6.279000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.100000E-02 -8.350000E-04 -1.410000E-01 -4.071000E-03 -1.800000E-01 -6.574000E-03 -0.000000E+00 -0.000000E+00 -1.760000E-01 -6.598000E-03 -1.230000E-01 -3.305000E-03 -1.690000E-01 -6.135000E-03 -1.220000E-01 -3.344000E-03 -1.540000E-01 -4.986000E-03 -2.690000E-01 -1.478100E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.030000E-01 -2.543000E-03 -1.870000E-01 -7.267000E-03 -1.690000E-01 -5.731000E-03 -0.000000E+00 -0.000000E+00 -1.220000E-01 -3.344000E-03 -1.690000E-01 -6.135000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.170000E-01 -2.807000E-03 -1.760000E-01 -6.534000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.000000E-02 -8.060000E-04 -1.290000E-01 -3.487000E-03 -1.790000E-01 -6.747000E-03 +5.186000E-03 +1.920000E-01 +7.646000E-03 0.000000E+00 0.000000E+00 tally 2: @@ -660,12 +660,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.200000E-01 -2.924000E-03 +1.400000E-01 +4.016000E-03 0.000000E+00 0.000000E+00 -1.740000E-01 -6.270000E-03 +1.760000E-01 +6.368000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -676,112 +676,16 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.200000E-01 -3.044000E-03 +1.140000E-01 +2.714000E-03 0.000000E+00 0.000000E+00 -1.510000E-01 -4.615000E-03 +1.590000E-01 +5.517000E-03 0.000000E+00 0.000000E+00 -1.710000E-01 -6.067000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.500000E-02 -9.390000E-04 -0.000000E+00 -0.000000E+00 -1.410000E-01 -4.001000E-03 -0.000000E+00 -0.000000E+00 -1.740000E-01 -6.270000E-03 -0.000000E+00 -0.000000E+00 -1.200000E-01 -2.924000E-03 -0.000000E+00 -0.000000E+00 -1.830000E-01 -6.879000E-03 -0.000000E+00 -0.000000E+00 -1.310000E-01 -3.541000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.750000E-01 -6.659000E-03 -0.000000E+00 -0.000000E+00 -2.820000E-01 -1.605400E-02 -0.000000E+00 -0.000000E+00 -1.980000E-01 -7.932000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.400000E-02 -1.912000E-03 -0.000000E+00 -0.000000E+00 -2.200000E-01 -9.958000E-03 -0.000000E+00 -0.000000E+00 -1.310000E-01 -3.541000E-03 -0.000000E+00 -0.000000E+00 -1.830000E-01 -6.879000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.110000E-01 -2.639000E-03 -0.000000E+00 -0.000000E+00 -1.360000E-01 -3.890000E-03 -0.000000E+00 -0.000000E+00 -1.770000E-01 -6.551000E-03 +1.800000E-01 +6.524000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -789,287 +693,383 @@ tally 2: 0.000000E+00 0.000000E+00 6.700000E-02 -9.310000E-04 +9.270000E-04 0.000000E+00 0.000000E+00 1.570000E-01 -4.975000E-03 +5.131000E-03 0.000000E+00 0.000000E+00 +1.760000E-01 +6.368000E-03 0.000000E+00 0.000000E+00 +1.400000E-01 +4.016000E-03 0.000000E+00 0.000000E+00 +1.570000E-01 +5.019000E-03 0.000000E+00 0.000000E+00 +1.210000E-01 +2.997000E-03 0.000000E+00 0.000000E+00 -1.480000E-01 -4.910000E-03 0.000000E+00 0.000000E+00 -2.720000E-01 -1.490600E-02 0.000000E+00 0.000000E+00 -1.510000E-01 -4.615000E-03 0.000000E+00 0.000000E+00 -1.200000E-01 -3.044000E-03 0.000000E+00 0.000000E+00 -1.800000E-01 -6.720000E-03 +1.780000E-01 +6.838000E-03 0.000000E+00 0.000000E+00 -1.050000E-01 -2.285000E-03 +2.440000E-01 +1.203200E-02 0.000000E+00 0.000000E+00 -1.790000E-01 -6.499000E-03 +2.120000E-01 +9.028000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.300000E-02 -1.927000E-03 +8.800000E-02 +1.644000E-03 0.000000E+00 0.000000E+00 -2.160000E-01 -9.418000E-03 +2.360000E-01 +1.139000E-02 0.000000E+00 0.000000E+00 -2.720000E-01 -1.490600E-02 +1.210000E-01 +2.997000E-03 0.000000E+00 0.000000E+00 -1.480000E-01 -4.910000E-03 +1.570000E-01 +5.019000E-03 0.000000E+00 0.000000E+00 -2.680000E-01 -1.445800E-02 0.000000E+00 0.000000E+00 -1.480000E-01 -4.488000E-03 0.000000E+00 0.000000E+00 -2.820000E-01 -1.605400E-02 0.000000E+00 0.000000E+00 -1.750000E-01 -6.659000E-03 0.000000E+00 0.000000E+00 -2.510000E-01 -1.283100E-02 0.000000E+00 0.000000E+00 -1.870000E-01 -7.731000E-03 -0.000000E+00 -0.000000E+00 -2.340000E-01 -1.105000E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.110000E-01 -9.215000E-03 -0.000000E+00 -0.000000E+00 -5.470000E-01 -7.228300E-02 -0.000000E+00 -0.000000E+00 -1.480000E-01 -4.488000E-03 -0.000000E+00 -0.000000E+00 -2.680000E-01 -1.445800E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.360000E-01 -3.890000E-03 -0.000000E+00 -0.000000E+00 -1.110000E-01 -2.639000E-03 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.804000E-03 -0.000000E+00 -0.000000E+00 -1.280000E-01 -3.302000E-03 -0.000000E+00 -0.000000E+00 -2.200000E-01 -9.834000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.900000E-02 -2.127000E-03 -0.000000E+00 -0.000000E+00 -1.860000E-01 -7.198000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.430000E-01 -4.337000E-03 -0.000000E+00 -0.000000E+00 -1.580000E-01 -5.104000E-03 -0.000000E+00 -0.000000E+00 -1.050000E-01 -2.285000E-03 -0.000000E+00 -0.000000E+00 -1.800000E-01 -6.720000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.860000E-01 -7.178000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -7.000000E-02 -1.020000E-03 -0.000000E+00 -0.000000E+00 -1.610000E-01 -5.237000E-03 -0.000000E+00 -0.000000E+00 -1.580000E-01 -5.104000E-03 -0.000000E+00 -0.000000E+00 -1.430000E-01 -4.337000E-03 -0.000000E+00 -0.000000E+00 -1.580000E-01 -5.254000E-03 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.091000E-03 -0.000000E+00 -0.000000E+00 -1.870000E-01 -7.731000E-03 -0.000000E+00 -0.000000E+00 -2.510000E-01 -1.283100E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.980000E-01 -7.934000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.500000E-02 -1.949000E-03 -0.000000E+00 -0.000000E+00 -2.150000E-01 -9.289000E-03 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.091000E-03 -0.000000E+00 -0.000000E+00 -1.580000E-01 -5.254000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.280000E-01 -3.302000E-03 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.804000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.070000E-01 +2.375000E-03 0.000000E+00 0.000000E+00 +1.490000E-01 +4.621000E-03 0.000000E+00 0.000000E+00 1.640000E-01 -5.424000E-03 +5.476000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.800000E-02 +7.240000E-04 +0.000000E+00 +0.000000E+00 +1.290000E-01 +3.357000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.470000E-01 +4.583000E-03 +0.000000E+00 +0.000000E+00 +2.610000E-01 +1.376900E-02 +0.000000E+00 +0.000000E+00 +1.590000E-01 +5.517000E-03 +0.000000E+00 +0.000000E+00 +1.140000E-01 +2.714000E-03 +0.000000E+00 +0.000000E+00 +1.630000E-01 +5.645000E-03 +0.000000E+00 +0.000000E+00 +1.090000E-01 +2.419000E-03 +0.000000E+00 +0.000000E+00 +1.820000E-01 +6.750000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.060000E-01 +2.530000E-03 +0.000000E+00 +0.000000E+00 +2.230000E-01 +1.002300E-02 +0.000000E+00 +0.000000E+00 +2.610000E-01 +1.376900E-02 +0.000000E+00 +0.000000E+00 +1.470000E-01 +4.583000E-03 +0.000000E+00 +0.000000E+00 +2.820000E-01 +1.613400E-02 +0.000000E+00 +0.000000E+00 +1.800000E-01 +6.690000E-03 +0.000000E+00 +0.000000E+00 +2.440000E-01 +1.203200E-02 +0.000000E+00 +0.000000E+00 +1.780000E-01 +6.838000E-03 +0.000000E+00 +0.000000E+00 +2.870000E-01 +1.696700E-02 +0.000000E+00 +0.000000E+00 +1.800000E-01 +6.556000E-03 +0.000000E+00 +0.000000E+00 +2.430000E-01 +1.211900E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.130000E-01 +9.451000E-03 +0.000000E+00 +0.000000E+00 +5.570000E-01 +7.415500E-02 +0.000000E+00 +0.000000E+00 +1.800000E-01 +6.690000E-03 +0.000000E+00 +0.000000E+00 +2.820000E-01 +1.613400E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.490000E-01 +4.621000E-03 +0.000000E+00 +0.000000E+00 +1.070000E-01 +2.375000E-03 +0.000000E+00 +0.000000E+00 +1.500000E-01 +4.604000E-03 +0.000000E+00 +0.000000E+00 +1.100000E-01 +2.552000E-03 +0.000000E+00 +0.000000E+00 +1.800000E-01 +6.518000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.050000E-01 +2.345000E-03 +0.000000E+00 +0.000000E+00 +2.150000E-01 +9.355000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.340000E-01 +3.818000E-03 +0.000000E+00 +0.000000E+00 +1.690000E-01 +5.911000E-03 +0.000000E+00 +0.000000E+00 +1.090000E-01 +2.419000E-03 +0.000000E+00 +0.000000E+00 +1.630000E-01 +5.645000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.860000E-01 +6.998000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.200000E-02 +1.090000E-03 +0.000000E+00 +0.000000E+00 +1.720000E-01 +6.062000E-03 +0.000000E+00 +0.000000E+00 +1.690000E-01 +5.911000E-03 +0.000000E+00 +0.000000E+00 +1.340000E-01 +3.818000E-03 +0.000000E+00 +0.000000E+00 +1.600000E-01 +5.454000E-03 +0.000000E+00 +0.000000E+00 +1.060000E-01 +2.328000E-03 +0.000000E+00 +0.000000E+00 +1.800000E-01 +6.556000E-03 +0.000000E+00 +0.000000E+00 +2.870000E-01 +1.696700E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.060000E-01 +8.670000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-01 +2.558000E-03 +0.000000E+00 +0.000000E+00 +2.340000E-01 +1.113000E-02 +0.000000E+00 +0.000000E+00 +1.060000E-01 +2.328000E-03 +0.000000E+00 +0.000000E+00 +1.600000E-01 +5.454000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-01 +2.552000E-03 +0.000000E+00 +0.000000E+00 +1.500000E-01 +4.604000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.730000E-01 +6.077000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1077,11 +1077,11 @@ tally 2: 0.000000E+00 0.000000E+00 6.200000E-02 -8.020000E-04 +8.400000E-04 0.000000E+00 0.000000E+00 -1.500000E-01 -4.588000E-03 +1.340000E-01 +3.634000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1092,284 +1092,60 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.700000E-01 -5.884000E-03 -0.000000E+00 -0.000000E+00 -2.280000E-01 -1.084800E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.856000E-03 -0.000000E+00 -0.000000E+00 -2.250000E-01 -1.047100E-02 -0.000000E+00 -0.000000E+00 -1.410000E-01 -4.001000E-03 -0.000000E+00 -0.000000E+00 -6.500000E-02 -9.390000E-04 -0.000000E+00 -0.000000E+00 -1.360000E-01 -3.852000E-03 -0.000000E+00 -0.000000E+00 -6.400000E-02 -8.700000E-04 -0.000000E+00 -0.000000E+00 -2.280000E-01 -1.084800E-02 -0.000000E+00 -0.000000E+00 -1.700000E-01 -5.884000E-03 -0.000000E+00 -0.000000E+00 -2.230000E-01 -1.001100E-02 -0.000000E+00 -0.000000E+00 -1.410000E-01 -4.185000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.980000E-01 -8.038000E-03 -0.000000E+00 -0.000000E+00 -5.030000E-01 -5.613900E-02 -0.000000E+00 -0.000000E+00 -2.200000E-01 -9.958000E-03 -0.000000E+00 -0.000000E+00 -9.400000E-02 -1.912000E-03 -0.000000E+00 -0.000000E+00 -2.140000E-01 -9.376000E-03 -0.000000E+00 -0.000000E+00 -7.300000E-02 -1.091000E-03 -0.000000E+00 -0.000000E+00 -1.410000E-01 -4.185000E-03 -0.000000E+00 -0.000000E+00 -2.230000E-01 -1.001100E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.808000E-03 -0.000000E+00 -0.000000E+00 -2.340000E-01 -1.119400E-02 -0.000000E+00 -0.000000E+00 -1.570000E-01 -4.975000E-03 -0.000000E+00 -0.000000E+00 -6.700000E-02 -9.310000E-04 -0.000000E+00 -0.000000E+00 1.600000E-01 -5.134000E-03 -0.000000E+00 -0.000000E+00 -5.300000E-02 -6.110000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.310000E-01 -1.084100E-02 -0.000000E+00 -0.000000E+00 -5.390000E-01 -6.215100E-02 -0.000000E+00 -0.000000E+00 -2.250000E-01 -1.047100E-02 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.856000E-03 -0.000000E+00 -0.000000E+00 -2.280000E-01 -1.059800E-02 -0.000000E+00 -0.000000E+00 -1.600000E-01 -5.214000E-03 -0.000000E+00 -0.000000E+00 -2.160000E-01 -9.418000E-03 -0.000000E+00 -0.000000E+00 -9.300000E-02 -1.927000E-03 -0.000000E+00 -0.000000E+00 -2.510000E-01 -1.271500E-02 -0.000000E+00 -0.000000E+00 -1.030000E-01 -2.229000E-03 -0.000000E+00 -0.000000E+00 -5.390000E-01 -6.215100E-02 -0.000000E+00 -0.000000E+00 -2.310000E-01 -1.084100E-02 -0.000000E+00 -0.000000E+00 -4.700000E-01 -4.972200E-02 -0.000000E+00 -0.000000E+00 -2.190000E-01 -9.821000E-03 -0.000000E+00 -0.000000E+00 -5.030000E-01 -5.613900E-02 -0.000000E+00 -0.000000E+00 -1.980000E-01 -8.038000E-03 -0.000000E+00 -0.000000E+00 -5.100000E-01 -5.929000E-02 -0.000000E+00 -0.000000E+00 -2.140000E-01 -9.406000E-03 -0.000000E+00 -0.000000E+00 -5.470000E-01 -7.228300E-02 -0.000000E+00 -0.000000E+00 -2.110000E-01 -9.215000E-03 -0.000000E+00 -0.000000E+00 -5.160000E-01 -5.892200E-02 -0.000000E+00 -0.000000E+00 -2.550000E-01 -1.480500E-02 -0.000000E+00 -0.000000E+00 -2.190000E-01 -9.821000E-03 -0.000000E+00 -0.000000E+00 -4.700000E-01 -4.972200E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.340000E-01 -1.119400E-02 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.808000E-03 +5.202000E-03 0.000000E+00 0.000000E+00 2.170000E-01 -9.509000E-03 +9.735000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.490000E-01 +4.565000E-03 +0.000000E+00 +0.000000E+00 +2.360000E-01 +1.145400E-02 +0.000000E+00 +0.000000E+00 +1.570000E-01 +5.131000E-03 +0.000000E+00 +0.000000E+00 +6.700000E-02 +9.270000E-04 +0.000000E+00 +0.000000E+00 +1.460000E-01 +4.382000E-03 +0.000000E+00 +0.000000E+00 +6.800000E-02 +1.030000E-03 +0.000000E+00 +0.000000E+00 +2.170000E-01 +9.735000E-03 0.000000E+00 0.000000E+00 1.600000E-01 -5.156000E-03 +5.202000E-03 0.000000E+00 0.000000E+00 -1.860000E-01 -7.198000E-03 +2.130000E-01 +9.111000E-03 0.000000E+00 0.000000E+00 -9.900000E-02 -2.127000E-03 -0.000000E+00 -0.000000E+00 -2.290000E-01 -1.058700E-02 -0.000000E+00 -0.000000E+00 -9.000000E-02 -1.780000E-03 +1.360000E-01 +4.056000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1380,20 +1156,180 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.550000E-01 -4.913000E-03 +2.070000E-01 +8.827000E-03 +0.000000E+00 +0.000000E+00 +4.970000E-01 +5.443700E-02 +0.000000E+00 +0.000000E+00 +2.360000E-01 +1.139000E-02 +0.000000E+00 +0.000000E+00 +8.800000E-02 +1.644000E-03 +0.000000E+00 +0.000000E+00 +1.890000E-01 +7.267000E-03 +0.000000E+00 +0.000000E+00 +1.000000E-01 +2.154000E-03 +0.000000E+00 +0.000000E+00 +1.360000E-01 +4.056000E-03 +0.000000E+00 +0.000000E+00 +2.130000E-01 +9.111000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.400000E-01 +3.972000E-03 +0.000000E+00 +0.000000E+00 +2.360000E-01 +1.118200E-02 +0.000000E+00 +0.000000E+00 +1.290000E-01 +3.357000E-03 +0.000000E+00 +0.000000E+00 +5.800000E-02 +7.240000E-04 +0.000000E+00 +0.000000E+00 +1.650000E-01 +5.497000E-03 +0.000000E+00 +0.000000E+00 +4.500000E-02 +4.390000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 2.380000E-01 -1.153400E-02 +1.167000E-02 0.000000E+00 0.000000E+00 -1.600000E-01 -5.214000E-03 +5.080000E-01 +5.729800E-02 +0.000000E+00 +0.000000E+00 +2.360000E-01 +1.145400E-02 +0.000000E+00 +0.000000E+00 +1.490000E-01 +4.565000E-03 +0.000000E+00 +0.000000E+00 +2.400000E-01 +1.169000E-02 +0.000000E+00 +0.000000E+00 +1.700000E-01 +5.850000E-03 +0.000000E+00 +0.000000E+00 +2.230000E-01 +1.002300E-02 +0.000000E+00 +0.000000E+00 +1.060000E-01 +2.530000E-03 +0.000000E+00 +0.000000E+00 +2.020000E-01 +8.370000E-03 +0.000000E+00 +0.000000E+00 +1.010000E-01 +2.179000E-03 +0.000000E+00 +0.000000E+00 +5.080000E-01 +5.729800E-02 +0.000000E+00 +0.000000E+00 +2.380000E-01 +1.167000E-02 +0.000000E+00 +0.000000E+00 +4.940000E-01 +5.315400E-02 0.000000E+00 0.000000E+00 2.280000E-01 -1.059800E-02 +1.061000E-02 +0.000000E+00 +0.000000E+00 +4.970000E-01 +5.443700E-02 +0.000000E+00 +0.000000E+00 +2.070000E-01 +8.827000E-03 +0.000000E+00 +0.000000E+00 +5.320000E-01 +6.384600E-02 +0.000000E+00 +0.000000E+00 +2.240000E-01 +1.040600E-02 +0.000000E+00 +0.000000E+00 +5.570000E-01 +7.415500E-02 +0.000000E+00 +0.000000E+00 +2.130000E-01 +9.451000E-03 +0.000000E+00 +0.000000E+00 +5.020000E-01 +5.764600E-02 +0.000000E+00 +0.000000E+00 +2.250000E-01 +1.096300E-02 +0.000000E+00 +0.000000E+00 +2.280000E-01 +1.061000E-02 +0.000000E+00 +0.000000E+00 +4.940000E-01 +5.315400E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1404,44 +1340,540 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 +2.360000E-01 +1.118200E-02 +0.000000E+00 +0.000000E+00 +1.400000E-01 +3.972000E-03 +0.000000E+00 +0.000000E+00 +2.130000E-01 +9.133000E-03 +0.000000E+00 +0.000000E+00 +1.660000E-01 +5.668000E-03 +0.000000E+00 +0.000000E+00 +2.150000E-01 +9.355000E-03 +0.000000E+00 +0.000000E+00 +1.050000E-01 +2.345000E-03 +0.000000E+00 +0.000000E+00 +2.110000E-01 +8.999000E-03 +0.000000E+00 +0.000000E+00 +1.030000E-01 +2.191000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.590000E-01 +5.087000E-03 +0.000000E+00 +0.000000E+00 +2.500000E-01 +1.274600E-02 +0.000000E+00 +0.000000E+00 +1.700000E-01 +5.850000E-03 +0.000000E+00 +0.000000E+00 +2.400000E-01 +1.169000E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.720000E-01 +6.062000E-03 +0.000000E+00 +0.000000E+00 +7.200000E-02 +1.090000E-03 +0.000000E+00 +0.000000E+00 +1.440000E-01 +4.264000E-03 +0.000000E+00 +0.000000E+00 +7.000000E-02 +1.284000E-03 +0.000000E+00 +0.000000E+00 +2.500000E-01 +1.274600E-02 +0.000000E+00 +0.000000E+00 +1.590000E-01 +5.087000E-03 +0.000000E+00 +0.000000E+00 +2.530000E-01 +1.284500E-02 +0.000000E+00 +0.000000E+00 +1.390000E-01 +4.087000E-03 +0.000000E+00 +0.000000E+00 +2.240000E-01 +1.040600E-02 +0.000000E+00 +0.000000E+00 +5.320000E-01 +6.384600E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.340000E-01 +1.113000E-02 +0.000000E+00 +0.000000E+00 +1.100000E-01 +2.558000E-03 +0.000000E+00 +0.000000E+00 +2.070000E-01 +8.695000E-03 +0.000000E+00 +0.000000E+00 +1.160000E-01 +3.278000E-03 +0.000000E+00 +0.000000E+00 +1.390000E-01 +4.087000E-03 +0.000000E+00 +0.000000E+00 +2.530000E-01 +1.284500E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.660000E-01 +5.668000E-03 +0.000000E+00 +0.000000E+00 +2.130000E-01 +9.133000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.340000E-01 +3.634000E-03 +0.000000E+00 +0.000000E+00 +6.200000E-02 +8.400000E-04 +0.000000E+00 +0.000000E+00 +1.600000E-01 +5.186000E-03 +0.000000E+00 +0.000000E+00 +5.400000E-02 +6.340000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.120000E-01 +2.592000E-03 +0.000000E+00 +0.000000E+00 +1.720000E-01 +6.066000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.220000E-01 +3.024000E-03 +0.000000E+00 +0.000000E+00 +1.370000E-01 +3.775000E-03 +0.000000E+00 +0.000000E+00 +6.800000E-02 +1.030000E-03 +0.000000E+00 +0.000000E+00 +1.460000E-01 +4.382000E-03 +0.000000E+00 +0.000000E+00 +1.600000E-01 +5.186000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.720000E-01 +6.066000E-03 +0.000000E+00 +0.000000E+00 +1.120000E-01 +2.592000E-03 +0.000000E+00 +0.000000E+00 +1.260000E-01 +3.360000E-03 +0.000000E+00 +0.000000E+00 +1.250000E-01 +3.287000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.580000E-01 +5.108000E-03 +0.000000E+00 +0.000000E+00 +2.510000E-01 +1.270100E-02 +0.000000E+00 +0.000000E+00 +1.000000E-01 +2.154000E-03 +0.000000E+00 +0.000000E+00 +1.890000E-01 +7.267000E-03 +0.000000E+00 +0.000000E+00 +1.710000E-01 +5.975000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.250000E-01 +3.287000E-03 +0.000000E+00 +0.000000E+00 +1.260000E-01 +3.360000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.230000E-01 +3.143000E-03 +0.000000E+00 +0.000000E+00 +1.300000E-01 +3.454000E-03 +0.000000E+00 +0.000000E+00 +4.500000E-02 +4.390000E-04 +0.000000E+00 +0.000000E+00 +1.650000E-01 +5.497000E-03 +0.000000E+00 +0.000000E+00 +1.380000E-01 +3.946000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.840000E-01 +6.872000E-03 +0.000000E+00 +0.000000E+00 +2.440000E-01 +1.221200E-02 +0.000000E+00 +0.000000E+00 +1.370000E-01 +3.775000E-03 +0.000000E+00 +0.000000E+00 +1.220000E-01 +3.024000E-03 +0.000000E+00 +0.000000E+00 +1.560000E-01 +4.952000E-03 +0.000000E+00 +0.000000E+00 +1.210000E-01 +3.039000E-03 +0.000000E+00 +0.000000E+00 +1.010000E-01 +2.179000E-03 +0.000000E+00 +0.000000E+00 +2.020000E-01 +8.370000E-03 +0.000000E+00 +0.000000E+00 +1.800000E-01 +6.542000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.440000E-01 +1.221200E-02 +0.000000E+00 +0.000000E+00 +1.840000E-01 +6.872000E-03 +0.000000E+00 +0.000000E+00 +2.430000E-01 +1.197500E-02 +0.000000E+00 +0.000000E+00 +1.700000E-01 +6.050000E-03 +0.000000E+00 +0.000000E+00 +2.510000E-01 +1.270100E-02 +0.000000E+00 +0.000000E+00 +1.580000E-01 +5.108000E-03 +0.000000E+00 +0.000000E+00 +2.750000E-01 +1.589500E-02 +0.000000E+00 +0.000000E+00 +1.680000E-01 +5.858000E-03 +0.000000E+00 +0.000000E+00 +2.250000E-01 +1.096300E-02 +0.000000E+00 +0.000000E+00 +5.020000E-01 +5.764600E-02 +0.000000E+00 +0.000000E+00 +2.260000E-01 +1.039600E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.700000E-01 +6.050000E-03 +0.000000E+00 +0.000000E+00 +2.430000E-01 +1.197500E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.300000E-01 +3.454000E-03 +0.000000E+00 +0.000000E+00 +1.230000E-01 +3.143000E-03 +0.000000E+00 +0.000000E+00 +1.590000E-01 +5.219000E-03 +0.000000E+00 +0.000000E+00 +1.270000E-01 +3.447000E-03 +0.000000E+00 +0.000000E+00 +1.030000E-01 +2.191000E-03 +0.000000E+00 +0.000000E+00 +2.110000E-01 +8.999000E-03 +0.000000E+00 +0.000000E+00 +2.090000E-01 +9.091000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.150000E-01 +2.821000E-03 +0.000000E+00 +0.000000E+00 +1.610000E-01 +5.499000E-03 +0.000000E+00 +0.000000E+00 +1.210000E-01 +3.039000E-03 +0.000000E+00 +0.000000E+00 +1.560000E-01 +4.952000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.000000E-02 +1.284000E-03 +0.000000E+00 +0.000000E+00 +1.440000E-01 +4.264000E-03 +0.000000E+00 +0.000000E+00 +1.580000E-01 +5.002000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 1.610000E-01 -5.237000E-03 +5.499000E-03 0.000000E+00 0.000000E+00 -7.000000E-02 -1.020000E-03 +1.150000E-01 +2.821000E-03 0.000000E+00 0.000000E+00 -1.410000E-01 -4.071000E-03 +1.630000E-01 +5.583000E-03 0.000000E+00 0.000000E+00 -6.100000E-02 -8.350000E-04 +1.270000E-01 +3.315000E-03 0.000000E+00 0.000000E+00 -2.380000E-01 -1.153400E-02 +1.680000E-01 +5.858000E-03 0.000000E+00 0.000000E+00 -1.550000E-01 -4.913000E-03 -0.000000E+00 -0.000000E+00 -2.320000E-01 -1.100400E-02 -0.000000E+00 -0.000000E+00 -1.460000E-01 -4.498000E-03 -0.000000E+00 -0.000000E+00 -2.140000E-01 -9.406000E-03 -0.000000E+00 -0.000000E+00 -5.100000E-01 -5.929000E-02 +2.750000E-01 +1.589500E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1452,28 +1884,28 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -2.150000E-01 -9.289000E-03 +1.160000E-01 +3.278000E-03 0.000000E+00 0.000000E+00 -9.500000E-02 -1.949000E-03 +2.070000E-01 +8.695000E-03 0.000000E+00 0.000000E+00 -1.870000E-01 -7.267000E-03 +1.840000E-01 +6.908000E-03 0.000000E+00 0.000000E+00 -1.030000E-01 -2.543000E-03 0.000000E+00 0.000000E+00 -1.460000E-01 -4.498000E-03 0.000000E+00 0.000000E+00 -2.320000E-01 -1.100400E-02 +1.270000E-01 +3.315000E-03 +0.000000E+00 +0.000000E+00 +1.630000E-01 +5.583000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1484,464 +1916,32 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 +1.270000E-01 +3.447000E-03 +0.000000E+00 +0.000000E+00 +1.590000E-01 +5.219000E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.400000E-02 +6.340000E-04 +0.000000E+00 +0.000000E+00 1.600000E-01 -5.156000E-03 +5.186000E-03 0.000000E+00 0.000000E+00 -2.170000E-01 -9.509000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.500000E-01 -4.588000E-03 -0.000000E+00 -0.000000E+00 -6.200000E-02 -8.020000E-04 -0.000000E+00 -0.000000E+00 -1.290000E-01 -3.487000E-03 -0.000000E+00 -0.000000E+00 -6.000000E-02 -8.060000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.090000E-01 -2.437000E-03 -0.000000E+00 -0.000000E+00 -1.650000E-01 -5.655000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.065000E-03 -0.000000E+00 -0.000000E+00 -1.570000E-01 -4.999000E-03 -0.000000E+00 -0.000000E+00 -6.400000E-02 -8.700000E-04 -0.000000E+00 -0.000000E+00 -1.360000E-01 -3.852000E-03 -0.000000E+00 -0.000000E+00 -1.750000E-01 -6.299000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.650000E-01 -5.655000E-03 -0.000000E+00 -0.000000E+00 -1.090000E-01 -2.437000E-03 -0.000000E+00 -0.000000E+00 -1.480000E-01 -4.674000E-03 -0.000000E+00 -0.000000E+00 -1.320000E-01 -3.548000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.440000E-01 -4.282000E-03 -0.000000E+00 -0.000000E+00 -2.190000E-01 -9.683000E-03 -0.000000E+00 -0.000000E+00 -7.300000E-02 -1.091000E-03 -0.000000E+00 -0.000000E+00 -2.140000E-01 -9.376000E-03 -0.000000E+00 -0.000000E+00 -1.830000E-01 -6.803000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.320000E-01 -3.548000E-03 -0.000000E+00 -0.000000E+00 -1.480000E-01 -4.674000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.350000E-01 -3.895000E-03 -0.000000E+00 -0.000000E+00 -1.430000E-01 -4.297000E-03 -0.000000E+00 -0.000000E+00 -5.300000E-02 -6.110000E-04 -0.000000E+00 -0.000000E+00 -1.600000E-01 -5.134000E-03 -0.000000E+00 -0.000000E+00 -1.380000E-01 -4.220000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.900000E-01 -7.412000E-03 -0.000000E+00 -0.000000E+00 -2.420000E-01 -1.208400E-02 -0.000000E+00 -0.000000E+00 -1.570000E-01 -4.999000E-03 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.065000E-03 -0.000000E+00 -0.000000E+00 -1.730000E-01 -6.279000E-03 -0.000000E+00 -0.000000E+00 -1.330000E-01 -3.621000E-03 -0.000000E+00 -0.000000E+00 -1.030000E-01 -2.229000E-03 -0.000000E+00 -0.000000E+00 -2.510000E-01 -1.271500E-02 -0.000000E+00 -0.000000E+00 -2.100000E-01 -8.970000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.420000E-01 -1.208400E-02 -0.000000E+00 -0.000000E+00 -1.900000E-01 -7.412000E-03 -0.000000E+00 -0.000000E+00 -2.610000E-01 -1.399900E-02 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.410000E-03 -0.000000E+00 -0.000000E+00 -2.190000E-01 -9.683000E-03 -0.000000E+00 -0.000000E+00 -1.440000E-01 -4.282000E-03 -0.000000E+00 -0.000000E+00 -2.690000E-01 -1.478100E-02 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.986000E-03 -0.000000E+00 -0.000000E+00 -2.550000E-01 -1.480500E-02 -0.000000E+00 -0.000000E+00 -5.160000E-01 -5.892200E-02 -0.000000E+00 -0.000000E+00 -2.310000E-01 -1.098900E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.410000E-03 -0.000000E+00 -0.000000E+00 -2.610000E-01 -1.399900E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.430000E-01 -4.297000E-03 -0.000000E+00 -0.000000E+00 -1.350000E-01 -3.895000E-03 -0.000000E+00 -0.000000E+00 -1.760000E-01 -6.534000E-03 -0.000000E+00 -0.000000E+00 -1.170000E-01 -2.807000E-03 -0.000000E+00 -0.000000E+00 -9.000000E-02 -1.780000E-03 -0.000000E+00 -0.000000E+00 -2.290000E-01 -1.058700E-02 -0.000000E+00 -0.000000E+00 -2.080000E-01 -8.854000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.305000E-03 -0.000000E+00 -0.000000E+00 -1.760000E-01 -6.598000E-03 -0.000000E+00 -0.000000E+00 -1.330000E-01 -3.621000E-03 -0.000000E+00 -0.000000E+00 -1.730000E-01 -6.279000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.100000E-02 -8.350000E-04 -0.000000E+00 -0.000000E+00 -1.410000E-01 -4.071000E-03 -0.000000E+00 -0.000000E+00 -1.800000E-01 -6.574000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.760000E-01 -6.598000E-03 -0.000000E+00 -0.000000E+00 -1.230000E-01 -3.305000E-03 -0.000000E+00 -0.000000E+00 -1.690000E-01 -6.135000E-03 -0.000000E+00 -0.000000E+00 -1.220000E-01 -3.344000E-03 -0.000000E+00 -0.000000E+00 -1.540000E-01 -4.986000E-03 -0.000000E+00 -0.000000E+00 -2.690000E-01 -1.478100E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.030000E-01 -2.543000E-03 -0.000000E+00 -0.000000E+00 -1.870000E-01 -7.267000E-03 -0.000000E+00 -0.000000E+00 -1.690000E-01 -5.731000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.220000E-01 -3.344000E-03 -0.000000E+00 -0.000000E+00 -1.690000E-01 -6.135000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.170000E-01 -2.807000E-03 -0.000000E+00 -0.000000E+00 -1.760000E-01 -6.534000E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -6.000000E-02 -8.060000E-04 -0.000000E+00 -0.000000E+00 -1.290000E-01 -3.487000E-03 -0.000000E+00 -0.000000E+00 -1.790000E-01 -6.747000E-03 +1.920000E-01 +7.646000E-03 0.000000E+00 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/score_current/test.py b/tests/regression_tests/score_current/test.py index a338a6626..1309584d2 100644 --- a/tests/regression_tests/score_current/test.py +++ b/tests/regression_tests/score_current/test.py @@ -16,12 +16,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.RectangularPrism(10.0, 10.0) - box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.rectangular_prism(10.0, 10.0) + box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 diff --git a/tests/regression_tests/seed/results_true.dat b/tests/regression_tests/seed/results_true.dat index ff34071c1..1f70e1513 100644 --- a/tests/regression_tests/seed/results_true.dat +++ b/tests/regression_tests/seed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.015003E-01 5.094212E-03 +2.961599E-01 2.921488E-03 diff --git a/tests/regression_tests/source/inputs_true.dat b/tests/regression_tests/source/inputs_true.dat index 0c3764ba6..c9c9c4277 100644 --- a/tests/regression_tests/source/inputs_true.dat +++ b/tests/regression_tests/source/inputs_true.dat @@ -1,150 +1,150 @@ - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - - - -4.0 -1.0 3.0 0.2 0.3 0.5 - - - -2.0 0.0 2.0 0.2 0.3 0.2 - - - - - -1.0 0.0 1.0 0.5 0.25 0.25 - - - - - - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - - - - 1.2 -2.3 0.781 - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - - - 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 - - - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - - - - -2.0 0.0 2.0 0.2 0.3 0.2 - - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - - - - -2.0 0.0 2.0 0.2 0.3 0.2 - - - - - - - - - - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - - - - - 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 - - - - - - - - - - - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + + + -4.0 -1.0 3.0 0.2 0.3 0.5 + + + -2.0 0.0 2.0 0.2 0.3 0.2 + + + + + -1.0 0.0 1.0 0.5 0.25 0.25 + + + + + + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + + + + 1.2 -2.3 0.781 + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + + -2.0 0.0 2.0 0.2 0.3 0.2 + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + + -2.0 0.0 2.0 0.2 0.3 0.2 + + + + + + + + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + + + 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 + + + + + + + + + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + diff --git a/tests/regression_tests/source/results_true.dat b/tests/regression_tests/source/results_true.dat index c671463be..62eaf6eff 100644 --- a/tests/regression_tests/source/results_true.dat +++ b/tests/regression_tests/source/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.942254E-01 2.571435E-03 +2.865754E-01 6.762423E-03 diff --git a/tests/regression_tests/source/test.py b/tests/regression_tests/source/test.py index 96efa77eb..e6a5bcf70 100644 --- a/tests/regression_tests/source/test.py +++ b/tests/regression_tests/source/test.py @@ -7,12 +7,12 @@ from tests.testing_harness import PyAPITestHarness class SourceTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): mat1 = openmc.Material(material_id=1, temperature=294) mat1.set_density('g/cm3', 4.5) - mat1.add_nuclide('U235', 1.0) - self._model.materials = openmc.Materials([mat1]) + mat1.add_nuclide(openmc.Nuclide('U235'), 1.0) + materials = openmc.Materials([mat1]) + materials.export_to_xml() sphere = openmc.Sphere(surface_id=1, r=10.0, boundary_type='vacuum') inside_sphere = openmc.Cell(cell_id=1) @@ -21,7 +21,9 @@ class SourceTestHarness(PyAPITestHarness): root = openmc.Universe(universe_id=0) root.add_cell(inside_sphere) - self._model.geometry = openmc.Geometry(root) + geometry = openmc.Geometry() + geometry.root_universe = root + geometry.export_to_xml() # Create an array of different sources x_dist = openmc.stats.Uniform(-3., 3.) @@ -37,15 +39,15 @@ class SourceTestHarness(PyAPITestHarness): spatial2 = openmc.stats.Box([-4., -4., -4.], [4., 4., 4.]) spatial3 = openmc.stats.Point([1.2, -2.3, 0.781]) spatial4 = openmc.stats.SphericalIndependent(r_dist, cos_theta_dist, - phi_dist, + phi_dist, origin=(1., 1., 0.)) - spatial5 = openmc.stats.CylindricalIndependent(r_dist, phi_dist, + spatial5 = openmc.stats.CylindricalIndependent(r_dist, phi_dist, z_dist, origin=(1., 1., 0.)) spatial6 = openmc.stats.SphericalIndependent(r_dist2, cos_theta_dist, - phi_dist, + phi_dist, origin=(1., 1., 0.)) - spatial7 = openmc.stats.CylindricalIndependent(r_dist1, phi_dist, + spatial7 = openmc.stats.CylindricalIndependent(r_dist1, phi_dist, z_dist, origin=(1., 1., 0.)) @@ -55,10 +57,7 @@ class SourceTestHarness(PyAPITestHarness): angle2 = openmc.stats.Monodirectional(reference_uvw=[0., 1., 0.]) angle3 = openmc.stats.Isotropic() - # Note that the definition for E is equivalent to logspace(0, 7) but we - # manually take powers because of last-digit differences that may cause - # test failures with different versions of numpy - E = np.array([10**x for x in np.linspace(0, 7)]) + E = np.logspace(0, 7) p = np.sin(np.linspace(0., pi)) p /= sum(np.diff(E)*p[:-1]) energy1 = openmc.stats.Maxwell(1.2895e6) @@ -68,23 +67,23 @@ class SourceTestHarness(PyAPITestHarness): time1 = openmc.stats.Uniform(2, 5) - source1 = openmc.IndependentSource(spatial1, angle1, energy1, strength=0.3) - source2 = openmc.IndependentSource(spatial2, angle2, energy2, strength=0.1) - source3 = openmc.IndependentSource(spatial3, angle3, energy3, strength=0.1) - source4 = openmc.IndependentSource(spatial4, angle3, energy3, strength=0.1) - source5 = openmc.IndependentSource(spatial5, angle3, energy3, strength=0.1) - source6 = openmc.IndependentSource(spatial5, angle3, energy4, strength=0.1) - source7 = openmc.IndependentSource(spatial6, angle3, energy4, time1, strength=0.1) - source8 = openmc.IndependentSource(spatial7, angle3, energy4, time1, strength=0.1) + source1 = openmc.Source(spatial1, angle1, energy1, strength=0.3) + source2 = openmc.Source(spatial2, angle2, energy2, strength=0.1) + source3 = openmc.Source(spatial3, angle3, energy3, strength=0.1) + source4 = openmc.Source(spatial4, angle3, energy3, strength=0.1) + source5 = openmc.Source(spatial5, angle3, energy3, strength=0.1) + source6 = openmc.Source(spatial5, angle3, energy4, strength=0.1) + source7 = openmc.Source(spatial6, angle3, energy4, time1, strength=0.1) + source8 = openmc.Source(spatial7, angle3, energy4, time1, strength=0.1) settings = openmc.Settings() settings.batches = 10 settings.inactive = 5 settings.particles = 1000 settings.source = [source1, source2, source3, source4, source5, source6, source7, source8] - self._model.settings = settings + settings.export_to_xml() def test_source(): - harness = SourceTestHarness('statepoint.10.h5', model=openmc.Model()) + harness = SourceTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/source_dlopen/inputs_true.dat b/tests/regression_tests/source_dlopen/inputs_true.dat index 9b4601d9f..23878ac20 100644 --- a/tests/regression_tests/source_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_dlopen/inputs_true.dat @@ -1,35 +1,23 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - 0 - - - - - 1 - - - 0.0 2000.0 1000000.0 - - - 1 2 - flux - - - + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + 0 + + diff --git a/tests/regression_tests/source_dlopen/results_true.dat b/tests/regression_tests/source_dlopen/results_true.dat index 1cddaf802..e69de29bb 100644 --- a/tests/regression_tests/source_dlopen/results_true.dat +++ b/tests/regression_tests/source_dlopen/results_true.dat @@ -1,5 +0,0 @@ -tally 1: -1.445856E+04 -2.090732E+07 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/source_dlopen/source_sampling.cpp b/tests/regression_tests/source_dlopen/source_sampling.cpp index 678eea4be..2c6de6d85 100644 --- a/tests/regression_tests/source_dlopen/source_sampling.cpp +++ b/tests/regression_tests/source_dlopen/source_sampling.cpp @@ -5,12 +5,13 @@ #include "openmc/random_lcg.h" #include "openmc/source.h" -class CustomSource : public openmc::Source { +class CustomSource : public openmc::Source +{ openmc::SourceSite sample(uint64_t* seed) const { openmc::SourceSite particle; // wgt - particle.particle = openmc::ParticleType::neutron(); + particle.particle = openmc::ParticleType::neutron; particle.wgt = 1.0; // position @@ -19,17 +20,16 @@ class CustomSource : public openmc::Source { particle.r.z = 0.; // angle particle.u = {1.0, 0.0, 0.0}; - particle.E = 1.00e3; + particle.E = 14.08e6; particle.delayed_group = 0; return particle; } }; -// 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 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 openmc_create_source(std::string parameters) { return std::make_unique(); } diff --git a/tests/regression_tests/source_dlopen/test.py b/tests/regression_tests/source_dlopen/test.py index 0581d6dee..41690224d 100644 --- a/tests/regression_tests/source_dlopen/test.py +++ b/tests/regression_tests/source_dlopen/test.py @@ -18,7 +18,7 @@ def compile_source(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_sources CXX) add_library(source SHARED source_sampling.cpp) find_package(OpenMC REQUIRED HINTS {}) @@ -61,18 +61,9 @@ def model(): model.settings.particles = 1000 model.settings.run_mode = 'fixed source' - tally = openmc.Tally() - mat_filter = openmc.MaterialFilter([natural_lead]) - # energy filter with two bins 0 eV - 1 keV and 1 keV - 1 MeV the second bin - # of the energy filter (last two entries in the tally results) should be - # zero - energy_filter = openmc.EnergyFilter([0.0, 2e3, 1e6]) - tally.filters = [mat_filter, energy_filter] - tally.scores = ['flux'] - model.tallies = openmc.Tallies([tally]) - # custom source from shared library - source = openmc.CompiledSource('build/libsource.so') + source = openmc.Source() + source.library = 'build/libsource.so' model.settings.source = source return model diff --git a/tests/regression_tests/source_file/results_true.dat b/tests/regression_tests/source_file/results_true.dat index 359e0526e..0d8600fed 100644 --- a/tests/regression_tests/source_file/results_true.dat +++ b/tests/regression_tests/source_file/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.827397E-01 1.150437E-03 +3.009416E-01 3.229998E-03 diff --git a/tests/regression_tests/source_mcpl_file/__init__.py b/tests/regression_tests/source_mcpl_file/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/source_mcpl_file/results_true.dat b/tests/regression_tests/source_mcpl_file/results_true.dat deleted file mode 100644 index 3ba1a4520..000000000 --- a/tests/regression_tests/source_mcpl_file/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -2.827397E-01 1.150438E-03 diff --git a/tests/regression_tests/source_mcpl_file/test.py b/tests/regression_tests/source_mcpl_file/test.py deleted file mode 100644 index 6e668ef19..000000000 --- a/tests/regression_tests/source_mcpl_file/test.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -import pytest -import glob -import os -import shutil -from tests.testing_harness import * - -pytestmark = pytest.mark.skipif( - shutil.which("mcpl-config") is None, - reason="mcpl-config command not found in PATH; MCPL is likely not available." -) - -settings1=""" - - eigenvalue - - - 10 - 5 - 1000 - - - -4 -4 -4 4 4 4 - - - -""" - -settings2 = """ - - eigenvalue - 10 - 5 - 1000 - - source.10.{} - - -""" - - -class SourceFileTestHarness(TestHarness): - def execute_test(self): - """Run OpenMC with the appropriate arguments and check the outputs.""" - try: - self._run_openmc() - self._test_output_created() - self._run_openmc_restart() - results = self._get_results() - self._write_results(results) - self._compare_results() - finally: - self._cleanup() - - def update_results(self): - """Update the results_true using the current version of OpenMC.""" - try: - self._run_openmc() - self._test_output_created() - self._run_openmc_restart() - results = self._get_results() - self._write_results(results) - self._overwrite_results() - finally: - self._cleanup() - - def _test_output_created(self): - """Make sure statepoint and source files have been created.""" - statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name)) - assert len(statepoint) == 1, 'Either multiple or no statepoint files ' \ - 'exist.' - assert statepoint[0].endswith('h5'), \ - 'Statepoint file is not a HDF5 file.' - - source = glob.glob(os.path.join(os.getcwd(), 'source.10.mcpl*')) - assert len(source) == 1, 'Either multiple or no source files exist.' - assert source[0].endswith('mcpl') or source[0].endswith('mcpl.gz'), \ - 'Source file is not a MCPL file.' - - def _run_openmc_restart(self): - # Get the name of the source file. - source = glob.glob(os.path.join(os.getcwd(), 'source.10.*')) - - # Write the new settings.xml file. - with open('settings.xml','w') as fh: - fh.write(settings2.format(source[0].split('.')[-1])) - - # Run OpenMC. - self._run_openmc() - - def _cleanup(self): - TestHarness._cleanup(self) - output = glob.glob(os.path.join(os.getcwd(), 'source.*')) - with open('settings.xml','w') as fh: - fh.write(settings1) - - -def test_source_file(): - harness = SourceFileTestHarness('statepoint.10.h5') - harness.main() diff --git a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat index 088d65ada..f4a0eba73 100644 --- a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat @@ -1,35 +1,23 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - 0 - - - - - 1 - - - 0.0 2000.0 1000000.0 - - - 1 2 - flux - - - + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + 0 + + diff --git a/tests/regression_tests/source_parameterized_dlopen/parameterized_source_sampling.cpp b/tests/regression_tests/source_parameterized_dlopen/parameterized_source_sampling.cpp index 81f3770c6..bf49af4c3 100644 --- a/tests/regression_tests/source_parameterized_dlopen/parameterized_source_sampling.cpp +++ b/tests/regression_tests/source_parameterized_dlopen/parameterized_source_sampling.cpp @@ -2,37 +2,36 @@ #include "openmc/source.h" class CustomSource : public openmc::Source { -public: - CustomSource(double energy) : energy_(energy) {} + public: + CustomSource(double energy) : energy_(energy) { } - // Samples from an instance of this class. - openmc::SourceSite sample(uint64_t* seed) const - { - openmc::SourceSite particle; - // wgt - particle.particle = openmc::ParticleType::neutron(); - particle.wgt = 1.0; - // position - particle.r.x = 0.0; - particle.r.y = 0.0; - particle.r.z = 0.0; - // angle - particle.u = {1.0, 0.0, 0.0}; - particle.E = this->energy_; - particle.delayed_group = 0; + // Samples from an instance of this class. + openmc::SourceSite sample(uint64_t* seed) const + { + openmc::SourceSite particle; + // wgt + particle.particle = openmc::ParticleType::neutron; + particle.wgt = 1.0; + // position + particle.r.x = 0.0; + particle.r.y = 0.0; + particle.r.z = 0.0; + // angle + particle.u = {1.0, 0.0, 0.0}; + particle.E = this->energy_; + particle.delayed_group = 0; - return particle; - } + return particle; + } -private: - double energy_; + private: + 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 openmc_create_source( - std::string parameter) +// 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 openmc_create_source(std::string parameter) { double energy = std::stod(parameter); return std::make_unique(energy); diff --git a/tests/regression_tests/source_parameterized_dlopen/results_true.dat b/tests/regression_tests/source_parameterized_dlopen/results_true.dat index 1cddaf802..e69de29bb 100644 --- a/tests/regression_tests/source_parameterized_dlopen/results_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/results_true.dat @@ -1,5 +0,0 @@ -tally 1: -1.445856E+04 -2.090732E+07 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/source_parameterized_dlopen/test.py b/tests/regression_tests/source_parameterized_dlopen/test.py index 151fb3735..c613cde4b 100644 --- a/tests/regression_tests/source_parameterized_dlopen/test.py +++ b/tests/regression_tests/source_parameterized_dlopen/test.py @@ -18,7 +18,7 @@ def compile_source(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc_sources CXX) add_library(source SHARED parameterized_source_sampling.cpp) find_package(OpenMC REQUIRED HINTS {}) @@ -61,17 +61,9 @@ def model(): model.settings.particles = 1000 model.settings.run_mode = 'fixed source' - tally = openmc.Tally() - mat_filter = openmc.MaterialFilter([natural_lead]) - # energy filter with two bins 0 eV - 1 keV and 1 keV - 1 MeV - # the second bin shouldn't have any results - energy_filter = openmc.EnergyFilter([0.0, 2e3, 1e6]) - tally.filters = [mat_filter, energy_filter] - tally.scores = ['flux'] - model.tallies = openmc.Tallies([tally]) - # custom source from shared library - source = openmc.CompiledSource('build/libsource.so') + source = openmc.Source() + source.library = 'build/libsource.so' source.parameters = '1e3' model.settings.source = source diff --git a/tests/regression_tests/sourcepoint_batch/results_true.dat b/tests/regression_tests/sourcepoint_batch/results_true.dat index 3665bdd08..4cd4e623d 100644 --- a/tests/regression_tests/sourcepoint_batch/results_true.dat +++ b/tests/regression_tests/sourcepoint_batch/results_true.dat @@ -1,3 +1,3 @@ k-combined: -2.920435E-01 9.109227E-04 -1.101997E+00 -8.197502E+00 4.294606E+00 +3.003690E-01 3.923324E-03 +-5.424825E+00 -4.990262E+00 -6.395029E+00 diff --git a/tests/regression_tests/sourcepoint_latest/results_true.dat b/tests/regression_tests/sourcepoint_latest/results_true.dat index 97b997ae6..fe46748c8 100644 --- a/tests/regression_tests/sourcepoint_latest/results_true.dat +++ b/tests/regression_tests/sourcepoint_latest/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 diff --git a/tests/regression_tests/sourcepoint_restart/results_true.dat b/tests/regression_tests/sourcepoint_restart/results_true.dat index c20b5f2a0..965dc45b1 100644 --- a/tests/regression_tests/sourcepoint_restart/results_true.dat +++ b/tests/regression_tests/sourcepoint_restart/results_true.dat @@ -1,78 +1,14 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 tally 1: -1.300000E-02 -3.900000E-05 -5.833114E-03 -7.476880E-06 +1.400000E-02 +5.000000E-05 +5.637968E-03 +7.140222E-06 0.000000E+00 0.000000E+00 -1.164000E-03 -5.072152E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.100000E-02 -1.110000E-04 -1.108363E-02 -2.889480E-05 -0.000000E+00 -0.000000E+00 -5.861433E-04 -3.435640E-07 -2.000000E-03 -2.000000E-06 -2.043490E-03 -1.793389E-06 -2.000000E-03 -2.000000E-06 -2.930717E-04 -8.589100E-08 -2.000000E-02 -9.000000E-05 -9.334862E-03 -1.853104E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.500000E-02 -1.430000E-04 -1.110224E-02 -2.872840E-05 -0.000000E+00 -0.000000E+00 -5.833203E-04 -1.701353E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.000000E-03 -1.100000E-05 -1.752967E-03 -1.027501E-06 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 +8.891645E-04 +4.440759E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -82,237 +18,381 @@ tally 1: 0.000000E+00 0.000000E+00 1.800000E-02 -7.600000E-05 -7.300761E-03 -1.254112E-05 +7.200000E-05 +8.618270E-03 +1.620709E-05 +0.000000E+00 +0.000000E+00 +2.884266E-04 +8.318989E-08 +0.000000E+00 +0.000000E+00 +8.903211E-04 +7.926717E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.300000E-02 +2.290000E-04 +1.685675E-02 +6.105228E-05 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +1.000000E-03 +1.000000E-06 +2.884266E-04 +8.318989E-08 +1.500000E-02 +6.300000E-05 +7.665313E-03 +1.617331E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-02 +6.900000E-05 +5.663296E-03 +1.118218E-05 +0.000000E+00 +0.000000E+00 +1.198138E-03 +8.972573E-07 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +1.300000E-02 +6.300000E-05 +5.687181E-03 +1.121031E-05 +0.000000E+00 +0.000000E+00 +5.963216E-04 +1.778036E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.500000E-02 +6.100000E-05 +1.040584E-02 +2.402892E-05 +0.000000E+00 +0.000000E+00 +5.879206E-04 +1.728865E-07 +0.000000E+00 +0.000000E+00 +8.903211E-04 +7.926717E-07 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +4.200000E-02 +3.880000E-04 +1.781042E-02 +7.329257E-05 +0.000000E+00 +0.000000E+00 +5.990419E-04 +1.794256E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.200000E-02 +1.220000E-04 +9.854350E-03 +2.671897E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.200000E-02 +4.400000E-05 +5.595730E-03 +9.201460E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.000000E-03 +1.000000E-05 +2.391548E-03 +1.608867E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +2.600000E-02 +1.920000E-04 +1.211360E-02 +3.507456E-05 +0.000000E+00 +0.000000E+00 +8.763472E-04 +4.224562E-07 +0.000000E+00 +0.000000E+00 +1.799697E-03 +1.260606E-06 +2.000000E-03 +2.000000E-06 +0.000000E+00 +0.000000E+00 +3.500000E-02 +2.750000E-04 +1.685749E-02 +6.486072E-05 +0.000000E+00 +0.000000E+00 +9.011069E-04 +8.119936E-07 +0.000000E+00 +0.000000E+00 +1.494965E-03 +1.523738E-06 +3.000000E-03 +5.000000E-06 +2.995479E-04 +8.972896E-08 +2.600000E-02 +1.600000E-04 +1.275573E-02 +3.540061E-05 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +2.000000E-03 +2.000000E-06 +1.794352E-03 +1.254260E-06 +2.000000E-03 +2.000000E-06 +0.000000E+00 +0.000000E+00 +1.000000E-02 +3.800000E-05 +4.799173E-03 +8.824671E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.000000E-03 +3.100000E-05 +4.430081E-03 +6.185529E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +3.291067E-03 +4.033124E-06 +1.000000E-03 +1.000000E-06 +5.971427E-04 +1.782961E-07 +2.800000E-02 +1.660000E-04 +1.217803E-02 +3.047875E-05 +0.000000E+00 +0.000000E+00 +9.011069E-04 +8.119936E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.300000E-02 +2.930000E-04 +1.600563E-02 +6.991498E-05 +0.000000E+00 +0.000000E+00 +5.962677E-04 +1.777713E-07 +0.000000E+00 +0.000000E+00 +8.958696E-04 +4.469905E-07 +2.000000E-03 +2.000000E-06 +0.000000E+00 +0.000000E+00 +1.800000E-02 +8.200000E-05 +8.048487E-03 +1.779097E-05 +0.000000E+00 +0.000000E+00 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.000000E-03 +5.000000E-06 +2.664923E-03 +2.009218E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +1.600000E-02 +7.000000E-05 +7.128932E-03 +1.345969E-05 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.200000E-02 +2.360000E-04 +1.452343E-02 +4.653003E-05 +0.000000E+00 +0.000000E+00 +2.995479E-04 +8.972896E-08 0.000000E+00 0.000000E+00 -5.841969E-04 -1.706438E-07 0.000000E+00 0.000000E+00 -5.861433E-04 -3.435640E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 3.000000E-02 -1.820000E-04 -1.518122E-02 -4.757233E-05 +2.160000E-04 +1.327819E-02 +4.230384E-05 0.000000E+00 0.000000E+00 -2.927374E-04 -8.569516E-08 -2.000000E-03 -2.000000E-06 -2.631167E-03 -3.503358E-06 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -2.500000E-02 -1.390000E-04 -9.343205E-03 -1.910189E-05 +8.958157E-04 +2.675003E-07 0.000000E+00 0.000000E+00 -2.039724E-03 -1.271217E-06 -1.000000E-03 -1.000000E-06 -5.861433E-04 -3.435640E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.400000E-02 -1.340000E-04 -1.080336E-02 -2.533338E-05 -0.000000E+00 -0.000000E+00 -2.914595E-04 -8.494867E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.400000E-02 -5.200000E-05 -6.711472E-03 -1.216306E-05 -0.000000E+00 -0.000000E+00 -5.847809E-04 -1.709846E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.700000E-02 -7.900000E-05 -6.413106E-03 -1.186604E-05 -0.000000E+00 -0.000000E+00 -5.861433E-04 -3.435640E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.900000E-02 -1.770000E-04 -1.314196E-02 -3.678739E-05 -0.000000E+00 -0.000000E+00 -1.167073E-03 -5.110971E-07 -0.000000E+00 -0.000000E+00 -5.861433E-04 -3.435640E-07 +5.768531E-04 +3.327596E-07 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -2.900000E-02 -1.830000E-04 -1.372758E-02 -4.360498E-05 +2.100000E-02 +1.150000E-04 +1.005499E-02 +2.671941E-05 0.000000E+00 0.000000E+00 -5.858090E-04 -1.715862E-07 +1.192535E-03 +7.110852E-07 0.000000E+00 0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.200000E-02 -1.000000E-04 -9.631311E-03 -2.001285E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.829191E-04 -3.397947E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -1.800000E-05 -4.094439E-03 -4.622331E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.170949E-03 -1.371123E-06 +2.995479E-04 +8.972896E-08 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -9.000000E-03 -5.100000E-05 -4.664405E-03 -1.087264E-05 +1.200000E-02 +4.600000E-05 +6.223479E-03 +9.948264E-06 0.000000E+00 0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.200000E-02 -1.300000E-04 -9.644227E-03 -2.300481E-05 -0.000000E+00 -0.000000E+00 -8.771587E-04 -4.270487E-07 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.500000E-02 -1.630000E-04 -1.257283E-02 -3.946813E-05 -0.000000E+00 -0.000000E+00 -1.171259E-03 -8.583084E-07 -0.000000E+00 -0.000000E+00 -1.462299E-03 -1.112414E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.400000E-02 -1.400000E-04 -1.138156E-02 -3.565057E-05 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.100000E-05 -4.383252E-03 -6.073597E-06 -0.000000E+00 -0.000000E+00 -8.707460E-04 -7.581986E-07 +2.884266E-04 +8.318989E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -323,220 +403,236 @@ tally 1: 0.000000E+00 1.100000E-02 3.500000E-05 -6.410606E-03 -1.066242E-05 +5.341464E-03 +7.422119E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.700000E-02 +8.500000E-05 +7.089406E-03 +1.347399E-05 +0.000000E+00 +0.000000E+00 +5.768531E-04 +3.327596E-07 +0.000000E+00 +0.000000E+00 +8.764011E-04 +4.224885E-07 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +2.300000E-02 +1.430000E-04 +1.185149E-02 +3.938904E-05 +0.000000E+00 +0.000000E+00 +2.080112E-03 +1.332746E-06 +0.000000E+00 +0.000000E+00 +1.198138E-03 +8.972573E-07 +1.000000E-03 +1.000000E-06 +5.989880E-04 +3.587866E-07 +3.000000E-02 +2.020000E-04 +1.190088E-02 +2.985574E-05 +0.000000E+00 +0.000000E+00 +5.971427E-04 +1.782961E-07 +0.000000E+00 +0.000000E+00 +2.651470E-03 +2.516819E-06 +4.000000E-03 +6.000000E-06 +0.000000E+00 +0.000000E+00 +1.200000E-02 +3.800000E-05 +5.332038E-03 +7.371181E-06 +0.000000E+00 +0.000000E+00 +3.003690E-04 +9.022151E-08 +0.000000E+00 +0.000000E+00 +2.995479E-04 +8.972896E-08 +1.000000E-03 +1.000000E-06 +2.995479E-04 +8.972896E-08 +3.000000E-03 +3.000000E-06 +2.087327E-03 +1.859777E-06 +0.000000E+00 +0.000000E+00 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.100000E-02 +2.510000E-04 +1.448290E-02 +4.809715E-05 +0.000000E+00 +0.000000E+00 +1.162053E-03 +8.367836E-07 +0.000000E+00 +0.000000E+00 +1.475335E-03 +1.140030E-06 +1.000000E-03 +1.000000E-06 +2.884266E-04 +8.318989E-08 +3.200000E-02 +2.220000E-04 +1.427003E-02 +4.164437E-05 +0.000000E+00 +0.000000E+00 +8.855692E-04 +2.614860E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +2.400000E-05 +3.864325E-03 +4.535592E-06 +0.000000E+00 +0.000000E+00 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +2.065114E-03 +1.468511E-06 +3.000000E-03 +3.000000E-06 +0.000000E+00 +0.000000E+00 1.000000E-03 1.000000E-06 -8.756564E-04 -4.254898E-07 +1.170401E-03 +6.850581E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +3.000000E-05 +4.121850E-03 +5.320749E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.100000E-02 +2.170000E-04 +1.483273E-02 +4.914676E-05 +0.000000E+00 +0.000000E+00 +8.763472E-04 +4.224562E-07 +0.000000E+00 +0.000000E+00 +3.003690E-04 +9.022151E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.300000E-02 +2.310000E-04 +1.399272E-02 +4.084044E-05 +0.000000E+00 +0.000000E+00 +1.499382E-03 +1.168447E-06 +1.000000E-03 +1.000000E-06 +8.930414E-04 +4.419952E-07 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 1.600000E-02 -6.000000E-05 -7.287540E-03 -1.279808E-05 +7.000000E-05 +7.077099E-03 +1.371332E-05 0.000000E+00 0.000000E+00 -5.822922E-04 -1.695337E-07 +2.994940E-04 +8.969666E-08 0.000000E+00 0.000000E+00 -1.172287E-03 -1.374256E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -3.400000E-02 -2.820000E-04 -1.603656E-02 -6.229803E-05 -0.000000E+00 -0.000000E+00 -1.460479E-03 -7.689660E-07 -1.000000E-03 -1.000000E-06 -1.165972E-03 -6.797578E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.900000E-02 -8.500000E-05 -7.880322E-03 -1.387762E-05 -0.000000E+00 -0.000000E+00 -8.755466E-04 -4.261064E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -2.400000E-05 -4.666802E-03 -4.926489E-06 -0.000000E+00 -0.000000E+00 -5.829191E-04 -3.397947E-07 -0.000000E+00 -0.000000E+00 -8.759908E-04 -4.256857E-07 -2.000000E-03 -2.000000E-06 -0.000000E+00 -0.000000E+00 -1.500000E-02 -5.900000E-05 -8.180347E-03 -1.622409E-05 -0.000000E+00 -0.000000E+00 -2.902487E-04 -8.424429E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.300000E-02 -1.390000E-04 -7.593262E-03 -1.708292E-05 -0.000000E+00 -0.000000E+00 -1.750169E-03 -1.193182E-06 -1.000000E-03 -1.000000E-06 -1.461465E-03 -7.684663E-07 +1.497740E-03 +2.243224E-06 2.000000E-03 4.000000E-06 -2.914595E-04 -8.494867E-08 -2.300000E-02 -1.350000E-04 -9.639670E-03 -2.161898E-05 -0.000000E+00 -0.000000E+00 -8.781869E-04 -4.288534E-07 -0.000000E+00 -0.000000E+00 -8.707460E-04 -7.581986E-07 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.100000E-02 -1.090000E-04 -9.045520E-03 -2.171457E-05 -0.000000E+00 -0.000000E+00 -5.851152E-04 -1.711804E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -7.000000E-05 -1.167023E-02 -2.840320E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -5.854747E-04 -3.427806E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.000000E-03 -5.000000E-06 -1.171618E-03 -6.863446E-07 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.300000E-02 -4.500000E-05 -6.428153E-03 -9.064469E-06 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -9.000000E-05 -8.185938E-03 -1.967120E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.300000E-05 -4.665341E-03 -5.426897E-06 0.000000E+00 0.000000E+00 +1.000000E-02 +3.400000E-05 +3.528506E-03 +4.251243E-06 0.000000E+00 0.000000E+00 +5.879206E-04 +1.728865E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -546,9 +642,13 @@ tally 1: 0.000000E+00 0.000000E+00 4.000000E-03 -4.000000E-06 -3.497088E-03 -3.563633E-06 +6.000000E-06 +9.002859E-04 +4.506150E-07 +0.000000E+00 +0.000000E+00 +8.939164E-04 +4.425201E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -557,62 +657,234 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +1.500000E-02 +5.500000E-05 +7.400046E-03 +1.140009E-05 +0.000000E+00 +0.000000E+00 +5.990419E-04 +1.794256E-07 +0.000000E+00 +0.000000E+00 +8.903211E-04 +7.926717E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.000000E-03 -9.000000E-06 -2.333045E-03 -1.870613E-06 +1.800000E-02 +7.400000E-05 +7.695028E-03 +1.396744E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -0.000000E+00 -0.000000E+00 -1.172287E-03 -1.374256E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -2.200000E-05 -6.413648E-03 -1.136518E-05 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 1.000000E-03 1.000000E-06 +5.990959E-04 +3.589159E-07 0.000000E+00 0.000000E+00 +0.000000E+00 +0.000000E+00 +2.400000E-02 +1.260000E-04 +1.220791E-02 +3.565074E-05 +0.000000E+00 +0.000000E+00 +2.995479E-04 +8.972896E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.000000E-03 +2.500000E-05 +3.572884E-03 +4.101061E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.935474E-04 +3.522985E-07 +1.000000E-03 +1.000000E-06 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +3.800000E-05 +5.382607E-03 +1.128619E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.200000E-02 +4.600000E-05 +6.554978E-03 +9.995681E-06 +0.000000E+00 +0.000000E+00 +2.884266E-04 +8.318989E-08 +0.000000E+00 +0.000000E+00 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.000000E-03 +1.100000E-05 +3.868525E-03 +3.829197E-06 +0.000000E+00 +0.000000E+00 +5.935474E-04 +3.522985E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +5.989880E-04 +3.587866E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-02 +3.100000E-05 +4.132972E-03 +4.495389E-06 +0.000000E+00 +0.000000E+00 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +1.000000E-03 +1.000000E-06 +2.967737E-04 +8.807464E-08 2.000000E-02 -1.200000E-04 -7.007604E-03 -1.379504E-05 +9.200000E-05 +8.597951E-03 +1.801722E-05 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.200000E-02 +3.200000E-05 +6.509749E-03 +9.403130E-06 +0.000000E+00 +0.000000E+00 +3.003690E-04 +9.022151E-08 +0.000000E+00 +0.000000E+00 +5.990959E-04 +3.589159E-07 0.000000E+00 0.000000E+00 -5.851152E-04 -1.711804E-07 0.000000E+00 0.000000E+00 -5.861433E-04 -3.435640E-07 1.000000E-03 1.000000E-06 +2.884266E-04 +8.318989E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 -1.700000E-02 -7.900000E-05 -7.281401E-03 -1.600845E-05 0.000000E+00 0.000000E+00 0.000000E+00 @@ -626,301 +898,13 @@ tally 1: 0.000000E+00 0.000000E+00 7.000000E-03 -1.900000E-05 -3.218959E-03 -4.543526E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -1.900000E-05 -4.380921E-03 -4.182826E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.100000E-02 -1.050000E-04 -9.932207E-03 -2.153598E-05 -0.000000E+00 -0.000000E+00 -5.854747E-04 -3.427806E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -7.400000E-05 -7.301011E-03 -1.358176E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.804973E-04 -3.369772E-07 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.300000E-02 -1.610000E-04 -9.647933E-03 -2.657983E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -1.900000E-05 -2.915422E-03 -2.203274E-06 -0.000000E+00 -0.000000E+00 -8.775182E-04 -4.280701E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.000000E-03 -9.000000E-06 -2.044244E-03 -1.796182E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -9.000000E-05 -6.718632E-03 -1.203946E-05 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.100000E-02 -2.700000E-05 -4.675703E-03 -5.128811E-06 -0.000000E+00 -0.000000E+00 -2.914595E-04 -8.494867E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -2.914595E-04 -8.494867E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -2.600000E-05 -4.670349E-03 -6.133014E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.500000E-02 -6.100000E-05 -8.751735E-03 -1.922421E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.400000E-02 -5.000000E-05 -6.126605E-03 -9.620966E-06 -0.000000E+00 -0.000000E+00 -5.835031E-04 -1.702381E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-03 -2.000000E-06 -5.847809E-04 -1.709846E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-03 -2.000000E-06 -8.719569E-04 -4.219258E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.700000E-05 -4.085939E-03 -4.936434E-06 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.500000E-05 -5.846700E-03 -9.739696E-06 -0.000000E+00 -0.000000E+00 +2.100000E-05 +3.890163E-03 +6.545535E-06 0.000000E+00 0.000000E+00 +2.995479E-04 +8.972896E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -930,17 +914,33 @@ tally 1: 0.000000E+00 0.000000E+00 1.300000E-02 -3.900000E-05 -6.128455E-03 -1.013669E-05 +4.300000E-05 +6.485840E-03 +1.112994E-05 0.000000E+00 0.000000E+00 -5.851152E-04 -1.711804E-07 +5.989880E-04 +3.587866E-07 0.000000E+00 0.000000E+00 -1.172287E-03 -1.374256E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.500000E-02 +4.900000E-05 +7.442524E-03 +1.164759E-05 +0.000000E+00 +0.000000E+00 +2.994940E-04 +8.969666E-08 +1.000000E-03 +1.000000E-06 +5.768531E-04 +3.327596E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -962,11 +962,11 @@ tally 1: 0.000000E+00 0.000000E+00 tally 2: -5.554367E-01 -6.170503E-02 -6.055520E-01 -7.334109E-02 -3.526894E+00 -2.488065E+00 -3.925114E+01 -3.081807E+02 +5.649702E-01 +6.385502E-02 +6.158199E-01 +7.586795E-02 +3.579551E+00 +2.563396E+00 +3.982345E+01 +3.172536E+02 diff --git a/tests/regression_tests/albedo_box/__init__.py b/tests/regression_tests/statepoint_batch/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from tests/regression_tests/albedo_box/__init__.py rename to tests/regression_tests/statepoint_batch/__init__.py diff --git a/tests/regression_tests/source_mcpl_file/geometry.xml b/tests/regression_tests/statepoint_batch/geometry.xml similarity index 100% rename from tests/regression_tests/source_mcpl_file/geometry.xml rename to tests/regression_tests/statepoint_batch/geometry.xml diff --git a/tests/regression_tests/albedo_box/materials.xml b/tests/regression_tests/statepoint_batch/materials.xml similarity index 100% rename from tests/regression_tests/albedo_box/materials.xml rename to tests/regression_tests/statepoint_batch/materials.xml diff --git a/tests/regression_tests/statepoint_batch/results_true.dat b/tests/regression_tests/statepoint_batch/results_true.dat new file mode 100644 index 000000000..cde417d0e --- /dev/null +++ b/tests/regression_tests/statepoint_batch/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +2.985923E-01 2.864193E-03 diff --git a/tests/regression_tests/albedo_box/settings.xml b/tests/regression_tests/statepoint_batch/settings.xml similarity index 52% rename from tests/regression_tests/albedo_box/settings.xml rename to tests/regression_tests/statepoint_batch/settings.xml index cc6668305..e2f8dad47 100644 --- a/tests/regression_tests/albedo_box/settings.xml +++ b/tests/regression_tests/statepoint_batch/settings.xml @@ -1,9 +1,17 @@ + + eigenvalue 10 5 1000 + + + -4 -4 -4 4 4 4 + + + diff --git a/tests/regression_tests/statepoint_batch/test.py b/tests/regression_tests/statepoint_batch/test.py new file mode 100644 index 000000000..323b28fc6 --- /dev/null +++ b/tests/regression_tests/statepoint_batch/test.py @@ -0,0 +1,18 @@ +from tests.testing_harness import TestHarness + + +class StatepointTestHarness(TestHarness): + def __init__(self): + super().__init__(None) + + def _test_output_created(self): + """Make sure statepoint files have been created.""" + sps = ('statepoint.03.h5', 'statepoint.06.h5', 'statepoint.09.h5') + for sp in sps: + self._sp_name = sp + TestHarness._test_output_created(self) + + +def test_statepoint_batch(): + harness = StatepointTestHarness() + harness.main() diff --git a/tests/regression_tests/statepoint_restart/results_true.dat b/tests/regression_tests/statepoint_restart/results_true.dat index b919b3000..0809b902e 100644 --- a/tests/regression_tests/statepoint_restart/results_true.dat +++ b/tests/regression_tests/statepoint_restart/results_true.dat @@ -1,18 +1,138 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 tally 1: +1.400000E-02 +5.000000E-05 +1.400000E-02 +5.000000E-05 +5.637968E-03 +7.140222E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.891645E-04 +4.440759E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.800000E-02 +7.200000E-05 +1.800000E-02 +7.200000E-05 +8.618270E-03 +1.620709E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.884266E-04 +8.318989E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.903211E-04 +7.926717E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.300000E-02 +2.290000E-04 +3.300000E-02 +2.290000E-04 +1.685675E-02 +6.105228E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.884266E-04 +8.318989E-08 +1.500000E-02 +6.300000E-05 +1.500000E-02 +6.300000E-05 +7.665313E-03 +1.617331E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-02 +6.900000E-05 +1.100000E-02 +6.900000E-05 +5.663296E-03 +1.118218E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.198138E-03 +8.972573E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 1.300000E-02 -3.900000E-05 +6.300000E-05 1.300000E-02 -3.900000E-05 -5.833114E-03 -7.476880E-06 +6.300000E-05 +5.687181E-03 +1.121031E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.164000E-03 -5.072152E-07 +5.963216E-04 +1.778036E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -25,36 +145,204 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -2.100000E-02 -1.110000E-04 -2.100000E-02 -1.110000E-04 -1.108363E-02 -2.889480E-05 +1.500000E-02 +6.100000E-05 +1.500000E-02 +6.100000E-05 +1.040584E-02 +2.402892E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.861433E-04 -3.435640E-07 +5.879206E-04 +1.728865E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.903211E-04 +7.926717E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +4.200000E-02 +3.880000E-04 +4.200000E-02 +3.880000E-04 +1.781042E-02 +7.329257E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.990419E-04 +1.794256E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.200000E-02 +1.220000E-04 +2.200000E-02 +1.220000E-04 +9.854350E-03 +2.671897E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.200000E-02 +4.400000E-05 +1.200000E-02 +4.400000E-05 +5.595730E-03 +9.201460E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.000000E-03 +1.000000E-05 +6.000000E-03 +1.000000E-05 +2.391548E-03 +1.608867E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +2.600000E-02 +1.920000E-04 +2.600000E-02 +1.920000E-04 +1.211360E-02 +3.507456E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.763472E-04 +4.224562E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.799697E-03 +1.260606E-06 2.000000E-03 2.000000E-06 +2.000000E-03 +2.000000E-06 +0.000000E+00 +0.000000E+00 +3.500000E-02 +2.750000E-04 +3.500000E-02 +2.750000E-04 +1.685749E-02 +6.486072E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.011069E-04 +8.119936E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.494965E-03 +1.523738E-06 3.000000E-03 5.000000E-06 -2.043490E-03 -1.793389E-06 +3.000000E-03 +5.000000E-06 +2.995479E-04 +8.972896E-08 +2.600000E-02 +1.600000E-04 +2.600000E-02 +1.600000E-04 +1.275573E-02 +3.540061E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.989880E-04 +3.587866E-07 2.000000E-03 2.000000E-06 2.000000E-03 2.000000E-06 -2.930717E-04 -8.589100E-08 -2.000000E-02 -9.000000E-05 -2.000000E-02 -9.000000E-05 -9.334862E-03 -1.853104E-05 +1.794352E-03 +1.254260E-06 +2.000000E-03 +2.000000E-06 +2.000000E-03 +2.000000E-06 +0.000000E+00 +0.000000E+00 +1.000000E-02 +3.800000E-05 +1.000000E-02 +3.800000E-05 +4.799173E-03 +8.824671E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -73,18 +361,42 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -2.500000E-02 -1.430000E-04 -2.500000E-02 -1.430000E-04 -1.110224E-02 -2.872840E-05 +9.000000E-03 +3.100000E-05 +9.000000E-03 +3.100000E-05 +4.430081E-03 +6.185529E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.833203E-04 -1.701353E-07 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +2.000000E-03 +4.000000E-06 +3.291067E-03 +4.033124E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +5.971427E-04 +1.782961E-07 +2.800000E-02 +1.660000E-04 +2.800000E-02 +1.660000E-04 +1.217803E-02 +3.047875E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.011069E-04 +8.119936E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -97,48 +409,120 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -5.000000E-03 -1.100000E-05 -5.000000E-03 -1.100000E-05 -1.752967E-03 -1.027501E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 +3.300000E-02 +2.930000E-04 +3.300000E-02 +2.930000E-04 +1.600563E-02 +6.991498E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +5.962677E-04 +1.777713E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +8.958696E-04 +4.469905E-07 +2.000000E-03 +2.000000E-06 +2.000000E-03 +2.000000E-06 0.000000E+00 0.000000E+00 1.800000E-02 -7.600000E-05 +8.200000E-05 1.800000E-02 -7.600000E-05 -7.300761E-03 -1.254112E-05 +8.200000E-05 +8.048487E-03 +1.779097E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.841969E-04 -1.706438E-07 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.000000E-03 +5.000000E-06 +3.000000E-03 +5.000000E-06 +2.664923E-03 +2.009218E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +1.600000E-02 +7.000000E-05 +1.600000E-02 +7.000000E-05 +7.128932E-03 +1.345969E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.200000E-02 +2.360000E-04 +3.200000E-02 +2.360000E-04 +1.452343E-02 +4.653003E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.995479E-04 +8.972896E-08 +0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.861433E-04 -3.435640E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -146,329 +530,65 @@ tally 1: 0.000000E+00 0.000000E+00 3.000000E-02 -1.820000E-04 +2.160000E-04 3.000000E-02 -1.820000E-04 -1.518122E-02 -4.757233E-05 +2.160000E-04 +1.327819E-02 +4.230384E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.927374E-04 -8.569516E-08 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 -2.631167E-03 -3.503358E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -2.500000E-02 -1.390000E-04 -2.500000E-02 -1.390000E-04 -9.343205E-03 -1.910189E-05 +8.958157E-04 +2.675003E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.039724E-03 -1.271217E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -5.861433E-04 -3.435640E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.400000E-02 -1.340000E-04 -2.400000E-02 -1.340000E-04 -1.080336E-02 -2.533338E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.914595E-04 -8.494867E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.400000E-02 -5.200000E-05 -1.400000E-02 -5.200000E-05 -6.711472E-03 -1.216306E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.847809E-04 -1.709846E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.700000E-02 -7.900000E-05 -1.700000E-02 -7.900000E-05 -6.413106E-03 -1.186604E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.861433E-04 -3.435640E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.900000E-02 -1.770000E-04 -2.900000E-02 -1.770000E-04 -1.314196E-02 -3.678739E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.167073E-03 -5.110971E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.861433E-04 -3.435640E-07 +5.768531E-04 +3.327596E-07 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -2.900000E-02 -1.830000E-04 -2.900000E-02 -1.830000E-04 -1.372758E-02 -4.360498E-05 +2.100000E-02 +1.150000E-04 +2.100000E-02 +1.150000E-04 +1.005499E-02 +2.671941E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.858090E-04 -1.715862E-07 +1.192535E-03 +7.110852E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.200000E-02 -1.000000E-04 -2.200000E-02 -1.000000E-04 -9.631311E-03 -2.001285E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.829191E-04 -3.397947E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -1.800000E-05 -8.000000E-03 -1.800000E-05 -4.094439E-03 -4.622331E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.170949E-03 -1.371123E-06 +2.995479E-04 +8.972896E-08 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -9.000000E-03 -5.100000E-05 -9.000000E-03 -5.100000E-05 -4.664405E-03 -1.087264E-05 +1.200000E-02 +4.600000E-05 +1.200000E-02 +4.600000E-05 +6.223479E-03 +9.948264E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.200000E-02 -1.300000E-04 -2.200000E-02 -1.300000E-04 -9.644227E-03 -2.300481E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.771587E-04 -4.270487E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.500000E-02 -1.630000E-04 -2.500000E-02 -1.630000E-04 -1.257283E-02 -3.946813E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.171259E-03 -8.583084E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.462299E-03 -1.112414E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.400000E-02 -1.400000E-04 -2.400000E-02 -1.400000E-04 -1.138156E-02 -3.565057E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.100000E-05 -9.000000E-03 -2.100000E-05 -4.383252E-03 -6.073597E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.707460E-04 -7.581986E-07 +2.884266E-04 +8.318989E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -485,20 +605,308 @@ tally 1: 3.500000E-05 1.100000E-02 3.500000E-05 -6.410606E-03 -1.066242E-05 +5.341464E-03 +7.422119E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.700000E-02 +8.500000E-05 +1.700000E-02 +8.500000E-05 +7.089406E-03 +1.347399E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.768531E-04 +3.327596E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.764011E-04 +4.224885E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +0.000000E+00 +0.000000E+00 +2.300000E-02 +1.430000E-04 +2.300000E-02 +1.430000E-04 +1.185149E-02 +3.938904E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.080112E-03 +1.332746E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.198138E-03 +8.972573E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +5.989880E-04 +3.587866E-07 +3.000000E-02 +2.020000E-04 +3.000000E-02 +2.020000E-04 +1.190088E-02 +2.985574E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.971427E-04 +1.782961E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.651470E-03 +2.516819E-06 +4.000000E-03 +6.000000E-06 +4.000000E-03 +6.000000E-06 +0.000000E+00 +0.000000E+00 +1.200000E-02 +3.800000E-05 +1.200000E-02 +3.800000E-05 +5.332038E-03 +7.371181E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.003690E-04 +9.022151E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.995479E-04 +8.972896E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.995479E-04 +8.972896E-08 +3.000000E-03 +3.000000E-06 +3.000000E-03 +3.000000E-06 +2.087327E-03 +1.859777E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.100000E-02 +2.510000E-04 +3.100000E-02 +2.510000E-04 +1.448290E-02 +4.809715E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.162053E-03 +8.367836E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.475335E-03 +1.140030E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.884266E-04 +8.318989E-08 +3.200000E-02 +2.220000E-04 +3.200000E-02 +2.220000E-04 +1.427003E-02 +4.164437E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.855692E-04 +2.614860E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +2.400000E-05 +1.000000E-02 +2.400000E-05 +3.864325E-03 +4.535592E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.065114E-03 +1.468511E-06 +3.000000E-03 +3.000000E-06 +3.000000E-03 +3.000000E-06 +0.000000E+00 +0.000000E+00 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 -8.756564E-04 -4.254898E-07 +1.170401E-03 +6.850581E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +3.000000E-05 +1.000000E-02 +3.000000E-05 +4.121850E-03 +5.320749E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.100000E-02 +2.170000E-04 +3.100000E-02 +2.170000E-04 +1.483273E-02 +4.914676E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.763472E-04 +4.224562E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.003690E-04 +9.022151E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.300000E-02 +2.310000E-04 +3.300000E-02 +2.310000E-04 +1.399272E-02 +4.084044E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.499382E-03 +1.168447E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +8.930414E-04 +4.419952E-07 1.000000E-03 1.000000E-06 1.000000E-03 @@ -506,305 +914,41 @@ tally 1: 0.000000E+00 0.000000E+00 1.600000E-02 -6.000000E-05 +7.000000E-05 1.600000E-02 -6.000000E-05 -7.287540E-03 -1.279808E-05 +7.000000E-05 +7.077099E-03 +1.371332E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.822922E-04 -1.695337E-07 +2.994940E-04 +8.969666E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.172287E-03 -1.374256E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -3.400000E-02 -2.820000E-04 -3.400000E-02 -2.820000E-04 -1.603656E-02 -6.229803E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.460479E-03 -7.689660E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -1.165972E-03 -6.797578E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.900000E-02 -8.500000E-05 -1.900000E-02 -8.500000E-05 -7.880322E-03 -1.387762E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.755466E-04 -4.261064E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -2.400000E-05 -8.000000E-03 -2.400000E-05 -4.666802E-03 -4.926489E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.829191E-04 -3.397947E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.759908E-04 -4.256857E-07 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 -0.000000E+00 -0.000000E+00 -1.500000E-02 -5.900000E-05 -1.500000E-02 -5.900000E-05 -8.180347E-03 -1.622409E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.902487E-04 -8.424429E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.300000E-02 -1.390000E-04 -2.300000E-02 -1.390000E-04 -7.593262E-03 -1.708292E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.750169E-03 -1.193182E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -1.461465E-03 -7.684663E-07 +1.497740E-03 +2.243224E-06 2.000000E-03 4.000000E-06 2.000000E-03 4.000000E-06 -2.914595E-04 -8.494867E-08 -2.300000E-02 -1.350000E-04 -2.300000E-02 -1.350000E-04 -9.639670E-03 -2.161898E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.781869E-04 -4.288534E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.707460E-04 -7.581986E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.100000E-02 -1.090000E-04 -2.100000E-02 -1.090000E-04 -9.045520E-03 -2.171457E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.851152E-04 -1.711804E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -7.000000E-05 -1.800000E-02 -7.000000E-05 -1.167023E-02 -2.840320E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -5.854747E-04 -3.427806E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.000000E-03 -5.000000E-06 -3.000000E-03 -5.000000E-06 -1.171618E-03 -6.863446E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.300000E-02 -4.500000E-05 -1.300000E-02 -4.500000E-05 -6.428153E-03 -9.064469E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -9.000000E-05 -1.800000E-02 -9.000000E-05 -8.185938E-03 -1.967120E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.300000E-05 -9.000000E-03 -2.300000E-05 -4.665341E-03 -5.426897E-06 0.000000E+00 0.000000E+00 +1.000000E-02 +3.400000E-05 +1.000000E-02 +3.400000E-05 +3.528506E-03 +4.251243E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +5.879206E-04 +1.728865E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -818,11 +962,17 @@ tally 1: 0.000000E+00 0.000000E+00 4.000000E-03 -4.000000E-06 +6.000000E-06 4.000000E-03 -4.000000E-06 -3.497088E-03 -3.563633E-06 +6.000000E-06 +9.002859E-04 +4.506150E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.939164E-04 +4.425201E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -835,90 +985,348 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +1.500000E-02 +5.500000E-05 +1.500000E-02 +5.500000E-05 +7.400046E-03 +1.140009E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.990419E-04 +1.794256E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.903211E-04 +7.926717E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.000000E-03 -9.000000E-06 -5.000000E-03 -9.000000E-06 -2.333045E-03 -1.870613E-06 +1.800000E-02 +7.400000E-05 +1.800000E-02 +7.400000E-05 +7.695028E-03 +1.396744E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.172287E-03 -1.374256E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -2.200000E-05 -8.000000E-03 -2.200000E-05 -6.413648E-03 -1.136518E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 +5.990959E-04 +3.589159E-07 0.000000E+00 0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.400000E-02 +1.260000E-04 +2.400000E-02 +1.260000E-04 +1.220791E-02 +3.565074E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.995479E-04 +8.972896E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.000000E-03 +2.500000E-05 +9.000000E-03 +2.500000E-05 +3.572884E-03 +4.101061E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.935474E-04 +3.522985E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +3.800000E-05 +1.000000E-02 +3.800000E-05 +5.382607E-03 +1.128619E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.200000E-02 +4.600000E-05 +1.200000E-02 +4.600000E-05 +6.554978E-03 +9.995681E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.884266E-04 +8.318989E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.000000E-03 +1.100000E-05 +7.000000E-03 +1.100000E-05 +3.868525E-03 +3.829197E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.935474E-04 +3.522985E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +5.989880E-04 +3.587866E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.994940E-04 +8.969666E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.100000E-02 +3.100000E-05 +1.100000E-02 +3.100000E-05 +4.132972E-03 +4.495389E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.967737E-04 +8.807464E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.007379E-04 +3.608860E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +2.967737E-04 +8.807464E-08 2.000000E-02 -1.200000E-04 +9.200000E-05 2.000000E-02 -1.200000E-04 -7.007604E-03 -1.379504E-05 +9.200000E-05 +8.597951E-03 +1.801722E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.851152E-04 -1.711804E-07 +5.989880E-04 +3.587866E-07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.200000E-02 +3.200000E-05 +1.200000E-02 +3.200000E-05 +6.509749E-03 +9.403130E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.003690E-04 +9.022151E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.990959E-04 +3.589159E-07 +0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.861433E-04 -3.435640E-07 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 +2.884266E-04 +8.318989E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 -1.700000E-02 -7.900000E-05 -1.700000E-02 -7.900000E-05 -7.281401E-03 -1.600845E-05 0.000000E+00 0.000000E+00 0.000000E+00 @@ -938,449 +1346,17 @@ tally 1: 0.000000E+00 0.000000E+00 7.000000E-03 -1.900000E-05 +2.100000E-05 7.000000E-03 -1.900000E-05 -3.218959E-03 -4.543526E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -1.900000E-05 -9.000000E-03 -1.900000E-05 -4.380921E-03 -4.182826E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.100000E-02 -1.050000E-04 -2.100000E-02 -1.050000E-04 -9.932207E-03 -2.153598E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.854747E-04 -3.427806E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -7.400000E-05 -1.800000E-02 -7.400000E-05 -7.301011E-03 -1.358176E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.804973E-04 -3.369772E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -2.300000E-02 -1.610000E-04 -2.300000E-02 -1.610000E-04 -9.647933E-03 -2.657983E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -1.900000E-05 -9.000000E-03 -1.900000E-05 -2.915422E-03 -2.203274E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.775182E-04 -4.280701E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.000000E-03 -9.000000E-06 -5.000000E-03 -9.000000E-06 -2.044244E-03 -1.796182E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.800000E-02 -9.000000E-05 -1.800000E-02 -9.000000E-05 -6.718632E-03 -1.203946E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.927374E-04 -8.569516E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.100000E-02 -2.700000E-05 -1.100000E-02 -2.700000E-05 -4.675703E-03 -5.128811E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.914595E-04 -8.494867E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.914595E-04 -8.494867E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.920435E-04 -8.528942E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.000000E-03 -2.600000E-05 -8.000000E-03 -2.600000E-05 -4.670349E-03 -6.133014E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.500000E-02 -6.100000E-05 -1.500000E-02 -6.100000E-05 -8.751735E-03 -1.922421E-05 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.400000E-02 -5.000000E-05 -1.400000E-02 -5.000000E-05 -6.126605E-03 -9.620966E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.835031E-04 -1.702381E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 -5.847809E-04 -1.709846E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 -8.719569E-04 -4.219258E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.700000E-05 -9.000000E-03 -2.700000E-05 -4.085939E-03 -4.936434E-06 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.930717E-04 -8.589100E-08 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.000000E-03 -2.500000E-05 -9.000000E-03 -2.500000E-05 -5.846700E-03 -9.739696E-06 -0.000000E+00 -0.000000E+00 +2.100000E-05 +3.890163E-03 +6.545535E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.995479E-04 +8.972896E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1394,23 +1370,47 @@ tally 1: 0.000000E+00 0.000000E+00 1.300000E-02 -3.900000E-05 +4.300000E-05 1.300000E-02 -3.900000E-05 -6.128455E-03 -1.013669E-05 +4.300000E-05 +6.485840E-03 +1.112994E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.851152E-04 -1.711804E-07 +5.989880E-04 +3.587866E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.172287E-03 -1.374256E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.500000E-02 +4.900000E-05 +1.500000E-02 +4.900000E-05 +7.442524E-03 +1.164759E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.994940E-04 +8.969666E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +5.768531E-04 +3.327596E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1442,11 +1442,11 @@ tally 1: 0.000000E+00 0.000000E+00 tally 2: -5.554367E-01 -6.170503E-02 -6.055520E-01 -7.334109E-02 -3.526894E+00 -2.488065E+00 -3.925114E+01 -3.081807E+02 +5.649702E-01 +6.385502E-02 +6.158199E-01 +7.586795E-02 +3.579551E+00 +2.563396E+00 +3.982345E+01 +3.172536E+02 diff --git a/tests/regression_tests/statepoint_restart/test.py b/tests/regression_tests/statepoint_restart/test.py index 82e514da8..4575607f7 100644 --- a/tests/regression_tests/statepoint_restart/test.py +++ b/tests/regression_tests/statepoint_restart/test.py @@ -1,10 +1,11 @@ -from pathlib import Path +import glob +import os import openmc from tests.testing_harness import TestHarness from tests.regression_tests import config -from tests import cdtemp + class StatepointRestartTestHarness(TestHarness): def __init__(self, final_sp, restart_sp): @@ -41,7 +42,7 @@ class StatepointRestartTestHarness(TestHarness): def _run_openmc_restart(self): # Get the name of the statepoint file. - statepoint = list(Path.cwd().glob(self._restart_sp)) + statepoint = glob.glob(os.path.join(os.getcwd(), self._restart_sp)) assert len(statepoint) == 1 statepoint = statepoint[0] @@ -58,37 +59,3 @@ def test_statepoint_restart(): harness = StatepointRestartTestHarness('statepoint.10.h5', 'statepoint.07.h5') harness.main() - - -def test_batch_check(request, capsys): - xmls = list(request.path.parent.glob('*.xml')) - - with cdtemp(xmls): - model = openmc.Model.from_xml() - model.settings.particles = 100 - - # run the model - sp_file = model.run(export_model_xml=False) - assert sp_file is not None - - # run a restart with the resulting statepoint - # and the settings unchanged - model.settings.batches = 6 - # ensure we capture output only from the next run - capsys.readouterr() - sp_file = model.run(export_model_xml=False, restart_file=sp_file) - # indicates that a new statepoint file was not created - assert sp_file is None - - output = capsys.readouterr().out - assert "WARNING" in output - assert "The number of batches specified for simulation" in output - - # update the number of batches and run again, - # this restart run should be successful - model.settings.batches = 15 - model.settings.statepoint = {} - sp_file = model.run(export_model_xml=False, restart_file=sp_file) - - sp = openmc.StatePoint(sp_file) - assert sp.n_batches == 15 diff --git a/tests/regression_tests/statepoint_sourcesep/results_true.dat b/tests/regression_tests/statepoint_sourcesep/results_true.dat index 97b997ae6..fe46748c8 100644 --- a/tests/regression_tests/statepoint_sourcesep/results_true.dat +++ b/tests/regression_tests/statepoint_sourcesep/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 diff --git a/tests/regression_tests/stride/__init__.py b/tests/regression_tests/stride/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/stride/inputs_true.dat b/tests/regression_tests/stride/inputs_true.dat deleted file mode 100644 index ebae53c05..000000000 --- a/tests/regression_tests/stride/inputs_true.dat +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - -4 -4 -4 4 4 4 - - - 1529170 - - diff --git a/tests/regression_tests/stride/results_true.dat b/tests/regression_tests/stride/results_true.dat deleted file mode 100644 index 825de3766..000000000 --- a/tests/regression_tests/stride/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -2.953207E-01 2.874356E-03 diff --git a/tests/regression_tests/stride/test.py b/tests/regression_tests/stride/test.py deleted file mode 100644 index f911af1f5..000000000 --- a/tests/regression_tests/stride/test.py +++ /dev/null @@ -1,29 +0,0 @@ -import pytest -import openmc - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def model(): - u = openmc.Material() - u.add_nuclide('U235', 1.0) - u.set_density('g/cm3', 4.5) - sph = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=u, region=-sph) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 1000 - model.settings.stride = 1_529_170 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box([-4, -4, -4], [4, 4, 4]) - ) - return model - - -def test_seed(model): - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/surface_source/inputs_true_read.dat b/tests/regression_tests/surface_source/inputs_true_read.dat new file mode 100644 index 000000000..3a122c737 --- /dev/null +++ b/tests/regression_tests/surface_source/inputs_true_read.dat @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + surface_source_true.h5 + + 1 + + + + + 3 + + + 1 + flux + + diff --git a/tests/regression_tests/surface_source/inputs_true_read_h5.dat b/tests/regression_tests/surface_source/inputs_true_read_h5.dat deleted file mode 100644 index 321c11d42..000000000 --- a/tests/regression_tests/surface_source/inputs_true_read_h5.dat +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - surface_source_true.h5 - - 1 - - - - 3 - - - 1 - flux - - - diff --git a/tests/regression_tests/surface_source/inputs_true_read_mcpl.dat b/tests/regression_tests/surface_source/inputs_true_read_mcpl.dat deleted file mode 100644 index 2ee76f618..000000000 --- a/tests/regression_tests/surface_source/inputs_true_read_mcpl.dat +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - surface_source_true.mcpl - - 1 - - - - 3 - - - 1 - flux - - - diff --git a/tests/regression_tests/surface_source/inputs_true_write.dat b/tests/regression_tests/surface_source/inputs_true_write.dat new file mode 100644 index 000000000..48dde9900 --- /dev/null +++ b/tests/regression_tests/surface_source/inputs_true_write.dat @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + 0 0 0 + + + + 1 + 1000 + + 1 + + + + + 3 + + + 1 + flux + + diff --git a/tests/regression_tests/surface_source/inputs_true_write_h5.dat b/tests/regression_tests/surface_source/inputs_true_write_h5.dat deleted file mode 100644 index 10e3af0a7..000000000 --- a/tests/regression_tests/surface_source/inputs_true_write_h5.dat +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - 0 0 0 - - - - 1 - 1000 - - 1 - - - - 3 - - - 1 - flux - - - diff --git a/tests/regression_tests/surface_source/inputs_true_write_mcpl.dat b/tests/regression_tests/surface_source/inputs_true_write_mcpl.dat deleted file mode 100644 index e9758144d..000000000 --- a/tests/regression_tests/surface_source/inputs_true_write_mcpl.dat +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - 0 0 0 - - - - 1 - true - 1000 - - 1 - - - - 3 - - - 1 - flux - - - diff --git a/tests/regression_tests/surface_source/surface_source_true.h5 b/tests/regression_tests/surface_source/surface_source_true.h5 index 02e94c90b..2ea48b2ac 100644 Binary files a/tests/regression_tests/surface_source/surface_source_true.h5 and b/tests/regression_tests/surface_source/surface_source_true.h5 differ diff --git a/tests/regression_tests/surface_source/surface_source_true.mcpl b/tests/regression_tests/surface_source/surface_source_true.mcpl deleted file mode 100644 index ca4b7c2c4..000000000 Binary files a/tests/regression_tests/surface_source/surface_source_true.mcpl and /dev/null differ diff --git a/tests/regression_tests/surface_source/test.py b/tests/regression_tests/surface_source/test.py index 13966b26d..dc60cfd3c 100644 --- a/tests/regression_tests/surface_source/test.py +++ b/tests/regression_tests/surface_source/test.py @@ -7,43 +7,13 @@ import pytest import openmc from tests.testing_harness import PyAPITestHarness -from tests.regression_tests import config - - -def mcpl_to_array(filepath): - import mcpl - - source = [] - with mcpl.MCPLFile(filepath) as f: - for p in f.particles: - source.append( - [ - *tuple(p.position), - *tuple(p.direction), - 1.0e6 * p.ekin, - 1.0e-3 * p.time, - p.weight, - p.pdgcode, - ] - ) - return np.sort(np.array(source), axis=0) - - -def assert_structured_arrays_close(arr1, arr2, rtol=1e-5, atol=1e-8): - assert arr1.dtype == arr2.dtype - - for field in arr1.dtype.names: - data1, data2 = arr1[field], arr2[field] - if data1.dtype.names: - assert_structured_arrays_close(data1, data2, rtol=rtol, atol=atol) - else: - np.testing.assert_allclose(data1, data2, rtol=rtol, atol=atol) @pytest.fixture def model(request): openmc.reset_auto_ids() - operation, file_format = request.node.get_closest_marker("params").args + marker = request.node.get_closest_marker("surf_source_op") + surf_source_op = marker.args[0] openmc_model = openmc.model.Model() @@ -72,19 +42,15 @@ def model(request): openmc_model.settings.batches = 10 openmc_model.settings.seed = 1 - if operation == 'write': + if surf_source_op == 'write': point = openmc.stats.Point((0, 0, 0)) - pt_src = openmc.IndependentSource(space=point) + pt_src = openmc.Source(space=point) openmc_model.settings.source = pt_src - surf_source_write_settings = {'surface_ids': [1], - 'max_particles': 1000} - if file_format == "mcpl": - surf_source_write_settings["mcpl"] = True - - openmc_model.settings.surf_source_write = surf_source_write_settings - elif operation == 'read': - openmc_model.settings.surf_source_read = {'path': f"surface_source_true.{file_format}"} + openmc_model.settings.surf_source_write = {'surface_ids': [1], + 'max_particles': 1000} + elif surf_source_op == 'read': + openmc_model.settings.surf_source_read = {'path': 'surface_source_true.h5'} # Tallies tal = openmc.Tally() @@ -97,30 +63,28 @@ def model(request): class SurfaceSourceTestHarness(PyAPITestHarness): - def __init__(self, statepoint_name, model=None, inputs_true=None, file_format="h5"): - super().__init__(statepoint_name, model, inputs_true) - self.file_format = file_format - def _test_output_created(self): - """Make sure the surface_source file has also been created.""" + """Make sure surface_source.h5 has also been created.""" super()._test_output_created() + # Check if 'surface_source.h5' has been created. if self._model.settings.surf_source_write: - assert os.path.exists(f"surface_source.{self.file_format}"), \ + assert os.path.exists('surface_source.h5'), \ 'Surface source file does not exist.' def _compare_output(self): """Make sure the current surface_source.h5 agree with the reference.""" if self._model.settings.surf_source_write: - if self.file_format == "h5": - with h5py.File("surface_source_true.h5", 'r') as f: - source_true = np.sort(f['source_bank'][()]) - with h5py.File("surface_source.h5", 'r') as f: - source_test = np.sort(f['source_bank'][()]) - assert_structured_arrays_close(source_true, source_test, atol=1e-07) - elif self.file_format == "mcpl": - source_true = mcpl_to_array("surface_source_true.mcpl") - source_test = mcpl_to_array("surface_source.mcpl") - np.testing.assert_allclose(source_true, source_test, rtol=1e-5, atol=1e-7) + with h5py.File("surface_source_true.h5", 'r') as f: + source_true = f['source_bank'][()] + # Convert dtye from mixed to a float for comparison assertion + source_true.dtype = 'float64' + with h5py.File("surface_source.h5", 'r') as f: + source_test = f['source_bank'][()] + # Convert dtye from mixed to a float for comparison assertion + source_test.dtype = 'float64' + np.testing.assert_allclose(np.sort(source_true), + np.sort(source_test), + atol=1e-07) def execute_test(self): """Build input XMLs, run OpenMC, check output and results.""" @@ -141,56 +105,28 @@ class SurfaceSourceTestHarness(PyAPITestHarness): def _overwrite_results(self): """Overwrite the results_true with the results_test.""" shutil.copyfile('results_test.dat', 'results_true.dat') - if os.path.exists(f"surface_source.{self.file_format}"): - shutil.copyfile(f"surface_source.{self.file_format}", f"surface_source_true.{self.file_format}") + if os.path.exists('surface_source.h5'): + shutil.copyfile('surface_source.h5', 'surface_source_true.h5') def _cleanup(self): """Delete statepoints, tally, and test files.""" super()._cleanup() - fs = f"surface_source.{self.file_format}" + fs = 'surface_source.h5' if os.path.exists(fs): os.remove(fs) -@pytest.mark.params('write', 'h5') -def test_surface_source_write(model, monkeypatch, request): - monkeypatch.setitem(config, "mpi_np", "1") # Results generated with 1 MPI process - operation, file_format = request.node.get_closest_marker("params").args - harness = SurfaceSourceTestHarness( - "statepoint.10.h5", model, f"inputs_true_{operation}_{file_format}.dat", - file_format=file_format - ) +@pytest.mark.surf_source_op('write') +def test_surface_source_write(model): + harness = SurfaceSourceTestHarness('statepoint.10.h5', + model, + 'inputs_true_write.dat') harness.main() -@pytest.mark.params('read', 'h5') -def test_surface_source_read(model, request): - operation, file_format = request.node.get_closest_marker("params").args - harness = SurfaceSourceTestHarness( - "statepoint.10.h5", model, f"inputs_true_{operation}_{file_format}.dat", - file_format=file_format - ) - harness.main() - - -@pytest.mark.skipif(shutil.which("mcpl-config") is None, reason="MCPL is not available.") -@pytest.mark.params('write', 'mcpl') -def test_surface_source_write_mcpl(model, monkeypatch, request): - monkeypatch.setitem(config, "mpi_np", "1") # Results generated with 1 MPI process - operation, file_format = request.node.get_closest_marker("params").args - harness = SurfaceSourceTestHarness( - "statepoint.10.h5", model, f"inputs_true_{operation}_{file_format}.dat", - file_format=file_format - ) - harness.main() - - -@pytest.mark.skipif(shutil.which("mcpl-config") is None, reason="MCPL is not available.") -@pytest.mark.params('read', 'mcpl') -def test_surface_source_read_mcpl(model, request): - operation, file_format = request.node.get_closest_marker("params").args - harness = SurfaceSourceTestHarness( - "statepoint.10.h5", model, f"inputs_true_{operation}_{file_format}.dat", - file_format=file_format - ) +@pytest.mark.surf_source_op('read') +def test_surface_source_read(model): + harness = SurfaceSourceTestHarness('statepoint.10.h5', + model, + 'inputs_true_read.dat') harness.main() diff --git a/tests/regression_tests/surface_source_write/__init__.py b/tests/regression_tests/surface_source_write/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/surface_source_write/_visualize.py b/tests/regression_tests/surface_source_write/_visualize.py deleted file mode 100644 index 73340cae0..000000000 --- a/tests/regression_tests/surface_source_write/_visualize.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Helper script to visualize the surface_source.h5 files created with this test. -""" - -import h5py -import matplotlib.pyplot as plt - - -if __name__ == "__main__": - - # Select an option - # "show": 3D visualization using matplotlib - # "savefig": 2D representation using matplotlib and storing the fig under plot_2d.png - option = "show" - # option = "savefig" - - # Select the case from its folder name - folder = "case-20" - - # Reading the surface source file - with h5py.File(f"{folder}/surface_source_true.h5", "r") as fp: - source_bank = fp["source_bank"][()] - r_xs = source_bank['r']['x'] - r_ys = source_bank['r']['y'] - r_zs = source_bank['r']['z'] - - print("Size of the source bank: ", len(source_bank)) - - # Select data range to visualize - idx_1 = 0 - idx_2 = -1 - - # Show 3D representation - if option == "show": - - fig = plt.figure(figsize=(10, 10)) - ax1 = fig.add_subplot(projection="3d", proj_type="ortho") - ax1.scatter(r_xs[idx_1:idx_2], r_ys[idx_1:idx_2], r_zs[idx_1:idx_2], marker=".") - ax1.view_init(0, 0) - ax1.xaxis.set_ticklabels([]) - ax1.set_ylabel("y-axis [cm]") - ax1.set_zlabel("z-axis [cm]") - ax1.set_aspect("equal", "box") - - plt.show() - - # Save 2D representations - elif option == "savefig": - - fig = plt.figure(figsize=(14, 5)) - ax1 = fig.add_subplot(121, projection="3d", proj_type="ortho") - ax1.scatter(r_xs[idx_1:idx_2], r_ys[idx_1:idx_2], r_zs[idx_1:idx_2], marker=".") - ax1.view_init(0, 0) - ax1.xaxis.set_ticklabels([]) - ax1.set_ylabel("y-axis [cm]") - ax1.set_zlabel("z-axis [cm]") - ax1.set_aspect("equal", "box") - - ax2 = fig.add_subplot(122, projection="3d", proj_type="ortho") - ax2.scatter(r_xs[idx_1:idx_2], r_ys[idx_1:idx_2], r_zs[idx_1:idx_2], marker=".") - ax2.view_init(90, -90) - ax2.zaxis.set_ticklabels([]) - ax2.set_xlabel("x-axis [cm]") - ax2.set_ylabel("y-axis [cm]") - ax2.set_aspect("equal", "box") - - plt.savefig("plot_2d.png") diff --git a/tests/regression_tests/surface_source_write/case-01/inputs_true.dat b/tests/regression_tests/surface_source_write/case-01/inputs_true.dat deleted file mode 100644 index 2a67b03dd..000000000 --- a/tests/regression_tests/surface_source_write/case-01/inputs_true.dat +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-01/results_true.dat b/tests/regression_tests/surface_source_write/case-01/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-01/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-01/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-01/surface_source_true.h5 deleted file mode 100644 index 3a2315acc..000000000 Binary files a/tests/regression_tests/surface_source_write/case-01/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-02/inputs_true.dat b/tests/regression_tests/surface_source_write/case-02/inputs_true.dat deleted file mode 100644 index 527f076b9..000000000 --- a/tests/regression_tests/surface_source_write/case-02/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 8 - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-02/results_true.dat b/tests/regression_tests/surface_source_write/case-02/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-02/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-02/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-02/surface_source_true.h5 deleted file mode 100644 index 2c2d5bc00..000000000 Binary files a/tests/regression_tests/surface_source_write/case-02/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-03/inputs_true.dat b/tests/regression_tests/surface_source_write/case-03/inputs_true.dat deleted file mode 100644 index 58c4e0a24..000000000 --- a/tests/regression_tests/surface_source_write/case-03/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-03/results_true.dat b/tests/regression_tests/surface_source_write/case-03/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-03/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-03/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-03/surface_source_true.h5 deleted file mode 100644 index d14771f5a..000000000 Binary files a/tests/regression_tests/surface_source_write/case-03/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-04/inputs_true.dat b/tests/regression_tests/surface_source_write/case-04/inputs_true.dat deleted file mode 100644 index 46701aea7..000000000 --- a/tests/regression_tests/surface_source_write/case-04/inputs_true.dat +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-04/results_true.dat b/tests/regression_tests/surface_source_write/case-04/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-04/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-04/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-04/surface_source_true.h5 deleted file mode 100644 index d2acc6991..000000000 Binary files a/tests/regression_tests/surface_source_write/case-04/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-05/inputs_true.dat b/tests/regression_tests/surface_source_write/case-05/inputs_true.dat deleted file mode 100644 index c420d797c..000000000 --- a/tests/regression_tests/surface_source_write/case-05/inputs_true.dat +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-05/results_true.dat b/tests/regression_tests/surface_source_write/case-05/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-05/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-05/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-05/surface_source_true.h5 deleted file mode 100644 index 553090b19..000000000 Binary files a/tests/regression_tests/surface_source_write/case-05/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-06/inputs_true.dat b/tests/regression_tests/surface_source_write/case-06/inputs_true.dat deleted file mode 100644 index e02d5e90c..000000000 --- a/tests/regression_tests/surface_source_write/case-06/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-06/results_true.dat b/tests/regression_tests/surface_source_write/case-06/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-06/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-06/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-06/surface_source_true.h5 deleted file mode 100644 index 60a9f4f82..000000000 Binary files a/tests/regression_tests/surface_source_write/case-06/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-07/inputs_true.dat b/tests/regression_tests/surface_source_write/case-07/inputs_true.dat deleted file mode 100644 index a4588c8d0..000000000 --- a/tests/regression_tests/surface_source_write/case-07/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-07/results_true.dat b/tests/regression_tests/surface_source_write/case-07/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-07/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-07/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-07/surface_source_true.h5 deleted file mode 100644 index cb3079251..000000000 Binary files a/tests/regression_tests/surface_source_write/case-07/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-08/inputs_true.dat b/tests/regression_tests/surface_source_write/case-08/inputs_true.dat deleted file mode 100644 index ecf3a6a2e..000000000 --- a/tests/regression_tests/surface_source_write/case-08/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-08/results_true.dat b/tests/regression_tests/surface_source_write/case-08/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-08/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-08/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-08/surface_source_true.h5 deleted file mode 100644 index ed3aba907..000000000 Binary files a/tests/regression_tests/surface_source_write/case-08/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-09/inputs_true.dat b/tests/regression_tests/surface_source_write/case-09/inputs_true.dat deleted file mode 100644 index 5d60f9dbe..000000000 --- a/tests/regression_tests/surface_source_write/case-09/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-09/results_true.dat b/tests/regression_tests/surface_source_write/case-09/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-09/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-09/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-09/surface_source_true.h5 deleted file mode 100644 index d62363f97..000000000 Binary files a/tests/regression_tests/surface_source_write/case-09/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-10/inputs_true.dat b/tests/regression_tests/surface_source_write/case-10/inputs_true.dat deleted file mode 100644 index 1940826c2..000000000 --- a/tests/regression_tests/surface_source_write/case-10/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-10/results_true.dat b/tests/regression_tests/surface_source_write/case-10/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-10/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-10/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-10/surface_source_true.h5 deleted file mode 100644 index acaf39cb4..000000000 Binary files a/tests/regression_tests/surface_source_write/case-10/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-11/inputs_true.dat b/tests/regression_tests/surface_source_write/case-11/inputs_true.dat deleted file mode 100644 index a4feff1b1..000000000 --- a/tests/regression_tests/surface_source_write/case-11/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-11/results_true.dat b/tests/regression_tests/surface_source_write/case-11/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-11/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-11/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-11/surface_source_true.h5 deleted file mode 100644 index 962f95fdd..000000000 Binary files a/tests/regression_tests/surface_source_write/case-11/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-12/inputs_true.dat b/tests/regression_tests/surface_source_write/case-12/inputs_true.dat deleted file mode 100644 index c069f425c..000000000 --- a/tests/regression_tests/surface_source_write/case-12/inputs_true.dat +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-12/results_true.dat b/tests/regression_tests/surface_source_write/case-12/results_true.dat deleted file mode 100644 index ad927bdf3..000000000 --- a/tests/regression_tests/surface_source_write/case-12/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -4.929000E-02 8.212396E-03 diff --git a/tests/regression_tests/surface_source_write/case-12/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-12/surface_source_true.h5 deleted file mode 100644 index 4b830d057..000000000 Binary files a/tests/regression_tests/surface_source_write/case-12/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-13/inputs_true.dat b/tests/regression_tests/surface_source_write/case-13/inputs_true.dat deleted file mode 100644 index 2a93fdb4d..000000000 --- a/tests/regression_tests/surface_source_write/case-13/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-13/results_true.dat b/tests/regression_tests/surface_source_write/case-13/results_true.dat deleted file mode 100644 index ad927bdf3..000000000 --- a/tests/regression_tests/surface_source_write/case-13/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -4.929000E-02 8.212396E-03 diff --git a/tests/regression_tests/surface_source_write/case-13/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-13/surface_source_true.h5 deleted file mode 100644 index f53e2c3a2..000000000 Binary files a/tests/regression_tests/surface_source_write/case-13/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-14/inputs_true.dat b/tests/regression_tests/surface_source_write/case-14/inputs_true.dat deleted file mode 100644 index 893f8ddc1..000000000 --- a/tests/regression_tests/surface_source_write/case-14/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-14/results_true.dat b/tests/regression_tests/surface_source_write/case-14/results_true.dat deleted file mode 100644 index ad927bdf3..000000000 --- a/tests/regression_tests/surface_source_write/case-14/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -4.929000E-02 8.212396E-03 diff --git a/tests/regression_tests/surface_source_write/case-14/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-14/surface_source_true.h5 deleted file mode 100644 index ec049fec4..000000000 Binary files a/tests/regression_tests/surface_source_write/case-14/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-15/inputs_true.dat b/tests/regression_tests/surface_source_write/case-15/inputs_true.dat deleted file mode 100644 index 875a2fb0b..000000000 --- a/tests/regression_tests/surface_source_write/case-15/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-15/results_true.dat b/tests/regression_tests/surface_source_write/case-15/results_true.dat deleted file mode 100644 index ad927bdf3..000000000 --- a/tests/regression_tests/surface_source_write/case-15/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -4.929000E-02 8.212396E-03 diff --git a/tests/regression_tests/surface_source_write/case-15/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-15/surface_source_true.h5 deleted file mode 100644 index fd5892096..000000000 Binary files a/tests/regression_tests/surface_source_write/case-15/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-16/inputs_true.dat b/tests/regression_tests/surface_source_write/case-16/inputs_true.dat deleted file mode 100644 index 347855e90..000000000 --- a/tests/regression_tests/surface_source_write/case-16/inputs_true.dat +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-16/results_true.dat b/tests/regression_tests/surface_source_write/case-16/results_true.dat deleted file mode 100644 index cd0619c1f..000000000 --- a/tests/regression_tests/surface_source_write/case-16/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.403371E+00 1.456192E-02 diff --git a/tests/regression_tests/surface_source_write/case-16/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-16/surface_source_true.h5 deleted file mode 100644 index 147ce0358..000000000 Binary files a/tests/regression_tests/surface_source_write/case-16/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-17/inputs_true.dat b/tests/regression_tests/surface_source_write/case-17/inputs_true.dat deleted file mode 100644 index 95d0a6712..000000000 --- a/tests/regression_tests/surface_source_write/case-17/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-17/results_true.dat b/tests/regression_tests/surface_source_write/case-17/results_true.dat deleted file mode 100644 index cd0619c1f..000000000 --- a/tests/regression_tests/surface_source_write/case-17/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.403371E+00 1.456192E-02 diff --git a/tests/regression_tests/surface_source_write/case-17/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-17/surface_source_true.h5 deleted file mode 100644 index 436063aee..000000000 Binary files a/tests/regression_tests/surface_source_write/case-17/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-18/inputs_true.dat b/tests/regression_tests/surface_source_write/case-18/inputs_true.dat deleted file mode 100644 index 807c72ae6..000000000 --- a/tests/regression_tests/surface_source_write/case-18/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-18/results_true.dat b/tests/regression_tests/surface_source_write/case-18/results_true.dat deleted file mode 100644 index cd0619c1f..000000000 --- a/tests/regression_tests/surface_source_write/case-18/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.403371E+00 1.456192E-02 diff --git a/tests/regression_tests/surface_source_write/case-18/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-18/surface_source_true.h5 deleted file mode 100644 index 436063aee..000000000 Binary files a/tests/regression_tests/surface_source_write/case-18/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-19/inputs_true.dat b/tests/regression_tests/surface_source_write/case-19/inputs_true.dat deleted file mode 100644 index 42aa78a09..000000000 --- a/tests/regression_tests/surface_source_write/case-19/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-19/results_true.dat b/tests/regression_tests/surface_source_write/case-19/results_true.dat deleted file mode 100644 index cd0619c1f..000000000 --- a/tests/regression_tests/surface_source_write/case-19/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.403371E+00 1.456192E-02 diff --git a/tests/regression_tests/surface_source_write/case-19/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-19/surface_source_true.h5 deleted file mode 100644 index eda3e030b..000000000 Binary files a/tests/regression_tests/surface_source_write/case-19/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-20/inputs_true.dat b/tests/regression_tests/surface_source_write/case-20/inputs_true.dat deleted file mode 100644 index 4c7a3f11d..000000000 --- a/tests/regression_tests/surface_source_write/case-20/inputs_true.dat +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-20/results_true.dat b/tests/regression_tests/surface_source_write/case-20/results_true.dat deleted file mode 100644 index 44293cf09..000000000 --- a/tests/regression_tests/surface_source_write/case-20/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.266853E+00 4.552028E-02 diff --git a/tests/regression_tests/surface_source_write/case-20/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-20/surface_source_true.h5 deleted file mode 100644 index 083ce90c8..000000000 Binary files a/tests/regression_tests/surface_source_write/case-20/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-21/inputs_true.dat b/tests/regression_tests/surface_source_write/case-21/inputs_true.dat deleted file mode 100644 index 71f9aae6a..000000000 --- a/tests/regression_tests/surface_source_write/case-21/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-21/results_true.dat b/tests/regression_tests/surface_source_write/case-21/results_true.dat deleted file mode 100644 index 44293cf09..000000000 --- a/tests/regression_tests/surface_source_write/case-21/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.266853E+00 4.552028E-02 diff --git a/tests/regression_tests/surface_source_write/case-21/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-21/surface_source_true.h5 deleted file mode 100644 index f7e886db4..000000000 Binary files a/tests/regression_tests/surface_source_write/case-21/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat b/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat deleted file mode 100644 index e9840be87..000000000 --- a/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 1 2 3 - 200 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-a01/results_true.dat b/tests/regression_tests/surface_source_write/case-a01/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-a01/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-a01/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-a01/surface_source_true.h5 deleted file mode 100644 index 807211e3a..000000000 Binary files a/tests/regression_tests/surface_source_write/case-a01/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d01/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d01/inputs_true.dat deleted file mode 100644 index 04703acfe..000000000 --- a/tests/regression_tests/surface_source_write/case-d01/inputs_true.dat +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d01/results_true.dat b/tests/regression_tests/surface_source_write/case-d01/results_true.dat deleted file mode 100644 index 26b9e30a3..000000000 --- a/tests/regression_tests/surface_source_write/case-d01/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.288719E-01 6.877101E-03 diff --git a/tests/regression_tests/surface_source_write/case-d01/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d01/surface_source_true.h5 deleted file mode 100644 index 9a66315ff..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d01/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d02/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d02/inputs_true.dat deleted file mode 100644 index d8b4e6803..000000000 --- a/tests/regression_tests/surface_source_write/case-d02/inputs_true.dat +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 1 - 300 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d02/results_true.dat b/tests/regression_tests/surface_source_write/case-d02/results_true.dat deleted file mode 100644 index 26b9e30a3..000000000 --- a/tests/regression_tests/surface_source_write/case-d02/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.288719E-01 6.877101E-03 diff --git a/tests/regression_tests/surface_source_write/case-d02/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d02/surface_source_true.h5 deleted file mode 100644 index 291062942..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d02/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d03/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d03/inputs_true.dat deleted file mode 100644 index d769184aa..000000000 --- a/tests/regression_tests/surface_source_write/case-d03/inputs_true.dat +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d03/results_true.dat b/tests/regression_tests/surface_source_write/case-d03/results_true.dat deleted file mode 100644 index 26b9e30a3..000000000 --- a/tests/regression_tests/surface_source_write/case-d03/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.288719E-01 6.877101E-03 diff --git a/tests/regression_tests/surface_source_write/case-d03/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d03/surface_source_true.h5 deleted file mode 100644 index 0af7160d4..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d03/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d04/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d04/inputs_true.dat deleted file mode 100644 index abefc2692..000000000 --- a/tests/regression_tests/surface_source_write/case-d04/inputs_true.dat +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 1 - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d04/results_true.dat b/tests/regression_tests/surface_source_write/case-d04/results_true.dat deleted file mode 100644 index 26b9e30a3..000000000 --- a/tests/regression_tests/surface_source_write/case-d04/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.288719E-01 6.877101E-03 diff --git a/tests/regression_tests/surface_source_write/case-d04/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d04/surface_source_true.h5 deleted file mode 100644 index 90ab00748..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d04/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d05/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d05/inputs_true.dat deleted file mode 100644 index 8b46b2b4e..000000000 --- a/tests/regression_tests/surface_source_write/case-d05/inputs_true.dat +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d05/results_true.dat b/tests/regression_tests/surface_source_write/case-d05/results_true.dat deleted file mode 100644 index 26b9e30a3..000000000 --- a/tests/regression_tests/surface_source_write/case-d05/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.288719E-01 6.877101E-03 diff --git a/tests/regression_tests/surface_source_write/case-d05/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d05/surface_source_true.h5 deleted file mode 100644 index 2f5521679..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d05/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d06/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d06/inputs_true.dat deleted file mode 100644 index ca52cf455..000000000 --- a/tests/regression_tests/surface_source_write/case-d06/inputs_true.dat +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d06/results_true.dat b/tests/regression_tests/surface_source_write/case-d06/results_true.dat deleted file mode 100644 index 26b9e30a3..000000000 --- a/tests/regression_tests/surface_source_write/case-d06/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.288719E-01 6.877101E-03 diff --git a/tests/regression_tests/surface_source_write/case-d06/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d06/surface_source_true.h5 deleted file mode 100644 index 27227ad49..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d06/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d07/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d07/inputs_true.dat deleted file mode 100644 index 40c439fe6..000000000 --- a/tests/regression_tests/surface_source_write/case-d07/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 101 102 103 104 105 106 - 300 - 7 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d07/results_true.dat b/tests/regression_tests/surface_source_write/case-d07/results_true.dat deleted file mode 100644 index 5a4ea6689..000000000 --- a/tests/regression_tests/surface_source_write/case-d07/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.947197E-01 3.711779E-02 diff --git a/tests/regression_tests/surface_source_write/case-d07/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d07/surface_source_true.h5 deleted file mode 100644 index fd9f0dc57..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d07/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-d08/inputs_true.dat b/tests/regression_tests/surface_source_write/case-d08/inputs_true.dat deleted file mode 100644 index c81d21b97..000000000 --- a/tests/regression_tests/surface_source_write/case-d08/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -4 -4 -20 4 4 20 - - - true - - - - 101 102 103 104 105 106 - 300 - 8 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-d08/results_true.dat b/tests/regression_tests/surface_source_write/case-d08/results_true.dat deleted file mode 100644 index 5a4ea6689..000000000 --- a/tests/regression_tests/surface_source_write/case-d08/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -9.947197E-01 3.711779E-02 diff --git a/tests/regression_tests/surface_source_write/case-d08/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-d08/surface_source_true.h5 deleted file mode 100644 index fd9f0dc57..000000000 Binary files a/tests/regression_tests/surface_source_write/case-d08/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-e01/inputs_true.dat b/tests/regression_tests/surface_source_write/case-e01/inputs_true.dat deleted file mode 100644 index 46701aea7..000000000 --- a/tests/regression_tests/surface_source_write/case-e01/inputs_true.dat +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 2 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-e01/results_true.dat b/tests/regression_tests/surface_source_write/case-e01/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-e01/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-e01/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-e01/surface_source_true.h5 deleted file mode 100644 index bbfbd152b..000000000 Binary files a/tests/regression_tests/surface_source_write/case-e01/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-e02/inputs_true.dat b/tests/regression_tests/surface_source_write/case-e02/inputs_true.dat deleted file mode 100644 index a4588c8d0..000000000 --- a/tests/regression_tests/surface_source_write/case-e02/inputs_true.dat +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-e02/results_true.dat b/tests/regression_tests/surface_source_write/case-e02/results_true.dat deleted file mode 100644 index d4d1d1e5a..000000000 --- a/tests/regression_tests/surface_source_write/case-e02/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -5.642735E-02 1.494035E-02 diff --git a/tests/regression_tests/surface_source_write/case-e02/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-e02/surface_source_true.h5 deleted file mode 100644 index bbfbd152b..000000000 Binary files a/tests/regression_tests/surface_source_write/case-e02/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/case-e03/inputs_true.dat b/tests/regression_tests/surface_source_write/case-e03/inputs_true.dat deleted file mode 100644 index 2a93fdb4d..000000000 --- a/tests/regression_tests/surface_source_write/case-e03/inputs_true.dat +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 1 - - - -2.0 -2.0 -2.0 2.0 2.0 2.0 - - - true - - - - 4 5 6 7 8 9 - 300 - 3 - - 1 - - diff --git a/tests/regression_tests/surface_source_write/case-e03/results_true.dat b/tests/regression_tests/surface_source_write/case-e03/results_true.dat deleted file mode 100644 index ad927bdf3..000000000 --- a/tests/regression_tests/surface_source_write/case-e03/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -4.929000E-02 8.212396E-03 diff --git a/tests/regression_tests/surface_source_write/case-e03/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-e03/surface_source_true.h5 deleted file mode 100644 index 22e108745..000000000 Binary files a/tests/regression_tests/surface_source_write/case-e03/surface_source_true.h5 and /dev/null differ diff --git a/tests/regression_tests/surface_source_write/test.py b/tests/regression_tests/surface_source_write/test.py deleted file mode 100644 index 094df1f8b..000000000 --- a/tests/regression_tests/surface_source_write/test.py +++ /dev/null @@ -1,1125 +0,0 @@ -"""Test the 'surface_source_write' setting. - -Results -------- - -All results are generated using only 1 MPI process. - -All results are generated using 1 thread except for "test_consistency_low_realization_number". -This specific test verifies that when the number of realization (i.e., point being candidate -to be stored) is lower than the capacity, results are reproducible even with multiple -threads (i.e., there is no potential thread competition that would produce different -results in that case). - -All results are generated using the history-based mode except for cases e01 to e03. - -All results are visually verified using the '_visualize.py' script in the regression test folder. - -OpenMC models -------------- - -Four OpenMC models with CSG-only geometries are used to cover the transmission, vacuum, -reflective and periodic Boundary Conditions (BC): - -- model_1: cylindrical core in 2 boxes (vacuum and transmission BC), -- model_2: cylindrical core in 1 box (vacuum BC), -- model_3: cylindrical core in 1 box (reflective BC), -- model_4: cylindrical core in 1 box (periodic BC). - -Two models including DAGMC geometries are also used, based on the mesh file 'dagmc.h5m' -available from tests/regression_tests/dagmc/legacy: - -- model_dagmc_1: model adapted from tests/regression_tests/dagmc/legacy, -- model_dagmc_2: model_dagmc_1 contained in two CSG boxes to introduce multiple level of coordinates. - -Test cases ----------- - -Test cases using CSG-only geometries: - -======== ======= ========= ========================= ===== =================================== -Folder Model Surface Cell BC* Expected particles -======== ======= ========= ========================= ===== =================================== -case-01 model_1 No No T+V Particles crossing any surface in - the model -case-02 model_1 1 No T Particles crossing this surface - only -case-03 model_1 Multiple No T Particles crossing the declared - surfaces -case-04 model_1 Multiple cell (lower universe) T Particles crossing the declared - surfaces that come from or are - coming to the cell -case-05 model_1 Multiple cell (root universe) T Particles crossing the declared - surfaces that come from or are - coming to the cell -case-06 model_1 No cell (lower universe) T Particles crossing any surface that - come from or are coming to the cell -case-07 model_1 No cell (root universe) T Particles crossing any surface that - come from or are coming to the cell -case-08 model_1 No cellfrom (lower universe) T Particles crossing any surface that - come from the cell -case-09 model_1 No cellto (lower universe) T Particles crossing any surface that - are coming to the cell -case-10 model_1 No cellfrom (root universe) T Particles crossing any surface that - come from the cell -case-11 model_1 No cellto (root universe) T Particles crossing any surface that - are coming to the cell -case-12 model_2 Multiple No V Particles crossing the declared - surfaces -case-13 model_2 Multiple cell (root universe) V Particles crossing any surface that - come from or are coming to the cell -case-14 model_2 Multiple cellfrom (root universe) V Particles crossing any surface that - are coming to the cell -case-15 model_2 Multiple cellto (root universe) V None -case-16 model_3 Multiple No R Particles crossing the declared - surfaces -case-17 model_3 Multiple cell (root universe) R None -case-18 model_3 Multiple cellfrom (root universe) R None -case-19 model_3 Multiple cellto (root universe) R None -case-20 model_4 1 No P+R Particles crossing the declared - periodic surface -case-21 model_4 1 cell (root universe) P+R None -======== ======= ========= ========================= ===== =================================== - -*: BC stands for Boundary Conditions, T for Transmission, R for Reflective, and V for Vacuum. - -An additional case, called 'case-a01', is used to check that the results are comparable when -the number of threads is set to 2 if the number of realization is lower than the capacity. - -Cases e01 to e03 are the event-based cases corresponding to the history-based cases 04, 07 and 13, -respectively. - -Test cases using DAGMC geometries: - -======== ============= ========= ===================== ===== =================================== -Folder Model Surface Cell BC* Expected particles -======== ============= ========= ===================== ===== =================================== -case-d01 model_dagmc_1 No No T+V Particles crossing any surface in - the model -case-d02 model_dagmc_1 1 No T Particles crossing this surface - only -case-d03 model_dagmc_1 No cell T Particles crossing any surface that - come from or are coming to the cell -case-d04 model_dagmc_1 1 cell T Particles crossing the declared - surface that come from or are - coming to the cell -case-d05 model_dagmc_1 No cellfrom T Particles crossing any surface that - come from the cell -case-d06 model_dagmc_1 No cellto T Particles crossing any surface that - are coming to the cell -case-d07 model_dagmc_2 Multiple cell (lower universe) T Particles crossing the declared - surfaces that come from or are - coming to the cell -case-d08 model_dagmc_2 Multiple cell (root universe) T Particles crossing the declared - surfaces that come from or are - coming to the cell -======== ============= ========= ===================== ===== =================================== - -*: BC stands for Boundary Conditions, T for Transmission, and V for Vacuum. - -Notes: - -- The test cases list is non-exhaustive compared to the number of possible combinations. - Test cases have been selected based on use and internal code logic. -- Cases 08 to 11 are testing that the feature still works even if the level of coordinates - before and after crossing a surface is different, -- Tests on boundary conditions are not performed on DAGMC models as the logic is shared - with CSG-only models, -- Cases that should return an error are tested in the 'test_exceptions' unit test - from 'unit_tests/surface_source_write/test.py'. - -TODO: - -- Test with a lattice. - -""" - -import os -import shutil -from pathlib import Path - -import h5py -import numpy as np -import openmc -import openmc.lib -import pytest - -from tests.testing_harness import PyAPITestHarness -from tests.regression_tests import config - - -@pytest.fixture(scope="function") -def single_thread(monkeypatch): - """Set the number of OMP threads to 1 for the test.""" - monkeypatch.setenv("OMP_NUM_THREADS", "1") - - -@pytest.fixture(scope="function") -def two_threads(monkeypatch): - """Set the number of OMP threads to 2 for the test.""" - monkeypatch.setenv("OMP_NUM_THREADS", "2") - - -@pytest.fixture(scope="function") -def single_process(monkeypatch): - """Set the number of MPI process to 1 for the test.""" - monkeypatch.setitem(config, "mpi_np", "1") - - -@pytest.fixture(scope="module") -def model_1(): - """Cylindrical core contained in a first box which is contained in a larger box. - A lower universe is used to describe the interior of the first box which - contains the core and its surrounding space. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - fuel = openmc.Material() - fuel.add_nuclide("U234", 0.0004524) - fuel.add_nuclide("U235", 0.0506068) - fuel.add_nuclide("U238", 0.9487090) - fuel.add_nuclide("U236", 0.0002318) - fuel.add_nuclide("O16", 2.0) - fuel.set_density("g/cm3", 11.0) - - water = openmc.Material() - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cm3", 1.0) - - # ============================================================================= - # Geometry - # ============================================================================= - - # ----------------------------------------------------------------------------- - # Cylindrical core - # ----------------------------------------------------------------------------- - - # Parameters - core_radius = 2.0 - core_height = 4.0 - - # Surfaces - core_cylinder = openmc.ZCylinder(r=core_radius) - core_lower_plane = openmc.ZPlane(-core_height / 2.0) - core_upper_plane = openmc.ZPlane(core_height / 2.0) - - # Region - core_region = -core_cylinder & +core_lower_plane & -core_upper_plane - - # Cells - core = openmc.Cell(fill=fuel, region=core_region) - outside_core_region = +core_cylinder | -core_lower_plane | +core_upper_plane - outside_core = openmc.Cell(fill=water, region=outside_core_region) - - # Universe - inside_box1_universe = openmc.Universe(cells=[core, outside_core]) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 6.0 - - # Surfaces - box1_rpp = openmc.model.RectangularParallelepiped( - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - ) - - # Cell - box1 = openmc.Cell(fill=inside_box1_universe, region=-box1_rpp) - - # ----------------------------------------------------------------------------- - # Box 2 - # ----------------------------------------------------------------------------- - - # Parameters - box2_size = 8 - - # Surfaces - box2_rpp = openmc.model.RectangularParallelepiped( - -box2_size / 2.0, box2_size / 2.0, - -box2_size / 2.0, box2_size / 2.0, - -box2_size / 2.0, box2_size / 2.0, - boundary_type="vacuum" - ) - - # Cell - box2 = openmc.Cell(fill=water, region=-box2_rpp & +box1_rpp) - - # Register geometry - model.geometry = openmc.Geometry([box1, box2]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - bounds = [ - -core_radius, - -core_radius, - -core_height / 2.0, - core_radius, - core_radius, - core_height / 2.0, - ] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource( - space=distribution, constraints={'fissionable': True}) - - return model - - -@pytest.fixture -def model_2(): - """Cylindrical core contained in a box. - A lower universe is used to describe the interior of the box which - contains the core and its surrounding space. - - The box is defined with vacuum boundary conditions. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - fuel = openmc.Material() - fuel.add_nuclide("U234", 0.0004524) - fuel.add_nuclide("U235", 0.0506068) - fuel.add_nuclide("U238", 0.9487090) - fuel.add_nuclide("U236", 0.0002318) - fuel.add_nuclide("O16", 2.0) - fuel.set_density("g/cm3", 11.0) - - water = openmc.Material() - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cm3", 1.0) - - # ============================================================================= - # Geometry - # ============================================================================= - - # ----------------------------------------------------------------------------- - # Cylindrical core - # ----------------------------------------------------------------------------- - - # Parameters - core_radius = 2.0 - core_height = 4.0 - - # Surfaces - core_cylinder = openmc.ZCylinder(r=core_radius) - core_lower_plane = openmc.ZPlane(-core_height / 2.0) - core_upper_plane = openmc.ZPlane(core_height / 2.0) - - # Region - core_region = -core_cylinder & +core_lower_plane & -core_upper_plane - - # Cells - core = openmc.Cell(fill=fuel, region=core_region) - outside_core_region = +core_cylinder | -core_lower_plane | +core_upper_plane - outside_core = openmc.Cell(fill=water, region=outside_core_region) - - # Universe - inside_box1_universe = openmc.Universe(cells=[core, outside_core]) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 6.0 - - # Surfaces - box1_rpp = openmc.model.RectangularParallelepiped( - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - boundary_type="vacuum" - ) - - # Cell - box1 = openmc.Cell(fill=inside_box1_universe, region=-box1_rpp) - - # Register geometry - model.geometry = openmc.Geometry([box1]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - bounds = [ - -core_radius, - -core_radius, - -core_height / 2.0, - core_radius, - core_radius, - core_height / 2.0, - ] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource( - space=distribution, constraints={'fissionable': True}) - - return model - - -@pytest.fixture -def model_3(): - """Cylindrical core contained in a box. - A lower universe is used to describe the interior of the box which - contains the core and its surrounding space. - - The box is defined with reflective boundary conditions. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - fuel = openmc.Material() - fuel.add_nuclide("U234", 0.0004524) - fuel.add_nuclide("U235", 0.0506068) - fuel.add_nuclide("U238", 0.9487090) - fuel.add_nuclide("U236", 0.0002318) - fuel.add_nuclide("O16", 2.0) - fuel.set_density("g/cm3", 11.0) - - water = openmc.Material() - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cm3", 1.0) - - # ============================================================================= - # Geometry - # ============================================================================= - - # ----------------------------------------------------------------------------- - # Cylindrical core - # ----------------------------------------------------------------------------- - - # Parameters - core_radius = 2.0 - core_height = 4.0 - - # Surfaces - core_cylinder = openmc.ZCylinder(r=core_radius) - core_lower_plane = openmc.ZPlane(-core_height / 2.0) - core_upper_plane = openmc.ZPlane(core_height / 2.0) - - # Region - core_region = -core_cylinder & +core_lower_plane & -core_upper_plane - - # Cells - core = openmc.Cell(fill=fuel, region=core_region) - outside_core_region = +core_cylinder | -core_lower_plane | +core_upper_plane - outside_core = openmc.Cell(fill=water, region=outside_core_region) - - # Universe - inside_box1_universe = openmc.Universe(cells=[core, outside_core]) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 6.0 - - # Surfaces - box1_rpp = openmc.model.RectangularParallelepiped( - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - -box1_size / 2.0, box1_size / 2.0, - boundary_type="reflective" - ) - - # Cell - box1 = openmc.Cell(fill=inside_box1_universe, region=-box1_rpp) - - # Register geometry - model.geometry = openmc.Geometry([box1]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - bounds = [ - -core_radius, - -core_radius, - -core_height / 2.0, - core_radius, - core_radius, - core_height / 2.0, - ] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource( - space=distribution, constraints={'fissionable': True}) - - return model - - -@pytest.fixture -def model_4(): - """Cylindrical core contained in a box. - A lower universe is used to describe the interior of the box which - contains the core and its surrounding space. - - The box is defined with a pair of periodic boundary with reflective - boundaries. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - fuel = openmc.Material() - fuel.add_nuclide("U234", 0.0004524) - fuel.add_nuclide("U235", 0.0506068) - fuel.add_nuclide("U238", 0.9487090) - fuel.add_nuclide("U236", 0.0002318) - fuel.add_nuclide("O16", 2.0) - fuel.set_density("g/cm3", 11.0) - - water = openmc.Material() - water.add_nuclide("H1", 2.0) - water.add_nuclide("O16", 1.0) - water.set_density("g/cm3", 1.0) - - # ============================================================================= - # Geometry - # ============================================================================= - - # ----------------------------------------------------------------------------- - # Cylindrical core - # ----------------------------------------------------------------------------- - - # Parameters - core_radius = 2.0 - core_height = 4.0 - - # Surfaces - core_cylinder = openmc.ZCylinder(r=core_radius) - core_lower_plane = openmc.ZPlane(-core_height / 2.0) - core_upper_plane = openmc.ZPlane(core_height / 2.0) - - # Region - core_region = -core_cylinder & +core_lower_plane & -core_upper_plane - - # Cells - core = openmc.Cell(fill=fuel, region=core_region) - outside_core_region = +core_cylinder | -core_lower_plane | +core_upper_plane - outside_core = openmc.Cell(fill=water, region=outside_core_region) - - # Universe - inside_box1_universe = openmc.Universe(cells=[core, outside_core]) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 6.0 - - # Surfaces - box1_lower_plane = openmc.ZPlane(-box1_size / 2.0, boundary_type="periodic") - box1_upper_plane = openmc.ZPlane(box1_size / 2.0, boundary_type="periodic") - box1_left_plane = openmc.XPlane(-box1_size / 2.0, boundary_type="reflective") - box1_right_plane = openmc.XPlane(box1_size / 2.0, boundary_type="reflective") - box1_rear_plane = openmc.YPlane(-box1_size / 2.0, boundary_type="reflective") - box1_front_plane = openmc.YPlane(box1_size / 2.0, boundary_type="reflective") - - # Region - box1_region = ( - +box1_lower_plane - & -box1_upper_plane - & +box1_left_plane - & -box1_right_plane - & +box1_rear_plane - & -box1_front_plane - ) - - # Cell - box1 = openmc.Cell(fill=inside_box1_universe, region=box1_region) - - # Register geometry - model.geometry = openmc.Geometry([box1]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - bounds = [ - -core_radius, - -core_radius, - -core_height / 2.0, - core_radius, - core_radius, - core_height / 2.0, - ] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource( - space=distribution, constraints={'fissionable': True}) - - return model - - -def return_surface_source_data(filepath): - """Read a surface source file and return a sorted array composed - of flatten arrays of source data for each surface source point. - - Parameters - ---------- - filepath : str - Path to the surface source file - - Returns - ------- - data : np.array - Sorted array composed of flatten arrays of source data for - each surface source point - - """ - data = [] - keys = [] - - # Read source file - source = openmc.read_source_file(filepath) - - for point in source: - r = point.r - u = point.u - e = point.E - time = point.time - wgt = point.wgt - delayed_group = point.delayed_group - surf_id = point.surf_id - particle = point.particle.pdg_number - key = ( - f"{r[0]:.10e} {r[1]:.10e} {r[2]:.10e} {u[0]:.10e} {u[1]:.10e} {u[2]:.10e}" - f"{e:.10e} {time:.10e} {wgt:.10e} {delayed_group} {surf_id} {particle}" - ) - keys.append(key) - values = [*r, *u, e, time, wgt, delayed_group, surf_id, particle] - assert len(values) == 12 - data.append(values) - - data = np.array(data) - keys = np.array(keys) - sorted_idx = np.argsort(keys) - - return data[sorted_idx] - - -class SurfaceSourceWriteTestHarness(PyAPITestHarness): - def __init__(self, statepoint_name, model=None, inputs_true=None, workdir=None): - super().__init__(statepoint_name, model, inputs_true) - self.workdir = workdir - - def _test_output_created(self): - """Make sure surface_source.h5 has also been created.""" - super()._test_output_created() - if self._model.settings.surf_source_write: - assert os.path.exists( - "surface_source.h5" - ), "Surface source file has not been created." - - def _compare_output(self): - """Compare surface_source.h5 files.""" - if self._model.settings.surf_source_write: - source_true = return_surface_source_data("surface_source_true.h5") - source_test = return_surface_source_data("surface_source.h5") - np.testing.assert_allclose(source_true, source_test, rtol=1e-07) - - def main(self): - """Accept commandline arguments and either run or update tests.""" - if config["build_inputs"]: - self.build_inputs() - elif config["update"]: - self.update_results() - else: - self.execute_test() - - def build_inputs(self): - """Build inputs.""" - base_dir = os.getcwd() - try: - os.chdir(self.workdir) - self._build_inputs() - finally: - os.chdir(base_dir) - - def execute_test(self): - """Build inputs, run OpenMC, and verify correct results.""" - base_dir = os.getcwd() - try: - os.chdir(self.workdir) - self._build_inputs() - inputs = self._get_inputs() - self._write_inputs(inputs) - self._compare_inputs() - self._run_openmc() - self._test_output_created() - self._compare_output() - results = self._get_results() - self._write_results(results) - self._compare_results() - finally: - self._cleanup() - os.chdir(base_dir) - - def update_results(self): - """Update results_true.dat and inputs_true.dat""" - base_dir = os.getcwd() - try: - os.chdir(self.workdir) - self._build_inputs() - inputs = self._get_inputs() - self._write_inputs(inputs) - self._overwrite_inputs() - self._run_openmc() - self._test_output_created() - results = self._get_results() - self._write_results(results) - self._overwrite_results() - finally: - self._cleanup() - os.chdir(base_dir) - - def _overwrite_results(self): - """Also add the 'surface_source.h5' file during overwriting.""" - super()._overwrite_results() - if os.path.exists("surface_source.h5"): - shutil.copyfile("surface_source.h5", "surface_source_true.h5") - - def _cleanup(self): - """Also remove the 'surface_source.h5' file while cleaning.""" - super()._cleanup() - fs = "surface_source.h5" - if os.path.exists(fs): - os.remove(fs) - - -@pytest.mark.skipif(config["event"] is True, reason="Results from history-based mode.") -@pytest.mark.parametrize( - "folder, model_name, parameter", - [ - ("case-01", "model_1", {"max_particles": 300}), - ("case-02", "model_1", {"max_particles": 300, "surface_ids": [8]}), - ( - "case-03", - "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9]}, - ), - ( - "case-04", - "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, - ), - ( - "case-05", - "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, - ), - ("case-06", "model_1", {"max_particles": 300, "cell": 2}), - ("case-07", "model_1", {"max_particles": 300, "cell": 3}), - ("case-08", "model_1", {"max_particles": 300, "cellfrom": 2}), - ("case-09", "model_1", {"max_particles": 300, "cellto": 2}), - ("case-10", "model_1", {"max_particles": 300, "cellfrom": 3}), - ("case-11", "model_1", {"max_particles": 300, "cellto": 3}), - ( - "case-12", - "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9]}, - ), - ( - "case-13", - "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, - ), - ( - "case-14", - "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": 3}, - ), - ( - "case-15", - "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": 3}, - ), - ( - "case-16", - "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9]}, - ), - ( - "case-17", - "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, - ), - ( - "case-18", - "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": 3}, - ), - ( - "case-19", - "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": 3}, - ), - ( - "case-20", - "model_4", - {"max_particles": 300, "surface_ids": [4]}, - ), - ( - "case-21", - "model_4", - {"max_particles": 300, "surface_ids": [4], "cell": 3}, - ), - ], -) -def test_surface_source_cell_history_based( - folder, model_name, parameter, single_thread, single_process, request -): - """Test on history-based results for CSG-only geometries.""" - assert os.environ["OMP_NUM_THREADS"] == "1" - assert config["mpi_np"] == "1" - model = request.getfixturevalue(model_name) - model.settings.surf_source_write = parameter - harness = SurfaceSourceWriteTestHarness( - "statepoint.5.h5", model=model, workdir=folder - ) - harness.main() - - -@pytest.mark.skipif(config["event"] is True, reason="Results from history-based mode.") -def test_consistency_low_realization_number(model_1, two_threads, single_process): - """The objective is to test that the results produced, in a case where - the number of potential realization (particle storage) is low - compared to the capacity of storage, are still consistent. - - This configuration ensures that the competition between threads does not - occur and that the content of the source file created can be compared. - - """ - assert os.environ["OMP_NUM_THREADS"] == "2" - assert config["mpi_np"] == "1" - model_1.settings.surf_source_write = { - "max_particles": 200, - "surface_ids": [1, 2, 3], - "cellfrom": 2, - } - harness = SurfaceSourceWriteTestHarness( - "statepoint.5.h5", model=model_1, workdir="case-a01" - ) - harness.main() - - -@pytest.mark.skipif(config["event"] is False, reason="Results from event-based mode.") -@pytest.mark.parametrize( - "folder, model_name, parameter", - [ - ( - "case-e01", - "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, - ), - ("case-e02", "model_1", {"max_particles": 300, "cell": 3}), - ( - "case-e03", - "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, - ), - ], -) -def test_surface_source_cell_event_based( - folder, model_name, parameter, single_thread, single_process, request -): - """Test on event-based results for CSG-only geometries.""" - assert os.environ["OMP_NUM_THREADS"] == "1" - assert config["mpi_np"] == "1" - model = request.getfixturevalue(model_name) - model.settings.surf_source_write = parameter - harness = SurfaceSourceWriteTestHarness( - "statepoint.5.h5", model=model, workdir=folder - ) - harness.main() - - -@pytest.fixture(scope="module") -def model_dagmc_1(): - """Model based on the mesh file 'dagmc.h5m' available from - tests/regression_tests/dagmc/legacy. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - u235 = openmc.Material(name="no-void fuel") - u235.add_nuclide("U235", 1.0, "ao") - u235.set_density("g/cc", 11) - u235.id = 40 - - water = openmc.Material(name="water") - water.add_nuclide("H1", 2.0, "ao") - water.add_nuclide("O16", 1.0, "ao") - water.set_density("g/cc", 1.0) - water.add_s_alpha_beta("c_H_in_H2O") - water.id = 41 - - materials = openmc.Materials([u235, water]) - model.materials = materials - - # ============================================================================= - # Geometry - # ============================================================================= - - dagmc_univ = openmc.DAGMCUniverse(Path("../../dagmc/legacy/dagmc.h5m")) - model.geometry = openmc.Geometry(dagmc_univ) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - source_box = openmc.stats.Box([-4, -4, -20], [4, 4, 20]) - model.settings.source = openmc.IndependentSource( - space=source_box, constraints={'fissionable': True}) - - return model - - -@pytest.fixture(scope="module") -def model_dagmc_2(): - """Model based on the mesh file 'dagmc.h5m' available from - tests/regression_tests/dagmc/legacy. - - This model corresponds to the model_dagmc_1 contained in two boxes to introduce - multiple level of coordinates from CSG geometry. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - u235 = openmc.Material(name="no-void fuel") - u235.add_nuclide("U235", 1.0, "ao") - u235.set_density("g/cc", 11) - u235.id = 40 - - water = openmc.Material(name="water") - water.add_nuclide("H1", 2.0, "ao") - water.add_nuclide("O16", 1.0, "ao") - water.set_density("g/cc", 1.0) - water.add_s_alpha_beta("c_H_in_H2O") - water.id = 41 - - materials = openmc.Materials([u235, water]) - model.materials = materials - - # ============================================================================= - # Geometry - # ============================================================================= - - dagmc_univ = openmc.DAGMCUniverse(Path("../../dagmc/legacy/dagmc.h5m")) - - # ----------------------------------------------------------------------------- - # Box 1 - # ----------------------------------------------------------------------------- - - # Parameters - box1_size = 44 - - # Surfaces - box1_lower_plane = openmc.ZPlane(-box1_size / 2.0, surface_id=101) - box1_upper_plane = openmc.ZPlane(box1_size / 2.0, surface_id=102) - box1_left_plane = openmc.XPlane(-box1_size / 2.0, surface_id=103) - box1_right_plane = openmc.XPlane(box1_size / 2.0, surface_id=104) - box1_rear_plane = openmc.YPlane(-box1_size / 2.0, surface_id=105) - box1_front_plane = openmc.YPlane(box1_size / 2.0, surface_id=106) - - # Region - box1_region = ( - +box1_lower_plane - & -box1_upper_plane - & +box1_left_plane - & -box1_right_plane - & +box1_rear_plane - & -box1_front_plane - ) - - # Cell - box1 = openmc.Cell(fill=dagmc_univ, region=box1_region, cell_id=8) - - # ----------------------------------------------------------------------------- - # Box 2 - # ----------------------------------------------------------------------------- - - # Parameters - box2_size = 48 - - # Surfaces - box2_lower_plane = openmc.ZPlane( - -box2_size / 2.0, boundary_type="vacuum", surface_id=107 - ) - box2_upper_plane = openmc.ZPlane( - box2_size / 2.0, boundary_type="vacuum", surface_id=108 - ) - box2_left_plane = openmc.XPlane( - -box2_size / 2.0, boundary_type="vacuum", surface_id=109 - ) - box2_right_plane = openmc.XPlane( - box2_size / 2.0, boundary_type="vacuum", surface_id=110 - ) - box2_rear_plane = openmc.YPlane( - -box2_size / 2.0, boundary_type="vacuum", surface_id=111 - ) - box2_front_plane = openmc.YPlane( - box2_size / 2.0, boundary_type="vacuum", surface_id=112 - ) - - # Region - inside_box2 = ( - +box2_lower_plane - & -box2_upper_plane - & +box2_left_plane - & -box2_right_plane - & +box2_rear_plane - & -box2_front_plane - ) - outside_box1 = ( - -box1_lower_plane - | +box1_upper_plane - | -box1_left_plane - | +box1_right_plane - | -box1_rear_plane - | +box1_front_plane - ) - - box2_region = inside_box2 & outside_box1 - - # Cell - box2 = openmc.Cell(fill=water, region=box2_region, cell_id=9) - - # Register geometry - model.geometry = openmc.Geometry([box1, box2]) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - source_box = openmc.stats.Box([-4, -4, -20], [4, 4, 20]) - model.settings.source = openmc.IndependentSource( - space=source_box, constraints={'fissionable': True}) - - return model - - -@pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled." -) -@pytest.mark.skipif(config["event"] is True, reason="Results from history-based mode.") -@pytest.mark.parametrize( - "folder, model_name, parameter", - [ - ("case-d01", "model_dagmc_1", {"max_particles": 300}), - ("case-d02", "model_dagmc_1", {"max_particles": 300, "surface_ids": [1]}), - ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": 2}), - ( - "case-d04", - "model_dagmc_1", - {"max_particles": 300, "surface_ids": [1], "cell": 2}, - ), - ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": 2}), - ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": 2}), - ( - "case-d07", - "model_dagmc_2", - { - "max_particles": 300, - "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": 7, - }, - ), - ( - "case-d08", - "model_dagmc_2", - { - "max_particles": 300, - "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": 8, - }, - ), - ], -) -def test_surface_source_cell_dagmc( - folder, model_name, parameter, single_thread, single_process, request -): - """Test on models with DAGMC geometries.""" - assert os.environ["OMP_NUM_THREADS"] == "1" - assert config["mpi_np"] == "1" - model = request.getfixturevalue(model_name) - model.settings.surf_source_write = parameter - harness = SurfaceSourceWriteTestHarness( - "statepoint.5.h5", model=model, workdir=folder - ) - harness.main() diff --git a/tests/regression_tests/surface_tally/inputs_true.dat b/tests/regression_tests/surface_tally/inputs_true.dat index 2b070c5a3..96639a076 100644 --- a/tests/regression_tests/surface_tally/inputs_true.dat +++ b/tests/regression_tests/surface_tally/inputs_true.dat @@ -1,105 +1,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 0 - - - -0.62992 -0.62992 -1 0.62992 0.62992 1 - - - true - - - - - - 1 - - - 2 - - - 0.0 4000000.0 20000000.0 - - - 0.0 0.7853981633974483 3.141592653589793 - - - 0.0 0.7853981633974483 3.141592653589793 - - - 1 - - - 2 - - - 1 - - - 2 - - - 3 - - - 5 6 1 2 3 - current - - - 5 4 1 2 3 - current - - - 7 8 1 2 3 - current - - - 7 4 1 2 3 - current - - - 4 1 2 3 - current - - - 10 1 2 3 - current - - - 11 1 - current - - - 11 1 - current - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 0 + + + -0.62992 -0.62992 -1 0.62992 0.62992 1 + + + + + + + 13 + + + 14 + + + 0.0 4000000.0 20000000.0 + + + 0.0 0.7853981633974483 3.141592653589793 + + + 0.0 0.7853981633974483 3.141592653589793 + + + 1 + + + 14 + + + 13 + + + 2 + + + 3 + + + 5 6 1 2 3 + current + + + 5 4 1 2 3 + current + + + 7 8 1 2 3 + current + + + 7 4 1 2 3 + current + + + 4 1 2 3 + current + + + 10 1 2 3 + current + + + 11 1 + current + + + 11 1 + current + + diff --git a/tests/regression_tests/surface_tally/results_true.dat b/tests/regression_tests/surface_tally/results_true.dat index e50102a88..cfd70a013 100644 --- a/tests/regression_tests/surface_tally/results_true.dat +++ b/tests/regression_tests/surface_tally/results_true.dat @@ -1,52 +1,52 @@ mean,std. dev. -2.4100000e-02,2.1052844e-03 -6.7900000e-02,2.3211587e-03 -1.6860000e-01,4.4800794e-03 -6.4710000e-01,9.1826527e-03 -2.2000000e-03,3.8873013e-04 -5.5000000e-03,1.0979779e-03 -1.2500000e-02,1.5438048e-03 -4.4700000e-02,1.9035055e-03 -2.4100000e-02,2.1052844e-03 -6.7900000e-02,2.3211587e-03 -1.6860000e-01,4.4800794e-03 -6.4710000e-01,9.1826527e-03 -2.2000000e-03,3.8873013e-04 -5.5000000e-03,1.0979779e-03 -1.2500000e-02,1.5438048e-03 -4.4700000e-02,1.9035055e-03 --7.3000000e-03,9.8938814e-04 --3.6600000e-02,2.5086517e-03 --4.1600000e-02,2.4864075e-03 --4.2380000e-01,9.6087923e-03 --1.0000000e-04,1.0000000e-04 --1.5000000e-03,4.5338235e-04 --3.0000000e-04,1.5275252e-04 --1.7300000e-02,1.4609738e-03 --7.3000000e-03,9.8938814e-04 --3.6600000e-02,2.5086517e-03 --4.1600000e-02,2.4864075e-03 --4.2380000e-01,9.6087923e-03 --1.0000000e-04,1.0000000e-04 --1.5000000e-03,4.5338235e-04 --3.0000000e-04,1.5275252e-04 --1.7300000e-02,1.4609738e-03 -1.6800000e-02,1.5902481e-03 -3.1300000e-02,3.8094911e-03 -1.2700000e-01,5.0990195e-03 -2.2330000e-01,9.3631073e-03 -2.1000000e-03,3.7859389e-04 -4.0000000e-03,1.0540926e-03 -1.2200000e-02,1.6110728e-03 -2.7400000e-02,1.6613248e-03 +1.9600000e-02,1.5719768e-03 +7.3700000e-02,1.9382122e-03 +1.7130000e-01,4.0907755e-03 +6.3490000e-01,8.8197380e-03 +2.5000000e-03,5.2174919e-04 +6.0000000e-03,1.6799471e-03 +1.0600000e-02,1.8749815e-03 +4.0200000e-02,1.6852300e-03 +1.9600000e-02,1.5719768e-03 +7.3700000e-02,1.9382122e-03 +1.7130000e-01,4.0907755e-03 +6.3490000e-01,8.8197380e-03 +2.5000000e-03,5.2174919e-04 +6.0000000e-03,1.6799471e-03 +1.0600000e-02,1.8749815e-03 +4.0200000e-02,1.6852300e-03 +4.7000000e-03,9.1954095e-04 +4.5400000e-02,2.4413111e-03 +4.2800000e-02,2.2150997e-03 +4.2460000e-01,7.3017502e-03 0.0000000e+00,0.0000000e+00 --3.2000000e-02,1.5634719e-03 +1.6000000e-03,2.6666667e-04 +4.0000000e-04,1.6329932e-04 +1.5700000e-02,1.1551816e-03 +-4.7000000e-03,9.1954095e-04 +-4.5400000e-02,2.4413111e-03 +-4.2800000e-02,2.2150997e-03 +-4.2460000e-01,7.3017502e-03 0.0000000e+00,0.0000000e+00 --3.5400000e-01,7.5938572e-03 +-1.6000000e-03,2.6666667e-04 +-4.0000000e-04,1.6329932e-04 +-1.5700000e-02,1.1551816e-03 +1.4900000e-02,1.5235193e-03 +2.8300000e-02,2.0925795e-03 +1.2850000e-01,4.0613353e-03 +2.1030000e-01,5.4955538e-03 +2.5000000e-03,5.2174919e-04 +4.4000000e-03,1.4847372e-03 +1.0200000e-02,1.8903263e-03 +2.4500000e-02,1.7966017e-03 0.0000000e+00,0.0000000e+00 --3.0000000e-03,6.4978629e-04 +-3.0900000e-02,2.0518285e-03 0.0000000e+00,0.0000000e+00 --2.1800000e-02,1.4892205e-03 +-3.4370000e-01,4.5093730e-03 +0.0000000e+00,0.0000000e+00 +-2.9000000e-03,8.0897741e-04 +0.0000000e+00,0.0000000e+00 +-2.2200000e-02,2.0210009e-03 0.0000000e+00,0.0000000e+00 0.0000000e+00,0.0000000e+00 0.0000000e+00,0.0000000e+00 diff --git a/tests/regression_tests/surface_tally/test.py b/tests/regression_tests/surface_tally/test.py index aa03a8aa2..96199ec2a 100644 --- a/tests/regression_tests/surface_tally/test.py +++ b/tests/regression_tests/surface_tally/test.py @@ -6,8 +6,7 @@ from tests.testing_harness import PyAPITestHarness class SurfaceTallyTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): # Instantiate some Materials and register the appropriate Nuclides uo2 = openmc.Material(name='UO2 fuel at 2.4% wt enrichment') uo2.set_density('g/cc', 10.0) @@ -22,7 +21,8 @@ class SurfaceTallyTestHarness(PyAPITestHarness): borated_water.add_nuclide('O16', 1.0) # Instantiate a Materials collection and export to XML - self._model.materials = openmc.Materials([uo2, borated_water]) + materials_file = openmc.Materials([uo2, borated_water]) + materials_file.export_to_xml() # Instantiate ZCylinder surfaces fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=1, @@ -61,7 +61,8 @@ class SurfaceTallyTestHarness(PyAPITestHarness): root_univ.add_cell(root_cell) # Instantiate a Geometry, register the root Universe - self._model.geometry = openmc.Geometry(root_univ) + geometry = openmc.Geometry(root_univ) + geometry.export_to_xml() # Instantiate a Settings object, set all runtime parameters settings_file = openmc.Settings() @@ -72,10 +73,10 @@ class SurfaceTallyTestHarness(PyAPITestHarness): # Create an initial uniform spatial source distribution bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:],) - settings_file.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) - self._model.settings = settings_file + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:],\ + only_fissionable=True) + settings_file.source = openmc.source.Source(space=uniform_dist) + settings_file.export_to_xml() # Tallies file tallies_file = openmc.Tallies() @@ -106,19 +107,19 @@ class SurfaceTallyTestHarness(PyAPITestHarness): # Create partial current tallies from water to fuel # Filters - mat_from_filter = openmc.MaterialFromFilter(borated_water) + cell_from_filter = openmc.CellFromFilter(water) cell_filter = openmc.CellFilter(fuel) # Cell to cell filters for partial current cell_to_cell_tally = openmc.Tally(name=str('water_to_fuel_1')) - cell_to_cell_tally.filters = [mat_from_filter, cell_filter, \ + cell_to_cell_tally.filters = [cell_from_filter, cell_filter, \ energy_filter, polar_filter, azimuthal_filter] cell_to_cell_tally.scores = ['current'] tallies_file.append(cell_to_cell_tally) # Cell from + surface filters for partial current cell_to_cell_tally = openmc.Tally(name=str('water_to_fuel_2')) - cell_to_cell_tally.filters = [mat_from_filter, surface_filter, \ + cell_to_cell_tally.filters = [cell_from_filter, surface_filter, \ energy_filter, polar_filter, azimuthal_filter] cell_to_cell_tally.scores = ['current'] tallies_file.append(cell_to_cell_tally) @@ -155,7 +156,7 @@ class SurfaceTallyTestHarness(PyAPITestHarness): surf_tally3.scores = ['current'] tallies_file.append(surf_tally3) - self._model.tallies = tallies_file + tallies_file.export_to_xml() def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -163,14 +164,16 @@ class SurfaceTallyTestHarness(PyAPITestHarness): sp = openmc.StatePoint(self._sp_name) # Extract the tally data as a Pandas DataFrame. - tally_dfs = [t.get_pandas_dataframe() for t in sp.tallies.values()] - df = pd.concat(tally_dfs, ignore_index=True) + df = pd.DataFrame() + for t in sp.tallies.values(): + df = df.append(t.get_pandas_dataframe(), ignore_index=True) # Extract the relevant data as a CSV string. cols = ('mean', 'std. dev.') return df.to_csv(None, columns=cols, index=False, float_format='%.7e') + return outstr def test_surface_tally(): - harness = SurfaceTallyTestHarness('statepoint.10.h5', model=openmc.Model()) + harness = SurfaceTallyTestHarness('statepoint.10.h5') harness.main() diff --git a/tests/regression_tests/survival_biasing/results_true.dat b/tests/regression_tests/survival_biasing/results_true.dat index 932414e98..edd968340 100644 --- a/tests/regression_tests/survival_biasing/results_true.dat +++ b/tests/regression_tests/survival_biasing/results_true.dat @@ -1,20 +1,20 @@ k-combined: -9.517646E-01 1.303111E-02 +9.826269E-01 1.626276E-02 tally 1: -4.164635E+01 -3.470110E+02 -1.724300E+01 -5.949580E+01 -2.124917E+00 -9.034789E-01 -1.844790E+00 -6.809026E-01 -4.784396E+00 -4.579552E+00 -3.348849E-02 -2.243613E-04 -3.573090E+08 -2.554338E+16 +4.209907E+01 +3.546281E+02 +1.759415E+01 +6.197412E+01 +2.165888E+00 +9.392975E-01 +1.873459E+00 +7.025989E-01 +4.850267E+00 +4.708899E+00 +3.397795E-02 +2.310621E-04 +3.628554E+08 +2.635633E+16 tally 2: -1.724300E+01 -5.949580E+01 +1.759415E+01 +6.197412E+01 diff --git a/tests/regression_tests/tallies/inputs_true.dat b/tests/regression_tests/tallies/inputs_true.dat index 40829f865..61daba0d4 100644 --- a/tests/regression_tests/tallies/inputs_true.dat +++ b/tests/regression_tests/tallies/inputs_true.dat @@ -1,187 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -199,12 +50,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -222,12 +73,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -249,12 +100,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -276,228 +127,378 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 400 - 5 - 0 - - - -160 -160 -183 160 160 183 - - - - - - 2 2 - -182.07 -182.07 - 182.07 182.07 - - - -3.14159 -1.885 -0.6283 0.6283 1.885 3.14159 - - - 1 - - - 10 21 22 23 - - - 1 2 3 4 5 6 - - - 0.0 0.253 1000.0 1000000.0 20000000.0 - - - 0.0 0.253 1000.0 1000000.0 20000000.0 - - - 1 2 3 4 - - - -1.0 -0.5 0.0 0.5 1.0 - - - 0.0 0.6283 1.2566 1.885 2.5132 3.14159 - - - 4 - - - 4 - - - 1 2 3 4 6 8 - - - 1 2 5 3 6 - - - 10 21 22 23 60 - - - 21 22 23 27 28 29 60 - - - 1 - flux - tracklength - - - 1 - flux - analog - - - 1 2 - flux - tracklength - - - 3 - total - - - 4 - U235 O16 total - delayed-nu-fission decay-rate - - - 5 - total - - - 6 - scatter - - - 5 6 - scatter nu-fission - - - 7 - total - - - 8 - scatter nu-scatter - - - 8 2 - scatter nu-scatter - - - 9 - flux - tracklength - - - 9 - flux - analog - - - 9 2 - flux - tracklength - - - 10 - scatter nu-scatter - analog - - - 11 - scatter nu-scatter flux total - analog - - - 11 - flux total - collision - - - 11 - flux total - tracklength - - - 12 - total - - - 15 - scatter - - - 13 - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - tracklength - - - 13 - U235 O16 total - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - tracklength - - - 13 - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - analog - - - 13 - U235 O16 total - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - analog - - - 13 - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - collision - - - 13 - U235 O16 total - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - collision - - - 14 - flux - tracklength - - - 14 - flux - analog - - - 14 - flux - collision - - - H1-production H2-production H3-production He3-production He4-production heating damage-energy - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 400 + 5 + 0 + + + -160 -160 -183 160 160 183 + + + + + + + 2 2 + -182.07 -182.07 + 182.07 182.07 + + + -3.14159 -1.885 -0.6283 0.6283 1.885 3.14159 + + + 1 + + + 10 21 22 23 + + + 1 2 3 4 5 6 + + + 0.0 0.253 1000.0 1000000.0 20000000.0 + + + 0.0 0.253 1000.0 1000000.0 20000000.0 + + + 1 2 3 4 + + + -1.0 -0.5 0.0 0.5 1.0 + + + 0.0 0.6283 1.2566 1.885 2.5132 3.14159 + + + 4 + + + 4 + + + 1 2 3 4 6 8 + + + 1 2 5 3 6 + + + 10 21 22 23 60 + + + 21 22 23 27 28 29 60 + + + 1 + flux + tracklength + + + 1 + flux + analog + + + 1 2 + flux + tracklength + + + 3 + total + + + 4 + U235 O16 total + delayed-nu-fission decay-rate + + + 5 + total + + + 6 + scatter + + + 5 6 + scatter nu-fission + + + 7 + total + + + 8 + scatter nu-scatter + + + 8 2 + scatter nu-scatter + + + 9 + flux + tracklength + + + 9 + flux + analog + + + 9 2 + flux + tracklength + + + 10 + scatter nu-scatter + analog + + + 11 + scatter nu-scatter flux total + analog + + + 11 + flux total + collision + + + 11 + flux total + tracklength + + + 12 + total + + + 15 + scatter + + + 13 + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + tracklength + + + 13 + U235 O16 total + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + tracklength + + + 13 + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + analog + + + 13 + U235 O16 total + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + analog + + + 13 + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + collision + + + 13 + U235 O16 total + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + collision + + + 14 + flux + tracklength + + + 14 + flux + analog + + + 14 + flux + collision + + + H1-production H2-production H3-production He3-production He4-production heating damage-energy + + diff --git a/tests/regression_tests/tallies/results_true.dat b/tests/regression_tests/tallies/results_true.dat index 1d3aca4b0..6739f5348 100644 --- a/tests/regression_tests/tallies/results_true.dat +++ b/tests/regression_tests/tallies/results_true.dat @@ -1 +1 @@ -d01c3accd5b4de2aa166a77df28cfe42f5738a44c2480752fcfae7564a507362fff006b6dffb7b1dfe248e14bacef0070cabacea5d75c5996653e5605f7c7384 \ No newline at end of file +ad28e723270c25dc46f27f1482052e381c802cb111ea8224368d4ea3d903eeaba1a3dce541957f24ec0634ed2ada6f20f97c0270c269b9bcae4b34a1b317a165 \ No newline at end of file diff --git a/tests/regression_tests/tallies/test.py b/tests/regression_tests/tallies/test.py index d20067ed3..3e1c6e7ba 100644 --- a/tests/regression_tests/tallies/test.py +++ b/tests/regression_tests/tallies/test.py @@ -13,7 +13,7 @@ def test_tallies(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 400 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + model.settings.source = openmc.Source(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) azimuthal_bins = (-3.14159, -1.8850, -0.6283, 0.6283, 1.8850, 3.14159) @@ -40,7 +40,7 @@ def test_tallies(): cellborn_tally = Tally() cellborn_tally.filters = [ - CellBornFilter((model.geometry.get_all_cells()[10], + CellbornFilter((model.geometry.get_all_cells()[10], model.geometry.get_all_cells()[21], 22, 23))] # Test both Cell objects and ids cellborn_tally.scores = ['total'] diff --git a/tests/regression_tests/tally_aggregation/inputs_true.dat b/tests/regression_tests/tally_aggregation/inputs_true.dat index 7351b230c..80356f711 100644 --- a/tests/regression_tests/tally_aggregation/inputs_true.dat +++ b/tests/regression_tests/tally_aggregation/inputs_true.dat @@ -1,56 +1,57 @@ - - - - - - - - - - - - - - - - - - - - - - 1.2 1.2 - 1 - 2 2 - -1.2 -1.2 - + + + + + + 1.2 1.2 + 1 + 2 2 + -1.2 -1.2 + 1 1 1 1 - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - - 0.0 0.253 1000.0 1000000.0 20000000.0 - - - 1 - - - 1 2 - U234 U235 U238 - nu-fission total - - - + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + + + 0.0 0.253 1000.0 1000000.0 20000000.0 + + + 1 + + + 1 2 + U234 U235 U238 + nu-fission total + + diff --git a/tests/regression_tests/tally_aggregation/results_true.dat b/tests/regression_tests/tally_aggregation/results_true.dat index ee6263373..a86eff895 100644 --- a/tests/regression_tests/tally_aggregation/results_true.dat +++ b/tests/regression_tests/tally_aggregation/results_true.dat @@ -1,97 +1,97 @@ -[[1.6242805e-05 6.2367673e-04] - [3.2895972e-01 1.7786452e-01] - [1.8044266e-02 7.0451122e-01]], [[1.6113947e-05 5.3572864e-04] - [3.1517504e-01 1.7132833e-01] - [1.8305682e-02 7.0072832e-01]], [[1.6472052e-05 5.5758006e-04] - [3.2362364e-01 1.7597163e-01] - [1.9107080e-02 7.2600440e-01]], [[1.6693277e-05 4.9204218e-04] - [3.2429262e-01 1.7600573e-01] - [1.9042489e-02 7.3053854e-01]][[2.9719061e-07 8.0925438e-05] - [8.9432259e-03 4.4057583e-03] - [5.2078407e-04 6.4387688e-03]], [[1.8572081e-07 2.5667235e-05] - [1.1641603e-02 5.7444311e-03] - [2.6983611e-04 6.9783224e-03]], [[2.4994113e-07 5.4993390e-05] - [6.0464041e-03 3.0764811e-03] - [2.6559118e-04 7.7279780e-03]], [[2.5965232e-07 3.9618775e-05] - [1.0409564e-02 5.1850104e-03] - [2.7831231e-04 7.4480576e-03]][[1.0329435e-06 8.0861229e-04] - [1.1265142e+00 5.5796079e-01] - [1.3965860e-06 5.0338828e-01]], [[2.2264172e-06 1.0828687e-03] - [1.4724979e-01 1.0226107e-01] - [2.2656045e-05 7.7618945e-01]], [[1.4789782e-05 2.2786630e-04] - [1.3149968e-02 2.9847169e-02] - [3.2638111e-04 1.1287326e+00]], [[4.7472938e-05 8.9680338e-05] - [5.1371041e-03 1.1101179e-02] - [7.4149084e-02 4.5347217e-01]][[1.7024771e-08 1.2878244e-05] - [1.8795566e-02 9.2705008e-03] - [2.2676749e-08 7.0878353e-03]], [[2.2018925e-07 1.0785388e-04] - [2.6715019e-03 1.6657928e-03] - [1.2479083e-05 8.6814018e-03]], [[2.0928485e-07 1.6600875e-06] - [1.1859535e-04 1.7969083e-04] - [1.5981387e-05 8.0489308e-03]], [[4.0016381e-07 7.6799157e-07] - [4.4157583e-05 9.4462925e-05] - [7.0115110e-04 3.8678806e-03]][[0.287433 0.2698042]], [[0.2751228 0.2598525]], [[0.280516 0.2648274]], [[0.2834448 0.2676736]], [[0.0370558 0.2148509]], [[0.0355217 0.2130189]], [[0.0385317 0.2292804]], [[0.0361655 0.2223832]], [[0.0033268 0.2855078]], [[0.0033498 0.2849403]], [[0.003359 0.2901157]], [[0.0034555 0.2982438]], [[0.0192046 0.1128364]], [[0.0195026 0.1147807]], [[0.0203405 0.1183102]], [[0.0202861 0.1187358]][[0.00889 0.0051934]], [[0.0115249 0.0072767]], [[0.0058841 0.0040289]], [[0.0103341 0.0063266]], [[0.0009734 0.0048865]], [[0.0016425 0.0038133]], [[0.0013902 0.0048875]], [[0.0012487 0.0039808]], [[1.8994140e-05 2.0410145e-03]], [[6.8277082e-05 3.4865782e-03]], [[6.1643568e-05 4.9220817e-03]], [[7.4147413e-05 4.9263295e-03]], [[0.0005213 0.0024208]], [[0.0002702 0.0014313]], [[0.0002665 0.0022006]], [[0.0002788 0.0014892]][[2.0601081e-04] - [4.2976789e-01] - [1.2726338e-01]], [[1.9802070e-04] - [4.1138025e-01] - [1.2339705e-01]], [[2.0174854e-04] - [4.1947542e-01] - [1.2566615e-01]], [[2.0386518e-04] - [4.2385140e-01] - [1.2706310e-01]], [[0.0003403] - [0.0624955] - [0.189071 ]], [[0.0002601] - [0.060449 ] - [0.1878314]], [[0.0002765] - [0.0652412] - [0.2022944]], [[0.0002082] - [0.0613252] - [0.1970153]], [[6.0336874e-05] - [1.0617692e-02] - [2.7815664e-01]], [[5.9823997e-05] - [1.0664059e-02] - [2.7756620e-01]], [[6.0873689e-05] - [1.0744209e-02] - [2.8266963e-01]], [[6.1621521e-05] - [1.0971177e-02] - [2.9066650e-01]], [[3.3297391e-05] - [3.9432037e-03] - [1.2806450e-01]], [[3.3863464e-05] - [4.0100180e-03] - [1.3023932e-01]], [[3.4930617e-05] - [4.1344613e-03] - [1.3448129e-01]], [[3.5061805e-05] - [4.1505999e-03] - [1.3483614e-01]][[5.8259835e-06] - [9.9096571e-03] - [2.7933778e-03]], [[8.0858909e-06] - [1.2843377e-02] - [4.5631248e-03]], [[4.3418585e-06] - [6.5638646e-03] - [2.7874612e-03]], [[6.9046376e-06] - [1.1531588e-02] - [3.7205377e-03]], [[8.0710599e-05] - [1.0889301e-03] - [4.8613465e-03]], [[2.4337121e-05] - [1.8861117e-03] - [3.6987509e-03]], [[5.4812439e-05] - [1.7085353e-03] - [4.7852139e-03]], [[3.9007791e-05] - [1.4998363e-03] - [3.8929646e-03]], [[7.5757577e-07] - [2.5845755e-05] - [2.0409391e-03]], [[1.0302346e-06] - [1.1907557e-04] - [3.4852130e-03]], [[9.1936614e-07] - [1.2974020e-04] - [4.9207575e-03]], [[5.6493555e-07] - [1.2113685e-04] - [4.9253980e-03]], [[5.4602210e-07] - [6.5233025e-05] - [2.4754550e-03]], [[3.2091909e-07] - [3.8472906e-05] - [1.4560974e-03]], [[4.8475651e-07] - [5.9108262e-05] - [2.2158781e-03]], [[3.3737822e-07] - [4.0544269e-05] - [1.5145628e-03]] \ No newline at end of file +[[1.6100557e-05 5.2845844e-04] + [3.1178030e-01 1.6963068e-01] + [1.8103970e-02 7.1792000e-01]], [[1.6327747e-05 5.3562414e-04] + [3.2299959e-01 1.7506573e-01] + [1.8518775e-02 7.2159429e-01]], [[1.5779072e-05 5.7847880e-04] + [3.1206099e-01 1.6937953e-01] + [1.7615699e-02 6.9887963e-01]], [[1.6129040e-05 5.2214564e-04] + [3.3116549e-01 1.7924984e-01] + [1.8339236e-02 7.1809645e-01]][[2.5070599e-07 4.1541177e-05] + [8.8868371e-03 4.3482360e-03] + [4.2929455e-04 5.1166511e-03]], [[2.6348920e-07 4.0911978e-05] + [9.5560259e-03 4.6948487e-03] + [5.1500008e-04 8.2022796e-03]], [[2.8482730e-07 5.2369388e-05] + [5.9366950e-03 2.9803949e-03] + [3.5036278e-04 7.1193378e-03]], [[4.9529279e-07 5.2183723e-05] + [1.1645140e-02 5.7325245e-03] + [9.3005699e-04 9.2536054e-03]][[1.0276552e-06 8.0660598e-04] + [1.1192721e+00 5.5462743e-01] + [1.3911834e-06 5.0699881e-01]], [[1.9629638e-06 1.0409504e-03] + [1.4059305e-01 9.8087142e-02] + [2.9492646e-05 7.8705320e-01]], [[1.5107402e-05 2.2995488e-04] + [1.3135825e-02 2.9816182e-02] + [3.2964785e-04 1.1215217e+00]], [[4.6238395e-05 8.7195730e-05] + [5.0054342e-03 1.0795027e-02] + [7.2217149e-02 4.4091666e-01]][[1.6532673e-08 1.2337935e-05] + [1.8386631e-02 9.0206165e-03] + [2.1821704e-08 6.5857974e-03]], [[1.4398993e-07 9.3322326e-05] + [1.7502917e-03 1.1333022e-03] + [1.2352929e-05 1.0990819e-02]], [[2.0866393e-07 1.5849226e-06] + [1.0531329e-04 1.2841877e-04] + [5.5780807e-06 5.5626593e-03]], [[6.2783320e-07 1.1660991e-06] + [6.5703644e-05 1.4478948e-04] + [1.1987891e-03 5.8870776e-03]][[0.2726472 0.2604765]], [[0.2826295 0.2668458]], [[0.2735803 0.2601036]], [[0.2904175 0.2750069]], [[0.0346119 0.2258269]], [[0.0357798 0.2250003]], [[0.0340719 0.2185953]], [[0.0361609 0.2167588]], [[0.0033548 0.2889666]], [[0.0034114 0.2907593]], [[0.003291 0.2797162]], [[0.0034234 0.2921258]], [[0.0192865 0.1128092]], [[0.0197139 0.1145903]], [[0.0187492 0.1104225]], [[0.0195192 0.1139769]][[0.0088278 0.0052328]], [[0.0095476 0.0057391]], [[0.0058888 0.003768 ]], [[0.0115889 0.007087 ]], [[0.0010202 0.0025054]], [[0.0003997 0.00688 ]], [[0.0007498 0.0052687]], [[0.0011406 0.0063813]], [[6.0992197e-05 2.7321486e-03]], [[3.8711312e-05 2.3727208e-03]], [[5.9558150e-05 3.2498217e-03]], [[4.8541326e-05 2.7025714e-03]], [[0.00043 0.0019911]], [[0.0005155 0.001849 ]], [[0.0003513 0.0026556]], [[0.0009313 0.0044993]][[1.9753031e-04] + [4.0779730e-01] + [1.2512884e-01]], [[2.0324106e-04] + [4.2264184e-01] + [1.2663026e-01]], [[1.9762520e-04] + [4.0915145e-01] + [1.2433487e-01]], [[2.0923706e-04] + [4.3430891e-01] + [1.3090624e-01]], [[0.0002534] + [0.0589558] + [0.2012296]], [[0.0002515] + [0.0604991] + [0.2000296]], [[0.0003047] + [0.0579695] + [0.1943931]], [[0.0002334] + [0.0612558] + [0.1914305]], [[6.0316499e-05] + [1.0710899e-02] + [2.8155013e-01]], [[6.3374666e-05] + [1.0915514e-02] + [2.8319179e-01]], [[5.9392082e-05] + [1.0461186e-02] + [2.7248670e-01]], [[6.1979034e-05] + [1.0864408e-02] + [2.8462272e-01]], [[3.3331895e-05] + [3.9469598e-03] + [1.2811544e-01]], [[3.3851214e-05] + [4.0088932e-03] + [1.3026145e-01]], [[3.2587500e-05] + [3.8583992e-03] + [1.2528067e-01]], [[3.3663516e-05] + [3.9862087e-03] + [1.2947625e-01]][[5.9589021e-06] + [9.8268994e-03] + [2.9572748e-03]], [[6.3833088e-06] + [1.0635294e-02] + [3.3142463e-03]], [[4.0655901e-06] + [6.5668548e-03] + [2.3984140e-03]], [[7.7097818e-06] + [1.2908862e-02] + [4.2297322e-03]], [[4.1105542e-05] + [1.1418202e-03] + [2.4520182e-03]], [[4.0406959e-05] + [4.9407982e-04] + [6.8737413e-03]], [[5.2191221e-05] + [9.9374825e-04] + [5.2279051e-03]], [[5.1601995e-05] + [1.3462879e-03] + [6.3408638e-03]], [[5.9462092e-07] + [9.1472877e-05] + [2.7312979e-03]], [[4.5487504e-07] + [5.5343645e-05] + [2.3723911e-03]], [[1.3568221e-06] + [1.0496033e-04] + [3.2486719e-03]], [[3.9251575e-07] + [7.1661652e-05] + [2.7020572e-03]], [[4.5230086e-07] + [5.4399064e-05] + [2.0363096e-03]], [[4.2836596e-07] + [5.0791493e-05] + [1.9188091e-03]], [[5.8337236e-07] + [7.0477126e-05] + [2.6777741e-03]], [[1.0127017e-06] + [1.2155206e-04] + [4.5930293e-03]] \ No newline at end of file diff --git a/tests/regression_tests/tally_aggregation/test.py b/tests/regression_tests/tally_aggregation/test.py index 08d911660..a29839a6f 100644 --- a/tests/regression_tests/tally_aggregation/test.py +++ b/tests/regression_tests/tally_aggregation/test.py @@ -33,8 +33,8 @@ def model(): [pin, pin], [pin, pin], ] - box = openmc.model.RectangularPrism(2*d, 2*d, boundary_type='reflective') - main_cell = openmc.Cell(fill=lattice, region=-box) + box = openmc.model.rectangular_prism(2*d, 2*d, boundary_type='reflective') + main_cell = openmc.Cell(fill=lattice, region=box) model.geometry = openmc.Geometry([main_cell]) model.settings.batches = 10 diff --git a/tests/regression_tests/tally_arithmetic/inputs_true.dat b/tests/regression_tests/tally_arithmetic/inputs_true.dat index 2b5234c34..fbbf94fa9 100644 --- a/tests/regression_tests/tally_arithmetic/inputs_true.dat +++ b/tests/regression_tests/tally_arithmetic/inputs_true.dat @@ -1,55 +1,56 @@ - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - 2 2 - -10.0 -10.0 - 10.0 10.0 - - - 1 2 - - - 0.0 10.0 20000000.0 - - - 1 - - - 2 1 - U234 U235 - nu-fission total - - - 1 3 - U238 U235 - total fission - - - + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + + 2 2 + -10.0 -10.0 + 10.0 10.0 + + + 1 2 + + + 0.0 10.0 20000000.0 + + + 1 + + + 2 1 + U234 U235 + nu-fission total + + + 1 3 + U238 U235 + total fission + + diff --git a/tests/regression_tests/tally_arithmetic/results_true.dat b/tests/regression_tests/tally_arithmetic/results_true.dat index baa380587..473dd5ee7 100644 --- a/tests/regression_tests/tally_arithmetic/results_true.dat +++ b/tests/regression_tests/tally_arithmetic/results_true.dat @@ -1,49 +1,49 @@ -[2.29467e-07 1.47622e-13 2.02646e-04 1.30367e-10 2.20704e-07 1.76624e-07 - 1.94907e-04 1.55980e-04 6.32267e-03 4.06754e-09 3.26873e-03 2.10286e-09 - 6.08121e-03 4.86666e-03 3.14390e-03 2.51599e-03 1.89223e-07 1.06256e-13 - 1.67106e-04 9.38364e-11 1.53300e-07 1.20220e-07 1.35382e-04 1.06168e-04 - 5.21380e-03 2.92775e-09 2.69546e-03 1.51361e-09 4.22399e-03 3.31252e-03 - 2.18374e-03 1.71253e-03 2.21146e-07 1.41349e-13 1.95297e-04 1.24828e-10 - 2.11844e-07 1.69398e-07 1.87083e-04 1.49598e-04 6.09339e-03 3.89470e-09 - 3.15020e-03 2.01351e-09 5.83710e-03 4.66754e-03 3.01770e-03 2.41305e-03 - 1.92872e-07 1.05908e-13 1.70328e-04 9.35293e-11 1.59466e-07 1.25399e-07 - 1.40827e-04 1.10741e-04 5.31433e-03 2.91817e-09 2.74744e-03 1.50865e-09 - 4.39388e-03 3.45520e-03 2.27158e-03 1.78629e-03 2.44601e-03 4.71663e-05 - 1.09430e-02 2.11013e-04 1.23573e-04 2.76181e-05 5.52841e-04 1.23558e-04 - 2.71755e-02 5.24023e-04 4.76200e-02 9.18253e-04 1.37291e-03 3.06841e-04 - 2.40577e-03 5.37681e-04 2.29014e-03 4.44674e-05 1.02456e-02 1.98938e-04 - 1.12524e-04 2.48126e-05 5.03411e-04 1.11007e-04 2.54438e-02 4.94038e-04 - 4.45855e-02 8.65710e-04 1.25016e-03 2.75671e-04 2.19067e-03 4.83061e-04 - 2.38500e-03 4.58053e-05 1.06700e-02 2.04924e-04 1.22899e-04 2.95267e-05 - 5.49826e-04 1.32097e-04 2.64977e-02 5.08903e-04 4.64323e-02 8.91758e-04 - 1.36542e-03 3.28045e-04 2.39265e-03 5.74839e-04 2.17094e-03 4.21772e-05 - 9.71236e-03 1.88693e-04 1.09358e-04 2.46984e-05 4.89245e-04 1.10496e-04 - 2.41194e-02 4.68594e-04 4.22648e-02 8.21124e-04 1.21498e-03 2.74402e-04 - 2.12902e-03 4.80839e-04][2.29467e-07 1.47622e-13 2.02646e-04 1.30367e-10 2.20704e-07 1.76624e-07 - 1.94907e-04 1.55980e-04 6.32267e-03 4.06754e-09 3.26873e-03 2.10286e-09 - 6.08121e-03 4.86666e-03 3.14390e-03 2.51599e-03 1.89223e-07 1.06256e-13 - 1.67106e-04 9.38364e-11 1.53300e-07 1.20220e-07 1.35382e-04 1.06168e-04 - 5.21380e-03 2.92775e-09 2.69546e-03 1.51361e-09 4.22399e-03 3.31252e-03 - 2.18374e-03 1.71253e-03 2.21146e-07 1.41349e-13 1.95297e-04 1.24828e-10 - 2.11844e-07 1.69398e-07 1.87083e-04 1.49598e-04 6.09339e-03 3.89470e-09 - 3.15020e-03 2.01351e-09 5.83710e-03 4.66754e-03 3.01770e-03 2.41305e-03 - 1.92872e-07 1.05908e-13 1.70328e-04 9.35293e-11 1.59466e-07 1.25399e-07 - 1.40827e-04 1.10741e-04 5.31433e-03 2.91817e-09 2.74744e-03 1.50865e-09 - 4.39388e-03 3.45520e-03 2.27158e-03 1.78629e-03 2.44601e-03 4.71663e-05 - 1.09430e-02 2.11013e-04 1.23573e-04 2.76181e-05 5.52841e-04 1.23558e-04 - 2.71755e-02 5.24023e-04 4.76200e-02 9.18253e-04 1.37291e-03 3.06841e-04 - 2.40577e-03 5.37681e-04 2.29014e-03 4.44674e-05 1.02456e-02 1.98938e-04 - 1.12524e-04 2.48126e-05 5.03411e-04 1.11007e-04 2.54438e-02 4.94038e-04 - 4.45855e-02 8.65710e-04 1.25016e-03 2.75671e-04 2.19067e-03 4.83061e-04 - 2.38500e-03 4.58053e-05 1.06700e-02 2.04924e-04 1.22899e-04 2.95267e-05 - 5.49826e-04 1.32097e-04 2.64977e-02 5.08903e-04 4.64323e-02 8.91758e-04 - 1.36542e-03 3.28045e-04 2.39265e-03 5.74839e-04 2.17094e-03 4.21772e-05 - 9.71236e-03 1.88693e-04 1.09358e-04 2.46984e-05 4.89245e-04 1.10496e-04 - 2.41194e-02 4.68594e-04 4.22648e-02 8.21124e-04 1.21498e-03 2.74402e-04 - 2.12902e-03 4.80839e-04][0.00608 0.00487 0.00314 0.00252 0.00422 0.00331 0.00218 0.00171 0.00584 - 0.00467 0.00302 0.00241 0.00439 0.00346 0.00227 0.00179 0.00137 0.00031 - 0.00241 0.00054 0.00125 0.00028 0.00219 0.00048 0.00137 0.00033 0.00239 - 0.00057 0.00121 0.00027 0.00213 0.00048][0.0002 0.00019 0.00327 0.00314 0.00017 0.00014 0.0027 0.00218 0.0002 - 0.00019 0.00315 0.00302 0.00017 0.00014 0.00275 0.00227 0.01094 0.00055 - 0.04762 0.00241 0.01025 0.0005 0.04459 0.00219 0.01067 0.00055 0.04643 - 0.00239 0.00971 0.00049 0.04226 0.00213][0.00314 0.00218 0.00302 0.00227 0.00241 0.00219 0.00239 0.00213] \ No newline at end of file +[2.18485e-07 1.40714e-13 1.90835e-04 1.22906e-10 2.14194e-07 1.70920e-07 + 1.87087e-04 1.49289e-04 5.77324e-03 3.71823e-09 2.98131e-03 1.92010e-09 + 5.65986e-03 4.51638e-03 2.92276e-03 2.33227e-03 1.77087e-07 1.04308e-13 + 1.54676e-04 9.11076e-11 1.53337e-07 1.20737e-07 1.33931e-04 1.05457e-04 + 4.67935e-03 2.75624e-09 2.41642e-03 1.42333e-09 4.05176e-03 3.19035e-03 + 2.09234e-03 1.64750e-03 2.32566e-07 1.53743e-13 2.03133e-04 1.34286e-10 + 2.42559e-07 1.94114e-07 2.11862e-04 1.69548e-04 6.14530e-03 4.06249e-09 + 3.17345e-03 2.09788e-09 6.40937e-03 5.12926e-03 3.30981e-03 2.64876e-03 + 2.15237e-07 1.23240e-13 1.87998e-04 1.07643e-10 1.85758e-07 1.46699e-07 + 1.62249e-04 1.28134e-04 5.68742e-03 3.25649e-09 2.93699e-03 1.68166e-09 + 4.90845e-03 3.87638e-03 2.53473e-03 2.00177e-03 2.47477e-03 4.87068e-05 + 1.06189e-02 2.08993e-04 1.26298e-04 3.02426e-05 5.41924e-04 1.29766e-04 + 2.77770e-02 5.46688e-04 4.83214e-02 9.51031e-04 1.41757e-03 3.39445e-04 + 2.46604e-03 5.90506e-04 2.31220e-03 4.16752e-05 9.92129e-03 1.78822e-04 + 1.15514e-04 2.68262e-05 4.95652e-04 1.15107e-04 2.59523e-02 4.67766e-04 + 4.51471e-02 8.13735e-04 1.29654e-03 3.01100e-04 2.25548e-03 5.23800e-04 + 2.30792e-03 4.67592e-05 9.90296e-03 2.00637e-04 1.15169e-04 2.57221e-05 + 4.94175e-04 1.10370e-04 2.59043e-02 5.24828e-04 4.50637e-02 9.13003e-04 + 1.29267e-03 2.88707e-04 2.24876e-03 5.02241e-04 2.35337e-03 4.59723e-05 + 1.00979e-02 1.97260e-04 1.17182e-04 2.59928e-05 5.02809e-04 1.11531e-04 + 2.64144e-02 5.15997e-04 4.59510e-02 8.97639e-04 1.31526e-03 2.91745e-04 + 2.28805e-03 5.07527e-04][2.18485e-07 1.40714e-13 1.90835e-04 1.22906e-10 2.14194e-07 1.70920e-07 + 1.87087e-04 1.49289e-04 5.77324e-03 3.71823e-09 2.98131e-03 1.92010e-09 + 5.65986e-03 4.51638e-03 2.92276e-03 2.33227e-03 1.77087e-07 1.04308e-13 + 1.54676e-04 9.11076e-11 1.53337e-07 1.20737e-07 1.33931e-04 1.05457e-04 + 4.67935e-03 2.75624e-09 2.41642e-03 1.42333e-09 4.05176e-03 3.19035e-03 + 2.09234e-03 1.64750e-03 2.32566e-07 1.53743e-13 2.03133e-04 1.34286e-10 + 2.42559e-07 1.94114e-07 2.11862e-04 1.69548e-04 6.14530e-03 4.06249e-09 + 3.17345e-03 2.09788e-09 6.40937e-03 5.12926e-03 3.30981e-03 2.64876e-03 + 2.15237e-07 1.23240e-13 1.87998e-04 1.07643e-10 1.85758e-07 1.46699e-07 + 1.62249e-04 1.28134e-04 5.68742e-03 3.25649e-09 2.93699e-03 1.68166e-09 + 4.90845e-03 3.87638e-03 2.53473e-03 2.00177e-03 2.47477e-03 4.87068e-05 + 1.06189e-02 2.08993e-04 1.26298e-04 3.02426e-05 5.41924e-04 1.29766e-04 + 2.77770e-02 5.46688e-04 4.83214e-02 9.51031e-04 1.41757e-03 3.39445e-04 + 2.46604e-03 5.90506e-04 2.31220e-03 4.16752e-05 9.92129e-03 1.78822e-04 + 1.15514e-04 2.68262e-05 4.95652e-04 1.15107e-04 2.59523e-02 4.67766e-04 + 4.51471e-02 8.13735e-04 1.29654e-03 3.01100e-04 2.25548e-03 5.23800e-04 + 2.30792e-03 4.67592e-05 9.90296e-03 2.00637e-04 1.15169e-04 2.57221e-05 + 4.94175e-04 1.10370e-04 2.59043e-02 5.24828e-04 4.50637e-02 9.13003e-04 + 1.29267e-03 2.88707e-04 2.24876e-03 5.02241e-04 2.35337e-03 4.59723e-05 + 1.00979e-02 1.97260e-04 1.17182e-04 2.59928e-05 5.02809e-04 1.11531e-04 + 2.64144e-02 5.15997e-04 4.59510e-02 8.97639e-04 1.31526e-03 2.91745e-04 + 2.28805e-03 5.07527e-04][0.00566 0.00452 0.00292 0.00233 0.00405 0.00319 0.00209 0.00165 0.00641 + 0.00513 0.00331 0.00265 0.00491 0.00388 0.00253 0.002 0.00142 0.00034 + 0.00247 0.00059 0.0013 0.0003 0.00226 0.00052 0.00129 0.00029 0.00225 + 0.0005 0.00132 0.00029 0.00229 0.00051][0.00019 0.00019 0.00298 0.00292 0.00015 0.00013 0.00242 0.00209 0.0002 + 0.00021 0.00317 0.00331 0.00019 0.00016 0.00294 0.00253 0.01062 0.00054 + 0.04832 0.00247 0.00992 0.0005 0.04515 0.00226 0.0099 0.00049 0.04506 + 0.00225 0.0101 0.0005 0.04595 0.00229][0.00292 0.00209 0.00331 0.00253 0.00247 0.00226 0.00225 0.00229] \ No newline at end of file diff --git a/tests/regression_tests/tally_assumesep/results_true.dat b/tests/regression_tests/tally_assumesep/results_true.dat index c9ccf0928..5728cfc04 100644 --- a/tests/regression_tests/tally_assumesep/results_true.dat +++ b/tests/regression_tests/tally_assumesep/results_true.dat @@ -1,11 +1,11 @@ k-combined: -6.268465E-01 1.154810E-02 +6.353587E-01 1.925016E-02 tally 1: -7.828708E+00 -1.230478E+01 +7.878503E+00 +1.242768E+01 tally 2: -2.582239E-01 -1.360117E-02 +2.687214E-01 +1.487262E-02 tally 3: -1.339335E+01 -3.663458E+01 +1.344654E+01 +3.630145E+01 diff --git a/tests/regression_tests/tally_nuclides/results_true.dat b/tests/regression_tests/tally_nuclides/results_true.dat index 93a0e03fb..ad385b82a 100644 --- a/tests/regression_tests/tally_nuclides/results_true.dat +++ b/tests/regression_tests/tally_nuclides/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.732610E-01 1.400780E-02 +9.655280E-01 1.463557E-02 tally 1: -7.123025E+00 -1.021136E+01 -1.619905E+00 -5.258592E-01 -1.561322E+00 -4.881841E-01 -5.503120E+00 -6.105683E+00 -7.123025E+00 -1.021136E+01 -1.619905E+00 -5.258592E-01 -1.561322E+00 -4.881841E-01 -5.503120E+00 -6.105683E+00 +6.932814E+00 +9.650528E+00 +1.591338E+00 +5.075076E-01 +1.541515E+00 +4.761914E-01 +5.341475E+00 +5.732892E+00 +6.932814E+00 +9.650528E+00 +1.591338E+00 +5.075076E-01 +1.541515E+00 +4.761914E-01 +5.341475E+00 +5.732892E+00 tally 2: -7.123025E+00 -1.021136E+01 -1.619905E+00 -5.258592E-01 -1.561322E+00 -4.881841E-01 -5.503120E+00 -6.105683E+00 +6.932814E+00 +9.650528E+00 +1.591338E+00 +5.075076E-01 +1.541515E+00 +4.761914E-01 +5.341475E+00 +5.732892E+00 diff --git a/tests/regression_tests/tally_slice_merge/inputs_true.dat b/tests/regression_tests/tally_slice_merge/inputs_true.dat index 7a992cc39..6f421b1d9 100644 --- a/tests/regression_tests/tally_slice_merge/inputs_true.dat +++ b/tests/regression_tests/tally_slice_merge/inputs_true.dat @@ -1,187 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -199,12 +50,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -222,12 +73,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -249,12 +100,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -276,72 +127,222 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -160 -160 -183 160 160 183 - - - - - - - 2 2 - -50.0 -50.0 - 50.0 50.0 - - - 21 27 - - - 0.0 0.625 20000000.0 - - - 21 - - - 1 - - - 16 8 - U235 U238 - fission nu-fission - tracklength - - - 6 8 - U235 U238 - fission nu-fission - tracklength - - - 7 8 - U235 U238 - fission nu-fission - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -160 -160 -183 160 160 183 + + + + + + + + 2 2 + -50.0 -50.0 + 50.0 50.0 + + + 21 27 + + + 0.0 0.625 20000000.0 + + + 21 + + + 1 + + + 16 8 + U235 U238 + fission nu-fission + tracklength + + + 6 8 + U235 U238 + fission nu-fission + tracklength + + + 7 8 + U235 U238 + fission nu-fission + tracklength + + diff --git a/tests/regression_tests/tally_slice_merge/results_true.dat b/tests/regression_tests/tally_slice_merge/results_true.dat index 4b2cbdf1a..84b296d64 100644 --- a/tests/regression_tests/tally_slice_merge/results_true.dat +++ b/tests/regression_tests/tally_slice_merge/results_true.dat @@ -1,36 +1,36 @@ cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U235 fission 1.93e-01 1.92e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U235 nu-fission 4.70e-01 4.67e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U238 fission 2.65e-07 2.60e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U238 nu-fission 6.60e-07 6.47e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U235 fission 3.39e-02 1.53e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U235 nu-fission 8.30e-02 3.75e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U238 fission 1.70e-02 2.01e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U238 nu-fission 4.76e-02 6.12e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U235 fission 7.61e-02 5.84e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U235 nu-fission 1.85e-01 1.42e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U238 fission 1.06e-07 7.62e-09 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U238 nu-fission 2.64e-07 1.90e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U235 fission 1.69e-02 1.34e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U235 nu-fission 4.15e-02 3.29e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U238 fission 1.10e-02 1.69e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U238 nu-fission 3.13e-02 5.35e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U235 fission 1.93e-01 1.92e-02 -1 21 0.00e+00 6.25e-01 U235 nu-fission 4.70e-01 4.67e-02 -2 21 0.00e+00 6.25e-01 U238 fission 2.65e-07 2.60e-08 -3 21 0.00e+00 6.25e-01 U238 nu-fission 6.60e-07 6.47e-08 -4 21 6.25e-01 2.00e+07 U235 fission 3.39e-02 1.53e-03 -5 21 6.25e-01 2.00e+07 U235 nu-fission 8.30e-02 3.75e-03 -6 21 6.25e-01 2.00e+07 U238 fission 1.70e-02 2.01e-03 -7 21 6.25e-01 2.00e+07 U238 nu-fission 4.76e-02 6.12e-03 -8 27 0.00e+00 6.25e-01 U235 fission 7.61e-02 5.84e-03 -9 27 0.00e+00 6.25e-01 U235 nu-fission 1.85e-01 1.42e-02 -10 27 0.00e+00 6.25e-01 U238 fission 1.06e-07 7.62e-09 -11 27 0.00e+00 6.25e-01 U238 nu-fission 2.64e-07 1.90e-08 -12 27 6.25e-01 2.00e+07 U235 fission 1.69e-02 1.34e-03 -13 27 6.25e-01 2.00e+07 U235 nu-fission 4.15e-02 3.29e-03 -14 27 6.25e-01 2.00e+07 U238 fission 1.10e-02 1.69e-03 -15 27 6.25e-01 2.00e+07 U238 nu-fission 3.13e-02 5.35e-03 +0 21 0.00e+00 6.25e-01 U235 fission 1.77e-01 1.81e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U235 nu-fission 4.32e-01 4.42e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U238 fission 2.43e-07 2.40e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U238 nu-fission 6.07e-07 5.97e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U235 fission 3.03e-02 1.93e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U235 nu-fission 7.41e-02 4.67e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U238 fission 1.65e-02 1.61e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U238 nu-fission 4.61e-02 4.87e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U235 fission 1.31e-01 2.54e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U235 nu-fission 3.18e-01 6.19e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U238 fission 1.80e-07 3.46e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U238 nu-fission 4.49e-07 8.62e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U235 fission 2.34e-02 1.23e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U235 nu-fission 5.72e-02 2.99e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U238 fission 1.24e-02 9.35e-04 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U238 nu-fission 3.44e-02 2.73e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U235 fission 1.77e-01 1.81e-02 +1 21 0.00e+00 6.25e-01 U235 nu-fission 4.32e-01 4.42e-02 +2 21 0.00e+00 6.25e-01 U238 fission 2.43e-07 2.40e-08 +3 21 0.00e+00 6.25e-01 U238 nu-fission 6.07e-07 5.97e-08 +4 21 6.25e-01 2.00e+07 U235 fission 3.03e-02 1.93e-03 +5 21 6.25e-01 2.00e+07 U235 nu-fission 7.41e-02 4.67e-03 +6 21 6.25e-01 2.00e+07 U238 fission 1.65e-02 1.61e-03 +7 21 6.25e-01 2.00e+07 U238 nu-fission 4.61e-02 4.87e-03 +8 27 0.00e+00 6.25e-01 U235 fission 1.31e-01 2.54e-02 +9 27 0.00e+00 6.25e-01 U235 nu-fission 3.18e-01 6.19e-02 +10 27 0.00e+00 6.25e-01 U238 fission 1.80e-07 3.46e-08 +11 27 0.00e+00 6.25e-01 U238 nu-fission 4.49e-07 8.62e-08 +12 27 6.25e-01 2.00e+07 U235 fission 2.34e-02 1.23e-03 +13 27 6.25e-01 2.00e+07 U235 nu-fission 5.72e-02 2.99e-03 +14 27 6.25e-01 2.00e+07 U238 fission 1.24e-02 9.35e-04 +15 27 6.25e-01 2.00e+07 U238 nu-fission 3.44e-02 2.73e-03 sum(distribcell) energy low [eV] energy high [eV] nuclide score mean std. dev. 0 (0, 100, 2000, 30000) 0.00e+00 6.25e-01 U235 fission 0.00e+00 0.00e+00 1 (0, 100, 2000, 30000) 0.00e+00 6.25e-01 U235 nu-fission 0.00e+00 0.00e+00 @@ -49,19 +49,19 @@ 14 (500, 5000, 50000) 6.25e-01 2.00e+07 U238 fission 0.00e+00 0.00e+00 15 (500, 5000, 50000) 6.25e-01 2.00e+07 U238 nu-fission 0.00e+00 0.00e+00 sum(mesh) energy low [eV] energy high [eV] nuclide score mean std. dev. -0 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 fission 1.94e-03 1.03e-03 -1 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 nu-fission 4.74e-03 2.50e-03 -2 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 fission 2.74e-09 1.42e-09 -3 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 nu-fission 6.83e-09 3.53e-09 -4 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 fission 9.02e-04 3.69e-04 -5 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 nu-fission 2.24e-03 9.12e-04 -6 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 fission 1.44e-03 8.42e-04 -7 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 nu-fission 4.37e-03 2.64e-03 -8 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 fission 1.27e-02 2.76e-03 -9 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 nu-fission 3.09e-02 6.72e-03 -10 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 fission 1.70e-08 3.57e-09 -11 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 nu-fission 4.25e-08 8.90e-09 -12 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 fission 1.43e-03 1.69e-04 -13 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 nu-fission 3.52e-03 4.20e-04 -14 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 fission 1.37e-03 2.98e-04 -15 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 nu-fission 4.16e-03 1.08e-03 +0 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 fission 2.75e-02 4.32e-03 +1 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 nu-fission 6.71e-02 1.05e-02 +2 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 fission 3.78e-08 5.83e-09 +3 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 nu-fission 9.42e-08 1.45e-08 +4 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 fission 3.96e-03 7.84e-04 +5 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 nu-fission 9.71e-03 1.91e-03 +6 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 fission 3.92e-03 8.53e-04 +7 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 nu-fission 1.08e-02 2.25e-03 +8 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 fission 5.42e-02 2.50e-02 +9 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 nu-fission 1.32e-01 6.10e-02 +10 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 fission 7.47e-08 3.42e-08 +11 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 nu-fission 1.86e-07 8.53e-08 +12 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 fission 6.58e-03 2.03e-03 +13 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 nu-fission 1.61e-02 4.95e-03 +14 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 fission 3.74e-03 1.12e-03 +15 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 nu-fission 1.05e-02 3.20e-03 diff --git a/tests/regression_tests/tally_slice_merge/test.py b/tests/regression_tests/tally_slice_merge/test.py index aec73979b..090e31448 100644 --- a/tests/regression_tests/tally_slice_merge/test.py +++ b/tests/regression_tests/tally_slice_merge/test.py @@ -149,9 +149,6 @@ class TallySliceMergeTestHarness(PyAPITestHarness): sum2 = mesh_tally.summation(filter_type=openmc.MeshFilter, filter_bins=[(2, 1), (2, 2)]) - mesh = mesh_tally.find_filter(openmc.MeshFilter).mesh - assert mesh.name == 'mesh' - # Merge the mesh tally slices merge_tally = sum1.merge(sum2) diff --git a/tests/regression_tests/time_cutoff/__init__.py b/tests/regression_tests/time_cutoff/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/time_cutoff/inputs_true.dat b/tests/regression_tests/time_cutoff/inputs_true.dat deleted file mode 100644 index e1102d475..000000000 --- a/tests/regression_tests/time_cutoff/inputs_true.dat +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - fixed source - 100 - 10 - - - 0.0 0.0 0.0 - - - 10000.0 1.0 - - - - 1e-07 - - - - - 0.0 1e-07 2e-07 - - - 1 - flux - - - diff --git a/tests/regression_tests/time_cutoff/results_true.dat b/tests/regression_tests/time_cutoff/results_true.dat deleted file mode 100644 index d3d5e1b3c..000000000 --- a/tests/regression_tests/time_cutoff/results_true.dat +++ /dev/null @@ -1,5 +0,0 @@ -tally 1: -1.383148E+02 -1.913099E+03 -0.000000E+00 -0.000000E+00 diff --git a/tests/regression_tests/time_cutoff/test.py b/tests/regression_tests/time_cutoff/test.py deleted file mode 100755 index 9554a6e2a..000000000 --- a/tests/regression_tests/time_cutoff/test.py +++ /dev/null @@ -1,42 +0,0 @@ -import openmc -import pytest - -from tests.testing_harness import PyAPITestHarness - - -@pytest.fixture -def time_model(): - model = openmc.Model() - time_cutoff = 1e-7 - - # A single sphere - s1 = openmc.Sphere(r=200, boundary_type='vacuum') - sphere = openmc.Cell() - sphere.region = -s1 - model.geometry = openmc.Geometry([sphere]) - - # Set the running parameters - settings_file = openmc.Settings() - settings_file.run_mode = 'fixed source' - settings_file.batches = 10 - settings_file.particles = 100 - settings_file.cutoff = {'time_neutron': time_cutoff} - settings_file.source = openmc.IndependentSource( - space=openmc.stats.Point(), energy=openmc.stats.Discrete([1e4], [1])) - model.settings = settings_file - - # Tally flux under time cutoff - tallies = openmc.Tallies() - tally = openmc.Tally() - tally.scores = ['flux'] - time_filter = openmc.TimeFilter([0, time_cutoff, 2*time_cutoff]) - tally.filters = [time_filter] - tallies.append(tally) - model.tallies = tallies - - return model - - -def test_time_cutoff(time_model): - harness = PyAPITestHarness('statepoint.10.h5', time_model) - harness.main() diff --git a/tests/regression_tests/torus/inputs_true.dat b/tests/regression_tests/torus/inputs_true.dat index df4af1443..0ccbda400 100644 --- a/tests/regression_tests/torus/inputs_true.dat +++ b/tests/regression_tests/torus/inputs_true.dat @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + diff --git a/tests/regression_tests/torus/large_major/inputs_true.dat b/tests/regression_tests/torus/large_major/inputs_true.dat index 513a8c67e..ae3f72d0f 100644 --- a/tests/regression_tests/torus/large_major/inputs_true.dat +++ b/tests/regression_tests/torus/large_major/inputs_true.dat @@ -1,36 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - -1000.0 0 0 - - - - - - flux - - - + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + -1000.0 0 0 + + + + + + + flux + + diff --git a/tests/regression_tests/torus/large_major/test.py b/tests/regression_tests/torus/large_major/test.py index 1ce1ab2ca..256716f4e 100644 --- a/tests/regression_tests/torus/large_major/test.py +++ b/tests/regression_tests/torus/large_major/test.py @@ -28,7 +28,7 @@ def model(): model.settings.run_mode ='fixed source' model.settings.particles = 1000 model.settings.batches = 10 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point((-R, 0, 0,))) + model.settings.source = openmc.Source(space=openmc.stats.Point((-R, 0, 0,))) tally = openmc.Tally() tally.scores = ['flux'] diff --git a/tests/regression_tests/torus/results_true.dat b/tests/regression_tests/torus/results_true.dat index 84cd3c7a4..42444ad09 100644 --- a/tests/regression_tests/torus/results_true.dat +++ b/tests/regression_tests/torus/results_true.dat @@ -1,2 +1,2 @@ k-combined: -7.666453E-01 1.478848E-02 +7.628424E-01 2.557300E-02 diff --git a/tests/regression_tests/trace/results_true.dat b/tests/regression_tests/trace/results_true.dat index 97b997ae6..fe46748c8 100644 --- a/tests/regression_tests/trace/results_true.dat +++ b/tests/regression_tests/trace/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 diff --git a/tests/regression_tests/track_output/geometry.xml b/tests/regression_tests/track_output/geometry.xml new file mode 100644 index 000000000..5b16fe26c --- /dev/null +++ b/tests/regression_tests/track_output/geometry.xml @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 + 2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 + 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 + 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 + 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 + 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 3 2 2 2 2 2 2 2 1 2 2 2 + 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + + + + + + + + + + -12.2682 -12.2682 + 1.63576 1.63576 + + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + + + + + + + + + + + + + + + + + -85.8774 -85.8774 + 24.5364 24.5364 + + 999 999 130 140 150 999 999 + 999 220 230 240 250 260 999 + 130 320 777 222 333 360 150 + 410 240 444 111 666 240 470 + 510 520 888 555 998 560 570 + 999 620 630 240 650 660 999 + 999 999 510 740 570 999 999 + + + + + + + + diff --git a/tests/regression_tests/track_output/materials.xml b/tests/regression_tests/track_output/materials.xml new file mode 100644 index 000000000..5dc9a6475 --- /dev/null +++ b/tests/regression_tests/track_output/materials.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/track_output/model.xml b/tests/regression_tests/track_output/model.xml deleted file mode 100644 index 36ccb2b46..000000000 --- a/tests/regression_tests/track_output/model.xml +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 -2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 -2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 -2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 -2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 -2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 3 2 2 2 2 2 2 2 1 2 2 2 -2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 1.63576 1.63576 - 15 15 - -12.2682 -12.2682 - -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - 24.5364 24.5364 - 7 7 - -85.8774 -85.8774 - -999 999 130 140 150 999 999 -999 220 230 240 250 260 999 -130 320 777 222 333 360 150 -410 240 444 111 666 240 470 -510 520 888 555 998 560 570 -999 620 630 240 650 660 999 -999 999 510 740 570 999 999 - - - - - - - - - - - - eigenvalue - 100 - 2 - 0 - - - -1.0 -1.0 -1.0 1.0 1.0 1.0 - - - 1 1 1 1 1 30 2 1 60 - - diff --git a/tests/regression_tests/track_output/results_true.dat b/tests/regression_tests/track_output/results_true.dat index 205ac3eec..756226d10 100644 --- a/tests/regression_tests/track_output/results_true.dat +++ b/tests/regression_tests/track_output/results_true.dat @@ -1,4 +1,4 @@ -neutron [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 0.000000e+00, 1.000000e+00, 23, 2403, 1) +ParticleType.NEUTRON [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 0.000000e+00, 1.000000e+00, 23, 2403, 1) ((-1.281491e+00, -4.879529e-01, -7.708709e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 1.323629e-10, 1.000000e+00, 22, 2403, 3) ((-1.368452e+00, -4.400285e-01, -7.114141e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 1.688824e-10, 1.000000e+00, 21, 2403, 2) ((-2.150539e+00, -9.015151e-03, -1.766823e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 4.973246e-10, 1.000000e+00, 22, 2403, 3) @@ -97,27 +97,27 @@ neutron [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921e-01, 4.14097 ((-1.585080e+01, 1.545037e+00, -2.159072e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 5.061748e-06, 1.000000e+00, 22, 2129, 3) ((-1.576406e+01, 1.529415e+00, -2.169209e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 5.199673e-06, 1.000000e+00, 23, 2129, 1) ((-1.553972e+01, 1.489015e+00, -2.195425e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 5.556377e-06, 1.000000e+00, 23, 2115, 1) - ((-1.546081e+01, 1.474803e+00, -2.204648e+01), (3.257038e-01, -9.420596e-01, -8.025439e-02), 3.076319e-01, 5.681853e-06, 1.000000e+00, 23, 2115, 1) + ((-1.546081e+01, 1.474803e+00, -2.204648e+01), (3.257038e-01, -9.420596e-01, -8.025439e-02), 3.076319e-01, 5.681852e-06, 1.000000e+00, 23, 2115, 1) ((-1.543563e+01, 1.401988e+00, -2.205268e+01), (-3.677195e-01, -8.784218e-01, -3.052172e-01), 8.422973e-02, 5.782605e-06, 1.000000e+00, 23, 2115, 1) ((-1.553972e+01, 1.153338e+00, -2.213907e+01), (-3.677195e-01, -8.784218e-01, -3.052172e-01), 8.422973e-02, 6.487752e-06, 1.000000e+00, 23, 2129, 1) ((-1.565955e+01, 8.670807e-01, -2.223854e+01), (1.611814e-01, 2.692337e-01, -9.494913e-01), 8.559448e-02, 7.299552e-06, 1.000000e+00, 23, 2129, 1) ((-1.563263e+01, 9.120446e-01, -2.239711e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 7.712256e-06, 1.000000e+00, 23, 2129, 1) - ((-1.592604e+01, 1.214620e+00, -2.249695e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 9.406032e-06, 1.000000e+00, 22, 2129, 3) + ((-1.592604e+01, 1.214620e+00, -2.249695e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 9.406031e-06, 1.000000e+00, 22, 2129, 3) ((-1.598742e+01, 1.277922e+00, -2.251784e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 9.760391e-06, 1.000000e+00, 21, 2129, 2) ((-1.670388e+01, 2.016770e+00, -2.276163e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 1.389636e-05, 1.000000e+00, 22, 2129, 3) ((-1.676526e+01, 2.080073e+00, -2.278252e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 1.425072e-05, 1.000000e+00, 23, 2129, 1) ((-1.681575e+01, 2.132139e+00, -2.279970e+01), (4.286076e-02, -9.409799e-01, -3.357375e-01), 1.813618e-02, 1.454218e-05, 1.000000e+00, 23, 2129, 1) ((-1.681374e+01, 2.087933e+00, -2.281547e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.479439e-05, 1.000000e+00, 23, 2129, 1) ((-1.682083e+01, 2.021795e+00, -2.287841e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.532970e-05, 1.000000e+00, 22, 2129, 3) - ((-1.684417e+01, 1.804084e+00, -2.308558e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.709181e-05, 1.000000e+00, 21, 2129, 2) + ((-1.684417e+01, 1.804084e+00, -2.308558e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.709182e-05, 1.000000e+00, 21, 2129, 2) ((-1.686879e+01, 1.574384e+00, -2.330417e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.895097e-05, 1.000000e+00, 22, 2129, 3) - ((-1.689212e+01, 1.356673e+00, -2.351134e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 2.071308e-05, 1.000000e+00, 23, 2129, 1) - ((-1.689233e+01, 1.354754e+00, -2.351317e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.072861e-05, 1.000000e+00, 23, 2129, 1) + ((-1.689212e+01, 1.356673e+00, -2.351134e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 2.071309e-05, 1.000000e+00, 23, 2129, 1) + ((-1.689233e+01, 1.354754e+00, -2.351317e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.072862e-05, 1.000000e+00, 23, 2129, 1) ((-1.689148e+01, 1.355453e+00, -2.351229e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.073958e-05, 1.000000e+00, 22, 2129, 3) ((-1.682182e+01, 1.413107e+00, -2.343954e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.164421e-05, 1.000000e+00, 21, 2129, 2) ((-1.636364e+01, 1.792326e+00, -2.296107e+01), (9.641593e-01, -1.162836e-01, 2.384846e-01), 7.837617e-03, 2.759442e-05, 1.000000e+00, 21, 2129, 2) ((-1.598564e+01, 1.746738e+00, -2.286758e+01), (9.641593e-01, -1.162836e-01, 2.384846e-01), 7.837617e-03, 3.079609e-05, 0.000000e+00, 21, 2129, 2)] -neutron [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e-01, 2.365819e-01, 9.608983e-01), 9.724461e+05, 0.000000e+00, 1.000000e+00, 23, 2403, 1) +ParticleType.NEUTRON [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e-01, 2.365819e-01, 9.608983e-01), 9.724461e+05, 0.000000e+00, 1.000000e+00, 23, 2403, 1) ((-9.064818e-01, -1.914524e-01, 4.118326e-01), (9.231638e-01, 3.100833e-01, 2.271937e-01), 1.746594e+05, 2.064696e-10, 1.000000e+00, 23, 2403, 1) ((-8.178800e-01, -1.616918e-01, 4.336377e-01), (9.231638e-01, 3.100833e-01, 2.271937e-01), 1.746594e+05, 3.725262e-10, 1.000000e+00, 11, 1756, 1) ((-3.834875e-01, -1.578285e-02, 5.405432e-01), (-5.547498e-01, -6.358598e-02, 8.295839e-01), 1.474011e+05, 1.186660e-09, 1.000000e+00, 11, 1756, 1) @@ -143,74 +143,124 @@ neutron [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e-01, 2.365819e ((-3.920090e+00, -9.211794e-01, 2.908406e+00), (9.094673e-01, -3.659267e-01, -1.974002e-01), 9.547085e+00, 1.260840e-07, 1.000000e+00, 23, 2387, 1) ((-3.729948e+00, -9.976834e-01, 2.867135e+00), (-2.916959e-01, -6.494657e-01, -7.022164e-01), 8.590591e+00, 1.750036e-07, 1.000000e+00, 23, 2387, 1) ((-3.744933e+00, -1.031047e+00, 2.831062e+00), (-2.916959e-01, -6.494657e-01, -7.022164e-01), 8.590591e+00, 1.876753e-07, 0.000000e+00, 23, 2387, 1)] -neutron [((6.474155e+00, -5.192870e+00, 5.413003e+00), (-9.597810e-01, -1.081529e-01, -2.590820e-01), 9.900333e+05, 4.450859e-05, 1.000000e+00, 21, 2367, 2) - ((6.142109e+00, -5.230286e+00, 5.323371e+00), (-9.597810e-01, -1.081529e-01, -2.590820e-01), 9.900333e+05, 4.450884e-05, 1.000000e+00, 22, 2367, 3) - ((6.041244e+00, -5.241652e+00, 5.296144e+00), (-9.597810e-01, -1.081529e-01, -2.590820e-01), 9.900333e+05, 4.450892e-05, 1.000000e+00, 23, 2367, 1) - ((6.004037e+00, -5.245845e+00, 5.286100e+00), (-6.195407e-01, -7.332723e-01, -2.801446e-01), 5.512347e+05, 4.450895e-05, 1.000000e+00, 23, 2367, 1) - ((5.725160e+00, -5.575916e+00, 5.159997e+00), (-6.195407e-01, -7.332723e-01, -2.801446e-01), 5.512347e+05, 4.450939e-05, 1.000000e+00, 23, 2366, 1) - ((5.599064e+00, -5.725160e+00, 5.102979e+00), (-6.195407e-01, -7.332723e-01, -2.801446e-01), 5.512347e+05, 4.450958e-05, 1.000000e+00, 23, 2352, 1) - ((5.296886e+00, -6.082810e+00, 4.966340e+00), (-6.195407e-01, -7.332723e-01, -2.801446e-01), 5.512347e+05, 4.451006e-05, 1.000000e+00, 22, 2352, 3) - ((5.240003e+00, -6.150135e+00, 4.940619e+00), (-6.195407e-01, -7.332723e-01, -2.801446e-01), 5.512347e+05, 4.451015e-05, 1.000000e+00, 21, 2352, 2) - ((4.752072e+00, -6.727638e+00, 4.719986e+00), (3.721510e-02, -9.647240e-01, 2.606197e-01), 5.045933e+05, 4.451092e-05, 1.000000e+00, 21, 2352, 2) - ((4.764028e+00, -7.037568e+00, 4.803713e+00), (3.721510e-02, -9.647240e-01, 2.606197e-01), 5.045933e+05, 4.451124e-05, 1.000000e+00, 22, 2352, 3) - ((4.767580e+00, -7.129630e+00, 4.828584e+00), (3.721510e-02, -9.647240e-01, 2.606197e-01), 5.045933e+05, 4.451134e-05, 1.000000e+00, 23, 2352, 1) - ((4.776502e+00, -7.360920e+00, 4.891066e+00), (3.721510e-02, -9.647240e-01, 2.606197e-01), 5.045933e+05, 4.451158e-05, 1.000000e+00, 23, 2338, 1) - ((4.778286e+00, -7.407162e+00, 4.903559e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451163e-05, 1.000000e+00, 23, 2338, 1) - ((4.981926e+00, -7.580442e+00, 5.259893e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451239e-05, 1.000000e+00, 22, 2338, 3) - ((5.154144e+00, -7.726985e+00, 5.561246e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451303e-05, 1.000000e+00, 21, 2338, 2) - ((5.313757e+00, -7.862801e+00, 5.840540e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451362e-05, 1.000000e+00, 22, 2338, 3) - ((5.485976e+00, -8.009344e+00, 6.141893e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451426e-05, 1.000000e+00, 23, 2338, 1) - ((5.725160e+00, -8.212869e+00, 6.560424e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451515e-05, 1.000000e+00, 23, 2339, 1) - ((6.004950e+00, -8.450945e+00, 7.050007e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451618e-05, 1.000000e+00, 22, 2339, 3) - ((6.360530e+00, -8.753512e+00, 7.672210e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451750e-05, 1.000000e+00, 23, 2339, 1) - ((6.646303e+00, -8.996680e+00, 8.172263e+00), (4.571054e-01, -3.889563e-01, 7.998548e-01), 1.818775e+05, 4.451856e-05, 1.000000e+00, 23, 2326, 1) - ((6.702490e+00, -9.044491e+00, 8.270582e+00), (2.028534e-01, -9.607965e-01, -1.889990e-01), 1.805295e+04, 4.451877e-05, 1.000000e+00, 23, 2326, 1) - ((6.745127e+00, -9.246436e+00, 8.230857e+00), (2.028534e-01, -9.607965e-01, -1.889990e-01), 1.805295e+04, 4.451990e-05, 1.000000e+00, 22, 2326, 3) - ((6.767219e+00, -9.351070e+00, 8.210274e+00), (2.028534e-01, -9.607965e-01, -1.889990e-01), 1.805295e+04, 4.452049e-05, 1.000000e+00, 21, 2326, 2) - ((6.885344e+00, -9.910562e+00, 8.100216e+00), (-3.857824e-01, -3.006310e-01, -8.722344e-01), 1.795765e+04, 4.452362e-05, 1.000000e+00, 21, 2326, 2) - ((6.803615e+00, -9.974251e+00, 7.915431e+00), (-7.096135e-01, 6.778415e-01, 1.923009e-01), 1.779137e+04, 4.452476e-05, 1.000000e+00, 21, 2326, 2) - ((6.334815e+00, -9.526441e+00, 8.042473e+00), (-1.748210e-01, 9.821705e-01, -6.912779e-02), 1.729669e+04, 4.452835e-05, 1.000000e+00, 21, 2326, 2) - ((6.304853e+00, -9.358111e+00, 8.030625e+00), (-1.748210e-01, 9.821705e-01, -6.912779e-02), 1.729669e+04, 4.452929e-05, 1.000000e+00, 22, 2326, 3) - ((6.288777e+00, -9.267793e+00, 8.024268e+00), (-1.748210e-01, 9.821705e-01, -6.912779e-02), 1.729669e+04, 4.452979e-05, 1.000000e+00, 23, 2326, 1) - ((6.275105e+00, -9.190979e+00, 8.018862e+00), (-7.174952e-01, 5.897531e-01, -3.706642e-01), 9.207900e+03, 4.453022e-05, 1.000000e+00, 23, 2326, 1) - ((6.038719e+00, -8.996680e+00, 7.896743e+00), (-7.174952e-01, 5.897531e-01, -3.706642e-01), 9.207900e+03, 4.453271e-05, 1.000000e+00, 23, 2339, 1) - ((6.028805e+00, -8.988531e+00, 7.891621e+00), (-2.989803e-01, 4.300779e-01, -8.518473e-01), 5.653774e+03, 4.453281e-05, 1.000000e+00, 23, 2339, 1) - ((5.725160e+00, -8.551743e+00, 7.026484e+00), (-2.989803e-01, 4.300779e-01, -8.518473e-01), 5.653774e+03, 4.454257e-05, 1.000000e+00, 23, 2338, 1) - ((5.507324e+00, -8.238390e+00, 6.405832e+00), (-2.989803e-01, 4.300779e-01, -8.518473e-01), 5.653774e+03, 4.454958e-05, 1.000000e+00, 22, 2338, 3) - ((5.417387e+00, -8.109017e+00, 6.149584e+00), (-2.989803e-01, 4.300779e-01, -8.518473e-01), 5.653774e+03, 4.455247e-05, 1.000000e+00, 21, 2338, 2) - ((5.162017e+00, -7.741671e+00, 5.421991e+00), (7.522612e-01, -1.036919e-01, -6.506543e-01), 5.619608e+03, 4.456069e-05, 1.000000e+00, 21, 2338, 2) - ((5.184146e+00, -7.744722e+00, 5.402851e+00), (7.522612e-01, -1.036919e-01, -6.506543e-01), 5.619608e+03, 4.456097e-05, 1.000000e+00, 22, 2338, 3) - ((5.348057e+00, -7.767315e+00, 5.261079e+00), (7.522612e-01, -1.036919e-01, -6.506543e-01), 5.619608e+03, 4.456307e-05, 1.000000e+00, 23, 2338, 1) - ((5.581568e+00, -7.799502e+00, 5.059108e+00), (2.029690e-01, -4.131185e-01, -8.877706e-01), 3.359662e+03, 4.456606e-05, 1.000000e+00, 23, 2338, 1) - ((5.707007e+00, -8.054818e+00, 4.510447e+00), (3.894183e-01, -7.459178e-01, -5.403333e-01), 3.303714e+03, 4.457377e-05, 1.000000e+00, 23, 2338, 1) - ((5.725160e+00, -8.089590e+00, 4.485259e+00), (3.894183e-01, -7.459178e-01, -5.403333e-01), 3.303714e+03, 4.457436e-05, 1.000000e+00, 23, 2339, 1) - ((5.750893e+00, -8.138881e+00, 4.449554e+00), (-2.879829e-01, -5.545287e-01, -7.807456e-01), 1.744626e+03, 4.457519e-05, 1.000000e+00, 23, 2339, 1) - ((5.725160e+00, -8.188431e+00, 4.379790e+00), (-2.879829e-01, -5.545287e-01, -7.807456e-01), 1.744626e+03, 4.457674e-05, 1.000000e+00, 23, 2338, 1) - ((5.532143e+00, -8.560097e+00, 3.856504e+00), (-6.185172e-01, -7.766669e-01, -1.192687e-01), 8.559363e+02, 4.458834e-05, 1.000000e+00, 23, 2338, 1) - ((5.522333e+00, -8.572415e+00, 3.854613e+00), (-3.452053e-01, -2.657159e-02, -9.381510e-01), 9.272133e+01, 4.458873e-05, 1.000000e+00, 23, 2338, 1) - ((5.366948e+00, -8.584375e+00, 3.432328e+00), (4.761677e-01, -8.187551e-01, -3.207871e-01), 6.522002e+00, 4.462253e-05, 1.000000e+00, 23, 2338, 1) - ((5.516634e+00, -8.841755e+00, 3.331487e+00), (4.237115e-01, -6.022578e-01, 6.765752e-01), 9.968491e-01, 4.471152e-05, 1.000000e+00, 23, 2338, 1) - ((5.625629e+00, -8.996680e+00, 3.505530e+00), (4.237115e-01, -6.022578e-01, 6.765752e-01), 9.968491e-01, 4.489779e-05, 1.000000e+00, 23, 2325, 1) - ((5.723424e+00, -9.135684e+00, 3.661687e+00), (7.706137e-01, -6.358415e-01, 4.312932e-02), 5.695813e-01, 4.506493e-05, 1.000000e+00, 23, 2325, 1) - ((5.725160e+00, -9.137116e+00, 3.661784e+00), (7.706137e-01, -6.358415e-01, 4.312932e-02), 5.695813e-01, 4.506708e-05, 1.000000e+00, 23, 2326, 1) - ((6.079210e+00, -9.429247e+00, 3.681599e+00), (7.706137e-01, -6.358415e-01, 4.312932e-02), 5.695813e-01, 4.550721e-05, 1.000000e+00, 22, 2326, 3) - ((6.147194e+00, -9.485341e+00, 3.685404e+00), (7.706137e-01, -6.358415e-01, 4.312932e-02), 5.695813e-01, 4.559172e-05, 1.000000e+00, 21, 2326, 2) - ((6.864744e+00, -1.007740e+01, 3.725564e+00), (3.888690e-01, -8.895503e-01, -2.397522e-01), 5.691123e-01, 4.648372e-05, 1.000000e+00, 21, 2326, 2) - ((6.908415e+00, -1.017730e+01, 3.698639e+00), (3.888690e-01, -8.895503e-01, -2.397522e-01), 5.691123e-01, 4.659135e-05, 1.000000e+00, 22, 2326, 3) - ((6.945959e+00, -1.026318e+01, 3.675492e+00), (3.888690e-01, -8.895503e-01, -2.397522e-01), 5.691123e-01, 4.668388e-05, 1.000000e+00, 23, 2326, 1) - ((6.966122e+00, -1.030930e+01, 3.663060e+00), (7.493672e-01, -6.303754e-01, 2.026713e-01), 2.849108e-01, 4.673357e-05, 1.000000e+00, 23, 2326, 1) - ((7.350254e+00, -1.063244e+01, 3.766951e+00), (7.493672e-01, -6.303754e-01, 2.026713e-01), 2.849108e-01, 4.742789e-05, 1.000000e+00, 23, 2311, 1) - ((7.360920e+00, -1.064141e+01, 3.769836e+00), (7.493672e-01, -6.303754e-01, 2.026713e-01), 2.849108e-01, 4.744717e-05, 1.000000e+00, 23, 2312, 1) - ((7.449168e+00, -1.071565e+01, 3.793703e+00), (1.626881e-01, -1.480918e-01, 9.755006e-01), 2.025207e-01, 4.760667e-05, 1.000000e+00, 23, 2312, 1) - ((7.495754e+00, -1.075805e+01, 4.073039e+00), (-1.185723e-01, -6.787603e-01, 7.247241e-01), 2.121260e-01, 4.806671e-05, 1.000000e+00, 23, 2312, 1) - ((7.451135e+00, -1.101347e+01, 4.345753e+00), (-4.978877e-01, -3.750598e-02, 8.664301e-01), 2.609768e-02, 4.865741e-05, 1.000000e+00, 23, 2312, 1) - ((7.426401e+00, -1.101533e+01, 4.388795e+00), (9.221835e-01, -6.407530e-02, 3.814078e-01), 2.031765e-02, 4.887973e-05, 1.000000e+00, 23, 2312, 1) - ((7.438938e+00, -1.101621e+01, 4.393980e+00), (8.832139e-01, 3.563144e-01, 3.049151e-01), 2.038019e-02, 4.894869e-05, 1.000000e+00, 23, 2312, 1) - ((7.578355e+00, -1.095996e+01, 4.442112e+00), (5.564936e-01, 8.135970e-01, 1.684482e-01), 4.869241e-02, 4.974811e-05, 1.000000e+00, 23, 2312, 1) - ((7.802376e+00, -1.063244e+01, 4.509922e+00), (5.564936e-01, 8.135970e-01, 1.684482e-01), 4.869241e-02, 5.106705e-05, 1.000000e+00, 23, 2327, 1) - ((7.826035e+00, -1.059785e+01, 4.517083e+00), (-8.227572e-01, -5.662268e-01, 4.957651e-02), 8.202195e-02, 5.120634e-05, 1.000000e+00, 23, 2327, 1) - ((7.775776e+00, -1.063244e+01, 4.520112e+00), (-8.227572e-01, -5.662268e-01, 4.957651e-02), 8.202195e-02, 5.136055e-05, 1.000000e+00, 23, 2312, 1) - ((7.360920e+00, -1.091795e+01, 4.545109e+00), (-8.227572e-01, -5.662268e-01, 4.957651e-02), 8.202195e-02, 5.263343e-05, 1.000000e+00, 23, 2311, 1) - ((7.180267e+00, -1.104227e+01, 4.555995e+00), (5.568446e-01, -6.706436e-01, -4.900625e-01), 5.560680e-02, 5.318772e-05, 1.000000e+00, 23, 2311, 1) - ((7.207392e+00, -1.107494e+01, 4.532123e+00), (9.936512e-01, 4.529367e-02, -1.029847e-01), 8.142074e-02, 5.333706e-05, 1.000000e+00, 23, 2311, 1) - ((7.252245e+00, -1.107290e+01, 4.527474e+00), (9.936512e-01, 4.529367e-02, -1.029847e-01), 8.142074e-02, 5.345144e-05, 0.000000e+00, 23, 2311, 1)] +ParticleType.NEUTRON [((6.474155e+00, -5.192870e+00, 5.413003e+00), (-3.042035e-02, -9.914979e-01, 1.265170e-01), 2.052226e+06, 4.450859e-05, 1.000000e+00, 21, 2367, 2) + ((6.467293e+00, -5.416535e+00, 5.441544e+00), (-3.042035e-02, -9.914979e-01, 1.265170e-01), 2.052226e+06, 4.450870e-05, 1.000000e+00, 22, 2367, 3) + ((6.464574e+00, -5.505149e+00, 5.452851e+00), (-3.042035e-02, -9.914979e-01, 1.265170e-01), 2.052226e+06, 4.450874e-05, 1.000000e+00, 23, 2367, 1) + ((6.461877e+00, -5.593034e+00, 5.464065e+00), (6.364108e-01, -7.713322e-01, 5.284745e-03), 1.141417e+06, 4.450879e-05, 1.000000e+00, 23, 2367, 1) + ((6.570892e+00, -5.725160e+00, 5.464970e+00), (6.364108e-01, -7.713322e-01, 5.284745e-03), 1.141417e+06, 4.450891e-05, 1.000000e+00, 32, 7, 1) + ((6.821003e+00, -6.028296e+00, 5.467047e+00), (6.364108e-01, -7.713322e-01, 5.284745e-03), 1.141417e+06, 4.450917e-05, 1.000000e+00, 31, 7, 4) + ((7.101210e+00, -6.367908e+00, 5.469374e+00), (6.364108e-01, -7.713322e-01, 5.284745e-03), 1.141417e+06, 4.450947e-05, 1.000000e+00, 32, 7, 1) + ((7.360920e+00, -6.682677e+00, 5.471531e+00), (6.364108e-01, -7.713322e-01, 5.284745e-03), 1.141417e+06, 4.450975e-05, 1.000000e+00, 23, 2353, 1) + ((7.833926e+00, -7.255962e+00, 5.475459e+00), (9.404210e-01, 3.383106e-01, -3.397550e-02), 1.289848e+05, 4.451025e-05, 1.000000e+00, 23, 2353, 1) + ((8.142528e+00, -7.144944e+00, 5.464309e+00), (9.404210e-01, 3.383106e-01, -3.397550e-02), 1.289848e+05, 4.451091e-05, 1.000000e+00, 22, 2353, 3) + ((8.590199e+00, -6.983897e+00, 5.448136e+00), (9.404210e-01, 3.383106e-01, -3.397550e-02), 1.289848e+05, 4.451187e-05, 1.000000e+00, 23, 2353, 1) + ((8.682515e+00, -6.950687e+00, 5.444801e+00), (6.997233e-01, 7.142820e-01, 1.373092e-02), 1.043159e+05, 4.451207e-05, 1.000000e+00, 23, 2353, 1) + ((8.996680e+00, -6.629985e+00, 5.450966e+00), (6.997233e-01, 7.142820e-01, 1.373092e-02), 1.043159e+05, 4.451307e-05, 1.000000e+00, 23, 2354, 1) + ((9.231138e+00, -6.390649e+00, 5.455567e+00), (6.997233e-01, 7.142820e-01, 1.373092e-02), 1.043159e+05, 4.451382e-05, 1.000000e+00, 22, 2354, 3) + ((9.650189e+00, -5.962879e+00, 5.463790e+00), (6.997233e-01, 7.142820e-01, 1.373092e-02), 1.043159e+05, 4.451516e-05, 1.000000e+00, 23, 2354, 1) + ((9.721007e+00, -5.890588e+00, 5.465180e+00), (6.565855e-01, -1.880518e-01, -7.304327e-01), 1.036285e+04, 4.451539e-05, 1.000000e+00, 23, 2354, 1) + ((9.939012e+00, -5.953026e+00, 5.222655e+00), (6.565855e-01, -1.880518e-01, -7.304327e-01), 1.036285e+04, 4.451775e-05, 1.000000e+00, 22, 2354, 3) + ((1.002133e+01, -5.976602e+00, 5.131083e+00), (6.565855e-01, -1.880518e-01, -7.304327e-01), 1.036285e+04, 4.451864e-05, 1.000000e+00, 23, 2354, 1) + ((1.020258e+01, -6.028514e+00, 4.929446e+00), (8.848761e-01, -4.005580e-02, -4.641012e-01), 8.908873e+03, 4.452060e-05, 1.000000e+00, 23, 2354, 1) + ((1.063244e+01, -6.047973e+00, 4.703991e+00), (8.848761e-01, -4.005580e-02, -4.641012e-01), 8.908873e+03, 4.452432e-05, 1.000000e+00, 23, 2355, 1) + ((1.084241e+01, -6.057477e+00, 4.593868e+00), (9.066652e-01, -6.565865e-02, 4.167099e-01), 3.324374e+03, 4.452614e-05, 1.000000e+00, 23, 2355, 1) + ((1.107130e+01, -6.074053e+00, 4.699070e+00), (9.066652e-01, -6.565865e-02, 4.167099e-01), 3.324374e+03, 4.452930e-05, 1.000000e+00, 22, 2355, 3) + ((1.121611e+01, -6.084540e+00, 4.765623e+00), (9.066652e-01, -6.565865e-02, 4.167099e-01), 3.324374e+03, 4.453130e-05, 1.000000e+00, 21, 2355, 2) + ((1.174815e+01, -6.123069e+00, 5.010155e+00), (9.066652e-01, -6.565865e-02, 4.167099e-01), 3.324374e+03, 4.453866e-05, 1.000000e+00, 22, 2355, 3) + ((1.189296e+01, -6.133556e+00, 5.076709e+00), (9.066652e-01, -6.565865e-02, 4.167099e-01), 3.324374e+03, 4.454067e-05, 1.000000e+00, 23, 2355, 1) + ((1.221698e+01, -6.157021e+00, 5.225634e+00), (5.263177e-01, -7.048209e-01, -4.756229e-01), 3.449618e+02, 4.454515e-05, 1.000000e+00, 23, 2355, 1) + ((1.226820e+01, -6.225607e+00, 5.179351e+00), (5.263177e-01, -7.048209e-01, -4.756229e-01), 3.449618e+02, 4.454893e-05, 1.000000e+00, 23, 2519, 1) + ((1.230378e+01, -6.273253e+00, 5.147199e+00), (9.203567e-01, -2.667811e-01, -2.859569e-01), 2.269067e+02, 4.455157e-05, 1.000000e+00, 23, 2519, 1) + ((1.237909e+01, -6.295083e+00, 5.123800e+00), (8.444192e-01, -5.115818e-01, 1.588717e-01), 1.686474e+02, 4.455549e-05, 1.000000e+00, 23, 2519, 1) + ((1.250758e+01, -6.372926e+00, 5.147974e+00), (8.444192e-01, -5.115818e-01, 1.588717e-01), 1.686474e+02, 4.456396e-05, 1.000000e+00, 22, 2519, 3) + ((1.258603e+01, -6.420455e+00, 5.162734e+00), (8.444192e-01, -5.115818e-01, 1.588717e-01), 1.686474e+02, 4.456914e-05, 1.000000e+00, 21, 2519, 2) + ((1.264082e+01, -6.453648e+00, 5.173042e+00), (3.837750e-01, -8.931658e-01, -2.344604e-01), 1.632815e+02, 4.457275e-05, 1.000000e+00, 21, 2519, 2) + ((1.288240e+01, -7.015898e+00, 5.025449e+00), (3.837750e-01, -8.931658e-01, -2.344604e-01), 1.632815e+02, 4.460837e-05, 1.000000e+00, 22, 2519, 3) + ((1.292943e+01, -7.125332e+00, 4.996722e+00), (3.837750e-01, -8.931658e-01, -2.344604e-01), 1.632815e+02, 4.461530e-05, 1.000000e+00, 23, 2519, 1) + ((1.303065e+01, -7.360920e+00, 4.934879e+00), (3.837750e-01, -8.931658e-01, -2.344604e-01), 1.632815e+02, 4.463022e-05, 1.000000e+00, 23, 2520, 1) + ((1.309295e+01, -7.505897e+00, 4.896822e+00), (3.189366e-01, -9.220512e-01, 2.193195e-01), 1.303968e+02, 4.463941e-05, 1.000000e+00, 23, 2520, 1) + ((1.311741e+01, -7.576618e+00, 4.913644e+00), (3.189366e-01, -9.220512e-01, 2.193195e-01), 1.303968e+02, 4.464426e-05, 1.000000e+00, 22, 2520, 3) + ((1.314895e+01, -7.667795e+00, 4.935331e+00), (3.189366e-01, -9.220512e-01, 2.193195e-01), 1.303968e+02, 4.465052e-05, 1.000000e+00, 21, 2520, 2) + ((1.345125e+01, -8.541749e+00, 5.143210e+00), (3.189366e-01, -9.220512e-01, 2.193195e-01), 1.303968e+02, 4.471053e-05, 1.000000e+00, 22, 2520, 3) + ((1.348278e+01, -8.632925e+00, 5.164897e+00), (3.189366e-01, -9.220512e-01, 2.193195e-01), 1.303968e+02, 4.471679e-05, 1.000000e+00, 23, 2520, 1) + ((1.356121e+01, -8.859646e+00, 5.218825e+00), (3.469373e-01, -8.669828e-01, 3.577365e-01), 1.276458e+02, 4.473236e-05, 1.000000e+00, 23, 2520, 1) + ((1.361604e+01, -8.996680e+00, 5.275368e+00), (3.469373e-01, -8.669828e-01, 3.577365e-01), 1.276458e+02, 4.474248e-05, 1.000000e+00, 23, 2521, 1) + ((1.390396e+01, -9.716172e+00, 5.572247e+00), (3.469373e-01, -8.669828e-01, 3.577365e-01), 1.276458e+02, 4.479558e-05, 1.000000e+00, 23, 2536, 1) + ((1.399742e+01, -9.949713e+00, 5.668611e+00), (-5.897476e-01, -6.217559e-01, 5.153807e-01), 3.643244e+01, 4.481282e-05, 1.000000e+00, 23, 2536, 1) + ((1.390396e+01, -1.004824e+01, 5.750282e+00), (-5.897476e-01, -6.217559e-01, 5.153807e-01), 3.643244e+01, 4.483180e-05, 1.000000e+00, 23, 2521, 1) + ((1.334984e+01, -1.063244e+01, 6.234531e+00), (-5.897476e-01, -6.217559e-01, 5.153807e-01), 3.643244e+01, 4.494435e-05, 1.000000e+00, 23, 2522, 1) + ((1.317711e+01, -1.081455e+01, 6.385480e+00), (-4.211158e-01, -4.515418e-01, 7.866203e-01), 3.302717e+01, 4.497943e-05, 1.000000e+00, 23, 2522, 1) + ((1.316679e+01, -1.082561e+01, 6.404749e+00), (-5.182259e-01, 3.860612e-01, 7.631505e-01), 1.437084e+01, 4.498251e-05, 1.000000e+00, 23, 2522, 1) + ((1.292206e+01, -1.064329e+01, 6.765147e+00), (-8.169098e-01, 1.482852e-01, 5.573777e-01), 1.219816e+01, 4.507257e-05, 1.000000e+00, 23, 2522, 1) + ((1.286229e+01, -1.063244e+01, 6.805923e+00), (-8.169098e-01, 1.482852e-01, 5.573777e-01), 1.219816e+01, 4.508772e-05, 1.000000e+00, 23, 2521, 1) + ((1.284917e+01, -1.063006e+01, 6.814880e+00), (-5.213758e-01, -3.360250e-01, 7.843816e-01), 8.052778e+00, 4.509105e-05, 1.000000e+00, 23, 2521, 1) + ((1.284547e+01, -1.063244e+01, 6.820442e+00), (-5.213758e-01, -3.360250e-01, 7.843816e-01), 8.052778e+00, 4.509285e-05, 1.000000e+00, 23, 2522, 1) + ((1.249929e+01, -1.085555e+01, 7.341246e+00), (-1.520079e-01, -3.513652e-01, 9.238161e-01), 7.069024e+00, 4.526201e-05, 1.000000e+00, 23, 2522, 1) + ((1.240103e+01, -1.108268e+01, 7.938428e+00), (-7.405967e-01, -3.230926e-01, 5.891754e-01), 4.460475e+00, 4.543779e-05, 1.000000e+00, 23, 2522, 1) + ((1.229354e+01, -1.112958e+01, 8.023945e+00), (-6.892797e-01, 5.508903e-01, 4.705458e-01), 2.006774e+00, 4.548748e-05, 1.000000e+00, 23, 2522, 1) + ((1.226820e+01, -1.110933e+01, 8.041241e+00), (-6.892797e-01, 5.508903e-01, 4.705458e-01), 2.006774e+00, 4.550624e-05, 1.000000e+00, 23, 2314, 1) + ((1.198501e+01, -1.088299e+01, 8.234567e+00), (-7.677533e-01, 4.569444e-01, 4.491733e-01), 1.935517e+00, 4.571593e-05, 1.000000e+00, 23, 2314, 1) + ((1.156403e+01, -1.063244e+01, 8.480859e+00), (-7.677533e-01, 4.569444e-01, 4.491733e-01), 1.935517e+00, 4.600087e-05, 1.000000e+00, 23, 2329, 1) + ((1.150264e+01, -1.059590e+01, 8.516776e+00), (-7.780064e-01, -9.937785e-02, 6.203467e-01), 1.893413e+00, 4.604243e-05, 1.000000e+00, 23, 2329, 1) + ((1.121659e+01, -1.063244e+01, 8.744860e+00), (-7.780064e-01, -9.937785e-02, 6.203467e-01), 1.893413e+00, 4.623561e-05, 1.000000e+00, 23, 2314, 1) + ((1.063244e+01, -1.070706e+01, 9.210632e+00), (-7.780064e-01, -9.937785e-02, 6.203467e-01), 1.893413e+00, 4.663011e-05, 1.000000e+00, 23, 2313, 1) + ((1.035391e+01, -1.074263e+01, 9.432717e+00), (-4.847677e-01, -8.685325e-01, -1.032060e-01), 5.647686e-01, 4.681821e-05, 1.000000e+00, 23, 2313, 1) + ((1.031409e+01, -1.081397e+01, 9.424239e+00), (-4.227592e-01, -9.022601e-01, -8.486053e-02), 5.651902e-01, 4.689723e-05, 1.000000e+00, 23, 2313, 1) + ((1.028497e+01, -1.087614e+01, 9.418392e+00), (1.549579e-01, -4.270887e-01, 8.908329e-01), 5.395517e-01, 4.696349e-05, 1.000000e+00, 23, 2313, 1) + ((1.034128e+01, -1.103135e+01, 9.742126e+00), (5.631544e-01, 4.925564e-01, 6.635098e-01), 2.637257e-01, 4.732118e-05, 1.000000e+00, 23, 2313, 1) + ((1.044415e+01, -1.094137e+01, 9.863334e+00), (-1.034377e-01, 7.912271e-01, 6.027108e-01), 1.474934e-01, 4.757836e-05, 1.000000e+00, 23, 2313, 1) + ((1.043959e+01, -1.090643e+01, 9.889950e+00), (1.163182e-01, 9.160889e-01, -3.837331e-01), 1.522434e-01, 4.766149e-05, 1.000000e+00, 23, 2313, 1) + ((1.045733e+01, -1.076664e+01, 9.831395e+00), (-8.136862e-01, 9.805444e-02, -5.729748e-01), 3.341488e-02, 4.794423e-05, 1.000000e+00, 23, 2313, 1) + ((1.044231e+01, -1.076483e+01, 9.820815e+00), (-8.437241e-01, 5.222731e-01, -1.239373e-01), 3.874838e-02, 4.801727e-05, 1.000000e+00, 23, 2313, 1) + ((1.028725e+01, -1.066884e+01, 9.798037e+00), (-8.066297e-01, 3.960430e-01, -4.387465e-01), 3.989754e-02, 4.869227e-05, 1.000000e+00, 23, 2313, 1) + ((1.021310e+01, -1.063244e+01, 9.757708e+00), (-8.066297e-01, 3.960430e-01, -4.387465e-01), 3.989754e-02, 4.902498e-05, 1.000000e+00, 23, 2328, 1) + ((1.012717e+01, -1.059025e+01, 9.710967e+00), (-4.762033e-01, 8.377852e-01, -2.671075e-01), 3.271721e-02, 4.941058e-05, 1.000000e+00, 23, 2328, 1) + ((1.001043e+01, -1.038486e+01, 9.645483e+00), (-4.762033e-01, 8.377852e-01, -2.671075e-01), 3.271721e-02, 5.039049e-05, 1.000000e+00, 22, 2328, 3) + ((9.971285e+00, -1.031600e+01, 9.623530e+00), (5.437395e-01, -6.104117e-01, -5.759730e-01), 2.765456e-02, 5.071901e-05, 1.000000e+00, 22, 2328, 3) + ((1.002723e+01, -1.037881e+01, 9.564267e+00), (5.437395e-01, -6.104117e-01, -5.759730e-01), 2.765456e-02, 5.116633e-05, 1.000000e+00, 23, 2328, 1) + ((1.025152e+01, -1.063060e+01, 9.326683e+00), (-8.159392e-01, -4.792697e-03, 5.781179e-01), 2.920905e-02, 5.295966e-05, 1.000000e+00, 23, 2328, 1) + ((1.000779e+01, -1.063203e+01, 9.499373e+00), (-6.486477e-01, -4.621598e-01, -6.047020e-01), 2.383638e-02, 5.422329e-05, 1.000000e+00, 23, 2328, 1) + ((1.000721e+01, -1.063244e+01, 9.498835e+00), (-6.486477e-01, -4.621598e-01, -6.047020e-01), 2.383638e-02, 5.422746e-05, 1.000000e+00, 23, 2313, 1) + ((9.852478e+00, -1.074269e+01, 9.354584e+00), (-6.686452e-01, -2.988396e-01, 6.808880e-01), 2.993224e-02, 5.534454e-05, 1.000000e+00, 23, 2313, 1) + ((9.765042e+00, -1.078177e+01, 9.443621e+00), (7.712484e-01, -5.215773e-01, 3.648739e-01), 3.590785e-02, 5.589099e-05, 1.000000e+00, 23, 2313, 1) + ((9.798992e+00, -1.080472e+01, 9.459682e+00), (-4.563170e-01, 8.081811e-01, -3.723144e-01), 2.674168e-02, 5.605894e-05, 1.000000e+00, 23, 2313, 1) + ((9.792857e+00, -1.079386e+01, 9.454677e+00), (-9.080336e-01, 4.172659e-01, 3.693418e-02), 9.753404e-03, 5.611838e-05, 1.000000e+00, 23, 2313, 1) + ((9.653805e+00, -1.072996e+01, 9.460332e+00), (-3.727950e-01, 2.889342e-01, -8.817828e-01), 1.781716e-02, 5.723944e-05, 1.000000e+00, 23, 2313, 1) + ((9.628677e+00, -1.071048e+01, 9.400895e+00), (-6.406523e-01, 7.657269e-01, -5.680598e-02), 1.764425e-02, 5.760453e-05, 1.000000e+00, 23, 2313, 1) + ((9.563380e+00, -1.063244e+01, 9.395105e+00), (-6.406523e-01, 7.657269e-01, -5.680598e-02), 1.764425e-02, 5.815928e-05, 1.000000e+00, 23, 2328, 1) + ((9.411305e+00, -1.045068e+01, 9.381621e+00), (3.205568e-01, -1.311309e-02, -9.471385e-01), 2.153422e-02, 5.945128e-05, 1.000000e+00, 23, 2328, 1) + ((9.860026e+00, -1.046903e+01, 8.055798e+00), (6.278124e-01, 1.023095e-01, -7.716115e-01), 2.013742e-02, 6.634788e-05, 1.000000e+00, 23, 2328, 1) + ((1.007604e+01, -1.043383e+01, 7.790303e+00), (6.790346e-01, 5.167838e-01, 5.213891e-01), 1.340865e-02, 6.810089e-05, 1.000000e+00, 23, 2328, 1) + ((1.008869e+01, -1.042421e+01, 7.800011e+00), (2.792456e-01, 1.367953e-01, 9.504257e-01), 8.576635e-03, 6.821715e-05, 1.000000e+00, 23, 2328, 1) + ((1.017046e+01, -1.038415e+01, 8.078330e+00), (-9.462370e-01, 3.185163e-01, 5.641780e-02), 1.119274e-01, 7.050324e-05, 1.000000e+00, 23, 2328, 1) + ((1.008276e+01, -1.035463e+01, 8.083559e+00), (-9.462370e-01, 3.185163e-01, 5.641780e-02), 1.119274e-01, 7.070353e-05, 1.000000e+00, 22, 2328, 3) + ((9.952201e+00, -1.031068e+01, 8.091343e+00), (-9.462370e-01, 3.185163e-01, 5.641780e-02), 1.119274e-01, 7.100170e-05, 1.000000e+00, 21, 2328, 2) + ((9.404929e+00, -1.012646e+01, 8.123973e+00), (-9.462370e-01, 3.185163e-01, 5.641780e-02), 1.119274e-01, 7.225157e-05, 1.000000e+00, 22, 2328, 3) + ((9.274369e+00, -1.008251e+01, 8.131758e+00), (-9.462370e-01, 3.185163e-01, 5.641780e-02), 1.119274e-01, 7.254974e-05, 1.000000e+00, 23, 2328, 1) + ((9.126730e+00, -1.003281e+01, 8.140560e+00), (-8.389978e-01, -2.248732e-01, 4.954945e-01), 1.164832e-01, 7.288692e-05, 1.000000e+00, 23, 2328, 1) + ((8.996680e+00, -1.006767e+01, 8.217365e+00), (-8.389978e-01, -2.248732e-01, 4.954945e-01), 1.164832e-01, 7.321528e-05, 1.000000e+00, 23, 2327, 1) + ((8.694758e+00, -1.014859e+01, 8.395674e+00), (5.156148e-01, 7.316558e-01, 4.458937e-01), 1.391972e-01, 7.397758e-05, 1.000000e+00, 23, 2327, 1) + ((8.996680e+00, -9.720167e+00, 8.656770e+00), (5.156148e-01, 7.316558e-01, 4.458937e-01), 1.391972e-01, 7.511228e-05, 1.000000e+00, 23, 2328, 1) + ((9.263031e+00, -9.342216e+00, 8.887105e+00), (5.734531e-01, -5.017666e-01, 6.475970e-01), 9.798082e-02, 7.611330e-05, 1.000000e+00, 23, 2328, 1) + ((9.334809e+00, -9.405021e+00, 8.968164e+00), (5.419546e-03, -7.721039e-01, -6.354732e-01), 1.234091e-01, 7.640240e-05, 1.000000e+00, 23, 2328, 1) + ((9.335117e+00, -9.448857e+00, 8.932084e+00), (5.419546e-03, -7.721039e-01, -6.354732e-01), 1.234091e-01, 7.651925e-05, 1.000000e+00, 22, 2328, 3) + ((9.336345e+00, -9.623801e+00, 8.788098e+00), (5.419546e-03, -7.721039e-01, -6.354732e-01), 1.234091e-01, 7.698556e-05, 1.000000e+00, 21, 2328, 2) + ((9.339070e+00, -1.001201e+01, 8.468584e+00), (5.419546e-03, -7.721039e-01, -6.354732e-01), 1.234091e-01, 7.802034e-05, 1.000000e+00, 22, 2328, 3) + ((9.340298e+00, -1.018696e+01, 8.324598e+00), (5.419546e-03, -7.721039e-01, -6.354732e-01), 1.234091e-01, 7.848665e-05, 1.000000e+00, 23, 2328, 1) + ((9.343193e+00, -1.059945e+01, 7.985097e+00), (1.798796e-01, 3.522536e-02, -9.830577e-01), 1.283272e-01, 7.958616e-05, 1.000000e+00, 23, 2328, 1) + ((9.397753e+00, -1.058877e+01, 7.686922e+00), (6.459563e-01, 7.279465e-03, -7.633397e-01), 1.319449e-01, 8.019832e-05, 1.000000e+00, 23, 2328, 1) + ((9.462343e+00, -1.058804e+01, 7.610595e+00), (-5.748716e-01, 5.760301e-01, -5.811299e-01), 8.880732e-02, 8.039733e-05, 1.000000e+00, 23, 2328, 1) + ((9.287877e+00, -1.041322e+01, 7.434230e+00), (-4.932135e-03, 1.668926e-01, 9.859627e-01), 3.503028e-02, 8.113361e-05, 1.000000e+00, 23, 2328, 1) + ((9.286930e+00, -1.038117e+01, 7.623600e+00), (-9.325544e-02, -9.933000e-01, -6.825369e-02), 3.173764e-02, 8.187553e-05, 1.000000e+00, 23, 2328, 1) + ((9.283901e+00, -1.041342e+01, 7.621384e+00), (-4.235208e-01, -5.129112e-01, 7.466942e-01), 4.258127e-02, 8.200731e-05, 1.000000e+00, 23, 2328, 1) + ((9.264517e+00, -1.043690e+01, 7.655560e+00), (-7.165846e-01, 3.926265e-01, 5.764988e-01), 4.485063e-02, 8.216767e-05, 1.000000e+00, 23, 2328, 1) + ((9.256348e+00, -1.043242e+01, 7.662132e+00), (1.703748e-01, -9.175599e-01, -3.592441e-01), 3.521226e-02, 8.220659e-05, 1.000000e+00, 23, 2328, 1) + ((9.284015e+00, -1.058143e+01, 7.603793e+00), (3.963415e-01, -8.051509e-01, 4.411865e-01), 2.970280e-02, 8.283227e-05, 1.000000e+00, 23, 2328, 1) + ((9.309126e+00, -1.063244e+01, 7.631745e+00), (3.963415e-01, -8.051509e-01, 4.411865e-01), 2.970280e-02, 8.309804e-05, 1.000000e+00, 23, 2313, 1) + ((9.317824e+00, -1.065011e+01, 7.641427e+00), (7.190682e-01, 8.976507e-02, -6.891177e-01), 2.867417e-02, 8.319011e-05, 1.000000e+00, 23, 2313, 1) + ((9.459378e+00, -1.063244e+01, 7.505770e+00), (7.190682e-01, 8.976507e-02, -6.891177e-01), 2.867417e-02, 8.403060e-05, 1.000000e+00, 23, 2328, 1) + ((9.492454e+00, -1.062831e+01, 7.474071e+00), (4.092619e-03, -9.482095e-01, -3.176193e-01), 4.656141e-02, 8.422700e-05, 1.000000e+00, 23, 2328, 1) + ((9.492472e+00, -1.063244e+01, 7.472688e+00), (4.092619e-03, -9.482095e-01, -3.176193e-01), 4.656141e-02, 8.424159e-05, 1.000000e+00, 23, 2313, 1) + ((9.492761e+00, -1.069927e+01, 7.450302e+00), (9.457151e-01, -1.928731e-01, 2.615777e-01), 4.542312e-02, 8.447773e-05, 1.000000e+00, 23, 2313, 1) + ((9.890524e+00, -1.078039e+01, 7.560320e+00), (7.849118e-01, -1.237812e-01, -6.071175e-01), 5.609444e-02, 8.590450e-05, 1.000000e+00, 23, 2313, 1) + ((1.004645e+01, -1.080498e+01, 7.439717e+00), (7.849118e-01, -1.237812e-01, -6.071175e-01), 5.609444e-02, 8.651090e-05, 0.000000e+00, 23, 2313, 1)] diff --git a/tests/regression_tests/track_output/settings.xml b/tests/regression_tests/track_output/settings.xml new file mode 100644 index 000000000..dcfa118c8 --- /dev/null +++ b/tests/regression_tests/track_output/settings.xml @@ -0,0 +1,23 @@ + + + + + eigenvalue + 2 + 0 + 100 + + + + + -1 -1 -1 1 1 1 + + + + + 1 1 1 + 1 1 30 + 2 1 60 + + + diff --git a/tests/regression_tests/track_output/test.py b/tests/regression_tests/track_output/test.py index 299e1aa34..62526117d 100644 --- a/tests/regression_tests/track_output/test.py +++ b/tests/regression_tests/track_output/test.py @@ -1,6 +1,7 @@ import glob import os from pathlib import Path +from subprocess import call import numpy as np import openmc @@ -25,8 +26,8 @@ class TrackTestHarness(TestHarness): # For MPI mode, combine track files if config['mpi']: - track_files = list(glob.glob('tracks_p*.h5')) - openmc.Tracks.combine(track_files, 'tracks.h5') + call(['../../../scripts/openmc-track-combine', '-o', 'tracks.h5'] + + glob.glob('tracks_p*.h5')) # Get string of track file information outstr = '' diff --git a/tests/regression_tests/translation/results_true.dat b/tests/regression_tests/translation/results_true.dat index 6e03d2224..32897b8e7 100644 --- a/tests/regression_tests/translation/results_true.dat +++ b/tests/regression_tests/translation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.076610E-01 6.454244E-03 +4.003951E-01 7.739871E-03 diff --git a/tests/regression_tests/trigger_batch_interval/results_true.dat b/tests/regression_tests/trigger_batch_interval/results_true.dat index 92fa99d87..2fcfaa10a 100644 --- a/tests/regression_tests/trigger_batch_interval/results_true.dat +++ b/tests/regression_tests/trigger_batch_interval/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.863217E-01 6.499354E-03 +9.764624E-01 8.747085E-03 tally 1: -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 tally 2: -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 diff --git a/tests/regression_tests/trigger_no_batch_interval/results_true.dat b/tests/regression_tests/trigger_no_batch_interval/results_true.dat index 92fa99d87..2fcfaa10a 100644 --- a/tests/regression_tests/trigger_no_batch_interval/results_true.dat +++ b/tests/regression_tests/trigger_no_batch_interval/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.863217E-01 6.499354E-03 +9.764624E-01 8.747085E-03 tally 1: -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 tally 2: -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 diff --git a/tests/regression_tests/trigger_no_status/results_true.dat b/tests/regression_tests/trigger_no_status/results_true.dat index a62e1b3fe..e95f05ccb 100644 --- a/tests/regression_tests/trigger_no_status/results_true.dat +++ b/tests/regression_tests/trigger_no_status/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.858966E-01 1.500542E-02 +9.688702E-01 2.263104E-02 tally 1: -7.081828E+00 -1.003709E+01 -1.607382E+00 -5.171386E-01 -1.559242E+00 -4.866413E-01 -5.474447E+00 -5.997737E+00 -7.081828E+00 -1.003709E+01 -1.607382E+00 -5.171386E-01 -1.559242E+00 -4.866413E-01 -5.474447E+00 -5.997737E+00 +7.069810E+00 +1.000691E+01 +1.597648E+00 +5.109653E-01 +1.547262E+00 +4.792189E-01 +5.472161E+00 +5.995488E+00 +7.069810E+00 +1.000691E+01 +1.597648E+00 +5.109653E-01 +1.547262E+00 +4.792189E-01 +5.472161E+00 +5.995488E+00 tally 2: -7.081828E+00 -1.003709E+01 -1.607382E+00 -5.171386E-01 -1.559242E+00 -4.866413E-01 -5.474447E+00 -5.997737E+00 +7.069810E+00 +1.000691E+01 +1.597648E+00 +5.109653E-01 +1.547262E+00 +4.792189E-01 +5.472161E+00 +5.995488E+00 diff --git a/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat b/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat index 59a829700..2c422697b 100644 --- a/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat +++ b/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat @@ -1,34 +1,35 @@ - - - - - - - - - - - - - eigenvalue - 400 - 15 - 10 - - 0.002 - std_dev - - - true - 1000 - 1 - - 1 - - - - flux - - - + + + + + + + + + + + + + + eigenvalue + 400 + 15 + 10 + + 0.003 + std_dev + + + true + 1000 + 1 + + 1 + + + + + flux + + diff --git a/tests/regression_tests/trigger_statepoint_restart/results_true.dat b/tests/regression_tests/trigger_statepoint_restart/results_true.dat index 3cb1e230d..3ab555d73 100644 --- a/tests/regression_tests/trigger_statepoint_restart/results_true.dat +++ b/tests/regression_tests/trigger_statepoint_restart/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.948661E-01 1.949846E-03 +2.963805E-01 2.986351E-03 tally 1: -5.515170E+01 -4.349007E+02 +8.017826E+01 +6.436316E+02 diff --git a/tests/regression_tests/trigger_statepoint_restart/test.py b/tests/regression_tests/trigger_statepoint_restart/test.py index b242f7f1c..8144c1d0b 100644 --- a/tests/regression_tests/trigger_statepoint_restart/test.py +++ b/tests/regression_tests/trigger_statepoint_restart/test.py @@ -29,7 +29,7 @@ def model(): settings.inactive = 10 settings.particles = 400 # Choose a sufficiently low threshold to enable use of trigger - settings.keff_trigger = {'type': 'std_dev', 'threshold': 0.002} + settings.keff_trigger = {'type': 'std_dev', 'threshold': 0.003} settings.trigger_max_batches = 1000 settings.trigger_batch_interval = 1 settings.trigger_active = True @@ -41,10 +41,10 @@ def model(): tallies = openmc.Tallies([t]) # Put it all together - model = openmc.Model(materials=materials, - geometry=geometry, - settings=settings, - tallies=tallies) + model = openmc.model.Model(materials=materials, + geometry=geometry, + settings=settings, + tallies=tallies) return model diff --git a/tests/regression_tests/trigger_tallies/results_true.dat b/tests/regression_tests/trigger_tallies/results_true.dat index 92fa99d87..2fcfaa10a 100644 --- a/tests/regression_tests/trigger_tallies/results_true.dat +++ b/tests/regression_tests/trigger_tallies/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.863217E-01 6.499354E-03 +9.764624E-01 8.747085E-03 tally 1: -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 tally 2: -1.423436E+01 -2.027258E+01 -3.223740E+00 -1.039872E+00 -3.125016E+00 -9.771709E-01 -1.101062E+01 -1.212977E+01 +1.408588E+01 +1.985937E+01 +3.194837E+00 +1.021391E+00 +3.096170E+00 +9.592197E-01 +1.089104E+01 +1.187349E+01 diff --git a/tests/regression_tests/triso/inputs_true.dat b/tests/regression_tests/triso/inputs_true.dat index c96684568..2ea049465 100644 --- a/tests/regression_tests/triso/inputs_true.dat +++ b/tests/regression_tests/triso/inputs_true.dat @@ -1,442 +1,442 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.3333333333333333 0.3333333333333333 0.3333333333333333 - 30 - 3 3 3 - -0.5 -0.5 -0.5 - -9 10 11 -6 7 8 -3 4 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.3333333333333333 0.3333333333333333 0.3333333333333333 + 38 + 3 3 3 + -0.5 -0.5 -0.5 + +17 18 19 +14 15 16 +11 12 13 -18 19 20 -15 16 17 -12 13 14 +26 27 28 +23 24 25 +20 21 22 -27 28 29 -24 25 26 -21 22 23 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 4 - 0 - - - 0.0 0.0 0.0 - - - - +35 36 37 +32 33 34 +29 30 31 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 4 + 0 + + + 0.0 0.0 0.0 + + + diff --git a/tests/regression_tests/triso/results_true.dat b/tests/regression_tests/triso/results_true.dat index d9850e410..279094ab3 100644 --- a/tests/regression_tests/triso/results_true.dat +++ b/tests/regression_tests/triso/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.604832E+00 2.031393E-03 +1.406055E+00 9.581396E-02 diff --git a/tests/regression_tests/triso/test.py b/tests/regression_tests/triso/test.py index 3fa5e3c60..c44715691 100644 --- a/tests/regression_tests/triso/test.py +++ b/tests/regression_tests/triso/test.py @@ -1,3 +1,7 @@ +import random +from math import sqrt + +import numpy as np import openmc import openmc.model @@ -5,8 +9,7 @@ from tests.testing_harness import PyAPITestHarness class TRISOTestHarness(PyAPITestHarness): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def _build_inputs(self): # Define TRISO matrials fuel = openmc.Material() fuel.set_density('g/cm3', 10.5) @@ -61,8 +64,8 @@ class TRISOTestHarness(PyAPITestHarness): box = openmc.Cell(region=box_region) outer_radius = 422.5*1e-4 - centers = openmc.model.pack_spheres( - radius=outer_radius, region=box_region, num_spheres=100, seed=1) + centers = openmc.model.pack_spheres(radius=outer_radius, + region=box_region, num_spheres=100) trisos = [openmc.model.TRISO(outer_radius, inner_univ, c) for c in centers] @@ -75,19 +78,20 @@ class TRISOTestHarness(PyAPITestHarness): box.fill = lattice root = openmc.Universe(0, cells=[box]) - self._model.geometry = openmc.Geometry(root) + geom = openmc.Geometry(root) + geom.export_to_xml() settings = openmc.Settings() settings.batches = 4 settings.inactive = 0 settings.particles = 100 - settings.source = openmc.IndependentSource(space=openmc.stats.Point()) - self._model.settings = settings + settings.source = openmc.Source(space=openmc.stats.Point()) + settings.export_to_xml() - self._model.materials = openmc.Materials([fuel, porous_carbon, ipyc, - sic, opyc, graphite]) + mats = openmc.Materials([fuel, porous_carbon, ipyc, sic, opyc, graphite]) + mats.export_to_xml() def test_triso(): - harness = TRISOTestHarness('statepoint.4.h5', model=openmc.Model()) + harness = TRISOTestHarness('statepoint.4.h5') harness.main() diff --git a/tests/regression_tests/uniform_fs/results_true.dat b/tests/regression_tests/uniform_fs/results_true.dat index f7ceecfb7..ebf06a8d3 100644 --- a/tests/regression_tests/uniform_fs/results_true.dat +++ b/tests/regression_tests/uniform_fs/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.675645E-01 4.342970E-03 +3.643255E-01 1.041799E-02 diff --git a/tests/regression_tests/universe/results_true.dat b/tests/regression_tests/universe/results_true.dat index 97b997ae6..fe46748c8 100644 --- a/tests/regression_tests/universe/results_true.dat +++ b/tests/regression_tests/universe/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.940336E-01 7.338463E-04 +2.987050E-01 1.827430E-03 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true.dat b/tests/regression_tests/unstructured_mesh/inputs_true.dat index e7a485b4d..e556782ad 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_hexes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_hexes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true0.dat b/tests/regression_tests/unstructured_mesh/inputs_true0.dat index 2508c25b3..2e2594cde 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true0.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true0.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true1.dat b/tests/regression_tests/unstructured_mesh/inputs_true1.dat index 04bbdb4b2..84a3b186b 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true1.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true1.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true10.dat b/tests/regression_tests/unstructured_mesh/inputs_true10.dat index 169f0a6b4..e9272a333 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true10.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true10.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true11.dat b/tests/regression_tests/unstructured_mesh/inputs_true11.dat index 8163750ca..0b89d280c 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true11.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true11.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true12.dat b/tests/regression_tests/unstructured_mesh/inputs_true12.dat index be0655e98..b3673a254 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true12.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true12.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true13.dat b/tests/regression_tests/unstructured_mesh/inputs_true13.dat index 42c0cc122..c466396b6 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true13.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true13.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true14.dat b/tests/regression_tests/unstructured_mesh/inputs_true14.dat index a27c7445d..8c6a5120a 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true14.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true14.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true15.dat b/tests/regression_tests/unstructured_mesh/inputs_true15.dat index c69bd15d0..1b9abbd83 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true15.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true15.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true2.dat b/tests/regression_tests/unstructured_mesh/inputs_true2.dat index ba9d477b5..7136d485a 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true2.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true2.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true3.dat b/tests/regression_tests/unstructured_mesh/inputs_true3.dat index d840bfa09..23900a060 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true3.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true3.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true4.dat b/tests/regression_tests/unstructured_mesh/inputs_true4.dat index db8e37177..995a1828f 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true4.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true4.dat @@ -1,90 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 9 + + + 10 + + + 9 + flux + tracklength + + + 10 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true5.dat b/tests/regression_tests/unstructured_mesh/inputs_true5.dat index b2bbc7e16..60229e5e5 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true5.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true5.dat @@ -1,90 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 11 + + + 12 + + + 11 + flux + tracklength + + + 12 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true6.dat b/tests/regression_tests/unstructured_mesh/inputs_true6.dat index d6ad0d98d..7a9257cb7 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true6.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true6.dat @@ -1,90 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 13 + + + 14 + + + 13 + flux + tracklength + + + 14 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true7.dat b/tests/regression_tests/unstructured_mesh/inputs_true7.dat index 924790a8c..52802febf 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true7.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true7.dat @@ -1,90 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 15 + + + 16 + + + 15 + flux + tracklength + + + 16 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true8.dat b/tests/regression_tests/unstructured_mesh/inputs_true8.dat index c04beb211..a0cbbcae7 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true8.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true8.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true9.dat b/tests/regression_tests/unstructured_mesh/inputs_true9.dat index 111898ff2..930bd8579 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true9.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true9.dat @@ -1,90 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 1.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/results_true.dat b/tests/regression_tests/unstructured_mesh/results_true.dat new file mode 100644 index 000000000..c93eadfdb --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/results_true.dat @@ -0,0 +1,26002 @@ +tally 1: +4.873713E-02 +2.881006E-04 +7.388548E-02 +6.421281E-04 +8.309847E-02 +8.079791E-04 +8.802030E-02 +8.590396E-04 +6.935977E-02 +5.711723E-04 +7.203243E-02 +5.847086E-04 +8.146742E-02 +8.422730E-04 +7.112287E-02 +5.331461E-04 +6.944025E-02 +6.220640E-04 +4.605581E-02 +3.052058E-04 +7.341445E-02 +6.319466E-04 +9.013420E-02 +1.083246E-03 +1.221831E-01 +1.761591E-03 +1.244445E-01 +1.714565E-03 +1.324446E-01 +2.041161E-03 +1.110879E-01 +1.399393E-03 +1.484356E-01 +2.412924E-03 +1.243711E-01 +1.740278E-03 +1.011503E-01 +1.167740E-03 +6.361036E-02 +4.887610E-04 +6.774704E-02 +6.414084E-04 +8.554708E-02 +9.422426E-04 +1.400424E-01 +2.238846E-03 +1.573053E-01 +2.687261E-03 +1.640744E-01 +2.864310E-03 +1.305526E-01 +1.848808E-03 +1.688498E-01 +3.171592E-03 +1.886270E-01 +3.972143E-03 +1.198794E-01 +1.610468E-03 +7.781359E-02 +8.133302E-04 +8.003923E-02 +7.488868E-04 +1.533578E-01 +2.662538E-03 +2.008234E-01 +4.137147E-03 +2.073409E-01 +4.520687E-03 +1.975748E-01 +4.160887E-03 +2.267844E-01 +5.491338E-03 +1.881489E-01 +3.776524E-03 +1.546827E-01 +2.713647E-03 +1.390602E-01 +2.088805E-03 +9.507737E-02 +1.035204E-03 +9.443902E-02 +9.783367E-04 +1.528603E-01 +2.521963E-03 +2.009995E-01 +4.414632E-03 +2.303894E-01 +5.751985E-03 +2.273601E-01 +5.379286E-03 +2.086601E-01 +4.747259E-03 +1.587188E-01 +2.863534E-03 +1.656423E-01 +2.826265E-03 +1.358638E-01 +2.045306E-03 +9.729054E-02 +1.078500E-03 +1.007280E-01 +1.185702E-03 +1.587021E-01 +2.754745E-03 +1.900019E-01 +3.874093E-03 +1.874138E-01 +4.177562E-03 +2.233840E-01 +5.748107E-03 +2.044120E-01 +4.806449E-03 +1.840480E-01 +3.872224E-03 +2.000442E-01 +4.610770E-03 +1.260142E-01 +1.809723E-03 +8.400216E-02 +8.434010E-04 +5.900093E-02 +3.850176E-04 +1.411568E-01 +2.471608E-03 +1.744586E-01 +3.239802E-03 +1.834956E-01 +3.972256E-03 +2.120173E-01 +4.965877E-03 +1.896203E-01 +3.727876E-03 +1.768841E-01 +3.517246E-03 +1.329247E-01 +1.981664E-03 +9.206320E-02 +1.061169E-03 +8.660878E-02 +8.546437E-04 +7.697726E-02 +7.926443E-04 +1.161555E-01 +1.548200E-03 +1.386967E-01 +2.047818E-03 +1.482373E-01 +2.537385E-03 +1.929067E-01 +4.259826E-03 +1.371938E-01 +1.949236E-03 +1.308202E-01 +2.027747E-03 +1.135428E-01 +1.560189E-03 +1.215934E-01 +1.672414E-03 +4.697342E-02 +3.377074E-04 +4.963529E-02 +3.397352E-04 +8.476039E-02 +8.774056E-04 +1.108440E-01 +1.411371E-03 +1.054914E-01 +1.252891E-03 +1.453762E-01 +2.358977E-03 +9.293716E-02 +9.683367E-04 +1.224872E-01 +1.612325E-03 +8.334352E-02 +7.907688E-04 +7.546069E-02 +7.025010E-04 +5.962134E-02 +6.951755E-04 +3.107769E-02 +1.723123E-04 +8.479467E-02 +9.620488E-04 +8.295926E-02 +7.769636E-04 +8.805824E-02 +8.500302E-04 +8.616294E-02 +8.661213E-04 +7.861089E-02 +6.835617E-04 +7.593919E-02 +7.633339E-04 +7.303400E-02 +6.464593E-04 +7.512486E-02 +6.007484E-04 +5.595863E-02 +4.403603E-04 +6.015811E-02 +4.297440E-04 +8.867588E-02 +8.521129E-04 +1.103542E-01 +1.469796E-03 +1.153731E-01 +1.606650E-03 +1.280835E-01 +1.791883E-03 +1.434578E-01 +2.215626E-03 +1.104920E-01 +1.470286E-03 +9.385805E-02 +1.114787E-03 +1.169307E-01 +1.600595E-03 +6.083594E-02 +4.303510E-04 +8.816849E-02 +8.791686E-04 +1.350912E-01 +2.127521E-03 +2.026574E-01 +4.456203E-03 +2.082171E-01 +4.587768E-03 +2.291899E-01 +5.560114E-03 +2.040384E-01 +4.355166E-03 +2.081784E-01 +5.172938E-03 +1.958644E-01 +4.308708E-03 +1.535028E-01 +2.754667E-03 +6.265531E-02 +4.662647E-04 +1.239416E-01 +1.608329E-03 +1.655136E-01 +3.098331E-03 +2.152185E-01 +5.116031E-03 +2.663061E-01 +7.502107E-03 +3.072160E-01 +9.873652E-03 +2.453306E-01 +6.585229E-03 +2.577460E-01 +6.982524E-03 +2.470375E-01 +6.761678E-03 +1.492132E-01 +2.465269E-03 +1.115903E-01 +1.444496E-03 +8.901752E-02 +9.826260E-04 +1.849459E-01 +3.824332E-03 +3.139129E-01 +1.040826E-02 +3.209843E-01 +1.072304E-02 +3.074029E-01 +9.805249E-03 +3.289037E-01 +1.137280E-02 +3.333668E-01 +1.140301E-02 +2.305636E-01 +5.572002E-03 +1.911618E-01 +3.897249E-03 +1.239342E-01 +1.745528E-03 +1.463546E-01 +2.897280E-03 +2.041194E-01 +4.264966E-03 +2.781505E-01 +8.222869E-03 +3.535732E-01 +1.290897E-02 +3.736359E-01 +1.424372E-02 +3.507573E-01 +1.268186E-02 +3.537878E-01 +1.317025E-02 +2.797764E-01 +8.141471E-03 +2.257660E-01 +5.307299E-03 +1.248875E-01 +1.867307E-03 +1.334027E-01 +1.952356E-03 +2.190936E-01 +5.220949E-03 +2.880627E-01 +9.292540E-03 +3.683567E-01 +1.398170E-02 +3.451428E-01 +1.245893E-02 +3.602954E-01 +1.357760E-02 +3.363047E-01 +1.177859E-02 +2.658735E-01 +8.042327E-03 +1.720687E-01 +3.616340E-03 +9.348145E-02 +9.216558E-04 +1.303415E-01 +2.064085E-03 +1.757103E-01 +3.440908E-03 +2.442374E-01 +6.810297E-03 +2.858542E-01 +8.698701E-03 +3.349866E-01 +1.174757E-02 +2.840415E-01 +8.265549E-03 +2.763234E-01 +8.045873E-03 +2.478361E-01 +6.589169E-03 +1.766169E-01 +3.338895E-03 +1.236805E-01 +1.649583E-03 +1.307918E-01 +1.796440E-03 +1.756810E-01 +3.938136E-03 +2.071625E-01 +4.889011E-03 +2.332393E-01 +5.650908E-03 +2.524899E-01 +7.236764E-03 +2.393364E-01 +5.985752E-03 +2.142983E-01 +4.994425E-03 +2.132056E-01 +4.981318E-03 +1.437349E-01 +2.274574E-03 +1.142901E-01 +1.631508E-03 +7.809219E-02 +7.844820E-04 +1.076778E-01 +1.505283E-03 +1.787646E-01 +3.437697E-03 +1.664344E-01 +2.938475E-03 +1.868305E-01 +3.942399E-03 +2.065932E-01 +4.503697E-03 +1.644873E-01 +3.015461E-03 +1.553155E-01 +2.637052E-03 +1.523517E-01 +2.641268E-03 +8.646767E-02 +8.586764E-04 +4.575304E-02 +2.880831E-04 +8.659752E-02 +1.007122E-03 +1.086638E-01 +1.418859E-03 +1.206844E-01 +1.631006E-03 +1.553521E-01 +2.699733E-03 +1.023448E-01 +1.229544E-03 +1.236892E-01 +1.719554E-03 +1.059603E-01 +1.474144E-03 +9.843445E-02 +1.147384E-03 +6.598215E-02 +6.724344E-04 +8.999660E-02 +1.129810E-03 +1.016655E-01 +1.128618E-03 +1.115822E-01 +1.437827E-03 +1.649326E-01 +3.015499E-03 +1.937529E-01 +4.048175E-03 +1.852317E-01 +3.668098E-03 +1.620688E-01 +2.937845E-03 +1.290063E-01 +1.922280E-03 +1.208701E-01 +1.669032E-03 +4.421440E-02 +2.483126E-04 +1.159755E-01 +1.426808E-03 +1.459714E-01 +2.613102E-03 +1.778589E-01 +3.427022E-03 +2.346134E-01 +5.940704E-03 +3.063520E-01 +1.009182E-02 +2.950770E-01 +9.132939E-03 +2.583166E-01 +7.253540E-03 +2.101808E-01 +5.272950E-03 +1.850368E-01 +3.730831E-03 +7.244837E-02 +5.806488E-04 +1.441504E-01 +2.203647E-03 +2.206693E-01 +5.103470E-03 +3.047901E-01 +9.751684E-03 +3.531926E-01 +1.351362E-02 +3.945357E-01 +1.624582E-02 +4.621245E-01 +2.215536E-02 +4.200516E-01 +1.926381E-02 +3.397496E-01 +1.264644E-02 +2.045791E-01 +4.443989E-03 +1.132779E-01 +1.665634E-03 +1.168744E-01 +1.466979E-03 +2.665743E-01 +7.799994E-03 +4.108479E-01 +1.764683E-02 +5.099245E-01 +2.656607E-02 +5.375292E-01 +2.986206E-02 +5.477580E-01 +3.184925E-02 +5.060566E-01 +2.644067E-02 +3.917491E-01 +1.649179E-02 +2.631839E-01 +7.172646E-03 +1.393797E-01 +2.179333E-03 +1.415608E-01 +2.582853E-03 +2.695963E-01 +8.100051E-03 +4.591315E-01 +2.150436E-02 +5.838830E-01 +3.565296E-02 +6.933462E-01 +4.933765E-02 +6.498992E-01 +4.329824E-02 +5.274087E-01 +2.893644E-02 +4.644714E-01 +2.208542E-02 +2.784825E-01 +8.228619E-03 +1.756971E-01 +3.435838E-03 +1.841108E-01 +3.753742E-03 +2.556216E-01 +6.993979E-03 +4.539882E-01 +2.105903E-02 +5.644697E-01 +3.353269E-02 +6.477708E-01 +4.262528E-02 +6.274586E-01 +4.094566E-02 +4.871803E-01 +2.460107E-02 +3.651460E-01 +1.537598E-02 +2.377974E-01 +6.036841E-03 +1.492687E-01 +2.421537E-03 +1.449703E-01 +2.190902E-03 +2.414255E-01 +6.387083E-03 +4.115719E-01 +1.783179E-02 +4.694990E-01 +2.282330E-02 +5.311416E-01 +2.970750E-02 +5.218655E-01 +2.795428E-02 +4.993270E-01 +2.574782E-02 +3.564483E-01 +1.422766E-02 +2.266457E-01 +5.534879E-03 +1.952576E-01 +4.177312E-03 +1.042590E-01 +1.176129E-03 +1.697991E-01 +3.286179E-03 +2.717221E-01 +8.156353E-03 +3.954295E-01 +1.626070E-02 +3.609317E-01 +1.316825E-02 +4.028309E-01 +1.737150E-02 +3.598743E-01 +1.378511E-02 +2.960368E-01 +9.045648E-03 +1.916245E-01 +4.182938E-03 +1.400504E-01 +2.146240E-03 +7.940300E-02 +7.986853E-04 +1.200054E-01 +1.726710E-03 +2.148774E-01 +4.835765E-03 +2.268851E-01 +5.713301E-03 +3.111988E-01 +1.041879E-02 +2.623195E-01 +7.661642E-03 +2.331769E-01 +5.928043E-03 +2.156752E-01 +5.033537E-03 +1.882320E-01 +3.956427E-03 +9.864956E-02 +1.084355E-03 +6.087770E-02 +5.179666E-04 +1.086978E-01 +1.313619E-03 +1.344587E-01 +1.970449E-03 +1.740701E-01 +3.313694E-03 +1.804922E-01 +3.525957E-03 +1.724149E-01 +3.543590E-03 +1.399028E-01 +2.273390E-03 +1.456847E-01 +2.524033E-03 +1.194497E-01 +1.524909E-03 +6.585025E-02 +6.225934E-04 +8.228757E-02 +8.696950E-04 +9.653270E-02 +9.897964E-04 +1.628236E-01 +3.163363E-03 +2.294784E-01 +5.585206E-03 +2.013744E-01 +4.481916E-03 +1.904412E-01 +4.042826E-03 +1.614976E-01 +2.818448E-03 +1.577143E-01 +2.732044E-03 +1.102866E-01 +1.529048E-03 +7.446456E-02 +6.633761E-04 +1.435986E-01 +2.237722E-03 +1.897248E-01 +4.132042E-03 +2.294338E-01 +5.931694E-03 +3.421437E-01 +1.221982E-02 +3.839244E-01 +1.553491E-02 +3.266968E-01 +1.088442E-02 +3.198477E-01 +1.080985E-02 +2.628059E-01 +7.789175E-03 +1.734962E-01 +3.443215E-03 +1.286647E-01 +1.955856E-03 +1.691938E-01 +3.460989E-03 +2.825603E-01 +8.930867E-03 +3.393298E-01 +1.245987E-02 +4.719879E-01 +2.299342E-02 +5.453030E-01 +3.116166E-02 +5.283745E-01 +2.875357E-02 +4.717010E-01 +2.274570E-02 +3.543923E-01 +1.356917E-02 +2.286992E-01 +5.495781E-03 +1.503321E-01 +2.412737E-03 +1.914802E-01 +4.228512E-03 +2.663347E-01 +7.478291E-03 +4.945846E-01 +2.581416E-02 +7.132283E-01 +5.214747E-02 +8.772549E-01 +8.070787E-02 +9.215230E-01 +8.643514E-02 +7.136543E-01 +5.309880E-02 +4.683027E-01 +2.335474E-02 +2.848724E-01 +8.819567E-03 +1.962746E-01 +4.034279E-03 +1.963942E-01 +4.150202E-03 +3.081918E-01 +1.036112E-02 +5.313924E-01 +2.943772E-02 +8.980200E-01 +8.439371E-02 +1.404070E+00 +1.986543E-01 +1.242684E+00 +1.571634E-01 +8.663320E-01 +7.587086E-02 +5.654541E-01 +3.252262E-02 +3.281152E-01 +1.090032E-02 +2.044034E-01 +4.517108E-03 +2.006195E-01 +4.176414E-03 +3.100848E-01 +1.042288E-02 +5.422115E-01 +3.004711E-02 +9.330393E-01 +8.964243E-02 +1.277607E+00 +1.657398E-01 +1.173275E+00 +1.409364E-01 +8.049595E-01 +6.791702E-02 +4.739057E-01 +2.461174E-02 +3.052609E-01 +9.872506E-03 +2.088298E-01 +4.793522E-03 +2.133326E-01 +4.862481E-03 +2.680060E-01 +7.625628E-03 +4.610074E-01 +2.155754E-02 +6.717074E-01 +4.626196E-02 +8.563743E-01 +7.430382E-02 +8.419238E-01 +7.436332E-02 +6.475334E-01 +4.244410E-02 +4.496406E-01 +2.101233E-02 +3.081348E-01 +1.046704E-02 +1.619249E-01 +3.062437E-03 +1.415369E-01 +2.255371E-03 +2.064850E-01 +4.712501E-03 +3.464136E-01 +1.293262E-02 +4.719265E-01 +2.272450E-02 +6.461406E-01 +4.354686E-02 +5.185955E-01 +2.909923E-02 +4.946850E-01 +2.606769E-02 +3.812863E-01 +1.500761E-02 +2.715616E-01 +7.844887E-03 +1.440914E-01 +2.297969E-03 +1.220110E-01 +1.727820E-03 +1.988195E-01 +4.845577E-03 +2.623807E-01 +7.651539E-03 +3.140727E-01 +1.024276E-02 +3.576120E-01 +1.349203E-02 +3.350431E-01 +1.214172E-02 +3.623127E-01 +1.392899E-02 +2.727478E-01 +8.086348E-03 +2.149275E-01 +5.361115E-03 +1.314584E-01 +1.963133E-03 +9.162433E-02 +9.983184E-04 +1.361470E-01 +2.027658E-03 +1.761731E-01 +3.389541E-03 +1.989963E-01 +4.594834E-03 +1.950142E-01 +4.102131E-03 +2.134629E-01 +4.672913E-03 +1.986280E-01 +4.090736E-03 +1.587464E-01 +2.850886E-03 +1.139834E-01 +1.491308E-03 +9.993253E-02 +1.150993E-03 +7.801279E-02 +7.470217E-04 +1.374998E-01 +1.969932E-03 +1.804494E-01 +3.568829E-03 +2.466413E-01 +6.594134E-03 +2.341345E-01 +5.848688E-03 +1.995756E-01 +4.362592E-03 +1.602288E-01 +3.066421E-03 +1.562435E-01 +2.552603E-03 +1.104688E-01 +1.359308E-03 +1.007842E-01 +1.139355E-03 +1.261199E-01 +1.847741E-03 +1.775287E-01 +3.680466E-03 +2.767100E-01 +8.008082E-03 +3.400792E-01 +1.195930E-02 +3.935631E-01 +1.640831E-02 +3.523748E-01 +1.302259E-02 +2.906020E-01 +9.059548E-03 +2.537932E-01 +6.876862E-03 +1.861336E-01 +3.787655E-03 +1.313071E-01 +2.065327E-03 +1.591139E-01 +2.819971E-03 +2.386577E-01 +6.457612E-03 +3.911616E-01 +1.594274E-02 +5.394472E-01 +3.061236E-02 +6.866890E-01 +4.817139E-02 +6.283365E-01 +4.055448E-02 +5.748601E-01 +3.459526E-02 +4.435554E-01 +2.009979E-02 +3.296444E-01 +1.154923E-02 +1.967361E-01 +4.169679E-03 +1.739968E-01 +3.208983E-03 +3.082977E-01 +9.811520E-03 +5.382503E-01 +3.058501E-02 +8.367621E-01 +7.291096E-02 +1.211062E+00 +1.496807E-01 +1.258748E+00 +1.608596E-01 +9.427524E-01 +9.038319E-02 +6.071099E-01 +3.854873E-02 +3.709298E-01 +1.478349E-02 +2.098170E-01 +4.835442E-03 +2.119024E-01 +4.712157E-03 +3.552855E-01 +1.323431E-02 +6.321647E-01 +4.077718E-02 +1.246141E+00 +1.565725E-01 +4.380951E+00 +1.942648E+00 +4.247605E+00 +1.810085E+00 +1.281712E+00 +1.683930E-01 +6.221859E-01 +3.919458E-02 +3.675010E-01 +1.432994E-02 +1.841643E-01 +3.510340E-03 +2.146914E-01 +5.048810E-03 +3.256950E-01 +1.139212E-02 +6.810729E-01 +4.813808E-02 +1.247489E+00 +1.574970E-01 +4.442262E+00 +1.985510E+00 +4.257415E+00 +1.821021E+00 +1.235711E+00 +1.535743E-01 +6.900244E-01 +4.832224E-02 +3.697406E-01 +1.425051E-02 +2.012083E-01 +4.510582E-03 +1.912047E-01 +4.273539E-03 +3.451744E-01 +1.225531E-02 +5.600376E-01 +3.307491E-02 +8.544790E-01 +7.409781E-02 +1.325242E+00 +1.782579E-01 +1.346957E+00 +1.841487E-01 +9.214797E-01 +8.688521E-02 +4.797898E-01 +2.328018E-02 +3.426011E-01 +1.225085E-02 +1.774389E-01 +3.518562E-03 +1.554220E-01 +2.654272E-03 +2.668481E-01 +7.631552E-03 +4.104944E-01 +1.755636E-02 +5.095732E-01 +2.660987E-02 +6.919120E-01 +4.918083E-02 +7.159855E-01 +5.218821E-02 +6.006622E-01 +3.710972E-02 +4.366095E-01 +2.004334E-02 +2.694762E-01 +7.978724E-03 +1.656914E-01 +3.089952E-03 +1.756674E-01 +3.399731E-03 +2.115494E-01 +4.962007E-03 +2.931609E-01 +9.634091E-03 +3.427335E-01 +1.230723E-02 +3.926075E-01 +1.686560E-02 +4.266016E-01 +1.861013E-02 +3.380544E-01 +1.177601E-02 +3.203345E-01 +1.042122E-02 +2.107818E-01 +4.975737E-03 +1.190587E-01 +1.667581E-03 +1.043469E-01 +1.388459E-03 +1.409254E-01 +2.165664E-03 +1.158111E-01 +1.584653E-03 +2.204672E-01 +5.077689E-03 +2.548870E-01 +6.790565E-03 +2.560290E-01 +6.703128E-03 +2.273470E-01 +5.548064E-03 +1.544622E-01 +2.859247E-03 +1.514176E-01 +2.580868E-03 +9.401839E-02 +9.957536E-04 +8.183741E-02 +1.018095E-03 +1.494302E-01 +2.610469E-03 +1.724667E-01 +3.163766E-03 +1.906518E-01 +3.886725E-03 +2.093021E-01 +4.547285E-03 +2.192608E-01 +5.381555E-03 +2.142120E-01 +5.229554E-03 +1.818979E-01 +3.730168E-03 +1.593537E-01 +2.930097E-03 +1.006301E-01 +1.243388E-03 +1.363959E-01 +2.201651E-03 +1.921074E-01 +4.287698E-03 +2.807569E-01 +8.586780E-03 +3.032112E-01 +9.281779E-03 +3.488735E-01 +1.290376E-02 +3.912428E-01 +1.651860E-02 +4.032276E-01 +1.745809E-02 +2.909627E-01 +9.146241E-03 +1.775633E-01 +3.593723E-03 +1.331733E-01 +1.922430E-03 +1.524251E-01 +2.694091E-03 +2.697127E-01 +7.768392E-03 +4.166062E-01 +1.776536E-02 +5.663715E-01 +3.298425E-02 +6.244007E-01 +3.998959E-02 +6.599368E-01 +4.570158E-02 +5.685603E-01 +3.382373E-02 +3.800938E-01 +1.547625E-02 +2.603056E-01 +7.053095E-03 +1.706694E-01 +3.148614E-03 +1.731386E-01 +3.384991E-03 +3.109075E-01 +1.033479E-02 +5.771187E-01 +3.413152E-02 +8.606415E-01 +7.510241E-02 +1.294303E+00 +1.706906E-01 +1.313399E+00 +1.767631E-01 +7.817706E-01 +6.342406E-02 +5.927279E-01 +3.756882E-02 +3.708410E-01 +1.458571E-02 +1.723505E-01 +3.356435E-03 +2.304233E-01 +5.998040E-03 +3.750987E-01 +1.501277E-02 +6.734152E-01 +4.746505E-02 +1.310995E+00 +1.732589E-01 +4.421199E+00 +1.964531E+00 +4.214183E+00 +1.786748E+00 +1.223434E+00 +1.530503E-01 +5.926626E-01 +3.641847E-02 +3.153714E-01 +1.019858E-02 +2.037244E-01 +4.381188E-03 +1.863505E-01 +3.684332E-03 +3.648623E-01 +1.378365E-02 +6.164882E-01 +3.893164E-02 +1.178969E+00 +1.417606E-01 +4.221345E+00 +1.789744E+00 +4.317433E+00 +1.872379E+00 +1.243011E+00 +1.581634E-01 +6.866745E-01 +4.754022E-02 +3.586774E-01 +1.301597E-02 +2.322214E-01 +5.492154E-03 +1.791966E-01 +3.463117E-03 +3.076717E-01 +9.716616E-03 +4.906144E-01 +2.470769E-02 +8.471037E-01 +7.406279E-02 +1.363587E+00 +1.889087E-01 +1.335963E+00 +1.803764E-01 +8.600227E-01 +7.530944E-02 +5.437258E-01 +3.114706E-02 +3.713934E-01 +1.456554E-02 +1.995931E-01 +4.422520E-03 +1.343031E-01 +2.012284E-03 +2.572828E-01 +6.840867E-03 +4.435747E-01 +2.050887E-02 +5.766007E-01 +3.437038E-02 +7.346272E-01 +5.540755E-02 +7.053071E-01 +5.111709E-02 +6.063267E-01 +3.981091E-02 +4.094521E-01 +1.801684E-02 +2.832627E-01 +8.238241E-03 +1.618924E-01 +3.067045E-03 +1.257079E-01 +1.802188E-03 +2.209365E-01 +5.343615E-03 +2.538278E-01 +7.109201E-03 +3.620261E-01 +1.396948E-02 +4.303042E-01 +1.872503E-02 +4.036624E-01 +1.774648E-02 +3.185915E-01 +1.192555E-02 +2.959360E-01 +9.265211E-03 +2.254861E-01 +5.671747E-03 +1.339005E-01 +2.034506E-03 +1.251282E-01 +1.754100E-03 +1.155042E-01 +1.606166E-03 +1.603827E-01 +2.694604E-03 +2.425425E-01 +6.218648E-03 +2.827714E-01 +8.247692E-03 +2.354428E-01 +5.778596E-03 +1.964531E-01 +4.365869E-03 +1.620035E-01 +3.000138E-03 +1.402609E-01 +2.252442E-03 +7.770439E-02 +7.584947E-04 +8.904883E-02 +9.832411E-04 +1.364994E-01 +2.060968E-03 +1.556202E-01 +3.013917E-03 +1.794759E-01 +3.609302E-03 +2.027676E-01 +4.271217E-03 +1.910134E-01 +3.830997E-03 +2.102956E-01 +4.746179E-03 +2.069806E-01 +4.732181E-03 +1.280198E-01 +1.803469E-03 +8.851884E-02 +1.050264E-03 +1.411243E-01 +2.309051E-03 +2.058752E-01 +4.840657E-03 +2.589000E-01 +7.354104E-03 +2.346176E-01 +5.819008E-03 +3.064791E-01 +9.995356E-03 +3.537650E-01 +1.318436E-02 +3.442248E-01 +1.225618E-02 +2.856280E-01 +9.047308E-03 +1.556316E-01 +2.976492E-03 +9.305931E-02 +9.568946E-04 +1.918345E-01 +3.871787E-03 +3.083654E-01 +1.109476E-02 +4.076303E-01 +1.807424E-02 +4.595063E-01 +2.220396E-02 +5.684770E-01 +3.345901E-02 +5.734059E-01 +3.325457E-02 +4.719375E-01 +2.393976E-02 +3.033874E-01 +1.029056E-02 +2.394489E-01 +6.540160E-03 +1.431584E-01 +2.691530E-03 +1.857128E-01 +3.720812E-03 +3.401652E-01 +1.213267E-02 +4.998027E-01 +2.627877E-02 +6.660538E-01 +4.542647E-02 +8.594730E-01 +7.625343E-02 +8.531451E-01 +7.416582E-02 +6.787742E-01 +4.744554E-02 +4.724654E-01 +2.328201E-02 +3.030469E-01 +9.464288E-03 +1.840238E-01 +3.680486E-03 +2.172436E-01 +4.932506E-03 +3.724089E-01 +1.512940E-02 +5.834908E-01 +3.595138E-02 +8.787419E-01 +7.754496E-02 +1.235501E+00 +1.556040E-01 +1.186802E+00 +1.419219E-01 +8.626663E-01 +7.644446E-02 +5.366263E-01 +2.954661E-02 +3.177208E-01 +1.051791E-02 +1.844215E-01 +3.676916E-03 +1.932190E-01 +4.023337E-03 +3.693850E-01 +1.452218E-02 +5.443615E-01 +3.020527E-02 +8.889578E-01 +8.111822E-02 +1.273207E+00 +1.655818E-01 +1.247526E+00 +1.585006E-01 +8.324980E-01 +7.213823E-02 +4.899464E-01 +2.450485E-02 +3.370823E-01 +1.208260E-02 +1.809043E-01 +3.714864E-03 +1.615415E-01 +2.906239E-03 +2.937828E-01 +9.651929E-03 +4.913048E-01 +2.639344E-02 +6.850176E-01 +4.797579E-02 +8.755910E-01 +7.958162E-02 +8.703001E-01 +7.730840E-02 +6.973913E-01 +5.089360E-02 +4.203999E-01 +1.844697E-02 +3.140340E-01 +1.039993E-02 +1.441709E-01 +2.488125E-03 +1.350197E-01 +2.064659E-03 +2.543930E-01 +7.177543E-03 +3.348117E-01 +1.259149E-02 +4.679892E-01 +2.273369E-02 +6.434887E-01 +4.331187E-02 +5.381700E-01 +2.974074E-02 +4.555945E-01 +2.167655E-02 +3.401588E-01 +1.191694E-02 +2.681734E-01 +7.550804E-03 +1.704519E-01 +3.365024E-03 +9.745304E-02 +1.232312E-03 +1.678994E-01 +3.221936E-03 +2.605430E-01 +7.393204E-03 +3.128187E-01 +1.138967E-02 +3.712111E-01 +1.460808E-02 +3.609117E-01 +1.331179E-02 +3.321706E-01 +1.170549E-02 +2.480901E-01 +6.266952E-03 +2.002359E-01 +4.338795E-03 +1.162468E-01 +1.536532E-03 +7.239001E-02 +5.815144E-04 +1.163546E-01 +1.453456E-03 +1.636165E-01 +3.201377E-03 +1.973025E-01 +4.660155E-03 +2.100585E-01 +5.039148E-03 +2.171398E-01 +5.070524E-03 +1.995065E-01 +4.193481E-03 +1.813545E-01 +3.549108E-03 +1.365406E-01 +2.182883E-03 +8.101165E-02 +7.758114E-04 +7.133170E-02 +5.967128E-04 +1.319234E-01 +1.933536E-03 +1.445023E-01 +2.409485E-03 +1.495938E-01 +2.481635E-03 +1.801306E-01 +3.481001E-03 +1.733442E-01 +3.171024E-03 +1.725688E-01 +3.165238E-03 +1.518925E-01 +2.585745E-03 +1.077414E-01 +1.395636E-03 +7.934204E-02 +7.147327E-04 +1.062269E-01 +1.354440E-03 +1.751122E-01 +3.623982E-03 +2.203107E-01 +5.413498E-03 +2.341057E-01 +5.605200E-03 +2.669322E-01 +7.526239E-03 +2.746743E-01 +7.646941E-03 +2.389916E-01 +6.235257E-03 +1.587546E-01 +2.827472E-03 +1.498724E-01 +2.673613E-03 +1.051763E-01 +1.391507E-03 +1.424360E-01 +2.468775E-03 +2.608608E-01 +7.055429E-03 +3.154162E-01 +1.024928E-02 +3.674104E-01 +1.418521E-02 +3.976162E-01 +1.732640E-02 +4.746502E-01 +2.349709E-02 +3.662445E-01 +1.447515E-02 +2.506236E-01 +6.593606E-03 +2.161204E-01 +4.801367E-03 +1.306963E-01 +1.975560E-03 +1.770351E-01 +3.932818E-03 +2.635109E-01 +7.772472E-03 +4.024536E-01 +1.731960E-02 +4.701442E-01 +2.265515E-02 +5.561475E-01 +3.235124E-02 +5.523785E-01 +3.142962E-02 +5.071292E-01 +2.592728E-02 +3.746613E-01 +1.518899E-02 +2.620776E-01 +7.439402E-03 +1.561701E-01 +2.901626E-03 +1.722037E-01 +3.249117E-03 +2.729386E-01 +8.041848E-03 +4.157578E-01 +1.761081E-02 +5.608817E-01 +3.221445E-02 +7.027459E-01 +5.154772E-02 +6.902150E-01 +4.817212E-02 +5.174043E-01 +2.771951E-02 +4.297342E-01 +1.970980E-02 +2.927718E-01 +9.421566E-03 +1.860039E-01 +3.719139E-03 +1.510489E-01 +2.673423E-03 +2.992366E-01 +9.425407E-03 +4.569637E-01 +2.187717E-02 +5.810709E-01 +3.569290E-02 +6.664391E-01 +4.607395E-02 +6.898814E-01 +4.853841E-02 +5.306547E-01 +2.907467E-02 +4.138514E-01 +1.844067E-02 +2.836181E-01 +9.090950E-03 +1.827952E-01 +3.670505E-03 +1.339105E-01 +1.976730E-03 +2.247962E-01 +5.455936E-03 +3.775577E-01 +1.529613E-02 +4.605234E-01 +2.228303E-02 +5.731045E-01 +3.426291E-02 +5.698592E-01 +3.415653E-02 +4.700203E-01 +2.298571E-02 +3.419079E-01 +1.254302E-02 +2.594048E-01 +7.486049E-03 +1.403745E-01 +2.288996E-03 +1.307053E-01 +2.306039E-03 +2.305399E-01 +5.746901E-03 +2.866663E-01 +8.437990E-03 +3.547902E-01 +1.415343E-02 +3.903305E-01 +1.721878E-02 +3.995569E-01 +1.663856E-02 +3.597994E-01 +1.369907E-02 +3.084707E-01 +1.005451E-02 +1.929703E-01 +4.111212E-03 +1.226805E-01 +1.616264E-03 +9.707080E-02 +1.277801E-03 +1.349714E-01 +2.412097E-03 +1.706592E-01 +3.112630E-03 +2.431900E-01 +6.662780E-03 +2.719484E-01 +7.972869E-03 +2.782047E-01 +8.195264E-03 +2.198394E-01 +5.159833E-03 +1.847153E-01 +3.606258E-03 +1.655937E-01 +3.412468E-03 +1.132640E-01 +1.342051E-03 +6.977329E-02 +6.061071E-04 +8.063628E-02 +7.877860E-04 +1.369291E-01 +2.216310E-03 +1.527061E-01 +2.661389E-03 +1.808807E-01 +3.626051E-03 +1.723708E-01 +3.227953E-03 +1.570487E-01 +2.824199E-03 +1.402935E-01 +2.196525E-03 +1.046978E-01 +1.394771E-03 +7.765529E-02 +6.990073E-04 +5.309912E-02 +4.179704E-04 +8.113995E-02 +8.093210E-04 +1.004879E-01 +1.274755E-03 +1.474015E-01 +2.957775E-03 +1.227188E-01 +1.661445E-03 +1.367411E-01 +2.049836E-03 +1.257025E-01 +1.739859E-03 +9.595806E-02 +1.143520E-03 +5.932828E-02 +4.443026E-04 +6.214003E-02 +4.698384E-04 +1.047908E-01 +1.265030E-03 +1.389236E-01 +2.066555E-03 +1.441238E-01 +2.187643E-03 +1.954745E-01 +4.024829E-03 +2.018960E-01 +4.436820E-03 +2.304400E-01 +5.702269E-03 +1.889259E-01 +3.911134E-03 +1.651129E-01 +2.907211E-03 +1.266147E-01 +1.798632E-03 +9.726395E-02 +1.038410E-03 +1.239366E-01 +2.020884E-03 +1.692392E-01 +3.039249E-03 +2.262593E-01 +5.810761E-03 +2.371783E-01 +6.148422E-03 +2.724207E-01 +7.965467E-03 +2.754620E-01 +8.212118E-03 +2.616121E-01 +7.738784E-03 +2.416846E-01 +6.508644E-03 +1.823329E-01 +4.244589E-03 +1.153662E-01 +1.541320E-03 +1.498687E-01 +2.427094E-03 +2.294988E-01 +5.678440E-03 +2.337590E-01 +6.042902E-03 +3.165064E-01 +1.047831E-02 +3.372589E-01 +1.176332E-02 +3.369130E-01 +1.214308E-02 +3.077673E-01 +9.854791E-03 +2.727368E-01 +8.153505E-03 +2.291204E-01 +5.762201E-03 +1.449108E-01 +2.631818E-03 +1.222645E-01 +1.652033E-03 +2.342919E-01 +6.080976E-03 +2.867658E-01 +9.143890E-03 +3.284926E-01 +1.110468E-02 +3.721608E-01 +1.458209E-02 +3.943281E-01 +1.624417E-02 +3.127115E-01 +1.090060E-02 +2.181120E-01 +5.081861E-03 +2.038850E-01 +4.541180E-03 +1.471756E-01 +2.612669E-03 +1.356517E-01 +2.315498E-03 +2.039418E-01 +4.569034E-03 +2.379673E-01 +6.028728E-03 +2.912334E-01 +8.794159E-03 +3.675708E-01 +1.388797E-02 +3.830007E-01 +1.493415E-02 +3.497252E-01 +1.323190E-02 +2.129266E-01 +5.366850E-03 +2.051774E-01 +5.235913E-03 +1.495687E-01 +2.578269E-03 +1.007903E-01 +1.213029E-03 +1.942201E-01 +4.152027E-03 +2.691558E-01 +7.844599E-03 +2.833552E-01 +8.562033E-03 +3.539964E-01 +1.296456E-02 +3.313330E-01 +1.152405E-02 +2.882665E-01 +9.275609E-03 +2.606018E-01 +7.326373E-03 +2.170792E-01 +5.088581E-03 +1.175397E-01 +1.425662E-03 +9.291662E-02 +1.030694E-03 +1.502293E-01 +2.605564E-03 +1.683973E-01 +3.164858E-03 +2.300104E-01 +5.597737E-03 +2.921841E-01 +9.137452E-03 +3.105624E-01 +1.077940E-02 +2.457323E-01 +6.748662E-03 +1.935480E-01 +4.153509E-03 +1.781340E-01 +3.735545E-03 +8.549182E-02 +7.932774E-04 +7.995611E-02 +6.914994E-04 +1.120022E-01 +1.608931E-03 +1.666393E-01 +3.351392E-03 +1.763892E-01 +3.781795E-03 +2.215879E-01 +5.446848E-03 +1.973224E-01 +4.088057E-03 +1.807076E-01 +3.807788E-03 +1.497413E-01 +2.510679E-03 +1.258135E-01 +1.824079E-03 +7.256548E-02 +6.032346E-04 +5.802787E-02 +4.068274E-04 +8.087439E-02 +8.125859E-04 +9.445601E-02 +1.220157E-03 +1.278262E-01 +1.976480E-03 +1.447187E-01 +2.496284E-03 +1.492610E-01 +2.453885E-03 +1.294170E-01 +1.822523E-03 +8.046777E-02 +7.104920E-04 +8.863832E-02 +9.206404E-04 +4.044133E-02 +2.016136E-04 +3.647497E-02 +1.736207E-04 +7.726524E-02 +7.189629E-04 +6.850678E-02 +5.399094E-04 +7.120540E-02 +6.049792E-04 +9.914070E-02 +1.178916E-03 +9.212489E-02 +1.014142E-03 +8.081211E-02 +7.572737E-04 +6.454690E-02 +5.539457E-04 +4.993214E-02 +3.161361E-04 +3.464406E-02 +1.743401E-04 +5.195266E-02 +3.077352E-04 +1.032248E-01 +1.231336E-03 +1.140722E-01 +1.517037E-03 +9.270288E-02 +1.194042E-03 +1.199421E-01 +1.713870E-03 +1.129313E-01 +1.491867E-03 +1.104339E-01 +1.526039E-03 +1.080665E-01 +1.372021E-03 +8.160995E-02 +6.843931E-04 +6.342734E-02 +5.271807E-04 +9.331087E-02 +1.097048E-03 +1.185250E-01 +1.534560E-03 +1.349132E-01 +2.447610E-03 +1.304714E-01 +2.217664E-03 +1.581891E-01 +2.862519E-03 +1.584546E-01 +2.780212E-03 +1.538480E-01 +2.634437E-03 +1.637997E-01 +2.992391E-03 +1.181898E-01 +1.765232E-03 +8.541970E-02 +8.382310E-04 +9.823634E-02 +1.116285E-03 +1.486333E-01 +2.343453E-03 +1.631008E-01 +2.995222E-03 +1.755338E-01 +3.448102E-03 +1.754730E-01 +3.227041E-03 +1.842652E-01 +3.637768E-03 +1.577573E-01 +2.654428E-03 +1.401177E-01 +2.280343E-03 +1.341096E-01 +1.900302E-03 +8.035023E-02 +8.312873E-04 +1.063904E-01 +1.375093E-03 +1.216848E-01 +1.721657E-03 +2.004753E-01 +4.510521E-03 +1.889712E-01 +3.847826E-03 +2.081610E-01 +4.756630E-03 +2.301263E-01 +5.717347E-03 +2.048600E-01 +4.561616E-03 +1.542754E-01 +2.639748E-03 +1.321829E-01 +1.993402E-03 +9.014640E-02 +9.359911E-04 +7.974780E-02 +8.078227E-04 +1.252435E-01 +1.711334E-03 +1.570584E-01 +2.959866E-03 +2.039016E-01 +4.591866E-03 +2.189983E-01 +5.090456E-03 +2.191556E-01 +5.055427E-03 +2.006583E-01 +4.702936E-03 +1.427473E-01 +2.173216E-03 +1.024856E-01 +1.223983E-03 +8.494077E-02 +9.050889E-04 +1.043652E-01 +1.259550E-03 +1.135027E-01 +1.445575E-03 +1.600726E-01 +2.607556E-03 +1.831531E-01 +4.043413E-03 +2.007142E-01 +4.477475E-03 +1.767643E-01 +3.298936E-03 +1.522826E-01 +2.841107E-03 +1.288167E-01 +1.944141E-03 +1.129177E-01 +1.466746E-03 +9.166114E-02 +1.059245E-03 +7.278205E-02 +7.174163E-04 +1.368554E-01 +2.140442E-03 +1.576875E-01 +2.802493E-03 +1.490721E-01 +2.494952E-03 +2.062740E-01 +4.926381E-03 +1.707643E-01 +3.221954E-03 +1.793503E-01 +3.661578E-03 +1.255583E-01 +1.994441E-03 +1.011375E-01 +1.127338E-03 +5.944771E-02 +5.079367E-04 +6.143141E-02 +4.850205E-04 +8.747215E-02 +9.029610E-04 +1.135806E-01 +1.572457E-03 +1.258766E-01 +1.776739E-03 +1.460430E-01 +2.470050E-03 +1.449479E-01 +2.231440E-03 +1.295714E-01 +1.929423E-03 +1.137994E-01 +1.612784E-03 +8.730775E-02 +8.683726E-04 +6.186674E-02 +4.521535E-04 +4.404648E-02 +3.596329E-04 +6.609800E-02 +5.725272E-04 +8.204018E-02 +7.710094E-04 +9.063221E-02 +1.005713E-03 +9.594152E-02 +1.071929E-03 +8.648906E-02 +9.624176E-04 +6.818770E-02 +5.453348E-04 +5.887333E-02 +4.783382E-04 +6.201530E-02 +4.304358E-04 +4.838730E-02 +3.281581E-04 +tally 2: +2.393627E-03 +2.636290E-06 +2.222156E-03 +1.516148E-06 +2.867439E-03 +2.178580E-06 +7.923009E-03 +1.131939E-05 +3.986634E-03 +4.120137E-06 +7.826419E-03 +1.381669E-05 +6.138176E-03 +7.147428E-06 +3.876880E-03 +2.697208E-06 +2.980562E-03 +3.407321E-06 +1.774473E-03 +8.936196E-07 +2.805366E-03 +2.770194E-06 +3.942385E-03 +3.541964E-06 +4.287920E-03 +3.508749E-06 +7.477034E-03 +1.023581E-05 +1.829256E-03 +9.746709E-07 +5.062973E-03 +5.540060E-06 +4.594275E-03 +5.704022E-06 +3.405515E-03 +3.312460E-06 +9.423220E-03 +1.189576E-05 +1.066888E-02 +2.047020E-05 +7.596120E-03 +1.097485E-05 +5.727684E-03 +9.708804E-06 +4.299383E-03 +3.708395E-06 +9.513211E-03 +1.464618E-05 +5.378401E-03 +5.129879E-06 +5.096252E-03 +3.430859E-06 +7.146855E-03 +1.124612E-05 +6.572738E-03 +7.596525E-06 +7.380131E-03 +9.633384E-06 +6.219137E-03 +8.163623E-06 +6.908868E-03 +8.615668E-06 +7.350963E-03 +1.116403E-05 +5.438361E-03 +6.022683E-06 +4.233493E-03 +5.102016E-06 +9.383252E-03 +1.536263E-05 +1.199002E-02 +2.034238E-05 +7.934135E-03 +8.959239E-06 +8.511914E-03 +1.022394E-05 +6.162682E-03 +4.504202E-06 +6.648149E-03 +5.723838E-06 +7.264317E-03 +8.981506E-06 +1.037779E-02 +1.703942E-05 +4.759363E-03 +3.403173E-06 +9.522407E-03 +1.428157E-05 +7.387030E-03 +1.550312E-05 +4.844392E-03 +8.366311E-06 +6.843631E-03 +8.685895E-06 +7.764489E-03 +8.325268E-06 +5.854513E-03 +5.702341E-06 +7.087671E-03 +1.025951E-05 +2.415844E-03 +2.739481E-06 +3.086207E-03 +1.914733E-06 +3.654957E-03 +3.442162E-06 +4.643653E-03 +7.197439E-06 +1.156734E-02 +1.759634E-05 +7.348653E-03 +9.450024E-06 +7.852217E-03 +9.889996E-06 +4.188787E-03 +2.746400E-06 +4.526053E-03 +3.421811E-06 +7.133876E-03 +5.514540E-06 +7.642743E-03 +1.296144E-05 +3.436567E-03 +5.211995E-06 +2.358938E-03 +1.100467E-06 +4.225043E-03 +3.484328E-06 +6.975938E-03 +1.402542E-05 +2.948552E-03 +2.413285E-06 +7.430097E-03 +9.911242E-06 +9.344383E-03 +1.730038E-05 +5.155130E-03 +4.067305E-06 +9.223392E-03 +1.460017E-05 +6.706254E-03 +1.105767E-05 +6.585388E-03 +9.369522E-06 +5.779745E-03 +9.335364E-06 +8.502853E-03 +1.535431E-05 +3.196086E-03 +2.721454E-06 +4.062636E-03 +4.530161E-06 +4.949408E-03 +4.754719E-06 +8.697214E-03 +1.269695E-05 +7.720575E-03 +1.111572E-05 +9.096811E-03 +1.174536E-05 +8.395332E-03 +1.344990E-05 +4.327467E-03 +4.178301E-06 +8.098133E-03 +2.129072E-05 +8.641159E-03 +1.993637E-05 +4.910339E-03 +4.798040E-06 +9.222729E-03 +1.731644E-05 +2.362293E-03 +1.920887E-06 +6.474215E-03 +7.989801E-06 +5.093903E-03 +4.638782E-06 +5.190870E-03 +4.064962E-06 +9.156062E-03 +1.062935E-05 +8.084833E-03 +1.278518E-05 +6.006837E-03 +5.037849E-06 +2.770574E-03 +1.880169E-06 +8.452309E-03 +1.160057E-05 +3.397900E-03 +2.727237E-06 +2.289237E-03 +1.800828E-06 +4.695731E-03 +3.765699E-06 +4.924545E-03 +5.339278E-06 +3.924491E-03 +3.534032E-06 +5.847744E-03 +5.832921E-06 +5.289218E-03 +4.574845E-06 +6.846305E-03 +7.758157E-06 +1.047199E-02 +2.215876E-05 +4.108674E-03 +4.661482E-06 +3.645438E-03 +3.482466E-06 +7.403892E-03 +9.076272E-06 +9.992980E-03 +1.850054E-05 +5.443023E-03 +6.695689E-06 +3.847833E-03 +4.206098E-06 +2.277807E-03 +2.917797E-06 +3.224646E-03 +2.590833E-06 +2.712146E-03 +1.564363E-06 +2.511703E-03 +2.073210E-06 +2.851624E-03 +2.406321E-06 +6.419364E-03 +8.208048E-06 +3.583974E-03 +2.129485E-06 +4.071264E-03 +3.984855E-06 +4.533579E-03 +3.713304E-06 +4.578848E-03 +5.079242E-06 +5.611098E-03 +6.817450E-06 +5.466353E-03 +4.988832E-06 +6.854470E-03 +7.459449E-06 +1.157268E-02 +2.134366E-05 +7.273077E-03 +9.732982E-06 +8.349702E-03 +1.250149E-05 +5.050822E-03 +6.018695E-06 +2.514025E-03 +1.130420E-06 +3.427587E-03 +3.225038E-06 +3.873162E-03 +2.996903E-06 +7.323374E-03 +8.254236E-06 +6.098103E-03 +7.253404E-06 +6.739636E-03 +8.349945E-06 +9.485072E-03 +1.713563E-05 +5.984992E-03 +9.163531E-06 +8.834991E-03 +1.335810E-05 +4.066934E-03 +3.579803E-06 +1.652658E-02 +4.834880E-05 +7.000637E-03 +1.069231E-05 +7.937972E-03 +1.290117E-05 +3.766475E-03 +2.867345E-06 +2.461271E-03 +1.788656E-06 +7.788544E-03 +1.121555E-05 +9.541095E-03 +2.231145E-05 +7.679962E-03 +9.840343E-06 +5.742139E-03 +4.940156E-06 +5.062263E-03 +4.779159E-06 +1.289208E-02 +2.955604E-05 +1.544740E-02 +3.866639E-05 +1.954402E-02 +4.721734E-05 +9.149250E-03 +1.133509E-05 +1.090073E-02 +2.153530E-05 +4.758115E-03 +3.459784E-06 +6.236554E-03 +7.454691E-06 +1.032788E-02 +1.596371E-05 +1.444275E-02 +3.574908E-05 +6.464816E-03 +6.384836E-06 +8.737589E-03 +1.139821E-05 +1.522241E-02 +3.688054E-05 +1.106278E-02 +2.001640E-05 +1.657751E-03 +7.896422E-07 +9.985083E-03 +2.005574E-05 +1.652296E-02 +4.365058E-05 +1.302377E-02 +2.178742E-05 +9.435666E-03 +1.687352E-05 +6.711506E-03 +6.885294E-06 +1.142166E-02 +1.609449E-05 +1.419856E-02 +2.849773E-05 +8.442366E-03 +1.011801E-05 +1.071637E-02 +1.610076E-05 +4.476911E-03 +3.961715E-06 +7.809454E-03 +1.419144E-05 +1.181657E-02 +2.104822E-05 +1.373873E-02 +2.251824E-05 +8.797909E-03 +9.748724E-06 +1.504789E-02 +4.195617E-05 +7.006137E-03 +6.669697E-06 +9.537389E-03 +1.849189E-05 +1.780900E-02 +4.302041E-05 +1.724591E-02 +3.993250E-05 +9.881865E-03 +1.435848E-05 +1.212976E-02 +2.281306E-05 +1.155598E-02 +2.437179E-05 +1.323280E-02 +2.884432E-05 +8.626223E-03 +1.632385E-05 +8.459408E-03 +1.577691E-05 +5.796477E-03 +8.302775E-06 +7.329870E-03 +9.181815E-06 +5.899442E-03 +9.585863E-06 +3.270135E-03 +2.283602E-06 +1.256169E-02 +2.107461E-05 +1.234423E-02 +1.770300E-05 +7.478528E-03 +9.995232E-06 +9.809248E-03 +1.705587E-05 +1.508701E-02 +4.933892E-05 +9.484511E-03 +1.383716E-05 +9.906783E-03 +1.637085E-05 +1.682365E-02 +3.925758E-05 +1.258622E-02 +2.571505E-05 +1.501752E-02 +3.834255E-05 +8.820664E-03 +1.146570E-05 +9.142316E-03 +1.367354E-05 +1.607994E-02 +3.440957E-05 +1.819921E-02 +4.213322E-05 +1.049376E-02 +1.508696E-05 +1.125487E-02 +1.829361E-05 +1.255946E-02 +2.400912E-05 +1.494753E-02 +2.880665E-05 +9.906163E-03 +1.714469E-05 +9.801065E-03 +1.600484E-05 +9.144471E-03 +1.267827E-05 +9.284445E-03 +1.370415E-05 +7.423687E-03 +7.432654E-06 +5.839529E-03 +7.346711E-06 +1.203215E-02 +1.827698E-05 +1.168395E-02 +2.279351E-05 +8.086186E-03 +1.615505E-05 +7.899387E-03 +1.190799E-05 +1.297481E-02 +2.625448E-05 +1.012733E-02 +1.604797E-05 +7.655395E-03 +8.264047E-06 +6.482761E-03 +7.546581E-06 +9.071892E-03 +1.344566E-05 +1.012199E-02 +1.652283E-05 +9.504897E-03 +1.476924E-05 +5.662581E-03 +5.323904E-06 +7.382282E-03 +1.000786E-05 +6.180783E-03 +7.844120E-06 +2.197420E-03 +1.391522E-06 +6.007425E-03 +7.959122E-06 +7.715644E-03 +1.608319E-05 +5.247749E-03 +7.416762E-06 +1.694277E-03 +6.578326E-07 +5.339576E-03 +5.097832E-06 +6.019786E-03 +5.618274E-06 +4.786336E-03 +7.186037E-06 +6.122950E-03 +5.610674E-06 +8.057029E-03 +1.204366E-05 +6.301473E-03 +6.965375E-06 +4.120695E-03 +3.695383E-06 +5.874479E-03 +6.599197E-06 +6.691277E-03 +7.819406E-06 +5.109849E-03 +6.563614E-06 +8.391296E-03 +9.940452E-06 +5.839507E-03 +5.521558E-06 +4.596793E-03 +4.130860E-06 +5.374245E-03 +1.030905E-05 +1.632711E-03 +8.301397E-07 +3.126223E-03 +2.656593E-06 +3.937711E-03 +3.000478E-06 +1.156184E-02 +2.627381E-05 +5.611109E-03 +6.000471E-06 +6.252306E-03 +8.525688E-06 +9.821256E-03 +2.080867E-05 +6.202478E-03 +9.705719E-06 +9.744072E-03 +1.419879E-05 +4.563774E-03 +5.256907E-06 +8.587477E-03 +1.097640E-05 +7.671018E-03 +1.047414E-05 +7.311535E-03 +8.520205E-06 +5.701036E-03 +7.538301E-06 +2.627195E-03 +1.584039E-06 +9.969461E-03 +1.489942E-05 +7.095469E-03 +8.576195E-06 +1.168498E-02 +2.716853E-05 +1.070319E-02 +2.148367E-05 +1.016441E-02 +1.786630E-05 +1.292596E-02 +2.389182E-05 +1.217737E-02 +2.769412E-05 +1.181009E-02 +2.340802E-05 +1.574105E-02 +3.124980E-05 +1.232805E-02 +2.754960E-05 +1.188839E-02 +2.281613E-05 +6.603428E-03 +7.994872E-06 +9.606012E-03 +1.590439E-05 +1.440947E-02 +3.393244E-05 +1.302185E-02 +2.781063E-05 +1.299900E-02 +2.077190E-05 +9.475720E-03 +1.345778E-05 +1.146355E-02 +2.243784E-05 +1.349840E-02 +2.573754E-05 +7.739444E-03 +8.409802E-06 +1.466716E-02 +2.433264E-05 +1.806287E-02 +4.053139E-05 +8.810509E-03 +1.132204E-05 +1.024195E-02 +1.779935E-05 +2.025420E-02 +5.383414E-05 +1.707065E-02 +3.895805E-05 +1.038874E-02 +1.447558E-05 +1.204454E-02 +2.594328E-05 +1.354337E-02 +2.168067E-05 +1.483635E-02 +2.755558E-05 +1.192445E-02 +3.329659E-05 +2.158708E-02 +6.668840E-05 +1.234119E-02 +2.669020E-05 +1.410581E-02 +3.302957E-05 +8.354805E-03 +9.152126E-06 +9.135582E-03 +1.272798E-05 +1.639890E-02 +3.260235E-05 +1.941356E-02 +4.768472E-05 +9.432927E-03 +1.518984E-05 +8.177517E-03 +1.165366E-05 +9.416129E-03 +1.296249E-05 +8.128386E-03 +8.608672E-06 +1.105831E-02 +1.814734E-05 +1.401062E-02 +3.340952E-05 +1.142672E-02 +2.129460E-05 +9.161476E-03 +1.306319E-05 +9.794446E-03 +1.416201E-05 +9.135097E-03 +1.706236E-05 +1.853399E-02 +3.920131E-05 +1.227701E-02 +2.106422E-05 +1.056602E-02 +2.102108E-05 +8.267866E-03 +1.184427E-05 +1.303652E-02 +3.007847E-05 +1.109107E-02 +1.508434E-05 +1.255273E-02 +3.715445E-05 +1.568071E-02 +3.587957E-05 +1.697298E-02 +4.299097E-05 +2.038316E-02 +6.095075E-05 +1.285306E-02 +2.307142E-05 +1.201762E-02 +3.129200E-05 +1.499546E-02 +3.208959E-05 +2.043263E-02 +5.689094E-05 +1.189038E-02 +2.042718E-05 +1.950482E-02 +5.269872E-05 +1.134487E-02 +2.521302E-05 +1.878263E-02 +4.929885E-05 +1.873654E-02 +5.934321E-05 +1.419859E-02 +2.646755E-05 +1.651980E-02 +4.148598E-05 +1.314908E-02 +2.182046E-05 +1.021903E-02 +1.717431E-05 +1.208532E-02 +2.496385E-05 +1.982124E-02 +4.519007E-05 +2.237475E-02 +7.384327E-05 +1.168783E-02 +2.197925E-05 +1.121917E-02 +1.848105E-05 +1.176886E-02 +1.989856E-05 +1.028612E-02 +2.002048E-05 +6.441121E-03 +1.208678E-05 +9.334858E-03 +1.685718E-05 +1.221526E-02 +2.734816E-05 +8.109247E-03 +1.518336E-05 +8.368313E-03 +1.063729E-05 +8.855930E-03 +1.170749E-05 +1.172890E-02 +1.956774E-05 +9.863812E-03 +1.315788E-05 +5.592525E-03 +6.344568E-06 +8.987555E-03 +2.234382E-05 +3.266822E-03 +2.479505E-06 +6.189326E-03 +8.824564E-06 +5.844977E-03 +5.169490E-06 +7.046630E-03 +1.052376E-05 +6.579857E-03 +8.415446E-06 +1.093757E-02 +1.570418E-05 +1.534199E-03 +4.843955E-07 +3.972367E-03 +3.930212E-06 +9.061215E-03 +1.261741E-05 +8.800538E-03 +1.921110E-05 +3.225443E-03 +3.493463E-06 +5.742921E-03 +7.524467E-06 +8.894549E-03 +9.527470E-06 +1.014672E-02 +2.120305E-05 +5.364672E-03 +6.378322E-06 +1.066153E-02 +1.712472E-05 +6.130226E-03 +6.243703E-06 +4.018022E-03 +2.930167E-06 +4.956188E-03 +4.356249E-06 +6.252583E-03 +6.885470E-06 +8.007253E-03 +8.821722E-06 +6.639119E-03 +8.933356E-06 +1.463344E-02 +3.442332E-05 +1.038024E-02 +1.880148E-05 +1.206043E-02 +2.558498E-05 +4.570005E-03 +3.726957E-06 +1.242332E-02 +2.230997E-05 +1.977578E-02 +4.435986E-05 +1.061292E-02 +2.445701E-05 +1.424423E-02 +3.432092E-05 +9.396166E-03 +1.401917E-05 +1.392713E-02 +2.180224E-05 +1.424206E-02 +2.481086E-05 +1.709208E-02 +4.686642E-05 +1.878028E-02 +4.097819E-05 +1.586170E-02 +3.899306E-05 +1.186469E-02 +2.666019E-05 +1.771802E-02 +4.244451E-05 +2.012793E-02 +4.893656E-05 +1.650347E-02 +3.934790E-05 +1.148512E-02 +1.454575E-05 +1.749383E-02 +5.245021E-05 +1.225617E-02 +3.059339E-05 +1.346221E-02 +2.189743E-05 +2.304004E-02 +5.757458E-05 +2.222990E-02 +5.924120E-05 +1.952055E-02 +4.455112E-05 +2.382543E-02 +8.732633E-05 +1.530886E-02 +4.091608E-05 +1.339459E-02 +2.841021E-05 +1.625542E-02 +3.786269E-05 +2.338447E-02 +6.870429E-05 +1.490538E-02 +3.792400E-05 +1.790848E-02 +4.535348E-05 +1.122685E-02 +2.253480E-05 +1.330235E-02 +2.292380E-05 +2.135308E-02 +5.586248E-05 +1.695542E-02 +3.629907E-05 +1.155426E-02 +1.914452E-05 +1.571691E-02 +3.489736E-05 +1.572803E-02 +4.611373E-05 +1.284552E-02 +2.456383E-05 +1.901269E-02 +4.808607E-05 +2.485036E-02 +8.880235E-05 +1.465112E-02 +3.185430E-05 +2.020800E-02 +4.881856E-05 +1.401589E-02 +2.430294E-05 +9.002706E-03 +1.229314E-05 +1.992235E-02 +4.240852E-05 +2.006701E-02 +4.842321E-05 +1.641971E-02 +4.817406E-05 +1.595751E-02 +4.338042E-05 +1.853727E-02 +4.393578E-05 +2.192942E-02 +6.739913E-05 +1.867919E-02 +5.139172E-05 +2.177355E-02 +5.751645E-05 +1.184805E-02 +2.240654E-05 +2.099274E-02 +5.999346E-05 +1.322643E-02 +2.131002E-05 +1.656305E-02 +4.169252E-05 +2.381731E-02 +9.074804E-05 +2.704019E-02 +1.044920E-04 +1.801171E-02 +4.035920E-05 +1.967092E-02 +5.363932E-05 +1.168953E-02 +1.754128E-05 +1.832249E-02 +3.962019E-05 +1.704595E-02 +3.468261E-05 +1.265896E-02 +2.389931E-05 +1.393723E-02 +3.209713E-05 +1.201908E-02 +2.196652E-05 +1.121588E-02 +1.970440E-05 +1.427491E-02 +2.765834E-05 +2.153384E-02 +5.860763E-05 +1.776842E-02 +3.609550E-05 +7.672472E-03 +1.269710E-05 +1.265904E-02 +2.534380E-05 +1.278354E-02 +2.508897E-05 +1.391779E-02 +4.666810E-05 +2.101476E-02 +6.314023E-05 +1.153450E-02 +1.634642E-05 +7.257174E-03 +7.518882E-06 +1.927707E-02 +5.477085E-05 +9.781524E-03 +2.152387E-05 +9.945925E-03 +2.025565E-05 +1.389600E-02 +2.298270E-05 +1.494296E-02 +3.352071E-05 +1.367151E-02 +2.896436E-05 +1.028864E-02 +1.588654E-05 +1.473101E-02 +2.707095E-05 +1.455944E-02 +2.781560E-05 +9.476864E-03 +1.561347E-05 +1.102794E-02 +1.772767E-05 +9.572498E-03 +1.064449E-05 +1.064989E-02 +1.750406E-05 +6.954816E-03 +6.367916E-06 +7.557762E-03 +9.032801E-06 +1.211805E-02 +1.920718E-05 +1.845178E-02 +5.873218E-05 +7.793790E-03 +1.112683E-05 +5.371627E-03 +5.960823E-06 +1.235046E-02 +2.103259E-05 +9.750089E-03 +1.543672E-05 +8.995748E-03 +1.080595E-05 +5.259436E-03 +1.260414E-05 +4.013446E-03 +6.247425E-06 +8.493091E-03 +1.154191E-05 +8.658736E-03 +1.173196E-05 +5.707568E-03 +4.449143E-06 +6.897118E-03 +1.114446E-05 +1.178625E-02 +1.974305E-05 +9.315402E-03 +1.290580E-05 +8.406166E-03 +1.025434E-05 +9.901055E-03 +1.667960E-05 +1.146925E-02 +2.215717E-05 +5.969641E-03 +6.447141E-06 +5.949865E-03 +8.960001E-06 +6.092588E-03 +5.866966E-06 +5.286804E-03 +4.484612E-06 +4.962451E-03 +8.039594E-06 +9.068920E-03 +1.020218E-05 +8.393955E-03 +1.320876E-05 +9.622928E-03 +1.423650E-05 +8.529527E-03 +9.768501E-06 +1.200903E-02 +2.384159E-05 +1.259390E-02 +2.566463E-05 +1.039659E-02 +1.406860E-05 +1.729423E-02 +3.541882E-05 +1.557253E-02 +3.014897E-05 +1.194539E-02 +2.560525E-05 +9.677750E-03 +1.383701E-05 +1.167374E-02 +1.893076E-05 +1.273338E-02 +2.292756E-05 +1.535190E-02 +3.729267E-05 +1.508233E-02 +2.812628E-05 +1.684483E-02 +3.431291E-05 +2.196642E-02 +6.517979E-05 +1.835655E-02 +4.270904E-05 +1.427403E-02 +2.810685E-05 +1.296891E-02 +3.425248E-05 +1.678523E-02 +5.402550E-05 +1.824967E-02 +5.634714E-05 +1.959838E-02 +4.878209E-05 +1.406357E-02 +2.175952E-05 +1.401524E-02 +2.275436E-05 +1.788740E-02 +3.919852E-05 +1.598923E-02 +2.974737E-05 +1.525101E-02 +3.383079E-05 +2.077298E-02 +5.733559E-05 +1.623945E-02 +5.546589E-05 +1.233338E-02 +2.483742E-05 +2.022717E-02 +5.714772E-05 +2.102155E-02 +5.635658E-05 +2.171802E-02 +5.725283E-05 +2.133014E-02 +5.962681E-05 +1.179614E-02 +2.066294E-05 +1.970629E-02 +4.561315E-05 +2.645275E-02 +9.399736E-05 +2.354050E-02 +6.803919E-05 +1.525552E-02 +2.858970E-05 +2.070256E-02 +5.101418E-05 +1.947053E-02 +4.695688E-05 +2.302697E-02 +7.365548E-05 +1.913354E-02 +4.496174E-05 +2.105937E-02 +5.760147E-05 +1.965231E-02 +4.417453E-05 +1.995841E-02 +5.444455E-05 +1.084572E-02 +1.610270E-05 +1.332954E-02 +2.257737E-05 +2.183162E-02 +5.722081E-05 +2.309396E-02 +6.057606E-05 +9.499018E-03 +1.386623E-05 +1.726231E-02 +3.538973E-05 +1.918548E-02 +5.089001E-05 +1.973649E-02 +5.391374E-05 +1.451999E-02 +3.154997E-05 +1.853969E-02 +4.789122E-05 +1.931149E-02 +4.543759E-05 +1.524463E-02 +3.367646E-05 +1.366351E-02 +2.193771E-05 +1.277601E-02 +2.556554E-05 +2.419813E-02 +6.652057E-05 +2.472332E-02 +7.514840E-05 +1.216343E-02 +1.994778E-05 +1.684175E-02 +4.956582E-05 +1.339179E-02 +2.283730E-05 +1.780869E-02 +4.714950E-05 +1.281070E-02 +3.243018E-05 +1.377308E-02 +3.117101E-05 +5.215885E-03 +4.980057E-06 +8.389167E-03 +9.063809E-06 +9.223056E-03 +1.174158E-05 +1.034179E-02 +1.248975E-05 +1.925913E-02 +6.207101E-05 +1.950035E-02 +4.864558E-05 +7.340878E-03 +8.419462E-06 +1.607559E-02 +3.378180E-05 +1.350363E-02 +2.299601E-05 +1.775362E-02 +4.047509E-05 +9.317817E-03 +1.104227E-05 +1.531705E-02 +4.269706E-05 +1.565342E-02 +3.305222E-05 +1.391485E-02 +2.938257E-05 +1.313236E-02 +2.426377E-05 +1.070285E-02 +1.778239E-05 +1.570769E-02 +2.778648E-05 +1.722250E-02 +3.454670E-05 +1.045335E-02 +1.595923E-05 +9.750797E-03 +1.489157E-05 +8.756572E-03 +1.522794E-05 +1.314662E-02 +2.457130E-05 +1.370416E-02 +3.418084E-05 +1.098248E-02 +2.064375E-05 +9.200090E-03 +1.182484E-05 +1.567874E-02 +3.315221E-05 +6.763240E-03 +8.877038E-06 +8.410342E-03 +8.599497E-06 +1.335894E-02 +2.549323E-05 +1.565848E-02 +3.152726E-05 +4.913273E-03 +5.986876E-06 +9.624242E-03 +1.314215E-05 +7.547191E-03 +9.843029E-06 +9.081341E-03 +1.527721E-05 +5.698591E-03 +6.688189E-06 +9.964477E-03 +1.260472E-05 +9.144787E-03 +1.380216E-05 +2.922066E-03 +3.175247E-06 +6.106620E-03 +6.365824E-06 +4.141014E-03 +5.277155E-06 +1.500883E-02 +2.794044E-05 +1.313811E-02 +2.817445E-05 +5.537395E-03 +6.121500E-06 +6.214355E-03 +7.107250E-06 +9.970886E-03 +1.328943E-05 +1.158117E-02 +2.364707E-05 +8.759169E-03 +1.211573E-05 +1.307338E-02 +2.576745E-05 +6.194517E-03 +9.257741E-06 +8.087970E-03 +1.366458E-05 +8.727779E-03 +1.125895E-05 +7.481614E-03 +9.784879E-06 +7.811272E-03 +1.168412E-05 +7.288542E-03 +8.415727E-06 +1.395237E-02 +3.211289E-05 +1.345304E-02 +2.404425E-05 +1.075854E-02 +1.527000E-05 +9.524531E-03 +1.516407E-05 +1.703097E-02 +3.823359E-05 +1.787871E-02 +5.611642E-05 +1.180236E-02 +1.719343E-05 +1.146997E-02 +2.095613E-05 +1.152446E-02 +1.653464E-05 +1.398187E-02 +2.396242E-05 +1.526339E-02 +3.893414E-05 +1.206190E-02 +2.128747E-05 +1.578188E-02 +3.704679E-05 +1.775426E-02 +3.663474E-05 +1.962916E-02 +5.493244E-05 +1.511991E-02 +3.404611E-05 +1.133202E-02 +2.452193E-05 +1.623663E-02 +3.459453E-05 +1.586922E-02 +3.841963E-05 +1.786175E-02 +4.289114E-05 +1.326353E-02 +2.595816E-05 +1.445145E-02 +2.990583E-05 +1.509105E-02 +2.887493E-05 +1.761108E-02 +3.799916E-05 +1.671644E-02 +3.638132E-05 +1.692226E-02 +3.667379E-05 +1.123264E-02 +2.662808E-05 +1.119900E-02 +1.598286E-05 +1.930512E-02 +4.893797E-05 +2.291023E-02 +7.500981E-05 +1.093046E-02 +2.227226E-05 +2.121672E-02 +7.861749E-05 +9.618950E-03 +1.801199E-05 +1.213716E-02 +2.201469E-05 +1.856853E-02 +4.365656E-05 +1.665627E-02 +3.787320E-05 +1.301603E-02 +3.128189E-05 +1.971201E-02 +6.183556E-05 +2.240750E-02 +7.011853E-05 +2.216291E-02 +6.809313E-05 +1.153008E-02 +2.676316E-05 +1.676451E-02 +4.351892E-05 +2.591571E-02 +8.037903E-05 +2.037389E-02 +4.959375E-05 +1.495140E-02 +2.829832E-05 +1.051363E-02 +2.065167E-05 +1.979307E-02 +5.604015E-05 +2.624329E-02 +8.019430E-05 +1.335982E-02 +2.844614E-05 +1.612983E-02 +6.010017E-05 +1.728825E-02 +4.711910E-05 +2.429057E-02 +7.415431E-05 +1.616100E-02 +3.084388E-05 +1.338558E-02 +3.228322E-05 +1.340928E-02 +3.387569E-05 +1.708924E-02 +4.087477E-05 +1.336049E-02 +2.477778E-05 +1.587999E-02 +3.626669E-05 +1.935273E-02 +4.723278E-05 +2.470520E-02 +7.859676E-05 +1.475079E-02 +3.640394E-05 +1.679996E-02 +3.695619E-05 +1.042709E-02 +1.967458E-05 +1.968690E-02 +5.949834E-05 +1.327946E-02 +2.828789E-05 +2.199912E-02 +6.466489E-05 +1.849493E-02 +3.808605E-05 +1.601814E-02 +3.868414E-05 +8.360208E-03 +8.722194E-06 +1.048244E-02 +1.553938E-05 +1.355191E-02 +3.191766E-05 +2.019710E-02 +5.689596E-05 +1.515848E-02 +3.149152E-05 +2.234350E-02 +6.679195E-05 +2.213825E-02 +7.381934E-05 +1.917888E-02 +4.731955E-05 +1.084756E-02 +1.986509E-05 +1.609220E-02 +3.078859E-05 +1.473280E-02 +3.933279E-05 +1.529880E-02 +3.127194E-05 +1.639564E-02 +4.529775E-05 +1.443123E-02 +3.075459E-05 +1.882187E-02 +5.273612E-05 +1.460498E-02 +3.301670E-05 +1.236974E-02 +2.302425E-05 +1.547979E-02 +5.040930E-05 +8.943072E-03 +1.146125E-05 +1.038577E-02 +2.359524E-05 +9.957494E-03 +1.246302E-05 +8.165810E-03 +1.286712E-05 +9.730475E-03 +1.696051E-05 +1.144342E-02 +1.696256E-05 +1.018757E-02 +1.502940E-05 +6.455273E-03 +6.892868E-06 +1.173241E-02 +1.925350E-05 +1.116334E-02 +1.482619E-05 +5.399877E-03 +4.405606E-06 +3.959202E-03 +4.471062E-06 +9.736729E-03 +1.616042E-05 +4.414460E-03 +5.308331E-06 +5.659090E-03 +4.225962E-06 +4.260578E-03 +3.519428E-06 +1.063057E-02 +2.671737E-05 +9.252412E-03 +1.335948E-05 +7.509662E-03 +1.033233E-05 +5.631650E-03 +4.603917E-06 +7.374915E-03 +9.613999E-06 +1.017301E-02 +1.890382E-05 +4.657208E-03 +4.110749E-06 +8.263045E-03 +9.144029E-06 +5.083557E-03 +3.617645E-06 +5.753770E-03 +6.399330E-06 +3.157208E-03 +2.023717E-06 +2.929392E-03 +1.415512E-06 +3.306531E-03 +3.326325E-06 +7.308585E-03 +7.051788E-06 +2.131441E-03 +3.159885E-06 +6.056253E-03 +6.146480E-06 +3.197345E-03 +1.906328E-06 +7.156591E-03 +8.158604E-06 +1.008394E-02 +1.612226E-05 +1.360120E-02 +3.007127E-05 +1.087460E-02 +1.978085E-05 +8.751267E-03 +1.202395E-05 +1.327913E-02 +2.254308E-05 +1.549315E-02 +3.493369E-05 +1.276663E-02 +2.254426E-05 +1.422943E-02 +3.266120E-05 +7.543284E-03 +8.425611E-06 +1.148895E-02 +2.316672E-05 +1.075957E-02 +1.733122E-05 +1.228568E-02 +2.274310E-05 +1.298949E-02 +3.103013E-05 +1.687551E-02 +3.373288E-05 +1.174671E-02 +1.478816E-05 +1.298113E-02 +2.280689E-05 +1.375075E-02 +3.564635E-05 +1.865407E-02 +4.650386E-05 +1.316565E-02 +3.034949E-05 +1.644195E-02 +3.039939E-05 +1.167304E-02 +1.910205E-05 +1.119646E-02 +2.041134E-05 +2.051982E-02 +5.295597E-05 +1.446398E-02 +2.483661E-05 +1.663221E-02 +4.310298E-05 +1.774865E-02 +3.613160E-05 +1.551828E-02 +3.922463E-05 +1.987068E-02 +5.088653E-05 +1.111420E-02 +2.006407E-05 +1.756540E-02 +4.468660E-05 +1.151848E-02 +1.953188E-05 +1.430522E-02 +3.322674E-05 +8.678157E-03 +1.516243E-05 +1.189921E-02 +1.954174E-05 +1.667314E-02 +5.548567E-05 +2.197194E-02 +6.943126E-05 +2.047457E-02 +4.730016E-05 +2.145796E-02 +5.503501E-05 +1.433861E-02 +3.407856E-05 +1.789249E-02 +4.132722E-05 +1.497597E-02 +3.790603E-05 +1.784518E-02 +5.989398E-05 +1.348223E-02 +2.451114E-05 +1.850761E-02 +4.354345E-05 +9.460668E-03 +1.235477E-05 +1.608153E-02 +3.627464E-05 +2.158938E-02 +7.192126E-05 +2.591114E-02 +7.881538E-05 +1.615323E-02 +3.735540E-05 +1.456875E-02 +2.959443E-05 +1.713879E-02 +3.971707E-05 +2.011125E-02 +5.426015E-05 +1.600843E-02 +3.860238E-05 +2.349989E-02 +6.721393E-05 +9.675390E-03 +1.720621E-05 +1.321534E-02 +2.201319E-05 +1.388877E-02 +3.752647E-05 +9.338560E-03 +1.222660E-05 +1.872993E-02 +4.179060E-05 +1.729197E-02 +4.763909E-05 +1.433923E-02 +3.648874E-05 +1.982945E-02 +5.208569E-05 +9.529878E-03 +1.355652E-05 +1.902053E-02 +4.097824E-05 +9.167842E-03 +1.041942E-05 +1.571952E-02 +4.188405E-05 +9.716564E-03 +2.414735E-05 +1.423573E-02 +3.524484E-05 +1.148788E-02 +2.604718E-05 +1.545038E-02 +3.289072E-05 +1.724229E-02 +4.091912E-05 +2.114484E-02 +5.448881E-05 +1.201008E-02 +1.761314E-05 +1.049205E-02 +1.851795E-05 +1.007470E-02 +1.508850E-05 +1.216162E-02 +1.779226E-05 +9.172443E-03 +1.542767E-05 +1.158129E-02 +2.700118E-05 +8.634939E-03 +1.235312E-05 +9.968731E-03 +1.636632E-05 +8.806160E-03 +1.312756E-05 +7.282738E-03 +7.675380E-06 +1.501313E-02 +3.403794E-05 +1.772683E-02 +3.946856E-05 +6.797082E-03 +6.826066E-06 +6.203754E-03 +6.576663E-06 +1.255269E-02 +2.273841E-05 +9.325891E-03 +1.968887E-05 +5.665941E-03 +7.672343E-06 +9.482040E-03 +1.321433E-05 +5.895438E-03 +7.290209E-06 +4.028986E-03 +3.562047E-06 +9.179212E-03 +1.479180E-05 +5.065510E-03 +7.876080E-06 +9.623638E-03 +1.331451E-05 +8.243023E-03 +1.155595E-05 +6.785547E-03 +8.869686E-06 +6.830346E-03 +6.869962E-06 +5.952624E-03 +7.591589E-06 +1.262730E-02 +2.795731E-05 +7.222793E-03 +7.969191E-06 +7.364474E-03 +9.912407E-06 +4.073203E-03 +3.221529E-06 +6.307497E-03 +8.387738E-06 +6.770719E-03 +9.965921E-06 +7.935928E-03 +9.247514E-06 +8.991810E-03 +1.001059E-05 +5.746536E-03 +5.204627E-06 +4.632325E-03 +3.055561E-06 +7.410656E-03 +9.676112E-06 +7.030579E-03 +9.078592E-06 +9.940893E-03 +2.033444E-05 +4.593423E-03 +3.918985E-06 +3.958315E-03 +2.344423E-06 +4.956734E-03 +6.309001E-06 +7.499601E-03 +8.403664E-06 +4.748645E-03 +4.199540E-06 +5.390021E-03 +5.915551E-06 +8.712210E-03 +1.738886E-05 +8.103852E-03 +9.180564E-06 +1.025459E-02 +1.310828E-05 +1.184291E-02 +1.833442E-05 +5.755536E-03 +5.404194E-06 +8.221201E-03 +9.335727E-06 +9.828395E-03 +1.545245E-05 +1.152575E-02 +1.759013E-05 +5.829495E-03 +7.232703E-06 +1.218356E-02 +2.664254E-05 +6.170466E-03 +7.308485E-06 +7.313197E-03 +7.829261E-06 +1.367693E-02 +3.155396E-05 +1.355349E-02 +2.093247E-05 +1.169703E-02 +1.533618E-05 +1.225998E-02 +3.530234E-05 +1.125463E-02 +1.795265E-05 +9.696736E-03 +1.412411E-05 +1.093214E-02 +1.673039E-05 +1.278387E-02 +2.130505E-05 +8.880561E-03 +1.364130E-05 +1.181523E-02 +1.870304E-05 +9.189492E-03 +1.453491E-05 +9.455271E-03 +1.423365E-05 +1.776658E-02 +4.257355E-05 +1.296514E-02 +2.121667E-05 +1.003865E-02 +1.487795E-05 +1.359312E-02 +2.765495E-05 +1.162264E-02 +2.140342E-05 +1.033131E-02 +1.304998E-05 +1.542205E-02 +3.650649E-05 +1.535565E-02 +3.683101E-05 +9.763595E-03 +1.309061E-05 +1.726548E-02 +4.632789E-05 +1.043992E-02 +1.651951E-05 +6.110039E-03 +6.694762E-06 +1.985635E-02 +6.510789E-05 +8.438493E-03 +9.248252E-06 +1.851818E-02 +4.904640E-05 +1.995254E-02 +5.020531E-05 +1.335907E-02 +2.466345E-05 +1.649899E-02 +3.318908E-05 +1.452837E-02 +3.635670E-05 +1.935287E-02 +5.575704E-05 +1.319131E-02 +2.791021E-05 +1.492064E-02 +3.073511E-05 +1.131605E-02 +2.493004E-05 +1.462680E-02 +2.849063E-05 +1.962759E-02 +5.083607E-05 +1.701425E-02 +4.167266E-05 +7.965972E-03 +1.229258E-05 +1.458100E-02 +2.718206E-05 +1.026138E-02 +2.113714E-05 +1.308429E-02 +2.003268E-05 +9.038340E-03 +9.340773E-06 +1.586616E-02 +3.218048E-05 +6.515114E-03 +9.139171E-06 +1.003265E-02 +1.250538E-05 +7.477346E-03 +9.170786E-06 +8.376990E-03 +1.161182E-05 +1.829624E-02 +3.702430E-05 +1.569831E-02 +2.881524E-05 +1.105450E-02 +2.103495E-05 +1.042629E-02 +1.723138E-05 +9.998085E-03 +1.227071E-05 +1.516738E-02 +3.324549E-05 +1.090125E-02 +1.985519E-05 +1.432278E-02 +3.386798E-05 +8.418229E-03 +1.050672E-05 +1.108353E-02 +1.739127E-05 +7.787352E-03 +1.084467E-05 +6.757477E-03 +8.314301E-06 +1.266965E-02 +2.014700E-05 +1.223368E-02 +1.816810E-05 +1.000405E-02 +2.132755E-05 +1.260170E-02 +2.392494E-05 +9.344763E-03 +1.208588E-05 +1.243003E-02 +2.215004E-05 +8.842577E-03 +1.468191E-05 +1.171609E-02 +2.634512E-05 +7.361574E-03 +1.005220E-05 +4.937175E-03 +3.421412E-06 +8.801345E-03 +1.258402E-05 +8.660082E-03 +1.317890E-05 +1.066110E-02 +2.285362E-05 +8.182265E-03 +1.352232E-05 +1.194368E-02 +2.542532E-05 +5.247990E-03 +7.113477E-06 +1.329855E-02 +2.805232E-05 +1.667204E-02 +4.715717E-05 +5.516192E-03 +4.861602E-06 +8.032885E-03 +9.526962E-06 +8.923177E-03 +1.221885E-05 +7.273785E-03 +7.646285E-06 +9.997748E-03 +1.389196E-05 +1.049460E-02 +1.325998E-05 +1.231591E-02 +1.779583E-05 +1.187687E-02 +1.777669E-05 +4.027367E-03 +5.095043E-06 +5.883273E-03 +1.010000E-05 +5.881059E-03 +5.701541E-06 +6.065490E-03 +8.604636E-06 +1.853273E-03 +1.189336E-06 +4.775189E-03 +6.494172E-06 +4.633358E-03 +4.183400E-06 +4.180683E-03 +5.129026E-06 +4.541541E-03 +5.646520E-06 +7.074233E-04 +2.834238E-07 +2.724695E-03 +2.217855E-06 +1.700068E-03 +8.357081E-07 +3.833078E-03 +2.656428E-06 +6.572586E-03 +8.866295E-06 +5.292952E-03 +3.867444E-06 +3.517788E-03 +2.530088E-06 +2.740599E-03 +2.004521E-06 +5.438345E-03 +8.165786E-06 +3.641025E-03 +3.113878E-06 +4.966383E-03 +7.623277E-06 +3.292270E-03 +2.722033E-06 +4.468651E-03 +5.017784E-06 +2.625164E-03 +1.543702E-06 +3.246447E-03 +2.141940E-06 +6.765655E-03 +9.017921E-06 +6.472797E-03 +5.971218E-06 +5.166553E-03 +3.916196E-06 +4.715011E-03 +4.421483E-06 +8.868545E-03 +1.033407E-05 +9.454655E-03 +1.287272E-05 +7.378309E-03 +9.793455E-06 +8.294983E-03 +1.242029E-05 +9.030433E-03 +1.660734E-05 +5.691832E-03 +4.629989E-06 +6.844709E-03 +1.039079E-05 +6.076908E-03 +6.364980E-06 +1.018307E-02 +1.478904E-05 +8.398207E-03 +1.353213E-05 +1.038657E-02 +1.650576E-05 +1.318384E-02 +2.408888E-05 +8.015055E-03 +1.126916E-05 +1.030145E-02 +1.582573E-05 +6.890267E-03 +8.319222E-06 +7.150937E-03 +7.850470E-06 +4.889144E-03 +3.720968E-06 +8.323465E-03 +1.115383E-05 +9.054557E-03 +1.439423E-05 +1.406749E-02 +2.792472E-05 +1.188336E-02 +2.280525E-05 +1.029778E-02 +1.535135E-05 +6.586615E-03 +8.689373E-06 +6.989279E-03 +6.602524E-06 +8.696264E-03 +1.699910E-05 +1.215054E-02 +1.809626E-05 +9.660496E-03 +1.576109E-05 +6.998390E-03 +6.984012E-06 +4.566410E-03 +4.700686E-06 +7.914312E-03 +8.046281E-06 +1.119024E-02 +1.682956E-05 +8.557711E-03 +1.169180E-05 +1.116108E-02 +2.002096E-05 +1.596243E-02 +3.319159E-05 +1.417800E-02 +2.698476E-05 +1.370714E-02 +3.345511E-05 +6.571905E-03 +1.170061E-05 +9.528663E-03 +1.906413E-05 +1.285473E-02 +1.987588E-05 +1.051645E-02 +2.095546E-05 +6.496841E-03 +6.085712E-06 +1.535496E-02 +3.318420E-05 +1.422914E-02 +2.578886E-05 +1.481483E-02 +2.681040E-05 +3.973095E-03 +3.122718E-06 +1.132021E-02 +1.735904E-05 +3.004322E-03 +4.387582E-06 +7.360833E-03 +1.310893E-05 +1.047617E-02 +1.750773E-05 +1.122781E-02 +2.131611E-05 +5.694910E-03 +7.234627E-06 +7.668968E-03 +8.067750E-06 +4.449311E-03 +4.768775E-06 +3.787286E-03 +2.624668E-06 +1.002060E-02 +1.749285E-05 +1.395365E-02 +2.967710E-05 +8.499007E-03 +1.449296E-05 +9.187712E-03 +1.502460E-05 +9.842313E-03 +1.218596E-05 +1.196667E-02 +1.597317E-05 +9.851299E-03 +1.503088E-05 +7.735045E-03 +9.286037E-06 +1.079491E-02 +1.766380E-05 +1.091930E-02 +1.648255E-05 +1.108268E-02 +1.578770E-05 +8.120340E-03 +1.291411E-05 +1.246096E-02 +2.528446E-05 +1.202701E-02 +1.816947E-05 +8.319659E-03 +1.340429E-05 +6.275166E-03 +6.982397E-06 +9.030250E-03 +1.174300E-05 +8.187094E-03 +1.235622E-05 +5.549210E-03 +5.420156E-06 +6.789734E-03 +7.904257E-06 +4.425697E-03 +3.919582E-06 +6.512926E-03 +7.118649E-06 +6.535547E-03 +1.403886E-05 +7.543231E-03 +1.205568E-05 +7.377749E-03 +1.142071E-05 +6.797258E-03 +7.523771E-06 +7.181352E-03 +8.290755E-06 +7.045510E-03 +1.013770E-05 +8.236912E-03 +1.265044E-05 +7.857392E-03 +1.143180E-05 +2.604005E-03 +2.317099E-06 +6.968220E-03 +1.347326E-05 +6.200344E-03 +7.619475E-06 +6.667622E-03 +1.088132E-05 +2.645846E-03 +1.854304E-06 +5.207931E-03 +4.574122E-06 +5.239891E-03 +5.012226E-06 +9.605662E-03 +1.784435E-05 +4.891233E-03 +6.117222E-06 +6.504651E-03 +1.229520E-05 +4.837232E-03 +6.126627E-06 +5.744494E-03 +9.825890E-06 +4.153989E-03 +5.541638E-06 +2.163062E-03 +2.727406E-06 +7.562241E-03 +1.683819E-05 +4.906111E-03 +7.696070E-06 +4.582205E-03 +7.559853E-06 +4.360889E-03 +6.753941E-06 +2.573412E-03 +2.074263E-06 +7.341817E-03 +1.510923E-05 +1.348516E-04 +1.818494E-08 +2.140265E-03 +2.186708E-06 +5.132621E-03 +6.802003E-06 +3.951538E-03 +5.966124E-06 +3.677707E-03 +4.225767E-06 +1.976184E-03 +9.056492E-07 +4.382040E-04 +1.920227E-07 +1.818577E-03 +1.643089E-06 +1.584983E-03 +1.096049E-06 +3.083453E-03 +3.167381E-06 +2.957748E-03 +3.417374E-06 +4.181554E-03 +3.122268E-06 +8.205844E-03 +1.339216E-05 +8.373927E-03 +1.673225E-05 +4.491527E-03 +6.082578E-06 +6.731608E-03 +1.117129E-05 +4.850830E-03 +4.259080E-06 +7.231407E-03 +8.438356E-06 +5.959383E-03 +1.199394E-05 +8.812537E-03 +1.137742E-05 +5.064971E-03 +5.265762E-06 +6.088263E-03 +5.366214E-06 +1.231967E-02 +2.529922E-05 +6.664708E-03 +6.756574E-06 +7.146824E-03 +6.992158E-06 +7.597362E-03 +8.315013E-06 +8.302133E-03 +1.025085E-05 +7.908279E-03 +8.283137E-06 +4.910695E-03 +4.757721E-06 +7.465751E-03 +1.337654E-05 +6.657558E-03 +7.888053E-06 +5.401779E-03 +5.483988E-06 +3.267001E-03 +2.915272E-06 +6.045569E-03 +6.294647E-06 +1.070370E-02 +1.951887E-05 +7.552609E-03 +7.432950E-06 +8.877234E-03 +1.068410E-05 +1.075436E-02 +1.493748E-05 +5.659998E-03 +5.370515E-06 +8.655450E-03 +1.139402E-05 +6.300286E-03 +8.630445E-06 +8.360752E-03 +1.357159E-05 +5.594374E-03 +5.201663E-06 +5.933381E-03 +5.223719E-06 +5.436755E-03 +5.337268E-06 +5.498344E-03 +4.605588E-06 +1.006944E-02 +1.688863E-05 +6.917860E-03 +8.432437E-06 +1.165526E-02 +1.802342E-05 +1.077532E-02 +2.444899E-05 +4.239569E-03 +2.886382E-06 +6.796744E-03 +5.792939E-06 +6.662910E-03 +5.729331E-06 +7.255977E-03 +1.065759E-05 +2.894086E-03 +1.903304E-06 +6.311066E-03 +4.912946E-06 +1.099018E-02 +2.054283E-05 +7.241143E-03 +7.442478E-06 +4.567091E-03 +3.071464E-06 +6.773593E-03 +5.905000E-06 +8.327525E-03 +9.451448E-06 +1.069359E-02 +1.514720E-05 +3.670959E-03 +3.304885E-06 +9.124065E-03 +1.471763E-05 +3.861446E-03 +3.151454E-06 +6.221877E-03 +1.027786E-05 +5.254419E-03 +6.135711E-06 +7.702917E-03 +1.051860E-05 +5.115541E-03 +6.357416E-06 +5.321924E-03 +4.501815E-06 +7.639895E-03 +1.792277E-05 +5.676732E-03 +4.933198E-06 +7.917058E-03 +1.103359E-05 +6.987672E-03 +8.124731E-06 +7.605775E-03 +1.154995E-05 +1.077244E-02 +2.439257E-05 +5.513601E-03 +7.937817E-06 +8.315505E-03 +9.181773E-06 +5.719492E-03 +6.912423E-06 +4.809607E-03 +6.393160E-06 +5.490138E-03 +6.557157E-06 +2.585724E-03 +1.337147E-06 +3.578006E-03 +2.074822E-06 +6.644166E-03 +9.849481E-06 +5.073345E-03 +6.101950E-06 +8.583604E-03 +1.928242E-05 +6.278182E-03 +8.352587E-06 +7.476949E-03 +1.201282E-05 +4.477112E-03 +4.894391E-06 +9.059255E-03 +1.429652E-05 +3.030949E-03 +1.590060E-06 +5.686827E-03 +5.262592E-06 +4.734421E-03 +6.896077E-06 +2.912353E-03 +1.875480E-06 +6.517175E-03 +6.330268E-06 +9.203829E-03 +1.181214E-05 +5.012765E-03 +5.129300E-06 +7.823830E-03 +1.330136E-05 +5.110174E-03 +4.376566E-06 +7.379964E-03 +8.333357E-06 +5.468869E-03 +6.083600E-06 +7.519458E-03 +1.048700E-05 +4.611391E-03 +3.814525E-06 +7.062996E-03 +1.181993E-05 +3.837864E-03 +3.789477E-06 +6.759816E-03 +8.026354E-06 +5.672758E-03 +4.924437E-06 +8.864970E-03 +1.097704E-05 +5.305515E-03 +6.789690E-06 +4.264513E-03 +5.260234E-06 +5.512145E-03 +8.119123E-06 +5.053780E-03 +5.404719E-06 +7.029594E-03 +9.741504E-06 +2.374002E-03 +1.449069E-06 +2.256464E-03 +1.391425E-06 +4.548643E-03 +7.978885E-06 +2.810872E-03 +2.456200E-06 +4.084882E-03 +6.257623E-06 +6.517591E-03 +9.674764E-06 +6.200630E-03 +9.438817E-06 +2.745907E-03 +1.809511E-06 +3.972065E-03 +3.245352E-06 +5.942817E-03 +7.352165E-06 +3.263414E-03 +3.353913E-06 +8.153438E-03 +1.079966E-05 +7.165596E-03 +1.017019E-05 +4.251216E-03 +2.817736E-06 +8.011851E-03 +1.068301E-05 +9.752890E-04 +7.589177E-07 +3.469946E-03 +2.493177E-06 +6.811986E-03 +8.722919E-06 +5.394586E-03 +6.424939E-06 +5.872081E-03 +8.499852E-06 +8.818832E-03 +1.189657E-05 +7.866284E-03 +8.632785E-06 +8.116334E-03 +1.347044E-05 +2.423674E-03 +2.219673E-06 +7.457717E-03 +9.186735E-06 +6.773921E-03 +1.764821E-05 +6.930098E-03 +1.011624E-05 +8.618704E-03 +1.022187E-05 +1.184609E-02 +2.438262E-05 +8.878289E-03 +1.326793E-05 +5.073855E-03 +4.038299E-06 +9.760737E-03 +1.548967E-05 +7.965991E-03 +1.151518E-05 +5.975862E-03 +1.006202E-05 +7.122347E-03 +8.079230E-06 +7.180618E-03 +7.951754E-06 +5.027224E-03 +6.787710E-06 +1.109603E-02 +1.848734E-05 +1.295024E-02 +3.036716E-05 +8.023705E-03 +8.286741E-06 +1.144577E-02 +2.665312E-05 +1.019084E-02 +1.881473E-05 +1.361484E-02 +2.576942E-05 +9.013737E-03 +1.466391E-05 +1.147532E-02 +2.462687E-05 +1.225257E-02 +2.181790E-05 +8.159645E-03 +1.259135E-05 +4.127139E-03 +2.557351E-06 +5.325669E-03 +6.365360E-06 +1.347774E-02 +2.661460E-05 +7.265261E-03 +1.252096E-05 +1.373140E-02 +2.385999E-05 +1.262611E-02 +2.245356E-05 +9.465554E-03 +2.262286E-05 +8.452943E-03 +1.155915E-05 +4.998547E-03 +7.068774E-06 +7.648621E-03 +9.105026E-06 +9.203837E-03 +1.311626E-05 +1.107019E-02 +1.950577E-05 +1.315936E-02 +2.410764E-05 +7.844275E-03 +9.659512E-06 +9.825100E-03 +1.724414E-05 +1.047811E-02 +1.262306E-05 +1.207238E-02 +2.752816E-05 +1.085843E-02 +1.470096E-05 +1.594894E-02 +4.046810E-05 +1.497569E-02 +2.863883E-05 +1.030144E-02 +2.348225E-05 +6.125370E-03 +7.226790E-06 +1.405421E-02 +4.764046E-05 +1.625035E-02 +3.353624E-05 +9.577818E-03 +1.794568E-05 +1.448263E-02 +2.770743E-05 +1.029916E-02 +1.861537E-05 +9.183850E-03 +1.591847E-05 +9.237708E-03 +1.576843E-05 +1.079813E-02 +1.581077E-05 +1.260676E-02 +3.554547E-05 +2.054039E-02 +5.879657E-05 +7.345172E-03 +8.644617E-06 +9.151035E-03 +1.651766E-05 +1.271524E-02 +2.302768E-05 +1.487615E-02 +3.960752E-05 +7.259983E-03 +1.107807E-05 +5.855371E-03 +4.857225E-06 +7.570428E-03 +9.406879E-06 +5.643592E-03 +7.265176E-06 +1.113252E-02 +1.652636E-05 +1.101056E-02 +1.732233E-05 +7.781992E-03 +7.475792E-06 +1.014997E-02 +1.698223E-05 +7.547933E-03 +1.219150E-05 +4.922153E-03 +4.916764E-06 +6.063790E-03 +7.031316E-06 +8.119766E-03 +1.484039E-05 +5.084706E-03 +4.983059E-06 +5.431730E-03 +5.048229E-06 +8.720640E-03 +1.061184E-05 +8.480299E-03 +1.325453E-05 +1.209019E-02 +2.053697E-05 +1.028370E-02 +2.394843E-05 +8.037695E-03 +1.000534E-05 +9.075446E-03 +1.720138E-05 +5.348851E-03 +5.241839E-06 +6.061215E-03 +7.799859E-06 +9.501216E-03 +1.498369E-05 +1.649742E-02 +3.974159E-05 +8.337027E-03 +1.677761E-05 +1.156020E-02 +1.673947E-05 +1.046774E-02 +2.653737E-05 +7.675581E-03 +8.456541E-06 +9.617224E-03 +1.794211E-05 +1.268842E-02 +2.897864E-05 +9.844835E-03 +1.818849E-05 +9.330947E-03 +1.549578E-05 +5.838065E-03 +7.948493E-06 +8.798788E-03 +1.342636E-05 +9.306629E-03 +1.318598E-05 +4.920602E-03 +4.823960E-06 +1.710686E-03 +7.729255E-07 +2.859179E-03 +1.745176E-06 +4.456373E-03 +4.366517E-06 +2.395798E-03 +1.736746E-06 +7.027745E-03 +1.682294E-05 +4.030298E-03 +4.530935E-06 +2.803361E-03 +2.792072E-06 +6.688412E-03 +1.091671E-05 +7.703157E-03 +8.772855E-06 +4.949493E-03 +3.982137E-06 +7.365244E-03 +1.073387E-05 +9.386372E-03 +1.134513E-05 +9.003757E-03 +1.332391E-05 +7.974051E-03 +1.354602E-05 +1.137434E-02 +1.857838E-05 +1.143520E-02 +2.117358E-05 +3.030499E-03 +2.165815E-06 +4.867784E-03 +3.911154E-06 +5.246175E-03 +6.161091E-06 +5.832426E-03 +5.525543E-06 +7.382520E-03 +9.067048E-06 +1.188676E-02 +1.778783E-05 +1.199313E-02 +2.082141E-05 +1.266957E-02 +1.962424E-05 +1.533876E-02 +3.337162E-05 +7.389726E-03 +1.341338E-05 +7.529503E-03 +1.564696E-05 +1.491955E-02 +2.945644E-05 +1.074068E-02 +1.373117E-05 +1.472706E-02 +3.572507E-05 +1.199986E-02 +3.422317E-05 +8.514133E-03 +1.135618E-05 +1.634996E-02 +4.087320E-05 +1.955740E-02 +5.492009E-05 +1.126909E-02 +1.541148E-05 +1.586435E-02 +3.446303E-05 +1.700178E-02 +4.898376E-05 +1.703540E-02 +3.720395E-05 +1.967755E-02 +4.525544E-05 +1.330271E-02 +2.702604E-05 +1.888903E-02 +4.979443E-05 +2.004837E-02 +5.083025E-05 +1.435878E-02 +3.285995E-05 +1.930301E-02 +5.509308E-05 +1.628120E-02 +3.580789E-05 +1.727344E-02 +4.342335E-05 +1.216615E-02 +1.983233E-05 +1.700189E-02 +4.670523E-05 +1.269439E-02 +2.172602E-05 +2.010215E-02 +5.553642E-05 +2.319103E-02 +6.565091E-05 +1.414047E-02 +3.346494E-05 +2.027618E-02 +5.626720E-05 +1.646954E-02 +3.312557E-05 +2.251086E-02 +5.995831E-05 +1.610985E-02 +3.156849E-05 +1.377020E-02 +2.853634E-05 +1.669701E-02 +3.307612E-05 +1.159986E-02 +1.816147E-05 +1.261975E-02 +1.769023E-05 +2.134097E-02 +5.752884E-05 +1.841902E-02 +4.295167E-05 +2.422207E-02 +7.083744E-05 +1.543392E-02 +4.221173E-05 +2.157215E-02 +6.548409E-05 +2.644384E-02 +8.410907E-05 +2.311629E-02 +6.681868E-05 +2.395484E-02 +6.437514E-05 +1.922089E-02 +4.174544E-05 +1.663494E-02 +3.328109E-05 +9.964643E-03 +1.255907E-05 +1.150794E-02 +1.961340E-05 +1.939308E-02 +4.712734E-05 +1.787616E-02 +4.675712E-05 +2.319516E-02 +6.969066E-05 +1.741640E-02 +5.935363E-05 +1.789596E-02 +4.474293E-05 +2.512717E-02 +7.989830E-05 +1.220933E-02 +1.607761E-05 +1.359674E-02 +2.403775E-05 +1.590621E-02 +4.874402E-05 +1.664365E-02 +3.902009E-05 +1.028716E-02 +1.812738E-05 +1.543365E-02 +3.451753E-05 +1.719718E-02 +5.881162E-05 +1.666983E-02 +4.833689E-05 +1.586040E-02 +3.290082E-05 +1.592280E-02 +2.852261E-05 +2.560930E-02 +8.694469E-05 +2.095050E-02 +5.412080E-05 +1.939382E-02 +4.569593E-05 +1.830391E-02 +4.667520E-05 +1.549161E-02 +4.356136E-05 +1.284248E-02 +2.163546E-05 +1.082843E-02 +1.936706E-05 +1.108300E-02 +2.032165E-05 +1.963227E-02 +5.789246E-05 +1.883825E-02 +5.273957E-05 +1.630332E-02 +3.434978E-05 +1.574688E-02 +3.564693E-05 +1.794394E-02 +3.918955E-05 +2.060232E-02 +5.819679E-05 +1.732204E-02 +4.346625E-05 +1.922985E-02 +4.636825E-05 +1.116057E-02 +1.992936E-05 +1.216817E-02 +1.947069E-05 +8.811885E-03 +1.441275E-05 +1.603072E-02 +3.965729E-05 +1.459394E-02 +2.864759E-05 +1.150127E-02 +2.431776E-05 +1.146459E-02 +2.593052E-05 +1.120930E-02 +2.027939E-05 +1.077685E-02 +1.909421E-05 +1.564605E-02 +5.177856E-05 +1.438847E-02 +2.596269E-05 +1.575101E-02 +2.945546E-05 +5.164090E-03 +4.380072E-06 +5.313984E-03 +4.984595E-06 +3.270078E-03 +3.714857E-06 +4.763025E-03 +5.471147E-06 +5.854797E-03 +4.013420E-06 +7.497916E-03 +9.530633E-06 +4.307122E-03 +4.511481E-06 +2.673595E-03 +1.496751E-06 +7.668976E-03 +1.208726E-05 +6.666645E-03 +9.107345E-06 +4.278473E-03 +3.613729E-06 +5.196607E-03 +6.165915E-06 +9.012663E-03 +1.072065E-05 +7.125950E-03 +1.021884E-05 +1.110525E-02 +1.609758E-05 +6.452393E-03 +6.522408E-06 +1.614916E-02 +2.933964E-05 +1.252957E-02 +2.095707E-05 +9.931672E-03 +1.358529E-05 +1.307449E-02 +2.442977E-05 +5.859693E-03 +6.187229E-06 +6.811267E-03 +6.011900E-06 +1.636036E-02 +4.227062E-05 +9.529154E-03 +1.673527E-05 +9.884570E-03 +1.607810E-05 +1.162560E-02 +2.293323E-05 +6.582499E-03 +8.254458E-06 +1.846807E-02 +3.840513E-05 +9.921319E-03 +1.528378E-05 +1.451278E-02 +3.842835E-05 +1.536970E-02 +4.453795E-05 +1.597714E-02 +3.763051E-05 +1.416499E-02 +2.488034E-05 +1.579940E-02 +3.618366E-05 +1.729494E-02 +4.587947E-05 +1.591255E-02 +3.608980E-05 +1.155321E-02 +2.053226E-05 +1.599423E-02 +3.545225E-05 +1.125966E-02 +2.267289E-05 +2.172447E-02 +5.857701E-05 +1.372075E-02 +3.321713E-05 +1.816373E-02 +4.485596E-05 +1.857039E-02 +4.872304E-05 +1.742011E-02 +3.730490E-05 +1.568977E-02 +3.029088E-05 +2.829373E-02 +1.168965E-04 +2.157357E-02 +7.579178E-05 +2.125484E-02 +6.473902E-05 +2.196378E-02 +7.339057E-05 +1.819373E-02 +4.494748E-05 +2.152003E-02 +5.928285E-05 +1.856070E-02 +4.410267E-05 +2.207371E-02 +6.449028E-05 +2.386394E-02 +6.969242E-05 +2.457216E-02 +1.102599E-04 +2.058268E-02 +5.017858E-05 +1.907854E-02 +4.286270E-05 +2.340706E-02 +8.278475E-05 +2.388190E-02 +6.533857E-05 +2.860789E-02 +9.992731E-05 +1.998933E-02 +5.361464E-05 +2.707938E-02 +9.662902E-05 +2.019340E-02 +5.415561E-05 +3.109482E-02 +1.022004E-04 +2.253924E-02 +7.055172E-05 +2.374030E-02 +6.831307E-05 +2.529035E-02 +8.295294E-05 +2.739289E-02 +8.546620E-05 +2.273185E-02 +6.442166E-05 +2.785353E-02 +8.812366E-05 +3.191849E-02 +1.234987E-04 +2.739246E-02 +9.446447E-05 +1.372157E-02 +2.877717E-05 +1.714263E-02 +4.531432E-05 +1.958677E-02 +4.920099E-05 +1.932218E-02 +4.756040E-05 +1.938252E-02 +5.565524E-05 +2.128472E-02 +6.581062E-05 +1.818983E-02 +4.440473E-05 +2.522476E-02 +9.504815E-05 +2.108060E-02 +6.460391E-05 +2.301325E-02 +6.325908E-05 +2.425505E-02 +7.889282E-05 +2.312674E-02 +8.098059E-05 +1.450662E-02 +3.120847E-05 +1.518342E-02 +2.854939E-05 +2.375891E-02 +6.170759E-05 +2.191567E-02 +5.656277E-05 +1.717224E-02 +4.219605E-05 +1.584923E-02 +2.801671E-05 +2.292044E-02 +6.761182E-05 +2.565035E-02 +9.677221E-05 +1.979804E-02 +4.912546E-05 +2.534051E-02 +8.007940E-05 +3.425993E-02 +1.487128E-04 +2.139063E-02 +5.051176E-05 +1.422774E-02 +2.343122E-05 +2.541660E-02 +8.204787E-05 +1.717071E-02 +3.842694E-05 +1.456931E-02 +2.599937E-05 +2.407397E-02 +7.826348E-05 +2.982739E-02 +1.099192E-04 +1.812330E-02 +4.520557E-05 +1.506065E-02 +3.120742E-05 +1.957887E-02 +5.130992E-05 +2.577824E-02 +8.648590E-05 +1.959134E-02 +6.907548E-05 +2.361937E-02 +6.849830E-05 +1.277061E-02 +2.340598E-05 +1.244142E-02 +2.267140E-05 +9.333247E-03 +1.041879E-05 +7.908182E-03 +9.293981E-06 +1.463279E-02 +3.362978E-05 +1.366375E-02 +2.733021E-05 +1.213165E-02 +1.941620E-05 +1.142127E-02 +1.911366E-05 +1.101989E-02 +1.602290E-05 +1.634784E-02 +3.444363E-05 +1.399007E-02 +2.474094E-05 +1.355244E-02 +2.255801E-05 +8.699738E-03 +1.229441E-05 +6.242338E-03 +7.967030E-06 +1.101667E-02 +2.565058E-05 +8.204914E-03 +1.826875E-05 +1.073981E-02 +1.693632E-05 +1.272259E-02 +2.077325E-05 +3.495009E-03 +2.520678E-06 +8.225887E-03 +1.254359E-05 +1.009530E-02 +1.562680E-05 +1.178865E-02 +2.042891E-05 +8.663517E-03 +1.609834E-05 +1.169582E-02 +2.164100E-05 +7.396443E-03 +1.192095E-05 +3.652278E-03 +3.129723E-06 +1.045202E-02 +2.112608E-05 +1.037936E-02 +1.718392E-05 +4.516079E-03 +3.575143E-06 +1.095270E-02 +1.774093E-05 +4.883767E-03 +5.927447E-06 +6.503683E-03 +7.716956E-06 +4.663924E-03 +5.713440E-06 +6.283619E-03 +4.627844E-06 +1.015268E-02 +1.309267E-05 +9.180971E-03 +1.527190E-05 +1.951120E-02 +4.198333E-05 +1.915689E-02 +5.707669E-05 +1.373893E-02 +2.451846E-05 +1.700799E-02 +4.037549E-05 +8.089066E-03 +1.170312E-05 +1.428411E-02 +2.720105E-05 +1.592720E-02 +3.708704E-05 +1.631763E-02 +3.412617E-05 +1.129445E-02 +1.941873E-05 +1.915612E-02 +4.735245E-05 +1.422466E-02 +3.019642E-05 +1.623769E-02 +4.050190E-05 +3.000266E-02 +1.011980E-04 +2.431859E-02 +7.075474E-05 +1.997843E-02 +5.249597E-05 +2.330404E-02 +6.963217E-05 +2.446833E-02 +7.157726E-05 +2.086381E-02 +6.071597E-05 +2.692405E-02 +8.142503E-05 +3.334489E-02 +1.331416E-04 +2.459016E-02 +7.539450E-05 +2.490317E-02 +6.829414E-05 +3.465734E-02 +1.336723E-04 +2.655747E-02 +8.402121E-05 +2.461979E-02 +7.593460E-05 +2.071273E-02 +5.109741E-05 +1.963799E-02 +4.721624E-05 +2.830417E-02 +1.108014E-04 +2.011415E-02 +4.210370E-05 +2.710260E-02 +9.007571E-05 +2.284700E-02 +6.898714E-05 +3.401467E-02 +1.508203E-04 +3.114460E-02 +1.181041E-04 +3.240556E-02 +1.301155E-04 +2.879980E-02 +1.090167E-04 +3.128129E-02 +1.046425E-04 +1.710639E-02 +3.063073E-05 +2.380055E-02 +6.611900E-05 +2.461530E-02 +6.805558E-05 +2.334066E-02 +6.791023E-05 +2.377977E-02 +7.167847E-05 +3.617503E-02 +1.573371E-04 +1.872815E-02 +5.621939E-05 +1.775203E-02 +4.642358E-05 +2.771547E-02 +8.299647E-05 +3.061731E-02 +1.020731E-04 +2.507147E-02 +7.334317E-05 +3.870082E-02 +1.721376E-04 +2.186224E-02 +6.325183E-05 +2.007397E-02 +5.062141E-05 +1.912434E-02 +4.450748E-05 +3.143924E-02 +1.217065E-04 +2.928610E-02 +1.369102E-04 +2.498862E-02 +9.234430E-05 +3.196385E-02 +1.380535E-04 +2.888275E-02 +9.066905E-05 +2.680537E-02 +9.933885E-05 +3.510043E-02 +1.418994E-04 +2.849205E-02 +9.541143E-05 +3.088469E-02 +1.124620E-04 +2.410541E-02 +7.456599E-05 +2.652028E-02 +7.737605E-05 +3.100674E-02 +1.204077E-04 +2.627656E-02 +7.414914E-05 +3.172017E-02 +1.179298E-04 +3.654420E-02 +1.501200E-04 +2.437387E-02 +8.465163E-05 +2.329587E-02 +8.609453E-05 +2.851454E-02 +9.764789E-05 +2.727184E-02 +1.020548E-04 +2.887669E-02 +9.379474E-05 +2.486065E-02 +6.980906E-05 +1.336139E-02 +3.237058E-05 +1.783830E-02 +4.308671E-05 +1.984536E-02 +4.793066E-05 +1.663979E-02 +3.245507E-05 +1.629628E-02 +3.780856E-05 +2.783691E-02 +9.185991E-05 +1.901340E-02 +4.331876E-05 +1.589227E-02 +3.023585E-05 +1.511908E-02 +3.924720E-05 +2.103836E-02 +5.685631E-05 +1.846361E-02 +5.596947E-05 +2.921881E-02 +1.027479E-04 +1.582650E-02 +2.965346E-05 +1.468540E-02 +2.895302E-05 +9.775043E-03 +1.581144E-05 +1.531973E-02 +3.646605E-05 +1.629584E-02 +4.077722E-05 +1.301406E-02 +2.211695E-05 +1.400095E-02 +2.464499E-05 +1.812501E-02 +5.136800E-05 +1.883997E-02 +4.846725E-05 +1.310098E-02 +2.076611E-05 +1.641887E-02 +3.214577E-05 +2.575947E-02 +7.664609E-05 +1.393085E-02 +2.533855E-05 +1.176890E-02 +1.965214E-05 +1.001319E-02 +1.752840E-05 +5.440474E-03 +5.776297E-06 +1.602659E-02 +3.187961E-05 +1.220713E-02 +2.605586E-05 +7.910828E-03 +1.235157E-05 +6.370403E-03 +7.314863E-06 +1.200010E-02 +2.093134E-05 +1.051384E-02 +2.114633E-05 +8.728632E-03 +1.217334E-05 +9.023232E-03 +1.429000E-05 +9.324890E-03 +1.238002E-05 +9.724819E-03 +1.340545E-05 +7.999095E-03 +1.507108E-05 +1.196325E-02 +2.492866E-05 +1.708992E-02 +4.187497E-05 +1.252870E-02 +2.576528E-05 +1.245286E-02 +2.205925E-05 +1.710226E-02 +4.820652E-05 +1.077670E-02 +2.779337E-05 +8.954749E-03 +1.459088E-05 +1.587508E-02 +5.891538E-05 +1.256231E-02 +3.626849E-05 +1.456161E-02 +2.677457E-05 +1.442492E-02 +2.873208E-05 +1.513933E-02 +2.781837E-05 +1.983944E-02 +4.742520E-05 +1.796161E-02 +5.099223E-05 +1.372378E-02 +2.143333E-05 +2.054995E-02 +5.149337E-05 +1.901284E-02 +4.203203E-05 +1.545044E-02 +3.240467E-05 +1.613542E-02 +3.093719E-05 +1.748080E-02 +3.676025E-05 +1.983930E-02 +5.826899E-05 +2.077484E-02 +5.311470E-05 +2.156771E-02 +7.349191E-05 +1.910656E-02 +5.646548E-05 +2.216856E-02 +5.896630E-05 +2.363877E-02 +6.273768E-05 +2.287745E-02 +6.142836E-05 +2.078760E-02 +5.965409E-05 +2.096805E-02 +6.106318E-05 +2.748905E-02 +8.547689E-05 +3.051782E-02 +1.062831E-04 +2.439885E-02 +6.963272E-05 +2.385521E-02 +7.024650E-05 +2.722803E-02 +8.442159E-05 +2.779212E-02 +9.251750E-05 +3.008247E-02 +1.087302E-04 +2.911535E-02 +9.162499E-05 +2.377217E-02 +6.480525E-05 +2.478405E-02 +8.301183E-05 +2.916643E-02 +1.151040E-04 +3.299041E-02 +1.251473E-04 +3.387553E-02 +1.275181E-04 +3.185326E-02 +1.151563E-04 +2.738559E-02 +8.510575E-05 +3.552781E-02 +1.467678E-04 +2.050637E-02 +4.879306E-05 +2.837699E-02 +8.517767E-05 +2.623559E-02 +7.322670E-05 +3.299486E-02 +1.475369E-04 +2.852314E-02 +1.058243E-04 +3.897511E-02 +1.782398E-04 +3.453237E-02 +1.467871E-04 +2.695630E-02 +9.399806E-05 +2.993587E-02 +1.069727E-04 +3.357367E-02 +1.220837E-04 +3.533685E-02 +1.307797E-04 +3.768880E-02 +1.706168E-04 +2.378269E-02 +8.193354E-05 +2.476389E-02 +6.667890E-05 +1.835306E-02 +3.678306E-05 +2.760875E-02 +1.044222E-04 +3.364777E-02 +1.294893E-04 +2.689602E-02 +8.234805E-05 +2.994600E-02 +1.038678E-04 +3.354397E-02 +1.250106E-04 +2.806016E-02 +1.032022E-04 +3.628839E-02 +1.512597E-04 +3.254567E-02 +1.229982E-04 +3.532092E-02 +1.401948E-04 +2.079706E-02 +5.214734E-05 +2.220721E-02 +6.771925E-05 +2.792774E-02 +9.954429E-05 +2.945320E-02 +1.043290E-04 +3.367757E-02 +1.278353E-04 +3.498071E-02 +1.439058E-04 +3.069969E-02 +1.094894E-04 +2.802931E-02 +9.732849E-05 +3.379486E-02 +1.251030E-04 +3.112018E-02 +1.419631E-04 +2.905240E-02 +9.457676E-05 +3.204785E-02 +1.232863E-04 +2.256002E-02 +6.449945E-05 +2.013216E-02 +4.579187E-05 +2.378756E-02 +7.502656E-05 +1.850227E-02 +4.559569E-05 +2.577098E-02 +8.077705E-05 +2.622626E-02 +8.900068E-05 +2.011102E-02 +5.119938E-05 +1.881459E-02 +5.303212E-05 +2.333357E-02 +8.135744E-05 +2.169922E-02 +5.260477E-05 +2.865567E-02 +1.072530E-04 +3.018313E-02 +1.180560E-04 +1.619341E-02 +3.631507E-05 +2.048742E-02 +6.014736E-05 +1.648517E-02 +3.461260E-05 +2.016257E-02 +5.377223E-05 +1.821956E-02 +4.021256E-05 +2.158168E-02 +6.922336E-05 +1.520759E-02 +3.087500E-05 +1.460640E-02 +2.484693E-05 +2.423578E-02 +9.468824E-05 +1.422992E-02 +2.626671E-05 +2.233711E-02 +6.453963E-05 +2.201935E-02 +6.607908E-05 +9.865297E-03 +1.253449E-05 +1.407603E-02 +2.374027E-05 +1.554488E-02 +3.357059E-05 +1.104207E-02 +1.800945E-05 +1.152633E-02 +1.752515E-05 +1.628689E-02 +3.825834E-05 +1.961306E-03 +1.509555E-06 +7.317970E-03 +1.170313E-05 +8.045927E-03 +1.128636E-05 +7.690351E-03 +9.455253E-06 +1.305182E-02 +2.924924E-05 +8.478606E-03 +1.183524E-05 +8.368030E-03 +9.397112E-06 +6.954808E-03 +5.988757E-06 +1.478825E-02 +2.903770E-05 +1.329221E-02 +2.352890E-05 +1.153738E-02 +2.279952E-05 +1.243207E-02 +2.027409E-05 +9.794691E-03 +2.519096E-05 +1.301443E-02 +2.673139E-05 +7.744527E-03 +8.512395E-06 +1.094360E-02 +1.898404E-05 +1.322530E-02 +2.416304E-05 +1.130737E-02 +2.067371E-05 +1.475002E-02 +2.641761E-05 +1.707041E-02 +4.061788E-05 +1.873188E-02 +3.858649E-05 +2.599435E-02 +7.840083E-05 +1.356899E-02 +3.303086E-05 +1.640959E-02 +4.231153E-05 +1.712330E-02 +4.025543E-05 +2.408636E-02 +6.859578E-05 +1.647314E-02 +3.975609E-05 +2.116131E-02 +5.516930E-05 +1.843826E-02 +4.250156E-05 +1.528596E-02 +3.432942E-05 +1.872595E-02 +4.482976E-05 +2.278412E-02 +7.039773E-05 +1.646460E-02 +3.454420E-05 +2.813905E-02 +1.098347E-04 +1.918135E-02 +4.628739E-05 +2.880134E-02 +1.294280E-04 +2.929725E-02 +1.035423E-04 +2.521557E-02 +8.873832E-05 +1.598874E-02 +3.488466E-05 +2.763380E-02 +9.554358E-05 +2.869939E-02 +9.202942E-05 +2.713151E-02 +8.978531E-05 +1.987710E-02 +4.592695E-05 +2.437199E-02 +8.143180E-05 +2.321959E-02 +6.492177E-05 +3.341995E-02 +1.498991E-04 +3.725498E-02 +1.896851E-04 +2.546980E-02 +7.669037E-05 +3.217017E-02 +1.220964E-04 +3.340259E-02 +1.408478E-04 +2.814856E-02 +9.960802E-05 +3.512673E-02 +1.528623E-04 +3.192684E-02 +1.177255E-04 +4.396846E-02 +2.179530E-04 +2.532908E-02 +9.266623E-05 +2.547875E-02 +7.493150E-05 +2.198311E-02 +5.696022E-05 +2.752789E-02 +8.630574E-05 +2.765173E-02 +8.761218E-05 +2.779760E-02 +1.213200E-04 +3.155525E-02 +1.104115E-04 +3.217963E-02 +1.396421E-04 +2.812793E-02 +1.067509E-04 +3.145703E-02 +1.323921E-04 +3.473095E-02 +1.271199E-04 +3.132386E-02 +1.050335E-04 +2.550248E-02 +7.173055E-05 +2.519509E-02 +8.292973E-05 +2.719586E-02 +9.875000E-05 +3.129909E-02 +1.364716E-04 +2.405862E-02 +6.392928E-05 +3.794317E-02 +1.796683E-04 +2.411060E-02 +7.563523E-05 +3.925533E-02 +1.941205E-04 +2.464678E-02 +8.141818E-05 +2.681802E-02 +8.985410E-05 +4.257422E-02 +2.011050E-04 +3.169616E-02 +1.228099E-04 +2.070267E-02 +8.295562E-05 +1.875182E-02 +4.519138E-05 +2.746689E-02 +8.527112E-05 +3.193689E-02 +1.260160E-04 +3.274412E-02 +1.277208E-04 +3.159605E-02 +1.244039E-04 +2.739115E-02 +9.148770E-05 +2.496372E-02 +7.319379E-05 +2.543741E-02 +8.751995E-05 +3.092377E-02 +1.322133E-04 +3.099099E-02 +1.159996E-04 +3.339925E-02 +1.244687E-04 +1.992237E-02 +5.132256E-05 +2.014907E-02 +4.750167E-05 +2.144112E-02 +6.724888E-05 +3.234934E-02 +1.819994E-04 +2.676069E-02 +9.670530E-05 +2.163370E-02 +5.007717E-05 +1.255610E-02 +2.744980E-05 +1.686689E-02 +4.406712E-05 +2.491027E-02 +8.641625E-05 +2.180394E-02 +5.962243E-05 +2.074450E-02 +7.196276E-05 +2.673557E-02 +9.943740E-05 +1.141559E-02 +2.064868E-05 +1.086445E-02 +1.772569E-05 +1.994739E-02 +6.095357E-05 +1.294529E-02 +2.949692E-05 +1.279449E-02 +2.013615E-05 +1.695923E-02 +5.267358E-05 +1.003362E-02 +1.892494E-05 +1.177407E-02 +3.074621E-05 +1.427717E-02 +3.062012E-05 +1.772566E-02 +4.566137E-05 +1.448022E-02 +2.786842E-05 +1.885150E-02 +4.869026E-05 +6.234737E-03 +6.766915E-06 +8.586280E-03 +1.484755E-05 +6.177392E-03 +1.214223E-05 +5.323791E-03 +4.680794E-06 +1.176080E-02 +2.484279E-05 +1.114881E-02 +1.645519E-05 +6.273419E-03 +6.143891E-06 +5.166701E-03 +3.867691E-06 +8.069436E-03 +1.040414E-05 +4.713136E-03 +5.175457E-06 +1.199780E-02 +1.859984E-05 +8.029148E-03 +8.699198E-06 +5.632949E-03 +5.837510E-06 +9.206218E-03 +1.575125E-05 +9.680753E-03 +1.846461E-05 +1.155184E-02 +2.188509E-05 +1.074904E-02 +1.891184E-05 +1.181458E-02 +2.456277E-05 +1.127047E-02 +2.593399E-05 +1.356860E-02 +2.814265E-05 +5.544832E-03 +6.946307E-06 +9.942970E-03 +1.675490E-05 +1.631004E-02 +3.536433E-05 +1.506925E-02 +2.482344E-05 +1.182795E-02 +1.897537E-05 +1.482385E-02 +3.899302E-05 +1.209032E-02 +1.754837E-05 +1.195251E-02 +2.049614E-05 +1.038664E-02 +1.424835E-05 +1.422392E-02 +2.932993E-05 +1.541884E-02 +3.247431E-05 +1.631665E-02 +4.604922E-05 +1.384486E-02 +3.663157E-05 +1.878261E-02 +4.189792E-05 +1.586209E-02 +3.733994E-05 +2.018001E-02 +5.531326E-05 +1.737200E-02 +4.051342E-05 +1.867979E-02 +4.835331E-05 +1.873274E-02 +7.026344E-05 +3.092919E-02 +1.440764E-04 +1.756290E-02 +4.330757E-05 +1.677922E-02 +3.960529E-05 +1.917939E-02 +5.218395E-05 +2.058760E-02 +5.104735E-05 +1.950686E-02 +4.503102E-05 +1.898111E-02 +5.123138E-05 +2.095898E-02 +6.978821E-05 +2.496761E-02 +7.344351E-05 +2.216966E-02 +6.981877E-05 +1.539258E-02 +3.355552E-05 +2.090036E-02 +5.893204E-05 +2.830594E-02 +9.908163E-05 +2.079711E-02 +5.700234E-05 +2.438388E-02 +7.315541E-05 +2.071811E-02 +5.920090E-05 +3.238056E-02 +1.338963E-04 +1.998547E-02 +4.982584E-05 +2.456523E-02 +7.090598E-05 +3.010218E-02 +9.569115E-05 +2.615311E-02 +8.034083E-05 +2.193093E-02 +6.501139E-05 +2.230235E-02 +6.810904E-05 +2.787441E-02 +9.364266E-05 +3.363819E-02 +1.294292E-04 +2.455137E-02 +7.174173E-05 +2.515678E-02 +6.839428E-05 +2.184998E-02 +5.948214E-05 +3.240910E-02 +1.297175E-04 +2.930001E-02 +9.691693E-05 +2.531952E-02 +7.468705E-05 +3.926456E-02 +1.746326E-04 +3.138940E-02 +1.141098E-04 +2.053774E-02 +4.616986E-05 +1.863850E-02 +5.063978E-05 +2.488227E-02 +8.135984E-05 +2.946035E-02 +9.621222E-05 +1.816353E-02 +4.227005E-05 +2.739033E-02 +9.425769E-05 +2.235176E-02 +7.322516E-05 +2.512226E-02 +7.712444E-05 +2.093974E-02 +5.655060E-05 +1.951079E-02 +4.907052E-05 +3.008712E-02 +9.648471E-05 +2.695713E-02 +8.322148E-05 +2.032086E-02 +4.478975E-05 +1.588968E-02 +3.284638E-05 +2.795370E-02 +9.478738E-05 +3.242775E-02 +1.467751E-04 +1.851414E-02 +5.030367E-05 +1.699040E-02 +4.048405E-05 +2.381562E-02 +8.005819E-05 +2.396088E-02 +7.106899E-05 +1.334683E-02 +2.033683E-05 +2.683684E-02 +9.730671E-05 +3.212945E-02 +1.268600E-04 +2.413721E-02 +7.785437E-05 +1.278877E-02 +2.285665E-05 +2.017408E-02 +5.101405E-05 +2.425974E-02 +8.238864E-05 +1.559733E-02 +4.134474E-05 +2.323747E-02 +5.912862E-05 +3.185441E-02 +1.214009E-04 +1.297541E-02 +3.542303E-05 +1.620965E-02 +3.785927E-05 +2.077217E-02 +5.048348E-05 +2.084714E-02 +5.308615E-05 +2.198650E-02 +6.677202E-05 +2.713339E-02 +7.996952E-05 +1.008900E-02 +1.493544E-05 +7.515252E-03 +6.938048E-06 +1.725580E-02 +4.511463E-05 +1.861578E-02 +4.706579E-05 +1.192562E-02 +1.706496E-05 +1.539067E-02 +3.704392E-05 +1.563574E-02 +3.149768E-05 +1.617709E-02 +3.434601E-05 +1.421795E-02 +2.693384E-05 +9.544761E-03 +1.420198E-05 +1.920816E-02 +4.315771E-05 +2.104112E-02 +6.953280E-05 +8.386327E-03 +1.191493E-05 +8.722802E-03 +1.610480E-05 +1.338316E-02 +2.795188E-05 +1.139681E-02 +2.426741E-05 +1.023902E-02 +1.793399E-05 +1.031055E-02 +1.727351E-05 +7.202274E-03 +8.248223E-06 +5.930048E-03 +5.651618E-06 +7.496873E-03 +1.049976E-05 +1.159952E-02 +1.637372E-05 +1.149358E-02 +2.129416E-05 +1.751957E-02 +3.876503E-05 +1.304134E-02 +2.268145E-05 +6.423719E-03 +1.030715E-05 +1.229584E-02 +1.921824E-05 +1.597047E-02 +2.887519E-05 +7.728575E-03 +8.694018E-06 +1.102992E-02 +1.663289E-05 +9.958745E-03 +1.518594E-05 +9.321102E-03 +1.260439E-05 +9.226395E-03 +1.473519E-05 +1.071198E-02 +1.716096E-05 +1.209027E-02 +2.012204E-05 +1.299345E-02 +2.535948E-05 +1.377877E-02 +2.712220E-05 +1.505661E-02 +3.492299E-05 +1.496534E-02 +3.555281E-05 +1.674256E-02 +3.935472E-05 +9.494973E-03 +1.562850E-05 +9.878116E-03 +1.686202E-05 +1.512689E-02 +2.756935E-05 +2.271723E-02 +7.190876E-05 +1.204699E-02 +2.702913E-05 +1.339825E-02 +2.817955E-05 +1.767135E-02 +4.942115E-05 +1.480386E-02 +6.975977E-05 +1.636386E-02 +3.439959E-05 +1.220265E-02 +2.153744E-05 +1.347844E-02 +2.910724E-05 +1.359228E-02 +3.101663E-05 +9.728835E-03 +1.507092E-05 +1.528103E-02 +3.443965E-05 +2.096063E-02 +6.754181E-05 +2.094364E-02 +6.023053E-05 +1.266226E-02 +2.412451E-05 +2.535680E-02 +7.344640E-05 +2.598994E-02 +9.953050E-05 +2.060213E-02 +7.034543E-05 +1.788607E-02 +3.674071E-05 +1.148154E-02 +1.909188E-05 +2.245671E-02 +6.003250E-05 +2.763268E-02 +9.551846E-05 +2.267967E-02 +6.032826E-05 +1.916473E-02 +4.604843E-05 +1.294451E-02 +1.970613E-05 +1.934618E-02 +4.918252E-05 +2.293529E-02 +7.197108E-05 +1.496065E-02 +2.444659E-05 +2.226558E-02 +5.644756E-05 +1.948569E-02 +4.450894E-05 +2.081785E-02 +5.246988E-05 +1.522522E-02 +3.455714E-05 +2.719218E-02 +8.650624E-05 +3.018717E-02 +1.279696E-04 +1.871704E-02 +6.935361E-05 +2.067645E-02 +5.026583E-05 +2.040699E-02 +4.591994E-05 +2.662203E-02 +8.511265E-05 +1.360877E-02 +2.453053E-05 +2.047026E-02 +5.992658E-05 +2.099358E-02 +6.877382E-05 +1.757234E-02 +4.380517E-05 +2.023155E-02 +5.570688E-05 +1.620245E-02 +3.127153E-05 +2.718760E-02 +1.061924E-04 +1.747980E-02 +4.190787E-05 +1.548489E-02 +3.376610E-05 +2.645660E-02 +9.074843E-05 +1.786629E-02 +4.215277E-05 +1.474131E-02 +2.581817E-05 +1.388717E-02 +2.989188E-05 +2.441704E-02 +7.084896E-05 +2.104368E-02 +5.681421E-05 +2.433800E-02 +7.895153E-05 +1.597437E-02 +3.483039E-05 +1.412656E-02 +2.566245E-05 +1.687717E-02 +3.771639E-05 +2.190482E-02 +8.253917E-05 +1.386107E-02 +3.378072E-05 +1.256494E-02 +2.033235E-05 +1.458675E-02 +2.616735E-05 +1.633493E-02 +3.166210E-05 +2.288089E-02 +6.714973E-05 +2.398060E-02 +7.693950E-05 +1.834264E-02 +4.444484E-05 +2.286357E-02 +5.661515E-05 +1.648013E-02 +4.331697E-05 +1.300614E-02 +2.342646E-05 +1.426626E-02 +2.966175E-05 +2.218616E-02 +7.311082E-05 +1.244578E-02 +2.216996E-05 +2.287835E-02 +6.924841E-05 +1.752439E-02 +4.165478E-05 +2.103286E-02 +5.842027E-05 +1.533084E-02 +3.870604E-05 +1.829172E-02 +5.193773E-05 +1.756896E-02 +4.997547E-05 +2.219401E-02 +5.804587E-05 +1.083994E-02 +1.562087E-05 +1.144466E-02 +2.086121E-05 +1.743653E-02 +3.615221E-05 +9.676259E-03 +1.226729E-05 +1.296315E-02 +2.293653E-05 +1.353945E-02 +3.069949E-05 +7.066700E-03 +7.777520E-06 +8.915397E-03 +1.286545E-05 +1.337770E-02 +2.968336E-05 +1.210357E-02 +2.373080E-05 +1.021357E-02 +1.742336E-05 +1.615799E-02 +4.003564E-05 +9.037428E-03 +1.958275E-05 +3.183370E-03 +2.393571E-06 +8.515537E-03 +1.434148E-05 +8.594763E-03 +1.144929E-05 +6.557583E-03 +6.809462E-06 +9.324712E-03 +1.284671E-05 +6.075741E-03 +8.217443E-06 +7.732948E-03 +1.254995E-05 +9.364155E-03 +1.391050E-05 +1.033625E-02 +1.710810E-05 +1.643522E-02 +5.092731E-05 +1.913240E-02 +5.188056E-05 +4.699889E-03 +4.253342E-06 +3.667145E-03 +3.051204E-06 +6.956946E-03 +7.413590E-06 +9.143993E-03 +1.510114E-05 +5.630486E-03 +7.481628E-06 +8.090881E-03 +1.407277E-05 +6.451248E-03 +9.019754E-06 +8.432893E-03 +1.236291E-05 +7.535742E-03 +9.713557E-06 +4.055813E-03 +2.764876E-06 +6.361136E-03 +7.935395E-06 +7.066013E-03 +9.687252E-06 +8.347614E-03 +1.322030E-05 +5.583607E-03 +6.318991E-06 +9.734817E-03 +1.915868E-05 +9.117770E-03 +1.299951E-05 +5.466583E-03 +5.814486E-06 +6.377661E-03 +5.982386E-06 +1.066356E-02 +1.915872E-05 +1.205945E-02 +1.894758E-05 +9.934821E-03 +1.678379E-05 +1.138156E-02 +2.321476E-05 +1.063324E-02 +1.739239E-05 +8.377153E-03 +1.072894E-05 +1.600249E-02 +3.173041E-05 +1.442818E-02 +3.650694E-05 +1.643458E-02 +2.935759E-05 +1.937762E-02 +5.539763E-05 +8.400592E-03 +1.059830E-05 +1.497133E-02 +3.316378E-05 +1.469275E-02 +3.001660E-05 +1.502203E-02 +2.852008E-05 +9.750216E-03 +1.395013E-05 +1.497859E-02 +2.421550E-05 +2.111839E-02 +6.023324E-05 +1.358782E-02 +2.820256E-05 +1.250078E-02 +2.294909E-05 +1.058650E-02 +1.688760E-05 +1.488385E-02 +2.666627E-05 +1.927781E-02 +5.429379E-05 +1.208022E-02 +2.250992E-05 +1.497153E-02 +2.676884E-05 +1.244590E-02 +2.756211E-05 +9.989045E-03 +1.303571E-05 +8.894574E-03 +1.174122E-05 +1.938283E-02 +4.239857E-05 +1.804394E-02 +3.515511E-05 +1.337739E-02 +2.482975E-05 +1.487943E-02 +3.347708E-05 +1.110033E-02 +2.136237E-05 +1.333452E-02 +2.308294E-05 +1.635319E-02 +3.229248E-05 +8.693802E-03 +1.542452E-05 +1.031414E-02 +2.112585E-05 +1.838966E-02 +4.539908E-05 +2.354073E-02 +7.698141E-05 +1.080321E-02 +1.831625E-05 +2.112481E-02 +6.253585E-05 +2.050287E-02 +5.388829E-05 +1.779381E-02 +3.937477E-05 +1.477468E-02 +2.411115E-05 +1.293051E-02 +2.250585E-05 +1.609738E-02 +3.396791E-05 +2.681377E-02 +8.749523E-05 +1.670204E-02 +4.359534E-05 +2.206205E-02 +6.377754E-05 +1.873639E-02 +5.703093E-05 +1.889950E-02 +5.052682E-05 +1.824219E-02 +6.072963E-05 +9.270805E-03 +9.959479E-06 +1.684688E-02 +3.370730E-05 +1.521705E-02 +2.961236E-05 +1.701708E-02 +4.241891E-05 +1.338529E-02 +2.440114E-05 +2.037312E-02 +5.462555E-05 +1.229143E-02 +1.878363E-05 +1.429618E-02 +3.043241E-05 +1.452304E-02 +3.335612E-05 +1.081202E-02 +1.892516E-05 +1.166461E-02 +2.163556E-05 +9.237578E-03 +1.212749E-05 +1.315603E-02 +2.637907E-05 +1.701531E-02 +4.938074E-05 +1.071566E-02 +1.400306E-05 +6.882737E-03 +1.095801E-05 +9.693556E-03 +1.516152E-05 +1.473076E-02 +4.380304E-05 +1.172802E-02 +2.661846E-05 +1.044100E-02 +1.616180E-05 +1.321485E-02 +2.517015E-05 +1.034434E-02 +2.118831E-05 +1.604723E-02 +3.547683E-05 +1.309313E-02 +2.716364E-05 +1.410482E-02 +2.701123E-05 +1.932682E-02 +4.094043E-05 +1.570824E-02 +3.228547E-05 +1.071500E-02 +2.525484E-05 +9.230951E-03 +1.398163E-05 +1.889558E-02 +4.381257E-05 +1.401925E-02 +2.692560E-05 +9.335801E-03 +1.384367E-05 +1.635939E-02 +3.876884E-05 +9.920998E-03 +1.367019E-05 +1.029500E-02 +1.637783E-05 +8.294680E-03 +1.093734E-05 +1.266183E-02 +2.587245E-05 +1.407777E-02 +2.856187E-05 +1.854542E-02 +4.825382E-05 +5.748894E-03 +8.790611E-06 +6.718806E-03 +1.183924E-05 +8.894787E-03 +1.306300E-05 +9.405707E-03 +1.288762E-05 +8.792692E-03 +1.122248E-05 +1.103181E-02 +1.580934E-05 +2.659005E-03 +1.548241E-06 +7.016434E-03 +7.516622E-06 +7.803753E-03 +1.013698E-05 +5.086094E-03 +7.063507E-06 +6.912737E-03 +6.574511E-06 +6.396947E-03 +6.066584E-06 +3.808735E-03 +2.749937E-06 +1.756683E-03 +8.375727E-07 +5.851836E-03 +1.028488E-05 +4.947448E-03 +5.127717E-06 +2.630989E-03 +1.428143E-06 +2.910935E-03 +1.681876E-06 +1.838842E-03 +8.992911E-07 +1.293684E-03 +6.685764E-07 +3.339457E-03 +3.028553E-06 +4.580626E-03 +4.624997E-06 +8.307235E-03 +1.674431E-05 +4.486573E-03 +3.705825E-06 +1.144529E-02 +2.352240E-05 +4.880878E-03 +3.852879E-06 +1.005985E-02 +1.391072E-05 +5.741160E-03 +7.136284E-06 +3.844734E-03 +3.016161E-06 +4.765015E-03 +4.225164E-06 +9.903891E-03 +1.243668E-05 +6.186072E-03 +7.288467E-06 +5.025861E-03 +4.672189E-06 +9.762213E-03 +1.357133E-05 +7.207433E-03 +1.732068E-05 +7.775127E-03 +1.904290E-05 +8.549835E-03 +9.367660E-06 +7.175698E-03 +7.187069E-06 +9.296385E-03 +1.322855E-05 +1.130874E-02 +1.956313E-05 +6.989995E-03 +7.487382E-06 +9.825026E-03 +1.567524E-05 +8.647918E-03 +1.652352E-05 +1.087355E-02 +1.533263E-05 +8.616514E-03 +1.142788E-05 +7.352790E-03 +1.365573E-05 +1.138586E-02 +2.265717E-05 +8.641472E-03 +1.322858E-05 +1.041352E-02 +1.315105E-05 +7.829927E-03 +1.004051E-05 +1.425328E-02 +2.580893E-05 +8.892806E-03 +1.300336E-05 +7.287566E-03 +1.259700E-05 +1.443032E-02 +3.334244E-05 +1.017849E-02 +1.483161E-05 +1.467996E-02 +3.045887E-05 +5.224154E-03 +5.244222E-06 +9.725108E-03 +1.589220E-05 +7.665836E-03 +1.588331E-05 +1.010342E-02 +1.784078E-05 +9.419018E-03 +1.369817E-05 +8.670373E-03 +1.032775E-05 +1.138937E-02 +1.811885E-05 +1.798735E-02 +4.793175E-05 +1.065784E-02 +1.799829E-05 +1.308082E-02 +2.484335E-05 +1.240918E-02 +2.570768E-05 +1.745339E-02 +5.770116E-05 +9.113925E-03 +1.349884E-05 +1.402932E-02 +2.482802E-05 +1.888352E-02 +4.563824E-05 +1.225796E-02 +2.638006E-05 +6.431220E-03 +8.855282E-06 +4.770081E-03 +4.250052E-06 +1.089652E-02 +1.611332E-05 +8.433574E-03 +1.309921E-05 +8.737584E-03 +1.411637E-05 +1.265065E-02 +2.849634E-05 +6.191713E-03 +9.561153E-06 +1.006364E-02 +1.497675E-05 +5.975885E-03 +7.218506E-06 +8.088755E-03 +1.058200E-05 +1.148407E-02 +1.800324E-05 +8.621138E-03 +1.060417E-05 +6.466931E-03 +5.559033E-06 +5.921299E-03 +7.337435E-06 +1.106199E-02 +1.985630E-05 +1.358816E-02 +2.266472E-05 +9.249095E-03 +1.326487E-05 +1.231097E-02 +2.413051E-05 +1.262777E-02 +2.135896E-05 +1.340058E-02 +2.838546E-05 +5.482441E-03 +5.699830E-06 +9.399780E-03 +1.217503E-05 +1.326355E-02 +3.084524E-05 +1.091665E-02 +1.571125E-05 +9.066945E-03 +1.253097E-05 +1.007715E-02 +1.495997E-05 +1.420187E-02 +3.247816E-05 +8.867918E-03 +1.783720E-05 +1.035797E-02 +1.618714E-05 +1.051439E-02 +1.905852E-05 +9.663711E-03 +1.733227E-05 +6.083326E-03 +8.227985E-06 +8.498983E-03 +1.203506E-05 +6.305066E-03 +7.288313E-06 +7.022938E-03 +1.842350E-05 +5.300040E-03 +6.674218E-06 +1.192288E-02 +2.251146E-05 +1.268268E-02 +2.376464E-05 +1.105252E-02 +1.907200E-05 +1.141409E-02 +2.122429E-05 +6.863367E-03 +9.680619E-06 +9.454583E-03 +1.410784E-05 +6.678539E-03 +7.419299E-06 +5.435679E-03 +5.223001E-06 +5.839983E-03 +7.472675E-06 +4.126792E-03 +4.743950E-06 +6.770400E-03 +9.680068E-06 +6.192936E-03 +7.071171E-06 +5.115501E-03 +7.222293E-06 +9.291347E-03 +2.204886E-05 +9.263101E-03 +2.093887E-05 +4.871234E-03 +4.945479E-06 +7.362790E-03 +1.225470E-05 +4.662289E-03 +6.432463E-06 +3.023591E-03 +2.882907E-06 +3.141104E-03 +2.308920E-06 +4.357737E-03 +7.258711E-06 +6.160322E-03 +8.985831E-06 +2.171491E-03 +1.749207E-06 +6.561643E-03 +8.803272E-06 +7.571781E-03 +1.203184E-05 +7.440169E-03 +1.110403E-05 +5.648646E-03 +5.494924E-06 +5.357281E-03 +6.204706E-06 +1.090071E-02 +2.058466E-05 +8.383241E-03 +1.206302E-05 +5.676127E-03 +7.724753E-06 +7.425364E-03 +1.054573E-05 +5.486371E-03 +8.048247E-06 +8.635014E-03 +1.394706E-05 +9.041685E-03 +1.478222E-05 +8.430211E-03 +1.309974E-05 +9.019663E-03 +1.451788E-05 +1.031929E-02 +1.746481E-05 +8.473885E-03 +1.174896E-05 +7.773439E-03 +1.036634E-05 +6.249343E-03 +6.064341E-06 +7.095661E-03 +1.120516E-05 +8.128270E-03 +7.992625E-06 +8.497285E-03 +1.303653E-05 +9.777637E-03 +1.235924E-05 +9.741495E-03 +1.557086E-05 +7.393292E-03 +1.285346E-05 +9.196281E-03 +1.458607E-05 +8.847877E-03 +1.117609E-05 +9.688267E-03 +1.592845E-05 +8.380207E-03 +9.989138E-06 +6.280642E-03 +9.051451E-06 +5.915732E-03 +6.877346E-06 +7.178298E-03 +7.637799E-06 +1.393362E-02 +3.213127E-05 +1.124851E-02 +1.946971E-05 +7.778231E-03 +8.216708E-06 +1.100977E-02 +1.616695E-05 +9.914677E-03 +1.920656E-05 +1.140639E-02 +1.803697E-05 +9.289048E-03 +2.453446E-05 +1.333524E-02 +2.981179E-05 +1.511863E-02 +3.813471E-05 +1.309031E-02 +3.606896E-05 +9.646063E-03 +1.776204E-05 +1.508239E-02 +3.051447E-05 +1.260645E-02 +2.587693E-05 +1.462482E-02 +3.353264E-05 +1.521268E-02 +3.209409E-05 +1.468435E-02 +2.541208E-05 +1.071159E-02 +1.974334E-05 +2.153100E-02 +5.966820E-05 +1.732644E-02 +4.011287E-05 +1.667843E-02 +3.822452E-05 +1.463217E-02 +3.010523E-05 +1.656645E-02 +5.475637E-05 +1.067989E-02 +1.830023E-05 +8.824628E-03 +1.045690E-05 +2.286417E-02 +6.960907E-05 +1.839696E-02 +4.509087E-05 +1.925060E-02 +3.941153E-05 +2.258451E-02 +6.336171E-05 +1.439116E-02 +3.414902E-05 +1.155750E-02 +1.864626E-05 +1.259396E-02 +2.399348E-05 +1.558812E-02 +4.045055E-05 +1.722120E-02 +4.143410E-05 +1.762002E-02 +3.632759E-05 +7.874101E-03 +8.254184E-06 +1.768575E-02 +3.461006E-05 +1.146683E-02 +1.794910E-05 +9.688500E-03 +1.346720E-05 +2.241492E-02 +6.339022E-05 +1.934312E-02 +4.482690E-05 +1.794148E-02 +3.870190E-05 +1.579372E-02 +3.004235E-05 +1.087259E-02 +1.529755E-05 +1.257568E-02 +2.258086E-05 +1.388017E-02 +3.225403E-05 +1.427934E-02 +2.832685E-05 +1.576751E-02 +4.828020E-05 +9.333555E-03 +1.323683E-05 +1.295220E-02 +2.221784E-05 +1.292944E-02 +2.650558E-05 +1.321910E-02 +2.608639E-05 +1.867794E-02 +5.342650E-05 +1.187778E-02 +2.004699E-05 +1.570348E-02 +3.839194E-05 +7.349983E-03 +1.280817E-05 +1.048335E-02 +1.591520E-05 +1.281254E-02 +2.311657E-05 +9.441415E-03 +1.884897E-05 +7.817420E-03 +1.075829E-05 +7.050894E-03 +8.992796E-06 +1.439696E-02 +2.646431E-05 +9.666048E-03 +1.691859E-05 +1.384058E-02 +2.171361E-05 +1.483968E-02 +2.360714E-05 +6.696329E-03 +8.201920E-06 +1.461109E-02 +3.484250E-05 +1.152968E-02 +2.487151E-05 +1.235571E-02 +1.863282E-05 +1.071843E-02 +2.007060E-05 +1.192423E-02 +2.405436E-05 +5.175335E-03 +5.686680E-06 +6.167308E-03 +6.085033E-06 +6.512706E-03 +7.423219E-06 +1.084502E-02 +2.042988E-05 +1.426237E-02 +3.199412E-05 +9.833550E-03 +1.401763E-05 +1.066371E-02 +2.034673E-05 +1.088205E-02 +1.432050E-05 +1.322884E-03 +6.133009E-07 +3.131323E-03 +2.085873E-06 +7.577039E-03 +1.169415E-05 +3.697020E-03 +2.265535E-06 +8.463691E-04 +7.163407E-07 +4.936343E-03 +4.470816E-06 +2.785210E-03 +2.057770E-06 +4.647148E-03 +1.334765E-05 +4.739139E-03 +4.910528E-06 +2.212737E-03 +9.823784E-07 +3.179311E-03 +2.106597E-06 +5.139877E-03 +6.883127E-06 +6.756613E-03 +1.192459E-05 +9.019603E-03 +1.454516E-05 +7.170921E-03 +1.179166E-05 +1.332204E-02 +2.272315E-05 +1.045555E-02 +1.579302E-05 +1.471762E-02 +2.957336E-05 +6.940743E-03 +6.167781E-06 +9.285093E-03 +1.234474E-05 +5.274768E-03 +9.733764E-06 +9.363326E-03 +1.064273E-05 +1.124025E-02 +1.812349E-05 +1.242897E-02 +2.335802E-05 +1.381362E-02 +3.426304E-05 +9.040314E-03 +1.768352E-05 +8.800291E-03 +1.233677E-05 +6.219799E-03 +6.238154E-06 +9.482593E-03 +1.409322E-05 +1.380779E-02 +2.529043E-05 +1.200427E-02 +2.953271E-05 +1.419132E-02 +3.098266E-05 +1.353906E-02 +2.607804E-05 +1.431241E-02 +2.799048E-05 +1.223915E-02 +2.748804E-05 +1.852083E-02 +5.311250E-05 +1.887810E-02 +5.774443E-05 +1.277722E-02 +2.643979E-05 +8.077414E-03 +1.128725E-05 +1.339142E-02 +2.294610E-05 +1.301300E-02 +2.073634E-05 +1.397830E-02 +3.029223E-05 +1.892762E-02 +4.920518E-05 +1.535394E-02 +4.149745E-05 +1.298011E-02 +2.187906E-05 +1.905806E-02 +4.036737E-05 +1.706919E-02 +3.990119E-05 +1.435454E-02 +2.543584E-05 +1.937779E-02 +5.201021E-05 +2.323117E-02 +6.155812E-05 +1.994685E-02 +5.377319E-05 +1.320573E-02 +2.175679E-05 +1.591133E-02 +3.535892E-05 +2.108852E-02 +6.407539E-05 +1.839423E-02 +4.410414E-05 +2.011863E-02 +4.580140E-05 +1.883453E-02 +4.495207E-05 +2.134485E-02 +5.276746E-05 +1.725640E-02 +4.465566E-05 +2.590341E-02 +8.438375E-05 +2.198626E-02 +5.942456E-05 +1.721832E-02 +3.710932E-05 +1.867389E-02 +4.165207E-05 +2.535786E-02 +8.231711E-05 +2.435788E-02 +7.524302E-05 +2.417986E-02 +7.690249E-05 +3.527942E-02 +1.503529E-04 +2.545610E-02 +7.903560E-05 +2.898461E-02 +1.038511E-04 +2.650130E-02 +7.765544E-05 +3.220034E-02 +1.339104E-04 +2.615617E-02 +8.054223E-05 +1.575566E-02 +3.464485E-05 +1.721242E-02 +3.933144E-05 +2.529147E-02 +7.224719E-05 +2.161550E-02 +5.729706E-05 +3.254276E-02 +1.237101E-04 +2.601524E-02 +7.880812E-05 +2.030934E-02 +5.449343E-05 +2.529817E-02 +7.746587E-05 +2.459558E-02 +7.049178E-05 +2.743013E-02 +1.051976E-04 +2.818835E-02 +9.687328E-05 +3.082240E-02 +1.199245E-04 +1.534318E-02 +3.153431E-05 +1.798131E-02 +4.183178E-05 +1.329898E-02 +2.483181E-05 +1.519124E-02 +3.090643E-05 +2.253493E-02 +6.110325E-05 +1.932903E-02 +5.403216E-05 +2.343651E-02 +6.986521E-05 +1.851194E-02 +4.830851E-05 +2.854734E-02 +1.149020E-04 +3.554508E-02 +1.594168E-04 +2.420896E-02 +8.063001E-05 +2.438815E-02 +6.949914E-05 +1.424242E-02 +3.042725E-05 +1.883095E-02 +4.453941E-05 +1.803807E-02 +5.353218E-05 +1.472433E-02 +2.708169E-05 +2.645673E-02 +1.277462E-04 +1.659156E-02 +4.460790E-05 +1.884914E-02 +5.255122E-05 +1.323181E-02 +3.012118E-05 +2.078655E-02 +7.250952E-05 +1.929529E-02 +4.896056E-05 +1.365072E-02 +2.296122E-05 +1.548320E-02 +3.361702E-05 +1.963984E-02 +5.182163E-05 +1.938728E-02 +4.745111E-05 +1.852813E-02 +4.964750E-05 +1.254203E-02 +2.416303E-05 +1.598636E-02 +3.867130E-05 +1.557994E-02 +3.560554E-05 +8.834017E-03 +1.069678E-05 +9.484032E-03 +1.565529E-05 +1.303143E-02 +2.234676E-05 +2.200867E-02 +5.927220E-05 +1.598709E-02 +2.961814E-05 +1.402800E-02 +2.779038E-05 +4.378255E-03 +4.055161E-06 +6.657558E-03 +8.689849E-06 +5.742424E-03 +6.994090E-06 +1.690917E-03 +9.618234E-07 +6.422205E-03 +6.220083E-06 +1.098008E-02 +1.552449E-05 +4.852648E-03 +6.005700E-06 +4.131316E-03 +2.940200E-06 +5.377384E-03 +9.958808E-06 +7.493944E-03 +1.136740E-05 +5.679683E-03 +5.334788E-06 +9.041948E-03 +1.233892E-05 +1.621598E-02 +3.896922E-05 +9.707536E-03 +1.580953E-05 +9.796285E-03 +1.170913E-05 +1.038632E-02 +1.400251E-05 +1.854616E-02 +3.938948E-05 +1.637195E-02 +3.459637E-05 +1.090541E-02 +1.920540E-05 +1.554833E-02 +3.590212E-05 +4.272073E-03 +3.682734E-06 +9.074265E-03 +9.996509E-06 +1.177873E-02 +2.562780E-05 +1.154733E-02 +1.708677E-05 +2.122244E-02 +5.095551E-05 +1.703089E-02 +4.517001E-05 +1.005035E-02 +1.266093E-05 +1.780384E-02 +3.747413E-05 +1.376515E-02 +3.253018E-05 +1.530894E-02 +2.892052E-05 +2.606504E-02 +7.859853E-05 +2.255541E-02 +6.286365E-05 +1.918774E-02 +4.676979E-05 +2.519231E-02 +7.640422E-05 +1.664088E-02 +4.401309E-05 +1.584636E-02 +3.452858E-05 +2.616309E-02 +8.630269E-05 +2.255699E-02 +5.940173E-05 +2.236967E-02 +6.994996E-05 +2.248979E-02 +5.377855E-05 +2.341480E-02 +6.489990E-05 +2.206893E-02 +5.500117E-05 +3.339387E-02 +1.332827E-04 +2.791990E-02 +9.540192E-05 +2.717893E-02 +9.827563E-05 +2.822648E-02 +9.247065E-05 +2.172258E-02 +6.122060E-05 +2.728508E-02 +9.267319E-05 +2.826253E-02 +1.031269E-04 +2.187117E-02 +5.283388E-05 +2.020422E-02 +6.258085E-05 +2.760119E-02 +8.854689E-05 +2.549801E-02 +7.868954E-05 +3.220341E-02 +1.492987E-04 +3.173533E-02 +1.221411E-04 +3.585220E-02 +1.462868E-04 +2.903224E-02 +9.451319E-05 +3.829574E-02 +1.873248E-04 +3.086935E-02 +1.256218E-04 +3.176725E-02 +1.374912E-04 +2.621060E-02 +7.855573E-05 +3.291329E-02 +1.248943E-04 +2.777869E-02 +9.696220E-05 +2.695184E-02 +8.169195E-05 +3.242055E-02 +1.203522E-04 +3.779282E-02 +1.712919E-04 +3.692252E-02 +1.722327E-04 +2.748845E-02 +9.639756E-05 +3.175151E-02 +1.162038E-04 +3.286221E-02 +1.232662E-04 +3.712727E-02 +1.594838E-04 +4.431598E-02 +2.588766E-04 +2.816960E-02 +9.502113E-05 +2.976286E-02 +1.142861E-04 +2.180841E-02 +6.585707E-05 +2.719208E-02 +8.542344E-05 +3.801560E-02 +1.668348E-04 +3.413937E-02 +1.429112E-04 +3.175514E-02 +1.235214E-04 +4.203652E-02 +2.192502E-04 +4.877746E-02 +2.744258E-04 +5.692679E-02 +3.692246E-04 +4.818489E-02 +2.687441E-04 +5.535578E-02 +3.290118E-04 +3.156612E-02 +1.123567E-04 +2.679829E-02 +7.787807E-05 +2.954264E-02 +1.270123E-04 +2.476226E-02 +8.030343E-05 +3.814973E-02 +1.578272E-04 +4.016143E-02 +2.884730E-04 +4.229195E-02 +2.061337E-04 +2.947005E-02 +1.041482E-04 +3.357567E-02 +1.360735E-04 +4.664871E-02 +2.552612E-04 +4.112621E-02 +2.176987E-04 +3.595856E-02 +1.956542E-04 +1.913431E-02 +5.063581E-05 +2.330523E-02 +6.230393E-05 +2.045993E-02 +5.592751E-05 +2.473756E-02 +7.625570E-05 +3.674309E-02 +1.672365E-04 +3.204595E-02 +1.157121E-04 +2.629494E-02 +8.519728E-05 +3.002442E-02 +1.205283E-04 +3.236353E-02 +1.309526E-04 +3.239381E-02 +1.479481E-04 +2.659107E-02 +1.086535E-04 +3.565570E-02 +1.622239E-04 +1.031682E-02 +1.492807E-05 +1.580618E-02 +2.893579E-05 +1.666675E-02 +4.393186E-05 +2.024456E-02 +4.734254E-05 +1.651767E-02 +4.977631E-05 +1.887559E-02 +4.409518E-05 +1.508773E-02 +4.644738E-05 +1.388725E-02 +2.554677E-05 +2.369485E-02 +7.387938E-05 +1.868167E-02 +4.664973E-05 +1.516685E-02 +3.321346E-05 +1.963316E-02 +4.662537E-05 +7.052241E-03 +1.080582E-05 +1.204334E-02 +2.356212E-05 +7.618798E-03 +1.308303E-05 +1.218334E-02 +2.230559E-05 +1.192185E-02 +2.127660E-05 +1.044557E-02 +1.520178E-05 +4.348002E-03 +4.867274E-06 +9.181379E-03 +1.456359E-05 +8.481267E-03 +1.556887E-05 +5.867984E-03 +5.323949E-06 +1.523208E-02 +3.002171E-05 +8.902081E-03 +1.728737E-05 +1.212351E-02 +2.267329E-05 +1.158769E-02 +1.826918E-05 +5.557893E-03 +6.873951E-06 +1.030077E-02 +1.814127E-05 +1.216476E-02 +2.168097E-05 +1.280341E-02 +2.462766E-05 +7.553244E-03 +7.549456E-06 +9.275611E-03 +9.489655E-06 +7.606773E-03 +8.958010E-06 +9.160622E-03 +1.424787E-05 +1.133109E-02 +1.611610E-05 +7.409008E-03 +1.208115E-05 +2.084102E-02 +5.449907E-05 +2.465743E-02 +1.037751E-04 +2.310657E-02 +6.292924E-05 +2.801769E-02 +8.512445E-05 +2.049117E-02 +6.630728E-05 +1.395829E-02 +3.118581E-05 +2.735901E-02 +9.218170E-05 +2.177632E-02 +5.817883E-05 +1.932991E-02 +6.388604E-05 +2.326591E-02 +8.330336E-05 +2.546379E-02 +9.605909E-05 +1.830716E-02 +5.090147E-05 +3.960142E-02 +1.859660E-04 +2.348343E-02 +6.600054E-05 +2.909393E-02 +1.040812E-04 +3.586926E-02 +1.451039E-04 +2.269127E-02 +6.430762E-05 +2.691696E-02 +8.449728E-05 +4.229624E-02 +2.362055E-04 +4.471419E-02 +2.231402E-04 +3.407449E-02 +1.370223E-04 +3.586700E-02 +1.483496E-04 +3.803403E-02 +1.652852E-04 +3.820565E-02 +1.619415E-04 +2.921534E-02 +1.128913E-04 +4.098638E-02 +1.981151E-04 +3.611801E-02 +1.596274E-04 +4.036543E-02 +1.787815E-04 +3.018584E-02 +1.080246E-04 +4.026732E-02 +1.932383E-04 +4.637639E-02 +3.369042E-04 +4.901208E-02 +2.912517E-04 +5.221514E-02 +2.936532E-04 +5.298382E-02 +3.167761E-04 +4.141488E-02 +1.913012E-04 +5.078383E-02 +2.957356E-04 +3.104830E-02 +1.114729E-04 +4.570836E-02 +2.306958E-04 +2.697314E-02 +8.551540E-05 +3.590745E-02 +1.369825E-04 +4.416767E-02 +2.348955E-04 +3.878026E-02 +1.683331E-04 +3.635274E-02 +1.469492E-04 +5.095760E-02 +3.033151E-04 +5.419363E-02 +3.231656E-04 +6.111133E-02 +4.092896E-04 +5.080100E-02 +2.813520E-04 +6.152776E-02 +4.073105E-04 +3.751766E-02 +1.468483E-04 +3.277827E-02 +1.186335E-04 +3.710633E-02 +1.751177E-04 +5.323020E-02 +3.420073E-04 +3.201431E-02 +1.550803E-04 +5.882138E-02 +4.307388E-04 +4.562728E-02 +2.741025E-04 +4.436946E-02 +2.582142E-04 +4.128151E-02 +1.889531E-04 +5.761773E-02 +4.256437E-04 +4.986009E-02 +2.652036E-04 +5.753376E-02 +3.668636E-04 +3.464308E-02 +1.308318E-04 +3.597366E-02 +1.880711E-04 +3.783475E-02 +1.677422E-04 +4.507477E-02 +2.257889E-04 +3.512550E-02 +1.623708E-04 +4.440361E-02 +2.237977E-04 +4.763862E-02 +2.507592E-04 +4.245582E-02 +2.037194E-04 +3.865696E-02 +1.809637E-04 +4.216341E-02 +1.962900E-04 +5.099828E-02 +2.952246E-04 +5.108812E-02 +2.920996E-04 +2.655713E-02 +8.104377E-05 +3.189652E-02 +1.226231E-04 +3.163248E-02 +1.587616E-04 +2.509589E-02 +9.570491E-05 +4.297892E-02 +2.277676E-04 +3.642828E-02 +1.647058E-04 +3.007066E-02 +1.231652E-04 +3.132243E-02 +1.486680E-04 +3.188231E-02 +1.196363E-04 +4.753178E-02 +2.731076E-04 +2.908004E-02 +1.035304E-04 +2.727262E-02 +9.600226E-05 +1.855747E-02 +5.837677E-05 +2.435306E-02 +7.097335E-05 +2.204917E-02 +6.488149E-05 +2.268670E-02 +6.926881E-05 +2.470896E-02 +8.507493E-05 +2.736268E-02 +9.366711E-05 +1.453619E-02 +2.821293E-05 +1.989468E-02 +5.291966E-05 +2.569258E-02 +8.578609E-05 +2.226465E-02 +6.565828E-05 +2.252517E-02 +7.081452E-05 +1.855256E-02 +4.738776E-05 +1.203698E-02 +2.579555E-05 +1.218962E-02 +2.270495E-05 +1.171765E-02 +2.354905E-05 +8.779187E-03 +1.212571E-05 +1.425888E-02 +2.553189E-05 +1.169957E-02 +2.644501E-05 +1.052860E-02 +1.949914E-05 +5.907471E-03 +5.068540E-06 +1.275403E-02 +2.624760E-05 +1.148436E-02 +1.794213E-05 +1.018673E-02 +1.501340E-05 +1.783660E-02 +4.785080E-05 +1.016197E-02 +2.293166E-05 +8.941927E-03 +1.192991E-05 +6.602581E-03 +1.272161E-05 +1.174062E-02 +2.147543E-05 +1.526300E-02 +3.260204E-05 +1.686817E-02 +4.102027E-05 +1.467939E-02 +2.968059E-05 +1.601430E-02 +4.562808E-05 +9.165391E-03 +2.688624E-05 +9.663957E-03 +1.372277E-05 +1.287992E-02 +2.365195E-05 +9.579531E-03 +1.375180E-05 +2.469585E-02 +8.049487E-05 +2.845287E-02 +1.112732E-04 +1.767051E-02 +4.658157E-05 +2.485448E-02 +9.432058E-05 +1.238872E-02 +2.846828E-05 +1.889711E-02 +4.468197E-05 +3.099403E-02 +1.059405E-04 +2.259916E-02 +7.077471E-05 +2.695314E-02 +9.575430E-05 +2.211342E-02 +5.413822E-05 +2.224612E-02 +7.249655E-05 +1.773084E-02 +4.592694E-05 +3.194210E-02 +1.064003E-04 +2.971760E-02 +9.736956E-05 +3.499652E-02 +1.826230E-04 +4.850239E-02 +2.738683E-04 +3.305773E-02 +1.168139E-04 +3.506155E-02 +1.587282E-04 +3.676758E-02 +1.484870E-04 +4.676291E-02 +2.525569E-04 +3.590431E-02 +1.478484E-04 +3.835973E-02 +1.689943E-04 +4.592471E-02 +2.353405E-04 +4.213441E-02 +2.024568E-04 +4.148586E-02 +1.780338E-04 +4.501161E-02 +2.189422E-04 +4.546973E-02 +2.294416E-04 +5.445339E-02 +3.211478E-04 +4.091696E-02 +1.919828E-04 +4.547941E-02 +2.523329E-04 +5.386399E-02 +3.097517E-04 +5.805028E-02 +3.886410E-04 +4.323647E-02 +2.210891E-04 +5.481511E-02 +3.380385E-04 +5.588950E-02 +3.728116E-04 +4.521068E-02 +2.655202E-04 +4.323965E-02 +1.976109E-04 +4.853174E-02 +2.734839E-04 +5.925107E-02 +4.092840E-04 +6.126965E-02 +3.889545E-04 +5.496039E-02 +3.536070E-04 +5.043703E-02 +3.116190E-04 +5.642187E-02 +3.765290E-04 +6.063856E-02 +4.379295E-04 +5.195487E-02 +3.214080E-04 +6.938655E-02 +5.412456E-04 +6.384563E-02 +4.345441E-04 +7.340916E-02 +5.829419E-04 +4.160832E-02 +1.915303E-04 +4.400244E-02 +2.364017E-04 +5.387088E-02 +3.278923E-04 +5.794972E-02 +3.768932E-04 +4.823866E-02 +2.869653E-04 +5.581812E-02 +3.628216E-04 +5.507172E-02 +3.230172E-04 +6.302356E-02 +4.527401E-04 +5.707918E-02 +3.888513E-04 +4.754358E-02 +2.594617E-04 +6.541199E-02 +4.781326E-04 +6.028104E-02 +4.146449E-04 +3.451579E-02 +1.431485E-04 +3.241942E-02 +1.223581E-04 +4.685494E-02 +2.525308E-04 +4.111890E-02 +2.121316E-04 +4.153961E-02 +1.996497E-04 +5.816750E-02 +3.609870E-04 +3.677652E-02 +1.668470E-04 +4.696518E-02 +2.600495E-04 +3.377120E-02 +1.501347E-04 +4.376838E-02 +2.325356E-04 +5.222808E-02 +3.054620E-04 +5.928320E-02 +4.267763E-04 +2.991812E-02 +1.056949E-04 +3.616946E-02 +1.524179E-04 +3.177703E-02 +1.168362E-04 +4.705585E-02 +2.646056E-04 +3.665252E-02 +1.695105E-04 +4.766781E-02 +2.674389E-04 +3.202832E-02 +1.073493E-04 +2.751650E-02 +9.309837E-05 +4.818224E-02 +2.392320E-04 +3.403290E-02 +1.418131E-04 +4.574016E-02 +2.354785E-04 +4.773050E-02 +2.476124E-04 +1.973857E-02 +5.421533E-05 +2.110340E-02 +6.009155E-05 +2.365572E-02 +6.648519E-05 +2.131581E-02 +5.365256E-05 +2.548189E-02 +8.296044E-05 +2.738380E-02 +8.103041E-05 +1.857273E-02 +4.206503E-05 +2.430428E-02 +7.766038E-05 +1.413939E-02 +2.821225E-05 +2.111430E-02 +5.198944E-05 +2.690085E-02 +9.577166E-05 +3.477173E-02 +1.518451E-04 +1.694126E-02 +4.610916E-05 +1.802237E-02 +4.677578E-05 +1.547843E-02 +3.071140E-05 +1.258621E-02 +2.676730E-05 +1.480772E-02 +2.870448E-05 +1.612853E-02 +3.275094E-05 +1.269558E-02 +2.294471E-05 +1.222544E-02 +1.845380E-05 +1.456829E-02 +3.311358E-05 +9.857513E-03 +1.669207E-05 +1.626604E-02 +4.458605E-05 +1.611973E-02 +3.998382E-05 +1.971005E-02 +6.046116E-05 +1.431380E-02 +2.594436E-05 +1.824132E-02 +5.495026E-05 +1.868711E-02 +5.257059E-05 +1.452558E-02 +2.646510E-05 +1.767521E-02 +4.157062E-05 +1.224286E-02 +2.048681E-05 +1.303634E-02 +2.950766E-05 +1.330541E-02 +2.767230E-05 +1.068270E-02 +1.441894E-05 +1.784826E-02 +4.556976E-05 +1.384211E-02 +2.825659E-05 +1.729138E-02 +3.675164E-05 +2.243899E-02 +6.004831E-05 +2.715655E-02 +9.746046E-05 +2.570504E-02 +8.920071E-05 +1.697516E-02 +3.974905E-05 +1.660121E-02 +3.254815E-05 +2.224450E-02 +5.768880E-05 +2.530951E-02 +9.164893E-05 +1.840321E-02 +4.291921E-05 +2.017760E-02 +6.034117E-05 +2.049468E-02 +4.717679E-05 +2.282381E-02 +6.631028E-05 +2.767431E-02 +8.578573E-05 +3.024946E-02 +1.035261E-04 +3.587885E-02 +1.385980E-04 +4.511890E-02 +2.188810E-04 +2.993143E-02 +1.172685E-04 +4.054681E-02 +1.947113E-04 +3.798858E-02 +1.756458E-04 +4.431323E-02 +2.215003E-04 +3.189602E-02 +1.184446E-04 +3.858052E-02 +1.789441E-04 +4.477428E-02 +2.243938E-04 +4.703586E-02 +2.423313E-04 +3.435009E-02 +1.302766E-04 +4.912269E-02 +2.876019E-04 +3.586050E-02 +1.601671E-04 +5.202288E-02 +2.962633E-04 +4.354503E-02 +2.302813E-04 +4.484413E-02 +2.193914E-04 +4.626090E-02 +2.295773E-04 +5.272085E-02 +3.140576E-04 +4.016476E-02 +1.851520E-04 +4.698312E-02 +2.700090E-04 +7.091623E-02 +6.301431E-04 +4.767851E-02 +2.507174E-04 +4.786618E-02 +2.609399E-04 +4.038170E-02 +1.767402E-04 +4.773992E-02 +2.552553E-04 +6.553326E-02 +4.533702E-04 +4.409668E-02 +2.246932E-04 +5.516788E-02 +3.459366E-04 +5.575453E-02 +3.327095E-04 +6.234876E-02 +4.350389E-04 +4.468174E-02 +2.279110E-04 +5.066531E-02 +2.919067E-04 +7.038547E-02 +5.211120E-04 +6.314941E-02 +4.264819E-04 +4.552569E-02 +2.253455E-04 +4.441783E-02 +2.383583E-04 +5.471130E-02 +3.515655E-04 +5.570461E-02 +3.610859E-04 +4.732130E-02 +2.515536E-04 +5.830395E-02 +4.045076E-04 +4.928927E-02 +2.534507E-04 +4.443354E-02 +2.155311E-04 +4.739067E-02 +2.296684E-04 +4.805589E-02 +2.422571E-04 +6.278404E-02 +4.449155E-04 +6.952048E-02 +5.145532E-04 +2.516418E-02 +7.500451E-05 +3.118980E-02 +1.112167E-04 +4.421923E-02 +2.460515E-04 +4.297090E-02 +2.413819E-04 +3.779702E-02 +1.857046E-04 +5.299210E-02 +3.257368E-04 +4.026655E-02 +1.807099E-04 +4.206085E-02 +2.256535E-04 +4.079656E-02 +1.987081E-04 +3.610266E-02 +1.649391E-04 +4.381846E-02 +2.263935E-04 +4.980200E-02 +2.864882E-04 +2.860174E-02 +1.712915E-04 +2.445643E-02 +1.020759E-04 +3.878477E-02 +2.026049E-04 +2.480236E-02 +6.838491E-05 +2.734325E-02 +9.461308E-05 +3.693833E-02 +1.822458E-04 +2.490103E-02 +7.329360E-05 +2.677818E-02 +8.305017E-05 +3.264724E-02 +1.437491E-04 +3.715999E-02 +2.239488E-04 +2.373224E-02 +6.329401E-05 +3.900048E-02 +1.863015E-04 +1.125664E-02 +2.181811E-05 +2.161924E-02 +7.195899E-05 +1.744174E-02 +4.273755E-05 +1.238666E-02 +2.145334E-05 +2.141496E-02 +5.796334E-05 +3.027096E-02 +9.721558E-05 +2.034339E-02 +5.581306E-05 +1.730093E-02 +4.542569E-05 +2.661993E-02 +8.452374E-05 +2.161864E-02 +5.465888E-05 +1.450249E-02 +2.452960E-05 +2.302180E-02 +6.121219E-05 +6.340596E-03 +5.499932E-06 +9.140384E-03 +1.585008E-05 +1.397492E-02 +2.598945E-05 +1.189682E-02 +2.167082E-05 +1.311861E-02 +2.016097E-05 +1.750898E-02 +4.671329E-05 +9.795781E-03 +1.975542E-05 +1.094278E-02 +1.976709E-05 +1.639501E-02 +3.446322E-05 +7.320291E-03 +7.206036E-06 +1.849111E-02 +4.335473E-05 +1.434342E-02 +2.991316E-05 +1.167361E-02 +1.759595E-05 +9.859610E-03 +1.289330E-05 +1.133762E-02 +1.561793E-05 +1.865540E-02 +4.343736E-05 +1.350518E-02 +2.129333E-05 +1.358916E-02 +2.271382E-05 +9.345990E-03 +1.288554E-05 +1.065558E-02 +1.661140E-05 +8.770677E-03 +1.373474E-05 +1.321675E-02 +2.139500E-05 +1.306520E-02 +2.539346E-05 +1.129556E-02 +2.247168E-05 +2.256971E-02 +6.489740E-05 +2.030940E-02 +5.625582E-05 +2.024779E-02 +5.494975E-05 +1.906346E-02 +4.047418E-05 +2.207434E-02 +6.757473E-05 +1.730595E-02 +3.788068E-05 +2.519625E-02 +9.116269E-05 +2.094102E-02 +5.386236E-05 +2.252706E-02 +7.123740E-05 +2.249589E-02 +6.348244E-05 +1.677894E-02 +4.502916E-05 +1.191569E-02 +2.092636E-05 +3.193092E-02 +1.066907E-04 +3.474315E-02 +1.354003E-04 +3.428457E-02 +1.357392E-04 +5.095478E-02 +3.135854E-04 +2.785938E-02 +1.094102E-04 +2.524070E-02 +7.421058E-05 +3.410453E-02 +1.325498E-04 +4.419349E-02 +2.287531E-04 +3.121966E-02 +1.145504E-04 +3.172565E-02 +1.576778E-04 +3.732684E-02 +1.794004E-04 +2.798822E-02 +9.904213E-05 +3.829890E-02 +1.745254E-04 +3.669187E-02 +1.481631E-04 +3.831832E-02 +1.640348E-04 +4.717292E-02 +2.431524E-04 +3.246900E-02 +1.090875E-04 +3.181397E-02 +1.110646E-04 +3.422430E-02 +1.455143E-04 +4.595899E-02 +2.593546E-04 +2.943781E-02 +1.144304E-04 +4.083225E-02 +2.153138E-04 +4.861114E-02 +2.668189E-04 +4.566953E-02 +2.275971E-04 +4.762605E-02 +2.702276E-04 +3.885235E-02 +1.678236E-04 +4.746492E-02 +2.732016E-04 +6.187919E-02 +3.977228E-04 +3.385168E-02 +1.655806E-04 +3.779606E-02 +1.742919E-04 +4.344441E-02 +2.144777E-04 +4.983722E-02 +2.780628E-04 +3.805659E-02 +1.869986E-04 +3.881150E-02 +1.693755E-04 +5.243613E-02 +3.131126E-04 +4.108551E-02 +1.935253E-04 +3.562260E-02 +1.423362E-04 +3.787549E-02 +1.654425E-04 +4.885818E-02 +2.578691E-04 +5.332653E-02 +3.213342E-04 +4.348495E-02 +2.331286E-04 +4.663540E-02 +2.474672E-04 +3.285731E-02 +1.375774E-04 +4.576846E-02 +2.311007E-04 +3.184404E-02 +1.192332E-04 +3.998156E-02 +1.844262E-04 +5.607513E-02 +3.422109E-04 +4.953587E-02 +2.676057E-04 +3.693477E-02 +1.700381E-04 +2.948894E-02 +1.003101E-04 +5.540578E-02 +3.851845E-04 +5.314370E-02 +3.109412E-04 +4.109329E-02 +1.998923E-04 +5.093669E-02 +3.059425E-04 +4.209028E-02 +2.361378E-04 +4.465662E-02 +2.120794E-04 +2.708725E-02 +9.631361E-05 +3.635562E-02 +1.595262E-04 +4.238804E-02 +1.947726E-04 +3.974596E-02 +1.806688E-04 +2.982744E-02 +1.207685E-04 +3.283297E-02 +1.354648E-04 +3.271957E-02 +1.397951E-04 +2.724542E-02 +1.015777E-04 +3.609538E-02 +1.698517E-04 +3.335710E-02 +1.624664E-04 +2.079895E-02 +5.610101E-05 +2.603309E-02 +9.493586E-05 +2.597898E-02 +9.783976E-05 +3.135251E-02 +1.402609E-04 +2.775791E-02 +9.666104E-05 +3.244893E-02 +1.414683E-04 +1.736161E-02 +4.120267E-05 +2.103660E-02 +6.662057E-05 +2.254942E-02 +6.127994E-05 +2.617237E-02 +9.655322E-05 +1.879302E-02 +4.046759E-05 +2.239207E-02 +7.270900E-05 +1.582884E-02 +3.421542E-05 +1.701627E-02 +3.287993E-05 +1.586730E-02 +3.071759E-05 +1.637662E-02 +4.285548E-05 +1.575516E-02 +2.967636E-05 +1.749637E-02 +4.429182E-05 +1.377991E-02 +2.869990E-05 +1.666042E-02 +3.900259E-05 +1.590173E-02 +4.041443E-05 +1.533466E-02 +3.740187E-05 +1.242820E-02 +2.230617E-05 +2.005763E-02 +5.559139E-05 +1.888435E-02 +5.293569E-05 +1.437606E-02 +2.992754E-05 +1.160735E-02 +2.488650E-05 +1.903862E-02 +4.929965E-05 +1.792944E-02 +4.623131E-05 +1.925927E-02 +4.967790E-05 +1.197483E-02 +1.865556E-05 +7.572584E-03 +1.282465E-05 +1.344056E-02 +2.673348E-05 +1.049282E-02 +1.487580E-05 +1.018581E-02 +1.491092E-05 +9.650534E-03 +1.458568E-05 +7.696745E-03 +8.956471E-06 +6.117465E-03 +6.145859E-06 +7.711888E-03 +1.379326E-05 +7.178538E-03 +8.529096E-06 +7.013352E-03 +9.358596E-06 +5.223833E-03 +4.743484E-06 +1.958755E-02 +5.840140E-05 +1.514889E-02 +3.048083E-05 +1.420009E-02 +3.392782E-05 +1.779423E-02 +4.000672E-05 +9.916829E-03 +1.600897E-05 +1.084516E-02 +1.883449E-05 +1.721403E-02 +3.892250E-05 +1.697631E-02 +5.336366E-05 +1.126561E-02 +1.779695E-05 +1.183784E-02 +2.042908E-05 +1.279900E-02 +2.278884E-05 +1.221352E-02 +2.185990E-05 +2.126137E-02 +5.259427E-05 +1.948422E-02 +7.413728E-05 +2.691940E-02 +7.987754E-05 +2.366460E-02 +7.849119E-05 +1.493129E-02 +3.458121E-05 +2.528845E-02 +7.805956E-05 +1.941301E-02 +4.532019E-05 +3.315469E-02 +1.407045E-04 +1.764622E-02 +4.338977E-05 +1.952377E-02 +5.147550E-05 +2.600704E-02 +9.058738E-05 +2.442799E-02 +7.377464E-05 +2.298511E-02 +6.212241E-05 +2.519641E-02 +9.638931E-05 +3.975880E-02 +1.694798E-04 +3.835063E-02 +1.723954E-04 +2.433477E-02 +7.177972E-05 +2.711003E-02 +1.279711E-04 +3.083661E-02 +1.018837E-04 +4.207502E-02 +2.089394E-04 +2.844391E-02 +9.560578E-05 +2.835547E-02 +8.648090E-05 +5.190679E-02 +2.829647E-04 +3.607591E-02 +1.406622E-04 +2.726024E-02 +9.295552E-05 +2.334992E-02 +7.837059E-05 +2.556006E-02 +8.066549E-05 +3.157571E-02 +1.018377E-04 +2.717890E-02 +9.754656E-05 +3.812328E-02 +1.529731E-04 +3.196833E-02 +1.246738E-04 +3.749985E-02 +1.546562E-04 +1.861417E-02 +4.193655E-05 +2.827800E-02 +8.681001E-05 +3.521111E-02 +1.537273E-04 +3.631214E-02 +1.510528E-04 +3.010902E-02 +1.101278E-04 +2.898513E-02 +1.002289E-04 +3.759216E-02 +1.686797E-04 +3.924809E-02 +1.926092E-04 +3.000742E-02 +1.032469E-04 +3.063104E-02 +1.058005E-04 +3.016836E-02 +1.406736E-04 +3.811226E-02 +2.142070E-04 +3.067660E-02 +1.137129E-04 +2.919174E-02 +9.744001E-05 +4.351818E-02 +2.481411E-04 +3.459089E-02 +1.418237E-04 +2.354519E-02 +7.125933E-05 +2.341512E-02 +7.530145E-05 +3.423411E-02 +1.362388E-04 +3.807351E-02 +1.835906E-04 +3.060066E-02 +1.306426E-04 +3.887634E-02 +1.767107E-04 +2.972630E-02 +1.452173E-04 +2.761804E-02 +8.313790E-05 +2.564981E-02 +1.041595E-04 +2.302814E-02 +5.748532E-05 +3.430159E-02 +1.266003E-04 +3.080546E-02 +1.097842E-04 +1.862840E-02 +4.692046E-05 +2.212362E-02 +5.769304E-05 +3.055531E-02 +1.529521E-04 +2.289574E-02 +8.233761E-05 +2.656172E-02 +8.446802E-05 +3.583300E-02 +1.541747E-04 +2.557682E-02 +7.916517E-05 +2.097606E-02 +5.055022E-05 +2.228757E-02 +5.988269E-05 +1.816051E-02 +3.901578E-05 +2.325555E-02 +7.127170E-05 +2.918248E-02 +1.039399E-04 +1.305527E-02 +2.604090E-05 +1.318002E-02 +2.893713E-05 +1.574393E-02 +3.521171E-05 +1.414192E-02 +3.552473E-05 +1.633140E-02 +3.849962E-05 +1.643542E-02 +4.093687E-05 +1.215108E-02 +2.596067E-05 +1.663208E-02 +4.623828E-05 +1.519499E-02 +2.784484E-05 +1.392851E-02 +2.190759E-05 +2.267580E-02 +6.466320E-05 +2.215409E-02 +7.872980E-05 +1.106097E-02 +1.935578E-05 +1.318957E-02 +2.458468E-05 +1.432387E-02 +2.771689E-05 +1.302310E-02 +2.533330E-05 +1.818189E-02 +4.776340E-05 +1.401528E-02 +2.698770E-05 +3.589051E-03 +3.157955E-06 +9.717553E-03 +1.921247E-05 +8.432737E-03 +1.168760E-05 +8.867899E-03 +2.125223E-05 +1.176987E-02 +2.796774E-05 +1.387858E-02 +2.900888E-05 +7.333775E-03 +9.493537E-06 +5.494780E-03 +7.270347E-06 +8.505259E-03 +1.106187E-05 +5.349113E-03 +6.272249E-06 +7.278213E-03 +7.362414E-06 +8.521400E-03 +1.020574E-05 +8.308309E-03 +1.075116E-05 +8.167064E-03 +1.109423E-05 +5.533013E-03 +6.466675E-06 +5.112442E-03 +8.851249E-06 +5.870076E-03 +6.648936E-06 +3.929558E-03 +2.494118E-06 +1.248728E-02 +2.662149E-05 +7.689572E-03 +1.632791E-05 +1.064286E-02 +1.731638E-05 +8.865827E-03 +2.182318E-05 +1.060594E-02 +1.974250E-05 +1.107000E-02 +1.741690E-05 +1.046576E-02 +1.304525E-05 +8.923758E-03 +1.382295E-05 +6.048588E-03 +6.515013E-06 +1.140457E-02 +1.772344E-05 +1.071605E-02 +2.320839E-05 +1.108521E-02 +2.146136E-05 +1.372658E-02 +3.150815E-05 +1.185879E-02 +2.592177E-05 +1.328057E-02 +2.007755E-05 +2.366818E-02 +6.240710E-05 +1.310524E-02 +2.483124E-05 +1.756288E-02 +3.846799E-05 +1.953925E-02 +4.224682E-05 +2.714173E-02 +9.200317E-05 +2.089836E-02 +5.417932E-05 +1.880252E-02 +4.633361E-05 +1.825440E-02 +4.676871E-05 +1.703893E-02 +3.290578E-05 +1.536560E-02 +2.501324E-05 +1.723409E-02 +4.375407E-05 +2.378506E-02 +6.856927E-05 +2.116439E-02 +5.565273E-05 +1.694042E-02 +5.241605E-05 +1.860566E-02 +4.783232E-05 +1.867229E-02 +4.443429E-05 +2.347238E-02 +6.225289E-05 +1.240017E-02 +2.472321E-05 +1.834566E-02 +5.076889E-05 +2.345212E-02 +6.899204E-05 +1.744726E-02 +4.012671E-05 +2.139472E-02 +5.719986E-05 +2.881782E-02 +1.041089E-04 +2.249258E-02 +6.622191E-05 +3.099210E-02 +1.124327E-04 +2.723683E-02 +1.077003E-04 +2.961326E-02 +1.107622E-04 +2.886855E-02 +1.209198E-04 +3.359957E-02 +1.450335E-04 +1.842677E-02 +4.144114E-05 +2.067987E-02 +5.241403E-05 +2.384292E-02 +8.392423E-05 +2.523377E-02 +7.399318E-05 +1.482060E-02 +2.934033E-05 +1.685267E-02 +4.268337E-05 +2.474266E-02 +6.858025E-05 +2.464842E-02 +7.502593E-05 +1.931712E-02 +6.623063E-05 +2.571146E-02 +8.499419E-05 +1.919509E-02 +5.019677E-05 +2.194688E-02 +6.974387E-05 +2.021151E-02 +5.705824E-05 +1.939673E-02 +5.393718E-05 +2.366200E-02 +7.358565E-05 +3.181441E-02 +1.136270E-04 +1.839678E-02 +3.699144E-05 +1.988625E-02 +6.005553E-05 +2.730155E-02 +9.038604E-05 +1.977072E-02 +5.242521E-05 +1.499223E-02 +2.966075E-05 +2.040274E-02 +6.508672E-05 +1.411627E-02 +2.586129E-05 +1.706927E-02 +3.713346E-05 +1.171754E-02 +1.971987E-05 +2.013780E-02 +5.939024E-05 +2.029685E-02 +6.146855E-05 +2.908889E-02 +1.037204E-04 +1.740582E-02 +3.597993E-05 +1.564902E-02 +6.335090E-05 +1.991302E-02 +4.746765E-05 +1.756837E-02 +4.867597E-05 +2.061727E-02 +6.000022E-05 +2.574876E-02 +8.243095E-05 +1.191200E-02 +1.934272E-05 +2.009666E-02 +4.813195E-05 +1.746764E-02 +5.388627E-05 +1.239022E-02 +2.424386E-05 +2.173442E-02 +4.983400E-05 +1.517203E-02 +3.068246E-05 +1.329712E-02 +2.150332E-05 +2.354363E-02 +8.627378E-05 +1.532883E-02 +3.270327E-05 +1.472157E-02 +3.319558E-05 +1.938773E-02 +4.827508E-05 +2.165397E-02 +6.469989E-05 +1.271540E-02 +1.967861E-05 +1.665138E-02 +4.718665E-05 +9.283413E-03 +1.143878E-05 +1.046201E-02 +2.072362E-05 +1.673621E-02 +3.707353E-05 +1.445073E-02 +2.924329E-05 +7.634313E-03 +1.179099E-05 +7.070615E-03 +8.043539E-06 +1.155338E-02 +1.871310E-05 +8.618350E-03 +1.431974E-05 +9.424572E-03 +1.207411E-05 +8.545662E-03 +1.247473E-05 +3.838707E-03 +4.805334E-06 +5.882837E-03 +4.922359E-06 +8.145896E-03 +1.250575E-05 +5.962503E-03 +5.532809E-06 +1.116529E-02 +3.223331E-05 +1.080742E-02 +1.791118E-05 +4.327838E-03 +3.722361E-06 +3.132066E-03 +2.831681E-06 +5.985652E-03 +5.243244E-06 +6.402910E-03 +9.755445E-06 +5.996163E-03 +1.017758E-05 +7.516797E-03 +1.133864E-05 +1.109701E-03 +5.874266E-07 +3.145346E-03 +2.131176E-06 +3.071793E-03 +3.203751E-06 +5.112008E-03 +6.623440E-06 +1.057799E-02 +2.219886E-05 +4.499437E-03 +4.252659E-06 +8.765798E-03 +1.784490E-05 +8.921959E-03 +1.351279E-05 +7.502480E-03 +1.202219E-05 +7.196379E-03 +9.204669E-06 +5.832796E-03 +1.016451E-05 +7.038191E-03 +6.254164E-06 +9.382421E-03 +1.566041E-05 +1.345656E-02 +3.028211E-05 +6.337258E-03 +7.407982E-06 +8.543843E-03 +1.265584E-05 +1.381261E-02 +2.802183E-05 +1.190749E-02 +1.793613E-05 +9.437321E-03 +1.194730E-05 +9.732419E-03 +1.651545E-05 +1.500610E-02 +3.340884E-05 +1.678411E-02 +3.491286E-05 +1.028094E-02 +1.374135E-05 +1.485088E-02 +3.057123E-05 +8.964661E-03 +1.485585E-05 +1.226822E-02 +2.015578E-05 +1.042577E-02 +1.589161E-05 +6.708855E-03 +9.646613E-06 +1.277453E-02 +2.203458E-05 +7.224932E-03 +8.275023E-06 +1.255069E-02 +2.759249E-05 +1.234545E-02 +2.557302E-05 +1.676381E-02 +3.443801E-05 +2.225843E-02 +7.382383E-05 +9.664194E-03 +1.388455E-05 +1.384208E-02 +2.485536E-05 +1.170741E-02 +2.722875E-05 +1.298519E-02 +2.278333E-05 +1.219523E-02 +2.170852E-05 +1.455145E-02 +2.652917E-05 +1.803860E-02 +4.551654E-05 +1.716760E-02 +3.418763E-05 +1.512094E-02 +3.308210E-05 +1.040105E-02 +1.595604E-05 +1.796769E-02 +3.949154E-05 +1.872289E-02 +4.103439E-05 +9.077191E-03 +1.199908E-05 +1.631540E-02 +3.369350E-05 +1.526935E-02 +3.456559E-05 +2.236068E-02 +7.214380E-05 +8.845141E-03 +2.279004E-05 +1.352347E-02 +2.540469E-05 +1.484395E-02 +3.807417E-05 +1.804445E-02 +4.342710E-05 +1.007944E-02 +1.452963E-05 +1.467548E-02 +4.429846E-05 +2.042873E-02 +5.671423E-05 +1.758792E-02 +5.925658E-05 +1.761311E-02 +4.685220E-05 +2.004514E-02 +5.536859E-05 +1.238507E-02 +2.340619E-05 +1.046525E-02 +1.737035E-05 +1.444879E-02 +3.355825E-05 +8.277840E-03 +1.437311E-05 +1.079506E-02 +1.848135E-05 +1.561308E-02 +4.224535E-05 +1.137179E-02 +2.608300E-05 +1.280633E-02 +2.210100E-05 +1.162328E-02 +2.231053E-05 +1.296251E-02 +2.730055E-05 +1.389949E-02 +3.026765E-05 +1.411889E-02 +3.201101E-05 +8.232902E-03 +1.404323E-05 +1.242929E-02 +2.465073E-05 +9.545643E-03 +1.867285E-05 +9.740853E-03 +1.452865E-05 +1.306805E-02 +2.407394E-05 +1.010373E-02 +1.920540E-05 +8.546938E-03 +1.818086E-05 +9.873382E-03 +2.146517E-05 +1.643827E-02 +5.513889E-05 +1.117018E-02 +2.390203E-05 +9.216643E-03 +1.323340E-05 +1.434946E-02 +2.862359E-05 +1.245343E-02 +2.322243E-05 +1.212911E-02 +2.285075E-05 +9.836707E-03 +1.645734E-05 +1.201364E-02 +2.024192E-05 +1.596859E-02 +3.442108E-05 +1.368837E-02 +2.688655E-05 +1.015380E-02 +1.592459E-05 +9.892082E-03 +1.321377E-05 +1.360812E-02 +3.262388E-05 +1.003913E-02 +1.400775E-05 +1.478387E-02 +3.871602E-05 +9.205053E-03 +1.179337E-05 +9.383339E-03 +1.300416E-05 +7.080640E-03 +8.203597E-06 +6.507205E-03 +7.055020E-06 +8.843528E-03 +1.233759E-05 +1.087757E-02 +1.436248E-05 +9.075363E-03 +1.538346E-05 +4.079253E-03 +4.032406E-06 +6.146524E-03 +1.072823E-05 +7.605892E-03 +2.021674E-05 +6.737771E-03 +8.340942E-06 +7.791360E-03 +1.322504E-05 +4.367729E-03 +5.871757E-06 +5.112041E-03 +7.704614E-06 +6.685377E-03 +8.598228E-06 +5.332365E-03 +6.964174E-06 +2.025949E-03 +1.106713E-06 +7.308916E-03 +1.083527E-05 +2.657078E-03 +2.018754E-06 +3.845964E-03 +3.282949E-06 +7.906876E-03 +1.309640E-05 +3.020084E-03 +2.116323E-06 +4.987032E-03 +5.707520E-06 +1.202747E-02 +3.060476E-05 +7.093728E-03 +7.508046E-06 +7.422432E-03 +8.656078E-06 +9.077236E-03 +2.478476E-05 +6.891522E-03 +1.220166E-05 +5.076941E-03 +4.237107E-06 +8.523515E-03 +1.390735E-05 +6.414767E-03 +9.365735E-06 +9.380022E-03 +1.462751E-05 +8.456230E-03 +1.199551E-05 +9.158278E-03 +1.192449E-05 +2.298967E-03 +1.013954E-06 +7.058890E-03 +6.383597E-06 +4.876567E-03 +3.760010E-06 +1.316587E-02 +2.644816E-05 +8.359774E-03 +1.081163E-05 +1.469243E-02 +3.486053E-05 +7.460324E-03 +7.746075E-06 +7.025833E-03 +7.150545E-06 +4.599519E-03 +5.621223E-06 +1.754686E-02 +5.599449E-05 +8.496819E-03 +1.519010E-05 +1.334303E-02 +2.243087E-05 +1.273838E-02 +2.372539E-05 +1.041534E-02 +2.066977E-05 +9.140508E-03 +1.075841E-05 +1.657971E-02 +4.469598E-05 +1.247039E-02 +2.906265E-05 +1.297140E-02 +2.473045E-05 +1.664008E-02 +4.158991E-05 +1.836946E-02 +4.883353E-05 +1.411162E-02 +4.313628E-05 +1.406170E-02 +2.454496E-05 +2.270767E-02 +6.143414E-05 +1.567617E-02 +3.204306E-05 +1.611804E-02 +3.752055E-05 +1.312188E-02 +2.232058E-05 +1.726062E-02 +4.888466E-05 +2.260453E-02 +5.912727E-05 +2.295104E-02 +7.305721E-05 +2.082979E-02 +5.212405E-05 +3.139636E-02 +1.124507E-04 +1.701985E-02 +5.917730E-05 +1.573079E-02 +3.833147E-05 +1.648501E-02 +4.521319E-05 +1.295769E-02 +2.000518E-05 +1.538561E-02 +3.581006E-05 +2.113104E-02 +5.954145E-05 +1.269260E-02 +1.914463E-05 +1.597644E-02 +2.898818E-05 +1.749472E-02 +4.995488E-05 +1.170597E-02 +2.494586E-05 +1.972148E-02 +5.486069E-05 +2.930071E-02 +1.089599E-04 +1.284182E-02 +2.296682E-05 +1.568134E-02 +3.876494E-05 +1.557912E-02 +3.819947E-05 +1.760851E-02 +3.904704E-05 +1.450774E-02 +4.086604E-05 +1.375807E-02 +3.319496E-05 +1.290194E-02 +2.142172E-05 +1.402767E-02 +2.932888E-05 +1.769773E-02 +4.995015E-05 +1.419402E-02 +3.040909E-05 +1.675459E-02 +3.235864E-05 +1.976178E-02 +5.009760E-05 +1.675838E-02 +3.910658E-05 +1.689170E-02 +3.464763E-05 +1.284022E-02 +2.649261E-05 +1.316325E-02 +2.377493E-05 +1.455084E-02 +2.510139E-05 +1.102459E-02 +1.885880E-05 +8.350866E-03 +8.396386E-06 +8.651131E-03 +1.124192E-05 +1.376705E-02 +2.764081E-05 +1.428569E-02 +3.790437E-05 +1.724679E-02 +3.366818E-05 +1.584053E-02 +3.651487E-05 +1.193033E-02 +2.181873E-05 +1.984626E-02 +5.592598E-05 +1.214395E-02 +1.945894E-05 +1.365596E-02 +2.557166E-05 +1.898643E-02 +5.157604E-05 +1.455388E-02 +2.799320E-05 +1.182403E-02 +2.115918E-05 +8.626630E-03 +1.007433E-05 +1.197781E-02 +1.983881E-05 +1.005772E-02 +1.640145E-05 +1.873799E-02 +4.930639E-05 +1.693176E-02 +3.650659E-05 +8.818286E-03 +1.286259E-05 +1.139988E-02 +1.621095E-05 +1.028933E-02 +1.453198E-05 +8.404568E-03 +9.460915E-06 +1.275744E-02 +2.774096E-05 +1.168183E-02 +1.973529E-05 +8.454758E-03 +1.146522E-05 +8.323601E-03 +8.829709E-06 +7.495546E-03 +8.715799E-06 +5.296323E-03 +6.046794E-06 +9.891852E-03 +1.398584E-05 +9.955102E-03 +1.943758E-05 +8.059482E-03 +1.695389E-05 +9.676780E-03 +1.658395E-05 +4.834433E-03 +5.897640E-06 +6.636064E-03 +7.609925E-06 +7.619866E-03 +1.212597E-05 +2.894660E-03 +1.856127E-06 +7.553124E-03 +1.223718E-05 +2.300404E-03 +1.121136E-06 +7.327033E-03 +9.105655E-06 +4.846398E-03 +4.166167E-06 +8.315901E-03 +1.319751E-05 +7.221182E-03 +7.485967E-06 +5.462020E-03 +3.502442E-06 +9.453474E-03 +1.071037E-05 +1.293719E-02 +2.483879E-05 +1.321412E-02 +2.574150E-05 +1.359066E-02 +2.348428E-05 +9.882529E-03 +1.691834E-05 +1.409150E-02 +3.523994E-05 +1.070054E-02 +1.906767E-05 +1.266239E-02 +1.972906E-05 +1.432889E-02 +3.545618E-05 +1.011895E-02 +1.360275E-05 +1.025183E-02 +1.608180E-05 +5.529921E-03 +7.911985E-06 +1.629012E-02 +3.223742E-05 +1.114479E-02 +2.101499E-05 +1.215717E-02 +1.846892E-05 +1.689915E-02 +4.620696E-05 +1.139613E-02 +1.742241E-05 +1.213431E-02 +2.199183E-05 +1.846118E-02 +5.474736E-05 +1.709853E-02 +3.678232E-05 +1.735796E-02 +4.553680E-05 +1.853277E-02 +4.646147E-05 +1.763467E-02 +4.466597E-05 +1.818218E-02 +4.824198E-05 +1.872596E-02 +6.942835E-05 +2.022757E-02 +5.512053E-05 +1.699277E-02 +3.870609E-05 +1.055491E-02 +1.687463E-05 +1.377011E-02 +2.394912E-05 +1.684636E-02 +3.614976E-05 +2.147831E-02 +6.616404E-05 +1.730285E-02 +3.913079E-05 +1.957720E-02 +5.565960E-05 +1.855637E-02 +4.612437E-05 +2.805186E-02 +1.029670E-04 +2.418902E-02 +6.781295E-05 +2.188652E-02 +6.579480E-05 +1.771569E-02 +4.195257E-05 +2.256760E-02 +6.456468E-05 +1.918774E-02 +5.286254E-05 +2.960608E-02 +1.004602E-04 +2.712839E-02 +8.980797E-05 +2.794452E-02 +1.254679E-04 +3.008968E-02 +1.089661E-04 +3.649934E-02 +1.734688E-04 +2.937679E-02 +1.082854E-04 +3.282797E-02 +1.345859E-04 +4.521759E-02 +2.543431E-04 +2.398232E-02 +7.384139E-05 +3.254161E-02 +1.265125E-04 +3.001705E-02 +1.111357E-04 +2.399317E-02 +6.646668E-05 +3.503715E-02 +1.480964E-04 +3.148980E-02 +1.398976E-04 +2.604556E-02 +9.628490E-05 +3.036652E-02 +1.264006E-04 +2.939357E-02 +1.170192E-04 +3.743087E-02 +1.775840E-04 +3.085132E-02 +1.134780E-04 +4.147944E-02 +1.996575E-04 +3.527838E-02 +1.521337E-04 +2.366172E-02 +6.804925E-05 +2.713514E-02 +1.027237E-04 +2.174215E-02 +5.749073E-05 +2.675659E-02 +8.382558E-05 +2.359986E-02 +7.430600E-05 +2.367000E-02 +7.298151E-05 +3.227569E-02 +1.232973E-04 +2.733957E-02 +1.003086E-04 +3.002721E-02 +9.578465E-05 +3.707352E-02 +1.507472E-04 +2.382487E-02 +6.891582E-05 +2.959048E-02 +1.054578E-04 +1.869568E-02 +4.658988E-05 +2.597326E-02 +8.064723E-05 +2.153451E-02 +5.840127E-05 +1.628961E-02 +4.271967E-05 +2.741092E-02 +8.522384E-05 +2.733756E-02 +9.324995E-05 +2.864715E-02 +1.013597E-04 +3.455306E-02 +1.448078E-04 +3.347393E-02 +1.327937E-04 +3.527874E-02 +1.637966E-04 +2.441550E-02 +8.480735E-05 +2.623780E-02 +8.256558E-05 +1.716091E-02 +5.253723E-05 +1.324941E-02 +2.243910E-05 +2.246659E-02 +6.057114E-05 +2.192475E-02 +5.668645E-05 +2.272490E-02 +7.122633E-05 +3.254641E-02 +1.485757E-04 +1.504227E-02 +2.731302E-05 +1.654008E-02 +4.044070E-05 +2.442456E-02 +8.014611E-05 +2.260914E-02 +6.419431E-05 +1.988931E-02 +6.266967E-05 +3.422754E-02 +1.464931E-04 +1.176286E-02 +1.819119E-05 +1.090258E-02 +1.835148E-05 +1.428818E-02 +2.432816E-05 +9.647717E-03 +2.418655E-05 +1.343547E-02 +2.294350E-05 +1.672666E-02 +4.724036E-05 +1.498173E-02 +2.999368E-05 +1.209667E-02 +2.648058E-05 +1.777083E-02 +3.928551E-05 +1.906246E-02 +4.800003E-05 +1.227253E-02 +2.454598E-05 +2.054852E-02 +5.627860E-05 +1.401620E-02 +3.395841E-05 +1.618774E-02 +3.315176E-05 +9.366645E-03 +1.322093E-05 +1.271711E-02 +2.946682E-05 +1.514436E-02 +3.698271E-05 +1.357568E-02 +2.661503E-05 +6.059837E-03 +6.072503E-06 +7.510121E-03 +8.006288E-06 +1.105528E-02 +2.101618E-05 +4.887318E-03 +5.427586E-06 +8.183502E-03 +1.217955E-05 +9.960866E-03 +1.427453E-05 +1.302537E-02 +2.752410E-05 +1.432159E-02 +3.046582E-05 +1.362132E-02 +3.362721E-05 +1.728813E-02 +4.356686E-05 +1.882553E-02 +4.115052E-05 +2.022059E-02 +5.094537E-05 +9.935622E-03 +1.476612E-05 +1.423961E-02 +2.791015E-05 +1.078457E-02 +3.254092E-05 +1.010483E-02 +1.743918E-05 +1.145080E-02 +2.471476E-05 +1.537588E-02 +3.948184E-05 +3.025085E-02 +1.211946E-04 +2.522059E-02 +8.250671E-05 +2.231553E-02 +6.323615E-05 +2.348918E-02 +6.900725E-05 +2.273346E-02 +5.949276E-05 +1.817883E-02 +4.693722E-05 +2.354895E-02 +7.506897E-05 +2.667415E-02 +1.051466E-04 +1.923174E-02 +4.215181E-05 +2.251124E-02 +6.197340E-05 +2.212823E-02 +7.382044E-05 +2.627751E-02 +1.262016E-04 +2.639401E-02 +8.435288E-05 +2.355251E-02 +6.467494E-05 +1.824258E-02 +4.508497E-05 +2.658510E-02 +7.928794E-05 +2.675987E-02 +1.019694E-04 +2.294475E-02 +7.019770E-05 +2.982020E-02 +1.172018E-04 +2.650631E-02 +7.994237E-05 +3.317163E-02 +1.365190E-04 +4.086398E-02 +2.004161E-04 +2.796562E-02 +1.066212E-04 +3.652322E-02 +1.878727E-04 +3.754838E-02 +1.647330E-04 +3.743316E-02 +1.789631E-04 +2.670365E-02 +8.773372E-05 +2.985106E-02 +9.743471E-05 +3.608668E-02 +1.610685E-04 +4.205670E-02 +1.842040E-04 +3.922858E-02 +1.953706E-04 +4.448502E-02 +2.469956E-04 +4.693316E-02 +2.454100E-04 +4.848290E-02 +2.671676E-04 +4.023569E-02 +1.713754E-04 +4.294287E-02 +2.063518E-04 +4.004042E-02 +1.923766E-04 +4.357533E-02 +2.186888E-04 +3.728630E-02 +1.990696E-04 +4.083902E-02 +1.919817E-04 +3.857997E-02 +1.821259E-04 +4.901557E-02 +2.767777E-04 +5.790464E-02 +3.872461E-04 +3.900935E-02 +1.730109E-04 +4.875435E-02 +2.872844E-04 +5.468952E-02 +3.456684E-04 +4.179342E-02 +2.001437E-04 +5.381510E-02 +3.724283E-04 +4.237622E-02 +1.941664E-04 +5.150719E-02 +2.908123E-04 +2.903885E-02 +1.031896E-04 +3.589197E-02 +1.392764E-04 +6.487280E-02 +5.024965E-04 +3.912537E-02 +1.856374E-04 +3.458921E-02 +1.576917E-04 +4.382484E-02 +2.169611E-04 +5.176404E-02 +2.803853E-04 +5.379322E-02 +3.067204E-04 +4.070213E-02 +1.816834E-04 +4.088864E-02 +1.878390E-04 +3.237349E-02 +1.191717E-04 +3.712382E-02 +1.504938E-04 +3.997504E-02 +1.782786E-04 +3.267526E-02 +1.297525E-04 +4.125020E-02 +1.924418E-04 +3.958215E-02 +1.901035E-04 +4.006168E-02 +1.832588E-04 +3.769986E-02 +1.717343E-04 +5.100625E-02 +2.898618E-04 +3.840461E-02 +1.682447E-04 +3.871359E-02 +1.824587E-04 +4.283505E-02 +2.070659E-04 +2.126415E-02 +4.973731E-05 +2.889038E-02 +1.088896E-04 +2.104568E-02 +6.548850E-05 +2.848041E-02 +1.298630E-04 +3.029276E-02 +1.138285E-04 +2.862761E-02 +9.675198E-05 +2.647642E-02 +8.418245E-05 +2.861468E-02 +1.081191E-04 +3.468627E-02 +1.277418E-04 +3.349950E-02 +1.317290E-04 +3.982514E-02 +1.794172E-04 +3.268932E-02 +1.255468E-04 +1.912998E-02 +4.577703E-05 +2.085203E-02 +6.226159E-05 +1.828176E-02 +4.944577E-05 +2.381226E-02 +8.891365E-05 +2.311077E-02 +6.656845E-05 +2.473067E-02 +7.334387E-05 +1.375348E-02 +2.283618E-05 +1.804582E-02 +4.143497E-05 +2.006609E-02 +4.873691E-05 +1.884382E-02 +4.819154E-05 +1.080497E-02 +1.376297E-05 +1.726756E-02 +3.375398E-05 +1.609526E-02 +3.821013E-05 +1.411969E-02 +2.227160E-05 +9.192959E-03 +1.631434E-05 +9.217380E-03 +1.968772E-05 +1.468647E-02 +2.623946E-05 +1.488244E-02 +3.525990E-05 +1.269069E-02 +2.294212E-05 +7.765318E-03 +1.103799E-05 +1.558612E-02 +3.323429E-05 +1.740029E-02 +5.933208E-05 +8.717198E-03 +1.192243E-05 +9.978251E-03 +1.485392E-05 +8.720289E-03 +1.149015E-05 +1.020781E-02 +2.305230E-05 +1.149654E-02 +1.940965E-05 +1.788016E-02 +4.220362E-05 +1.110418E-02 +1.718658E-05 +2.482931E-02 +1.001964E-04 +1.645044E-02 +4.054796E-05 +1.894652E-02 +4.678890E-05 +1.434380E-02 +3.165754E-05 +1.258510E-02 +2.725122E-05 +2.869257E-02 +1.023938E-04 +1.622348E-02 +4.537915E-05 +2.185647E-02 +5.507321E-05 +1.954237E-02 +4.309665E-05 +2.035261E-02 +6.714277E-05 +2.087253E-02 +4.818549E-05 +1.582401E-02 +3.291377E-05 +2.671073E-02 +9.777211E-05 +2.512135E-02 +7.547644E-05 +2.506727E-02 +7.485132E-05 +1.404823E-02 +2.446571E-05 +2.280451E-02 +6.346040E-05 +2.677285E-02 +8.686426E-05 +2.736182E-02 +1.019696E-04 +4.245358E-02 +2.031516E-04 +3.781676E-02 +1.657018E-04 +3.988823E-02 +1.948658E-04 +4.639548E-02 +2.606408E-04 +2.998045E-02 +1.078111E-04 +3.116186E-02 +1.123729E-04 +5.002484E-02 +3.007452E-04 +4.018989E-02 +2.134973E-04 +3.706873E-02 +1.705493E-04 +4.841352E-02 +3.006314E-04 +4.754905E-02 +2.640563E-04 +4.364220E-02 +2.190548E-04 +5.500865E-02 +3.565984E-04 +5.532256E-02 +3.576995E-04 +5.047039E-02 +2.937072E-04 +5.060213E-02 +3.044944E-04 +6.416214E-02 +4.414515E-04 +4.420142E-02 +2.374155E-04 +7.189342E-02 +5.468649E-04 +6.014136E-02 +3.940429E-04 +6.349933E-02 +4.207906E-04 +8.074317E-02 +7.419627E-04 +5.500576E-02 +3.305937E-04 +6.217792E-02 +4.170384E-04 +5.168117E-02 +2.909656E-04 +6.458066E-02 +4.333028E-04 +5.398600E-02 +3.328720E-04 +6.745198E-02 +5.123388E-04 +7.585366E-02 +6.172453E-04 +7.667038E-02 +6.845297E-04 +8.031109E-02 +7.564824E-04 +7.073034E-02 +5.458581E-04 +7.573691E-02 +6.181860E-04 +7.610572E-02 +6.320225E-04 +9.472534E-02 +1.007312E-03 +8.942164E-02 +8.735772E-04 +6.678710E-02 +5.406900E-04 +6.813491E-02 +4.871261E-04 +6.435084E-02 +4.334073E-04 +6.618817E-02 +4.692824E-04 +8.000303E-02 +7.136374E-04 +7.211464E-02 +6.123883E-04 +9.166818E-02 +8.952483E-04 +5.925322E-02 +4.492782E-04 +9.608215E-02 +9.616517E-04 +9.591584E-02 +9.489183E-04 +6.551541E-02 +4.745820E-04 +9.550949E-02 +9.531681E-04 +5.425472E-02 +3.720953E-04 +6.247517E-02 +4.393993E-04 +5.896488E-02 +4.002445E-04 +5.123472E-02 +2.943668E-04 +7.803224E-02 +6.809156E-04 +6.717709E-02 +5.320659E-04 +4.752627E-02 +2.528912E-04 +4.731481E-02 +2.339422E-04 +6.377650E-02 +5.060539E-04 +6.343027E-02 +4.521666E-04 +5.104223E-02 +3.253849E-04 +6.842536E-02 +5.197571E-04 +3.944396E-02 +2.024706E-04 +3.774197E-02 +1.745573E-04 +3.016158E-02 +1.057402E-04 +2.940171E-02 +1.161392E-04 +5.428473E-02 +3.726778E-04 +3.466389E-02 +1.374879E-04 +2.493688E-02 +9.144503E-05 +4.409357E-02 +2.282136E-04 +3.898092E-02 +1.692947E-04 +4.161525E-02 +2.078651E-04 +4.453363E-02 +2.219554E-04 +4.844461E-02 +2.561895E-04 +1.992414E-02 +5.397706E-05 +1.350002E-02 +2.916535E-05 +2.067487E-02 +4.903837E-05 +2.325603E-02 +8.788747E-05 +2.013029E-02 +5.389647E-05 +3.203793E-02 +1.247710E-04 +1.965175E-02 +5.312061E-05 +2.463239E-02 +8.315266E-05 +2.236927E-02 +6.414213E-05 +2.615164E-02 +7.702130E-05 +3.011875E-02 +1.090074E-04 +3.242536E-02 +1.289377E-04 +1.086798E-02 +1.760814E-05 +1.502391E-02 +3.139067E-05 +2.028244E-02 +5.583147E-05 +1.735464E-02 +4.295725E-05 +1.595857E-02 +2.787063E-05 +2.051018E-02 +5.355572E-05 +1.177619E-02 +1.717906E-05 +1.084749E-02 +1.707026E-05 +1.825630E-02 +5.376844E-05 +1.670967E-02 +3.402950E-05 +1.517723E-02 +3.554202E-05 +2.351000E-02 +7.935893E-05 +1.408337E-02 +2.327322E-05 +1.414777E-02 +2.697883E-05 +1.345682E-02 +2.740309E-05 +1.807340E-02 +5.667578E-05 +1.943061E-02 +4.787161E-05 +1.781260E-02 +6.060590E-05 +1.822299E-02 +4.962172E-05 +2.071085E-02 +5.813369E-05 +1.228031E-02 +2.872901E-05 +1.195238E-02 +1.942759E-05 +2.092949E-02 +5.642842E-05 +1.529365E-02 +3.149749E-05 +2.339941E-02 +7.277783E-05 +2.913166E-02 +1.578357E-04 +1.733543E-02 +4.484055E-05 +2.332788E-02 +5.763144E-05 +2.815285E-02 +1.152065E-04 +2.037972E-02 +4.949376E-05 +3.118074E-02 +1.103084E-04 +2.652943E-02 +7.950175E-05 +2.821700E-02 +9.085185E-05 +2.985586E-02 +1.075718E-04 +2.519195E-02 +7.329635E-05 +2.548988E-02 +7.800201E-05 +4.334204E-02 +2.354327E-04 +4.370525E-02 +2.090531E-04 +4.006925E-02 +2.178363E-04 +4.954585E-02 +2.700073E-04 +4.092841E-02 +2.238665E-04 +2.776415E-02 +8.914334E-05 +4.493102E-02 +2.333231E-04 +5.357023E-02 +3.291447E-04 +3.963439E-02 +1.816002E-04 +5.209753E-02 +3.068180E-04 +4.986170E-02 +2.874548E-04 +4.594257E-02 +2.466016E-04 +7.630622E-02 +6.261797E-04 +5.881534E-02 +3.747957E-04 +6.780811E-02 +4.976784E-04 +8.984762E-02 +8.898655E-04 +5.491164E-02 +3.345133E-04 +5.735501E-02 +3.771763E-04 +7.877228E-02 +6.794994E-04 +9.906424E-02 +1.046741E-03 +5.785970E-02 +4.133043E-04 +7.848689E-02 +6.870125E-04 +1.047444E-01 +1.223298E-03 +7.404855E-02 +5.854937E-04 +9.032228E-02 +8.427419E-04 +8.401933E-02 +7.146695E-04 +8.655196E-02 +8.118612E-04 +1.130946E-01 +1.398959E-03 +9.597180E-02 +1.024696E-03 +1.173027E-01 +1.427372E-03 +1.057440E-01 +1.169551E-03 +1.236176E-01 +1.570398E-03 +1.126957E-01 +1.332155E-03 +1.492376E-01 +2.275171E-03 +1.540101E-01 +2.443893E-03 +1.715020E-01 +3.018404E-03 +7.291542E-02 +5.897697E-04 +7.660305E-02 +6.300479E-04 +9.197170E-02 +8.994110E-04 +9.982203E-02 +1.045655E-03 +1.033399E-01 +1.152382E-03 +1.139526E-01 +1.408827E-03 +8.350520E-02 +7.494750E-04 +9.839459E-02 +1.011369E-03 +1.077860E-01 +1.279212E-03 +1.228340E-01 +1.621769E-03 +1.144053E-01 +1.334188E-03 +1.571539E-01 +2.565349E-03 +6.233439E-02 +4.263330E-04 +6.563411E-02 +5.048147E-04 +6.507814E-02 +4.812141E-04 +6.362658E-02 +4.417375E-04 +7.986988E-02 +7.190156E-04 +8.970255E-02 +8.714050E-04 +5.717855E-02 +3.416545E-04 +5.668804E-02 +3.415895E-04 +7.197316E-02 +5.676520E-04 +7.136224E-02 +5.599617E-04 +8.054458E-02 +7.445675E-04 +1.023397E-01 +1.107780E-03 +4.458142E-02 +2.130924E-04 +5.439535E-02 +3.275861E-04 +5.080989E-02 +2.798307E-04 +3.946665E-02 +1.879310E-04 +6.271593E-02 +4.257844E-04 +4.965993E-02 +2.741721E-04 +4.221851E-02 +1.992549E-04 +3.585135E-02 +1.543110E-04 +4.558668E-02 +2.566453E-04 +3.888908E-02 +1.783945E-04 +4.502379E-02 +2.492156E-04 +5.625550E-02 +3.626058E-04 +2.128686E-02 +5.310350E-05 +2.848081E-02 +1.032351E-04 +3.198369E-02 +1.191780E-04 +3.220035E-02 +1.276802E-04 +3.463447E-02 +1.270326E-04 +3.109004E-02 +1.168059E-04 +2.332999E-02 +6.452643E-05 +2.117480E-02 +5.228816E-05 +2.838827E-02 +1.161483E-04 +2.329241E-02 +6.809020E-05 +2.459549E-02 +7.138168E-05 +2.765800E-02 +9.045558E-05 +1.370243E-02 +3.338519E-05 +1.582736E-02 +3.857108E-05 +1.914636E-02 +4.789559E-05 +1.905516E-02 +4.419778E-05 +1.810520E-02 +3.877471E-05 +2.115307E-02 +7.229884E-05 +1.882956E-02 +4.805493E-05 +9.281049E-03 +1.409203E-05 +1.706945E-02 +3.299567E-05 +2.172381E-02 +5.595328E-05 +1.104074E-02 +1.584618E-05 +1.946919E-02 +4.863958E-05 +1.238685E-02 +2.066688E-05 +1.378714E-02 +2.843856E-05 +1.670520E-02 +3.555438E-05 +2.766185E-02 +9.046517E-05 +1.691132E-02 +3.290270E-05 +1.927098E-02 +5.061316E-05 +1.202893E-02 +1.958457E-05 +1.922540E-02 +4.323737E-05 +1.274015E-02 +2.175309E-05 +1.524415E-02 +3.024778E-05 +1.567541E-02 +4.050037E-05 +1.898211E-02 +6.605988E-05 +2.223387E-02 +5.741257E-05 +2.452031E-02 +8.066778E-05 +2.491977E-02 +8.109453E-05 +2.610295E-02 +7.731723E-05 +1.803031E-02 +3.613025E-05 +2.184838E-02 +6.008277E-05 +2.576522E-02 +7.561914E-05 +3.038022E-02 +1.150600E-04 +2.471237E-02 +7.123333E-05 +3.173089E-02 +1.261453E-04 +3.197437E-02 +1.411443E-04 +2.786611E-02 +8.928073E-05 +4.565549E-02 +2.352807E-04 +3.535175E-02 +1.583088E-04 +4.110758E-02 +2.035220E-04 +5.345474E-02 +3.515666E-04 +3.820824E-02 +1.563980E-04 +3.254512E-02 +1.163872E-04 +4.763741E-02 +2.544110E-04 +5.216626E-02 +2.867256E-04 +4.162668E-02 +2.258042E-04 +5.349959E-02 +3.167588E-04 +5.268155E-02 +3.037455E-04 +4.827712E-02 +2.530854E-04 +7.203623E-02 +5.807994E-04 +5.256504E-02 +2.870331E-04 +7.227033E-02 +5.557721E-04 +8.778648E-02 +8.961223E-04 +5.726539E-02 +3.647823E-04 +5.856701E-02 +3.711206E-04 +8.418818E-02 +8.420171E-04 +1.110902E-01 +1.311451E-03 +6.849413E-02 +4.990580E-04 +8.795189E-02 +8.053436E-04 +1.002509E-01 +1.136773E-03 +8.057346E-02 +7.326604E-04 +8.129820E-02 +6.905078E-04 +7.847809E-02 +7.619983E-04 +9.737274E-02 +1.035174E-03 +1.154716E-01 +1.385047E-03 +9.040089E-02 +8.570313E-04 +1.211664E-01 +1.547158E-03 +1.031330E-01 +1.146280E-03 +1.249586E-01 +1.649464E-03 +7.259655E-02 +5.736210E-04 +9.951286E-02 +1.046118E-03 +1.634971E-01 +2.756448E-03 +1.297207E-01 +1.735289E-03 +6.477036E-02 +5.010788E-04 +7.479236E-02 +6.145152E-04 +9.983365E-02 +1.091064E-03 +1.057264E-01 +1.249917E-03 +8.524281E-02 +7.807948E-04 +1.159165E-01 +1.434680E-03 +7.914697E-02 +6.791950E-04 +9.369015E-02 +9.476358E-04 +9.819988E-02 +1.022095E-03 +9.686028E-02 +1.016599E-03 +1.294766E-01 +1.810274E-03 +1.296189E-01 +1.785443E-03 +5.535491E-02 +4.100726E-04 +5.475647E-02 +3.309264E-04 +7.075605E-02 +6.187772E-04 +6.387417E-02 +4.196497E-04 +7.578685E-02 +6.019889E-04 +8.903112E-02 +9.119475E-04 +6.385945E-02 +4.650950E-04 +5.390120E-02 +3.165606E-04 +5.744329E-02 +3.580388E-04 +5.920600E-02 +3.893593E-04 +7.525234E-02 +6.092966E-04 +8.573764E-02 +7.942436E-04 +2.797792E-02 +8.517754E-05 +3.790894E-02 +1.764825E-04 +4.239936E-02 +2.094748E-04 +4.003024E-02 +1.918379E-04 +5.137956E-02 +3.003587E-04 +3.883708E-02 +2.005906E-04 +2.858632E-02 +9.126637E-05 +3.012004E-02 +9.617653E-05 +4.160100E-02 +1.981616E-04 +4.247458E-02 +1.951666E-04 +3.989011E-02 +1.920698E-04 +5.270057E-02 +4.088719E-04 +1.934929E-02 +4.412789E-05 +2.359082E-02 +7.371994E-05 +2.394998E-02 +6.675994E-05 +2.637339E-02 +8.517554E-05 +2.328326E-02 +6.212789E-05 +3.651578E-02 +1.464186E-04 +2.140441E-02 +5.613878E-05 +2.241671E-02 +6.918410E-05 +2.337122E-02 +6.432183E-05 +2.144477E-02 +6.203786E-05 +3.024192E-02 +1.083505E-04 +3.331930E-02 +1.347081E-04 +1.564695E-02 +3.553327E-05 +1.812645E-02 +3.940659E-05 +2.235798E-02 +6.269701E-05 +1.419345E-02 +3.096864E-05 +2.228629E-02 +7.578567E-05 +1.860794E-02 +4.332178E-05 +1.533239E-02 +3.896858E-05 +1.580257E-02 +3.874692E-05 +2.185955E-02 +7.842950E-05 +1.195136E-02 +1.715334E-05 +1.691111E-02 +5.345113E-05 +1.575376E-02 +3.654434E-05 +1.594875E-02 +2.957220E-05 +1.223541E-02 +2.476765E-05 +1.370590E-02 +2.764042E-05 +2.661246E-02 +1.016998E-04 +2.080371E-02 +4.813282E-05 +2.468736E-02 +6.974038E-05 +1.405638E-02 +2.572385E-05 +2.459760E-02 +7.159383E-05 +1.228308E-02 +1.773752E-05 +1.017949E-02 +1.885833E-05 +2.024611E-02 +5.718430E-05 +1.797631E-02 +4.281825E-05 +1.570780E-02 +3.056781E-05 +1.271841E-02 +2.456995E-05 +2.932023E-02 +9.261980E-05 +3.237241E-02 +1.211680E-04 +2.105195E-02 +5.549955E-05 +2.483667E-02 +7.162437E-05 +2.011907E-02 +5.130375E-05 +1.983609E-02 +4.987791E-05 +1.492495E-02 +3.087968E-05 +2.870495E-02 +9.962637E-05 +2.722358E-02 +8.845542E-05 +2.118986E-02 +5.204535E-05 +4.348038E-02 +2.209404E-04 +3.712818E-02 +1.689129E-04 +4.138693E-02 +1.981821E-04 +4.470777E-02 +2.289185E-04 +2.764424E-02 +9.090079E-05 +2.655560E-02 +9.474172E-05 +4.524862E-02 +2.292538E-04 +5.164196E-02 +2.774634E-04 +3.466551E-02 +1.631603E-04 +3.563208E-02 +1.379234E-04 +4.211986E-02 +1.930478E-04 +3.079625E-02 +1.135265E-04 +5.465211E-02 +3.301887E-04 +4.860409E-02 +2.888426E-04 +7.075978E-02 +5.108370E-04 +6.867881E-02 +5.424435E-04 +3.427613E-02 +1.426574E-04 +5.955830E-02 +3.940963E-04 +6.828982E-02 +4.738886E-04 +6.525289E-02 +4.898769E-04 +3.737982E-02 +1.638396E-04 +5.286730E-02 +3.082087E-04 +6.158083E-02 +4.216724E-04 +4.980750E-02 +2.726737E-04 +5.696575E-02 +3.692634E-04 +5.058820E-02 +2.744701E-04 +6.726109E-02 +4.926664E-04 +7.839336E-02 +6.590448E-04 +7.010209E-02 +5.719905E-04 +8.384171E-02 +7.652328E-04 +6.937383E-02 +5.168671E-04 +9.468263E-02 +9.868090E-04 +5.004326E-02 +2.785169E-04 +6.606152E-02 +4.541359E-04 +9.675798E-02 +1.063286E-03 +7.230289E-02 +5.573682E-04 +6.543974E-02 +5.078440E-04 +5.267920E-02 +3.176937E-04 +8.194553E-02 +6.982175E-04 +9.613453E-02 +1.079846E-03 +6.113228E-02 +4.004864E-04 +8.522953E-02 +7.810809E-04 +5.316859E-02 +3.091340E-04 +7.827195E-02 +6.540396E-04 +5.463776E-02 +3.503148E-04 +5.071284E-02 +3.191021E-04 +8.557140E-02 +7.639230E-04 +7.700044E-02 +6.547991E-04 +5.105846E-02 +2.888427E-04 +5.004859E-02 +2.887941E-04 +5.147919E-02 +3.256217E-04 +5.538533E-02 +3.360110E-04 +6.140039E-02 +4.129538E-04 +5.936836E-02 +4.315037E-04 +4.930384E-02 +2.889606E-04 +4.619680E-02 +2.419601E-04 +4.445739E-02 +2.331544E-04 +4.824154E-02 +2.469526E-04 +6.974394E-02 +5.056104E-04 +6.084953E-02 +3.932556E-04 +3.577286E-02 +1.452599E-04 +3.166228E-02 +1.303590E-04 +3.862777E-02 +1.632780E-04 +3.916934E-02 +1.779181E-04 +3.625045E-02 +1.745839E-04 +4.231134E-02 +2.225093E-04 +3.359703E-02 +1.419870E-04 +4.006089E-02 +1.707049E-04 +3.658866E-02 +1.730857E-04 +3.341254E-02 +1.297042E-04 +4.263417E-02 +2.215026E-04 +3.955323E-02 +1.921082E-04 +2.174079E-02 +5.222197E-05 +2.442434E-02 +8.243601E-05 +2.914443E-02 +1.214208E-04 +1.824800E-02 +4.893719E-05 +3.091152E-02 +1.051207E-04 +2.972565E-02 +1.063333E-04 +3.002196E-02 +1.026816E-04 +1.967353E-02 +5.819743E-05 +2.921034E-02 +1.035681E-04 +2.329404E-02 +7.915033E-05 +2.537416E-02 +9.811049E-05 +2.636605E-02 +8.177530E-05 +9.035064E-03 +1.555651E-05 +1.655675E-02 +4.002782E-05 +1.372662E-02 +3.244904E-05 +1.311878E-02 +2.619244E-05 +1.611214E-02 +3.084313E-05 +1.574836E-02 +3.450927E-05 +7.693366E-03 +1.606361E-05 +1.135596E-02 +1.801519E-05 +1.342059E-02 +2.516888E-05 +1.160985E-02 +2.390704E-05 +1.383386E-02 +2.800471E-05 +1.971360E-02 +8.842562E-05 +1.183879E-02 +1.932907E-05 +8.105380E-03 +1.234549E-05 +1.271210E-02 +2.405656E-05 +1.537131E-02 +3.137697E-05 +1.591997E-02 +3.769775E-05 +1.088552E-02 +1.713348E-05 +1.515322E-02 +3.039160E-05 +1.275379E-02 +2.585038E-05 +8.475047E-03 +1.032301E-05 +1.017506E-02 +2.019761E-05 +1.192565E-02 +2.149550E-05 +8.221048E-03 +8.986302E-06 +1.307738E-02 +2.107929E-05 +1.086073E-02 +1.558009E-05 +2.199295E-02 +5.739512E-05 +1.994568E-02 +5.494728E-05 +1.534082E-02 +3.625194E-05 +1.764761E-02 +4.067341E-05 +1.796742E-02 +4.680639E-05 +2.032190E-02 +5.017032E-05 +1.749541E-02 +4.866856E-05 +1.732369E-02 +4.955885E-05 +1.681732E-02 +3.837118E-05 +1.769405E-02 +5.487143E-05 +2.888259E-02 +1.026998E-04 +2.098585E-02 +6.932453E-05 +3.313341E-02 +1.351006E-04 +3.207197E-02 +1.295024E-04 +2.459220E-02 +8.336446E-05 +2.450985E-02 +6.648377E-05 +3.117162E-02 +1.195002E-04 +4.003079E-02 +2.123347E-04 +2.176609E-02 +6.269817E-05 +2.994428E-02 +1.235590E-04 +3.524085E-02 +1.599016E-04 +2.408409E-02 +6.486120E-05 +4.186261E-02 +1.804413E-04 +4.461985E-02 +2.229520E-04 +3.815900E-02 +1.674626E-04 +4.651996E-02 +2.353452E-04 +4.372936E-02 +2.126895E-04 +3.471725E-02 +1.536658E-04 +3.777496E-02 +1.682954E-04 +4.542053E-02 +2.887036E-04 +3.302349E-02 +1.252640E-04 +3.007472E-02 +1.103699E-04 +4.167073E-02 +1.843542E-04 +3.435406E-02 +1.576055E-04 +5.142055E-02 +2.840339E-04 +4.459791E-02 +2.437118E-04 +5.240798E-02 +3.061931E-04 +6.184982E-02 +3.987655E-04 +4.185540E-02 +2.035740E-04 +4.274424E-02 +1.929214E-04 +4.853301E-02 +2.820023E-04 +7.063952E-02 +5.492235E-04 +4.633212E-02 +2.687210E-04 +5.821695E-02 +3.976817E-04 +6.625094E-02 +4.940422E-04 +6.129214E-02 +4.099540E-04 +3.772075E-02 +1.660719E-04 +3.714570E-02 +1.541156E-04 +4.493005E-02 +2.310471E-04 +4.557412E-02 +2.432878E-04 +4.065422E-02 +1.871281E-04 +5.417420E-02 +3.505844E-04 +3.708658E-02 +1.717372E-04 +5.130291E-02 +3.077258E-04 +3.417926E-02 +1.492890E-04 +3.377463E-02 +1.256710E-04 +5.369283E-02 +3.432927E-04 +4.836021E-02 +2.588228E-04 +3.269371E-02 +1.286374E-04 +2.896989E-02 +1.123018E-04 +4.848291E-02 +2.612160E-04 +4.333314E-02 +2.292463E-04 +3.759979E-02 +1.680559E-04 +5.061237E-02 +2.724683E-04 +3.926039E-02 +1.797325E-04 +3.938137E-02 +1.851970E-04 +3.570566E-02 +1.506562E-04 +4.159909E-02 +2.157074E-04 +5.099360E-02 +2.844970E-04 +4.605309E-02 +2.508391E-04 +2.500341E-02 +7.363724E-05 +3.039879E-02 +1.123549E-04 +3.534598E-02 +1.698480E-04 +3.702744E-02 +1.486744E-04 +3.410129E-02 +1.365716E-04 +3.991621E-02 +1.846954E-04 +3.186334E-02 +1.158884E-04 +3.268754E-02 +1.178259E-04 +2.428429E-02 +7.876563E-05 +2.495449E-02 +7.906081E-05 +3.551756E-02 +1.519603E-04 +3.018593E-02 +9.724962E-05 +2.032098E-02 +4.781656E-05 +3.017998E-02 +1.313561E-04 +2.424929E-02 +6.480258E-05 +1.950042E-02 +4.417513E-05 +2.943418E-02 +9.948664E-05 +2.707621E-02 +1.035208E-04 +1.957350E-02 +4.711947E-05 +1.583335E-02 +2.891313E-05 +2.972335E-02 +1.047751E-04 +1.739423E-02 +4.376709E-05 +1.705633E-02 +3.892027E-05 +2.121975E-02 +5.891607E-05 +1.002146E-02 +2.339078E-05 +1.405706E-02 +3.175594E-05 +1.011207E-02 +1.585291E-05 +1.573069E-02 +3.554827E-05 +1.518567E-02 +3.047833E-05 +1.617187E-02 +3.397385E-05 +7.920296E-03 +1.026935E-05 +1.007121E-02 +1.858100E-05 +1.510615E-02 +3.313591E-05 +8.793659E-03 +1.446961E-05 +1.205856E-02 +2.648093E-05 +8.862721E-03 +1.309660E-05 +1.096965E-02 +1.673476E-05 +9.547722E-03 +1.233633E-05 +1.206088E-02 +1.968307E-05 +1.373042E-02 +2.332622E-05 +7.956349E-03 +9.952553E-06 +1.135126E-02 +2.254375E-05 +8.206639E-03 +1.278801E-05 +8.323868E-03 +9.465618E-06 +5.007925E-03 +3.901625E-06 +1.175607E-02 +2.482648E-05 +1.115574E-02 +1.628158E-05 +1.194446E-02 +2.092004E-05 +1.597054E-02 +4.823093E-05 +2.068463E-02 +6.502935E-05 +1.091363E-02 +1.741992E-05 +1.977283E-02 +6.091082E-05 +1.302782E-02 +3.043481E-05 +9.410139E-03 +1.600990E-05 +2.280622E-02 +8.006568E-05 +1.891920E-02 +4.976676E-05 +1.429805E-02 +3.039093E-05 +1.718931E-02 +4.113244E-05 +1.888654E-02 +4.574971E-05 +1.694065E-02 +4.597734E-05 +2.282444E-02 +7.094719E-05 +1.988920E-02 +4.882297E-05 +2.742750E-02 +8.906026E-05 +2.101679E-02 +5.924755E-05 +1.895054E-02 +4.827704E-05 +1.764949E-02 +3.979458E-05 +2.040100E-02 +5.014728E-05 +2.987304E-02 +1.026215E-04 +1.943000E-02 +5.159278E-05 +2.438024E-02 +8.804424E-05 +1.861542E-02 +5.122973E-05 +2.192303E-02 +7.333728E-05 +2.042748E-02 +5.322568E-05 +1.860799E-02 +4.480883E-05 +2.511896E-02 +8.995213E-05 +2.543363E-02 +7.306514E-05 +2.559384E-02 +7.149326E-05 +2.813173E-02 +8.655606E-05 +1.981717E-02 +5.094262E-05 +3.244910E-02 +1.169817E-04 +2.278981E-02 +6.510336E-05 +2.089376E-02 +5.410560E-05 +4.419213E-02 +2.403809E-04 +3.061708E-02 +1.062702E-04 +2.717980E-02 +8.418003E-05 +2.722963E-02 +1.052169E-04 +3.623076E-02 +1.607841E-04 +3.979211E-02 +1.939688E-04 +2.474544E-02 +8.590714E-05 +3.372593E-02 +1.249071E-04 +2.961528E-02 +1.048999E-04 +3.445466E-02 +1.406914E-04 +2.454390E-02 +6.874037E-05 +2.368906E-02 +7.545364E-05 +3.410678E-02 +1.304264E-04 +2.229870E-02 +5.686464E-05 +2.886351E-02 +1.132080E-04 +2.149789E-02 +5.426448E-05 +3.009295E-02 +1.146713E-04 +3.196558E-02 +1.284969E-04 +2.870373E-02 +1.154291E-04 +2.864913E-02 +1.010245E-04 +2.270198E-02 +5.519665E-05 +2.760090E-02 +9.328867E-05 +2.484231E-02 +7.506549E-05 +2.750137E-02 +8.791015E-05 +3.435235E-02 +1.548738E-04 +2.827137E-02 +9.747974E-05 +2.704164E-02 +8.477548E-05 +3.021819E-02 +1.103214E-04 +3.294793E-02 +1.535995E-04 +4.645100E-02 +2.665607E-04 +1.872361E-02 +5.132776E-05 +2.760454E-02 +9.345927E-05 +3.258565E-02 +1.242178E-04 +3.666600E-02 +1.621867E-04 +2.545558E-02 +7.466531E-05 +2.185810E-02 +5.238791E-05 +3.105333E-02 +1.301601E-04 +3.170709E-02 +1.068496E-04 +1.858402E-02 +4.089794E-05 +2.136675E-02 +8.120782E-05 +2.443102E-02 +6.744651E-05 +2.220457E-02 +6.176678E-05 +2.702281E-02 +8.511652E-05 +2.446488E-02 +7.312450E-05 +2.589652E-02 +8.029643E-05 +2.337286E-02 +6.920676E-05 +2.906370E-02 +9.769604E-05 +1.361898E-02 +2.599329E-05 +1.718829E-02 +4.532911E-05 +2.553342E-02 +8.882028E-05 +1.945946E-02 +5.218395E-05 +1.097230E-02 +2.337563E-05 +2.298715E-02 +7.077749E-05 +2.181520E-02 +7.357036E-05 +1.664629E-02 +3.440840E-05 +1.886608E-02 +6.788750E-05 +1.789466E-02 +3.954208E-05 +1.813733E-02 +4.477178E-05 +1.319469E-02 +3.100847E-05 +1.940763E-02 +6.158493E-05 +1.149667E-02 +1.737857E-05 +2.405005E-02 +9.854391E-05 +1.421017E-02 +2.890108E-05 +1.029738E-02 +1.683759E-05 +1.065410E-02 +1.640087E-05 +9.811218E-03 +1.720212E-05 +1.158507E-02 +1.760286E-05 +1.432482E-02 +2.834073E-05 +3.465902E-03 +3.161524E-06 +1.038868E-02 +2.168047E-05 +1.116866E-02 +1.793978E-05 +8.524850E-03 +9.322322E-06 +1.237537E-02 +3.617368E-05 +1.465218E-02 +3.350573E-05 +7.514724E-03 +9.368017E-06 +2.560189E-03 +1.617445E-06 +8.383240E-03 +1.252593E-05 +9.446758E-03 +1.648768E-05 +7.696663E-03 +8.060991E-06 +9.311783E-03 +1.189977E-05 +6.939672E-03 +8.850888E-06 +5.252459E-03 +4.564362E-06 +7.234899E-03 +1.328951E-05 +8.665099E-03 +1.300142E-05 +9.793568E-03 +2.082520E-05 +8.825280E-03 +1.579613E-05 +1.194803E-02 +1.908193E-05 +1.074524E-02 +2.172388E-05 +1.481905E-02 +2.964893E-05 +1.294498E-02 +3.011738E-05 +8.115330E-03 +1.173017E-05 +1.093458E-02 +1.599591E-05 +1.415025E-02 +2.928045E-05 +8.999567E-03 +1.238982E-05 +7.873894E-03 +9.521432E-06 +7.526246E-03 +7.594924E-06 +1.349525E-02 +3.958103E-05 +1.459461E-02 +3.194364E-05 +1.198421E-02 +2.138597E-05 +1.015128E-02 +1.539096E-05 +1.747797E-02 +3.561184E-05 +2.401867E-02 +7.148091E-05 +1.586654E-02 +3.323231E-05 +1.800611E-02 +4.401522E-05 +1.463450E-02 +2.989044E-05 +1.683853E-02 +3.902727E-05 +1.359168E-02 +2.739250E-05 +9.625117E-03 +1.469220E-05 +1.294386E-02 +2.799895E-05 +1.103469E-02 +2.133672E-05 +1.869882E-02 +4.772681E-05 +1.503975E-02 +2.896451E-05 +1.677894E-02 +4.314601E-05 +2.258467E-02 +1.041456E-04 +1.878411E-02 +4.558049E-05 +1.310146E-02 +2.541487E-05 +1.653039E-02 +3.204738E-05 +1.927088E-02 +5.304249E-05 +8.390867E-03 +1.408823E-05 +1.750394E-02 +4.947439E-05 +1.909888E-02 +5.305029E-05 +1.321359E-02 +3.195949E-05 +1.767250E-02 +4.284184E-05 +1.766010E-02 +4.445269E-05 +1.752133E-02 +3.470706E-05 +2.024733E-02 +5.360810E-05 +1.219423E-02 +1.890812E-05 +1.433551E-02 +2.552372E-05 +1.488366E-02 +3.633706E-05 +1.309982E-02 +2.303088E-05 +1.409845E-02 +2.964092E-05 +1.364964E-02 +2.674995E-05 +2.346093E-02 +7.742790E-05 +1.619070E-02 +3.640820E-05 +1.814514E-02 +4.174971E-05 +2.088143E-02 +7.915120E-05 +2.104482E-02 +4.999110E-05 +2.108577E-02 +5.080473E-05 +1.346978E-02 +2.428984E-05 +1.812802E-02 +3.900263E-05 +1.634894E-02 +3.058475E-05 +1.823343E-02 +4.657246E-05 +1.701022E-02 +3.432397E-05 +1.436832E-02 +2.643066E-05 +1.883466E-02 +4.651260E-05 +1.591237E-02 +3.845574E-05 +1.590406E-02 +3.248073E-05 +1.054631E-02 +1.655070E-05 +2.057489E-02 +5.055329E-05 +1.697824E-02 +3.893444E-05 +1.770103E-02 +4.383559E-05 +2.134851E-02 +6.780393E-05 +1.403120E-02 +2.708815E-05 +1.449734E-02 +2.419619E-05 +1.239576E-02 +2.043627E-05 +1.415699E-02 +2.224645E-05 +1.888682E-02 +4.935465E-05 +2.160682E-02 +6.329152E-05 +2.247940E-02 +7.810124E-05 +9.606213E-03 +1.667840E-05 +2.476229E-02 +8.144159E-05 +1.725175E-02 +3.611282E-05 +1.207190E-02 +1.626596E-05 +1.353421E-02 +2.329766E-05 +1.059055E-02 +1.677463E-05 +9.737491E-03 +1.431106E-05 +6.593375E-03 +7.399377E-06 +7.039159E-03 +1.176702E-05 +1.413677E-02 +3.138472E-05 +1.094329E-02 +2.263303E-05 +6.672931E-03 +6.045366E-06 +1.032380E-02 +2.352298E-05 +8.848889E-03 +1.498309E-05 +1.268157E-02 +2.766060E-05 +7.349115E-03 +1.091693E-05 +1.228088E-02 +2.189060E-05 +1.067250E-02 +1.715732E-05 +1.212246E-02 +2.269620E-05 +4.674814E-03 +3.219220E-06 +8.219501E-03 +1.509768E-05 +1.073016E-02 +2.022852E-05 +9.406782E-03 +1.697200E-05 +7.646611E-03 +1.456233E-05 +1.080915E-02 +2.357182E-05 +6.308610E-03 +8.327166E-06 +7.590107E-03 +8.423541E-06 +1.348669E-02 +2.807690E-05 +1.095856E-02 +2.888898E-05 +5.395294E-03 +5.989965E-06 +6.079841E-03 +7.580064E-06 +7.505564E-03 +8.646729E-06 +6.201233E-03 +6.428779E-06 +1.063698E-02 +1.939413E-05 +7.313889E-03 +9.141624E-06 +9.430810E-03 +1.648005E-05 +4.842603E-03 +4.844512E-06 +5.427814E-03 +4.345647E-06 +6.437292E-03 +1.207973E-05 +8.251158E-03 +1.318350E-05 +8.809423E-03 +1.058811E-05 +5.856619E-03 +4.969559E-06 +6.991101E-03 +6.849651E-06 +5.629621E-03 +5.550323E-06 +2.585500E-03 +1.553122E-06 +1.066559E-02 +1.715979E-05 +3.085260E-03 +6.253271E-06 +9.034984E-03 +1.521387E-05 +6.190606E-03 +9.176053E-06 +9.871403E-03 +1.358973E-05 +9.739545E-03 +1.286586E-05 +7.798343E-03 +9.886920E-06 +8.149958E-03 +1.041850E-05 +2.102030E-02 +6.158217E-05 +1.435765E-02 +3.237028E-05 +7.642569E-03 +7.907376E-06 +1.123406E-02 +1.955695E-05 +1.457081E-02 +3.914562E-05 +1.788958E-02 +5.996510E-05 +1.769436E-02 +4.502383E-05 +1.240825E-02 +2.303672E-05 +1.715444E-02 +4.328672E-05 +1.566180E-02 +3.978890E-05 +1.487883E-02 +3.400964E-05 +8.561200E-03 +1.036201E-05 +2.295904E-02 +5.920445E-05 +1.388508E-02 +3.937752E-05 +1.678190E-02 +4.497456E-05 +2.154484E-02 +5.386125E-05 +6.765444E-03 +7.415266E-06 +1.215420E-02 +2.091620E-05 +2.017061E-02 +7.287759E-05 +1.909053E-02 +5.506644E-05 +1.735888E-02 +3.831995E-05 +1.991557E-02 +4.972306E-05 +1.790749E-02 +4.112227E-05 +1.407457E-02 +3.094925E-05 +2.974572E-02 +1.118172E-04 +1.708785E-02 +4.386435E-05 +2.659193E-02 +9.219939E-05 +3.035144E-02 +1.010119E-04 +1.546737E-02 +3.391982E-05 +1.887938E-02 +4.714248E-05 +1.653679E-02 +4.949250E-05 +2.110944E-02 +5.597556E-05 +2.409526E-02 +6.448595E-05 +2.230819E-02 +5.707848E-05 +1.670895E-02 +3.363955E-05 +1.501463E-02 +2.702669E-05 +1.631677E-02 +3.749166E-05 +1.693626E-02 +4.121173E-05 +2.622206E-02 +7.529216E-05 +2.377917E-02 +7.407839E-05 +1.384279E-02 +2.857021E-05 +2.126418E-02 +7.856414E-05 +1.911630E-02 +4.652883E-05 +2.184179E-02 +5.852148E-05 +1.866708E-02 +6.033622E-05 +1.172279E-02 +3.314139E-05 +1.311652E-02 +2.727134E-05 +1.670812E-02 +4.624330E-05 +1.830609E-02 +5.348783E-05 +8.513210E-03 +1.188353E-05 +1.897475E-02 +4.496529E-05 +1.598385E-02 +3.154883E-05 +1.811274E-02 +4.681726E-05 +1.851236E-02 +4.861112E-05 +1.207908E-02 +2.020737E-05 +1.762593E-02 +4.600809E-05 +1.426171E-02 +3.389465E-05 +1.390938E-02 +4.304132E-05 +1.119665E-02 +2.002203E-05 +7.985862E-03 +1.299182E-05 +1.682922E-02 +3.705605E-05 +1.031217E-02 +1.306045E-05 +1.806448E-02 +4.605140E-05 +1.608612E-02 +3.278234E-05 +7.379583E-03 +7.040180E-06 +1.449866E-02 +3.734314E-05 +1.126405E-02 +1.862160E-05 +1.434466E-02 +3.067276E-05 +1.321482E-02 +2.270946E-05 +1.175946E-02 +2.009819E-05 +8.940307E-03 +1.544249E-05 +1.025576E-02 +1.330247E-05 +1.007614E-02 +1.877197E-05 +8.436802E-03 +1.196625E-05 +2.085623E-02 +4.953759E-05 +1.670794E-02 +3.716863E-05 +1.187761E-02 +1.890192E-05 +1.850976E-02 +4.429493E-05 +4.944517E-03 +5.165715E-06 +8.128340E-03 +1.296218E-05 +1.004447E-02 +2.214422E-05 +9.963052E-03 +1.184842E-05 +7.100471E-03 +8.005623E-06 +8.470273E-03 +9.214382E-06 +1.033575E-02 +1.452750E-05 +9.624022E-03 +1.558452E-05 +8.869432E-03 +1.517840E-05 +1.644470E-02 +3.397196E-05 +7.598019E-03 +8.133919E-06 +8.945737E-03 +9.377464E-06 +5.254834E-03 +4.575273E-06 +7.542267E-03 +7.505652E-06 +9.629827E-03 +1.342434E-05 +1.060266E-02 +1.838055E-05 +3.984507E-03 +2.782462E-06 +6.823286E-03 +7.715504E-06 +8.192618E-03 +1.009785E-05 +6.740618E-03 +6.753208E-06 +1.002813E-02 +1.566585E-05 +1.402360E-02 +2.627061E-05 +9.551680E-03 +1.549743E-05 +8.410173E-03 +1.532161E-05 +9.576682E-03 +1.926642E-05 +1.644285E-02 +3.894395E-05 +9.352112E-03 +1.947845E-05 +9.522578E-03 +1.480589E-05 +1.000109E-02 +1.623473E-05 +1.271924E-02 +2.496798E-05 +1.245375E-02 +2.043780E-05 +1.519888E-02 +3.853835E-05 +6.618627E-03 +6.345424E-06 +7.617580E-03 +8.381516E-06 +7.713051E-03 +1.245806E-05 +8.903456E-03 +2.254781E-05 +1.402208E-02 +2.721848E-05 +1.177140E-02 +1.953130E-05 +1.553072E-02 +2.893580E-05 +1.482066E-02 +3.081970E-05 +9.853191E-03 +1.543282E-05 +1.186384E-02 +2.281665E-05 +1.908232E-02 +6.119132E-05 +1.778254E-02 +3.849134E-05 +1.611496E-02 +4.189813E-05 +1.421950E-02 +3.103442E-05 +2.000883E-02 +5.088716E-05 +1.245870E-02 +2.904861E-05 +2.474667E-02 +7.684411E-05 +1.941450E-02 +4.850566E-05 +1.968721E-02 +4.734318E-05 +2.432138E-02 +7.957731E-05 +1.944046E-02 +4.206030E-05 +2.088512E-02 +5.312412E-05 +2.457361E-02 +7.162438E-05 +2.803303E-02 +9.243404E-05 +2.233188E-02 +6.441041E-05 +2.574667E-02 +7.744780E-05 +2.097121E-02 +5.650314E-05 +2.655826E-02 +8.660847E-05 +3.014326E-02 +9.991619E-05 +2.918919E-02 +9.452555E-05 +2.056057E-02 +5.184372E-05 +2.990570E-02 +1.037648E-04 +2.737932E-02 +8.833139E-05 +2.356419E-02 +7.644776E-05 +3.458839E-02 +1.364027E-04 +3.248751E-02 +1.186240E-04 +3.228724E-02 +1.162923E-04 +2.982979E-02 +1.051045E-04 +2.749198E-02 +9.013699E-05 +2.265201E-02 +7.821751E-05 +2.861490E-02 +8.974738E-05 +3.877353E-02 +1.862085E-04 +2.264214E-02 +6.419386E-05 +2.565522E-02 +8.379023E-05 +3.327436E-02 +1.251213E-04 +3.365022E-02 +1.304927E-04 +3.331544E-02 +1.267184E-04 +3.940664E-02 +2.082874E-04 +3.417164E-02 +1.331489E-04 +3.695924E-02 +1.695935E-04 +3.660181E-02 +1.980269E-04 +3.049799E-02 +1.104243E-04 +3.359904E-02 +1.326383E-04 +2.972450E-02 +9.587313E-05 +2.323160E-02 +6.471218E-05 +1.839074E-02 +4.208719E-05 +2.714264E-02 +9.372657E-05 +2.872170E-02 +1.078922E-04 +3.679226E-02 +1.459261E-04 +2.377295E-02 +6.705585E-05 +3.481909E-02 +1.319533E-04 +3.638325E-02 +1.510511E-04 +2.047379E-02 +4.974814E-05 +3.932322E-02 +1.843858E-04 +1.516217E-02 +3.326445E-05 +2.722332E-02 +9.017263E-05 +1.892837E-02 +4.765562E-05 +1.649353E-02 +4.048523E-05 +2.604495E-02 +7.686911E-05 +2.994865E-02 +1.202039E-04 +1.882216E-02 +4.312602E-05 +1.766775E-02 +4.354878E-05 +2.897250E-02 +9.600078E-05 +2.918339E-02 +9.787984E-05 +2.599062E-02 +8.583368E-05 +3.616458E-02 +1.785317E-04 +1.716456E-02 +4.424230E-05 +2.976397E-02 +1.196639E-04 +2.137198E-02 +5.435882E-05 +1.498606E-02 +2.867869E-05 +2.026381E-02 +6.453877E-05 +2.108149E-02 +4.938367E-05 +1.505838E-02 +2.707808E-05 +1.913971E-02 +5.184273E-05 +2.583671E-02 +9.189443E-05 +2.089460E-02 +5.910541E-05 +2.539127E-02 +8.107037E-05 +2.284066E-02 +6.852612E-05 +9.835860E-03 +1.246182E-05 +1.766679E-02 +4.158408E-05 +1.105611E-02 +1.647013E-05 +1.530049E-02 +3.919500E-05 +1.429716E-02 +3.352166E-05 +1.357586E-02 +3.091775E-05 +1.403296E-02 +3.179172E-05 +1.978070E-02 +4.850759E-05 +2.453097E-02 +8.428665E-05 +1.939330E-02 +4.556576E-05 +1.086518E-02 +1.408645E-05 +1.579821E-02 +2.749151E-05 +6.361591E-03 +6.898179E-06 +7.702358E-03 +9.157872E-06 +1.066424E-02 +1.306101E-05 +9.634515E-03 +1.294132E-05 +1.081282E-02 +2.088218E-05 +1.644232E-02 +3.681578E-05 +9.494639E-03 +1.279154E-05 +5.636874E-03 +4.703193E-06 +1.434790E-02 +2.701384E-05 +1.369675E-02 +2.567531E-05 +1.234911E-02 +2.590620E-05 +1.416398E-02 +2.960800E-05 +1.122603E-02 +2.610403E-05 +1.184891E-02 +2.685267E-05 +1.469060E-02 +3.133618E-05 +2.298108E-02 +7.360049E-05 +1.696881E-02 +4.073271E-05 +1.829044E-02 +4.488597E-05 +8.021195E-03 +1.042375E-05 +7.483229E-03 +7.662752E-06 +9.938980E-03 +1.473587E-05 +6.186154E-03 +7.146893E-06 +1.873257E-02 +5.084856E-05 +1.274591E-02 +1.901691E-05 +1.717315E-02 +4.508495E-05 +2.587324E-02 +7.720386E-05 +1.352804E-02 +2.480610E-05 +1.759894E-02 +3.784552E-05 +1.498671E-02 +2.624849E-05 +2.471517E-02 +8.403653E-05 +2.938643E-02 +1.151484E-04 +2.091784E-02 +5.415805E-05 +1.642239E-02 +3.265718E-05 +2.253062E-02 +7.550922E-05 +1.773827E-02 +4.843752E-05 +1.778692E-02 +4.982541E-05 +3.337468E-02 +1.392002E-04 +3.682265E-02 +1.607062E-04 +2.911908E-02 +1.003985E-04 +2.664232E-02 +8.588222E-05 +2.953127E-02 +1.183748E-04 +2.406807E-02 +7.188877E-05 +3.628487E-02 +1.515959E-04 +3.071907E-02 +1.118121E-04 +3.755060E-02 +1.884817E-04 +3.845138E-02 +2.043330E-04 +4.208968E-02 +1.887229E-04 +2.650790E-02 +1.045695E-04 +4.879444E-02 +2.746335E-04 +3.995698E-02 +1.935956E-04 +3.437302E-02 +1.339692E-04 +4.424777E-02 +2.155808E-04 +4.000509E-02 +1.787367E-04 +3.942601E-02 +1.823141E-04 +5.484106E-02 +3.357163E-04 +5.027689E-02 +2.971747E-04 +5.028897E-02 +2.941870E-04 +5.290232E-02 +3.200207E-04 +3.871560E-02 +1.936856E-04 +4.561909E-02 +2.445140E-04 +5.329116E-02 +3.392022E-04 +6.411682E-02 +4.525641E-04 +4.491390E-02 +2.298662E-04 +4.543173E-02 +2.388585E-04 +4.973450E-02 +2.830273E-04 +4.837326E-02 +2.678945E-04 +5.988650E-02 +4.209610E-04 +5.451978E-02 +3.358217E-04 +7.335314E-02 +6.137308E-04 +7.801463E-02 +6.544817E-04 +5.589338E-02 +3.522166E-04 +5.916022E-02 +3.858273E-04 +4.698963E-02 +3.027433E-04 +5.895924E-02 +3.790017E-04 +4.172371E-02 +2.119338E-04 +3.894831E-02 +1.648204E-04 +5.343858E-02 +3.103206E-04 +4.977655E-02 +3.012635E-04 +6.585931E-02 +4.493935E-04 +5.729670E-02 +3.590518E-04 +5.609196E-02 +3.629946E-04 +6.500048E-02 +4.440662E-04 +4.327539E-02 +2.067690E-04 +5.097662E-02 +2.815490E-04 +4.628356E-02 +2.348648E-04 +4.666148E-02 +2.514991E-04 +3.669329E-02 +1.552102E-04 +4.034392E-02 +1.825094E-04 +5.718186E-02 +3.730299E-04 +3.997528E-02 +2.286198E-04 +5.850080E-02 +4.179988E-04 +3.979728E-02 +1.855473E-04 +6.121586E-02 +4.774824E-04 +5.116923E-02 +2.889253E-04 +4.642274E-02 +2.436217E-04 +5.061482E-02 +2.853049E-04 +3.070349E-02 +1.198974E-04 +4.050110E-02 +1.836951E-04 +2.876275E-02 +1.060796E-04 +3.061263E-02 +1.137168E-04 +4.146381E-02 +1.869894E-04 +4.129877E-02 +1.932088E-04 +3.448209E-02 +1.434523E-04 +3.610442E-02 +1.605801E-04 +4.093512E-02 +1.814782E-04 +4.568118E-02 +2.299954E-04 +3.364878E-02 +1.376802E-04 +3.936126E-02 +1.675197E-04 +1.952985E-02 +4.623048E-05 +2.129951E-02 +6.166111E-05 +2.459526E-02 +8.426675E-05 +1.884092E-02 +4.164051E-05 +3.428763E-02 +1.417068E-04 +3.407514E-02 +1.241486E-04 +3.064802E-02 +1.103630E-04 +2.019877E-02 +7.059498E-05 +3.794436E-02 +1.883194E-04 +3.266721E-02 +1.280477E-04 +2.490808E-02 +7.281690E-05 +3.064961E-02 +1.125362E-04 +1.514239E-02 +2.910925E-05 +1.569321E-02 +3.950962E-05 +1.817240E-02 +4.154077E-05 +1.593815E-02 +3.459272E-05 +2.573968E-02 +8.029098E-05 +2.193871E-02 +6.210741E-05 +1.234720E-02 +1.843394E-05 +1.130766E-02 +2.245547E-05 +1.418762E-02 +3.357410E-05 +1.391485E-02 +2.559415E-05 +1.331696E-02 +2.115069E-05 +1.903725E-02 +4.411480E-05 +2.293870E-02 +6.557987E-05 +2.241944E-02 +7.768129E-05 +8.399478E-03 +1.343754E-05 +1.217880E-02 +2.018185E-05 +1.416256E-02 +2.227003E-05 +1.520064E-02 +2.978679E-05 +1.664846E-02 +4.183492E-05 +1.339491E-02 +2.674827E-05 +9.628607E-03 +1.279454E-05 +1.158026E-02 +1.554728E-05 +1.367791E-02 +2.379966E-05 +1.376699E-02 +2.264472E-05 +1.833088E-02 +4.495911E-05 +2.473484E-02 +1.122059E-04 +1.980130E-02 +4.468138E-05 +2.937836E-02 +1.114018E-04 +2.021222E-02 +4.559590E-05 +2.115889E-02 +5.272398E-05 +2.751444E-02 +8.716393E-05 +3.118255E-02 +1.201980E-04 +3.295258E-02 +1.221249E-04 +3.264934E-02 +1.357065E-04 +2.388443E-02 +6.703731E-05 +2.649789E-02 +7.940354E-05 +4.696656E-02 +2.514244E-04 +4.553686E-02 +2.438972E-04 +3.908818E-02 +1.840355E-04 +4.402566E-02 +2.377775E-04 +3.875910E-02 +1.778735E-04 +3.543152E-02 +1.527725E-04 +6.193982E-02 +4.578553E-04 +4.402817E-02 +2.274373E-04 +3.677275E-02 +1.884320E-04 +5.902021E-02 +3.951715E-04 +4.943375E-02 +2.711632E-04 +3.724773E-02 +1.641879E-04 +4.993443E-02 +2.771281E-04 +7.563062E-02 +6.734531E-04 +4.553601E-02 +2.283737E-04 +5.336189E-02 +3.085766E-04 +6.930581E-02 +5.723133E-04 +4.674295E-02 +2.785390E-04 +8.412725E-02 +7.467027E-04 +6.681883E-02 +4.824696E-04 +8.430398E-02 +7.823907E-04 +9.943266E-02 +1.106796E-03 +8.916803E-02 +8.767378E-04 +7.239961E-02 +6.787255E-04 +8.722424E-02 +9.332353E-04 +1.031401E-01 +1.218166E-03 +7.299280E-02 +5.585065E-04 +8.196460E-02 +7.464830E-04 +7.514349E-02 +6.162898E-04 +7.409781E-02 +6.092201E-04 +1.155025E-01 +1.496467E-03 +1.069759E-01 +1.259983E-03 +1.226295E-01 +1.569654E-03 +1.503421E-01 +2.355624E-03 +1.080703E-01 +1.309087E-03 +1.129782E-01 +1.371142E-03 +8.048452E-02 +7.348043E-04 +1.058381E-01 +1.164709E-03 +6.615819E-02 +4.794240E-04 +7.980754E-02 +6.987820E-04 +1.120426E-01 +1.285452E-03 +1.016962E-01 +1.116490E-03 +1.045603E-01 +1.203503E-03 +9.692551E-02 +1.029307E-03 +1.510121E-01 +2.326069E-03 +1.459994E-01 +2.277384E-03 +8.473854E-02 +7.832629E-04 +1.294853E-01 +1.741522E-03 +6.032354E-02 +3.886121E-04 +6.987142E-02 +5.446194E-04 +7.739481E-02 +6.779391E-04 +6.202592E-02 +4.288928E-04 +1.105924E-01 +1.283621E-03 +9.239492E-02 +9.223732E-04 +6.604268E-02 +4.595692E-04 +7.012590E-02 +5.276378E-04 +9.125615E-02 +8.968665E-04 +8.440076E-02 +7.298457E-04 +6.290364E-02 +4.350725E-04 +9.542023E-02 +1.023159E-03 +3.785503E-02 +1.773114E-04 +5.510138E-02 +3.186315E-04 +4.425845E-02 +2.296502E-04 +5.216949E-02 +3.102279E-04 +5.711604E-02 +3.708531E-04 +6.348926E-02 +4.437737E-04 +3.531423E-02 +1.381941E-04 +4.676905E-02 +2.710798E-04 +5.132004E-02 +2.836163E-04 +4.379959E-02 +2.484735E-04 +5.314318E-02 +3.059228E-04 +6.677411E-02 +5.104497E-04 +2.953361E-02 +1.221048E-04 +3.348688E-02 +1.218024E-04 +3.189405E-02 +1.283561E-04 +3.066128E-02 +1.074943E-04 +2.627008E-02 +7.434735E-05 +4.099188E-02 +1.844425E-04 +2.657946E-02 +8.006763E-05 +2.677024E-02 +9.837536E-05 +2.297001E-02 +6.348807E-05 +2.847736E-02 +1.016726E-04 +3.650898E-02 +1.905274E-04 +3.678596E-02 +1.737202E-04 +9.741068E-03 +1.427221E-05 +2.112559E-02 +7.299641E-05 +1.626433E-02 +3.325133E-05 +1.556047E-02 +3.623423E-05 +2.005845E-02 +4.817075E-05 +2.235018E-02 +6.309213E-05 +1.555635E-02 +3.399168E-05 +8.473936E-03 +1.206918E-05 +2.003025E-02 +5.771667E-05 +1.619274E-02 +3.694213E-05 +2.398087E-02 +8.309002E-05 +2.048279E-02 +5.775057E-05 +1.959187E-02 +4.755352E-05 +1.817346E-02 +4.751135E-05 +1.533477E-02 +4.769982E-05 +1.889382E-02 +4.706002E-05 +1.855621E-02 +4.644130E-05 +3.121451E-02 +1.173056E-04 +1.135235E-02 +2.022523E-05 +1.457214E-02 +3.250403E-05 +1.330384E-02 +2.287686E-05 +1.426049E-02 +2.827899E-05 +2.255732E-02 +6.597520E-05 +1.409157E-02 +2.947510E-05 +2.387117E-02 +7.502115E-05 +3.498075E-02 +1.588586E-04 +2.661630E-02 +9.051962E-05 +3.141346E-02 +1.130104E-04 +2.363639E-02 +7.247261E-05 +2.949581E-02 +1.015620E-04 +3.405344E-02 +1.368730E-04 +3.067699E-02 +1.186942E-04 +2.860325E-02 +1.027432E-04 +3.136948E-02 +1.261067E-04 +2.884168E-02 +9.121556E-05 +3.172681E-02 +1.271781E-04 +6.082138E-02 +3.967354E-04 +4.665628E-02 +2.447254E-04 +3.873489E-02 +1.666752E-04 +5.112906E-02 +2.817112E-04 +3.867668E-02 +1.713578E-04 +4.211970E-02 +1.934977E-04 +6.886477E-02 +4.937257E-04 +7.019363E-02 +5.620739E-04 +5.569741E-02 +3.372249E-04 +5.856502E-02 +3.766765E-04 +5.390171E-02 +3.381837E-04 +4.680414E-02 +2.500022E-04 +1.026456E-01 +1.147075E-03 +8.535063E-02 +7.808065E-04 +8.630449E-02 +8.031445E-04 +1.052149E-01 +1.184292E-03 +7.701701E-02 +6.253512E-04 +7.834187E-02 +6.672354E-04 +1.359360E-01 +1.907855E-03 +1.460384E-01 +2.190423E-03 +1.080390E-01 +1.234268E-03 +1.317673E-01 +1.856930E-03 +9.690172E-02 +1.006627E-03 +9.258404E-02 +9.457422E-04 +1.832246E-01 +3.427961E-03 +2.054091E-01 +4.398902E-03 +1.593682E-01 +2.662133E-03 +1.880778E-01 +3.629787E-03 +2.013148E-01 +4.265877E-03 +1.990549E-01 +4.200017E-03 +5.469090E-01 +3.082757E-02 +5.552625E-01 +3.233826E-02 +2.571401E-01 +6.723483E-03 +8.548854E-01 +7.413280E-02 +5.209393E-01 +2.787584E-02 +5.093657E-01 +2.715480E-02 +1.566145E-01 +2.600405E-03 +1.993120E-01 +4.010479E-03 +1.707332E-01 +2.996975E-03 +1.840203E-01 +3.525950E-03 +5.686602E-01 +3.269532E-02 +5.046470E-01 +2.580015E-02 +1.740098E-01 +3.137069E-03 +1.748447E-01 +3.287313E-03 +5.281969E-01 +2.835860E-02 +5.218758E-01 +2.764449E-02 +2.811590E-01 +8.077168E-03 +7.835313E-01 +6.174409E-02 +8.916676E-02 +8.704144E-04 +1.147415E-01 +1.428848E-03 +1.059630E-01 +1.142821E-03 +9.640793E-02 +9.919169E-04 +1.380046E-01 +2.013093E-03 +1.453872E-01 +2.230703E-03 +8.067716E-02 +7.607075E-04 +7.414787E-02 +5.831873E-04 +1.108173E-01 +1.334816E-03 +9.716310E-02 +1.050788E-03 +1.058275E-01 +1.176253E-03 +1.234077E-01 +1.611857E-03 +4.645374E-02 +2.489769E-04 +5.612855E-02 +3.674944E-04 +5.305509E-02 +3.127379E-04 +4.929601E-02 +2.809620E-04 +6.549144E-02 +4.537754E-04 +6.303494E-02 +4.236715E-04 +3.880272E-02 +1.704460E-04 +3.861758E-02 +1.663017E-04 +5.862395E-02 +3.858310E-04 +4.737923E-02 +2.823280E-04 +5.280787E-02 +3.043443E-04 +5.249474E-02 +3.019614E-04 +2.485904E-02 +6.701075E-05 +2.926990E-02 +9.417758E-05 +3.125676E-02 +1.037311E-04 +3.289406E-02 +1.368340E-04 +4.071134E-02 +1.830700E-04 +4.109741E-02 +2.038834E-04 +2.347652E-02 +7.157581E-05 +2.072441E-02 +5.807283E-05 +4.102695E-02 +2.107954E-04 +2.166639E-02 +5.788402E-05 +3.219359E-02 +1.250457E-04 +2.832465E-02 +9.610853E-05 +1.624643E-02 +3.730962E-05 +1.725120E-02 +4.481115E-05 +1.578099E-02 +3.024585E-05 +1.571746E-02 +3.035996E-05 +1.731202E-02 +3.502473E-05 +1.643420E-02 +3.632173E-05 +1.040551E-02 +1.294862E-05 +1.127727E-02 +2.039819E-05 +1.438022E-02 +2.857038E-05 +1.260556E-02 +2.928756E-05 +2.034502E-02 +6.038560E-05 +1.640843E-02 +3.872409E-05 +2.122181E-02 +6.703870E-05 +1.545958E-02 +2.933443E-05 +1.550763E-02 +3.859489E-05 +1.928201E-02 +4.243101E-05 +2.196809E-02 +5.810938E-05 +2.193973E-02 +5.702613E-05 +1.517387E-02 +3.300117E-05 +1.732347E-02 +3.857976E-05 +1.415891E-02 +2.906573E-05 +1.407775E-02 +3.402531E-05 +2.277203E-02 +7.764043E-05 +1.580648E-02 +4.707367E-05 +2.763176E-02 +9.424628E-05 +2.372205E-02 +6.537717E-05 +2.585656E-02 +7.555138E-05 +3.438842E-02 +1.498651E-04 +1.953849E-02 +4.797528E-05 +2.039273E-02 +6.513710E-05 +3.691903E-02 +1.454538E-04 +3.217932E-02 +1.398798E-04 +2.774657E-02 +8.279249E-05 +2.820457E-02 +9.228219E-05 +3.106567E-02 +1.239322E-04 +1.804981E-02 +4.099893E-05 +5.969428E-02 +3.940876E-04 +5.835174E-02 +4.018253E-04 +5.448605E-02 +3.344901E-04 +6.458561E-02 +4.749467E-04 +4.505232E-02 +2.290467E-04 +4.529186E-02 +2.210661E-04 +6.923883E-02 +5.074459E-04 +6.905166E-02 +5.269603E-04 +4.247615E-02 +2.080915E-04 +5.430061E-02 +3.320737E-04 +6.603377E-02 +5.144612E-04 +5.251003E-02 +3.190205E-04 +1.030147E-01 +1.109176E-03 +8.155464E-02 +7.067482E-04 +8.922744E-02 +8.197146E-04 +1.284288E-01 +1.811686E-03 +9.277212E-02 +8.820708E-04 +7.960421E-02 +7.018415E-04 +1.101447E-01 +1.238620E-03 +1.594606E-01 +2.631417E-03 +7.676797E-02 +6.249548E-04 +9.678537E-02 +1.039683E-03 +1.315012E-01 +1.823501E-03 +9.822710E-02 +1.049106E-03 +2.200833E-01 +4.944909E-03 +1.814148E-01 +3.455606E-03 +2.808713E-01 +7.998623E-03 +8.607047E-01 +7.471518E-02 +1.510873E-01 +2.350444E-03 +1.952158E-01 +3.987281E-03 +2.563955E-01 +6.736419E-03 +8.288790E-01 +6.935905E-02 +1.663306E-01 +2.909230E-03 +2.069533E-01 +4.392557E-03 +8.171538E-01 +6.926168E-02 +2.771724E-01 +7.947364E-03 +1.718421E-01 +3.078316E-03 +1.912710E-01 +3.901809E-03 +4.978656E-01 +2.591511E-02 +4.943901E-01 +2.504533E-02 +2.519316E-01 +6.571958E-03 +7.930433E-01 +6.483055E-02 +1.486665E-01 +2.270454E-03 +2.161805E-01 +4.796812E-03 +1.737906E-01 +3.149960E-03 +1.909929E-01 +3.837468E-03 +5.280144E-01 +2.824797E-02 +5.994269E-01 +3.679537E-02 +8.367283E-02 +8.246835E-04 +9.345285E-02 +9.180702E-04 +1.084220E-01 +1.234841E-03 +1.132694E-01 +1.417334E-03 +1.213506E-01 +1.536611E-03 +1.485290E-01 +2.261244E-03 +7.557519E-02 +6.112603E-04 +7.935833E-02 +6.583374E-04 +1.009825E-01 +1.083491E-03 +7.954123E-02 +7.044944E-04 +1.118116E-01 +1.371403E-03 +1.197452E-01 +1.570554E-03 +5.190598E-02 +3.551665E-04 +5.730111E-02 +3.980792E-04 +6.248836E-02 +4.466985E-04 +6.019178E-02 +4.124940E-04 +7.202094E-02 +5.415764E-04 +7.189177E-02 +5.472909E-04 +3.981535E-02 +1.797809E-04 +4.820928E-02 +2.773872E-04 +5.050408E-02 +2.801362E-04 +5.149907E-02 +3.058260E-04 +6.167709E-02 +3.980579E-04 +6.251960E-02 +4.234132E-04 +2.843012E-02 +8.808063E-05 +2.337612E-02 +6.606638E-05 +2.936391E-02 +9.914901E-05 +3.131118E-02 +1.224255E-04 +3.590121E-02 +1.554613E-04 +3.734616E-02 +1.611929E-04 +2.718818E-02 +8.275683E-05 +2.355063E-02 +6.269602E-05 +3.417456E-02 +1.470468E-04 +2.761636E-02 +8.857401E-05 +2.817665E-02 +9.358473E-05 +4.330547E-02 +2.125793E-04 +1.281131E-02 +2.508003E-05 +1.558497E-02 +4.131225E-05 +1.604825E-02 +3.789735E-05 +1.198312E-02 +2.201855E-05 +1.841476E-02 +4.406610E-05 +2.191664E-02 +5.706023E-05 +1.037877E-02 +1.403046E-05 +1.142906E-02 +1.784198E-05 +2.165180E-02 +7.328897E-05 +1.781165E-02 +3.964227E-05 +1.706685E-02 +3.626318E-05 +2.611118E-02 +8.937284E-05 +1.889982E-02 +5.096931E-05 +1.354993E-02 +3.469204E-05 +1.092599E-02 +1.697195E-05 +1.380052E-02 +2.909184E-05 +2.326409E-02 +7.737047E-05 +2.386034E-02 +7.722570E-05 +1.642655E-02 +4.387424E-05 +1.696224E-02 +3.657599E-05 +1.094347E-02 +1.803801E-05 +1.156552E-02 +2.421906E-05 +1.583036E-02 +3.257752E-05 +1.517584E-02 +3.200691E-05 +3.827074E-02 +1.889669E-04 +2.449951E-02 +7.459613E-05 +2.623209E-02 +8.154118E-05 +2.849776E-02 +9.089323E-05 +2.334185E-02 +6.201992E-05 +2.654520E-02 +9.694536E-05 +3.237617E-02 +1.167467E-04 +3.675105E-02 +1.763620E-04 +2.004612E-02 +5.066812E-05 +2.903446E-02 +9.486419E-05 +3.334691E-02 +1.228445E-04 +2.623258E-02 +7.799037E-05 +4.888525E-02 +2.729676E-04 +3.600959E-02 +1.553932E-04 +5.438364E-02 +3.353294E-04 +5.232566E-02 +2.992982E-04 +3.034775E-02 +1.324830E-04 +4.164626E-02 +2.036943E-04 +5.059600E-02 +2.935825E-04 +5.879411E-02 +3.888487E-04 +3.938426E-02 +2.093554E-04 +4.838794E-02 +2.715001E-04 +4.972503E-02 +2.740094E-04 +4.955213E-02 +2.667621E-04 +6.113745E-02 +4.048275E-04 +5.341164E-02 +3.153602E-04 +5.975662E-02 +3.838000E-04 +8.595500E-02 +8.321615E-04 +6.107919E-02 +3.898803E-04 +5.530668E-02 +3.235594E-04 +7.580790E-02 +6.272237E-04 +9.941256E-02 +1.054222E-03 +6.091493E-02 +3.907622E-04 +6.317933E-02 +4.235462E-04 +1.014991E-01 +1.038642E-03 +7.701856E-02 +6.147885E-04 +1.112163E-01 +1.265790E-03 +7.536078E-02 +5.769678E-04 +1.302318E-01 +1.742411E-03 +1.635988E-01 +2.867432E-03 +7.255186E-02 +6.284552E-04 +1.087261E-01 +1.292949E-03 +1.071717E-01 +1.182413E-03 +1.275727E-01 +1.701949E-03 +7.308862E-02 +5.588046E-04 +8.677475E-02 +7.923200E-04 +1.598968E-01 +2.752916E-03 +1.090514E-01 +1.267867E-03 +9.373573E-02 +9.468462E-04 +8.656897E-02 +7.993780E-04 +1.556811E-01 +2.570483E-03 +1.563481E-01 +2.547541E-03 +1.019280E-01 +1.066946E-03 +1.407263E-01 +2.139026E-03 +9.439261E-02 +9.727226E-04 +1.162727E-01 +1.469225E-03 +8.572873E-02 +7.472360E-04 +8.412598E-02 +7.378763E-04 +1.184615E-01 +1.447843E-03 +1.129877E-01 +1.387240E-03 +7.089346E-02 +5.210102E-04 +7.106181E-02 +5.601420E-04 +9.767580E-02 +1.010123E-03 +8.639404E-02 +7.865066E-04 +8.288207E-02 +7.425178E-04 +8.992435E-02 +9.501100E-04 +6.866676E-02 +5.516503E-04 +6.325590E-02 +4.342044E-04 +7.431495E-02 +6.348268E-04 +7.599335E-02 +5.991771E-04 +7.274975E-02 +5.571106E-04 +6.766739E-02 +5.249260E-04 +3.181945E-02 +1.159273E-04 +4.099202E-02 +1.863511E-04 +4.739506E-02 +2.375175E-04 +4.566762E-02 +2.462349E-04 +4.309564E-02 +2.169367E-04 +4.968602E-02 +2.836430E-04 +2.554238E-02 +7.130377E-05 +3.399568E-02 +1.313338E-04 +4.489588E-02 +2.608490E-04 +3.609823E-02 +1.664739E-04 +3.688252E-02 +1.524824E-04 +4.371937E-02 +2.194516E-04 +2.432742E-02 +6.816206E-05 +2.481126E-02 +7.715594E-05 +3.225220E-02 +1.297648E-04 +2.820482E-02 +8.756926E-05 +2.911932E-02 +9.466605E-05 +3.374238E-02 +1.328376E-04 +2.602288E-02 +8.674133E-05 +2.044276E-02 +4.796182E-05 +2.621162E-02 +8.521865E-05 +3.451732E-02 +1.272449E-04 +2.497288E-02 +7.862985E-05 +3.797623E-02 +1.934870E-04 +1.693158E-02 +3.957575E-05 +2.516921E-02 +7.540607E-05 +1.916047E-02 +5.115510E-05 +1.903519E-02 +5.491559E-05 +1.655257E-02 +2.970206E-05 +1.806193E-02 +4.421369E-05 +1.074232E-02 +1.704622E-05 +9.240900E-03 +1.255060E-05 +1.183407E-02 +1.748671E-05 +9.219696E-03 +1.609190E-05 +1.034386E-02 +1.462148E-05 +1.114705E-02 +1.850428E-05 +1.297960E-02 +2.423078E-05 +1.184491E-02 +2.140225E-05 +1.658431E-02 +4.388936E-05 +1.318219E-02 +2.389643E-05 +1.560221E-02 +3.262330E-05 +1.536994E-02 +2.967325E-05 +1.474070E-02 +2.850636E-05 +1.423540E-02 +2.724881E-05 +1.128414E-02 +1.691587E-05 +7.509669E-03 +1.138736E-05 +1.063708E-02 +1.760414E-05 +1.145186E-02 +2.083540E-05 +1.762181E-02 +4.474974E-05 +2.084088E-02 +6.507170E-05 +2.057308E-02 +5.516523E-05 +2.241191E-02 +7.120840E-05 +1.269523E-02 +2.005337E-05 +1.660064E-02 +3.697642E-05 +3.182773E-02 +1.204858E-04 +3.242190E-02 +1.182654E-04 +2.434893E-02 +7.105045E-05 +2.652135E-02 +7.481704E-05 +1.907560E-02 +5.087922E-05 +2.190903E-02 +6.429867E-05 +3.105119E-02 +1.183209E-04 +2.464967E-02 +7.797261E-05 +2.817912E-02 +9.460889E-05 +4.586402E-02 +2.494422E-04 +3.145613E-02 +1.306566E-04 +3.581523E-02 +1.371038E-04 +3.824846E-02 +1.899412E-04 +4.263531E-02 +1.873636E-04 +3.042311E-02 +1.167731E-04 +2.732643E-02 +7.846176E-05 +4.050189E-02 +1.908935E-04 +3.434384E-02 +1.361814E-04 +4.495849E-02 +2.646832E-04 +4.092138E-02 +2.017353E-04 +5.344413E-02 +3.250472E-04 +4.697795E-02 +2.453442E-04 +3.679979E-02 +1.575515E-04 +3.908452E-02 +1.742990E-04 +4.284114E-02 +2.154331E-04 +4.380058E-02 +2.263026E-04 +3.985455E-02 +1.829559E-04 +3.394862E-02 +1.228745E-04 +4.744764E-02 +2.814058E-04 +3.949446E-02 +1.946576E-04 +6.109758E-02 +4.065478E-04 +5.344244E-02 +3.173404E-04 +5.996641E-02 +3.831573E-04 +7.955351E-02 +6.865984E-04 +4.384271E-02 +1.999570E-04 +6.435559E-02 +4.377030E-04 +4.969051E-02 +2.811028E-04 +5.599815E-02 +3.868544E-04 +4.163040E-02 +2.191546E-04 +4.845338E-02 +2.687605E-04 +7.016148E-02 +5.682673E-04 +6.371981E-02 +4.441518E-04 +6.553775E-02 +4.702345E-04 +5.818627E-02 +3.716053E-04 +7.301288E-02 +5.661570E-04 +6.855403E-02 +4.925246E-04 +4.751877E-02 +3.119215E-04 +6.178405E-02 +4.942348E-04 +5.778084E-02 +3.682642E-04 +6.794905E-02 +4.813721E-04 +4.580484E-02 +2.283874E-04 +4.833285E-02 +2.496503E-04 +6.283852E-02 +4.289179E-04 +5.868559E-02 +3.829967E-04 +4.942181E-02 +2.770674E-04 +4.633288E-02 +2.530825E-04 +6.521627E-02 +4.531563E-04 +6.926577E-02 +4.930307E-04 +4.947134E-02 +2.743687E-04 +5.599354E-02 +3.625867E-04 +4.586533E-02 +2.169603E-04 +6.057563E-02 +3.949284E-04 +3.269565E-02 +1.324708E-04 +3.688715E-02 +1.561195E-04 +4.607386E-02 +2.561957E-04 +4.286297E-02 +2.186313E-04 +3.835517E-02 +1.807457E-04 +3.101308E-02 +1.258603E-04 +4.256564E-02 +2.156265E-04 +3.995257E-02 +1.962160E-04 +3.999004E-02 +1.700193E-04 +4.593940E-02 +2.325862E-04 +2.746637E-02 +1.056011E-04 +2.945679E-02 +1.039840E-04 +4.237269E-02 +1.976737E-04 +3.339233E-02 +1.438661E-04 +3.371702E-02 +1.468814E-04 +3.238843E-02 +1.164792E-04 +2.064297E-02 +5.618891E-05 +2.155723E-02 +6.462578E-05 +2.273621E-02 +5.819206E-05 +1.964446E-02 +5.147180E-05 +2.401285E-02 +7.795637E-05 +2.729940E-02 +9.076729E-05 +2.213041E-02 +6.949614E-05 +1.338392E-02 +2.465408E-05 +2.431872E-02 +7.724266E-05 +2.524967E-02 +1.026115E-04 +2.737266E-02 +9.841098E-05 +2.112771E-02 +5.889604E-05 +1.496282E-02 +4.007026E-05 +1.889629E-02 +5.468925E-05 +1.783224E-02 +4.566541E-05 +8.331789E-03 +9.954892E-06 +1.796677E-02 +3.918970E-05 +1.970964E-02 +4.450042E-05 +1.137654E-02 +1.965594E-05 +8.407972E-03 +1.166241E-05 +1.447552E-02 +2.605420E-05 +8.376429E-03 +1.246530E-05 +1.335436E-02 +3.392789E-05 +1.200101E-02 +2.280708E-05 +1.602954E-02 +3.739523E-05 +9.669299E-03 +1.679999E-05 +1.566345E-02 +3.502619E-05 +1.588366E-02 +3.186835E-05 +1.901368E-02 +4.343637E-05 +2.267083E-02 +7.178904E-05 +9.004042E-03 +1.176762E-05 +1.804933E-02 +4.338938E-05 +1.071906E-02 +1.634166E-05 +9.615294E-03 +1.267674E-05 +1.558814E-02 +2.851576E-05 +1.376105E-02 +2.761523E-05 +1.902761E-02 +6.150446E-05 +1.854745E-02 +5.066723E-05 +1.702864E-02 +4.027369E-05 +2.099003E-02 +6.424422E-05 +2.011904E-02 +5.529868E-05 +1.661724E-02 +3.837653E-05 +1.373297E-02 +2.945958E-05 +1.569666E-02 +3.146459E-05 +1.202400E-02 +1.784017E-05 +1.532156E-02 +4.083467E-05 +1.855533E-02 +4.148169E-05 +2.388887E-02 +7.104659E-05 +3.029475E-02 +1.112701E-04 +3.479830E-02 +1.457081E-04 +2.993443E-02 +1.034283E-04 +2.618538E-02 +8.150737E-05 +1.973658E-02 +5.388325E-05 +1.908984E-02 +4.925317E-05 +2.558471E-02 +7.645976E-05 +3.057900E-02 +1.526871E-04 +2.038898E-02 +6.028856E-05 +1.936824E-02 +5.652676E-05 +1.860724E-02 +4.433157E-05 +1.859342E-02 +6.046452E-05 +3.104650E-02 +1.107731E-04 +2.791826E-02 +8.517252E-05 +2.550906E-02 +7.911190E-05 +3.228374E-02 +1.235126E-04 +2.983461E-02 +1.169772E-04 +2.340715E-02 +7.962272E-05 +2.472431E-02 +7.854176E-05 +3.116101E-02 +1.113261E-04 +2.726866E-02 +8.448946E-05 +2.872167E-02 +1.004750E-04 +3.032428E-02 +1.229901E-04 +3.053428E-02 +1.122910E-04 +3.083822E-02 +1.483669E-04 +2.064536E-02 +5.782771E-05 +3.181149E-02 +1.187295E-04 +4.583432E-02 +2.558159E-04 +2.666121E-02 +9.350519E-05 +3.358219E-02 +1.192091E-04 +2.369325E-02 +8.059778E-05 +3.102351E-02 +1.289691E-04 +2.820355E-02 +1.068875E-04 +3.480350E-02 +1.443944E-04 +3.560608E-02 +1.469841E-04 +4.990478E-02 +3.032798E-04 +3.784020E-02 +1.765328E-04 +3.316256E-02 +1.290263E-04 +4.033997E-02 +1.799350E-04 +3.929687E-02 +1.626134E-04 +3.235240E-02 +1.382862E-04 +3.388379E-02 +1.425521E-04 +3.879634E-02 +1.814360E-04 +3.990331E-02 +1.937058E-04 +2.486877E-02 +7.060573E-05 +2.847067E-02 +8.714105E-05 +4.490738E-02 +2.182380E-04 +3.277939E-02 +1.222614E-04 +2.300113E-02 +6.725020E-05 +3.241132E-02 +1.183039E-04 +3.117719E-02 +1.083016E-04 +2.675135E-02 +8.558799E-05 +3.944468E-02 +1.742389E-04 +4.399132E-02 +2.295328E-04 +2.087405E-02 +4.684764E-05 +1.956671E-02 +4.488034E-05 +3.135372E-02 +1.064232E-04 +1.852589E-02 +4.046644E-05 +2.367532E-02 +7.100616E-05 +2.728169E-02 +9.976058E-05 +2.896959E-02 +9.844663E-05 +2.865198E-02 +1.092590E-04 +3.163730E-02 +1.082131E-04 +3.268958E-02 +1.309514E-04 +2.046897E-02 +4.893795E-05 +2.472680E-02 +7.874493E-05 +2.926292E-02 +1.081766E-04 +3.002458E-02 +1.013573E-04 +1.360951E-02 +2.635847E-05 +2.311727E-02 +6.168251E-05 +3.020182E-02 +1.206713E-04 +2.697417E-02 +8.378246E-05 +1.334960E-02 +2.306197E-05 +1.590087E-02 +4.689125E-05 +2.011479E-02 +6.965285E-05 +1.633667E-02 +3.972970E-05 +2.002848E-02 +4.881276E-05 +2.201774E-02 +5.990084E-05 +1.590141E-02 +4.489842E-05 +1.287558E-02 +2.913250E-05 +1.902193E-02 +5.067435E-05 +1.740647E-02 +4.536926E-05 +2.127020E-02 +6.939263E-05 +1.655808E-02 +3.850014E-05 +1.186084E-02 +2.566137E-05 +1.183085E-02 +2.088219E-05 +1.691039E-02 +4.357920E-05 +6.413071E-03 +5.791752E-06 +1.069744E-02 +1.593929E-05 +9.843254E-03 +1.483187E-05 +6.822909E-03 +6.785866E-06 +4.540728E-03 +3.073065E-06 +1.381635E-02 +3.287951E-05 +9.881421E-03 +1.765396E-05 +5.794819E-03 +6.579960E-06 +1.064665E-02 +1.825529E-05 +9.708618E-03 +2.420624E-05 +3.867809E-03 +3.463878E-06 +1.036922E-02 +1.880088E-05 +1.209814E-02 +2.247120E-05 +6.289728E-03 +9.053460E-06 +1.121820E-02 +2.376217E-05 +6.107387E-03 +9.842112E-06 +6.679042E-03 +7.917785E-06 +4.610676E-03 +3.822313E-06 +8.094200E-03 +1.556770E-05 +1.289830E-02 +2.263732E-05 +1.240554E-02 +2.182216E-05 +1.709643E-02 +4.443205E-05 +1.240518E-02 +1.925823E-05 +1.427630E-02 +3.038114E-05 +1.316587E-02 +2.528125E-05 +1.051316E-02 +1.998843E-05 +1.171370E-02 +1.977243E-05 +1.035585E-02 +1.603691E-05 +7.844703E-03 +1.578836E-05 +1.090930E-02 +1.495715E-05 +8.811473E-03 +9.095511E-06 +1.164754E-02 +2.113385E-05 +1.218588E-02 +2.577136E-05 +9.989257E-03 +1.768442E-05 +1.346846E-02 +3.232091E-05 +1.442996E-02 +2.734716E-05 +9.319830E-03 +1.357660E-05 +8.976517E-03 +1.130996E-05 +1.111410E-02 +1.774598E-05 +7.097237E-03 +9.606334E-06 +7.668810E-03 +9.333553E-06 +7.744641E-03 +1.065587E-05 +7.076161E-03 +1.063617E-05 +9.841337E-03 +1.147612E-05 +9.084818E-03 +1.406836E-05 +2.026892E-02 +5.186751E-05 +2.132295E-02 +5.072988E-05 +2.033996E-02 +4.765789E-05 +2.446954E-02 +7.232017E-05 +1.029334E-02 +1.244212E-05 +1.235238E-02 +2.298965E-05 +1.681496E-02 +3.708751E-05 +2.101172E-02 +5.242154E-05 +1.722265E-02 +4.432357E-05 +1.352905E-02 +2.104447E-05 +2.195095E-02 +5.623046E-05 +2.089078E-02 +5.825067E-05 +2.311666E-02 +7.574537E-05 +1.562461E-02 +4.452838E-05 +3.307359E-02 +1.363268E-04 +2.572970E-02 +8.059205E-05 +2.345159E-02 +6.488182E-05 +2.554049E-02 +8.362508E-05 +2.006928E-02 +5.496633E-05 +2.259482E-02 +7.740649E-05 +1.761243E-02 +4.766457E-05 +1.125462E-02 +1.662484E-05 +1.806884E-02 +4.002727E-05 +1.875035E-02 +3.963856E-05 +2.507230E-02 +7.918744E-05 +1.948387E-02 +4.675980E-05 +2.102608E-02 +5.253998E-05 +2.725383E-02 +8.911499E-05 +1.527724E-02 +2.634360E-05 +2.318415E-02 +6.853391E-05 +1.953638E-02 +4.357651E-05 +2.681123E-02 +9.518790E-05 +1.619023E-02 +3.280100E-05 +2.160140E-02 +5.673289E-05 +2.207700E-02 +6.204249E-05 +1.851529E-02 +4.084658E-05 +2.064003E-02 +5.523222E-05 +1.936444E-02 +5.709920E-05 +2.135402E-02 +6.226947E-05 +1.913624E-02 +5.176876E-05 +1.979246E-02 +4.760307E-05 +2.697598E-02 +1.023961E-04 +1.163038E-02 +1.840715E-05 +1.922611E-02 +4.751185E-05 +1.370913E-02 +2.686855E-05 +1.541222E-02 +3.013601E-05 +2.247424E-02 +5.214783E-05 +1.763181E-02 +3.495488E-05 +9.375723E-03 +1.593258E-05 +1.436433E-02 +3.431677E-05 +1.300122E-02 +2.534320E-05 +1.428291E-02 +3.109112E-05 +1.320134E-02 +2.937454E-05 +1.496684E-02 +2.934259E-05 +1.257843E-02 +3.153056E-05 +1.573087E-02 +3.089207E-05 +1.074581E-02 +1.656493E-05 +8.983048E-03 +1.169670E-05 +1.588106E-02 +3.644142E-05 +1.135062E-02 +1.548990E-05 +1.342453E-02 +4.068693E-05 +7.143669E-03 +1.309838E-05 +1.911833E-02 +5.539347E-05 +1.578655E-02 +3.784881E-05 +1.010592E-02 +2.000143E-05 +2.107750E-02 +5.152671E-05 +1.352516E-02 +2.742309E-05 +1.298482E-02 +2.958789E-05 +8.061759E-03 +1.027922E-05 +1.145755E-02 +1.975699E-05 +7.630008E-03 +9.001956E-06 +1.110176E-02 +1.756811E-05 +7.622179E-03 +1.192472E-05 +1.157431E-02 +3.153358E-05 +1.329349E-02 +2.758940E-05 +7.723627E-03 +1.213940E-05 +6.430868E-03 +5.865444E-06 +6.666510E-03 +6.225385E-06 +3.314737E-03 +2.247442E-06 +5.145333E-03 +3.979329E-06 +6.496136E-03 +9.042875E-06 +3.832205E-03 +4.079904E-06 +1.091525E-02 +2.123166E-05 +1.100375E-02 +2.753282E-05 +6.452706E-03 +9.971091E-06 +5.931053E-03 +8.601691E-06 +9.574695E-03 +1.435980E-05 +6.378307E-03 +9.114546E-06 +1.035293E-02 +2.113676E-05 +5.515936E-03 +4.201853E-06 +5.579006E-03 +4.124072E-06 +9.045101E-03 +2.746668E-05 +7.146555E-03 +1.150230E-05 +6.281008E-03 +5.825971E-06 +5.295060E-03 +6.107698E-06 +4.285052E-03 +3.897963E-06 +1.261316E-02 +3.054847E-05 +1.248209E-02 +3.143433E-05 +1.216297E-02 +1.827405E-05 +1.257515E-02 +2.571939E-05 +8.877488E-03 +1.136667E-05 +1.224337E-02 +2.556328E-05 +1.610471E-02 +3.359843E-05 +1.376758E-02 +2.898825E-05 +1.066381E-02 +1.891264E-05 +1.370280E-02 +3.200949E-05 +1.218455E-02 +2.842079E-05 +1.205249E-02 +2.816694E-05 +1.292481E-02 +2.311574E-05 +1.500071E-02 +5.524516E-05 +1.629889E-02 +3.414163E-05 +1.715035E-02 +4.138447E-05 +7.880253E-03 +8.429037E-06 +1.066213E-02 +2.491824E-05 +1.071709E-02 +1.648251E-05 +1.278476E-02 +2.151462E-05 +2.029414E-02 +5.704631E-05 +1.835961E-02 +3.756414E-05 +1.086076E-02 +1.970149E-05 +1.953320E-02 +6.822321E-05 +1.727515E-02 +4.272841E-05 +2.113792E-02 +5.363596E-05 +1.255464E-02 +2.618423E-05 +1.849104E-02 +3.910212E-05 +1.080830E-02 +1.627578E-05 +1.065175E-02 +1.245618E-05 +1.729833E-02 +4.769086E-05 +1.229654E-02 +2.017586E-05 +2.000316E-02 +5.539455E-05 +1.490083E-02 +2.662412E-05 +1.257552E-02 +2.450638E-05 +2.265863E-02 +5.948942E-05 +1.592510E-02 +3.967897E-05 +1.671764E-02 +3.518609E-05 +2.134651E-02 +6.970473E-05 +1.145479E-02 +2.341492E-05 +1.110701E-02 +1.473716E-05 +1.365215E-02 +2.532562E-05 +1.569347E-02 +3.022408E-05 +1.740868E-02 +4.263025E-05 +2.046954E-02 +5.236013E-05 +2.088018E-02 +4.754884E-05 +2.143648E-02 +5.630377E-05 +2.321051E-02 +7.417245E-05 +1.393331E-02 +2.372413E-05 +1.272764E-02 +2.686784E-05 +1.996763E-02 +6.034803E-05 +1.543709E-02 +3.597724E-05 +1.374704E-02 +2.238864E-05 +1.485050E-02 +3.200278E-05 +1.630595E-02 +3.026169E-05 +1.885152E-02 +5.848418E-05 +1.903463E-02 +4.081588E-05 +2.873487E-02 +1.002249E-04 +2.191651E-02 +7.843435E-05 +2.375413E-02 +7.774516E-05 +1.237198E-02 +2.127422E-05 +1.942702E-02 +4.732051E-05 +2.103354E-02 +6.483331E-05 +1.285994E-02 +2.290156E-05 +1.249524E-02 +2.455002E-05 +1.236581E-02 +2.393541E-05 +1.379145E-02 +2.529751E-05 +1.562825E-02 +4.587015E-05 +2.641863E-02 +9.120767E-05 +2.733140E-02 +1.071137E-04 +1.919060E-02 +5.181037E-05 +2.129817E-02 +5.796235E-05 +1.260439E-02 +1.817703E-05 +1.848829E-02 +4.798194E-05 +1.216642E-02 +2.707330E-05 +1.410959E-02 +2.525781E-05 +9.453654E-03 +1.551579E-05 +9.766342E-03 +1.477317E-05 +1.836540E-02 +5.242882E-05 +1.804249E-02 +4.602986E-05 +1.853466E-02 +4.366676E-05 +1.525913E-02 +3.246161E-05 +1.673660E-02 +3.399297E-05 +1.837090E-02 +4.346348E-05 +1.396823E-02 +3.367275E-05 +9.246854E-03 +1.212445E-05 +1.410130E-02 +3.106294E-05 +1.307073E-02 +2.149583E-05 +9.704033E-03 +1.660514E-05 +1.044410E-02 +1.303462E-05 +1.166356E-02 +2.043704E-05 +1.318169E-02 +2.754937E-05 +1.812814E-02 +4.404582E-05 +1.552606E-02 +3.211975E-05 +1.585862E-02 +3.414359E-05 +1.446034E-02 +2.967784E-05 +7.649239E-03 +1.381600E-05 +6.893844E-03 +7.460924E-06 +1.354488E-02 +2.777125E-05 +1.007415E-02 +1.536552E-05 +8.075475E-03 +1.134760E-05 +1.130634E-02 +1.578798E-05 +6.590888E-03 +9.273749E-06 +7.448105E-03 +8.982164E-06 +5.823642E-03 +5.865562E-06 +9.093169E-03 +9.535064E-06 +4.848224E-03 +3.763431E-06 +9.282171E-03 +1.433250E-05 +1.127548E-02 +2.124250E-05 +9.878278E-03 +2.325491E-05 +1.039485E-02 +2.066791E-05 +1.155396E-02 +2.135511E-05 +1.450572E-02 +3.456258E-05 +1.246739E-02 +2.299204E-05 +1.290333E-02 +2.343647E-05 +1.121371E-02 +1.743282E-05 +5.468489E-03 +5.451707E-06 +1.180352E-02 +2.521651E-05 +1.416461E-02 +3.062871E-05 +1.076659E-02 +2.220002E-05 +2.448020E-02 +1.177322E-04 +1.517807E-02 +2.911032E-05 +1.031229E-02 +1.643057E-05 +1.200918E-02 +2.501705E-05 +1.613952E-02 +3.362754E-05 +1.378304E-02 +2.726242E-05 +1.857986E-02 +5.056092E-05 +1.576878E-02 +3.540682E-05 +1.910927E-02 +4.403442E-05 +1.829771E-02 +4.616084E-05 +1.164328E-02 +2.237054E-05 +1.680617E-02 +5.383688E-05 +2.087579E-02 +7.699421E-05 +2.381231E-02 +8.579600E-05 +1.885763E-02 +4.911360E-05 +2.649401E-02 +7.833957E-05 +1.350269E-02 +2.364349E-05 +1.757223E-02 +4.850663E-05 +2.411131E-02 +7.298399E-05 +2.774250E-02 +9.193073E-05 +2.282427E-02 +5.981367E-05 +2.721816E-02 +9.146779E-05 +2.832490E-02 +1.002337E-04 +2.942107E-02 +1.083982E-04 +2.629534E-02 +7.761525E-05 +2.690294E-02 +9.295211E-05 +2.031569E-02 +5.738480E-05 +2.590631E-02 +8.501230E-05 +3.031225E-02 +1.054523E-04 +2.423433E-02 +6.759709E-05 +3.382137E-02 +1.369015E-04 +2.496378E-02 +7.510237E-05 +2.672791E-02 +9.783698E-05 +2.507828E-02 +7.618011E-05 +1.769181E-02 +3.552782E-05 +2.096115E-02 +5.131019E-05 +3.063827E-02 +1.178430E-04 +3.120124E-02 +1.130478E-04 +2.031644E-02 +7.092047E-05 +2.760866E-02 +8.532139E-05 +2.786328E-02 +8.451452E-05 +2.700290E-02 +9.059845E-05 +3.660807E-02 +1.468682E-04 +3.105005E-02 +1.103431E-04 +3.734607E-02 +1.551359E-04 +3.447674E-02 +1.455364E-04 +2.264216E-02 +5.558419E-05 +2.211961E-02 +5.818600E-05 +3.130555E-02 +1.297184E-04 +3.457400E-02 +1.544678E-04 +2.687511E-02 +9.290746E-05 +3.047806E-02 +1.034500E-04 +3.560765E-02 +1.552412E-04 +3.095201E-02 +1.306105E-04 +3.230749E-02 +1.340962E-04 +2.928305E-02 +1.168468E-04 +4.265647E-02 +2.076643E-04 +3.298446E-02 +1.507110E-04 +2.986290E-02 +1.139639E-04 +3.435605E-02 +1.436737E-04 +3.052232E-02 +1.060392E-04 +3.396111E-02 +1.269448E-04 +3.167642E-02 +1.425279E-04 +2.821678E-02 +9.529119E-05 +4.113237E-02 +1.985887E-04 +3.525258E-02 +1.581696E-04 +3.297968E-02 +1.288343E-04 +2.799503E-02 +1.215560E-04 +4.104348E-02 +2.019357E-04 +3.825115E-02 +1.695340E-04 +2.776267E-02 +8.959306E-05 +3.443399E-02 +1.543941E-04 +2.347389E-02 +6.957205E-05 +2.325934E-02 +7.017456E-05 +2.441186E-02 +8.613195E-05 +1.983392E-02 +5.161177E-05 +2.710281E-02 +8.919133E-05 +2.744420E-02 +8.533228E-05 +2.193886E-02 +6.175359E-05 +1.830518E-02 +5.544200E-05 +2.341425E-02 +7.903797E-05 +2.450511E-02 +8.157422E-05 +2.452935E-02 +7.643569E-05 +3.274389E-02 +1.348587E-04 +9.730875E-03 +1.447356E-05 +1.623715E-02 +3.017421E-05 +1.516567E-02 +3.422832E-05 +1.065832E-02 +1.723340E-05 +1.938164E-02 +4.958486E-05 +1.489311E-02 +2.833615E-05 +1.617585E-02 +3.768666E-05 +1.471840E-02 +3.108380E-05 +1.804409E-02 +4.531066E-05 +2.150485E-02 +6.386092E-05 +1.088027E-02 +2.181372E-05 +1.017312E-02 +2.124217E-05 +1.432834E-02 +2.609903E-05 +1.583698E-02 +3.341095E-05 +9.743784E-03 +1.280783E-05 +7.846675E-03 +7.302042E-06 +9.804358E-03 +1.279367E-05 +1.297038E-02 +2.247676E-05 +1.204029E-02 +2.186972E-05 +8.944589E-03 +1.610694E-05 +1.437621E-02 +2.903841E-05 +1.162625E-02 +1.600570E-05 +5.705942E-03 +6.026539E-06 +9.949459E-03 +1.121060E-05 +1.355078E-02 +3.639982E-05 +1.253062E-02 +2.184327E-05 +1.128093E-02 +2.186156E-05 +1.351097E-02 +3.128150E-05 +1.302602E-02 +2.954976E-05 +1.581710E-02 +2.880115E-05 +8.299998E-03 +1.148143E-05 +1.419270E-02 +3.823010E-05 +8.195314E-03 +1.206128E-05 +1.089466E-02 +1.659227E-05 +1.434916E-02 +2.871463E-05 +1.677690E-02 +5.753038E-05 +2.577031E-02 +8.627098E-05 +2.327382E-02 +8.071762E-05 +2.476661E-02 +7.787162E-05 +2.107385E-02 +5.721321E-05 +1.990587E-02 +5.438566E-05 +1.715009E-02 +3.760846E-05 +2.840951E-02 +9.042931E-05 +2.308683E-02 +6.425853E-05 +2.068224E-02 +5.497174E-05 +2.518837E-02 +7.159468E-05 +1.844753E-02 +5.256599E-05 +2.195768E-02 +5.682427E-05 +4.576470E-02 +2.500482E-04 +3.107728E-02 +1.163017E-04 +3.132822E-02 +1.179930E-04 +3.352262E-02 +1.295829E-04 +2.943942E-02 +9.539846E-05 +3.672963E-02 +1.518887E-04 +3.639000E-02 +1.578688E-04 +3.932185E-02 +1.696900E-04 +3.126478E-02 +1.158570E-04 +3.784245E-02 +1.552955E-04 +3.346893E-02 +1.329769E-04 +3.045629E-02 +1.110202E-04 +4.501003E-02 +2.328334E-04 +5.330472E-02 +3.651809E-04 +4.289711E-02 +2.197266E-04 +3.259040E-02 +1.193252E-04 +4.449895E-02 +2.225829E-04 +4.124007E-02 +1.878125E-04 +4.737006E-02 +2.432331E-04 +4.433616E-02 +2.209854E-04 +5.530206E-02 +3.206482E-04 +6.256960E-02 +4.281638E-04 +5.285253E-02 +3.112894E-04 +4.439981E-02 +2.141823E-04 +5.016707E-02 +2.707515E-04 +6.882017E-02 +4.979869E-04 +4.465718E-02 +2.306648E-04 +3.888039E-02 +1.657354E-04 +5.385073E-02 +3.147914E-04 +4.640933E-02 +2.345368E-04 +7.051618E-02 +6.268651E-04 +4.375120E-02 +2.369745E-04 +6.068695E-02 +4.021878E-04 +6.068536E-02 +3.839552E-04 +3.602602E-02 +1.670809E-04 +4.995017E-02 +2.763744E-04 +4.392495E-02 +2.564028E-04 +5.093161E-02 +3.505664E-04 +4.432335E-02 +2.193425E-04 +4.855910E-02 +2.650606E-04 +5.176805E-02 +3.189213E-04 +4.890781E-02 +2.548831E-04 +6.554400E-02 +5.204569E-04 +6.588153E-02 +4.746561E-04 +6.675922E-02 +5.163608E-04 +7.271786E-02 +5.798664E-04 +4.837626E-02 +2.803260E-04 +5.224310E-02 +3.238220E-04 +4.580609E-02 +2.616101E-04 +5.119315E-02 +2.907515E-04 +4.372268E-02 +2.158620E-04 +4.124410E-02 +2.181852E-04 +4.882021E-02 +2.584581E-04 +5.914423E-02 +3.994010E-04 +4.163873E-02 +1.967708E-04 +3.798723E-02 +1.675576E-04 +6.178751E-02 +4.293350E-04 +5.052828E-02 +2.945947E-04 +3.889945E-02 +1.723031E-04 +4.778867E-02 +2.787658E-04 +2.556412E-02 +7.318557E-05 +3.450636E-02 +1.552235E-04 +2.997657E-02 +1.090031E-04 +2.250800E-02 +7.954622E-05 +3.846568E-02 +1.836107E-04 +3.701622E-02 +1.828496E-04 +3.972718E-02 +1.850244E-04 +2.403274E-02 +8.024833E-05 +3.407142E-02 +1.362787E-04 +3.563489E-02 +1.418007E-04 +2.285168E-02 +6.135475E-05 +3.573895E-02 +1.429096E-04 +1.944631E-02 +4.643790E-05 +2.223553E-02 +6.647009E-05 +2.178313E-02 +5.702943E-05 +1.885794E-02 +4.219512E-05 +2.626415E-02 +7.357902E-05 +2.590102E-02 +7.754226E-05 +1.790062E-02 +4.192871E-05 +1.566226E-02 +3.285418E-05 +2.611458E-02 +8.677724E-05 +2.644054E-02 +7.951101E-05 +1.688067E-02 +3.275169E-05 +2.281883E-02 +7.048130E-05 +1.383028E-02 +2.557495E-05 +1.750718E-02 +3.486088E-05 +1.458508E-02 +2.726606E-05 +1.229121E-02 +2.297397E-05 +1.858922E-02 +4.177321E-05 +1.787571E-02 +4.327284E-05 +6.566818E-03 +9.185537E-06 +1.448563E-02 +2.622240E-05 +1.621707E-02 +3.406357E-05 +1.085556E-02 +1.536032E-05 +1.333272E-02 +2.646991E-05 +1.453289E-02 +2.893412E-05 +1.518348E-02 +4.580967E-05 +1.404090E-02 +2.660292E-05 +1.349000E-02 +3.442831E-05 +1.633780E-02 +4.356999E-05 +1.600602E-02 +3.943089E-05 +1.590141E-02 +3.641474E-05 +1.086814E-02 +1.688254E-05 +1.698352E-02 +4.714162E-05 +1.318224E-02 +2.638496E-05 +1.119975E-02 +1.718066E-05 +1.575614E-02 +3.441783E-05 +1.418915E-02 +2.794370E-05 +1.971441E-02 +5.386951E-05 +2.749934E-02 +9.685175E-05 +2.450793E-02 +8.361790E-05 +3.096368E-02 +1.517345E-04 +1.966521E-02 +5.193037E-05 +1.488285E-02 +2.767080E-05 +2.628867E-02 +8.549789E-05 +3.222975E-02 +1.197226E-04 +3.578145E-02 +1.651405E-04 +2.717256E-02 +9.455312E-05 +2.846483E-02 +1.022437E-04 +2.373681E-02 +7.165349E-05 +4.893242E-02 +2.730109E-04 +3.477536E-02 +1.404582E-04 +4.928227E-02 +2.924560E-04 +4.544606E-02 +2.179936E-04 +3.160536E-02 +1.247483E-04 +4.089837E-02 +1.816429E-04 +6.363669E-02 +4.595645E-04 +5.951940E-02 +3.700880E-04 +3.810687E-02 +1.688583E-04 +5.679150E-02 +3.460302E-04 +5.729570E-02 +3.719866E-04 +5.082871E-02 +2.938785E-04 +7.469781E-02 +6.673208E-04 +6.652451E-02 +4.877821E-04 +6.401348E-02 +4.744885E-04 +5.622051E-02 +3.395523E-04 +6.073961E-02 +3.833605E-04 +6.232929E-02 +4.148823E-04 +7.969677E-02 +6.803601E-04 +8.037601E-02 +7.230061E-04 +7.865258E-02 +6.933305E-04 +9.845581E-02 +1.080566E-03 +6.878501E-02 +5.274776E-04 +7.015010E-02 +5.143444E-04 +1.156668E-01 +1.410105E-03 +1.192152E-01 +1.498896E-03 +7.577104E-02 +6.219937E-04 +8.184079E-02 +7.335058E-04 +1.139638E-01 +1.401155E-03 +8.075065E-02 +6.916698E-04 +1.437821E-01 +2.126013E-03 +8.850980E-02 +8.276893E-04 +1.464407E-01 +2.249915E-03 +1.357666E-01 +1.907685E-03 +8.903971E-02 +8.785322E-04 +1.035557E-01 +1.229512E-03 +9.987363E-02 +1.066492E-03 +1.408315E-01 +2.126682E-03 +7.775073E-02 +6.482580E-04 +9.217616E-02 +9.279523E-04 +1.346724E-01 +1.896751E-03 +8.733262E-02 +8.612501E-04 +9.983468E-02 +1.028984E-03 +9.096031E-02 +9.623493E-04 +1.646266E-01 +2.794929E-03 +1.304703E-01 +1.750382E-03 +8.811642E-02 +8.019013E-04 +1.067542E-01 +1.239326E-03 +4.255870E-02 +2.117948E-04 +6.657200E-02 +4.734337E-04 +6.716890E-02 +5.510834E-04 +4.697673E-02 +2.522950E-04 +9.074058E-02 +9.095881E-04 +7.248365E-02 +5.562525E-04 +5.894139E-02 +3.919992E-04 +4.322527E-02 +2.007041E-04 +8.846643E-02 +8.126375E-04 +8.094023E-02 +7.286166E-04 +5.884744E-02 +3.735579E-04 +6.484926E-02 +4.588123E-04 +4.890138E-02 +2.886686E-04 +5.972248E-02 +4.039813E-04 +4.560235E-02 +2.196157E-04 +4.488985E-02 +2.203187E-04 +6.734006E-02 +5.380869E-04 +5.510066E-02 +3.247707E-04 +4.520538E-02 +2.496589E-04 +4.217127E-02 +2.278109E-04 +5.551062E-02 +3.500669E-04 +4.092402E-02 +1.766989E-04 +4.298954E-02 +2.252953E-04 +4.437029E-02 +2.305532E-04 +3.704655E-02 +2.009774E-04 +3.598121E-02 +1.524807E-04 +3.045852E-02 +1.197202E-04 +2.601757E-02 +8.242731E-05 +3.357946E-02 +1.363746E-04 +3.932253E-02 +1.907001E-04 +2.390507E-02 +6.834171E-05 +2.346501E-02 +7.056602E-05 +3.597630E-02 +1.581562E-04 +3.090953E-02 +1.047491E-04 +2.070578E-02 +5.748122E-05 +3.347346E-02 +1.259074E-04 +1.513003E-02 +3.897988E-05 +1.367854E-02 +2.775960E-05 +1.645455E-02 +3.040738E-05 +1.324152E-02 +2.645298E-05 +1.588183E-02 +3.062863E-05 +1.734153E-02 +4.637284E-05 +1.634443E-02 +5.133843E-05 +1.119328E-02 +1.753195E-05 +1.323203E-02 +3.022286E-05 +1.135797E-02 +1.802055E-05 +1.090441E-02 +1.701011E-05 +1.759035E-02 +4.033287E-05 +2.242877E-02 +6.151790E-05 +1.946253E-02 +5.767287E-05 +1.450600E-02 +3.658456E-05 +2.053561E-02 +7.347202E-05 +2.172703E-02 +6.439721E-05 +1.970458E-02 +4.600512E-05 +1.750068E-02 +4.248050E-05 +2.615060E-02 +8.063501E-05 +1.471555E-02 +3.115498E-05 +1.390462E-02 +3.029928E-05 +2.277300E-02 +6.669696E-05 +1.701430E-02 +3.723197E-05 +3.366433E-02 +1.230840E-04 +2.650631E-02 +9.335504E-05 +2.977659E-02 +1.071113E-04 +3.153286E-02 +1.137530E-04 +2.593564E-02 +7.559506E-05 +2.027223E-02 +6.394080E-05 +3.666363E-02 +1.619679E-04 +4.008059E-02 +1.775008E-04 +2.019835E-02 +5.995987E-05 +3.269994E-02 +1.328649E-04 +4.298198E-02 +2.261101E-04 +3.478624E-02 +1.430238E-04 +5.024091E-02 +3.090307E-04 +5.399488E-02 +3.370022E-04 +4.802423E-02 +2.449581E-04 +4.962540E-02 +2.661791E-04 +4.714200E-02 +2.609694E-04 +5.413235E-02 +3.323523E-04 +7.865185E-02 +6.448405E-04 +6.245568E-02 +4.162905E-04 +4.774685E-02 +2.886302E-04 +6.062406E-02 +4.267779E-04 +6.732377E-02 +5.175823E-04 +5.345323E-02 +3.251415E-04 +1.081562E-01 +1.271390E-03 +1.021968E-01 +1.089652E-03 +9.531149E-02 +1.008862E-03 +1.099951E-01 +1.318432E-03 +8.728617E-02 +7.926236E-04 +6.759692E-02 +4.951495E-04 +1.622908E-01 +2.679920E-03 +1.297048E-01 +1.704599E-03 +1.105751E-01 +1.365137E-03 +1.338049E-01 +1.961877E-03 +1.135987E-01 +1.340952E-03 +9.047766E-02 +8.460145E-04 +5.706400E-01 +3.358746E-02 +5.767616E-01 +3.370236E-02 +1.875657E-01 +3.661666E-03 +1.871296E-01 +3.729992E-03 +2.210728E-01 +4.924615E-03 +1.665143E-01 +2.811366E-03 +8.372362E-01 +7.140730E-02 +2.631175E-01 +6.985957E-03 +5.750239E-01 +3.400521E-02 +4.828940E-01 +2.485485E-02 +1.859770E-01 +3.523984E-03 +1.672669E-01 +2.904958E-03 +2.375331E-01 +5.780405E-03 +7.840038E-01 +6.231709E-02 +2.132004E-01 +4.651951E-03 +1.326778E-01 +1.947761E-03 +8.211106E-01 +6.821312E-02 +2.477970E-01 +6.338987E-03 +2.133989E-01 +4.688136E-03 +1.689238E-01 +2.975501E-03 +7.799516E-01 +6.145987E-02 +2.571652E-01 +6.720137E-03 +1.616850E-01 +2.755887E-03 +1.967353E-01 +3.935902E-03 +8.257842E-02 +7.608737E-04 +1.275267E-01 +1.697194E-03 +9.926640E-02 +1.068598E-03 +8.218999E-02 +7.531509E-04 +1.532040E-01 +2.576896E-03 +1.294690E-01 +1.713096E-03 +7.154094E-02 +5.360062E-04 +7.586730E-02 +7.229435E-04 +1.259416E-01 +1.689821E-03 +9.056538E-02 +9.471446E-04 +8.469906E-02 +7.604134E-04 +1.005850E-01 +1.057108E-03 +4.463277E-02 +2.328840E-04 +5.523748E-02 +3.372196E-04 +5.232544E-02 +2.999576E-04 +4.417355E-02 +2.638798E-04 +5.782793E-02 +3.530500E-04 +5.944743E-02 +4.220391E-04 +3.657199E-02 +1.400109E-04 +3.808082E-02 +1.658520E-04 +6.410370E-02 +4.501663E-04 +4.310905E-02 +2.075429E-04 +4.755667E-02 +2.801406E-04 +4.959581E-02 +2.962253E-04 +2.252513E-02 +6.049713E-05 +2.991518E-02 +9.529790E-05 +2.664048E-02 +8.582855E-05 +2.475820E-02 +1.017459E-04 +3.488574E-02 +1.383218E-04 +2.890941E-02 +9.208222E-05 +2.098791E-02 +5.427914E-05 +1.943877E-02 +4.588171E-05 +3.481570E-02 +1.557210E-04 +2.398110E-02 +7.150967E-05 +2.011861E-02 +5.252956E-05 +2.839521E-02 +9.935802E-05 +1.502686E-02 +3.105045E-05 +1.609461E-02 +3.412102E-05 +2.098494E-02 +4.964297E-05 +1.885164E-02 +4.396914E-05 +1.991326E-02 +6.264911E-05 +1.856961E-02 +5.669686E-05 +1.440755E-02 +2.776990E-05 +1.370375E-02 +2.537463E-05 +1.757189E-02 +4.061709E-05 +1.902797E-02 +4.188635E-05 +1.135542E-02 +1.840125E-05 +1.821693E-02 +5.706852E-05 +1.966443E-02 +6.182591E-05 +1.098595E-02 +1.890446E-05 +1.880596E-02 +4.985208E-05 +2.224492E-02 +6.056638E-05 +1.938365E-02 +5.095134E-05 +2.004141E-02 +4.931528E-05 +1.584800E-02 +3.117640E-05 +8.716172E-03 +1.000356E-05 +1.306598E-02 +2.437620E-05 +1.303208E-02 +2.038909E-05 +1.496313E-02 +2.545249E-05 +9.598787E-03 +1.772891E-05 +3.131961E-02 +1.312684E-04 +2.918177E-02 +1.061777E-04 +3.088357E-02 +1.333663E-04 +3.322098E-02 +1.522259E-04 +1.912743E-02 +4.246859E-05 +2.493296E-02 +7.677374E-05 +3.831962E-02 +1.658539E-04 +3.935899E-02 +1.741789E-04 +2.392516E-02 +6.888699E-05 +3.042757E-02 +1.017878E-04 +3.071050E-02 +1.067951E-04 +3.345411E-02 +1.329032E-04 +5.446194E-02 +3.217845E-04 +4.790665E-02 +2.591914E-04 +4.370165E-02 +2.303527E-04 +4.427824E-02 +2.343428E-04 +4.182303E-02 +1.991080E-04 +4.098398E-02 +1.789986E-04 +6.431595E-02 +4.788578E-04 +6.788255E-02 +4.777967E-04 +4.412014E-02 +2.235134E-04 +5.533021E-02 +3.194019E-04 +5.464587E-02 +3.422291E-04 +5.703799E-02 +3.461325E-04 +1.119858E-01 +1.361306E-03 +9.089503E-02 +9.100663E-04 +9.511706E-02 +1.044926E-03 +1.074655E-01 +1.234547E-03 +7.705184E-02 +6.240812E-04 +6.897178E-02 +4.976520E-04 +1.412576E-01 +2.058554E-03 +1.216520E-01 +1.524026E-03 +8.791442E-02 +8.344056E-04 +1.037643E-01 +1.183835E-03 +8.708765E-02 +7.895562E-04 +8.580552E-02 +7.861920E-04 +7.918410E-01 +6.387826E-02 +2.447419E-01 +6.181230E-03 +4.587452E-01 +2.121897E-02 +5.203331E-01 +2.787312E-02 +1.850399E-01 +3.508673E-03 +1.651942E-01 +2.817305E-03 +5.838903E-01 +3.492429E-02 +5.155122E-01 +2.720158E-02 +1.904412E-01 +3.741626E-03 +1.981500E-01 +4.136229E-03 +2.022324E-01 +4.246984E-03 +1.652234E-01 +2.873591E-03 +5.115500E-01 +2.708582E-02 +5.791183E-01 +3.432760E-02 +8.107545E-01 +6.659574E-02 +2.634253E-01 +6.999531E-03 +4.915877E-01 +2.533318E-02 +5.693871E-01 +3.325807E-02 +1.791869E-01 +3.312861E-03 +1.858183E-01 +3.543802E-03 +2.123169E-01 +4.557530E-03 +1.672616E-01 +2.835857E-03 +1.711699E-01 +3.060667E-03 +1.758571E-01 +3.190864E-03 +9.235761E-02 +9.669475E-04 +1.140668E-01 +1.438348E-03 +1.377681E-01 +1.929906E-03 +1.011292E-01 +1.113302E-03 +1.364692E-01 +1.951502E-03 +1.414788E-01 +2.087246E-03 +7.454906E-02 +6.183963E-04 +7.314067E-02 +5.725364E-04 +1.053516E-01 +1.161166E-03 +8.265045E-02 +7.800060E-04 +9.317212E-02 +9.511500E-04 +9.087762E-02 +9.141004E-04 +5.226230E-02 +3.109563E-04 +5.578744E-02 +3.618499E-04 +6.973131E-02 +5.043558E-04 +6.157852E-02 +4.070680E-04 +6.811553E-02 +5.258915E-04 +7.611557E-02 +6.131989E-04 +5.088876E-02 +3.182936E-04 +5.436219E-02 +3.078199E-04 +5.597453E-02 +3.396588E-04 +4.107053E-02 +1.911728E-04 +4.290228E-02 +2.123049E-04 +5.788555E-02 +4.117326E-04 +2.353071E-02 +6.995800E-05 +3.463664E-02 +1.422097E-04 +2.918840E-02 +1.004566E-04 +2.736799E-02 +9.048433E-05 +3.463497E-02 +1.286836E-04 +4.726762E-02 +2.541389E-04 +2.411585E-02 +6.917613E-05 +2.704813E-02 +8.764995E-05 +2.810800E-02 +8.757217E-05 +2.291436E-02 +6.377954E-05 +3.013851E-02 +1.161125E-04 +2.972621E-02 +9.625050E-05 +1.751438E-02 +6.055922E-05 +2.205862E-02 +7.232896E-05 +1.960773E-02 +4.550316E-05 +1.937614E-02 +4.905471E-05 +2.518721E-02 +8.112827E-05 +2.590049E-02 +7.419054E-05 +1.339646E-02 +2.029891E-05 +2.067244E-02 +4.823190E-05 +2.295710E-02 +6.620610E-05 +8.933646E-03 +1.197590E-05 +2.088372E-02 +5.448793E-05 +1.573345E-02 +2.834414E-05 +1.618549E-02 +3.394500E-05 +1.562728E-02 +4.232429E-05 +1.762718E-02 +4.646038E-05 +1.691115E-02 +4.088904E-05 +1.778865E-02 +4.585630E-05 +1.699861E-02 +3.633558E-05 +1.474531E-02 +2.687795E-05 +1.191135E-02 +1.966547E-05 +1.368911E-02 +2.475254E-05 +8.726049E-03 +1.080420E-05 +1.855900E-02 +4.086770E-05 +1.042736E-02 +1.532968E-05 +2.750891E-02 +9.887827E-05 +2.557586E-02 +8.191188E-05 +2.651219E-02 +9.860563E-05 +2.544872E-02 +7.883150E-05 +2.096053E-02 +5.337477E-05 +1.819029E-02 +3.850870E-05 +3.202501E-02 +1.153271E-04 +2.876516E-02 +9.848331E-05 +2.271111E-02 +7.379330E-05 +2.854025E-02 +9.337598E-05 +2.824372E-02 +1.030571E-04 +2.318994E-02 +6.966557E-05 +4.138096E-02 +1.938864E-04 +3.680662E-02 +1.462240E-04 +3.808984E-02 +1.773752E-04 +4.968859E-02 +2.697606E-04 +3.120957E-02 +1.068433E-04 +3.625725E-02 +1.561439E-04 +4.266936E-02 +2.044742E-04 +5.527178E-02 +3.492180E-04 +3.492336E-02 +1.434781E-04 +3.345516E-02 +1.260850E-04 +5.316011E-02 +3.146473E-04 +3.770174E-02 +1.639797E-04 +7.987130E-02 +6.938936E-04 +5.700087E-02 +3.483872E-04 +7.902435E-02 +7.070267E-04 +8.115977E-02 +7.037262E-04 +5.028735E-02 +2.816840E-04 +5.862112E-02 +3.890181E-04 +8.026709E-02 +6.991067E-04 +8.844060E-02 +8.768540E-04 +6.027542E-02 +3.820896E-04 +5.955846E-02 +4.114052E-04 +7.223606E-02 +5.860849E-04 +8.036129E-02 +7.080829E-04 +1.251201E-01 +1.753212E-03 +9.518009E-02 +1.007169E-03 +1.499658E-01 +2.357452E-03 +1.582289E-01 +2.673309E-03 +9.723433E-02 +1.085206E-03 +9.223640E-02 +9.320231E-04 +1.244253E-01 +1.604811E-03 +1.389205E-01 +2.073518E-03 +8.898557E-02 +8.481843E-04 +8.699525E-02 +8.194442E-04 +1.194952E-01 +1.512778E-03 +8.679982E-02 +8.002571E-04 +1.529795E-01 +2.441631E-03 +1.087018E-01 +1.206359E-03 +1.572820E-01 +2.488454E-03 +1.378974E-01 +1.949060E-03 +1.016220E-01 +1.073888E-03 +1.189492E-01 +1.535660E-03 +9.307965E-02 +9.698515E-04 +9.538400E-02 +9.813891E-04 +9.106730E-02 +8.805352E-04 +8.371498E-02 +7.560974E-04 +1.021881E-01 +1.077841E-03 +9.309692E-02 +9.810570E-04 +6.954893E-02 +5.308895E-04 +7.248184E-02 +6.039844E-04 +8.357871E-02 +7.377145E-04 +7.117434E-02 +5.362599E-04 +9.546800E-02 +9.918303E-04 +8.154604E-02 +6.899246E-04 +5.541527E-02 +3.261092E-04 +5.781147E-02 +3.640210E-04 +7.071250E-02 +5.530093E-04 +7.012881E-02 +5.436620E-04 +5.986681E-02 +4.315165E-04 +7.228996E-02 +5.573189E-04 +4.764962E-02 +2.567629E-04 +4.978411E-02 +3.039433E-04 +5.251712E-02 +3.236802E-04 +3.942522E-02 +1.927267E-04 +5.510943E-02 +3.217347E-04 +5.118639E-02 +3.171944E-04 +4.252043E-02 +1.916953E-04 +4.412672E-02 +2.246415E-04 +4.088117E-02 +1.787513E-04 +3.610456E-02 +1.564509E-04 +3.814757E-02 +1.686026E-04 +4.627344E-02 +2.494575E-04 +1.994893E-02 +5.126553E-05 +3.216228E-02 +1.182156E-04 +2.950065E-02 +1.138201E-04 +2.866289E-02 +1.160231E-04 +3.983095E-02 +1.721863E-04 +4.012198E-02 +1.784164E-04 +2.106311E-02 +4.994977E-05 +2.781446E-02 +1.039157E-04 +3.488260E-02 +1.405115E-04 +2.875112E-02 +9.762388E-05 +3.224104E-02 +1.323284E-04 +3.641337E-02 +1.501812E-04 +1.480062E-02 +3.027272E-05 +1.408753E-02 +3.690601E-05 +1.944937E-02 +4.432175E-05 +1.283324E-02 +2.250887E-05 +2.073256E-02 +5.466671E-05 +2.186071E-02 +5.661539E-05 +1.133978E-02 +1.956348E-05 +1.049553E-02 +1.718390E-05 +1.539596E-02 +3.369585E-05 +2.039324E-02 +5.820403E-05 +1.043006E-02 +1.903901E-05 +2.777446E-02 +1.204671E-04 +1.484365E-02 +2.996962E-05 +1.109804E-02 +1.818652E-05 +9.835588E-03 +1.388426E-05 +1.478128E-02 +3.969614E-05 +1.020395E-02 +1.717436E-05 +1.487209E-02 +3.915846E-05 +9.230116E-03 +1.588076E-05 +8.372399E-03 +1.186179E-05 +8.663998E-03 +1.212384E-05 +1.164683E-02 +2.389782E-05 +1.148782E-02 +1.884731E-05 +9.267384E-03 +2.342255E-05 +2.492427E-02 +7.177126E-05 +1.937892E-02 +5.238888E-05 +1.533925E-02 +3.007374E-05 +2.897108E-02 +9.563790E-05 +1.504253E-02 +4.162972E-05 +1.506486E-02 +3.027445E-05 +2.421349E-02 +6.937729E-05 +1.981713E-02 +4.308765E-05 +2.688788E-02 +8.996617E-05 +2.298292E-02 +6.356151E-05 +2.521588E-02 +9.500495E-05 +1.944459E-02 +4.357545E-05 +4.894435E-02 +2.638450E-04 +3.864018E-02 +1.798269E-04 +3.849780E-02 +1.779556E-04 +4.806157E-02 +2.545276E-04 +2.419299E-02 +8.084015E-05 +2.835677E-02 +9.629003E-05 +3.964564E-02 +1.838380E-04 +4.177908E-02 +1.949235E-04 +3.068221E-02 +1.216833E-04 +3.203560E-02 +1.147717E-04 +3.493031E-02 +1.439593E-04 +3.780820E-02 +1.626400E-04 +5.390584E-02 +3.457131E-04 +3.911344E-02 +1.787461E-04 +5.600310E-02 +3.942394E-04 +5.721857E-02 +3.841430E-04 +3.425794E-02 +1.301099E-04 +4.896944E-02 +2.649497E-04 +5.468018E-02 +3.296430E-04 +5.960549E-02 +4.028002E-04 +4.289904E-02 +2.047984E-04 +3.417711E-02 +1.286477E-04 +5.147540E-02 +3.225127E-04 +4.429517E-02 +2.370511E-04 +5.333104E-02 +3.409602E-04 +6.102677E-02 +4.290957E-04 +7.075039E-02 +5.312660E-04 +7.760160E-02 +6.260977E-04 +5.110208E-02 +2.931608E-04 +6.284669E-02 +4.546881E-04 +6.386212E-02 +5.062176E-04 +7.791663E-02 +6.553468E-04 +4.847427E-02 +2.698567E-04 +5.036036E-02 +2.562333E-04 +6.628275E-02 +4.863329E-04 +5.107250E-02 +3.360646E-04 +5.438547E-02 +3.250878E-04 +5.955142E-02 +3.888695E-04 +6.613363E-02 +4.562672E-04 +7.873757E-02 +6.608787E-04 +4.633363E-02 +2.332785E-04 +6.000714E-02 +4.102538E-04 +5.607310E-02 +3.721702E-04 +7.224050E-02 +5.754880E-04 +5.604428E-02 +3.636927E-04 +4.542882E-02 +2.350087E-04 +6.010895E-02 +3.888132E-04 +5.026253E-02 +3.056826E-04 +5.083017E-02 +2.951657E-04 +4.774445E-02 +2.553998E-04 +6.166209E-02 +4.248389E-04 +5.750738E-02 +3.545368E-04 +5.475371E-02 +3.742657E-04 +5.136434E-02 +3.013480E-04 +4.625465E-02 +2.735615E-04 +5.057347E-02 +3.133161E-04 +4.695282E-02 +2.640479E-04 +3.979050E-02 +1.911432E-04 +5.106567E-02 +2.846885E-04 +4.782744E-02 +3.086692E-04 +2.945927E-02 +1.037190E-04 +3.548884E-02 +1.667740E-04 +4.339365E-02 +2.324267E-04 +3.578638E-02 +1.439546E-04 +4.531719E-02 +2.379087E-04 +4.291461E-02 +2.163748E-04 +2.831504E-02 +9.351629E-05 +2.425588E-02 +6.929284E-05 +3.519439E-02 +1.401196E-04 +3.174238E-02 +1.187918E-04 +2.505587E-02 +7.333276E-05 +3.252855E-02 +1.518816E-04 +2.315654E-02 +6.200895E-05 +2.574270E-02 +7.613474E-05 +2.520902E-02 +7.303619E-05 +2.985551E-02 +9.745575E-05 +2.508447E-02 +9.702485E-05 +2.448965E-02 +6.790622E-05 +1.765762E-02 +3.709919E-05 +1.979233E-02 +4.686113E-05 +2.477181E-02 +7.217121E-05 +2.046923E-02 +5.529696E-05 +1.619249E-02 +3.536888E-05 +3.084138E-02 +1.038251E-04 +1.430547E-02 +2.813880E-05 +1.024198E-02 +1.564502E-05 +1.440933E-02 +2.677391E-05 +1.139030E-02 +1.562766E-05 +1.706815E-02 +3.602648E-05 +1.960477E-02 +5.223127E-05 +1.075038E-02 +1.946902E-05 +8.176023E-03 +9.795109E-06 +1.400712E-02 +2.798724E-05 +9.098651E-03 +2.320760E-05 +1.621999E-02 +5.890457E-05 +1.662025E-02 +5.381012E-05 +1.501846E-02 +3.187427E-05 +1.115569E-02 +2.112610E-05 +8.934007E-03 +1.127244E-05 +1.053736E-02 +2.738972E-05 +1.687632E-02 +3.758437E-05 +1.176928E-02 +1.998369E-05 +1.090722E-02 +2.070033E-05 +1.922176E-02 +4.611119E-05 +6.410110E-03 +7.146719E-06 +3.860269E-03 +5.922652E-06 +6.045740E-03 +5.074973E-06 +4.971635E-03 +3.431959E-06 +2.426203E-02 +7.370761E-05 +2.680359E-02 +8.998719E-05 +1.630553E-02 +3.567524E-05 +1.914533E-02 +4.240964E-05 +1.508665E-02 +2.912142E-05 +1.672855E-02 +3.656656E-05 +1.451039E-02 +2.817950E-05 +1.687413E-02 +4.142926E-05 +1.597006E-02 +4.478288E-05 +1.688899E-02 +3.586099E-05 +1.833640E-02 +5.132894E-05 +2.002488E-02 +5.326859E-05 +1.914416E-02 +5.599172E-05 +2.207570E-02 +7.740090E-05 +2.366938E-02 +6.568915E-05 +2.649512E-02 +1.020488E-04 +1.483135E-02 +2.984413E-05 +1.887848E-02 +4.268175E-05 +3.001817E-02 +1.047979E-04 +2.212608E-02 +6.788700E-05 +2.058642E-02 +5.920693E-05 +2.072658E-02 +5.071607E-05 +1.860802E-02 +4.555855E-05 +1.666833E-02 +3.918400E-05 +2.410251E-02 +7.518781E-05 +2.431099E-02 +9.040361E-05 +3.409049E-02 +1.428531E-04 +3.176194E-02 +1.054320E-04 +3.008617E-02 +1.140028E-04 +3.827724E-02 +1.656866E-04 +3.578801E-02 +1.469705E-04 +3.205988E-02 +1.211102E-04 +2.718611E-02 +8.166121E-05 +3.164768E-02 +1.161478E-04 +2.324305E-02 +6.697244E-05 +2.947200E-02 +1.259054E-04 +2.746439E-02 +9.282287E-05 +2.653377E-02 +8.108059E-05 +4.445537E-02 +2.152169E-04 +4.052651E-02 +1.733821E-04 +3.053999E-02 +1.118515E-04 +4.177700E-02 +2.106180E-04 +3.721658E-02 +1.614887E-04 +4.250554E-02 +2.125286E-04 +3.259794E-02 +1.259532E-04 +3.279076E-02 +1.281014E-04 +3.769459E-02 +1.592958E-04 +3.620173E-02 +1.496207E-04 +3.630649E-02 +1.531507E-04 +3.419905E-02 +1.389163E-04 +3.811683E-02 +1.632070E-04 +3.778477E-02 +1.788000E-04 +3.255090E-02 +1.292645E-04 +4.054674E-02 +2.009707E-04 +3.396471E-02 +1.380670E-04 +2.970522E-02 +1.194017E-04 +2.926855E-02 +1.209863E-04 +2.414836E-02 +7.131380E-05 +2.902285E-02 +9.925626E-05 +3.804797E-02 +1.754536E-04 +2.561987E-02 +7.861985E-05 +2.621638E-02 +8.635601E-05 +3.392178E-02 +1.612402E-04 +2.949056E-02 +1.075244E-04 +2.861194E-02 +9.347554E-05 +3.281854E-02 +1.750223E-04 +2.528376E-02 +8.170461E-05 +2.855965E-02 +1.276904E-04 +2.210588E-02 +6.285379E-05 +1.501664E-02 +3.174414E-05 +2.485082E-02 +8.044179E-05 +2.609565E-02 +9.700928E-05 +3.800572E-02 +1.865757E-04 +1.880640E-02 +4.090279E-05 +2.909814E-02 +1.043206E-04 +3.180763E-02 +1.216425E-04 +1.518998E-02 +2.699690E-05 +2.630226E-02 +9.511365E-05 +2.282938E-02 +6.428433E-05 +2.493692E-02 +7.780311E-05 +1.137087E-02 +2.156846E-05 +1.680608E-02 +3.976947E-05 +2.724734E-02 +8.526080E-05 +3.353531E-02 +1.249343E-04 +1.997488E-02 +5.686628E-05 +1.952335E-02 +5.168354E-05 +2.332315E-02 +6.296001E-05 +1.903421E-02 +4.970639E-05 +1.988764E-02 +4.758272E-05 +2.237483E-02 +6.308654E-05 +2.024263E-02 +6.708430E-05 +1.794493E-02 +3.980589E-05 +1.605168E-02 +3.661129E-05 +1.264028E-02 +2.003973E-05 +1.316289E-02 +3.041847E-05 +2.132558E-02 +7.506854E-05 +1.515922E-02 +4.400695E-05 +1.165029E-02 +3.144519E-05 +1.431392E-02 +3.510266E-05 +9.378262E-03 +1.745913E-05 +1.348722E-02 +2.279535E-05 +1.219541E-02 +2.124436E-05 +9.186874E-03 +1.308201E-05 +5.510134E-03 +6.127474E-06 +1.018457E-02 +2.037011E-05 +7.480002E-03 +8.821059E-06 +1.284192E-02 +2.896216E-05 +1.251268E-02 +2.241281E-05 +1.134027E-02 +1.937376E-05 +9.348782E-03 +1.387252E-05 +1.595911E-02 +3.477329E-05 +1.611731E-02 +4.121294E-05 +5.771625E-03 +5.262561E-06 +1.339971E-02 +2.328961E-05 +4.724286E-03 +7.486861E-06 +7.887185E-03 +1.309912E-05 +1.017668E-02 +1.329563E-05 +9.929419E-03 +2.048058E-05 +1.172543E-02 +2.164855E-05 +8.748399E-03 +1.455014E-05 +7.388493E-03 +1.213908E-05 +9.357160E-03 +1.459184E-05 +1.182596E-02 +2.754657E-05 +1.376694E-02 +2.808688E-05 +8.736677E-03 +1.261523E-05 +1.058599E-02 +2.132582E-05 +8.904592E-03 +1.412855E-05 +8.871956E-03 +1.042407E-05 +4.818722E-03 +5.533432E-06 +7.132170E-03 +1.066330E-05 +1.265366E-02 +2.062988E-05 +1.146186E-02 +1.978609E-05 +1.727631E-02 +6.317086E-05 +9.722001E-03 +1.628574E-05 +1.808415E-02 +4.814964E-05 +2.313210E-02 +7.257429E-05 +6.096746E-03 +8.507143E-06 +1.095433E-02 +2.574564E-05 +1.144512E-02 +2.130606E-05 +1.709946E-02 +3.435958E-05 +5.794154E-03 +4.298264E-06 +1.345102E-02 +2.470605E-05 +1.674615E-02 +3.806453E-05 +1.058112E-02 +1.675643E-05 +1.487609E-02 +2.876672E-05 +1.727197E-02 +4.888253E-05 +2.720121E-02 +8.232238E-05 +3.268443E-02 +1.194042E-04 +1.427634E-02 +2.639442E-05 +2.055060E-02 +5.261649E-05 +1.637582E-02 +3.886105E-05 +2.416272E-02 +6.712570E-05 +1.431266E-02 +2.383080E-05 +1.632066E-02 +3.444426E-05 +2.435113E-02 +8.254028E-05 +2.015885E-02 +5.481740E-05 +1.973867E-02 +5.116489E-05 +1.865655E-02 +4.752313E-05 +3.165189E-02 +1.474543E-04 +3.338700E-02 +1.226611E-04 +1.856968E-02 +4.098217E-05 +2.747306E-02 +8.290244E-05 +3.019952E-02 +1.096277E-04 +2.941793E-02 +9.471376E-05 +1.359209E-02 +2.775872E-05 +1.604302E-02 +3.176242E-05 +2.130560E-02 +6.015704E-05 +2.273639E-02 +7.032069E-05 +2.128699E-02 +6.074255E-05 +1.492456E-02 +3.510276E-05 +2.424866E-02 +6.867482E-05 +2.858266E-02 +9.553376E-05 +1.423686E-02 +2.731632E-05 +2.183114E-02 +5.075377E-05 +1.790750E-02 +4.419157E-05 +2.189439E-02 +5.678221E-05 +1.528824E-02 +2.994220E-05 +1.591232E-02 +3.345909E-05 +2.006375E-02 +5.328672E-05 +1.926568E-02 +5.794406E-05 +1.995889E-02 +5.771200E-05 +2.190352E-02 +6.226272E-05 +2.344085E-02 +7.170778E-05 +1.490160E-02 +3.189456E-05 +1.964283E-02 +4.674552E-05 +1.729274E-02 +5.276904E-05 +2.041435E-02 +6.736760E-05 +1.278262E-02 +2.244619E-05 +1.454136E-02 +3.039925E-05 +9.619956E-03 +1.773332E-05 +1.228153E-02 +2.003326E-05 +9.672849E-03 +1.662330E-05 +1.711969E-02 +5.651042E-05 +1.584751E-02 +3.641664E-05 +1.935632E-02 +5.597824E-05 +1.126109E-02 +1.753857E-05 +1.782849E-02 +4.695997E-05 +1.381158E-02 +2.666475E-05 +1.219375E-02 +1.818815E-05 +1.066559E-02 +2.272800E-05 +1.442020E-02 +2.898674E-05 +1.020932E-02 +1.446241E-05 +1.118415E-02 +1.992502E-05 +8.105784E-03 +1.344204E-05 +1.498438E-02 +4.583095E-05 +1.019191E-02 +1.878658E-05 +1.933752E-02 +5.597403E-05 +1.355162E-02 +2.693353E-05 +1.009187E-02 +1.416651E-05 +1.762231E-02 +4.342948E-05 +8.265997E-03 +1.115148E-05 +7.740105E-03 +9.350881E-06 +6.132761E-03 +5.990846E-06 +8.311803E-03 +1.337310E-05 +1.148410E-02 +2.801843E-05 +1.254654E-02 +2.859306E-05 +5.729723E-03 +7.417371E-06 +3.329556E-03 +2.852362E-06 +8.995510E-03 +1.519541E-05 +9.885451E-03 +1.504316E-05 +8.000781E-03 +1.318972E-05 +8.116139E-03 +1.599393E-05 +5.483106E-03 +5.909268E-06 +7.119776E-03 +7.398166E-06 +5.696562E-03 +8.267139E-06 +3.253311E-03 +3.490487E-06 +7.617341E-03 +1.591870E-05 +4.477136E-03 +4.507128E-06 +4.186692E-03 +4.522007E-06 +9.913744E-03 +1.537264E-05 +5.097688E-03 +5.151058E-06 +3.958711E-03 +4.681053E-06 +8.278901E-03 +1.024219E-05 +8.835906E-03 +1.016849E-05 +8.456874E-03 +1.177568E-05 +1.261330E-02 +3.084433E-05 +4.949744E-03 +4.615766E-06 +3.553617E-03 +2.732540E-06 +9.121684E-03 +1.577246E-05 +1.008197E-02 +2.084343E-05 +1.384668E-02 +3.110319E-05 +6.699315E-03 +6.544515E-06 +9.247650E-03 +1.217430E-05 +1.382529E-02 +2.309065E-05 +1.239699E-02 +2.979052E-05 +7.678409E-03 +9.823153E-06 +1.313584E-02 +2.664709E-05 +1.402449E-02 +3.295040E-05 +1.404510E-02 +2.328440E-05 +1.395545E-02 +3.064026E-05 +6.468889E-03 +1.142683E-05 +1.117536E-02 +2.247013E-05 +7.150789E-03 +7.587094E-06 +1.607791E-02 +4.401441E-05 +1.397191E-02 +2.767660E-05 +1.377649E-02 +3.853853E-05 +9.740469E-03 +1.610242E-05 +1.439220E-02 +3.310057E-05 +1.312482E-02 +2.812275E-05 +9.319391E-03 +1.598131E-05 +1.513017E-02 +3.596580E-05 +1.246425E-02 +2.621144E-05 +1.701677E-02 +4.718452E-05 +1.345504E-02 +2.750081E-05 +1.915828E-02 +6.206762E-05 +1.487706E-02 +3.498164E-05 +1.808302E-02 +5.043185E-05 +1.413342E-02 +3.559061E-05 +1.138146E-02 +1.786839E-05 +1.140044E-02 +1.941117E-05 +1.554299E-02 +2.899451E-05 +1.350147E-02 +2.424308E-05 +2.075976E-02 +7.307325E-05 +1.356231E-02 +2.080054E-05 +1.518370E-02 +3.316853E-05 +1.189204E-02 +1.901003E-05 +2.058005E-02 +5.143687E-05 +2.045751E-02 +5.497205E-05 +1.513733E-02 +2.666165E-05 +1.753330E-02 +3.936189E-05 +1.683976E-02 +3.581825E-05 +1.511066E-02 +2.645123E-05 +1.175520E-02 +1.609321E-05 +1.932866E-02 +4.358405E-05 +2.152647E-02 +5.525043E-05 +1.359163E-02 +2.720874E-05 +1.591814E-02 +3.441323E-05 +1.498891E-02 +3.242215E-05 +1.394632E-02 +2.541758E-05 +1.898119E-02 +4.729644E-05 +1.689587E-02 +3.933248E-05 +1.435155E-02 +2.582993E-05 +1.316763E-02 +2.353008E-05 +1.157136E-02 +1.833702E-05 +1.655168E-02 +3.162804E-05 +1.516917E-02 +4.365366E-05 +2.271626E-02 +6.252949E-05 +2.415893E-02 +6.451266E-05 +1.132077E-02 +1.979205E-05 +1.218269E-02 +1.887580E-05 +1.457860E-02 +2.603959E-05 +1.799378E-02 +3.831940E-05 +1.973304E-02 +5.131280E-05 +1.650072E-02 +4.421326E-05 +1.309761E-02 +2.093703E-05 +9.968119E-03 +1.734048E-05 +2.388636E-02 +8.126332E-05 +1.459477E-02 +3.488715E-05 +2.918991E-02 +9.400845E-05 +2.039305E-02 +4.974054E-05 +1.348400E-02 +3.490462E-05 +1.687564E-02 +4.279173E-05 +1.513373E-02 +2.823507E-05 +1.994888E-02 +5.071283E-05 +1.764059E-02 +4.346435E-05 +1.859116E-02 +5.299840E-05 +1.380401E-02 +2.348130E-05 +1.635474E-02 +3.937702E-05 +2.064198E-02 +5.607997E-05 +1.842824E-02 +4.282589E-05 +2.078636E-02 +5.236688E-05 +1.710805E-02 +3.985969E-05 +1.543166E-02 +3.277155E-05 +1.311119E-02 +2.103436E-05 +1.223030E-02 +1.772840E-05 +1.428400E-02 +2.879115E-05 +1.711044E-02 +3.871812E-05 +1.431954E-02 +2.831455E-05 +7.837091E-03 +1.187250E-05 +7.756280E-03 +8.554725E-06 +7.995791E-03 +1.095905E-05 +8.605179E-03 +1.177231E-05 +8.958756E-03 +1.332678E-05 +1.034574E-02 +2.171120E-05 +6.001176E-03 +7.941410E-06 +1.257551E-02 +2.312537E-05 +4.129076E-03 +2.677243E-06 +8.501326E-03 +1.658402E-05 +5.816010E-03 +5.905913E-06 +7.839173E-03 +8.421697E-06 +5.918322E-03 +9.025041E-06 +5.736561E-03 +7.633742E-06 +9.243956E-03 +1.198288E-05 +8.562607E-03 +9.900387E-06 +8.517736E-03 +1.400152E-05 +8.058111E-03 +8.346635E-06 +6.429181E-03 +8.483646E-06 +9.766782E-03 +1.860263E-05 +8.854052E-03 +1.734509E-05 +8.929637E-03 +1.491512E-05 +5.233001E-03 +5.925028E-06 +9.295152E-03 +1.768126E-05 +1.257918E-02 +2.632079E-05 +1.127993E-02 +1.815069E-05 +1.522302E-02 +3.459869E-05 +2.039110E-02 +6.104303E-05 +7.018288E-03 +8.011469E-06 +1.296372E-02 +2.439899E-05 +1.344461E-02 +3.144942E-05 +1.591259E-02 +3.662184E-05 +1.592134E-02 +3.534978E-05 +1.397292E-02 +2.673400E-05 +1.387726E-02 +2.413584E-05 +1.403292E-02 +2.450220E-05 +1.623686E-02 +3.934040E-05 +1.455326E-02 +3.956697E-05 +1.848869E-02 +4.594096E-05 +1.562335E-02 +2.895160E-05 +1.934214E-02 +6.527205E-05 +2.762082E-02 +1.002001E-04 +1.646443E-02 +4.757237E-05 +1.974118E-02 +5.871473E-05 +1.812863E-02 +4.571190E-05 +2.841456E-02 +1.256913E-04 +1.572056E-02 +3.604561E-05 +1.479375E-02 +4.114818E-05 +2.139729E-02 +5.158299E-05 +1.827112E-02 +4.755220E-05 +2.918330E-02 +9.121760E-05 +1.800084E-02 +4.226384E-05 +2.357640E-02 +6.593693E-05 +2.849119E-02 +1.014082E-04 +2.107159E-02 +6.738763E-05 +2.185077E-02 +6.120235E-05 +1.870103E-02 +5.126759E-05 +2.228030E-02 +5.885366E-05 +1.218959E-02 +1.923700E-05 +1.518833E-02 +2.980819E-05 +2.131881E-02 +6.164198E-05 +1.857691E-02 +5.149996E-05 +1.967993E-02 +4.929073E-05 +2.037752E-02 +5.254462E-05 +2.428694E-02 +7.415972E-05 +2.311199E-02 +5.830300E-05 +1.781340E-02 +5.016711E-05 +2.109282E-02 +5.439384E-05 +2.646402E-02 +7.981598E-05 +2.872928E-02 +1.157883E-04 +2.296882E-02 +5.600052E-05 +2.145069E-02 +6.153603E-05 +3.194172E-02 +1.130937E-04 +2.556185E-02 +8.976008E-05 +2.450563E-02 +7.657853E-05 +2.632135E-02 +8.318821E-05 +2.937358E-02 +9.572656E-05 +2.779408E-02 +9.729157E-05 +2.029619E-02 +5.815728E-05 +2.107188E-02 +5.405801E-05 +2.864120E-02 +9.187238E-05 +3.189900E-02 +1.158697E-04 +2.174543E-02 +6.126120E-05 +1.866666E-02 +3.831554E-05 +4.074514E-02 +2.019874E-04 +3.077997E-02 +1.155565E-04 +2.845511E-02 +9.760556E-05 +2.358164E-02 +7.014622E-05 +3.662127E-02 +1.520968E-04 +3.309700E-02 +1.256130E-04 +2.775361E-02 +1.078304E-04 +3.177889E-02 +1.327385E-04 +2.523394E-02 +8.921547E-05 +3.189185E-02 +1.647022E-04 +2.967954E-02 +1.071890E-04 +2.119897E-02 +5.752892E-05 +3.434445E-02 +1.342008E-04 +2.714518E-02 +8.681886E-05 +2.897958E-02 +9.065153E-05 +2.696222E-02 +8.540024E-05 +2.987888E-02 +9.648932E-05 +2.811456E-02 +9.230152E-05 +2.638667E-02 +8.721739E-05 +3.440902E-02 +1.421180E-04 +2.352488E-02 +7.481613E-05 +3.172354E-02 +1.853144E-04 +2.170608E-02 +6.022568E-05 +1.913037E-02 +5.905188E-05 +3.295652E-02 +1.433947E-04 +2.543187E-02 +9.035364E-05 +1.729217E-02 +3.824473E-05 +1.983528E-02 +6.034582E-05 +3.265521E-02 +1.315037E-04 +2.437483E-02 +7.364625E-05 +1.554696E-02 +3.206723E-05 +2.145024E-02 +5.715848E-05 +1.057830E-02 +1.743678E-05 +1.046397E-02 +1.560587E-05 +9.479417E-03 +1.712347E-05 +1.254587E-02 +3.235855E-05 +1.579355E-02 +4.509260E-05 +1.484926E-02 +2.799512E-05 +1.228686E-02 +2.031169E-05 +1.212962E-02 +2.512835E-05 +1.657642E-02 +4.655608E-05 +1.385236E-02 +2.324629E-05 +1.422372E-02 +4.206039E-05 +1.285229E-02 +2.234088E-05 +1.063684E-02 +2.048991E-05 +1.054286E-02 +1.650301E-05 +7.250865E-03 +8.349919E-06 +4.846842E-03 +5.611575E-06 +6.655706E-03 +8.978424E-06 +1.009164E-02 +1.254527E-05 +8.369823E-03 +8.564886E-06 +7.078759E-03 +7.850385E-06 +6.511893E-03 +7.778046E-06 +9.070684E-03 +1.106525E-05 +6.662311E-03 +5.901628E-06 +5.341082E-03 +4.512027E-06 +2.019250E-02 +5.835499E-05 +1.804537E-02 +4.752474E-05 +2.143023E-02 +6.883510E-05 +1.472836E-02 +3.235428E-05 +2.050065E-02 +5.392162E-05 +1.244535E-02 +2.314093E-05 +1.512563E-02 +2.709722E-05 +1.844357E-02 +4.096498E-05 +1.230849E-02 +2.204180E-05 +1.094959E-02 +1.878473E-05 +1.443675E-02 +2.665387E-05 +1.322804E-02 +2.121836E-05 +2.663562E-02 +9.639039E-05 +3.653391E-02 +1.705389E-04 +2.009980E-02 +5.226492E-05 +2.269292E-02 +7.235254E-05 +2.630232E-02 +8.600830E-05 +2.058472E-02 +6.670991E-05 +2.641568E-02 +9.197032E-05 +2.754053E-02 +1.038311E-04 +3.121142E-02 +1.199600E-04 +2.717065E-02 +9.654646E-05 +2.242629E-02 +1.009563E-04 +2.075151E-02 +5.816770E-05 +3.942214E-02 +1.987805E-04 +3.882076E-02 +1.939596E-04 +2.920978E-02 +1.084721E-04 +2.600676E-02 +8.334881E-05 +2.923234E-02 +1.017212E-04 +3.586528E-02 +1.334235E-04 +3.797598E-02 +1.702103E-04 +3.232846E-02 +1.218180E-04 +3.377761E-02 +1.378231E-04 +4.192066E-02 +2.072314E-04 +2.738955E-02 +8.865239E-05 +3.568104E-02 +1.804686E-04 +3.548082E-02 +1.615200E-04 +5.031302E-02 +3.122101E-04 +3.009267E-02 +1.144558E-04 +3.199905E-02 +1.145847E-04 +3.777360E-02 +1.663536E-04 +3.384202E-02 +1.350575E-04 +4.560705E-02 +2.708256E-04 +3.136124E-02 +1.138594E-04 +4.666445E-02 +2.341642E-04 +4.832203E-02 +2.735704E-04 +2.846160E-02 +9.724755E-05 +3.958876E-02 +1.723911E-04 +3.564894E-02 +1.460291E-04 +5.846112E-02 +3.948391E-04 +3.546238E-02 +1.608118E-04 +3.537206E-02 +1.460004E-04 +5.554597E-02 +3.566908E-04 +5.109455E-02 +3.208060E-04 +5.520597E-02 +3.527162E-04 +4.201987E-02 +1.917230E-04 +6.660358E-02 +4.711986E-04 +5.432898E-02 +3.242512E-04 +4.089084E-02 +1.879065E-04 +3.784277E-02 +1.557193E-04 +5.046288E-02 +2.834904E-04 +5.513093E-02 +3.595041E-04 +3.711842E-02 +1.494648E-04 +4.392972E-02 +2.015209E-04 +4.988699E-02 +2.634722E-04 +3.989393E-02 +1.816607E-04 +5.144002E-02 +2.769398E-04 +4.565016E-02 +2.355239E-04 +6.482286E-02 +4.539075E-04 +4.470289E-02 +2.139336E-04 +4.617957E-02 +2.463023E-04 +4.418753E-02 +2.283032E-04 +4.649993E-02 +2.511721E-04 +4.930410E-02 +2.838380E-04 +3.882151E-02 +1.837693E-04 +2.680799E-02 +8.238578E-05 +5.755520E-02 +4.130996E-04 +4.496883E-02 +2.557734E-04 +3.602591E-02 +1.512327E-04 +2.530643E-02 +9.160435E-05 +4.057178E-02 +1.911452E-04 +3.912871E-02 +1.943839E-04 +2.823744E-02 +1.084509E-04 +3.870972E-02 +1.741549E-04 +2.669650E-02 +9.821873E-05 +3.580275E-02 +1.589657E-04 +2.195198E-02 +5.837423E-05 +2.079687E-02 +6.448549E-05 +3.002400E-02 +1.160249E-04 +2.957314E-02 +1.189151E-04 +2.377935E-02 +6.808549E-05 +1.839041E-02 +4.555435E-05 +3.430294E-02 +1.387042E-04 +2.592718E-02 +9.050017E-05 +1.535960E-02 +3.794370E-05 +2.078265E-02 +7.317160E-05 +1.576237E-02 +2.996656E-05 +2.216535E-02 +6.517900E-05 +1.811146E-02 +4.238302E-05 +1.455371E-02 +3.667385E-05 +2.634667E-02 +8.364438E-05 +1.996539E-02 +4.953189E-05 +1.816175E-02 +3.710475E-05 +1.218979E-02 +2.484826E-05 +2.442424E-02 +8.794676E-05 +2.372381E-02 +7.702420E-05 +2.231590E-02 +9.784571E-05 +2.172844E-02 +5.916333E-05 +1.145998E-02 +1.962910E-05 +1.702504E-02 +5.111810E-05 +6.914654E-03 +8.875412E-06 +1.075152E-02 +2.522276E-05 +1.773996E-02 +4.090619E-05 +9.269666E-03 +1.495738E-05 +1.266630E-02 +2.461812E-05 +1.423043E-02 +3.464040E-05 +1.459824E-02 +3.078483E-05 +9.387052E-03 +1.202926E-05 +9.667799E-03 +1.454321E-05 +9.447707E-03 +1.271935E-05 +1.549107E-02 +2.931692E-05 +1.961989E-02 +5.758509E-05 +1.679927E-02 +4.376812E-05 +1.729049E-02 +4.546154E-05 +2.214419E-02 +5.744861E-05 +1.574631E-02 +3.404805E-05 +1.512389E-02 +2.852541E-05 +1.564070E-02 +2.961719E-05 +1.156911E-02 +1.664384E-05 +1.199574E-02 +1.963095E-05 +1.575890E-02 +3.865614E-05 +8.533212E-03 +1.165342E-05 +2.974207E-02 +1.029138E-04 +3.078702E-02 +1.267340E-04 +2.895029E-02 +9.417641E-05 +2.705881E-02 +1.080454E-04 +2.385421E-02 +7.531760E-05 +2.083704E-02 +6.502784E-05 +3.429066E-02 +1.504413E-04 +3.503625E-02 +1.408918E-04 +2.706075E-02 +8.947448E-05 +3.189758E-02 +1.230472E-04 +2.544089E-02 +8.519294E-05 +2.520959E-02 +8.797041E-05 +5.070461E-02 +3.189504E-04 +4.884044E-02 +2.572701E-04 +3.547633E-02 +1.862450E-04 +4.388084E-02 +2.567378E-04 +3.492269E-02 +1.420917E-04 +2.806485E-02 +1.009649E-04 +5.059445E-02 +2.907485E-04 +4.808491E-02 +2.424314E-04 +4.942392E-02 +3.097207E-04 +3.897127E-02 +1.994484E-04 +3.839420E-02 +1.746523E-04 +3.244417E-02 +1.184480E-04 +5.623036E-02 +3.492166E-04 +6.425888E-02 +4.935669E-04 +4.877756E-02 +2.579133E-04 +4.955342E-02 +2.926551E-04 +5.396104E-02 +3.055339E-04 +5.871614E-02 +3.961828E-04 +6.708244E-02 +4.826510E-04 +5.278021E-02 +2.835069E-04 +6.918022E-02 +5.087677E-04 +5.576575E-02 +3.607685E-04 +4.871576E-02 +2.820267E-04 +4.103199E-02 +1.970300E-04 +7.773659E-02 +6.470582E-04 +8.599878E-02 +8.479845E-04 +6.886056E-02 +5.267028E-04 +5.721217E-02 +3.681350E-04 +7.713996E-02 +6.425519E-04 +5.865857E-02 +4.103676E-04 +9.128533E-02 +9.001212E-04 +6.876681E-02 +4.977191E-04 +8.130881E-02 +7.186877E-04 +7.550488E-02 +6.383683E-04 +6.074888E-02 +4.148348E-04 +5.625163E-02 +3.768206E-04 +7.967025E-02 +7.546239E-04 +1.062008E-01 +1.178026E-03 +7.335119E-02 +5.749705E-04 +4.820386E-02 +2.843684E-04 +8.285561E-02 +7.331262E-04 +6.377785E-02 +4.639306E-04 +6.793437E-02 +5.094372E-04 +5.119790E-02 +2.807423E-04 +9.613221E-02 +9.824061E-04 +7.536222E-02 +5.822997E-04 +4.761788E-02 +2.477789E-04 +6.084099E-02 +4.333532E-04 +4.906915E-02 +3.040989E-04 +7.222981E-02 +6.031356E-04 +4.171024E-02 +1.905756E-04 +4.528343E-02 +2.268220E-04 +6.279446E-02 +4.327452E-04 +5.128421E-02 +2.753808E-04 +6.231043E-02 +4.457498E-04 +4.764799E-02 +2.670171E-04 +6.361492E-02 +4.379323E-04 +5.965053E-02 +3.939821E-04 +5.490029E-02 +3.380966E-04 +6.827868E-02 +4.968827E-04 +3.309475E-02 +1.331187E-04 +4.603502E-02 +2.672301E-04 +3.793331E-02 +1.804286E-04 +2.266265E-02 +5.756031E-05 +5.949869E-02 +3.999807E-04 +3.963197E-02 +1.762880E-04 +3.899893E-02 +1.642926E-04 +3.082622E-02 +1.074710E-04 +5.463795E-02 +3.382616E-04 +4.577997E-02 +2.244114E-04 +2.946043E-02 +1.104054E-04 +3.390553E-02 +1.311928E-04 +2.012911E-02 +4.877248E-05 +3.010504E-02 +1.111957E-04 +2.530155E-02 +8.217373E-05 +2.188500E-02 +5.370079E-05 +3.794688E-02 +1.630376E-04 +3.361882E-02 +1.162902E-04 +2.106804E-02 +5.229501E-05 +2.245974E-02 +5.982159E-05 +2.505198E-02 +8.478230E-05 +2.287601E-02 +6.940045E-05 +2.246447E-02 +6.064445E-05 +2.014030E-02 +4.596852E-05 +1.547790E-02 +2.802405E-05 +1.827409E-02 +3.706838E-05 +1.250681E-02 +2.504890E-05 +1.523959E-02 +3.397988E-05 +1.959572E-02 +4.638773E-05 +2.192689E-02 +6.243400E-05 +1.209982E-02 +1.817250E-05 +1.262662E-02 +2.516249E-05 +1.684816E-02 +3.966147E-05 +6.158783E-03 +6.145844E-06 +1.336232E-02 +2.474390E-05 +1.990714E-02 +5.523583E-05 +2.459172E-02 +7.004859E-05 +1.772252E-02 +4.853898E-05 +1.485696E-02 +2.873818E-05 +1.413071E-02 +3.178019E-05 +3.091676E-02 +1.063557E-04 +2.309515E-02 +6.359073E-05 +1.550213E-02 +4.421294E-05 +2.192641E-02 +6.676847E-05 +1.438379E-02 +2.502494E-05 +9.323835E-03 +1.058149E-05 +1.950987E-02 +5.777120E-05 +1.128375E-02 +1.672801E-05 +2.835693E-02 +1.026638E-04 +3.616127E-02 +1.505209E-04 +2.584643E-02 +7.628678E-05 +3.372488E-02 +1.431161E-04 +2.972258E-02 +1.013165E-04 +2.718135E-02 +9.239632E-05 +4.046046E-02 +2.091323E-04 +3.184363E-02 +1.406831E-04 +2.906162E-02 +9.931921E-05 +3.473938E-02 +1.672263E-04 +3.247790E-02 +1.200800E-04 +2.283247E-02 +6.591169E-05 +5.157721E-02 +2.857973E-04 +5.318589E-02 +3.355446E-04 +5.396648E-02 +3.222881E-04 +3.455908E-02 +1.577620E-04 +4.000627E-02 +1.811544E-04 +3.827765E-02 +1.701640E-04 +6.111711E-02 +4.195077E-04 +4.813123E-02 +2.551093E-04 +5.248302E-02 +3.053078E-04 +6.395395E-02 +4.882393E-04 +4.085525E-02 +2.131190E-04 +4.537763E-02 +2.817462E-04 +9.621518E-02 +9.753697E-04 +8.338063E-02 +7.366007E-04 +9.141446E-02 +9.402148E-04 +6.429772E-02 +4.457199E-04 +6.537278E-02 +4.627356E-04 +6.465671E-02 +4.504472E-04 +8.801279E-02 +8.983416E-04 +7.192007E-02 +5.371364E-04 +6.236850E-02 +5.079591E-04 +7.006768E-02 +5.856072E-04 +6.331101E-02 +4.271617E-04 +5.772433E-02 +3.721594E-04 +1.415443E-01 +2.106304E-03 +1.333977E-01 +1.819393E-03 +9.668520E-02 +1.012563E-03 +7.876408E-02 +7.180366E-04 +1.082944E-01 +1.226100E-03 +7.858017E-02 +6.820487E-04 +1.233753E-01 +1.710493E-03 +8.940326E-02 +8.711409E-04 +1.097575E-01 +1.284214E-03 +1.079765E-01 +1.255092E-03 +8.764292E-02 +8.394106E-04 +8.007939E-02 +7.022808E-04 +1.214238E-01 +1.596170E-03 +1.421555E-01 +2.105744E-03 +9.333869E-02 +9.022978E-04 +7.506639E-02 +6.221271E-04 +1.304706E-01 +1.799634E-03 +7.986544E-02 +7.526969E-04 +9.702135E-02 +9.836576E-04 +7.294081E-02 +5.906372E-04 +1.297603E-01 +1.782812E-03 +9.082392E-02 +8.669323E-04 +6.578070E-02 +5.122022E-04 +8.815494E-02 +8.142597E-04 +8.155167E-02 +7.217382E-04 +1.018109E-01 +1.086157E-03 +7.197825E-02 +5.331106E-04 +5.627838E-02 +3.449520E-04 +9.010939E-02 +8.605735E-04 +7.405764E-02 +5.833698E-04 +6.370311E-02 +4.307727E-04 +5.655449E-02 +4.002735E-04 +7.828799E-02 +6.754020E-04 +6.189231E-02 +4.227420E-04 +6.662691E-02 +5.039861E-04 +5.981533E-02 +4.042598E-04 +4.616563E-02 +2.512572E-04 +5.126904E-02 +2.954937E-04 +4.940896E-02 +3.013823E-04 +3.651484E-02 +1.509448E-04 +6.169343E-02 +4.343928E-04 +5.276526E-02 +3.035402E-04 +3.757296E-02 +1.669063E-04 +3.701904E-02 +1.472772E-04 +5.041077E-02 +2.708039E-04 +3.789204E-02 +1.599636E-04 +3.750354E-02 +1.758214E-04 +3.841079E-02 +1.623123E-04 +2.067644E-02 +6.321573E-05 +2.854616E-02 +9.473813E-05 +2.444174E-02 +7.627675E-05 +1.711406E-02 +4.015948E-05 +3.249873E-02 +1.518375E-04 +3.257016E-02 +1.207336E-04 +2.196857E-02 +6.460695E-05 +2.336435E-02 +6.693447E-05 +3.087108E-02 +1.244672E-04 +2.930263E-02 +1.042844E-04 +2.973494E-02 +9.755987E-05 +2.663199E-02 +7.916063E-05 +8.110891E-03 +9.147184E-06 +1.596974E-02 +3.945176E-05 +1.126941E-02 +1.972987E-05 +1.498580E-02 +2.597248E-05 +2.296704E-02 +6.870338E-05 +1.864901E-02 +4.568849E-05 +9.655003E-03 +1.218230E-05 +8.917615E-03 +1.497980E-05 +1.991649E-02 +4.425777E-05 +1.938334E-02 +4.450084E-05 +1.468869E-02 +2.783700E-05 +1.990846E-02 +4.552853E-05 +1.774831E-02 +4.009193E-05 +1.266322E-02 +2.320002E-05 +1.658764E-02 +3.986878E-05 +1.698328E-02 +4.091919E-05 +2.128494E-02 +6.048618E-05 +2.030808E-02 +5.574087E-05 +1.270134E-02 +2.233463E-05 +1.683769E-02 +3.536069E-05 +9.809511E-03 +1.445622E-05 +8.599393E-03 +1.081146E-05 +1.931983E-02 +6.640579E-05 +2.037581E-02 +5.286217E-05 +3.532151E-02 +1.703716E-04 +2.959688E-02 +1.000744E-04 +2.794173E-02 +9.833908E-05 +2.721311E-02 +8.705508E-05 +2.259018E-02 +6.498840E-05 +2.999787E-02 +1.185856E-04 +4.036794E-02 +2.072046E-04 +3.144378E-02 +1.169125E-04 +2.933694E-02 +1.105938E-04 +3.942738E-02 +1.729860E-04 +3.260874E-02 +1.481232E-04 +2.353895E-02 +7.836100E-05 +5.876129E-02 +3.975363E-04 +4.766425E-02 +2.519722E-04 +4.033714E-02 +1.807849E-04 +4.729862E-02 +2.401753E-04 +4.304677E-02 +2.096845E-04 +3.822586E-02 +1.740610E-04 +5.685525E-02 +3.389362E-04 +5.053276E-02 +3.049584E-04 +4.125673E-02 +1.768692E-04 +4.228077E-02 +2.108012E-04 +4.501666E-02 +2.298865E-04 +3.308537E-02 +1.337489E-04 +9.085434E-02 +8.630952E-04 +8.043671E-02 +6.998250E-04 +6.790115E-02 +5.151102E-04 +9.822017E-02 +1.054933E-03 +6.615956E-02 +4.705198E-04 +5.651598E-02 +3.870178E-04 +9.749998E-02 +1.051885E-03 +8.349892E-02 +7.963070E-04 +6.591239E-02 +4.655083E-04 +6.485664E-02 +4.646649E-04 +5.727855E-02 +3.614456E-04 +5.982342E-02 +3.951869E-04 +1.437862E-01 +2.121299E-03 +1.381644E-01 +1.981530E-03 +1.258886E-01 +1.695067E-03 +1.148436E-01 +1.441218E-03 +9.597117E-02 +1.101364E-03 +8.065670E-02 +7.548241E-04 +1.190394E-01 +1.472809E-03 +1.202733E-01 +1.590349E-03 +9.488301E-02 +9.917086E-04 +8.590582E-02 +8.395527E-04 +8.538615E-02 +7.662543E-04 +6.840866E-02 +5.508149E-04 +1.309341E-01 +1.788800E-03 +1.431432E-01 +2.124925E-03 +1.253592E-01 +1.673315E-03 +1.027124E-01 +1.115422E-03 +1.257192E-01 +1.618975E-03 +1.009903E-01 +1.140739E-03 +8.317957E-02 +7.328749E-04 +8.230977E-02 +7.081126E-04 +1.122030E-01 +1.312445E-03 +9.156529E-02 +9.645560E-04 +7.593394E-02 +6.433631E-04 +7.347627E-02 +5.887314E-04 +9.176044E-02 +8.793675E-04 +9.196817E-02 +9.288935E-04 +8.602817E-02 +7.934807E-04 +6.540851E-02 +5.134819E-04 +7.784855E-02 +7.374549E-04 +7.145641E-02 +5.431170E-04 +6.586554E-02 +4.742469E-04 +6.889110E-02 +5.369623E-04 +5.852275E-02 +3.823255E-04 +5.130633E-02 +2.938484E-04 +5.009392E-02 +2.807458E-04 +5.334814E-02 +3.079752E-04 +4.264743E-02 +1.994080E-04 +4.606571E-02 +2.446337E-04 +4.932925E-02 +2.518310E-04 +3.172175E-02 +1.173609E-04 +4.799012E-02 +2.513615E-04 +5.034796E-02 +2.882966E-04 +3.398215E-02 +1.394103E-04 +3.801944E-02 +1.702277E-04 +3.688050E-02 +1.492715E-04 +2.945875E-02 +1.064246E-04 +3.293199E-02 +1.292973E-04 +5.057135E-02 +2.972879E-04 +2.902424E-02 +1.009778E-04 +2.994301E-02 +1.055013E-04 +3.820998E-02 +1.811607E-04 +2.790027E-02 +1.186505E-04 +3.074064E-02 +1.078519E-04 +3.248893E-02 +1.169499E-04 +2.353194E-02 +8.076603E-05 +1.809505E-02 +4.072324E-05 +3.396351E-02 +1.453516E-04 +2.286807E-02 +5.496448E-05 +1.987060E-02 +5.376353E-05 +3.044601E-02 +1.115521E-04 +1.248945E-02 +2.198679E-05 +1.803171E-02 +4.771632E-05 +1.378131E-02 +4.134383E-05 +1.555134E-02 +4.721156E-05 +2.534113E-02 +8.351023E-05 +1.500299E-02 +2.635770E-05 +1.071802E-02 +2.136252E-05 +1.137076E-02 +1.975771E-05 +1.456502E-02 +2.501472E-05 +9.727505E-03 +1.483236E-05 +1.454436E-02 +2.710978E-05 +1.978067E-02 +5.285365E-05 +1.360981E-02 +2.336372E-05 +9.847294E-03 +1.509563E-05 +1.524613E-02 +3.552566E-05 +1.773316E-02 +4.971550E-05 +1.867569E-02 +4.914571E-05 +1.751220E-02 +3.467782E-05 +1.304981E-02 +3.349123E-05 +1.082428E-02 +1.865766E-05 +9.584944E-03 +1.325745E-05 +9.180830E-03 +1.262337E-05 +1.640308E-02 +3.160798E-05 +9.874242E-03 +1.450077E-05 +2.800307E-02 +9.021643E-05 +2.465166E-02 +8.472087E-05 +2.134009E-02 +5.841535E-05 +2.840708E-02 +9.453242E-05 +1.817238E-02 +4.004063E-05 +2.108886E-02 +5.388334E-05 +3.062270E-02 +1.286139E-04 +2.538387E-02 +8.871389E-05 +1.989607E-02 +5.232630E-05 +3.196356E-02 +1.567584E-04 +2.768337E-02 +8.817683E-05 +1.657009E-02 +3.128845E-05 +6.221175E-02 +5.006436E-04 +4.068999E-02 +2.287368E-04 +3.891057E-02 +1.725015E-04 +3.661313E-02 +1.700136E-04 +4.325252E-02 +2.377359E-04 +3.132785E-02 +1.053139E-04 +4.447018E-02 +2.340749E-04 +4.887097E-02 +2.828548E-04 +3.659403E-02 +1.932574E-04 +3.839512E-02 +1.702624E-04 +3.434064E-02 +1.413220E-04 +3.562809E-02 +1.569627E-04 +6.182234E-02 +4.171544E-04 +6.100628E-02 +4.051419E-04 +6.647923E-02 +4.900740E-04 +7.287500E-02 +5.551039E-04 +4.730174E-02 +2.512478E-04 +5.228155E-02 +3.234257E-04 +6.367674E-02 +4.355277E-04 +6.127620E-02 +5.160754E-04 +4.996635E-02 +2.866391E-04 +4.386223E-02 +2.253152E-04 +5.319524E-02 +3.262631E-04 +5.127473E-02 +2.891196E-04 +1.048530E-01 +1.182483E-03 +8.170362E-02 +7.286542E-04 +7.965260E-02 +6.956308E-04 +8.522862E-02 +7.597262E-04 +6.792526E-02 +5.514875E-04 +5.653238E-02 +4.231108E-04 +8.040674E-02 +7.324397E-04 +6.538609E-02 +5.208188E-04 +6.236588E-02 +4.356839E-04 +6.164613E-02 +4.180417E-04 +7.331991E-02 +6.180767E-04 +5.657072E-02 +3.533489E-04 +7.827811E-02 +6.870284E-04 +7.791072E-02 +6.465127E-04 +1.083139E-01 +1.260161E-03 +8.407475E-02 +7.634468E-04 +6.669029E-02 +4.841099E-04 +7.629250E-02 +6.708847E-04 +6.145772E-02 +4.524294E-04 +6.227290E-02 +4.295289E-04 +6.532027E-02 +4.771341E-04 +5.543686E-02 +3.242450E-04 +6.507036E-02 +4.562060E-04 +6.918175E-02 +5.208846E-04 +5.915840E-02 +4.026369E-04 +7.574284E-02 +6.257363E-04 +6.443876E-02 +4.697084E-04 +4.704047E-02 +2.420667E-04 +6.871095E-02 +5.703679E-04 +7.652879E-02 +6.996775E-04 +4.488343E-02 +2.199039E-04 +4.340162E-02 +2.117909E-04 +5.505629E-02 +3.299335E-04 +5.395493E-02 +3.792417E-04 +4.982738E-02 +2.664394E-04 +5.864743E-02 +4.020406E-04 +3.700812E-02 +1.675101E-04 +3.590296E-02 +1.636877E-04 +3.701403E-02 +2.028641E-04 +3.559772E-02 +1.412606E-04 +4.420940E-02 +2.126895E-04 +3.967986E-02 +1.668324E-04 +2.751914E-02 +1.031787E-04 +3.350726E-02 +1.282541E-04 +3.400056E-02 +1.396521E-04 +2.928242E-02 +1.253649E-04 +3.696302E-02 +1.675271E-04 +2.971538E-02 +1.050504E-04 +2.147157E-02 +6.672784E-05 +2.068698E-02 +5.314224E-05 +3.024410E-02 +1.161314E-04 +2.564259E-02 +8.893011E-05 +2.244324E-02 +6.402041E-05 +3.352393E-02 +1.269472E-04 +2.503002E-02 +1.001149E-04 +2.271412E-02 +6.142137E-05 +2.662779E-02 +8.519648E-05 +2.760352E-02 +9.770118E-05 +3.168086E-02 +1.170083E-04 +2.636525E-02 +8.041298E-05 +1.168923E-02 +2.309996E-05 +1.341095E-02 +2.785722E-05 +9.527042E-03 +1.301984E-05 +8.579383E-03 +1.158986E-05 +1.770829E-02 +3.709440E-05 +1.285206E-02 +2.277856E-05 +5.715674E-03 +5.170007E-06 +7.751126E-03 +1.014219E-05 +1.566218E-02 +2.874454E-05 +1.550600E-02 +4.482121E-05 +1.310088E-02 +2.996692E-05 +1.266810E-02 +2.452354E-05 +1.328220E-02 +2.441758E-05 +9.553257E-03 +1.316655E-05 +1.072874E-02 +2.962475E-05 +1.419443E-02 +2.691293E-05 +1.389066E-02 +2.460204E-05 +1.520080E-02 +2.942326E-05 +9.725298E-03 +1.180312E-05 +9.645833E-03 +1.760954E-05 +8.964384E-03 +1.441525E-05 +7.797734E-03 +7.875870E-06 +1.222531E-02 +2.143962E-05 +9.811025E-03 +1.223418E-05 +2.347719E-02 +7.632207E-05 +2.624065E-02 +8.577440E-05 +1.872843E-02 +5.642768E-05 +2.884633E-02 +1.120462E-04 +1.331677E-02 +2.169139E-05 +2.073785E-02 +6.410937E-05 +2.069105E-02 +5.558996E-05 +2.409694E-02 +8.187520E-05 +1.689558E-02 +4.223843E-05 +1.624061E-02 +3.418316E-05 +2.151976E-02 +5.877173E-05 +2.360183E-02 +9.731432E-05 +3.349038E-02 +1.331399E-04 +3.071585E-02 +1.134216E-04 +3.064437E-02 +1.380256E-04 +3.411658E-02 +1.385980E-04 +1.902680E-02 +4.966952E-05 +2.548619E-02 +8.563915E-05 +2.627494E-02 +8.806514E-05 +3.156158E-02 +1.348057E-04 +2.555848E-02 +8.827726E-05 +2.109045E-02 +5.840881E-05 +3.141908E-02 +1.092575E-04 +2.542704E-02 +7.869948E-05 +4.409974E-02 +2.370516E-04 +4.511455E-02 +2.385642E-04 +3.493033E-02 +1.329289E-04 +3.573369E-02 +1.645671E-04 +3.658071E-02 +1.701779E-04 +2.875736E-02 +1.063832E-04 +4.612939E-02 +2.341592E-04 +4.488569E-02 +2.371072E-04 +3.283008E-02 +1.266329E-04 +4.421310E-02 +2.144763E-04 +3.688239E-02 +1.597994E-04 +3.783217E-02 +1.715032E-04 +7.381035E-02 +5.788223E-04 +5.920057E-02 +3.764365E-04 +5.566865E-02 +3.245756E-04 +5.294945E-02 +3.171578E-04 +5.308993E-02 +3.020899E-04 +4.015025E-02 +1.763785E-04 +5.449993E-02 +4.477957E-04 +6.098529E-02 +4.698598E-04 +4.562321E-02 +2.217931E-04 +4.372709E-02 +2.205027E-04 +5.027493E-02 +3.024221E-04 +5.350904E-02 +3.184156E-04 +4.989979E-02 +2.950952E-04 +5.166796E-02 +2.972852E-04 +5.157410E-02 +3.015135E-04 +4.679395E-02 +2.264100E-04 +4.534145E-02 +2.596978E-04 +4.610982E-02 +2.659116E-04 +4.420313E-02 +2.280910E-04 +4.382650E-02 +2.133009E-04 +4.090414E-02 +1.993174E-04 +3.320114E-02 +1.287562E-04 +4.502626E-02 +2.259113E-04 +3.962180E-02 +1.762251E-04 +4.967895E-02 +3.145518E-04 +4.494669E-02 +2.411637E-04 +4.339354E-02 +2.011700E-04 +4.176613E-02 +2.014202E-04 +4.442877E-02 +2.331921E-04 +3.398932E-02 +1.379211E-04 +3.482327E-02 +1.541052E-04 +3.556969E-02 +1.558964E-04 +3.691095E-02 +1.643955E-04 +2.226522E-02 +6.975395E-05 +3.915757E-02 +1.657456E-04 +2.866444E-02 +9.309362E-05 +2.855915E-02 +1.131346E-04 +2.537276E-02 +7.948738E-05 +3.789334E-02 +1.685996E-04 +2.751514E-02 +9.186058E-05 +3.178599E-02 +1.355963E-04 +3.907421E-02 +2.055557E-04 +2.791323E-02 +1.069896E-04 +3.339152E-02 +1.362152E-04 +2.050184E-02 +4.863200E-05 +2.291794E-02 +8.183025E-05 +2.124223E-02 +7.063324E-05 +2.399149E-02 +7.407918E-05 +1.796496E-02 +3.936797E-05 +2.078322E-02 +6.098637E-05 +3.024688E-02 +1.288165E-04 +2.239542E-02 +6.306787E-05 +2.616525E-02 +8.655425E-05 +2.919821E-02 +1.113037E-04 +1.673318E-02 +3.601539E-05 +1.608480E-02 +3.314965E-05 +2.821455E-02 +8.921863E-05 +1.974153E-02 +4.431146E-05 +2.003418E-02 +5.758763E-05 +2.061128E-02 +6.512772E-05 +1.559522E-02 +3.594737E-05 +1.934663E-02 +5.001512E-05 +1.075360E-02 +1.792213E-05 +8.194926E-03 +1.028496E-05 +2.034805E-02 +5.444881E-05 +1.609037E-02 +3.970183E-05 +1.347309E-02 +2.123107E-05 +1.407160E-02 +3.569412E-05 +1.624142E-02 +3.714221E-05 +1.299629E-02 +2.459818E-05 +1.122458E-02 +2.237869E-05 +1.211612E-02 +2.219160E-05 +1.408358E-02 +4.218855E-05 +6.735065E-03 +8.482615E-06 +6.793305E-03 +7.845095E-06 +8.478782E-03 +1.709477E-05 +1.133766E-02 +1.980469E-05 +9.653050E-03 +1.415133E-05 +5.831329E-03 +8.381192E-06 +6.218892E-03 +7.102476E-06 +7.592811E-03 +9.310767E-06 +6.506941E-03 +1.095631E-05 +9.452991E-03 +1.264596E-05 +4.768636E-03 +3.507810E-06 +2.077918E-02 +5.890772E-05 +1.762060E-02 +3.525407E-05 +1.205428E-02 +2.724892E-05 +1.469350E-02 +2.710234E-05 +8.551477E-03 +8.546946E-06 +1.223789E-02 +2.595121E-05 +1.076533E-02 +2.013472E-05 +1.864688E-02 +4.804170E-05 +1.271229E-02 +2.770046E-05 +1.016698E-02 +1.439334E-05 +1.713823E-02 +4.788386E-05 +1.253277E-02 +2.231383E-05 +3.154747E-02 +1.214804E-04 +1.749980E-02 +3.647612E-05 +1.830338E-02 +4.569688E-05 +2.308843E-02 +6.321283E-05 +1.594268E-02 +4.383360E-05 +2.466928E-02 +8.077902E-05 +2.901767E-02 +1.088029E-04 +2.554390E-02 +8.895350E-05 +2.146121E-02 +5.921450E-05 +1.943347E-02 +4.952984E-05 +1.991855E-02 +5.703083E-05 +1.411715E-02 +3.539989E-05 +2.706714E-02 +1.408378E-04 +2.476826E-02 +8.960297E-05 +3.280672E-02 +1.342648E-04 +2.769569E-02 +8.949765E-05 +2.254343E-02 +7.118925E-05 +2.821645E-02 +1.008088E-04 +2.332049E-02 +7.198089E-05 +3.472802E-02 +1.359900E-04 +2.098228E-02 +6.775921E-05 +2.011754E-02 +4.899916E-05 +2.887549E-02 +1.210569E-04 +2.169717E-02 +5.971602E-05 +4.083980E-02 +2.063696E-04 +2.682109E-02 +9.162241E-05 +4.087409E-02 +1.874734E-04 +3.397314E-02 +1.355352E-04 +2.503682E-02 +7.832902E-05 +3.341902E-02 +1.279805E-04 +3.470031E-02 +1.457506E-04 +3.434771E-02 +1.308149E-04 +1.924341E-02 +5.117189E-05 +2.610217E-02 +8.124782E-05 +2.672020E-02 +8.422537E-05 +2.913338E-02 +1.020506E-04 +3.799748E-02 +1.583935E-04 +2.396284E-02 +7.323177E-05 +4.085381E-02 +1.817575E-04 +3.429492E-02 +1.389255E-04 +2.955640E-02 +9.833007E-05 +3.550154E-02 +1.507005E-04 +3.041263E-02 +1.000878E-04 +3.068456E-02 +1.089623E-04 +2.480886E-02 +6.953343E-05 +2.214997E-02 +5.427501E-05 +2.822289E-02 +1.091821E-04 +2.246583E-02 +6.845501E-05 +3.548869E-02 +1.564383E-04 +3.342714E-02 +1.555114E-04 +3.584609E-02 +1.533905E-04 +2.543087E-02 +6.947810E-05 +3.395479E-02 +1.360453E-04 +3.067172E-02 +1.109996E-04 +2.290343E-02 +6.048129E-05 +1.985458E-02 +4.438216E-05 +3.051514E-02 +1.050122E-04 +2.086630E-02 +6.348306E-05 +2.009163E-02 +5.579571E-05 +2.312023E-02 +7.424842E-05 +2.349909E-02 +7.517591E-05 +2.465382E-02 +7.402420E-05 +2.149996E-02 +6.067745E-05 +2.388756E-02 +6.487269E-05 +1.918145E-02 +4.328933E-05 +1.951810E-02 +4.931597E-05 +1.743909E-02 +3.923120E-05 +1.959452E-02 +4.325142E-05 +1.836248E-02 +3.960818E-05 +1.633324E-02 +3.551742E-05 +1.863545E-02 +4.322646E-05 +2.548530E-02 +8.566650E-05 +1.370389E-02 +3.068862E-05 +1.702755E-02 +3.470486E-05 +2.110298E-02 +5.769891E-05 +1.950441E-02 +4.624026E-05 +1.773108E-02 +3.976096E-05 +2.121981E-02 +6.568857E-05 +1.052851E-02 +1.559210E-05 +1.304079E-02 +2.231298E-05 +1.944748E-02 +4.683893E-05 +1.445243E-02 +2.703435E-05 +1.597053E-02 +3.429994E-05 +1.650649E-02 +6.011419E-05 +8.568107E-03 +1.035370E-05 +5.963022E-03 +7.941116E-06 +1.005055E-02 +1.089546E-05 +9.025557E-03 +1.235125E-05 +1.058696E-02 +1.548458E-05 +1.428111E-02 +3.101021E-05 +6.332158E-03 +7.284553E-06 +1.107873E-02 +1.880555E-05 +9.074481E-03 +1.488548E-05 +8.633788E-03 +1.494006E-05 +9.852689E-03 +2.277679E-05 +1.279962E-02 +3.267960E-05 +1.096915E-02 +1.703897E-05 +6.543158E-03 +6.896083E-06 +7.823512E-03 +1.199583E-05 +6.285302E-03 +8.223945E-06 +7.196837E-03 +8.695066E-06 +6.939525E-03 +8.067024E-06 +4.593174E-03 +3.678022E-06 +4.766649E-03 +6.980855E-06 +4.492564E-03 +4.106885E-06 +5.836560E-03 +5.166762E-06 +4.091860E-03 +3.202729E-06 +2.851717E-03 +1.441790E-06 +1.131813E-02 +1.990562E-05 +8.044232E-03 +9.338147E-06 +9.601976E-03 +1.551372E-05 +1.271494E-02 +2.673243E-05 +6.142371E-03 +6.616946E-06 +7.543735E-03 +1.129556E-05 +1.054461E-02 +1.314345E-05 +1.244849E-02 +1.966250E-05 +9.734137E-03 +1.778830E-05 +1.360778E-02 +2.168963E-05 +8.980518E-03 +9.981098E-06 +5.673726E-03 +6.390047E-06 +1.495065E-02 +3.570344E-05 +1.139512E-02 +2.213315E-05 +1.578970E-02 +3.505969E-05 +1.629500E-02 +3.158196E-05 +1.481063E-02 +3.260955E-05 +1.632506E-02 +3.683693E-05 +1.058030E-02 +1.860245E-05 +1.014653E-02 +1.703372E-05 +1.053471E-02 +1.946614E-05 +1.087794E-02 +1.741794E-05 +1.749138E-02 +4.059625E-05 +1.441949E-02 +4.081297E-05 +2.238698E-02 +8.411387E-05 +1.355243E-02 +2.880517E-05 +2.176689E-02 +7.043906E-05 +1.938423E-02 +5.171647E-05 +1.365868E-02 +3.105929E-05 +1.615560E-02 +3.821091E-05 +1.688664E-02 +4.289252E-05 +1.314826E-02 +2.645963E-05 +1.505920E-02 +3.910868E-05 +1.696322E-02 +4.410507E-05 +1.531505E-02 +2.627391E-05 +1.302530E-02 +2.447578E-05 +2.215989E-02 +5.624695E-05 +1.558271E-02 +3.591163E-05 +1.660587E-02 +4.451639E-05 +2.152716E-02 +6.525487E-05 +1.897151E-02 +5.231568E-05 +1.728826E-02 +5.214345E-05 +1.902678E-02 +5.314163E-05 +2.333937E-02 +8.182246E-05 +9.443854E-03 +1.172248E-05 +1.198026E-02 +2.003714E-05 +2.138685E-02 +6.175227E-05 +1.274599E-02 +2.433959E-05 +1.947534E-02 +5.207291E-05 +1.815170E-02 +4.398794E-05 +3.169585E-02 +1.333543E-04 +1.905286E-02 +4.657423E-05 +1.494275E-02 +3.505332E-05 +1.763876E-02 +4.461835E-05 +1.182033E-02 +2.214931E-05 +1.968821E-02 +5.319218E-05 +1.722391E-02 +3.689380E-05 +1.164039E-02 +2.017520E-05 +1.987702E-02 +4.962563E-05 +1.593272E-02 +4.198443E-05 +1.295575E-02 +3.292363E-05 +1.574293E-02 +3.434465E-05 +2.730586E-02 +8.253402E-05 +2.116215E-02 +5.127586E-05 +1.343828E-02 +2.408890E-05 +1.857254E-02 +4.513774E-05 +1.500919E-02 +3.231350E-05 +1.678659E-02 +3.962936E-05 +1.488856E-02 +2.386764E-05 +1.230601E-02 +2.575268E-05 +2.037392E-02 +5.965465E-05 +1.096474E-02 +1.759636E-05 +2.187484E-02 +6.525702E-05 +1.374639E-02 +2.555749E-05 +1.511590E-02 +3.826384E-05 +1.563929E-02 +3.222315E-05 +1.684288E-02 +4.027516E-05 +1.773599E-02 +6.209617E-05 +1.720006E-02 +3.431594E-05 +1.841885E-02 +4.086225E-05 +1.218119E-02 +2.095533E-05 +1.065430E-02 +1.713440E-05 +1.058773E-02 +1.668419E-05 +1.135705E-02 +1.500764E-05 +1.158632E-02 +2.852635E-05 +8.247777E-03 +1.228385E-05 +1.907771E-02 +4.597570E-05 +1.777609E-02 +4.816332E-05 +1.285738E-02 +2.710713E-05 +1.336306E-02 +2.768885E-05 +7.498631E-03 +1.438567E-05 +1.168505E-02 +2.200300E-05 +8.575921E-03 +8.903420E-06 +6.935145E-03 +9.218014E-06 +9.998062E-03 +1.881829E-05 +8.939471E-03 +1.098615E-05 +7.860596E-03 +1.449285E-05 +1.082459E-02 +1.896980E-05 +5.782585E-03 +5.702033E-06 +1.004504E-02 +2.149248E-05 +7.503097E-03 +1.089878E-05 +6.843525E-03 +9.834532E-06 +1.381318E-03 +8.252352E-07 +5.676320E-03 +7.883845E-06 +5.874523E-03 +3.759183E-06 +4.793821E-03 +2.805686E-06 +6.125800E-03 +6.903423E-06 +8.300434E-03 +1.293197E-05 +8.058716E-03 +1.160479E-05 +6.964643E-03 +9.276538E-06 +3.462172E-03 +2.364550E-06 +4.968406E-03 +4.433251E-06 +6.306240E-03 +6.070974E-06 +6.018210E-03 +7.366216E-06 +8.837800E-03 +9.688936E-06 +5.096909E-03 +4.382163E-06 +3.815130E-03 +6.161058E-06 +4.515200E-03 +4.595497E-06 +6.864810E-03 +1.010895E-05 +6.423468E-03 +9.143165E-06 +9.538660E-03 +1.560977E-05 +1.261072E-02 +2.250707E-05 +1.026530E-02 +1.637414E-05 +9.557506E-03 +1.527890E-05 +8.827930E-03 +1.066139E-05 +5.478962E-03 +5.569868E-06 +9.080187E-03 +1.204024E-05 +1.528742E-02 +3.325338E-05 +1.337087E-02 +1.956015E-05 +1.675398E-02 +4.575869E-05 +1.281954E-02 +3.179463E-05 +8.332353E-03 +1.484699E-05 +1.617850E-02 +3.768574E-05 +1.581638E-02 +5.060008E-05 +1.558998E-02 +3.489775E-05 +1.170539E-02 +1.670388E-05 +9.403406E-03 +1.210849E-05 +6.538447E-03 +7.590433E-06 +1.533222E-02 +3.995585E-05 +9.660974E-03 +1.337453E-05 +1.612761E-02 +3.190924E-05 +1.123730E-02 +1.881522E-05 +6.517842E-03 +9.004602E-06 +1.039422E-02 +1.944508E-05 +1.196688E-02 +2.077099E-05 +1.825266E-02 +5.884867E-05 +1.114412E-02 +1.635734E-05 +6.855502E-03 +9.696697E-06 +7.937283E-03 +1.011203E-05 +1.305061E-02 +2.491232E-05 +2.084992E-02 +5.566232E-05 +9.019271E-03 +1.005494E-05 +1.029368E-02 +1.905328E-05 +1.763980E-02 +4.024339E-05 +9.329184E-03 +1.252705E-05 +1.325489E-02 +2.563636E-05 +1.556775E-02 +3.949834E-05 +2.061223E-02 +6.392049E-05 +1.758113E-02 +3.625999E-05 +1.157256E-02 +2.047838E-05 +8.563192E-03 +1.228712E-05 +1.031763E-02 +1.411955E-05 +1.512631E-02 +4.654173E-05 +1.486827E-02 +2.864290E-05 +2.251974E-02 +5.878585E-05 +1.538325E-02 +2.676876E-05 +1.352613E-02 +3.627305E-05 +1.449237E-02 +3.612781E-05 +1.192626E-02 +2.019597E-05 +1.304918E-02 +2.426503E-05 +1.605822E-02 +3.012824E-05 +1.727927E-02 +3.755550E-05 +9.669506E-03 +1.630871E-05 +1.276773E-02 +2.526258E-05 +1.428968E-02 +3.134862E-05 +1.703682E-02 +4.403612E-05 +1.839993E-02 +4.005997E-05 +1.709877E-02 +3.494229E-05 +1.020568E-02 +2.306756E-05 +1.556313E-02 +2.961997E-05 +1.367798E-02 +2.209767E-05 +1.479845E-02 +2.697536E-05 +1.064351E-02 +1.544937E-05 +1.457069E-02 +3.339049E-05 +1.022585E-02 +1.440893E-05 +1.072359E-02 +1.406891E-05 +2.091105E-02 +5.324749E-05 +1.381809E-02 +3.338254E-05 +1.600746E-02 +3.282400E-05 +1.918686E-02 +4.509327E-05 +1.087716E-02 +1.741352E-05 +1.712809E-02 +3.956314E-05 +1.312095E-02 +1.981242E-05 +1.874899E-02 +4.287445E-05 +1.113725E-02 +2.004136E-05 +7.103716E-03 +7.213595E-06 +1.369370E-02 +3.063256E-05 +9.195487E-03 +1.412638E-05 +1.141322E-02 +1.860950E-05 +1.114463E-02 +1.989362E-05 +1.766608E-02 +3.977019E-05 +1.831950E-02 +5.100972E-05 +9.842311E-03 +1.641174E-05 +1.050669E-02 +1.611304E-05 +9.275886E-03 +1.425314E-05 +1.489107E-02 +2.846318E-05 +1.024738E-02 +1.638704E-05 +1.238766E-02 +2.905937E-05 +8.220882E-03 +1.610701E-05 +7.911660E-03 +1.204791E-05 +6.724074E-03 +8.382502E-06 +7.246664E-03 +1.223989E-05 +9.981199E-03 +1.983647E-05 +7.195641E-03 +1.261848E-05 +5.805501E-03 +6.427362E-06 +7.853739E-03 +1.109259E-05 +5.029358E-03 +4.590158E-06 +7.362545E-03 +9.705721E-06 +6.742269E-03 +5.672589E-06 +8.306759E-03 +1.150294E-05 +2.269532E-03 +1.413152E-06 +5.728846E-03 +6.054291E-06 +6.497853E-03 +7.598936E-06 +5.211040E-03 +7.706367E-06 +1.091775E-02 +2.620541E-05 +7.186930E-03 +7.840316E-06 +5.773406E-03 +6.737773E-06 +8.315747E-03 +1.614189E-05 +1.045710E-02 +1.408567E-05 +1.373927E-02 +2.417114E-05 +4.474588E-03 +2.860895E-06 +7.106756E-03 +8.922176E-06 +1.703428E-02 +3.411039E-05 +7.032210E-03 +5.972986E-06 +7.519022E-03 +9.923714E-06 +1.019763E-02 +1.870985E-05 +1.003939E-02 +1.665677E-05 +5.257180E-03 +7.163497E-06 +6.709259E-03 +1.080672E-05 +6.660210E-03 +8.371462E-06 +1.339388E-02 +2.963406E-05 +2.041319E-02 +6.283530E-05 +1.277136E-02 +2.113278E-05 +1.095487E-02 +1.788661E-05 +1.210895E-02 +2.269317E-05 +9.526669E-03 +1.459758E-05 +1.595135E-02 +4.590455E-05 +1.583142E-02 +3.433698E-05 +1.814067E-02 +5.361094E-05 +2.020117E-02 +5.966829E-05 +1.078165E-02 +2.464395E-05 +1.503699E-02 +3.786272E-05 +1.636813E-02 +3.872799E-05 +2.272579E-02 +7.702949E-05 +1.895617E-02 +5.205980E-05 +1.364788E-02 +2.639491E-05 +1.991314E-02 +7.408716E-05 +1.011963E-02 +1.544567E-05 +1.853803E-02 +4.673643E-05 +1.601464E-02 +3.647742E-05 +2.688432E-02 +8.994718E-05 +1.910229E-02 +4.828596E-05 +1.310107E-02 +2.599395E-05 +2.493961E-02 +8.021464E-05 +2.136141E-02 +5.184829E-05 +2.544806E-02 +7.994724E-05 +1.143679E-02 +1.661591E-05 +1.709579E-02 +4.337367E-05 +2.083317E-02 +5.556329E-05 +1.866022E-02 +4.397347E-05 +3.145206E-02 +1.280431E-04 +2.210382E-02 +5.769121E-05 +1.823923E-02 +4.074602E-05 +1.528594E-02 +3.104999E-05 +1.711154E-02 +4.112452E-05 +1.507762E-02 +2.770618E-05 +2.206514E-02 +6.022082E-05 +2.319277E-02 +5.836530E-05 +1.896072E-02 +4.024144E-05 +1.655441E-02 +4.163720E-05 +1.804406E-02 +4.084019E-05 +2.452803E-02 +7.291599E-05 +2.802970E-02 +1.259325E-04 +2.453139E-02 +7.079239E-05 +2.489486E-02 +6.688553E-05 +2.178711E-02 +7.105053E-05 +1.906738E-02 +4.476745E-05 +2.527667E-02 +8.182112E-05 +2.331217E-02 +6.232971E-05 +2.781953E-02 +9.708263E-05 +1.997547E-02 +4.443113E-05 +2.088515E-02 +5.171598E-05 +2.303205E-02 +8.024769E-05 +1.915503E-02 +4.593806E-05 +2.571317E-02 +8.223527E-05 +1.506654E-02 +3.035107E-05 +2.999022E-02 +1.183624E-04 +2.875220E-02 +1.019916E-04 +1.859536E-02 +4.941826E-05 +2.237740E-02 +6.098459E-05 +1.818345E-02 +4.548133E-05 +2.387148E-02 +8.542723E-05 +1.893980E-02 +4.021031E-05 +2.098013E-02 +5.353962E-05 +2.652625E-02 +8.621445E-05 +1.979268E-02 +5.173051E-05 +2.005599E-02 +5.014567E-05 +1.869207E-02 +4.863434E-05 +2.062895E-02 +5.960259E-05 +2.035386E-02 +4.757091E-05 +1.380341E-02 +2.450580E-05 +1.716354E-02 +4.220694E-05 +1.514915E-02 +2.661478E-05 +9.617277E-03 +1.245420E-05 +1.625088E-02 +3.575586E-05 +1.556949E-02 +3.732096E-05 +1.713751E-02 +3.918991E-05 +1.288808E-02 +2.331234E-05 +1.411636E-02 +2.581158E-05 +8.295504E-03 +1.118839E-05 +1.490088E-02 +3.193897E-05 +1.120118E-02 +1.562213E-05 +1.159281E-02 +1.980721E-05 +1.203548E-02 +2.711369E-05 +1.339573E-02 +2.158602E-05 +1.280581E-02 +2.079765E-05 +1.083998E-02 +1.727408E-05 +1.315255E-02 +2.519274E-05 +1.207379E-02 +2.152665E-05 +1.232904E-02 +2.825538E-05 +1.209938E-02 +2.379986E-05 +7.347293E-03 +8.920021E-06 +1.420050E-02 +2.556068E-05 +1.406290E-02 +2.882913E-05 +1.226796E-02 +2.904134E-05 +1.529742E-02 +3.412784E-05 +9.361135E-03 +1.953641E-05 +7.653780E-03 +9.090398E-06 +1.172034E-02 +1.741493E-05 +6.481510E-03 +6.366134E-06 +1.483462E-02 +3.419849E-05 +7.287071E-03 +9.994231E-06 +7.014536E-03 +8.683589E-06 +3.914638E-03 +3.851978E-06 +1.039507E-02 +1.247058E-05 +1.449371E-02 +3.268737E-05 +6.107315E-03 +1.275657E-05 +5.912533E-03 +5.291900E-06 +1.241975E-02 +2.776459E-05 +1.652474E-02 +3.478228E-05 +9.924557E-03 +2.111611E-05 +1.112655E-02 +2.134337E-05 +1.490879E-02 +4.120682E-05 +1.214873E-02 +1.828276E-05 +1.878471E-02 +4.595384E-05 +1.068338E-02 +2.052816E-05 +9.957982E-03 +1.661273E-05 +8.679245E-03 +1.539340E-05 +7.944462E-03 +1.238828E-05 +9.333064E-03 +1.407498E-05 +2.180639E-02 +5.625519E-05 +2.409216E-02 +8.351837E-05 +2.095008E-02 +5.330117E-05 +2.458431E-02 +7.696318E-05 +1.741223E-02 +4.634669E-05 +2.052947E-02 +5.641630E-05 +2.507271E-02 +7.084493E-05 +2.192019E-02 +5.996923E-05 +1.687601E-02 +3.734411E-05 +2.188351E-02 +5.331644E-05 +2.625531E-02 +8.987505E-05 +1.947839E-02 +5.362737E-05 +2.561506E-02 +8.555702E-05 +3.072429E-02 +1.057779E-04 +2.548154E-02 +8.649311E-05 +2.215408E-02 +5.389914E-05 +2.857258E-02 +9.992187E-05 +2.271191E-02 +6.458178E-05 +3.417289E-02 +1.353676E-04 +2.406069E-02 +7.233156E-05 +2.858289E-02 +1.096000E-04 +3.086685E-02 +1.088635E-04 +1.806766E-02 +4.316705E-05 +2.440571E-02 +6.395626E-05 +3.255341E-02 +1.376111E-04 +4.078794E-02 +1.950454E-04 +2.169319E-02 +5.623674E-05 +2.222088E-02 +7.931181E-05 +3.507566E-02 +1.330312E-04 +3.153876E-02 +1.223922E-04 +3.739825E-02 +1.655348E-04 +3.186914E-02 +1.164407E-04 +3.186332E-02 +1.211760E-04 +3.046668E-02 +1.045865E-04 +2.468913E-02 +7.595312E-05 +2.725403E-02 +9.530282E-05 +3.669370E-02 +1.633028E-04 +4.142607E-02 +2.202378E-04 +2.274887E-02 +6.024427E-05 +2.852673E-02 +1.084379E-04 +3.552692E-02 +1.550998E-04 +1.953889E-02 +4.742931E-05 +4.288258E-02 +2.326284E-04 +3.527647E-02 +1.532875E-04 +3.831735E-02 +1.712470E-04 +3.740668E-02 +1.804477E-04 +3.067443E-02 +1.226235E-04 +2.859755E-02 +9.502065E-05 +3.656012E-02 +1.473474E-04 +4.428469E-02 +2.135422E-04 +3.876237E-02 +1.826793E-04 +3.168779E-02 +1.136526E-04 +4.132746E-02 +1.944335E-04 +3.080999E-02 +1.075137E-04 +3.809598E-02 +1.579372E-04 +3.950419E-02 +1.784657E-04 +5.023062E-02 +3.049706E-04 +4.789752E-02 +2.554387E-04 +3.458880E-02 +1.324150E-04 +4.090067E-02 +1.965130E-04 +3.045883E-02 +1.164732E-04 +3.897593E-02 +1.862204E-04 +1.900547E-02 +4.239429E-05 +2.523518E-02 +8.151515E-05 +3.480501E-02 +1.535823E-04 +2.911328E-02 +1.131135E-04 +3.135787E-02 +1.158315E-04 +2.364659E-02 +7.666160E-05 +3.489798E-02 +1.613478E-04 +3.305825E-02 +1.226465E-04 +3.424037E-02 +1.511504E-04 +3.144976E-02 +1.315971E-04 +2.386686E-02 +9.966283E-05 +2.343488E-02 +7.865295E-05 +1.809482E-02 +3.639503E-05 +1.592339E-02 +3.078924E-05 +3.395399E-02 +1.387775E-04 +2.173542E-02 +6.688037E-05 +1.139408E-02 +1.661367E-05 +1.191973E-02 +1.884978E-05 +2.149843E-02 +5.543388E-05 +2.139730E-02 +5.948238E-05 +1.878719E-02 +3.863865E-05 +2.861748E-02 +9.903233E-05 +1.663769E-02 +3.586183E-05 +2.392378E-02 +7.633777E-05 +1.826846E-02 +4.768962E-05 +1.258024E-02 +2.584217E-05 +1.836655E-02 +4.161069E-05 +1.896044E-02 +4.007711E-05 +1.782079E-02 +3.615894E-05 +1.682346E-02 +3.435373E-05 +1.864611E-02 +4.004514E-05 +2.027124E-02 +4.802356E-05 +1.572197E-02 +4.060890E-05 +1.809973E-02 +5.222844E-05 +8.922954E-03 +1.541312E-05 +1.042804E-02 +1.919810E-05 +1.663952E-02 +3.230801E-05 +1.416041E-02 +3.240599E-05 +1.364911E-02 +2.047968E-05 +1.466030E-02 +2.789488E-05 +7.525078E-03 +8.889694E-06 +6.730764E-03 +9.941085E-06 +1.007468E-02 +1.767697E-05 +1.050555E-02 +1.620042E-05 +8.346548E-03 +1.182646E-05 +9.053361E-03 +1.420984E-05 +1.665200E-02 +5.444887E-05 +1.527178E-02 +2.919176E-05 +1.380005E-02 +2.920152E-05 +9.043029E-03 +1.785555E-05 +1.950145E-02 +4.990311E-05 +1.401098E-02 +2.753310E-05 +1.823652E-02 +4.520948E-05 +1.710659E-02 +4.707810E-05 +1.381860E-02 +3.468506E-05 +1.372395E-02 +3.175759E-05 +1.525561E-02 +3.615913E-05 +1.061450E-02 +1.832455E-05 +2.040145E-02 +5.544400E-05 +2.550363E-02 +8.291428E-05 +1.927840E-02 +6.340108E-05 +1.775966E-02 +3.592996E-05 +1.876698E-02 +5.056466E-05 +1.520416E-02 +3.176693E-05 +2.911719E-02 +1.110393E-04 +2.789335E-02 +1.015992E-04 +2.154244E-02 +6.800841E-05 +2.176042E-02 +6.210896E-05 +2.465235E-02 +8.769146E-05 +2.163089E-02 +6.884278E-05 +4.263944E-02 +2.012458E-04 +3.780523E-02 +1.771907E-04 +3.718152E-02 +1.480234E-04 +3.477776E-02 +1.409494E-04 +3.400758E-02 +1.358091E-04 +2.463564E-02 +6.885284E-05 +3.580510E-02 +1.389221E-04 +2.581734E-02 +7.795599E-05 +4.453340E-02 +2.222774E-04 +3.924298E-02 +2.048002E-04 +2.186414E-02 +7.503195E-05 +2.414346E-02 +6.884988E-05 +4.920381E-02 +2.986041E-04 +4.271226E-02 +2.407998E-04 +3.511456E-02 +1.659456E-04 +3.959546E-02 +1.811704E-04 +4.332790E-02 +2.327770E-04 +3.005794E-02 +1.236765E-04 +4.201285E-02 +1.831068E-04 +3.539806E-02 +1.349359E-04 +4.860033E-02 +2.640914E-04 +3.738028E-02 +1.608258E-04 +3.344288E-02 +1.192143E-04 +3.329781E-02 +1.262633E-04 +5.050402E-02 +3.082255E-04 +6.167912E-02 +4.537041E-04 +4.061325E-02 +2.373203E-04 +4.113180E-02 +2.244264E-04 +4.273661E-02 +2.061457E-04 +3.909923E-02 +1.794019E-04 +4.467948E-02 +2.422984E-04 +3.644554E-02 +1.488516E-04 +6.208616E-02 +4.066650E-04 +5.622731E-02 +3.479864E-04 +3.604649E-02 +1.527817E-04 +4.489847E-02 +2.244948E-04 +4.852333E-02 +2.452380E-04 +5.916579E-02 +3.675786E-04 +5.027889E-02 +3.063063E-04 +5.223329E-02 +3.266355E-04 +5.303921E-02 +3.002831E-04 +4.084190E-02 +2.089059E-04 +4.269058E-02 +1.927344E-04 +4.181196E-02 +1.890866E-04 +4.239920E-02 +2.054052E-04 +4.178606E-02 +2.121443E-04 +3.962721E-02 +1.900681E-04 +3.998106E-02 +1.671101E-04 +4.097110E-02 +1.864628E-04 +5.252376E-02 +2.919653E-04 +4.986589E-02 +2.923184E-04 +4.281919E-02 +2.017141E-04 +5.707825E-02 +3.443945E-04 +4.193701E-02 +1.801946E-04 +3.890873E-02 +1.604416E-04 +2.771300E-02 +8.201460E-05 +4.516255E-02 +2.288159E-04 +3.504308E-02 +1.480297E-04 +3.354671E-02 +1.345202E-04 +4.155997E-02 +1.900709E-04 +2.311887E-02 +6.056166E-05 +4.403743E-02 +2.374715E-04 +1.996468E-02 +5.260666E-05 +3.196737E-02 +1.421833E-04 +4.035771E-02 +1.965928E-04 +3.317174E-02 +1.529423E-04 +2.357781E-02 +6.449390E-05 +2.467934E-02 +6.935734E-05 +4.424222E-02 +2.197069E-04 +3.398377E-02 +1.404692E-04 +2.969392E-02 +9.932175E-05 +2.586642E-02 +8.639774E-05 +2.018938E-02 +4.704545E-05 +2.460053E-02 +8.337921E-05 +2.140944E-02 +5.566819E-05 +1.750162E-02 +4.330128E-05 +1.823667E-02 +3.807392E-05 +2.182322E-02 +5.835666E-05 +1.996510E-02 +4.925786E-05 +2.054306E-02 +5.967285E-05 +2.448060E-02 +6.724552E-05 +2.420255E-02 +7.171101E-05 +2.224533E-02 +7.074407E-05 +2.688010E-02 +1.048025E-04 +1.252593E-02 +1.992438E-05 +1.627058E-02 +3.557197E-05 +1.458375E-02 +2.939085E-05 +6.673846E-03 +7.665690E-06 +1.782098E-02 +4.530371E-05 +1.873366E-02 +5.530746E-05 +1.014089E-02 +1.628821E-05 +9.132953E-03 +1.379610E-05 +1.363905E-02 +2.661815E-05 +1.338513E-02 +2.253429E-05 +8.423240E-03 +1.911938E-05 +1.484012E-02 +4.135636E-05 +1.418073E-02 +3.323365E-05 +1.543051E-02 +2.985655E-05 +1.632770E-02 +3.517623E-05 +2.008031E-02 +5.274018E-05 +1.602450E-02 +3.958879E-05 +1.750372E-02 +3.314152E-05 +1.219742E-02 +2.258004E-05 +1.433533E-02 +3.618336E-05 +9.075804E-03 +1.317139E-05 +7.380199E-03 +7.236358E-06 +1.782556E-02 +3.957064E-05 +1.184192E-02 +2.021154E-05 +2.859581E-02 +1.054928E-04 +2.697349E-02 +9.676496E-05 +2.792217E-02 +1.147611E-04 +1.382301E-02 +2.417383E-05 +2.411827E-02 +7.056685E-05 +1.982700E-02 +4.766108E-05 +2.818071E-02 +9.359800E-05 +2.219449E-02 +6.075282E-05 +2.314416E-02 +6.478789E-05 +2.443285E-02 +8.381567E-05 +2.019536E-02 +5.428133E-05 +1.353132E-02 +2.740754E-05 +4.406952E-02 +2.190081E-04 +3.446584E-02 +1.346151E-04 +3.753184E-02 +1.527576E-04 +3.033111E-02 +1.034049E-04 +2.855894E-02 +9.711291E-05 +2.771557E-02 +8.771393E-05 +3.898957E-02 +1.908877E-04 +4.305288E-02 +1.970134E-04 +3.486097E-02 +1.545961E-04 +3.499273E-02 +1.436152E-04 +3.110132E-02 +1.127757E-04 +3.008751E-02 +1.139676E-04 +6.319815E-02 +4.327893E-04 +5.504272E-02 +3.344552E-04 +4.591545E-02 +2.365710E-04 +3.617316E-02 +1.560924E-04 +5.218885E-02 +3.077972E-04 +4.686114E-02 +2.529342E-04 +5.728060E-02 +4.031273E-04 +3.978176E-02 +1.860198E-04 +5.004767E-02 +3.136544E-04 +4.523333E-02 +2.208929E-04 +3.194586E-02 +1.141458E-04 +3.721301E-02 +1.553134E-04 +7.477681E-02 +6.639195E-04 +6.780397E-02 +4.776195E-04 +6.358469E-02 +4.696106E-04 +6.032980E-02 +4.286567E-04 +5.153943E-02 +2.983568E-04 +5.818770E-02 +4.058262E-04 +6.750249E-02 +5.176461E-04 +5.373447E-02 +3.160363E-04 +6.782408E-02 +5.197564E-04 +5.101341E-02 +3.150794E-04 +3.969145E-02 +1.890305E-04 +4.675755E-02 +2.829176E-04 +4.899174E-02 +2.593746E-04 +7.529462E-02 +5.829369E-04 +5.523513E-02 +3.275402E-04 +3.691494E-02 +1.532620E-04 +6.863824E-02 +5.261979E-04 +5.665568E-02 +3.399426E-04 +5.021140E-02 +2.920406E-04 +5.159035E-02 +3.147743E-04 +8.420431E-02 +7.633948E-04 +6.502238E-02 +5.063282E-04 +4.930238E-02 +2.812855E-04 +4.815381E-02 +2.482742E-04 +4.967200E-02 +2.680540E-04 +5.523567E-02 +3.370328E-04 +4.300524E-02 +2.081672E-04 +3.836521E-02 +1.711214E-04 +5.253824E-02 +3.333353E-04 +4.027059E-02 +1.822925E-04 +3.645004E-02 +1.495178E-04 +3.990377E-02 +1.790132E-04 +4.399597E-02 +2.136921E-04 +4.313937E-02 +2.093007E-04 +3.431599E-02 +1.398795E-04 +4.051219E-02 +1.961233E-04 +4.595652E-02 +2.564444E-04 +3.332030E-02 +1.206481E-04 +4.197497E-02 +2.029057E-04 +3.566567E-02 +1.599693E-04 +3.563813E-02 +1.390992E-04 +3.428900E-02 +1.439048E-04 +3.548443E-02 +1.582734E-04 +3.147837E-02 +1.431168E-04 +3.473859E-02 +1.320531E-04 +3.340003E-02 +1.534631E-04 +2.995214E-02 +1.115961E-04 +3.783601E-02 +1.612451E-04 +2.593349E-02 +7.511302E-05 +2.220229E-02 +5.650585E-05 +2.396506E-02 +6.330344E-05 +2.415591E-02 +7.979178E-05 +3.230518E-02 +1.226469E-04 +3.148292E-02 +1.291525E-04 +2.555369E-02 +7.214626E-05 +2.008785E-02 +5.277321E-05 +2.623915E-02 +1.052699E-04 +1.687230E-02 +3.802212E-05 +1.828669E-02 +5.222647E-05 +2.568728E-02 +1.046345E-04 +1.666034E-02 +3.189735E-05 +1.441649E-02 +2.909234E-05 +1.961081E-02 +5.252583E-05 +1.446604E-02 +2.906063E-05 +2.499966E-02 +7.290861E-05 +2.036936E-02 +5.610925E-05 +9.247556E-03 +1.678837E-05 +1.093088E-02 +2.167681E-05 +1.260502E-02 +2.987668E-05 +9.613002E-03 +1.269981E-05 +1.504319E-02 +4.123453E-05 +1.804155E-02 +4.790967E-05 +1.950375E-02 +5.823817E-05 +1.292954E-02 +2.425508E-05 +9.979565E-03 +1.879915E-05 +1.627001E-02 +4.007960E-05 +1.727217E-02 +3.779588E-05 +1.821599E-02 +4.516560E-05 +1.246029E-02 +2.877178E-05 +7.419932E-03 +1.075442E-05 +1.027139E-02 +1.750906E-05 +6.011548E-03 +5.357981E-06 +1.284150E-02 +2.684216E-05 +7.873217E-03 +1.261811E-05 +3.056254E-02 +1.119101E-04 +2.367459E-02 +7.012832E-05 +3.125473E-02 +1.349511E-04 +2.032722E-02 +6.005633E-05 +1.966372E-02 +4.807430E-05 +1.888280E-02 +4.353141E-05 +3.148229E-02 +1.087028E-04 +2.569052E-02 +8.345601E-05 +1.988235E-02 +5.083043E-05 +3.033509E-02 +1.353984E-04 +2.455111E-02 +8.578087E-05 +2.292969E-02 +6.706042E-05 +3.506638E-02 +1.418820E-04 +2.811805E-02 +8.950254E-05 +3.758364E-02 +1.763474E-04 +4.852969E-02 +3.045767E-04 +3.345491E-02 +1.265446E-04 +3.311976E-02 +1.271997E-04 +4.406586E-02 +2.049053E-04 +3.977663E-02 +1.944792E-04 +3.568273E-02 +1.393831E-04 +4.714003E-02 +2.666571E-04 +3.938142E-02 +1.784684E-04 +3.504464E-02 +1.619498E-04 +6.038764E-02 +4.057914E-04 +5.523867E-02 +3.480079E-04 +5.012020E-02 +2.738532E-04 +5.300843E-02 +3.225930E-04 +4.819845E-02 +2.912996E-04 +4.192723E-02 +2.042929E-04 +5.437230E-02 +3.831173E-04 +4.855340E-02 +2.801897E-04 +5.632430E-02 +3.684549E-04 +3.908351E-02 +1.754220E-04 +3.723203E-02 +1.565670E-04 +3.662475E-02 +1.409549E-04 +7.828360E-02 +6.808841E-04 +6.139852E-02 +4.032303E-04 +6.455776E-02 +4.632098E-04 +4.996191E-02 +2.795507E-04 +5.586957E-02 +3.475409E-04 +4.296598E-02 +2.317524E-04 +6.386330E-02 +4.717762E-04 +5.291090E-02 +3.247736E-04 +5.483498E-02 +3.421555E-04 +4.502506E-02 +2.409819E-04 +5.510776E-02 +3.436300E-04 +4.165980E-02 +1.924264E-04 +5.979906E-02 +3.843900E-04 +5.815532E-02 +3.901796E-04 +6.144432E-02 +4.159903E-04 +5.918684E-02 +3.926095E-04 +7.241076E-02 +5.527725E-04 +5.729097E-02 +3.531500E-04 +5.051843E-02 +2.810907E-04 +5.618582E-02 +3.776148E-04 +5.589932E-02 +3.335647E-04 +6.161520E-02 +4.831295E-04 +5.389348E-02 +3.065669E-04 +4.348189E-02 +2.135964E-04 +4.695822E-02 +2.384098E-04 +6.006602E-02 +3.844395E-04 +4.864361E-02 +2.423012E-04 +4.186798E-02 +1.902022E-04 +4.797983E-02 +2.448734E-04 +4.768596E-02 +2.637688E-04 +4.383760E-02 +2.023880E-04 +3.729270E-02 +2.011170E-04 +4.671060E-02 +2.774443E-04 +4.261256E-02 +2.074667E-04 +3.057615E-02 +1.013174E-04 +3.642349E-02 +1.538488E-04 +2.640419E-02 +8.839937E-05 +5.298488E-02 +3.147305E-04 +2.462926E-02 +7.609382E-05 +3.274348E-02 +1.347060E-04 +4.085845E-02 +2.061636E-04 +3.613681E-02 +1.608827E-04 +3.188424E-02 +1.170448E-04 +3.090210E-02 +1.209556E-04 +4.916591E-02 +2.638816E-04 +3.463680E-02 +1.731202E-04 +2.473796E-02 +8.278777E-05 +2.876733E-02 +1.050578E-04 +2.818020E-02 +9.186488E-05 +2.922451E-02 +9.710630E-05 +2.867494E-02 +1.008386E-04 +2.048136E-02 +5.645393E-05 +2.709023E-02 +9.906565E-05 +2.060958E-02 +6.002022E-05 +2.400813E-02 +7.048793E-05 +2.041445E-02 +5.660380E-05 +3.022382E-02 +1.232007E-04 +2.428404E-02 +7.261848E-05 +1.317267E-02 +4.498520E-05 +1.725417E-02 +4.131436E-05 +1.439809E-02 +2.877223E-05 +1.849952E-02 +3.964099E-05 +1.298598E-02 +2.510194E-05 +1.158199E-02 +1.753824E-05 +2.399736E-02 +7.914398E-05 +1.618716E-02 +3.923219E-05 +1.582299E-02 +3.446241E-05 +1.281460E-02 +2.948723E-05 +1.687823E-02 +3.916635E-05 +1.992356E-02 +5.363759E-05 +9.964687E-03 +2.281351E-05 +9.741073E-03 +1.461704E-05 +1.016266E-02 +1.578045E-05 +1.165241E-02 +1.448412E-05 +1.645559E-02 +3.314741E-05 +1.019874E-02 +1.584348E-05 +1.400560E-02 +2.950132E-05 +1.339261E-02 +2.462337E-05 +9.864617E-03 +2.007031E-05 +1.033312E-02 +1.570664E-05 +1.150186E-02 +1.612123E-05 +8.165735E-03 +9.980334E-06 +1.039922E-02 +2.137334E-05 +7.778314E-03 +1.402972E-05 +2.352819E-02 +7.324745E-05 +1.832670E-02 +5.260061E-05 +1.958916E-02 +4.738463E-05 +2.752632E-02 +1.321234E-04 +1.290240E-02 +2.435598E-05 +1.180814E-02 +1.989960E-05 +1.968230E-02 +4.672576E-05 +2.074128E-02 +5.154692E-05 +1.506303E-02 +2.974396E-05 +2.158432E-02 +6.994225E-05 +2.106432E-02 +6.601892E-05 +1.297999E-02 +2.683746E-05 +4.398209E-02 +2.260240E-04 +3.493420E-02 +1.634600E-04 +3.877993E-02 +1.929775E-04 +2.663088E-02 +8.262555E-05 +2.385591E-02 +7.188146E-05 +2.756789E-02 +8.724472E-05 +4.223824E-02 +2.331366E-04 +3.372408E-02 +1.376633E-04 +2.877054E-02 +1.172152E-04 +2.505284E-02 +6.877934E-05 +2.710121E-02 +9.089126E-05 +2.491989E-02 +7.126133E-05 +4.605415E-02 +2.550818E-04 +3.674502E-02 +1.551214E-04 +3.682502E-02 +1.637234E-04 +4.294065E-02 +2.131753E-04 +3.770825E-02 +1.835164E-04 +3.445084E-02 +1.375944E-04 +3.954845E-02 +1.848016E-04 +4.320951E-02 +2.332661E-04 +2.976462E-02 +1.143727E-04 +3.263580E-02 +1.287108E-04 +4.185045E-02 +1.965114E-04 +3.879064E-02 +1.631517E-04 +6.117745E-02 +4.170051E-04 +5.208900E-02 +2.961117E-04 +5.034441E-02 +2.985461E-04 +4.763203E-02 +2.520770E-04 +4.424593E-02 +2.210065E-04 +4.633482E-02 +2.857246E-04 +6.172917E-02 +4.365884E-04 +4.667374E-02 +2.416468E-04 +4.615839E-02 +2.447158E-04 +4.202865E-02 +1.984881E-04 +3.687271E-02 +1.549029E-04 +3.781817E-02 +1.658791E-04 +5.350156E-02 +3.106556E-04 +5.738403E-02 +3.535711E-04 +5.581047E-02 +3.600168E-04 +5.548481E-02 +3.477589E-04 +5.976117E-02 +4.066921E-04 +3.679728E-02 +1.797632E-04 +4.181607E-02 +2.319380E-04 +4.475783E-02 +2.471295E-04 +5.073065E-02 +2.731166E-04 +4.282973E-02 +2.376864E-04 +3.923270E-02 +1.868782E-04 +3.175293E-02 +1.204289E-04 +3.821514E-02 +1.563696E-04 +4.698886E-02 +2.394623E-04 +4.501447E-02 +2.402396E-04 +3.789686E-02 +1.636683E-04 +4.356985E-02 +2.501184E-04 +3.738072E-02 +1.625968E-04 +3.207025E-02 +1.387594E-04 +3.204040E-02 +1.219128E-04 +4.516239E-02 +2.412503E-04 +4.133319E-02 +1.807484E-04 +2.760180E-02 +8.957336E-05 +4.274635E-02 +2.203768E-04 +3.183938E-02 +1.177784E-04 +3.431517E-02 +1.538918E-04 +3.335945E-02 +1.452163E-04 +3.036081E-02 +1.173248E-04 +3.231608E-02 +1.473817E-04 +3.026666E-02 +1.062646E-04 +2.381248E-02 +6.812346E-05 +2.438669E-02 +7.616674E-05 +2.657091E-02 +8.997086E-05 +2.155185E-02 +7.092421E-05 +2.241945E-02 +5.990905E-05 +3.070897E-02 +1.109960E-04 +2.580881E-02 +7.863309E-05 +2.134721E-02 +6.345767E-05 +3.007460E-02 +1.199346E-04 +2.158487E-02 +5.631137E-05 +2.267038E-02 +6.523479E-05 +2.199756E-02 +6.744627E-05 +1.920160E-02 +4.676740E-05 +1.927293E-02 +5.882526E-05 +1.309800E-02 +2.176798E-05 +1.864318E-02 +4.222760E-05 +2.427004E-02 +7.787837E-05 +2.143559E-02 +5.842615E-05 +1.187245E-02 +3.400806E-05 +1.386855E-02 +2.215090E-05 +1.089761E-02 +1.742663E-05 +1.054008E-02 +1.719743E-05 +1.573092E-02 +2.947697E-05 +1.260841E-02 +2.538616E-05 +9.335769E-03 +1.220699E-05 +9.218607E-03 +1.346226E-05 +1.232919E-02 +2.739036E-05 +1.540769E-02 +3.545632E-05 +1.047417E-02 +1.403218E-05 +8.091074E-03 +9.942405E-06 +9.757397E-03 +1.839030E-05 +1.147311E-02 +2.272680E-05 +6.625367E-03 +9.542469E-06 +1.132951E-02 +2.290402E-05 +1.276799E-02 +2.736073E-05 +1.641171E-02 +4.522620E-05 +1.038484E-02 +2.444781E-05 +1.059856E-02 +2.086366E-05 +1.070727E-02 +3.120073E-05 +9.434079E-03 +2.288235E-05 +1.260589E-02 +2.115523E-05 +8.609571E-03 +1.014235E-05 +1.906718E-02 +4.342750E-05 +1.697807E-02 +3.746587E-05 +1.655549E-02 +3.279717E-05 +2.335945E-02 +8.680066E-05 +1.947075E-02 +4.582833E-05 +2.334564E-02 +6.827484E-05 +1.970475E-02 +5.161446E-05 +2.176597E-02 +8.091171E-05 +1.794831E-02 +4.826888E-05 +1.453865E-02 +2.543285E-05 +2.285340E-02 +7.733631E-05 +1.495227E-02 +3.812970E-05 +2.993202E-02 +1.105328E-04 +2.591986E-02 +7.889731E-05 +2.891690E-02 +1.170195E-04 +2.591958E-02 +8.245187E-05 +2.472591E-02 +6.792489E-05 +1.984583E-02 +4.399055E-05 +2.723781E-02 +1.063286E-04 +2.214049E-02 +6.647832E-05 +1.976025E-02 +4.630788E-05 +2.362519E-02 +9.840049E-05 +2.147637E-02 +5.680267E-05 +1.716604E-02 +3.707514E-05 +3.853916E-02 +1.905886E-04 +3.220009E-02 +1.166545E-04 +3.072451E-02 +1.105417E-04 +3.416322E-02 +1.445852E-04 +3.081335E-02 +1.205464E-04 +2.381824E-02 +7.421006E-05 +2.919176E-02 +1.443329E-04 +3.165320E-02 +1.643449E-04 +2.399334E-02 +7.031311E-05 +2.931290E-02 +1.089751E-04 +2.541529E-02 +9.960904E-05 +2.496511E-02 +9.522684E-05 +4.191717E-02 +2.319644E-04 +4.194175E-02 +2.515421E-04 +4.029489E-02 +2.034800E-04 +2.949880E-02 +1.001309E-04 +3.311240E-02 +2.069653E-04 +3.311074E-02 +1.645850E-04 +2.609443E-02 +7.829184E-05 +2.523310E-02 +7.753633E-05 +3.376196E-02 +1.542562E-04 +3.370657E-02 +1.584460E-04 +2.316126E-02 +6.322560E-05 +2.849745E-02 +1.006036E-04 +4.156928E-02 +1.941410E-04 +3.356649E-02 +1.323048E-04 +3.504110E-02 +1.432793E-04 +4.188246E-02 +2.087133E-04 +2.686062E-02 +1.008920E-04 +3.264472E-02 +1.519956E-04 +3.182824E-02 +1.190821E-04 +3.230472E-02 +1.432567E-04 +3.014385E-02 +1.104329E-04 +3.127630E-02 +1.124605E-04 +3.215046E-02 +1.161615E-04 +3.028866E-02 +1.020886E-04 +3.771125E-02 +1.568073E-04 +3.370873E-02 +1.337798E-04 +4.025498E-02 +1.918052E-04 +2.635483E-02 +7.350768E-05 +2.361243E-02 +7.420144E-05 +3.747673E-02 +2.016310E-04 +2.747199E-02 +8.499093E-05 +3.168249E-02 +1.354519E-04 +2.123972E-02 +5.349966E-05 +2.029422E-02 +4.819609E-05 +2.757353E-02 +9.520625E-05 +3.241854E-02 +1.263115E-04 +2.339411E-02 +8.048390E-05 +2.881367E-02 +9.755501E-05 +2.959500E-02 +1.180648E-04 +2.255464E-02 +6.753101E-05 +4.047075E-02 +1.783640E-04 +3.116618E-02 +1.271595E-04 +2.360487E-02 +7.555159E-05 +2.020519E-02 +5.400702E-05 +2.646647E-02 +7.518930E-05 +2.547209E-02 +9.058727E-05 +1.278101E-02 +2.432873E-05 +2.394671E-02 +7.236070E-05 +1.399890E-02 +2.909745E-05 +1.693268E-02 +4.013852E-05 +1.661474E-02 +3.646989E-05 +1.683699E-02 +3.576439E-05 +1.878683E-02 +4.752490E-05 +1.779186E-02 +5.032257E-05 +1.615460E-02 +3.517429E-05 +1.467092E-02 +2.974604E-05 +1.693919E-02 +3.956534E-05 +1.570365E-02 +3.373372E-05 +1.503755E-02 +3.242993E-05 +1.350241E-02 +2.471502E-05 +1.132128E-02 +2.210554E-05 +1.394835E-02 +2.288474E-05 +7.707010E-03 +1.408651E-05 +1.105673E-02 +1.950348E-05 +1.597153E-02 +2.996363E-05 +1.072279E-02 +1.642956E-05 +9.931403E-03 +1.596209E-05 +3.110131E-03 +1.979116E-06 +1.465778E-02 +2.665954E-05 +8.711776E-03 +1.658595E-05 +3.336279E-03 +3.121041E-06 +1.220546E-02 +2.078425E-05 +1.225808E-02 +2.498648E-05 +5.941201E-03 +5.858248E-06 +8.017505E-03 +9.987361E-06 +1.032012E-02 +1.689346E-05 +1.122116E-02 +2.547015E-05 +7.303253E-03 +1.021165E-05 +1.018508E-02 +1.390217E-05 +6.537846E-03 +1.231905E-05 +3.757225E-03 +2.146236E-06 +6.253529E-03 +8.259456E-06 +8.429652E-03 +1.132331E-05 +6.846152E-03 +1.089548E-05 +1.540905E-02 +4.707146E-05 +1.380105E-02 +2.885252E-05 +1.506988E-02 +3.657193E-05 +1.379370E-02 +2.325176E-05 +9.540645E-03 +2.912938E-05 +1.053361E-02 +1.745746E-05 +8.796644E-03 +1.302715E-05 +9.798877E-03 +1.776907E-05 +1.287457E-02 +2.307421E-05 +1.194402E-02 +2.276268E-05 +7.875525E-03 +1.292927E-05 +5.533880E-03 +9.384723E-06 +1.864321E-02 +4.177596E-05 +1.252461E-02 +2.176958E-05 +1.644030E-02 +4.131255E-05 +1.697179E-02 +3.953043E-05 +9.140492E-03 +1.319242E-05 +9.958402E-03 +1.459665E-05 +1.425287E-02 +3.897232E-05 +1.522358E-02 +3.028879E-05 +1.361118E-02 +2.815573E-05 +1.173677E-02 +3.088583E-05 +1.617474E-02 +3.012921E-05 +1.598127E-02 +3.641752E-05 +1.724536E-02 +3.982285E-05 +2.253691E-02 +6.632574E-05 +2.268227E-02 +5.893945E-05 +2.582333E-02 +9.202078E-05 +1.982485E-02 +6.093449E-05 +1.544437E-02 +3.045457E-05 +1.968776E-02 +5.933245E-05 +2.092753E-02 +6.834686E-05 +1.664629E-02 +4.979724E-05 +1.855281E-02 +6.404621E-05 +2.195650E-02 +6.222690E-05 +2.186198E-02 +5.700014E-05 +2.078639E-02 +4.826480E-05 +2.147531E-02 +5.352146E-05 +2.309193E-02 +6.508444E-05 +2.306719E-02 +7.442212E-05 +2.181171E-02 +6.065432E-05 +2.787754E-02 +1.071646E-04 +2.038266E-02 +6.322425E-05 +2.066861E-02 +6.321760E-05 +2.341755E-02 +6.599464E-05 +1.940287E-02 +5.285084E-05 +2.311451E-02 +6.931733E-05 +2.685211E-02 +9.869681E-05 +2.577665E-02 +9.741583E-05 +2.127713E-02 +7.233352E-05 +3.534780E-02 +1.462501E-04 +2.985988E-02 +1.001501E-04 +2.157060E-02 +5.933210E-05 +2.112991E-02 +6.091345E-05 +1.791858E-02 +4.849939E-05 +2.317059E-02 +5.941629E-05 +1.585209E-02 +3.680922E-05 +1.761272E-02 +4.005327E-05 +2.673873E-02 +8.415236E-05 +2.195005E-02 +7.869690E-05 +2.169063E-02 +6.115181E-05 +1.902034E-02 +4.602942E-05 +2.149684E-02 +6.272837E-05 +2.152317E-02 +5.647475E-05 +1.267811E-02 +2.551472E-05 +1.902212E-02 +4.501454E-05 +1.468929E-02 +2.854665E-05 +2.098348E-02 +5.162857E-05 +1.448437E-02 +3.165154E-05 +1.385842E-02 +2.946322E-05 +2.214565E-02 +6.004180E-05 +1.824698E-02 +3.872549E-05 +1.212354E-02 +2.133339E-05 +2.018308E-02 +5.701150E-05 +2.166624E-02 +5.196544E-05 +2.142212E-02 +5.674884E-05 +1.267848E-02 +2.171626E-05 +1.758911E-02 +4.711902E-05 +1.111921E-02 +2.058872E-05 +1.517506E-02 +2.980149E-05 +1.147226E-02 +1.573079E-05 +1.249264E-02 +2.217903E-05 +1.604063E-02 +3.750625E-05 +1.275295E-02 +2.494568E-05 +1.612605E-02 +3.577658E-05 +1.249864E-02 +3.018969E-05 +1.188510E-02 +2.704321E-05 +1.571000E-02 +3.615816E-05 +1.235323E-02 +2.593348E-05 +1.676586E-02 +4.472755E-05 +1.093806E-02 +1.930162E-05 +1.176929E-02 +2.511180E-05 +1.397747E-02 +2.813515E-05 +9.701315E-03 +1.930872E-05 +1.399983E-02 +3.413054E-05 +1.986885E-02 +5.082098E-05 +8.243555E-03 +1.200852E-05 +1.024429E-02 +1.296572E-05 +1.258003E-02 +1.952799E-05 +1.610829E-02 +3.961341E-05 +1.010586E-02 +1.549208E-05 +1.252095E-02 +2.770018E-05 +8.230588E-03 +1.450505E-05 +8.380929E-03 +1.203824E-05 +8.828715E-03 +1.191588E-05 +6.588527E-03 +7.910780E-06 +6.380189E-03 +6.533479E-06 +5.052056E-03 +5.336338E-06 +3.648351E-03 +2.706990E-06 +2.149471E-03 +1.225876E-06 +9.270100E-03 +1.169691E-05 +1.117400E-02 +2.249063E-05 +5.230590E-03 +4.655893E-06 +7.224676E-03 +1.008003E-05 +3.887357E-03 +3.670860E-06 +3.183273E-03 +1.847498E-06 +3.708170E-03 +2.623818E-06 +5.854425E-03 +1.020941E-05 +5.406569E-03 +5.391988E-06 +9.036302E-03 +1.748353E-05 +8.903194E-03 +1.445005E-05 +9.987482E-03 +2.075751E-05 +8.426663E-03 +1.155563E-05 +8.912136E-03 +1.175066E-05 +4.122838E-03 +3.170046E-06 +4.845177E-03 +4.237971E-06 +6.822194E-03 +1.051328E-05 +4.425000E-03 +4.417976E-06 +7.424172E-03 +9.891741E-06 +4.992950E-03 +5.945799E-06 +7.149030E-03 +1.123994E-05 +4.625444E-03 +5.049047E-06 +1.123851E-02 +2.017630E-05 +1.074541E-02 +1.709195E-05 +1.430110E-02 +3.117294E-05 +9.806637E-03 +1.530391E-05 +1.043812E-02 +1.609521E-05 +1.012866E-02 +1.391247E-05 +1.428192E-02 +2.902409E-05 +1.605416E-02 +3.562493E-05 +9.063095E-03 +1.372032E-05 +9.587205E-03 +1.473939E-05 +9.634515E-03 +1.858518E-05 +1.164975E-02 +2.656325E-05 +1.361864E-02 +2.518422E-05 +1.167329E-02 +2.323748E-05 +1.622385E-02 +3.856234E-05 +1.214097E-02 +2.153842E-05 +1.381854E-02 +2.815505E-05 +1.415211E-02 +4.135908E-05 +1.568971E-02 +3.813496E-05 +1.198123E-02 +2.333564E-05 +8.499425E-03 +1.126897E-05 +1.312625E-02 +3.325212E-05 +1.172860E-02 +2.042689E-05 +1.005348E-02 +1.782865E-05 +1.548579E-02 +3.103766E-05 +1.744521E-02 +3.960003E-05 +1.654740E-02 +3.986988E-05 +1.620467E-02 +3.009003E-05 +1.948116E-02 +5.036150E-05 +1.418148E-02 +2.971887E-05 +1.337833E-02 +2.666872E-05 +1.314218E-02 +2.648418E-05 +1.436798E-02 +2.490823E-05 +9.444986E-03 +1.101269E-05 +1.962001E-02 +8.135189E-05 +1.158154E-02 +1.952295E-05 +1.471099E-02 +3.133120E-05 +1.541812E-02 +3.170497E-05 +1.674531E-02 +4.322938E-05 +1.669392E-02 +3.544709E-05 +1.333115E-02 +3.211381E-05 +1.738951E-02 +4.841020E-05 +1.007222E-02 +1.774930E-05 +1.295078E-02 +2.638113E-05 +1.271717E-02 +2.298976E-05 +1.404483E-02 +2.889248E-05 +1.576832E-02 +3.529377E-05 +1.252846E-02 +2.718789E-05 +2.519173E-02 +8.963887E-05 +1.493179E-02 +3.748831E-05 +1.259822E-02 +2.429153E-05 +1.224327E-02 +1.829117E-05 +1.391862E-02 +2.860704E-05 +8.357253E-03 +1.029121E-05 +1.570825E-02 +3.413707E-05 +1.359733E-02 +2.641606E-05 +1.091443E-02 +1.715332E-05 +8.155749E-03 +1.261821E-05 +1.313846E-02 +2.597075E-05 +8.293564E-03 +1.056976E-05 +1.638901E-02 +3.229628E-05 +1.331850E-02 +3.096114E-05 +1.103350E-02 +1.929035E-05 +1.727217E-02 +4.051979E-05 +9.518809E-03 +1.410510E-05 +1.300800E-02 +2.937228E-05 +1.046353E-02 +1.575334E-05 +1.036019E-02 +1.658144E-05 +8.892217E-03 +1.726775E-05 +9.649910E-03 +1.409080E-05 +1.146930E-02 +2.018867E-05 +8.918398E-03 +1.307570E-05 +1.525733E-02 +3.596673E-05 +1.004009E-02 +1.246514E-05 +1.066698E-02 +2.185894E-05 +7.770912E-03 +1.480934E-05 +7.264717E-03 +8.442828E-06 +6.706343E-03 +6.852573E-06 +5.559456E-03 +4.744752E-06 +5.773360E-03 +7.781275E-06 +1.331078E-02 +3.353599E-05 +8.788678E-03 +1.329146E-05 +4.884040E-03 +4.077409E-06 +8.675118E-03 +1.319086E-05 +4.761159E-03 +3.796641E-06 +5.277064E-03 +5.807731E-06 +1.108365E-02 +1.916299E-05 +5.331867E-03 +3.733672E-06 +7.054526E-03 +6.862094E-06 +5.863290E-03 +8.388015E-06 +7.544134E-03 +1.042553E-05 +5.750484E-03 +5.095339E-06 +5.249358E-03 +3.213161E-06 +7.899479E-03 +9.484436E-06 +4.160278E-03 +4.806702E-06 +7.679996E-03 +2.071836E-05 +6.241972E-03 +1.620756E-05 +5.913948E-03 +7.527048E-06 +4.733716E-03 +5.631878E-06 +2.903451E-03 +2.658722E-06 +3.127420E-03 +2.299870E-06 +2.273717E-03 +1.344135E-06 +6.534306E-03 +1.124316E-05 +7.835003E-03 +1.715904E-05 +4.882363E-03 +4.758963E-06 +3.720325E-03 +3.452423E-06 +1.428452E-03 +1.333526E-06 +3.504443E-03 +2.552735E-06 +8.268492E-03 +1.053438E-05 +9.457152E-03 +1.477101E-05 +4.409644E-03 +4.661365E-06 +5.391744E-03 +4.980226E-06 +7.357835E-03 +8.692158E-06 +4.819563E-03 +3.684180E-06 +7.257471E-03 +8.300854E-06 +8.234387E-03 +1.648552E-05 +7.005187E-03 +8.215133E-06 +8.218179E-03 +1.271584E-05 +4.248638E-03 +4.615897E-06 +6.471659E-03 +7.110986E-06 +8.889291E-03 +1.460347E-05 +8.616060E-03 +1.124291E-05 +8.973876E-03 +1.442105E-05 +6.214996E-03 +1.237961E-05 +6.199460E-03 +8.437599E-06 +2.474487E-03 +1.269623E-06 +1.303002E-02 +3.064014E-05 +1.148543E-02 +2.273454E-05 +1.266333E-02 +2.372659E-05 +1.058814E-02 +2.391393E-05 +5.834966E-03 +9.147127E-06 +5.517822E-03 +5.264691E-06 +1.270359E-02 +2.820747E-05 +1.820335E-02 +4.287032E-05 +1.202094E-02 +2.800408E-05 +7.736254E-03 +1.836141E-05 +6.145051E-03 +6.272679E-06 +7.726439E-03 +1.228446E-05 +1.411190E-02 +2.865658E-05 +6.550872E-03 +6.014982E-06 +2.088300E-02 +7.573466E-05 +1.388048E-02 +3.669556E-05 +1.132008E-02 +1.910843E-05 +1.611954E-02 +3.536212E-05 +1.481933E-02 +3.146401E-05 +1.247993E-02 +2.294126E-05 +1.394123E-02 +2.867543E-05 +1.072461E-02 +1.866919E-05 +8.610956E-03 +1.120688E-05 +8.083860E-03 +8.161992E-06 +1.162751E-02 +1.795366E-05 +9.128039E-03 +1.252646E-05 +9.364221E-03 +1.603445E-05 +8.294106E-03 +1.019170E-05 +5.833363E-03 +4.941650E-06 +9.811611E-03 +1.274458E-05 +1.603475E-02 +3.880395E-05 +1.271422E-02 +2.182851E-05 +1.519349E-02 +3.269445E-05 +9.595042E-03 +1.801667E-05 +7.059973E-03 +7.819618E-06 +5.876271E-03 +1.068936E-05 +1.340147E-02 +3.113903E-05 +4.145261E-03 +3.270808E-06 +1.596720E-02 +3.465819E-05 +1.433346E-02 +2.905578E-05 +8.468040E-03 +1.341062E-05 +1.395194E-02 +2.559614E-05 +1.200470E-02 +1.982352E-05 +1.665933E-02 +3.793148E-05 +1.726359E-02 +3.968046E-05 +6.540447E-03 +5.939253E-06 +8.142400E-03 +1.045929E-05 +6.566817E-03 +8.688594E-06 +1.015592E-02 +1.244647E-05 +1.077665E-02 +1.554617E-05 +1.360651E-02 +3.317478E-05 +1.060123E-02 +1.533418E-05 +3.815593E-03 +2.480255E-06 +9.569339E-03 +1.129499E-05 +9.012545E-03 +1.643164E-05 +1.246360E-02 +3.026280E-05 +8.297915E-03 +9.462041E-06 +5.099837E-03 +5.488747E-06 +8.276566E-03 +1.499072E-05 +3.692279E-03 +3.276555E-06 +8.083217E-03 +1.216780E-05 +9.547609E-03 +1.541880E-05 +1.043999E-02 +1.447586E-05 +9.984558E-03 +1.393147E-05 +6.036500E-03 +1.256268E-05 +5.023445E-03 +4.154969E-06 +7.024538E-03 +1.085504E-05 +7.537608E-03 +1.160621E-05 +5.017595E-03 +4.922120E-06 +5.050436E-03 +4.024516E-06 +3.123518E-03 +1.695608E-06 +3.831129E-03 +3.485286E-06 +5.964101E-03 +9.872984E-06 +3.809889E-03 +3.837033E-06 +4.120333E-03 +3.567476E-06 +3.925178E-03 +5.899336E-06 +3.890602E-03 +8.542757E-06 +6.033356E-03 +7.736141E-06 +4.271392E-03 +3.643602E-06 +2.282046E-03 +1.281394E-06 +6.262911E-03 +1.134696E-05 +4.313813E-03 +4.443331E-06 +1.308832E-03 +4.103970E-07 +2.590108E-03 +2.620429E-06 +5.831777E-03 +4.892875E-06 +5.376268E-03 +5.205758E-06 +9.496856E-03 +1.606537E-05 +7.245952E-03 +7.095242E-06 +7.623819E-03 +1.187689E-05 +5.536252E-03 +5.148443E-06 +1.245396E-02 +2.199505E-05 +7.641760E-03 +1.306388E-05 +1.005116E-02 +1.904677E-05 +1.159156E-02 +2.899326E-05 +1.114868E-02 +2.094752E-05 +1.010147E-02 +1.978005E-05 +8.874213E-03 +1.298622E-05 +1.283785E-02 +2.632677E-05 +5.598145E-03 +4.564302E-06 +4.874451E-03 +6.380741E-06 +4.166868E-03 +4.546806E-06 +5.450652E-03 +4.552973E-06 +9.123569E-03 +1.521157E-05 +1.341420E-02 +2.773663E-05 +9.949075E-03 +1.548877E-05 +1.128600E-02 +1.714535E-05 +9.944157E-03 +1.206624E-05 +9.339838E-03 +1.587210E-05 +1.407135E-02 +3.845557E-05 +1.079969E-02 +1.419090E-05 +1.806763E-02 +5.775082E-05 +1.538811E-02 +3.591506E-05 +9.283522E-03 +1.519392E-05 +8.256501E-03 +1.262631E-05 +1.236476E-02 +1.963613E-05 +2.020990E-02 +5.409171E-05 +1.152596E-02 +2.039197E-05 +1.050303E-02 +2.499041E-05 +1.326414E-02 +2.783213E-05 +7.696971E-03 +9.711977E-06 +1.473705E-02 +2.646008E-05 +1.062292E-02 +1.576562E-05 +1.707377E-02 +4.212601E-05 +8.778679E-03 +1.128995E-05 +9.710118E-03 +1.623481E-05 +7.636475E-03 +1.094355E-05 +1.387905E-02 +2.941626E-05 +1.776651E-02 +4.396460E-05 +1.818565E-02 +4.350858E-05 +1.761749E-02 +4.630235E-05 +2.043671E-02 +6.064648E-05 +1.635160E-02 +4.147100E-05 +1.364022E-02 +2.386011E-05 +1.724650E-02 +5.086651E-05 +1.457393E-02 +3.218203E-05 +1.625704E-02 +4.109869E-05 +1.536770E-02 +3.150971E-05 +1.415214E-02 +2.531338E-05 +1.764117E-02 +3.839917E-05 +1.856292E-02 +4.105079E-05 +1.122011E-02 +2.240362E-05 +1.237537E-02 +1.904481E-05 +1.725511E-02 +3.218693E-05 +1.246019E-02 +2.168729E-05 +2.268477E-02 +6.638152E-05 +1.772582E-02 +4.134691E-05 +1.846727E-02 +4.453692E-05 +2.211594E-02 +6.148331E-05 +1.337994E-02 +2.272968E-05 +1.800735E-02 +4.594283E-05 +1.767634E-02 +3.572802E-05 +2.109287E-02 +7.624418E-05 +2.116135E-02 +5.023945E-05 +1.511244E-02 +3.916543E-05 +2.555283E-02 +8.270634E-05 +2.320248E-02 +6.856995E-05 +1.490210E-02 +3.025554E-05 +1.650536E-02 +3.349063E-05 +2.005340E-02 +6.329046E-05 +1.876604E-02 +4.632276E-05 +2.017935E-02 +5.608622E-05 +1.623543E-02 +3.183867E-05 +1.059288E-02 +1.746867E-05 +1.923413E-02 +5.626395E-05 +1.874482E-02 +5.158196E-05 +1.436557E-02 +3.262805E-05 +1.736130E-02 +4.360560E-05 +2.044766E-02 +5.055246E-05 +1.508312E-02 +3.245600E-05 +1.328001E-02 +2.673879E-05 +1.466660E-02 +2.878429E-05 +1.289951E-02 +2.132152E-05 +1.410955E-02 +2.671457E-05 +1.814074E-02 +4.435357E-05 +2.012953E-02 +5.472686E-05 +1.186784E-02 +2.108638E-05 +1.158902E-02 +2.017687E-05 +9.605924E-03 +1.492077E-05 +1.409567E-02 +2.579784E-05 +1.311103E-02 +2.570267E-05 +1.707665E-02 +4.130920E-05 +1.248159E-02 +2.515719E-05 +2.097524E-02 +5.151201E-05 +1.444457E-02 +2.981175E-05 +1.072187E-02 +1.803695E-05 +9.014009E-03 +1.215827E-05 +9.559055E-03 +1.537581E-05 +1.354384E-02 +2.184405E-05 +4.828517E-03 +6.482158E-06 +6.253387E-03 +5.785292E-06 +1.379191E-02 +2.710641E-05 +1.011815E-02 +1.374848E-05 +1.342278E-02 +3.152030E-05 +8.883639E-03 +1.651249E-05 +1.847885E-02 +6.016422E-05 +8.586243E-03 +1.066056E-05 +6.968205E-03 +8.792141E-06 +1.218017E-02 +2.375039E-05 +4.288567E-03 +2.617468E-06 +6.568856E-03 +6.417620E-06 +9.364388E-03 +1.515485E-05 +7.810927E-03 +9.503941E-06 +1.316444E-02 +2.494672E-05 +8.772821E-03 +1.075467E-05 +9.114583E-03 +1.293064E-05 +5.120610E-03 +5.597666E-06 +1.156077E-02 +2.090644E-05 +1.044752E-02 +1.460984E-05 +4.306774E-03 +7.024156E-06 +6.743680E-03 +9.397053E-06 +1.132063E-02 +2.916783E-05 +9.875394E-03 +1.234227E-05 +8.066518E-03 +1.631648E-05 +1.197445E-02 +2.795662E-05 +1.196930E-02 +2.592654E-05 +1.424965E-02 +2.937215E-05 +9.362177E-03 +1.637802E-05 +1.115631E-02 +2.100489E-05 +6.612368E-03 +1.091592E-05 +1.030811E-02 +2.480048E-05 +1.024176E-02 +1.540918E-05 +8.799976E-03 +1.413045E-05 +1.817266E-02 +5.223457E-05 +1.320418E-02 +2.287606E-05 +1.190482E-02 +2.042598E-05 +1.296875E-02 +2.780267E-05 +1.250433E-02 +2.092242E-05 +1.114237E-02 +1.800945E-05 +1.312112E-02 +2.394975E-05 +1.206217E-02 +2.206129E-05 +1.913237E-02 +5.391475E-05 +2.015987E-02 +4.368668E-05 +1.126423E-02 +1.875823E-05 +1.360231E-02 +2.402648E-05 +1.853506E-02 +4.518491E-05 +1.582011E-02 +3.202477E-05 +1.750058E-02 +4.932715E-05 +1.849790E-02 +5.325631E-05 +2.129000E-02 +5.323882E-05 +1.294333E-02 +2.153410E-05 +2.386151E-02 +7.053393E-05 +2.237759E-02 +6.198345E-05 +1.402168E-02 +3.040550E-05 +2.166707E-02 +7.200843E-05 +1.815377E-02 +4.704586E-05 +2.159074E-02 +9.800484E-05 +2.096789E-02 +5.417603E-05 +2.036776E-02 +5.114163E-05 +1.950805E-02 +5.196224E-05 +1.203115E-02 +2.466652E-05 +2.375017E-02 +7.101139E-05 +2.078435E-02 +4.980028E-05 +1.967736E-02 +5.349609E-05 +1.492202E-02 +3.151061E-05 +2.448505E-02 +7.345642E-05 +2.875745E-02 +9.624049E-05 +1.308936E-02 +2.260928E-05 +1.883770E-02 +5.294121E-05 +2.132133E-02 +6.019067E-05 +2.681408E-02 +8.810170E-05 +1.857403E-02 +3.926673E-05 +1.774032E-02 +4.025585E-05 +2.588771E-02 +8.059759E-05 +2.050194E-02 +4.648784E-05 +2.612192E-02 +8.558295E-05 +1.686319E-02 +3.786866E-05 +2.745753E-02 +9.703052E-05 +2.602614E-02 +7.340705E-05 +2.099702E-02 +6.252305E-05 +2.411550E-02 +6.674417E-05 +2.570206E-02 +6.917677E-05 +2.753425E-02 +1.088979E-04 +2.289782E-02 +6.832742E-05 +1.728790E-02 +4.390010E-05 +2.345865E-02 +7.335296E-05 +1.670224E-02 +4.918814E-05 +2.958698E-02 +1.008389E-04 +2.262155E-02 +8.019776E-05 +2.171260E-02 +5.857256E-05 +2.739550E-02 +9.699654E-05 +1.898108E-02 +5.073772E-05 +2.158139E-02 +5.640212E-05 +2.653056E-02 +9.005949E-05 +2.557757E-02 +8.651930E-05 +1.719263E-02 +3.746877E-05 +1.270461E-02 +2.702019E-05 +2.371990E-02 +6.567867E-05 +2.133774E-02 +5.624387E-05 +2.412439E-02 +8.327847E-05 +2.144516E-02 +5.810134E-05 +2.096771E-02 +5.764847E-05 +2.010218E-02 +6.106688E-05 +2.662466E-02 +1.031716E-04 +2.128503E-02 +6.330504E-05 +2.077576E-02 +5.659759E-05 +1.910625E-02 +4.810183E-05 +1.994507E-02 +5.522830E-05 +1.318359E-02 +2.202071E-05 +1.847673E-02 +3.890771E-05 +1.525363E-02 +3.383373E-05 +2.323360E-02 +7.009641E-05 +2.160465E-02 +6.270896E-05 +2.815837E-02 +9.926554E-05 +2.825700E-02 +1.156243E-04 +1.661438E-02 +3.352935E-05 +1.707558E-02 +4.079662E-05 +1.663970E-02 +5.171770E-05 +1.537161E-02 +3.951696E-05 +1.515887E-02 +2.815234E-05 +1.262479E-02 +2.666049E-05 +2.270831E-02 +7.402779E-05 +1.637425E-02 +3.359896E-05 +1.433044E-02 +3.016015E-05 +1.086052E-02 +2.105095E-05 +1.827948E-02 +5.404440E-05 +1.512356E-02 +4.090325E-05 +1.341869E-02 +3.777277E-05 +1.144273E-02 +2.320403E-05 +1.032338E-02 +2.111004E-05 +1.324432E-02 +2.369582E-05 +1.323267E-02 +2.312589E-05 +7.378365E-03 +1.207116E-05 +1.198900E-02 +2.410816E-05 +1.143776E-02 +1.697429E-05 +5.960596E-03 +5.491388E-06 +8.671020E-03 +1.423578E-05 +1.046649E-02 +1.660152E-05 +1.015412E-02 +1.356611E-05 +4.437919E-03 +4.449282E-06 +8.070532E-03 +1.158768E-05 +1.339134E-02 +2.307637E-05 +1.588497E-02 +3.768975E-05 +9.869781E-03 +2.027492E-05 +1.346984E-02 +2.839713E-05 +1.481565E-02 +2.641963E-05 +1.622974E-02 +3.155688E-05 +1.228654E-02 +2.276535E-05 +9.854382E-03 +2.229720E-05 +8.655941E-03 +1.144096E-05 +8.579998E-03 +1.286624E-05 +1.701319E-02 +3.924030E-05 +9.817319E-03 +1.540490E-05 +2.169451E-02 +7.317248E-05 +2.105716E-02 +5.189702E-05 +1.963335E-02 +5.619116E-05 +2.183187E-02 +6.185293E-05 +1.721212E-02 +3.966296E-05 +1.657518E-02 +3.547912E-05 +1.888518E-02 +5.599282E-05 +1.856419E-02 +5.261571E-05 +2.022215E-02 +6.235701E-05 +1.750049E-02 +3.437263E-05 +2.144519E-02 +5.816976E-05 +1.487741E-02 +2.693460E-05 +1.556861E-02 +3.808581E-05 +2.287702E-02 +6.471426E-05 +1.502995E-02 +3.547384E-05 +2.333943E-02 +7.259310E-05 +1.682037E-02 +3.512266E-05 +1.559563E-02 +3.813310E-05 +2.534274E-02 +7.364335E-05 +2.480122E-02 +7.936460E-05 +1.877264E-02 +4.302495E-05 +2.255108E-02 +6.304951E-05 +1.327871E-02 +2.341276E-05 +1.978158E-02 +5.064958E-05 +2.719711E-02 +8.697999E-05 +3.450441E-02 +1.360084E-04 +2.418992E-02 +8.130715E-05 +2.755861E-02 +9.435699E-05 +2.906789E-02 +1.164895E-04 +2.492886E-02 +9.051357E-05 +2.149004E-02 +5.322652E-05 +1.882200E-02 +4.828092E-05 +3.559788E-02 +1.520518E-04 +2.750436E-02 +8.574229E-05 +2.225856E-02 +5.803244E-05 +2.338675E-02 +7.020780E-05 +3.715161E-02 +1.672352E-04 +2.832183E-02 +9.613959E-05 +3.620891E-02 +1.820751E-04 +1.842315E-02 +4.292893E-05 +3.073714E-02 +1.167359E-04 +2.239778E-02 +6.910113E-05 +3.816869E-02 +1.838537E-04 +3.039700E-02 +1.010395E-04 +2.746450E-02 +9.520787E-05 +2.678376E-02 +8.958685E-05 +1.959265E-02 +4.827447E-05 +2.161190E-02 +5.224194E-05 +2.866820E-02 +9.300929E-05 +3.051657E-02 +1.108463E-04 +2.779434E-02 +9.578374E-05 +2.381065E-02 +7.364073E-05 +3.580671E-02 +1.702522E-04 +3.245610E-02 +1.420184E-04 +3.074561E-02 +1.162297E-04 +2.368174E-02 +7.463994E-05 +3.053229E-02 +1.165041E-04 +2.791292E-02 +9.751321E-05 +1.851477E-02 +4.170606E-05 +2.647316E-02 +8.255669E-05 +2.688714E-02 +9.392494E-05 +3.140666E-02 +1.096021E-04 +2.467545E-02 +7.718465E-05 +1.941157E-02 +5.524811E-05 +3.374306E-02 +1.292663E-04 +2.025089E-02 +5.179623E-05 +2.535741E-02 +7.702579E-05 +2.469316E-02 +7.765177E-05 +2.952585E-02 +9.607704E-05 +2.637948E-02 +7.897857E-05 +2.244297E-02 +6.198303E-05 +2.299365E-02 +6.928750E-05 +2.384571E-02 +7.218845E-05 +3.265249E-02 +1.473318E-04 +2.949982E-02 +1.044208E-04 +2.330464E-02 +7.007243E-05 +1.937666E-02 +4.990461E-05 +1.836576E-02 +3.977508E-05 +2.200706E-02 +5.431158E-05 +1.760216E-02 +3.954597E-05 +2.161653E-02 +5.051231E-05 +2.685593E-02 +8.262522E-05 +2.031027E-02 +5.469024E-05 +1.729977E-02 +3.470083E-05 +2.245610E-02 +6.463192E-05 +2.480332E-02 +6.706820E-05 +1.636383E-02 +3.512895E-05 +1.629117E-02 +3.227987E-05 +1.777456E-02 +3.877314E-05 +1.523888E-02 +2.794713E-05 +1.933720E-02 +5.130630E-05 +2.073569E-02 +5.667785E-05 +2.159324E-02 +5.953356E-05 +2.252773E-02 +7.064923E-05 +1.497171E-02 +3.139235E-05 +1.702700E-02 +3.702921E-05 +1.197831E-02 +2.110040E-05 +1.326288E-02 +2.668205E-05 +9.877691E-03 +1.417188E-05 +9.222468E-03 +1.493126E-05 +1.916119E-02 +5.100381E-05 +1.618530E-02 +3.741295E-05 +9.744935E-03 +1.312151E-05 +4.205073E-03 +5.238984E-06 +1.606532E-02 +3.801359E-05 +1.115862E-02 +2.015015E-05 +1.312318E-02 +3.970688E-05 +1.092582E-02 +1.677629E-05 +8.988789E-03 +1.272128E-05 +1.116462E-02 +1.435361E-05 +1.177363E-02 +2.013606E-05 +1.392896E-02 +3.825189E-05 +7.595272E-03 +1.080161E-05 +1.243058E-02 +1.937258E-05 +8.823743E-03 +1.585993E-05 +1.072892E-02 +2.225554E-05 +9.610737E-03 +1.152464E-05 +7.143175E-03 +1.112162E-05 +9.471167E-03 +1.466213E-05 +1.060489E-02 +1.784667E-05 +2.767925E-02 +9.174943E-05 +1.613735E-02 +3.391468E-05 +1.980520E-02 +6.099070E-05 +2.710790E-02 +1.005842E-04 +1.498945E-02 +3.548209E-05 +2.090399E-02 +6.229284E-05 +1.867828E-02 +5.023418E-05 +2.101525E-02 +5.304849E-05 +1.495603E-02 +3.564927E-05 +2.206499E-02 +8.477764E-05 +1.774373E-02 +4.204463E-05 +1.321048E-02 +2.339091E-05 +3.032303E-02 +1.133561E-04 +2.906158E-02 +1.116010E-04 +1.416547E-02 +3.074243E-05 +2.396880E-02 +6.563656E-05 +2.277934E-02 +6.079700E-05 +1.978949E-02 +5.275993E-05 +2.518782E-02 +7.984951E-05 +2.706826E-02 +9.202956E-05 +2.708490E-02 +9.059865E-05 +1.986295E-02 +4.689709E-05 +2.616568E-02 +8.883803E-05 +2.130847E-02 +6.518411E-05 +2.806912E-02 +8.769554E-05 +3.084102E-02 +1.172123E-04 +2.897371E-02 +1.021030E-04 +2.903836E-02 +1.108727E-04 +2.605433E-02 +8.468280E-05 +2.332233E-02 +6.130579E-05 +3.234471E-02 +1.225845E-04 +3.300429E-02 +1.500123E-04 +2.311117E-02 +6.190932E-05 +2.436504E-02 +7.178823E-05 +3.008481E-02 +1.005979E-04 +1.928369E-02 +4.312116E-05 +3.011679E-02 +1.179304E-04 +4.008683E-02 +1.751489E-04 +3.496459E-02 +1.796935E-04 +3.097461E-02 +1.095044E-04 +2.638565E-02 +8.181552E-05 +2.620917E-02 +8.987429E-05 +3.998881E-02 +1.948994E-04 +3.258728E-02 +1.341640E-04 +2.561706E-02 +9.239575E-05 +2.588589E-02 +8.721515E-05 +2.944746E-02 +1.052164E-04 +2.989662E-02 +1.085775E-04 +4.206933E-02 +1.998885E-04 +4.066845E-02 +1.897463E-04 +3.508215E-02 +1.528988E-04 +3.120069E-02 +1.132167E-04 +3.286119E-02 +1.352262E-04 +2.909519E-02 +9.371026E-05 +3.840859E-02 +1.674324E-04 +2.454802E-02 +8.382699E-05 +3.347874E-02 +1.411597E-04 +3.060526E-02 +1.367041E-04 +3.069666E-02 +1.180094E-04 +2.561383E-02 +8.330685E-05 +2.628522E-02 +7.556832E-05 +3.582384E-02 +1.465406E-04 +2.376316E-02 +6.457049E-05 +2.495648E-02 +7.422669E-05 +3.093179E-02 +1.305765E-04 +2.264932E-02 +6.586890E-05 +2.047598E-02 +6.261296E-05 +1.933007E-02 +4.833006E-05 +3.257759E-02 +1.237865E-04 +2.571050E-02 +9.464525E-05 +2.463103E-02 +7.258362E-05 +2.557654E-02 +9.353236E-05 +2.284662E-02 +6.268018E-05 +2.491527E-02 +7.859483E-05 +1.681318E-02 +3.501371E-05 +1.365219E-02 +2.989006E-05 +2.210617E-02 +7.141867E-05 +1.271132E-02 +2.094510E-05 +1.683888E-02 +3.625752E-05 +2.058113E-02 +5.450372E-05 +1.739717E-02 +3.555630E-05 +1.829530E-02 +4.644023E-05 +1.776594E-02 +4.124796E-05 +1.418883E-02 +2.672278E-05 +1.760442E-02 +4.591128E-05 +1.891750E-02 +4.822430E-05 +2.178972E-02 +6.432900E-05 +1.443029E-02 +3.016588E-05 +2.256303E-02 +6.869229E-05 +2.251806E-02 +6.650662E-05 +1.323995E-02 +2.512378E-05 +1.335985E-02 +2.654692E-05 +1.740401E-02 +4.340090E-05 +1.330095E-02 +2.489342E-05 +1.207888E-02 +2.391548E-05 +1.667832E-02 +4.429778E-05 +1.489741E-02 +3.841273E-05 +1.143220E-02 +2.495364E-05 +1.240317E-02 +2.477660E-05 +1.342275E-02 +2.581056E-05 +1.621941E-02 +4.158232E-05 +1.159374E-02 +2.088416E-05 +9.404397E-03 +1.695010E-05 +1.056534E-02 +1.863945E-05 +1.162004E-02 +2.136658E-05 +1.095144E-02 +1.546737E-05 +1.144118E-02 +2.034439E-05 +1.322456E-02 +2.558634E-05 +1.172292E-02 +1.883806E-05 +8.086459E-03 +8.879405E-06 +9.613483E-03 +1.997653E-05 +9.179038E-03 +1.284128E-05 +1.897153E-02 +6.588307E-05 +1.524499E-02 +3.816344E-05 +1.007550E-02 +2.293895E-05 +1.297928E-02 +3.448976E-05 +6.475985E-03 +7.421175E-06 +7.302236E-03 +9.360854E-06 +1.268448E-02 +2.201962E-05 +1.331579E-02 +2.325496E-05 +1.816213E-02 +4.264316E-05 +1.951988E-02 +5.119100E-05 +1.565522E-02 +3.615086E-05 +2.309450E-02 +9.333193E-05 +1.557690E-02 +3.930051E-05 +9.451777E-03 +1.526280E-05 +2.041329E-02 +5.032056E-05 +2.673356E-02 +9.468703E-05 +1.094269E-02 +1.894088E-05 +1.679176E-02 +3.840079E-05 +1.732446E-02 +4.238174E-05 +1.027564E-02 +2.013019E-05 +1.861457E-02 +4.141552E-05 +2.507166E-02 +6.889370E-05 +2.041729E-02 +4.876339E-05 +2.283941E-02 +6.377266E-05 +1.892643E-02 +4.163099E-05 +2.187765E-02 +5.763946E-05 +2.028538E-02 +6.131503E-05 +2.103645E-02 +5.318838E-05 +1.715798E-02 +3.499249E-05 +1.485800E-02 +3.358359E-05 +1.984948E-02 +5.445579E-05 +1.703301E-02 +4.679668E-05 +3.309820E-02 +1.234499E-04 +2.275776E-02 +6.157529E-05 +3.261448E-02 +1.319771E-04 +2.554946E-02 +8.196680E-05 +2.004888E-02 +4.990133E-05 +1.939965E-02 +6.076153E-05 +2.548646E-02 +8.064466E-05 +2.855104E-02 +1.012305E-04 +2.762007E-02 +1.037910E-04 +1.839340E-02 +4.279463E-05 +1.686751E-02 +4.608015E-05 +2.084644E-02 +5.002926E-05 +4.132950E-02 +1.846233E-04 +3.460120E-02 +1.298466E-04 +3.552467E-02 +1.570092E-04 +2.933106E-02 +9.609808E-05 +2.684190E-02 +7.922498E-05 +2.487139E-02 +6.891792E-05 +3.728495E-02 +1.689194E-04 +2.818457E-02 +8.676068E-05 +3.441368E-02 +1.333471E-04 +2.818973E-02 +1.038355E-04 +2.356477E-02 +6.812284E-05 +2.343339E-02 +6.179023E-05 +4.344270E-02 +2.389724E-04 +4.294905E-02 +2.093287E-04 +3.836620E-02 +1.778263E-04 +2.841149E-02 +8.871119E-05 +4.014563E-02 +1.768024E-04 +2.920772E-02 +1.000217E-04 +2.615172E-02 +8.720279E-05 +2.000501E-02 +4.816703E-05 +4.057421E-02 +1.875221E-04 +2.445887E-02 +8.924764E-05 +2.817821E-02 +8.605351E-05 +2.110986E-02 +5.069715E-05 +2.927821E-02 +9.308711E-05 +3.362175E-02 +1.332596E-04 +3.475808E-02 +1.323338E-04 +3.289085E-02 +1.244729E-04 +3.022584E-02 +1.318809E-04 +3.196364E-02 +1.297968E-04 +1.687072E-02 +3.179809E-05 +1.801683E-02 +4.078604E-05 +2.960756E-02 +1.160952E-04 +3.466058E-02 +1.382880E-04 +2.412524E-02 +9.376449E-05 +3.370586E-02 +1.749860E-04 +1.744924E-02 +4.569761E-05 +2.327075E-02 +7.176336E-05 +2.067060E-02 +5.038568E-05 +2.065122E-02 +5.674893E-05 +1.185396E-02 +1.904589E-05 +1.187338E-02 +1.832962E-05 +1.361451E-02 +2.819447E-05 +1.785195E-02 +4.401066E-05 +2.526233E-02 +8.640741E-05 +1.793604E-02 +5.730915E-05 +1.571041E-02 +3.175367E-05 +1.678219E-02 +3.936420E-05 +1.486918E-02 +3.526965E-05 +2.794130E-02 +1.195339E-04 +1.996768E-02 +7.226779E-05 +1.162384E-02 +2.197081E-05 +2.096325E-02 +5.793563E-05 +1.837867E-02 +4.515139E-05 +1.703731E-02 +3.926907E-05 +1.268651E-02 +2.343106E-05 +1.879725E-02 +4.716744E-05 +1.709910E-02 +3.710250E-05 +1.228622E-02 +3.339394E-05 +1.352711E-02 +2.975058E-05 +1.155424E-02 +1.880536E-05 +1.121092E-02 +2.205103E-05 +1.476077E-02 +3.330714E-05 +1.255099E-02 +2.385469E-05 +1.347481E-02 +2.408221E-05 +1.470344E-02 +2.583766E-05 +9.187814E-03 +1.701394E-05 +1.028524E-02 +2.190585E-05 +1.204921E-02 +2.386486E-05 +1.214004E-02 +1.925520E-05 +1.294814E-02 +2.325545E-05 +1.470310E-02 +3.633457E-05 +7.703457E-03 +8.319661E-06 +9.053019E-03 +1.860099E-05 +3.939164E-03 +3.269741E-06 +9.533908E-03 +1.325293E-05 +1.227483E-02 +2.491268E-05 +1.259791E-02 +2.146362E-05 +4.323047E-03 +3.283543E-06 +9.255709E-03 +2.197638E-05 +4.603184E-03 +3.514783E-06 +4.229364E-03 +6.002727E-06 +1.275699E-02 +2.227133E-05 +1.051975E-02 +1.875691E-05 +1.939046E-02 +4.923847E-05 +1.621043E-02 +4.902401E-05 +1.162276E-02 +2.501804E-05 +1.178308E-02 +2.464996E-05 +1.264103E-02 +2.350170E-05 +1.829675E-02 +4.158987E-05 +1.935990E-02 +4.658558E-05 +2.050484E-02 +5.542682E-05 +1.261518E-02 +2.496199E-05 +2.338316E-02 +6.665179E-05 +1.422276E-02 +2.677276E-05 +1.418978E-02 +3.508840E-05 +3.161101E-02 +1.103014E-04 +2.806809E-02 +9.416094E-05 +1.970337E-02 +5.207680E-05 +2.017517E-02 +5.029958E-05 +2.476977E-02 +9.671590E-05 +1.993423E-02 +5.639950E-05 +2.220619E-02 +5.949033E-05 +2.663071E-02 +8.742719E-05 +1.716007E-02 +3.560277E-05 +1.620846E-02 +3.298124E-05 +2.027814E-02 +5.137992E-05 +2.241055E-02 +6.475298E-05 +3.149111E-02 +1.240574E-04 +3.301990E-02 +1.297806E-04 +2.289529E-02 +7.022820E-05 +2.770187E-02 +1.305531E-04 +2.647167E-02 +8.125885E-05 +2.470047E-02 +6.618469E-05 +1.972532E-02 +5.720249E-05 +2.301743E-02 +6.802664E-05 +1.851738E-02 +4.051694E-05 +1.781820E-02 +3.908008E-05 +2.011234E-02 +4.945371E-05 +1.788427E-02 +4.535953E-05 +3.355984E-02 +1.399308E-04 +3.141513E-02 +1.324421E-04 +3.123214E-02 +1.131961E-04 +2.990237E-02 +1.043368E-04 +2.483001E-02 +7.814014E-05 +2.780841E-02 +9.315514E-05 +2.944866E-02 +1.125594E-04 +3.115948E-02 +1.382235E-04 +3.135984E-02 +1.125014E-04 +2.632324E-02 +9.453811E-05 +3.001476E-02 +1.041868E-04 +2.694256E-02 +8.321200E-05 +2.693560E-02 +7.578608E-05 +3.360780E-02 +1.359544E-04 +3.373802E-02 +1.372586E-04 +2.236018E-02 +6.411192E-05 +2.962695E-02 +1.020105E-04 +2.783038E-02 +9.884369E-05 +2.407145E-02 +7.259162E-05 +2.611296E-02 +9.023141E-05 +3.127878E-02 +1.135229E-04 +2.950226E-02 +9.691197E-05 +2.305590E-02 +6.460450E-05 +2.321268E-02 +7.274626E-05 +2.804961E-02 +9.491270E-05 +2.841803E-02 +1.054470E-04 +2.423205E-02 +7.810874E-05 +2.714164E-02 +9.975157E-05 +2.873229E-02 +1.122814E-04 +2.098758E-02 +5.056677E-05 +2.557067E-02 +8.748635E-05 +2.267297E-02 +8.906984E-05 +2.139317E-02 +5.463244E-05 +2.294894E-02 +7.412557E-05 +1.571457E-02 +3.620884E-05 +2.240494E-02 +5.721050E-05 +2.805329E-02 +9.134972E-05 +3.310961E-02 +1.309241E-04 +1.731055E-02 +3.757453E-05 +1.519094E-02 +3.101001E-05 +3.089642E-02 +1.273235E-04 +2.655794E-02 +1.020322E-04 +1.930391E-02 +4.470231E-05 +1.322122E-02 +2.280479E-05 +2.267352E-02 +6.781380E-05 +2.377301E-02 +7.062640E-05 +1.061766E-02 +1.383149E-05 +1.989374E-02 +6.361786E-05 +2.625067E-02 +9.026084E-05 +2.498518E-02 +8.804371E-05 +2.106620E-02 +5.099756E-05 +1.201370E-02 +2.098230E-05 +2.562363E-02 +8.111943E-05 +1.462361E-02 +2.865648E-05 +2.187381E-02 +5.860668E-05 +1.613482E-02 +4.384305E-05 +1.621606E-02 +3.449398E-05 +1.444365E-02 +3.579161E-05 +1.323646E-02 +2.542031E-05 +1.061139E-02 +1.881978E-05 +8.801940E-03 +1.018150E-05 +1.139983E-02 +2.019736E-05 +1.681598E-02 +3.690065E-05 +1.399493E-02 +3.175563E-05 +1.420691E-02 +2.466458E-05 +1.368415E-02 +2.617814E-05 +4.389391E-03 +3.790342E-06 +8.841774E-03 +1.306452E-05 +6.705949E-03 +6.428293E-06 +3.807333E-03 +3.521598E-06 +8.526487E-03 +1.179686E-05 +6.365036E-03 +6.849920E-06 +9.633887E-03 +1.541102E-05 +1.123781E-02 +1.889506E-05 +6.073970E-03 +7.042592E-06 +5.473005E-03 +4.622656E-06 +9.289202E-03 +1.795737E-05 +1.030725E-02 +2.040465E-05 +6.753476E-03 +7.775016E-06 +5.874996E-03 +7.699447E-06 +4.803223E-03 +5.048987E-06 +9.387232E-03 +2.256112E-05 +6.779777E-03 +7.696560E-06 +7.302784E-03 +1.204717E-05 +1.858153E-02 +4.240154E-05 +1.133429E-02 +1.757188E-05 +1.090884E-02 +1.956959E-05 +1.761310E-02 +4.472462E-05 +1.208597E-02 +2.241660E-05 +8.447260E-03 +1.837826E-05 +2.154735E-02 +7.183466E-05 +1.059584E-02 +1.725144E-05 +1.078223E-02 +1.741743E-05 +1.142825E-02 +1.725056E-05 +8.052096E-03 +1.288141E-05 +8.852506E-03 +1.479325E-05 +1.503791E-02 +2.827810E-05 +1.427595E-02 +2.627358E-05 +1.151486E-02 +1.821048E-05 +1.479919E-02 +3.026089E-05 +1.396424E-02 +2.976716E-05 +1.102878E-02 +1.569768E-05 +1.486600E-02 +4.640833E-05 +2.329305E-02 +6.388242E-05 +1.077778E-02 +2.630229E-05 +1.187595E-02 +2.158652E-05 +1.706939E-02 +3.589833E-05 +9.894219E-03 +1.748099E-05 +2.294330E-02 +6.429613E-05 +2.112393E-02 +5.525797E-05 +1.888943E-02 +4.229674E-05 +1.872573E-02 +5.200290E-05 +2.190997E-02 +6.830515E-05 +1.857860E-02 +5.271689E-05 +1.824118E-02 +4.252719E-05 +1.695109E-02 +4.377846E-05 +1.942043E-02 +4.638640E-05 +2.430706E-02 +8.617790E-05 +1.728181E-02 +4.311630E-05 +1.163790E-02 +2.136880E-05 +2.488767E-02 +7.230908E-05 +2.919997E-02 +9.955761E-05 +2.584993E-02 +1.031623E-04 +2.268255E-02 +6.949158E-05 +3.146416E-02 +1.268057E-04 +2.236165E-02 +6.966628E-05 +2.724737E-02 +9.874601E-05 +2.224496E-02 +7.784128E-05 +2.189895E-02 +6.090239E-05 +1.839473E-02 +4.209614E-05 +2.542360E-02 +8.396121E-05 +2.052856E-02 +4.913619E-05 +3.120344E-02 +1.291172E-04 +2.944557E-02 +1.038017E-04 +3.259220E-02 +1.571837E-04 +2.454004E-02 +8.331616E-05 +2.553435E-02 +9.440752E-05 +2.541943E-02 +9.586937E-05 +2.061350E-02 +7.364042E-05 +2.329153E-02 +9.064116E-05 +2.078416E-02 +4.749189E-05 +2.761182E-02 +8.657370E-05 +2.266317E-02 +6.326775E-05 +2.686321E-02 +1.043542E-04 +2.182754E-02 +7.805811E-05 +2.766205E-02 +9.723951E-05 +1.892390E-02 +5.005671E-05 +2.382207E-02 +6.769044E-05 +2.015930E-02 +6.032256E-05 +1.427037E-02 +3.798052E-05 +1.767507E-02 +6.512871E-05 +2.123882E-02 +4.907487E-05 +2.157816E-02 +6.678135E-05 +1.919870E-02 +5.942855E-05 +2.192776E-02 +5.912113E-05 +1.744859E-02 +5.000179E-05 +1.577374E-02 +3.368332E-05 +2.305821E-02 +6.854360E-05 +2.058939E-02 +5.959718E-05 +1.350163E-02 +3.072943E-05 +1.774684E-02 +4.504160E-05 +1.929554E-02 +5.149838E-05 +1.225057E-02 +1.846451E-05 +1.522995E-02 +3.345735E-05 +1.488842E-02 +2.657892E-05 +1.308637E-02 +2.575083E-05 +1.550443E-02 +4.365385E-05 +1.262294E-02 +2.496948E-05 +2.022153E-02 +5.150955E-05 +2.016439E-02 +5.276144E-05 +1.850133E-02 +4.648369E-05 +9.903588E-03 +1.610212E-05 +1.242472E-02 +2.311415E-05 +1.448322E-02 +3.103193E-05 +1.821292E-02 +6.275309E-05 +1.275608E-02 +5.475363E-05 +1.800193E-02 +4.234061E-05 +8.782455E-03 +1.649077E-05 +1.220656E-02 +2.499398E-05 +1.247528E-02 +3.099809E-05 +4.915298E-03 +5.476965E-06 +9.391788E-03 +1.606380E-05 +6.771266E-03 +8.450336E-06 +5.095855E-03 +3.842657E-06 +1.019612E-02 +1.603701E-05 +1.266368E-02 +2.593740E-05 +1.437121E-03 +9.237680E-07 +7.738730E-03 +1.337549E-05 +1.101810E-02 +1.737730E-05 +3.189798E-03 +4.831494E-06 +8.313307E-03 +1.236384E-05 +4.760766E-03 +2.835247E-06 +8.211101E-03 +1.004626E-05 +4.023937E-03 +3.045420E-06 +3.795398E-03 +3.753905E-06 +6.439348E-03 +6.445882E-06 +8.789930E-03 +9.641461E-06 +1.003210E-02 +1.871561E-05 +7.188383E-03 +7.745644E-06 +8.884373E-03 +1.210321E-05 +4.201731E-03 +3.267512E-06 +6.156152E-03 +6.439386E-06 +6.368503E-03 +6.063000E-06 +5.865149E-03 +6.343581E-06 +8.242843E-03 +1.255409E-05 +6.079907E-03 +8.904171E-06 +1.068165E-02 +1.977482E-05 +9.934550E-03 +1.529904E-05 +9.391801E-03 +1.672164E-05 +9.638027E-03 +1.793124E-05 +1.056323E-02 +2.728241E-05 +7.672750E-03 +1.245311E-05 +5.340667E-03 +9.209395E-06 +1.355760E-02 +6.094725E-05 +8.047003E-03 +9.586050E-06 +1.285221E-02 +3.064011E-05 +1.569140E-02 +3.403460E-05 +1.271345E-02 +2.195068E-05 +1.226525E-02 +2.591890E-05 +1.571067E-02 +3.670153E-05 +1.000122E-02 +2.251836E-05 +1.263608E-02 +2.857491E-05 +1.467989E-02 +3.065952E-05 +1.992801E-02 +5.197568E-05 +1.634631E-02 +3.854791E-05 +9.765387E-03 +1.929348E-05 +1.567478E-02 +4.572326E-05 +1.122681E-02 +1.875141E-05 +1.438219E-02 +2.962331E-05 +2.198487E-02 +5.569638E-05 +1.350017E-02 +2.505385E-05 +1.864402E-02 +5.207299E-05 +1.588104E-02 +4.725574E-05 +1.091009E-02 +1.886410E-05 +2.047245E-02 +6.638244E-05 +1.595713E-02 +4.444025E-05 +1.240157E-02 +1.827292E-05 +8.920440E-03 +1.437145E-05 +1.325339E-02 +2.805692E-05 +1.008187E-02 +1.747750E-05 +1.944508E-02 +6.365499E-05 +2.320316E-02 +7.205046E-05 +2.067013E-02 +4.788913E-05 +1.843860E-02 +4.912723E-05 +2.314076E-02 +7.987697E-05 +2.082200E-02 +6.799905E-05 +1.477196E-02 +2.747397E-05 +1.645001E-02 +3.474675E-05 +2.251395E-02 +7.952533E-05 +1.283424E-02 +2.565340E-05 +1.302741E-02 +2.183293E-05 +1.627063E-02 +3.188570E-05 +1.694690E-02 +4.854666E-05 +1.768424E-02 +4.519650E-05 +1.688309E-02 +3.658427E-05 +2.081183E-02 +4.936469E-05 +1.521899E-02 +3.630188E-05 +1.538105E-02 +4.012152E-05 +1.852161E-02 +4.542222E-05 +2.027891E-02 +7.078559E-05 +1.530632E-02 +4.004295E-05 +1.251099E-02 +2.014674E-05 +1.766586E-02 +3.643771E-05 +1.011259E-02 +1.798254E-05 +1.785577E-02 +4.209205E-05 +1.591733E-02 +2.948407E-05 +1.973149E-02 +5.858390E-05 +2.318672E-02 +6.821666E-05 +1.606927E-02 +3.208169E-05 +1.561903E-02 +3.274947E-05 +8.671178E-03 +1.320312E-05 +1.321121E-02 +2.770105E-05 +1.276830E-02 +2.392358E-05 +8.675945E-03 +1.600673E-05 +1.631955E-02 +3.628609E-05 +1.268176E-02 +2.698295E-05 +1.305170E-02 +3.392622E-05 +1.151833E-02 +2.146481E-05 +1.382454E-02 +2.543511E-05 +1.268190E-02 +2.770093E-05 +1.670138E-02 +4.515019E-05 +1.411501E-02 +2.397072E-05 +1.054121E-02 +1.734424E-05 +1.038572E-02 +1.525222E-05 +1.239423E-02 +1.885637E-05 +8.231991E-03 +1.095003E-05 +1.346736E-02 +2.994113E-05 +1.282791E-02 +2.684630E-05 +1.377004E-02 +3.238869E-05 +1.142596E-02 +1.735764E-05 +1.062508E-02 +1.743282E-05 +1.257942E-02 +2.057274E-05 +1.169000E-02 +2.474569E-05 +6.423798E-03 +8.173196E-06 +7.740555E-03 +1.569990E-05 +8.666292E-03 +1.364526E-05 +1.430519E-02 +3.144468E-05 +1.034424E-02 +1.702524E-05 +1.041966E-02 +1.828082E-05 +7.823260E-03 +1.110455E-05 +7.252199E-03 +9.925677E-06 +2.994718E-03 +1.593375E-06 +1.048984E-02 +2.573976E-05 +5.641360E-03 +5.936595E-06 +5.229774E-03 +7.041393E-06 +9.930813E-03 +1.689201E-05 +4.386542E-03 +4.754619E-06 +5.133633E-03 +4.043150E-06 +3.269722E-03 +1.970563E-06 +4.951504E-03 +6.193676E-06 +4.410157E-03 +4.926957E-06 +8.875217E-03 +1.522029E-05 +6.496616E-03 +8.828653E-06 +5.733530E-03 +7.478095E-06 +4.584225E-03 +3.801824E-06 +5.014833E-03 +4.595598E-06 +4.918988E-03 +9.258105E-06 +5.483056E-03 +9.195257E-06 +5.228430E-03 +7.940306E-06 +5.117645E-03 +7.631754E-06 +5.072391E-03 +5.531082E-06 +3.632197E-03 +2.983079E-06 +4.693965E-03 +5.099544E-06 +2.051996E-03 +1.135888E-06 +7.304764E-03 +1.039220E-05 +3.647755E-03 +4.449912E-06 +3.476959E-03 +2.187942E-06 +9.489533E-03 +2.316279E-05 +5.751162E-03 +8.659685E-06 +4.963073E-03 +5.706592E-06 +6.138111E-03 +1.068804E-05 +9.307217E-03 +1.519475E-05 +4.545925E-03 +6.535861E-06 +8.294344E-03 +1.556852E-05 +7.173393E-03 +9.233319E-06 +1.078215E-02 +1.572789E-05 +9.705333E-03 +3.544244E-05 +7.945812E-03 +1.276101E-05 +1.168294E-02 +2.467022E-05 +6.645644E-03 +7.587545E-06 +5.760001E-03 +9.365634E-06 +8.601051E-03 +1.363162E-05 +8.005982E-03 +1.328267E-05 +1.261419E-02 +3.207736E-05 +5.901262E-03 +6.935112E-06 +6.430185E-03 +9.087951E-06 +6.884844E-03 +8.313889E-06 +4.278770E-03 +3.441959E-06 +1.137804E-02 +2.133967E-05 +1.214381E-02 +2.232652E-05 +1.740437E-02 +3.543180E-05 +1.246386E-02 +2.766736E-05 +1.214083E-02 +1.935442E-05 +1.166031E-02 +2.273794E-05 +1.042912E-02 +2.534376E-05 +1.253440E-02 +2.906078E-05 +3.580466E-03 +2.034018E-06 +9.607729E-03 +1.395640E-05 +9.100903E-03 +1.455039E-05 +5.382398E-03 +1.056575E-05 +1.720209E-02 +4.611390E-05 +1.189486E-02 +2.081478E-05 +2.098921E-02 +5.268336E-05 +1.295792E-02 +2.491469E-05 +1.359035E-02 +2.476233E-05 +1.320672E-02 +2.504384E-05 +1.004322E-02 +1.517085E-05 +6.328234E-03 +7.222517E-06 +7.696931E-03 +8.736384E-06 +9.062335E-03 +1.635044E-05 +1.220397E-02 +2.109811E-05 +9.542900E-03 +1.414586E-05 +2.001020E-02 +5.728709E-05 +1.200225E-02 +1.611148E-05 +1.851644E-02 +5.098601E-05 +1.159430E-02 +2.048997E-05 +1.198809E-02 +2.688531E-05 +1.067777E-02 +1.707832E-05 +1.686877E-02 +4.601130E-05 +1.514223E-02 +3.020548E-05 +9.412452E-03 +1.296937E-05 +8.734687E-03 +1.791696E-05 +7.182753E-03 +7.961564E-06 +7.131070E-03 +8.835775E-06 +1.176780E-02 +2.003672E-05 +1.238591E-02 +1.851917E-05 +1.482210E-02 +4.681620E-05 +8.008500E-03 +8.162099E-06 +1.099128E-02 +1.643104E-05 +1.234719E-02 +2.252478E-05 +9.121398E-03 +1.338217E-05 +9.649799E-03 +1.957300E-05 +1.239326E-02 +2.066867E-05 +7.925470E-03 +9.921111E-06 +6.952410E-03 +1.209167E-05 +1.305189E-02 +2.993481E-05 +1.011683E-02 +1.814412E-05 +9.138673E-03 +1.288657E-05 +9.613647E-03 +1.454996E-05 +9.587432E-03 +1.425997E-05 +4.100970E-03 +3.581979E-06 +6.384398E-03 +9.449653E-06 +5.332770E-03 +4.810910E-06 +8.205597E-03 +1.367429E-05 +4.458035E-03 +3.530187E-06 +3.214674E-03 +1.992488E-06 +6.119990E-03 +6.950277E-06 +4.194752E-03 +3.822292E-06 +7.270772E-03 +8.358483E-06 +7.963665E-03 +1.211727E-05 +1.139690E-02 +2.688370E-05 +1.072253E-02 +1.923075E-05 +9.310029E-03 +2.222401E-05 +6.635931E-03 +6.447355E-06 +6.067077E-03 +9.323989E-06 +6.686810E-03 +6.491688E-06 +7.266522E-03 +7.228635E-06 +2.677445E-03 +2.282809E-06 +7.272519E-03 +9.053976E-06 +5.368115E-03 +6.336538E-06 +3.059467E-03 +2.284551E-06 +3.148000E-03 +2.437724E-06 +3.588594E-03 +3.284908E-06 +4.456313E-03 +7.520958E-06 +2.798347E-03 +2.236317E-06 +6.840217E-03 +9.048482E-06 +1.575769E-03 +9.897286E-07 +2.611268E-03 +1.755955E-06 +1.750700E-03 +1.182162E-06 +2.239940E-03 +2.450046E-06 +1.507196E-03 +1.074090E-06 +6.865521E-03 +7.835832E-06 +2.312288E-03 +2.250952E-06 +4.625802E-03 +5.487129E-06 +2.141186E-03 +9.777142E-07 +1.364855E-03 +9.688473E-07 +3.118005E-03 +3.532909E-06 +2.850409E-03 +1.719105E-06 +3.414722E-03 +2.946427E-06 +5.867545E-03 +6.300551E-06 +3.511602E-03 +3.730751E-06 +2.231751E-03 +2.052805E-06 +2.099977E-03 +1.555011E-06 +2.936833E-03 +2.400849E-06 +5.147373E-03 +6.410685E-06 +9.334636E-03 +1.426974E-05 +5.355177E-03 +5.994759E-06 +5.939796E-03 +1.063177E-05 +5.190027E-03 +5.190207E-06 +5.258137E-03 +4.118191E-06 +6.041649E-03 +6.155598E-06 +5.622082E-03 +4.644624E-06 +1.149290E-02 +2.616444E-05 +7.309708E-03 +8.042562E-06 +3.694461E-03 +3.564990E-06 +6.879292E-03 +1.011779E-05 +9.522458E-03 +1.559720E-05 +5.391999E-03 +4.832231E-06 +5.698037E-03 +5.073533E-06 +1.893957E-03 +1.407429E-06 +7.904603E-03 +1.129256E-05 +5.420913E-03 +6.627464E-06 +6.982381E-03 +6.809893E-06 +6.325870E-03 +7.532835E-06 +4.682244E-03 +3.460830E-06 +6.920599E-03 +8.574244E-06 +3.733359E-03 +3.700527E-06 +4.030359E-03 +3.986131E-06 +5.047907E-03 +4.426148E-06 +9.528005E-03 +1.550618E-05 +7.877900E-03 +1.006685E-05 +9.780723E-03 +1.657015E-05 +4.812077E-03 +4.098229E-06 +7.016687E-03 +7.149177E-06 +4.037284E-03 +3.400182E-06 +3.277155E-03 +2.337977E-06 +6.137543E-03 +6.092367E-06 +6.278125E-03 +9.707219E-06 +2.576720E-03 +3.914988E-06 +4.835272E-03 +7.752895E-06 +6.736014E-03 +7.302508E-06 +6.970854E-03 +6.682760E-06 +6.313642E-03 +5.551521E-06 +7.635449E-03 +8.984939E-06 +8.683849E-03 +1.560378E-05 +7.530787E-03 +9.173765E-06 +1.569516E-02 +3.949851E-05 +1.097068E-02 +2.119987E-05 +7.309184E-03 +7.015811E-06 +8.665715E-03 +1.546974E-05 +7.723895E-03 +1.518562E-05 +4.905466E-03 +4.093288E-06 +1.077564E-02 +2.805109E-05 +8.569399E-03 +1.273736E-05 +1.038612E-02 +1.719585E-05 +7.354212E-03 +8.198097E-06 +9.350739E-03 +1.720908E-05 +4.787259E-03 +6.741535E-06 +7.220875E-03 +8.792305E-06 +5.379919E-03 +5.042148E-06 +8.788109E-03 +1.266781E-05 +7.402327E-03 +7.894813E-06 +4.207623E-03 +3.460121E-06 +7.902663E-03 +9.560483E-06 +5.174573E-03 +4.082169E-06 +1.104658E-02 +2.127916E-05 +5.782523E-03 +5.112492E-06 +3.632634E-03 +2.502751E-06 +5.337278E-03 +4.486802E-06 +4.249421E-03 +4.213447E-06 +7.491058E-03 +9.439118E-06 +5.243136E-03 +5.575342E-06 +1.237618E-02 +2.148757E-05 +8.041605E-03 +1.026055E-05 +6.349704E-03 +1.417430E-05 +6.087425E-03 +8.075635E-06 +4.602367E-03 +3.651645E-06 +4.154919E-03 +5.935728E-06 +1.040123E-02 +1.813267E-05 +8.425233E-03 +1.322959E-05 +5.094732E-03 +6.066657E-06 +3.282128E-03 +2.438795E-06 +4.478721E-03 +5.352957E-06 +4.621930E-03 +3.979448E-06 +3.591134E-03 +3.542812E-06 +3.931582E-03 +3.195193E-06 +7.517289E-03 +1.202563E-05 +4.445629E-03 +3.532948E-06 +5.122199E-03 +4.733178E-06 +6.079088E-03 +5.645343E-06 +5.005001E-03 +5.722868E-06 +4.017636E-03 +3.624033E-06 +3.326000E-03 +2.420695E-06 +3.011641E-03 +3.505638E-06 +2.136977E-03 +8.951049E-07 +1.175447E-03 +4.124064E-07 +7.823514E-03 +1.228293E-05 +4.920698E-03 +4.693144E-06 +3.285795E-03 +2.440402E-06 +4.028141E-03 +3.884837E-06 +2.781317E-03 +1.300197E-06 +3.926044E-03 +3.109193E-06 +4.628411E-03 +5.325271E-06 +4.051196E-03 +3.567334E-06 +3.272251E-03 +4.622968E-06 +3.143217E-03 +2.173404E-06 +2.374311E-03 +1.308003E-06 +1.326934E-03 +9.031223E-07 +3.522915E-03 +4.391282E-06 +5.770000E-04 +1.329958E-07 +2.830130E-03 +3.011060E-06 +2.210339E-03 +1.635883E-06 +3.721215E-03 +3.080210E-06 +6.120484E-03 +5.355595E-06 +3.678377E-03 +3.709180E-06 +2.413835E-03 +1.404139E-06 +5.860060E-03 +6.753555E-06 +6.142222E-03 +6.895111E-06 +4.689827E-03 +4.987858E-06 +3.810291E-03 +3.578451E-06 +4.720787E-03 +7.371870E-06 +1.759885E-03 +1.135197E-06 +4.523542E-03 +5.744713E-06 +4.512130E-03 +5.150402E-06 +8.505535E-03 +9.989819E-06 +8.615921E-03 +1.014660E-05 +6.886961E-03 +6.750505E-06 +6.626919E-03 +8.244527E-06 +9.376957E-03 +1.235456E-05 +9.638288E-03 +1.489772E-05 +1.001130E-02 +1.552242E-05 +1.028076E-02 +1.757757E-05 +3.716261E-03 +3.414503E-06 +1.351126E-02 +2.981345E-05 +7.730660E-03 +1.296080E-05 +8.324008E-03 +1.413367E-05 +9.824794E-03 +1.737391E-05 +8.406562E-03 +1.011462E-05 +6.244264E-03 +9.615840E-06 +5.753008E-03 +5.938129E-06 +1.161932E-02 +1.759635E-05 +7.019897E-03 +6.911798E-06 +1.124973E-02 +2.227076E-05 +9.974498E-03 +1.531239E-05 +1.750036E-02 +3.960636E-05 +1.123801E-02 +2.603078E-05 +6.620195E-03 +8.846067E-06 +8.621539E-03 +1.476285E-05 +1.144148E-02 +2.816625E-05 +9.236578E-03 +2.087006E-05 +1.022756E-02 +2.015506E-05 +8.313712E-03 +1.245193E-05 +8.472316E-03 +1.040768E-05 +1.100682E-02 +1.897584E-05 +7.072576E-03 +7.806879E-06 +8.257296E-03 +1.365708E-05 +8.677246E-03 +1.251818E-05 +1.847630E-03 +1.221029E-06 +3.514354E-03 +2.801550E-06 +4.635307E-03 +4.312440E-06 +1.719934E-02 +3.993958E-05 +1.168750E-02 +1.940685E-05 +1.392387E-02 +2.505551E-05 +9.162097E-03 +2.003276E-05 +1.068024E-02 +1.620043E-05 +6.143827E-03 +6.330015E-06 +9.757303E-03 +1.665448E-05 +1.205259E-02 +2.076304E-05 +1.099561E-02 +1.990285E-05 +8.729352E-03 +1.425139E-05 +5.036499E-03 +3.597216E-06 +4.573901E-03 +4.390016E-06 +1.098170E-02 +1.803805E-05 +1.450456E-02 +2.780429E-05 +6.373863E-03 +6.571288E-06 +9.888037E-03 +1.449978E-05 +1.253128E-02 +2.292463E-05 +1.075201E-02 +1.610392E-05 +8.884084E-03 +1.322461E-05 +5.357264E-03 +5.936993E-06 +1.493177E-02 +2.673706E-05 +5.699430E-03 +5.340117E-06 +8.188668E-03 +1.253943E-05 +4.838650E-03 +3.385865E-06 +1.000094E-02 +1.476818E-05 +1.063068E-02 +1.693667E-05 +9.830500E-03 +1.503630E-05 +1.025245E-02 +1.763545E-05 +1.028864E-02 +1.849793E-05 +5.900779E-03 +6.170864E-06 +1.177015E-02 +2.226737E-05 +7.509689E-03 +8.719533E-06 +1.206431E-02 +2.678780E-05 +9.200857E-03 +1.643527E-05 +5.468133E-03 +4.453812E-06 +7.516784E-03 +9.212924E-06 +1.111732E-02 +1.394083E-05 +1.179677E-02 +1.966452E-05 +4.112066E-03 +2.360474E-06 +4.867401E-03 +6.026552E-06 +8.104035E-03 +1.092048E-05 +1.016367E-02 +1.245298E-05 +8.572029E-03 +1.314727E-05 +5.230427E-03 +4.291571E-06 +1.462827E-02 +3.660743E-05 +1.133693E-02 +1.987800E-05 +8.632273E-03 +1.741700E-05 +9.505339E-03 +1.209742E-05 +3.350003E-03 +1.830051E-06 +1.189483E-02 +1.823139E-05 +6.269531E-03 +9.062971E-06 +5.745106E-03 +7.814173E-06 +5.494288E-03 +5.220575E-06 +8.224322E-03 +1.417410E-05 +7.485116E-03 +7.578271E-06 +4.217646E-03 +3.209044E-06 +9.597899E-03 +1.579356E-05 +9.222350E-03 +1.143785E-05 +5.917673E-03 +5.975846E-06 +4.191188E-03 +2.824383E-06 +5.746277E-03 +5.928494E-06 +5.146451E-03 +4.826427E-06 +3.536845E-03 +2.903999E-06 +2.348669E-03 +2.151234E-06 +7.673915E-03 +1.147821E-05 +4.006830E-03 +3.592361E-06 +4.896990E-03 +5.179793E-06 +5.024089E-03 +5.234216E-06 +6.039638E-03 +6.322254E-06 +8.201689E-03 +1.116771E-05 +6.614252E-03 +1.021009E-05 +4.191696E-03 +4.388316E-06 +1.128526E-02 +1.976083E-05 +1.067513E-02 +1.823942E-05 +3.764982E-03 +3.222515E-06 +3.948813E-03 +4.451513E-06 +1.000152E-02 +2.107330E-05 +6.164282E-03 +1.724834E-05 +1.006014E-02 +2.134032E-05 +1.286695E-02 +3.067989E-05 +8.978723E-03 +1.251581E-05 +5.346415E-03 +5.350269E-06 +3.635013E-03 +4.204044E-06 +6.583641E-03 +8.886395E-06 +6.112499E-03 +7.100313E-06 +9.075416E-03 +1.361298E-05 +9.360748E-03 +1.479673E-05 +1.287873E-02 +2.436676E-05 +1.196275E-02 +1.944035E-05 +9.130004E-03 +1.555860E-05 +9.992520E-03 +1.245497E-05 +1.115802E-02 +1.670908E-05 +1.081540E-02 +1.882462E-05 +1.372827E-02 +2.757409E-05 +8.020036E-03 +1.222038E-05 +6.290610E-03 +4.837074E-06 +1.576319E-02 +3.661568E-05 +1.430139E-02 +3.954353E-05 +1.550808E-02 +5.413485E-05 +9.529567E-03 +2.562847E-05 +1.252063E-02 +2.284038E-05 +8.998915E-03 +1.107600E-05 +1.128710E-02 +3.131513E-05 +8.894334E-03 +1.612799E-05 +9.936476E-03 +1.499512E-05 +1.085220E-02 +1.879083E-05 +7.842398E-03 +1.147755E-05 +9.478975E-03 +1.366773E-05 +8.870185E-03 +1.264668E-05 +1.265677E-02 +3.003173E-05 +7.082798E-03 +9.455651E-06 +6.207587E-03 +1.035866E-05 +9.389246E-03 +1.904336E-05 +6.809780E-03 +1.110927E-05 +1.415613E-02 +3.324858E-05 +1.411282E-02 +2.597041E-05 +1.427512E-02 +3.295595E-05 +1.943942E-02 +5.877560E-05 +8.220965E-03 +9.356934E-06 +9.250583E-03 +1.365956E-05 +1.656914E-02 +3.475091E-05 +1.843152E-02 +4.655130E-05 +1.153837E-02 +1.618003E-05 +1.196430E-02 +2.260049E-05 +1.575201E-02 +2.932265E-05 +1.575583E-02 +3.216253E-05 +1.342670E-02 +3.092689E-05 +1.018784E-02 +1.786160E-05 +1.303515E-02 +2.169915E-05 +1.219880E-02 +3.353411E-05 +7.032946E-03 +7.709601E-06 +1.229650E-02 +2.705058E-05 +1.615409E-02 +3.472477E-05 +1.821028E-02 +3.933712E-05 +1.470364E-02 +2.795706E-05 +1.050280E-02 +2.133231E-05 +1.154231E-02 +1.968046E-05 +7.645500E-03 +1.039514E-05 +1.741509E-02 +3.584004E-05 +8.821919E-03 +1.428153E-05 +1.857457E-02 +4.195598E-05 +1.552507E-02 +2.892265E-05 +7.183282E-03 +9.228195E-06 +1.217604E-02 +1.939061E-05 +1.541421E-02 +3.334972E-05 +2.052820E-02 +5.660936E-05 +9.353019E-03 +1.426621E-05 +1.251082E-02 +2.228447E-05 +1.368721E-02 +2.531714E-05 +1.226667E-02 +2.368414E-05 +1.371101E-02 +2.448795E-05 +1.201033E-02 +2.393841E-05 +1.280636E-02 +2.115640E-05 +1.264839E-02 +2.387771E-05 +9.055229E-03 +1.568024E-05 +9.856570E-03 +1.373965E-05 +1.373503E-02 +2.764304E-05 +1.700784E-02 +3.483410E-05 +1.212809E-02 +2.883883E-05 +1.598449E-02 +4.084533E-05 +1.457711E-02 +2.808561E-05 +1.586485E-02 +3.242222E-05 +1.605131E-02 +4.105521E-05 +1.119495E-02 +1.615746E-05 +1.324399E-02 +2.727755E-05 +9.867968E-03 +1.269902E-05 +1.261254E-02 +2.302293E-05 +1.153152E-02 +1.778319E-05 +9.627863E-03 +1.562429E-05 +9.050432E-03 +2.011089E-05 +1.012233E-02 +1.405672E-05 +8.911922E-03 +1.231699E-05 +1.264744E-02 +3.182267E-05 +1.122935E-02 +1.396398E-05 +1.004271E-02 +2.482202E-05 +7.894125E-03 +1.026568E-05 +8.738637E-03 +1.294773E-05 +1.219349E-02 +2.177467E-05 +9.967898E-03 +1.619041E-05 +7.763622E-03 +1.314523E-05 +7.889504E-03 +1.517342E-05 +7.877888E-03 +9.676691E-06 +7.292674E-03 +8.328724E-06 +9.035083E-03 +1.302638E-05 +9.363679E-03 +1.575034E-05 +9.640810E-03 +1.648917E-05 +6.094059E-03 +5.041308E-06 +4.386721E-03 +4.583987E-06 +8.186442E-03 +1.162059E-05 +6.547204E-03 +5.040030E-06 +4.382851E-03 +3.779716E-06 +4.722787E-03 +2.981327E-06 +1.235870E-02 +2.314605E-05 +1.222127E-02 +2.292500E-05 +7.743975E-03 +1.242313E-05 +5.687154E-03 +5.021930E-06 +7.628599E-03 +1.334325E-05 +8.144837E-03 +9.544871E-06 +8.964376E-03 +1.242765E-05 +9.619105E-03 +1.533853E-05 +1.084215E-02 +2.414197E-05 +6.098310E-03 +6.403053E-06 +3.971375E-03 +2.559046E-06 +4.956486E-03 +4.314077E-06 +1.650323E-02 +3.308582E-05 +1.785233E-02 +4.022948E-05 +1.226233E-02 +2.222264E-05 +1.324548E-02 +2.290739E-05 +1.170726E-02 +2.043035E-05 +1.128481E-02 +1.783746E-05 +1.446854E-02 +2.465804E-05 +1.308709E-02 +2.086517E-05 +1.532165E-02 +3.175587E-05 +1.176741E-02 +2.528693E-05 +6.104662E-03 +5.418027E-06 +5.028482E-03 +7.038340E-06 +1.452720E-02 +2.907362E-05 +2.155983E-02 +5.793543E-05 +8.953378E-03 +1.144318E-05 +1.193284E-02 +1.941045E-05 +1.898089E-02 +4.676936E-05 +8.078140E-03 +1.008669E-05 +1.345743E-02 +3.010294E-05 +1.166065E-02 +2.971259E-05 +2.140319E-02 +6.942386E-05 +1.156518E-02 +2.123401E-05 +1.063148E-02 +1.679318E-05 +1.035058E-02 +1.786819E-05 +1.141576E-02 +1.488341E-05 +2.132304E-02 +6.407400E-05 +1.417013E-02 +2.428688E-05 +1.578758E-02 +4.383560E-05 +1.510669E-02 +4.330783E-05 +1.061421E-02 +2.120867E-05 +9.836246E-03 +1.836620E-05 +1.170301E-02 +2.304010E-05 +2.297562E-02 +7.378766E-05 +2.077496E-02 +6.096800E-05 +8.479570E-03 +1.315595E-05 +1.334700E-02 +2.778150E-05 +1.518804E-02 +2.768676E-05 +1.665283E-02 +3.264844E-05 +1.337650E-02 +2.908404E-05 +1.642169E-02 +3.787016E-05 +1.532468E-02 +3.092775E-05 +1.264533E-02 +1.889367E-05 +1.570062E-02 +2.982615E-05 +1.201853E-02 +1.991814E-05 +1.956945E-02 +4.268136E-05 +1.749406E-02 +3.890385E-05 +9.761579E-03 +1.266596E-05 +1.131974E-02 +1.669105E-05 +1.583139E-02 +3.408051E-05 +1.813736E-02 +4.024179E-05 +1.749162E-02 +4.075339E-05 +1.806084E-02 +4.998400E-05 +1.798603E-02 +3.527089E-05 +1.363365E-02 +2.545698E-05 +1.735765E-02 +3.680633E-05 +1.313196E-02 +2.758452E-05 +1.257866E-02 +2.792705E-05 +1.371026E-02 +2.875442E-05 +1.449637E-02 +2.956474E-05 +1.184945E-02 +2.021992E-05 +1.160263E-02 +1.677863E-05 +1.486874E-02 +2.727812E-05 +1.334215E-02 +2.696922E-05 +8.375076E-03 +1.127780E-05 +1.398722E-02 +2.987500E-05 +1.431399E-02 +2.337988E-05 +1.685216E-02 +4.010946E-05 +1.220900E-02 +2.279807E-05 +1.359371E-02 +3.406479E-05 +1.497337E-02 +3.514338E-05 +1.077240E-02 +1.570437E-05 +1.286688E-02 +2.067034E-05 +1.804016E-02 +3.897670E-05 +1.720304E-02 +3.923736E-05 +1.248667E-02 +2.229239E-05 +9.872479E-03 +1.547272E-05 +1.404898E-02 +3.940008E-05 +1.102828E-02 +2.118933E-05 +9.527731E-03 +1.232685E-05 +1.183452E-02 +2.230399E-05 +1.235818E-02 +2.095622E-05 +9.045793E-03 +1.310065E-05 +7.573693E-03 +7.912407E-06 +7.098140E-03 +1.002223E-05 +1.087704E-02 +1.644644E-05 +1.403508E-02 +2.293868E-05 +1.102953E-02 +2.108622E-05 +1.278029E-02 +2.765609E-05 +1.000153E-02 +1.489998E-05 +1.023204E-02 +1.425642E-05 +1.077781E-02 +1.616312E-05 +1.504135E-02 +3.226364E-05 +8.290904E-03 +1.302393E-05 +1.081631E-02 +1.596914E-05 +1.061779E-02 +1.936956E-05 +9.609920E-03 +1.233187E-05 +7.536017E-03 +8.104937E-06 +1.064514E-02 +1.960743E-05 +4.303700E-03 +3.157059E-06 +4.544730E-03 +3.063284E-06 +9.403522E-03 +1.530342E-05 +6.146303E-03 +5.481247E-06 +5.504300E-03 +4.029062E-06 +2.514628E-03 +2.046696E-06 +1.150234E-02 +3.434888E-05 +6.476274E-03 +8.282595E-06 +5.180114E-03 +8.533421E-06 +6.593161E-03 +7.470575E-06 +1.087271E-02 +2.875725E-05 +1.114108E-02 +1.774790E-05 +9.707234E-03 +2.320447E-05 +7.474544E-03 +7.620487E-06 +1.189904E-02 +1.770896E-05 +8.306981E-03 +1.023805E-05 +1.044243E-02 +2.358835E-05 +7.956950E-03 +1.442236E-05 +6.383279E-03 +9.306381E-06 +6.540012E-03 +7.870617E-06 +7.547221E-03 +8.818582E-06 +8.118902E-03 +1.018402E-05 +1.219458E-02 +2.121863E-05 +9.183066E-03 +1.021558E-05 +8.537042E-03 +2.163043E-05 +9.801780E-03 +1.896248E-05 +7.436543E-03 +6.348631E-06 +8.783038E-03 +1.450508E-05 +1.198218E-02 +2.299991E-05 +1.176673E-02 +1.772108E-05 +7.610905E-03 +1.295193E-05 +1.236441E-02 +2.279242E-05 +1.374811E-02 +2.984764E-05 +8.276450E-03 +9.063020E-06 +2.838721E-02 +8.556398E-05 +1.876318E-02 +4.502643E-05 +1.545136E-02 +3.024495E-05 +1.307062E-02 +3.391324E-05 +1.321284E-02 +2.975134E-05 +1.195812E-02 +2.014099E-05 +2.398471E-02 +7.682355E-05 +1.699635E-02 +4.513757E-05 +1.109010E-02 +1.505508E-05 +1.463044E-02 +3.130849E-05 +1.445299E-02 +3.424691E-05 +1.847738E-02 +4.339745E-05 +2.269521E-02 +6.754400E-05 +1.622681E-02 +3.412820E-05 +1.867140E-02 +4.737811E-05 +1.704633E-02 +5.070683E-05 +2.137995E-02 +5.989756E-05 +1.262222E-02 +2.579396E-05 +1.649755E-02 +3.278397E-05 +1.021540E-02 +1.333464E-05 +1.399361E-02 +4.091195E-05 +1.481283E-02 +2.778259E-05 +1.110529E-02 +1.543650E-05 +1.370454E-02 +2.585161E-05 +2.187939E-02 +5.698664E-05 +2.156023E-02 +5.655243E-05 +1.819754E-02 +4.650955E-05 +1.667214E-02 +4.523740E-05 +1.212974E-02 +1.755527E-05 +1.664077E-02 +4.676917E-05 +1.598420E-02 +3.367421E-05 +2.197091E-02 +6.311844E-05 +1.554809E-02 +4.350026E-05 +1.662573E-02 +3.639737E-05 +1.377054E-02 +2.979629E-05 +1.718171E-02 +6.738915E-05 +2.224715E-02 +5.208199E-05 +2.028701E-02 +5.025768E-05 +2.346558E-02 +7.283542E-05 +2.047816E-02 +5.352208E-05 +2.103499E-02 +5.936660E-05 +1.795967E-02 +4.651152E-05 +2.451667E-02 +7.714718E-05 +2.018245E-02 +4.706972E-05 +1.870240E-02 +5.089247E-05 +1.414303E-02 +2.510243E-05 +1.249731E-02 +1.910688E-05 +1.461191E-02 +2.931018E-05 +1.772779E-02 +3.502831E-05 +2.405954E-02 +7.243269E-05 +1.698120E-02 +5.235943E-05 +1.363172E-02 +2.557442E-05 +2.085610E-02 +5.559729E-05 +1.434576E-02 +2.498955E-05 +2.151921E-02 +5.863979E-05 +1.804978E-02 +3.738678E-05 +1.626456E-02 +3.204521E-05 +1.416110E-02 +2.454304E-05 +1.349966E-02 +2.225683E-05 +1.376360E-02 +2.288533E-05 +1.304562E-02 +2.360964E-05 +1.204823E-02 +2.235548E-05 +1.581808E-02 +3.833344E-05 +1.458683E-02 +2.424983E-05 +1.532417E-02 +3.313140E-05 +1.674514E-02 +3.698941E-05 +8.820684E-03 +1.237269E-05 +1.325954E-02 +2.839297E-05 +1.346247E-02 +2.329594E-05 +1.218804E-02 +2.010088E-05 +7.816904E-03 +8.061895E-06 +1.115974E-02 +1.481199E-05 +1.126424E-02 +1.437812E-05 +1.155465E-02 +2.043504E-05 +1.330918E-02 +2.482809E-05 +1.359646E-02 +2.349457E-05 +6.879034E-03 +6.482253E-06 +1.025078E-02 +1.436298E-05 +1.124296E-02 +1.766927E-05 +9.157794E-03 +1.732026E-05 +1.080917E-02 +1.759748E-05 +1.224046E-02 +1.895136E-05 +1.132499E-02 +1.940702E-05 +1.055316E-02 +1.421109E-05 +6.950077E-03 +8.886009E-06 +1.146153E-02 +2.328053E-05 +6.534133E-03 +9.046637E-06 +5.113551E-03 +7.352574E-06 +1.096783E-02 +1.762871E-05 +8.670928E-03 +1.642712E-05 +6.666016E-03 +7.936419E-06 +4.024813E-03 +3.317441E-06 +6.604655E-03 +6.471414E-06 +7.218922E-03 +7.914816E-06 +7.543650E-03 +1.006296E-05 +8.390292E-03 +1.280688E-05 +6.833212E-03 +9.885211E-06 +8.859184E-03 +1.491876E-05 +4.271802E-03 +4.619779E-06 +8.415017E-03 +1.758541E-05 +7.880304E-03 +1.207340E-05 +6.190265E-03 +5.244062E-06 +1.255358E-02 +3.409848E-05 +4.588111E-03 +6.615112E-06 +7.290138E-03 +8.053715E-06 +2.708550E-03 +1.222054E-06 +7.971324E-03 +1.019545E-05 +2.186309E-03 +3.012755E-06 +1.730168E-02 +4.007549E-05 +9.437870E-03 +1.374155E-05 +8.710815E-03 +1.058748E-05 +6.876864E-03 +1.161077E-05 +1.183718E-02 +2.088043E-05 +1.317392E-02 +2.144719E-05 +1.202134E-02 +2.244800E-05 +1.219063E-02 +1.871706E-05 +9.457262E-03 +1.576600E-05 +8.456836E-03 +1.009365E-05 +6.722846E-03 +7.231603E-06 +9.056257E-03 +1.228372E-05 +1.680554E-02 +5.472386E-05 +1.583876E-02 +4.084512E-05 +1.451889E-02 +2.656784E-05 +1.154750E-02 +2.200804E-05 +8.960773E-03 +1.608168E-05 +1.021117E-02 +2.175200E-05 +1.537603E-02 +3.295291E-05 +1.346321E-02 +3.199823E-05 +1.020297E-02 +2.083570E-05 +1.574785E-02 +3.797866E-05 +1.224712E-02 +2.543224E-05 +1.213857E-02 +2.596422E-05 +1.978514E-02 +5.572712E-05 +1.721724E-02 +3.343383E-05 +1.917708E-02 +6.017423E-05 +1.746870E-02 +4.670195E-05 +1.601664E-02 +3.757776E-05 +1.391434E-02 +2.787908E-05 +2.112923E-02 +6.179734E-05 +1.494974E-02 +3.147270E-05 +2.027112E-02 +5.409774E-05 +1.762825E-02 +3.716705E-05 +1.490183E-02 +2.636325E-05 +1.144233E-02 +1.895260E-05 +2.252480E-02 +6.008716E-05 +2.061068E-02 +4.967689E-05 +1.978565E-02 +5.823807E-05 +1.627207E-02 +3.508510E-05 +2.308648E-02 +7.339685E-05 +9.920567E-03 +1.588060E-05 +1.582116E-02 +3.710173E-05 +1.359849E-02 +3.693990E-05 +2.449553E-02 +7.939873E-05 +1.712995E-02 +3.401990E-05 +1.578519E-02 +2.835653E-05 +1.996773E-02 +5.153308E-05 +1.784633E-02 +3.372557E-05 +2.328886E-02 +7.016669E-05 +1.908795E-02 +5.601183E-05 +2.149293E-02 +6.345938E-05 +2.432779E-02 +7.634443E-05 +2.394049E-02 +6.577991E-05 +1.506740E-02 +3.094281E-05 +1.388336E-02 +2.886613E-05 +1.614618E-02 +3.561899E-05 +1.595134E-02 +4.065708E-05 +1.340027E-02 +2.204671E-05 +1.472267E-02 +2.861240E-05 +1.790210E-02 +5.856300E-05 +2.646480E-02 +1.056654E-04 +1.880864E-02 +4.142515E-05 +1.426154E-02 +2.963840E-05 +1.165132E-02 +2.176252E-05 +1.428324E-02 +2.725319E-05 +1.588976E-02 +3.970327E-05 +1.833160E-02 +4.559784E-05 +1.772585E-02 +4.748240E-05 +1.848953E-02 +5.090661E-05 +1.272374E-02 +2.030829E-05 +1.412613E-02 +3.146328E-05 +1.649479E-02 +4.133012E-05 +1.209661E-02 +4.450673E-05 +1.369084E-02 +2.392580E-05 +1.531641E-02 +3.089017E-05 +1.580566E-02 +3.194323E-05 +1.132108E-02 +1.399526E-05 +8.190342E-03 +9.145143E-06 +7.902353E-03 +1.504796E-05 +1.258132E-02 +2.292738E-05 +6.958024E-03 +9.709387E-06 +1.037667E-02 +1.407859E-05 +1.201319E-02 +2.053522E-05 +9.379406E-03 +1.510952E-05 +1.279685E-02 +2.736611E-05 +1.191802E-02 +2.186093E-05 +6.155316E-03 +6.209415E-06 +8.817944E-03 +1.322568E-05 +7.497837E-03 +1.365620E-05 +9.976490E-03 +1.734874E-05 +7.558291E-03 +1.424385E-05 +8.801002E-03 +1.425950E-05 +9.075301E-03 +1.401503E-05 +5.681746E-03 +5.798447E-06 +4.827386E-03 +3.466370E-06 +5.884691E-03 +5.754861E-06 +1.211858E-02 +2.621006E-05 +5.629512E-03 +6.112612E-06 +5.768978E-03 +5.711093E-06 +1.075576E-02 +1.954724E-05 +5.977668E-03 +7.957209E-06 +6.775985E-03 +8.582096E-06 +3.503043E-03 +2.684132E-06 +8.113430E-03 +1.099167E-05 +8.263729E-03 +1.412028E-05 +3.781179E-03 +3.287824E-06 +8.368219E-03 +9.803361E-06 +1.068347E-02 +1.390398E-05 +1.118234E-02 +1.591023E-05 +1.016006E-02 +2.761365E-05 +6.634695E-03 +7.415821E-06 +1.042368E-02 +1.700083E-05 +1.024339E-02 +1.630692E-05 +5.465831E-03 +6.271754E-06 +1.117655E-02 +1.998616E-05 +8.708982E-03 +1.145629E-05 +3.321055E-03 +3.386533E-06 +8.951176E-03 +1.175568E-05 +7.413974E-03 +1.358203E-05 +1.289235E-02 +2.359140E-05 +9.817553E-03 +1.518261E-05 +9.879433E-03 +1.602972E-05 +1.177378E-02 +2.259438E-05 +5.796294E-03 +6.245744E-06 +1.138092E-02 +2.136416E-05 +8.927027E-03 +9.348267E-06 +9.673957E-03 +1.246216E-05 +1.280715E-02 +4.429778E-05 +8.808327E-03 +1.178528E-05 +7.125501E-03 +7.483806E-06 +4.620428E-03 +9.310180E-06 +1.680437E-02 +3.451199E-05 +2.026938E-02 +4.346902E-05 +1.635252E-02 +5.026111E-05 +1.278583E-02 +2.192134E-05 +1.301566E-02 +2.384432E-05 +9.286694E-03 +1.400657E-05 +1.107901E-02 +1.953576E-05 +1.150656E-02 +2.102378E-05 +1.772830E-02 +3.480088E-05 +1.063150E-02 +1.401509E-05 +1.374475E-02 +2.299888E-05 +6.867995E-03 +1.027748E-05 +1.580376E-02 +3.847030E-05 +1.668637E-02 +3.953893E-05 +1.442844E-02 +3.008408E-05 +1.827058E-02 +4.753438E-05 +1.440759E-02 +3.206648E-05 +1.592968E-02 +4.677348E-05 +1.718273E-02 +3.488836E-05 +1.688712E-02 +4.196255E-05 +2.047044E-02 +4.959256E-05 +1.306218E-02 +3.057713E-05 +8.848692E-03 +1.833823E-05 +1.117548E-02 +2.553563E-05 +2.169142E-02 +6.306137E-05 +2.218276E-02 +5.572871E-05 +1.802302E-02 +4.705313E-05 +1.782656E-02 +4.017437E-05 +1.925947E-02 +4.703183E-05 +1.641263E-02 +3.693267E-05 +1.516396E-02 +3.126646E-05 +1.512145E-02 +3.336386E-05 +1.579023E-02 +3.449473E-05 +1.368503E-02 +3.144328E-05 +1.108096E-02 +1.983330E-05 +1.447670E-02 +3.832266E-05 +1.831886E-02 +3.928136E-05 +1.893457E-02 +5.869250E-05 +1.764892E-02 +5.005397E-05 +1.637340E-02 +3.702753E-05 +9.686698E-03 +1.449037E-05 +1.006947E-02 +1.933484E-05 +1.884484E-02 +4.561680E-05 +1.468883E-02 +2.792875E-05 +1.670400E-02 +3.477624E-05 +1.632153E-02 +3.402425E-05 +9.187335E-03 +1.053828E-05 +9.985824E-03 +1.585776E-05 +1.303759E-02 +3.027649E-05 +1.872005E-02 +5.130980E-05 +1.633753E-02 +4.260466E-05 +1.020425E-02 +1.707335E-05 +1.320758E-02 +2.695180E-05 +1.208449E-02 +3.007055E-05 +1.286574E-02 +2.373357E-05 +1.095090E-02 +2.877553E-05 +1.692473E-02 +4.961965E-05 +1.190920E-02 +2.375507E-05 +5.682089E-03 +4.636856E-06 +1.035844E-02 +1.997872E-05 +9.666688E-03 +1.483243E-05 +1.613905E-02 +3.984840E-05 +1.572095E-02 +3.368762E-05 +1.108904E-02 +1.539438E-05 +1.486260E-02 +4.070529E-05 +1.042750E-02 +1.813263E-05 +1.042360E-02 +1.689881E-05 +8.718623E-03 +1.199955E-05 +1.039440E-02 +1.674301E-05 +5.162509E-03 +6.408708E-06 +9.563193E-03 +1.362142E-05 +6.648598E-03 +1.021485E-05 +1.122742E-02 +1.540873E-05 +7.837929E-03 +1.128828E-05 +1.114590E-02 +2.553030E-05 +1.141215E-02 +2.510840E-05 +1.152836E-02 +2.344713E-05 +7.971937E-03 +1.506387E-05 +1.248527E-02 +2.125446E-05 +6.066628E-03 +9.574143E-06 +1.087280E-02 +1.688717E-05 +9.550524E-03 +1.250483E-05 +5.306519E-03 +4.846453E-06 +7.512202E-03 +8.651766E-06 +7.508820E-03 +8.634705E-06 +5.185887E-03 +4.163304E-06 +1.379038E-02 +3.492367E-05 +9.235196E-03 +1.206055E-05 +1.392051E-02 +3.803496E-05 +7.049846E-03 +9.147756E-06 +5.323140E-03 +4.281730E-06 +8.229124E-03 +1.548991E-05 +7.235167E-03 +1.441034E-05 +2.366009E-03 +3.874657E-06 +5.945679E-03 +1.067197E-05 +5.871383E-03 +5.656813E-06 +9.732147E-03 +2.269675E-05 +6.582049E-03 +7.833573E-06 +3.066363E-03 +3.098185E-06 +5.796032E-03 +6.625438E-06 +8.122368E-03 +9.655803E-06 +1.121766E-02 +1.750086E-05 +1.036527E-02 +1.842391E-05 +5.944076E-03 +6.439480E-06 +2.283818E-03 +1.352210E-06 +1.446587E-03 +7.807258E-07 +4.944507E-03 +3.694344E-06 +3.281169E-03 +2.925608E-06 +9.286754E-03 +1.260048E-05 +1.272772E-02 +2.464058E-05 +1.270753E-02 +3.173555E-05 +1.419952E-02 +2.835999E-05 +9.671107E-03 +1.686465E-05 +9.583433E-03 +1.323773E-05 +1.186931E-02 +2.163029E-05 +1.267789E-02 +2.021594E-05 +8.275560E-03 +9.163723E-06 +1.062420E-02 +1.977462E-05 +1.198470E-02 +1.979838E-05 +1.324773E-02 +2.853129E-05 +1.727253E-02 +3.432691E-05 +1.381997E-02 +2.842333E-05 +1.578301E-02 +3.356518E-05 +1.555696E-02 +3.183947E-05 +8.166265E-03 +8.629223E-06 +1.747785E-02 +4.250397E-05 +9.541135E-03 +1.246077E-05 +1.393808E-02 +3.012112E-05 +1.209324E-02 +2.429593E-05 +1.079402E-02 +2.325836E-05 +1.374417E-02 +2.491779E-05 +9.500289E-03 +1.572888E-05 +1.222769E-02 +2.456217E-05 +1.097825E-02 +1.938425E-05 +1.410107E-02 +2.407486E-05 +2.024375E-02 +6.980050E-05 +1.220648E-02 +3.245536E-05 +1.137633E-02 +1.667373E-05 +1.038617E-02 +1.405080E-05 +1.243797E-02 +2.413125E-05 +9.998308E-03 +1.605906E-05 +8.805567E-03 +1.128015E-05 +1.388695E-02 +3.039013E-05 +1.242352E-02 +2.040627E-05 +2.645008E-02 +8.679965E-05 +2.076456E-02 +5.640973E-05 +1.805209E-02 +4.120924E-05 +1.246120E-02 +3.006639E-05 +1.810150E-02 +4.756486E-05 +1.472448E-02 +3.309142E-05 +2.571400E-02 +8.648041E-05 +1.341319E-02 +3.280431E-05 +1.535941E-02 +4.819536E-05 +2.373309E-02 +7.918529E-05 +5.757795E-03 +4.733061E-06 +1.174264E-02 +2.108284E-05 +1.884131E-02 +4.721518E-05 +1.750610E-02 +4.223243E-05 +1.716739E-02 +3.617002E-05 +1.252851E-02 +2.099071E-05 +1.388277E-02 +3.109337E-05 +1.350362E-02 +3.082057E-05 +1.238489E-02 +3.728424E-05 +9.966253E-03 +2.035860E-05 +2.285240E-02 +8.446864E-05 +1.327084E-02 +3.045931E-05 +1.193699E-02 +2.204142E-05 +6.923219E-03 +9.602029E-06 +1.838247E-02 +4.807008E-05 +1.863076E-02 +4.604209E-05 +1.334000E-02 +2.761396E-05 +1.141315E-02 +2.474696E-05 +2.286809E-02 +1.083380E-04 +1.645875E-02 +3.520343E-05 +1.229791E-02 +2.380600E-05 +1.284486E-02 +2.254139E-05 +1.854605E-02 +4.752272E-05 +1.049692E-02 +1.983824E-05 +7.207727E-03 +7.286730E-06 +1.686364E-02 +3.977916E-05 +1.314115E-02 +2.189974E-05 +1.520236E-02 +3.635654E-05 +1.096706E-02 +2.475645E-05 +7.932651E-03 +1.085523E-05 +1.515150E-02 +4.556316E-05 +1.171402E-02 +3.284784E-05 +1.087897E-02 +1.567310E-05 +8.199381E-03 +9.564718E-06 +9.456870E-03 +1.207744E-05 +8.827517E-03 +1.658191E-05 +5.512807E-03 +6.038391E-06 +8.573999E-03 +1.207656E-05 +1.047145E-02 +1.674083E-05 +9.666379E-03 +1.231732E-05 +1.046000E-02 +1.782331E-05 +6.009504E-03 +6.261797E-06 +1.111917E-02 +1.768100E-05 +1.105060E-02 +1.934982E-05 +5.280218E-03 +7.191057E-06 +7.637218E-03 +9.728555E-06 +1.009144E-02 +1.219856E-05 +4.974619E-03 +4.499916E-06 +6.589686E-03 +1.040697E-05 +7.787208E-03 +1.023212E-05 +6.068811E-03 +5.842725E-06 +3.416649E-03 +3.146550E-06 +9.213350E-03 +2.154615E-05 +6.752158E-03 +9.801770E-06 +4.758057E-03 +6.649209E-06 +6.129868E-03 +8.342508E-06 +2.783932E-03 +2.140712E-06 +6.308493E-03 +1.039901E-05 +2.249137E-03 +1.153739E-06 +2.514780E-03 +1.593412E-06 +6.018183E-03 +8.965827E-06 +3.234291E-03 +2.042484E-06 +7.860270E-03 +1.035245E-05 +3.414591E-03 +2.249770E-06 +7.941000E-03 +1.449758E-05 +3.591791E-03 +2.245391E-06 +7.807797E-03 +1.011270E-05 +7.726893E-03 +1.478217E-05 +2.506930E-03 +2.954554E-06 +5.955023E-03 +7.260418E-06 +5.294809E-03 +8.225926E-06 +2.802166E-03 +1.996795E-06 +2.404798E-03 +1.266950E-06 +4.125341E-03 +2.979146E-06 +7.417991E-03 +8.566910E-06 +8.158248E-03 +1.230927E-05 +7.976311E-03 +1.332178E-05 +8.873852E-03 +1.480843E-05 +9.373684E-03 +1.259336E-05 +8.214068E-03 +1.186084E-05 +6.962685E-03 +7.715598E-06 +8.834013E-03 +1.972166E-05 +5.435947E-03 +4.590835E-06 +5.487949E-03 +5.939754E-06 +6.678491E-03 +8.355182E-06 +4.058912E-03 +5.880001E-06 +1.360573E-02 +2.671641E-05 +1.143610E-02 +2.018223E-05 +7.702740E-03 +1.433952E-05 +5.873725E-03 +6.789166E-06 +1.088086E-02 +3.437425E-05 +7.089361E-03 +1.461407E-05 +8.765624E-03 +1.242854E-05 +9.453645E-03 +1.575322E-05 +1.001462E-02 +1.448625E-05 +1.282490E-02 +2.290074E-05 +8.545890E-03 +1.273760E-05 +7.387390E-03 +9.140356E-06 +1.399357E-02 +2.449459E-05 +1.337581E-02 +3.113825E-05 +1.423915E-02 +2.729711E-05 +6.580885E-03 +8.347839E-06 +7.779718E-03 +1.007558E-05 +7.480792E-03 +1.083253E-05 +1.275448E-02 +2.722719E-05 +1.292106E-02 +2.421066E-05 +9.755948E-03 +1.426055E-05 +9.117272E-03 +1.368142E-05 +7.455531E-03 +8.688003E-06 +1.042236E-02 +1.801425E-05 +1.296287E-02 +2.809397E-05 +1.390180E-02 +2.674920E-05 +1.265490E-02 +3.041327E-05 +1.269961E-02 +2.824134E-05 +1.133938E-02 +1.625519E-05 +9.821144E-03 +2.178670E-05 +1.530578E-02 +3.585772E-05 +1.299672E-02 +2.588612E-05 +1.544212E-02 +3.143850E-05 +8.347818E-03 +1.132876E-05 +1.393101E-02 +2.890996E-05 +6.639867E-03 +7.587375E-06 +1.839132E-02 +4.637735E-05 +1.188258E-02 +1.953879E-05 +1.588672E-02 +3.134987E-05 +1.425154E-02 +2.751603E-05 +4.920276E-03 +4.432356E-06 +1.374206E-02 +2.842285E-05 +1.673110E-02 +4.601232E-05 +1.254973E-02 +2.188833E-05 +6.444727E-03 +5.222041E-06 +1.023529E-02 +1.572480E-05 +1.087382E-02 +1.692895E-05 +9.038702E-03 +1.572012E-05 +1.398299E-02 +2.818260E-05 +8.766186E-03 +1.494609E-05 +1.321841E-02 +2.007819E-05 +1.562133E-02 +3.892744E-05 +8.289134E-03 +1.177987E-05 +8.947084E-03 +1.094585E-05 +1.594810E-02 +3.949297E-05 +1.285384E-02 +2.278617E-05 +5.689452E-03 +7.280228E-06 +9.766401E-03 +2.148390E-05 +8.496573E-03 +8.437729E-06 +7.991945E-03 +9.550933E-06 +9.608813E-03 +1.425597E-05 +1.052303E-02 +1.935336E-05 +8.548009E-03 +1.333735E-05 +7.337588E-03 +9.975447E-06 +1.423505E-02 +3.258201E-05 +1.136654E-02 +2.510870E-05 +7.860115E-03 +8.206414E-06 +8.309608E-03 +1.504702E-05 +1.110051E-02 +2.051470E-05 +6.172688E-03 +9.409184E-06 +9.740436E-03 +1.437599E-05 +8.997021E-03 +1.150131E-05 +1.279849E-02 +3.206319E-05 +1.028663E-02 +1.505898E-05 +1.122879E-02 +1.673337E-05 +8.223903E-03 +9.720008E-06 +8.464761E-03 +1.103940E-05 +6.670166E-03 +6.071848E-06 +4.620811E-03 +6.527856E-06 +3.824735E-03 +3.340845E-06 +5.634323E-03 +5.012909E-06 +3.166012E-03 +3.619323E-06 +9.167802E-03 +1.056621E-05 +3.221327E-03 +1.773076E-06 +5.412502E-03 +5.413007E-06 +6.702745E-03 +8.187361E-06 +4.863392E-03 +3.807791E-06 +4.405641E-03 +4.058186E-06 +6.131083E-03 +7.250341E-06 +4.913764E-03 +5.744987E-06 +4.588314E-03 +3.202328E-06 +6.804591E-03 +8.479426E-06 +7.252910E-03 +8.758909E-06 +4.312950E-03 +3.434388E-06 +1.807777E-03 +1.380521E-06 +4.671070E-03 +5.538033E-06 +7.067950E-03 +1.174764E-05 +2.930719E-03 +1.441738E-06 +1.279222E-03 +1.078804E-06 +3.507572E-03 +5.821750E-06 +9.678721E-03 +2.476852E-05 +2.874671E-03 +2.470595E-06 +2.182691E-03 +1.629987E-06 +3.621537E-03 +9.191521E-06 +1.740159E-03 +6.544183E-07 +3.203873E-03 +3.602845E-06 +2.890800E-03 +2.526106E-06 +3.068561E-03 +4.213711E-06 +6.078860E-03 +7.760574E-06 +7.287103E-03 +7.524310E-06 +7.509754E-03 +2.547783E-05 +2.646412E-03 +2.157075E-06 +6.255289E-03 +6.947406E-06 +4.941751E-03 +7.943248E-06 +9.224779E-03 +1.410566E-05 +4.906800E-03 +4.350073E-06 +7.923221E-03 +1.421559E-05 +2.900094E-03 +1.652857E-06 +3.445014E-03 +1.996755E-06 +2.978919E-03 +3.704572E-06 +8.310828E-03 +1.128557E-05 +8.914816E-03 +1.105293E-05 +6.453823E-03 +7.530365E-06 +8.529848E-03 +1.250596E-05 +1.241639E-02 +1.968019E-05 +3.654989E-03 +2.852818E-06 +6.194753E-03 +4.637962E-06 +7.168410E-03 +9.747482E-06 +7.074135E-03 +8.723001E-06 +3.088414E-03 +2.165114E-06 +4.736900E-03 +4.690360E-06 +5.496866E-03 +6.084993E-06 +9.992636E-03 +2.331975E-05 +5.785665E-03 +9.290287E-06 +9.268775E-03 +1.727651E-05 +1.110749E-02 +2.320101E-05 +6.035119E-03 +6.006884E-06 +6.097186E-03 +8.477525E-06 +9.286855E-03 +1.325325E-05 +5.725710E-03 +5.595748E-06 +5.225326E-03 +5.682741E-06 +8.374162E-03 +1.358989E-05 +8.070266E-03 +8.525794E-06 +5.663014E-03 +8.326352E-06 +1.077577E-02 +1.774824E-05 +6.823384E-03 +7.461723E-06 +1.309151E-02 +2.293933E-05 +9.734117E-03 +1.567869E-05 +1.064840E-02 +1.998801E-05 +6.598548E-03 +1.247960E-05 +8.533419E-03 +1.698271E-05 +1.187770E-02 +2.246194E-05 +3.905374E-03 +2.559130E-06 +2.608870E-03 +1.558560E-06 +6.052893E-03 +5.374399E-06 +5.291540E-03 +8.103686E-06 +7.976421E-03 +1.021030E-05 +9.757093E-03 +1.668583E-05 +7.385489E-03 +1.285403E-05 +7.929263E-03 +7.987788E-06 +9.704986E-03 +2.962975E-05 +7.525077E-03 +1.306302E-05 +6.991034E-03 +1.064873E-05 +5.005358E-03 +9.835012E-06 +8.092808E-03 +1.147394E-05 +4.474087E-03 +3.834905E-06 +6.834524E-03 +6.982199E-06 +4.812916E-03 +4.467796E-06 +5.990512E-03 +7.842268E-06 +4.574709E-03 +3.970763E-06 +4.788106E-03 +3.924811E-06 +8.916249E-03 +1.850608E-05 +5.259665E-03 +8.293438E-06 +9.696546E-03 +1.517672E-05 +4.590212E-03 +5.096431E-06 +7.314462E-03 +1.714769E-05 +3.860185E-03 +3.127895E-06 +1.784310E-03 +9.235975E-07 +5.547235E-03 +5.112055E-06 +5.865507E-03 +6.708947E-06 +4.328438E-03 +4.229047E-06 +5.092655E-03 +5.828910E-06 +6.709671E-03 +7.080990E-06 +4.327802E-03 +3.188523E-06 +4.937391E-03 +4.569445E-06 +8.293491E-03 +1.319561E-05 +3.930138E-03 +6.730814E-06 +4.416256E-03 +4.105889E-06 +3.467315E-03 +2.354469E-06 +5.332491E-03 +9.029639E-06 +2.694692E-03 +1.279641E-06 +5.342987E-03 +6.713119E-06 +7.519588E-03 +1.092346E-05 +5.285743E-03 +5.723628E-06 +6.665656E-03 +8.544653E-06 +3.846760E-03 +2.666108E-06 +6.284377E-03 +9.724369E-06 +6.196868E-03 +8.329996E-06 +5.286331E-03 +6.920429E-06 +7.052727E-03 +1.143953E-05 +5.029353E-03 +3.735294E-06 +2.407489E-03 +2.444788E-06 +4.133935E-04 +9.497986E-08 +6.027018E-03 +1.025712E-05 +3.598018E-03 +3.018229E-06 +4.613658E-03 +4.076030E-06 +3.342670E-03 +3.029962E-06 +3.733008E-03 +2.515848E-06 +5.141865E-03 +9.007182E-06 +7.728541E-03 +1.349554E-05 +1.579734E-03 +1.531714E-06 +3.519217E-03 +3.673203E-06 +5.032814E-03 +4.394432E-06 +1.399643E-03 +6.119406E-07 +3.930826E-03 +4.507517E-06 +4.767309E-03 +5.014044E-06 diff --git a/tests/regression_tests/unstructured_mesh/test.py b/tests/regression_tests/unstructured_mesh/test.py index 7607531d8..9ed36c69c 100644 --- a/tests/regression_tests/unstructured_mesh/test.py +++ b/tests/regression_tests/unstructured_mesh/test.py @@ -86,18 +86,6 @@ class UnstructuredMeshTest(PyAPITestHarness): data.shape = (data.size, 1) return np.sum(data, axis=1) - def update_results(self): - """Update results_true.dat and inputs_true.dat""" - try: - self._build_inputs() - inputs = self._get_inputs() - self._write_inputs(inputs) - self._overwrite_inputs() - self._run_openmc() - self._test_output_created() - finally: - self._cleanup() - def _cleanup(self): super()._cleanup() output = glob.glob('tally*.vtk') @@ -231,7 +219,7 @@ def model(): space = openmc.stats.SphericalIndependent(r, cos_theta, phi) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.IndependentSource(space=space, energy=energy) + source = openmc.Source(space=space, energy=energy) settings.source = source model.settings = settings @@ -256,7 +244,7 @@ for i, (lib, estimator, ext_geom, holes) in enumerate(product(*param_values)): def test_unstructured_mesh_tets(model, test_opts): # skip the test if the library is not enabled if test_opts['library'] == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip("DAGMC (and MOAB) mesh not enabled in this build.") + pytest.skip("DAGMC (and MOAB) mesh not enbaled in this build.") if test_opts['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): pytest.skip("LibMesh is not enabled in this build.") @@ -277,8 +265,6 @@ def test_unstructured_mesh_tets(model, test_opts): # add analagous unstructured mesh tally uscd_mesh = openmc.UnstructuredMesh(mesh_filename, test_opts['library']) - if test_opts['library'] == 'moab': - uscd_mesh.options = 'MAX_DEPTH=15;PLANE_SET=2' uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) # create tallies @@ -324,3 +310,4 @@ def test_unstructured_mesh_hexes(model): harness.ELEM_PER_VOXEL = 1 harness.main() + diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_dagmc_tets.vtk b/tests/regression_tests/unstructured_mesh/test_mesh_dagmc_tets.vtk deleted file mode 100644 index 2ddd228cf..000000000 --- a/tests/regression_tests/unstructured_mesh/test_mesh_dagmc_tets.vtk +++ /dev/null @@ -1,159 +0,0 @@ -# vtk DataFile Version 2.0 -made_with_cad_to_dagmc_package, Created by Gmsh 4.12.1 -ASCII -DATASET UNSTRUCTURED_GRID -POINTS 14 double --0.5 -0.5 0.5 --0.5 -0.5 -0.5 --0.5 0.5 0.5 --0.5 0.5 -0.5 -0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 --0.5 0 0 -0.5 0 0 -0 -0.5 0 -0 0.5 0 -0 0 -0.5 -0 0 0.5 - -CELLS 68 268 -1 0 -1 1 -1 2 -1 3 -1 4 -1 5 -1 6 -1 7 -2 1 0 -2 0 2 -2 3 2 -2 1 3 -2 5 4 -2 4 6 -2 7 6 -2 5 7 -2 1 5 -2 0 4 -2 3 7 -2 2 6 -3 1 0 8 -3 0 2 8 -3 3 1 8 -3 2 3 8 -3 5 9 4 -3 4 9 6 -3 7 9 5 -3 6 9 7 -3 0 1 10 -3 4 0 10 -3 1 5 10 -3 5 4 10 -3 2 11 3 -3 6 11 2 -3 3 11 7 -3 7 11 6 -3 1 3 12 -3 5 1 12 -3 3 7 12 -3 7 5 12 -3 0 13 2 -3 4 13 0 -3 2 13 6 -3 6 13 4 -4 13 8 12 10 -4 11 8 12 13 -4 12 11 13 9 -4 10 12 13 9 -4 12 3 11 7 -4 13 2 8 0 -4 8 12 1 3 -4 11 3 8 2 -4 10 8 1 0 -4 0 10 13 4 -4 1 12 10 5 -4 11 2 13 6 -4 4 9 13 6 -4 6 9 11 7 -4 10 9 4 5 -4 7 9 12 5 -4 3 8 12 11 -4 1 12 8 10 -4 8 11 2 13 -4 10 13 8 0 -4 13 10 9 4 -4 11 13 9 6 -4 12 11 9 7 -4 9 10 12 5 - -CELL_TYPES 68 -1 -1 -1 -1 -1 -1 -1 -1 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 diff --git a/tests/regression_tests/void/inputs_true.dat b/tests/regression_tests/void/inputs_true.dat index cd2d14206..644952097 100644 --- a/tests/regression_tests/void/inputs_true.dat +++ b/tests/regression_tests/void/inputs_true.dat @@ -1,131 +1,132 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 3 - - - 0.0 0.0 0.0 - - - - - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 - - - 1 - total - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 3 + + + 0.0 0.0 0.0 + + + + + + + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 + + + 1 + total + + diff --git a/tests/regression_tests/void/test.py b/tests/regression_tests/void/test.py index 76c15eb39..af1e3887b 100644 --- a/tests/regression_tests/void/test.py +++ b/tests/regression_tests/void/test.py @@ -23,7 +23,7 @@ def model(): model.settings.run_mode = 'fixed source' model.settings.batches = 3 model.settings.particles = 1000 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + model.settings.source = openmc.Source(space=openmc.stats.Point()) cell_filter = openmc.CellFilter(cells) tally = openmc.Tally() diff --git a/tests/regression_tests/volume_calc/inputs_true.dat b/tests/regression_tests/volume_calc/inputs_true.dat index ed7024c57..aaf6d8b00 100644 --- a/tests/regression_tests/volume_calc/inputs_true.dat +++ b/tests/regression_tests/volume_calc/inputs_true.dat @@ -1,75 +1,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - volume - - cell - 1 2 3 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - material - 1 2 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - universe - 0 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - cell - 1 2 3 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - material - 1 2 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - cell - 1 2 3 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + volume + + cell + 1 2 3 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + material + 1 2 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + universe + 0 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + material + 1 2 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + diff --git a/tests/regression_tests/volume_calc/inputs_true_mg.dat b/tests/regression_tests/volume_calc/inputs_true_mg.dat index 127566084..21c2a9834 100644 --- a/tests/regression_tests/volume_calc/inputs_true_mg.dat +++ b/tests/regression_tests/volume_calc/inputs_true_mg.dat @@ -1,76 +1,76 @@ - - - mg_lib.h5 - - - - - - - - - - - - - - - - - - - - - - - - volume - multi-group - - cell - 1 2 3 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - material - 1 2 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - universe - 0 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - cell - 1 2 3 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - material - 1 2 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - cell - 1 2 3 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - + + + + + + + + + + + + + mg_lib.h5 + + + + + + + + + + + + + + + volume + multi-group + + cell + 1 2 3 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + material + 1 2 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + universe + 0 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + material + 1 2 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index c94d16c79..e04eac7ff 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -21,6 +21,7 @@ class VolumeTest(PyAPITestHarness): if not is_ce: self.inputs_true = 'inputs_true_mg.dat' + def _build_inputs(self): # Define materials water = openmc.Material(1) water.add_nuclide('H1', 2.0) @@ -38,7 +39,7 @@ class VolumeTest(PyAPITestHarness): materials = openmc.Materials((water, fuel)) if not self.is_ce: materials.cross_sections = 'mg_lib.h5' - self._model.materials = materials + materials.export_to_xml() cyl = openmc.ZCylinder(surface_id=1, r=1.0, boundary_type='vacuum') top_sphere = openmc.Sphere(surface_id=2, z0=5., r=1., boundary_type='vacuum') @@ -52,7 +53,8 @@ class VolumeTest(PyAPITestHarness): bottom_hemisphere = openmc.Cell(3, fill=water, region=-bottom_sphere & -top_plane) root = openmc.Universe(0, cells=(inside_cyl, top_hemisphere, bottom_hemisphere)) - self._model.geometry = openmc.Geometry(root) + geometry = openmc.Geometry(root) + geometry.export_to_xml() # Set up stochastic volume calculation ll, ur = root.bounding_box @@ -77,7 +79,7 @@ class VolumeTest(PyAPITestHarness): if not self.is_ce: settings.energy_mode = 'multi-group' settings.volume_calculations = vol_calcs - self._model.settings = settings + settings.export_to_xml() # Create the MGXS file if necessary if not self.is_ce: @@ -168,5 +170,5 @@ class VolumeTest(PyAPITestHarness): @pytest.mark.parametrize('is_ce', [True, False]) def test_volume_calc(is_ce): - harness = VolumeTest(is_ce, '', model=openmc.Model()) + harness = VolumeTest(is_ce, '') harness.main() diff --git a/tests/regression_tests/weightwindows/generators/__init__.py b/tests/regression_tests/weightwindows/generators/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/weightwindows/generators/test.py b/tests/regression_tests/weightwindows/generators/test.py deleted file mode 100644 index 4dc0ab80d..000000000 --- a/tests/regression_tests/weightwindows/generators/test.py +++ /dev/null @@ -1,61 +0,0 @@ -import os - -import numpy as np -import openmc -import pytest - - -def test_ww_generator(run_in_tmpdir): - # create a simple spherical shield model - model = openmc.Model() - - water = openmc.Material() - water.set_density('g/cc', 1.0) - water.add_nuclide('H1', 0.66) - water.add_nuclide('O16', 0.34) - - s = openmc.Sphere(r=50, boundary_type='vacuum') - c = openmc.Cell(fill=water, region=-s) - - model.geometry = openmc.Geometry([c]) - - model.settings.particles = 500 - model.settings.batches = 5 - model.settings.run_mode = 'fixed source' - model.settings.max_history_splits = 100 - - mesh = openmc.RegularMesh.from_domain(model.geometry.root_universe) - energy_bounds = np.linspace(0.0, 1e6, 70) - particle = 'neutron' - - # include another tally to make sure user-specified tallies and those automaticaly - # created by weight window generators can coexist - tally = openmc.Tally() - ef = openmc.EnergyFilter(energy_bounds) - tally.filters = [ef] - tally.scores = ['flux'] - model.tallies = [tally] - - wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle) - wwg.update_parameters = {'ratio': 5.0, 'threshold': 0.8, 'value': 'mean'} - - model.settings.weight_window_generators = wwg - model.run() - - # we test the effectiveness of the update method elsewhere, so - # just test that the generation happens successfully here - assert os.path.exists('weight_windows.h5') - - wws_mean = openmc.WeightWindowsList.from_hdf5() - assert len(wws_mean) == 1 - - # check that generation using the relative error works too - wwg.update_parameters['value'] = 'rel_err' - model.run() - - wws_rel_err = openmc.WeightWindowsList.from_hdf5() - assert len(wws_rel_err) == 1 - - # we should not get the same set of weight windows when switching to use of - # rel. err. - assert (wws_mean[0].lower_ww_bounds != wws_rel_err[0].lower_ww_bounds).any() diff --git a/tests/regression_tests/weightwindows/inputs_true.dat b/tests/regression_tests/weightwindows/inputs_true.dat new file mode 100644 index 000000000..e6a0ad55f --- /dev/null +++ b/tests/regression_tests/weightwindows/inputs_true.dat @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 200 + 2 + + + 0.001 0.001 0.001 + + + 14000000.0 1.0 + + + true + + 2 + neutron + 0.0 0.5 20000000.0 + -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 7.695031155172816e-14 -1.0 7.476545089278482e-06 -1.0 2.1612150425221703e-06 -1.0 -1.0 -1.0 2.1360401784344975e-18 -1.0 1.3455341306162382e-05 -1.0 3.353295403842037e-05 -1.0 3.0160758454323657e-07 -1.0 1.0262431550731535e-13 -1.0 1.6859219614058024e-19 -1.0 3.853097455417877e-06 -1.0 4.354946981329799e-05 -1.0 7.002861620919232e-08 -1.0 -1.0 -1.0 -1.0 -1.0 1.6205064883026195e-11 -1.0 1.7041669224797384e-09 -1.0 1.8747824667478637e-14 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 5.619835883512353e-14 -1.0 1.951356547084204e-15 -1.0 8.48176145671274e-10 -1.0 -1.0 -1.0 1.4508262073256659e-13 -1.0 4.109066205029878e-05 -1.0 0.00020573181450240786 -1.0 2.124999182004655e-05 -1.0 5.5379154134462336e-08 -1.0 1.5550455959178486e-06 -1.0 0.0007213722022489493 -1.0 0.007673145137236567 -1.0 0.0008175033526488423 -1.0 1.008394964750947e-06 -1.0 6.848642863465585e-07 -1.0 0.0010737081832502356 -1.0 0.007197662162700777 -1.0 0.0007151459162818186 -1.0 2.253382683081525e-06 -1.0 1.3181562352445092e-10 -1.0 1.93847081892941e-05 -1.0 0.00046029617115127556 -1.0 2.5629068330446215e-05 -1.0 5.504813693036933e-12 -1.0 -1.0 -1.0 3.3164825349503764e-16 -1.0 3.937160538176268e-07 -1.0 -1.0 -1.0 -1.0 -1.0 1.5172912057312398e-14 -1.0 6.315154082213375e-07 -1.0 3.855884234344845e-06 -1.0 1.7770136411255912e-05 -1.0 1.6421491993751715e-11 -1.0 5.97653814110781e-06 -1.0 0.001959411999677113 -1.0 0.013330619853379314 -1.0 0.0017950613169359904 -1.0 2.4306375693722205e-06 -1.0 6.922231352729155e-05 -1.0 0.08657573566388353 -1.0 -1.0 -1.0 0.0835648710074336 -1.0 0.00016419031150495913 -1.0 9.03108551826469e-05 -1.0 0.0848872967381878 -1.0 -1.0 -1.0 0.08288806458368345 -1.0 5.6949597066784976e-05 -1.0 8.037131813528501e-07 -1.0 0.0016637126543321873 -1.0 0.01664109232689093 -1.0 0.0018327593437608 -1.0 6.542700644645627e-07 -1.0 -1.0 -1.0 6.655926357459275e-08 -1.0 5.783974359937857e-06 -1.0 2.679340942769232e-06 -1.0 -1.0 -1.0 -1.0 -1.0 2.1040609012865134e-05 -1.0 2.9282097947816224e-05 -1.0 1.284759166582202e-05 -1.0 1.0092905083158804e-11 -1.0 1.3228013765525015e-05 -1.0 0.007136750029575816 -1.0 0.06539005235506369 -1.0 0.0064803314120165335 -1.0 2.6011787393916806e-06 -1.0 8.887234042637684e-05 -1.0 0.5 -1.0 -1.0 -1.0 0.4877856021170283 -1.0 0.00017699858357744463 -1.0 0.0001670700632870335 -1.0 0.4899999304038166 -1.0 -1.0 -1.0 0.48573842213878143 -1.0 0.00021534568699157805 -1.0 7.84289689494925e-06 -1.0 0.0063790654507599135 -1.0 0.06550426960512012 -1.0 0.006639379668946672 -1.0 7.754700849337902e-06 -1.0 2.7207433165796702e-11 -1.0 5.985108617124989e-06 -1.0 3.634644995026692e-05 -1.0 3.932389299316285e-06 -1.0 -1.0 -1.0 -1.0 -1.0 1.271128669411295e-07 -1.0 8.846493399850663e-06 -1.0 2.499931357628383e-07 -1.0 8.533030345699353e-17 -1.0 1.6699254277734109e-06 -1.0 0.0017541380096893788 -1.0 0.015148978428271613 -1.0 0.0016279794552427574 -1.0 2.380955631371226e-06 -1.0 2.1648918040467363e-05 -1.0 0.0833931797381589 -1.0 -1.0 -1.0 0.08285899874014539 -1.0 2.762955748645507e-05 -1.0 5.1161740516205715e-05 -1.0 0.08095280568305474 -1.0 -1.0 -1.0 0.08636569925236791 -1.0 3.452537179033895e-05 -1.0 3.5981031766416143e-06 -1.0 0.001570829313580841 -1.0 0.01621821782442112 -1.0 0.0015447823995470042 -1.0 7.989579285134734e-06 -1.0 -1.0 -1.0 2.594951085377588e-06 -1.0 4.323138781337963e-05 -1.0 6.948292975998466e-07 -1.0 -1.0 -1.0 -1.0 -1.0 2.4469456008493614e-09 -1.0 9.041149893307806e-07 -1.0 2.2060992580622125e-11 -1.0 -1.0 -1.0 1.681305446488884e-11 -1.0 7.091263906557291e-05 -1.0 0.00027464244062887683 -1.0 1.28584557092134e-05 -1.0 2.0295213621716706e-09 -1.0 1.2911827198500372e-08 -1.0 0.0009127050763987511 -1.0 0.007385384405891666 -1.0 0.0010019432401508087 -1.0 1.080711295768551e-05 -1.0 8.020767115181574e-07 -1.0 0.0009252532821720597 -1.0 0.007188410694198128 -1.0 0.0007245451610090619 -1.0 2.5157355790201773e-07 -1.0 1.4825219199133353e-12 -1.0 4.756872959630257e-05 -1.0 0.0002668579837809081 -1.0 2.8226276944532696e-05 -1.0 5.182269672663266e-10 -1.0 -1.0 -1.0 2.936268747135548e-14 -1.0 2.5447281241730366e-07 -1.0 3.89841667138598e-08 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 2.639268952045579e-10 -1.0 3.7051518220083886e-06 -1.0 1.1333627604823673e-09 -1.0 -1.0 -1.0 -1.0 -1.0 1.2296747260635405e-06 -1.0 7.962899789920809e-06 -1.0 8.211982683649991e-09 -1.0 -1.0 -1.0 -1.0 -1.0 2.5639656866250453e-06 -1.0 2.2487617828938326e-05 -1.0 3.2799045883372075e-06 -1.0 4.076762579823379e-17 -1.0 1.5476769237571295e-14 -1.0 1.0305672698745657e-11 -1.0 1.957092814065688e-05 -1.0 3.8523247550378815e-12 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 2.7697233171399416e-13 -1.0 -1.0 -1.0 -1.0 -1.0 + -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 7.695031155172816e-13 -10.0 7.476545089278483e-05 -10.0 2.1612150425221703e-05 -10.0 -10.0 -10.0 2.1360401784344976e-17 -10.0 0.00013455341306162382 -10.0 0.00033532954038420373 -10.0 3.0160758454323656e-06 -10.0 1.0262431550731535e-12 -10.0 1.6859219614058023e-18 -10.0 3.853097455417877e-05 -10.0 0.00043549469813297995 -10.0 7.002861620919232e-07 -10.0 -10.0 -10.0 -10.0 -10.0 1.6205064883026195e-10 -10.0 1.7041669224797384e-08 -10.0 1.8747824667478637e-13 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 5.619835883512353e-13 -10.0 1.951356547084204e-14 -10.0 8.48176145671274e-09 -10.0 -10.0 -10.0 1.4508262073256658e-12 -10.0 0.0004109066205029878 -10.0 0.0020573181450240785 -10.0 0.00021249991820046548 -10.0 5.537915413446234e-07 -10.0 1.5550455959178486e-05 -10.0 0.0072137220224894934 -10.0 0.07673145137236567 -10.0 0.008175033526488424 -10.0 1.0083949647509469e-05 -10.0 6.848642863465585e-06 -10.0 0.010737081832502356 -10.0 0.07197662162700777 -10.0 0.007151459162818186 -10.0 2.253382683081525e-05 -10.0 1.3181562352445092e-09 -10.0 0.000193847081892941 -10.0 0.004602961711512756 -10.0 0.00025629068330446217 -10.0 5.504813693036933e-11 -10.0 -10.0 -10.0 3.3164825349503764e-15 -10.0 3.937160538176268e-06 -10.0 -10.0 -10.0 -10.0 -10.0 1.51729120573124e-13 -10.0 6.3151540822133754e-06 -10.0 3.855884234344845e-05 -10.0 0.0001777013641125591 -10.0 1.6421491993751715e-10 -10.0 5.97653814110781e-05 -10.0 0.01959411999677113 -10.0 0.13330619853379314 -10.0 0.017950613169359905 -10.0 2.4306375693722206e-05 -10.0 0.0006922231352729155 -10.0 0.8657573566388354 -10.0 -10.0 -10.0 0.8356487100743359 -10.0 0.0016419031150495913 -10.0 0.000903108551826469 -10.0 0.848872967381878 -10.0 -10.0 -10.0 0.8288806458368345 -10.0 0.0005694959706678497 -10.0 8.037131813528501e-06 -10.0 0.016637126543321872 -10.0 0.1664109232689093 -10.0 0.018327593437608 -10.0 6.5427006446456266e-06 -10.0 -10.0 -10.0 6.655926357459275e-07 -10.0 5.7839743599378564e-05 -10.0 2.679340942769232e-05 -10.0 -10.0 -10.0 -10.0 -10.0 0.00021040609012865135 -10.0 0.00029282097947816227 -10.0 0.0001284759166582202 -10.0 1.0092905083158804e-10 -10.0 0.00013228013765525016 -10.0 0.07136750029575815 -10.0 0.6539005235506369 -10.0 0.06480331412016534 -10.0 2.6011787393916804e-05 -10.0 0.0008887234042637684 -10.0 5.0 -10.0 -10.0 -10.0 4.877856021170283 -10.0 0.0017699858357744464 -10.0 0.001670700632870335 -10.0 4.899999304038166 -10.0 -10.0 -10.0 4.8573842213878144 -10.0 0.0021534568699157807 -10.0 7.84289689494925e-05 -10.0 0.06379065450759913 -10.0 0.6550426960512012 -10.0 0.06639379668946672 -10.0 7.754700849337902e-05 -10.0 2.7207433165796704e-10 -10.0 5.985108617124989e-05 -10.0 0.0003634644995026692 -10.0 3.9323892993162844e-05 -10.0 -10.0 -10.0 -10.0 -10.0 1.271128669411295e-06 -10.0 8.846493399850663e-05 -10.0 2.499931357628383e-06 -10.0 8.533030345699353e-16 -10.0 1.669925427773411e-05 -10.0 0.017541380096893787 -10.0 0.15148978428271614 -10.0 0.016279794552427576 -10.0 2.380955631371226e-05 -10.0 0.00021648918040467362 -10.0 0.8339317973815891 -10.0 -10.0 -10.0 0.828589987401454 -10.0 0.0002762955748645507 -10.0 0.0005116174051620571 -10.0 0.8095280568305474 -10.0 -10.0 -10.0 0.8636569925236791 -10.0 0.0003452537179033895 -10.0 3.5981031766416144e-05 -10.0 0.015708293135808408 -10.0 0.16218217824421122 -10.0 0.015447823995470043 -10.0 7.989579285134734e-05 -10.0 -10.0 -10.0 2.594951085377588e-05 -10.0 0.0004323138781337963 -10.0 6.948292975998466e-06 -10.0 -10.0 -10.0 -10.0 -10.0 2.4469456008493615e-08 -10.0 9.041149893307805e-06 -10.0 2.2060992580622125e-10 -10.0 -10.0 -10.0 1.681305446488884e-10 -10.0 0.0007091263906557291 -10.0 0.002746424406288768 -10.0 0.000128584557092134 -10.0 2.0295213621716707e-08 -10.0 1.2911827198500372e-07 -10.0 0.009127050763987512 -10.0 0.07385384405891665 -10.0 0.010019432401508087 -10.0 0.0001080711295768551 -10.0 8.020767115181574e-06 -10.0 0.009252532821720597 -10.0 0.07188410694198127 -10.0 0.0072454516100906195 -10.0 2.515735579020177e-06 -10.0 1.4825219199133352e-11 -10.0 0.0004756872959630257 -10.0 0.0026685798378090807 -10.0 0.000282262769445327 -10.0 5.182269672663266e-09 -10.0 -10.0 -10.0 2.9362687471355483e-13 -10.0 2.5447281241730365e-06 -10.0 3.89841667138598e-07 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 2.639268952045579e-09 -10.0 3.7051518220083885e-05 -10.0 1.1333627604823672e-08 -10.0 -10.0 -10.0 -10.0 -10.0 1.2296747260635405e-05 -10.0 7.96289978992081e-05 -10.0 8.211982683649991e-08 -10.0 -10.0 -10.0 -10.0 -10.0 2.5639656866250452e-05 -10.0 0.00022487617828938325 -10.0 3.2799045883372076e-05 -10.0 4.076762579823379e-16 -10.0 1.5476769237571296e-13 -10.0 1.0305672698745658e-10 -10.0 0.0001957092814065688 -10.0 3.852324755037882e-11 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 2.7697233171399415e-12 -10.0 -10.0 -10.0 -10.0 -10.0 + 3 + 1.5 + 10 + 1e-38 + + + 5 6 7 + -240 -240 -240 + 240 240 240 + + + 2 + neutron + 0.0 0.5 20000000.0 + -1.0 -1.0 -1.0 5.447493368067179e-10 -1.0 4.0404626147344e-13 -1.0 9.382800796426366e-17 -1.0 -1.0 -1.0 5.752120832330886e-11 -1.0 3.520674728719278e-05 -1.0 8.76041935303527e-05 -1.0 3.136829920007009e-05 -1.0 -1.0 -1.0 4.233410073487772e-06 -1.0 0.00025519632243117644 -1.0 0.0004777967757842694 -1.0 0.00035983547999740665 -1.0 4.6258592060517866e-07 -1.0 4.587143797469485e-08 -1.0 0.00012918433677593975 -1.0 0.000469589568463265 -1.0 8.862760180332873e-05 -1.0 3.2790914744011534e-06 -1.0 1.1514579117272292e-10 -1.0 2.2950716170641463e-05 -1.0 6.92296299242814e-05 -1.0 2.1606550732170693e-05 -1.0 2.617878055106949e-16 -1.0 -1.0 -1.0 -1.0 -1.0 1.722191123879782e-08 -1.0 -1.0 -1.0 -1.0 -1.0 2.1234980618763222e-13 -1.0 1.4628847959717225e-05 -1.0 2.777791741571174e-05 -1.0 9.53380658669839e-06 -1.0 1.078687446476881e-14 -1.0 3.0571050855707084e-06 -1.0 0.0008231482263927564 -1.0 0.0038811025614225057 -1.0 0.0012297303081805393 -1.0 4.6842350882367666e-05 -1.0 0.00016757997590048827 -1.0 0.011724714376848187 -1.0 0.06827568359008944 -1.0 0.011440381012864086 -1.0 0.0003782322077390033 -1.0 5.098747893974248e-05 -1.0 0.01208261392046878 -1.0 0.06428782790571179 -1.0 0.011294708566804167 -1.0 8.168081568291806e-05 -1.0 2.34750482787598e-05 -1.0 0.0008787411098754915 -1.0 0.0051513292132259495 -1.0 0.0011028020390507682 -1.0 1.0882011018684852e-06 -1.0 1.0588257623722672e-07 -1.0 2.7044817176109556e-05 -1.0 2.6211239246796104e-05 -1.0 2.0707648529746894e-06 -1.0 -1.0 -1.0 1.3806577785135177e-06 -1.0 0.00010077009726691265 -1.0 0.00043130977711323417 -1.0 0.0001335621430311088 -1.0 3.792209399652396e-06 -1.0 0.00022057970761624768 -1.0 0.01884234453311008 -1.0 0.11510120013926417 -1.0 0.01825795827020865 -1.0 0.00020848309220162036 -1.0 0.0013332554437480327 -1.0 0.49317081643076643 -1.0 -1.0 -1.0 0.4899952354672477 -1.0 0.0014957033281168012 -1.0 0.001550036616828061 -1.0 0.4897735047310072 -1.0 -1.0 -1.0 0.5 -1.0 0.0011076796092102186 -1.0 0.0002792896409558745 -1.0 0.01721806295736377 -1.0 0.11891251244906934 -1.0 0.019040707071165303 -1.0 0.00017329528628152923 -1.0 4.670673837764874e-08 -1.0 0.00012637534695610975 -1.0 0.00027052054298385255 -1.0 0.0001497958445994315 -1.0 3.2478301680021854e-08 -1.0 7.239087311622819e-08 -1.0 0.00046693784586018913 -1.0 0.001537590300149361 -1.0 0.00023686818807101741 -1.0 8.616027294555462e-07 -1.0 0.0002362355168421952 -1.0 0.05708498338352203 -1.0 0.42372713683725016 -1.0 0.054902816619122045 -1.0 0.00030002326388383244 -1.0 0.0023295401596005313 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0027847329307350423 -1.0 0.003432919201293737 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.002672923773363389 -1.0 0.0003182108781955478 -1.0 0.05639071613735579 -1.0 0.4346984808472855 -1.0 0.05500108683629957 -1.0 0.00024175998138228048 -1.0 2.774067049392004e-07 -1.0 0.0003257646134837451 -1.0 0.0012648333883989995 -1.0 0.0002981891705231209 -1.0 4.986698316296507e-06 -1.0 3.419181071650816e-06 -1.0 0.00010814452764860558 -1.0 0.0006934466049804711 -1.0 0.00025106741008066317 -1.0 5.515522196186723e-06 -1.0 0.00014242053195529864 -1.0 0.018541112907970003 -1.0 0.12364069326350118 -1.0 0.017602971074583987 -1.0 0.00021305826462238593 -1.0 0.0015016500045374082 -1.0 0.4903495510314233 -1.0 -1.0 -1.0 0.4952432605379829 -1.0 0.0017693279949094218 -1.0 0.0009304497896205121 -1.0 0.4873897581604287 -1.0 -1.0 -1.0 0.4981497862127628 -1.0 0.0011273340972061078 -1.0 0.00014126153603265097 -1.0 0.01729816946709781 -1.0 0.11819165666519223 -1.0 0.017802624844035688 -1.0 0.0001319677450153934 -1.0 2.210707325798542e-07 -1.0 0.00017287873387910357 -1.0 0.0005197081842709918 -1.0 9.256616392487858e-05 -1.0 1.0325207105027347e-08 -1.0 2.027381220364608e-16 -1.0 1.2257360246712472e-05 -1.0 3.8561696337086434e-05 -1.0 1.8064550990294753e-05 -1.0 7.691527781829036e-17 -1.0 1.298062961617927e-05 -1.0 0.001178616843705956 -1.0 0.004441328419270369 -1.0 0.0008919466185572302 -1.0 5.272021975060514e-06 -1.0 0.00016079768514218546 -1.0 0.011128424196387618 -1.0 0.06433819434431046 -1.0 0.010955637485319249 -1.0 8.370896020975689e-05 -1.0 0.00022234471595443313 -1.0 0.01102706140784316 -1.0 0.06684484191345574 -1.0 0.011113024641218336 -1.0 0.00012558879474108074 -1.0 1.0044390728858277e-05 -1.0 0.000808100901275472 -1.0 0.005384625561469684 -1.0 0.001146714816952061 -1.0 3.5740607788414942e-06 -1.0 2.2512327083641865e-10 -1.0 6.717625881826167e-05 -1.0 6.949587369646497e-05 -1.0 2.9093345975075226e-05 -1.0 -1.0 -1.0 -1.0 -1.0 8.582011716859219e-15 -1.0 8.304845400451923e-08 -1.0 4.5757238372058234e-11 -1.0 -1.0 -1.0 1.3116807133030035e-15 -1.0 2.6866894852481906e-05 -1.0 4.3166052799897375e-05 -1.0 6.401055165502384e-06 -1.0 5.726152701849347e-16 -1.0 8.541606727879512e-07 -1.0 0.0002029396545382813 -1.0 0.0004299195570308035 -1.0 8.544159282151438e-05 -1.0 1.0995322456277382e-06 -1.0 1.289814511028015e-06 -1.0 0.00011042047857307253 -1.0 0.0006870228272606287 -1.0 0.0001399807456616496 -1.0 4.279460329782799e-09 -1.0 1.2907171695294846e-13 -1.0 1.9257248009114363e-05 -1.0 9.332371598523186e-05 -1.0 1.3106335518133802e-05 -1.0 6.574706543646946e-16 -1.0 -1.0 -1.0 3.8270536025799805e-15 -1.0 2.101790478097517e-09 -1.0 9.904481358675478e-13 -1.0 -1.0 + -10.0 -10.0 -10.0 5.447493368067179e-09 -10.0 4.0404626147344005e-12 -10.0 9.382800796426367e-16 -10.0 -10.0 -10.0 5.752120832330886e-10 -10.0 0.0003520674728719278 -10.0 0.0008760419353035269 -10.0 0.0003136829920007009 -10.0 -10.0 -10.0 4.233410073487772e-05 -10.0 0.0025519632243117644 -10.0 0.004777967757842694 -10.0 0.0035983547999740664 -10.0 4.625859206051786e-06 -10.0 4.587143797469485e-07 -10.0 0.0012918433677593976 -10.0 0.0046958956846326495 -10.0 0.0008862760180332873 -10.0 3.279091474401153e-05 -10.0 1.151457911727229e-09 -10.0 0.00022950716170641464 -10.0 0.0006922962992428139 -10.0 0.00021606550732170693 -10.0 2.6178780551069492e-15 -10.0 -10.0 -10.0 -10.0 -10.0 1.722191123879782e-07 -10.0 -10.0 -10.0 -10.0 -10.0 2.123498061876322e-12 -10.0 0.00014628847959717226 -10.0 0.0002777791741571174 -10.0 9.53380658669839e-05 -10.0 1.078687446476881e-13 -10.0 3.0571050855707086e-05 -10.0 0.008231482263927564 -10.0 0.03881102561422506 -10.0 0.012297303081805393 -10.0 0.00046842350882367664 -10.0 0.0016757997590048828 -10.0 0.11724714376848187 -10.0 0.6827568359008944 -10.0 0.11440381012864086 -10.0 0.003782322077390033 -10.0 0.0005098747893974248 -10.0 0.1208261392046878 -10.0 0.6428782790571179 -10.0 0.11294708566804167 -10.0 0.0008168081568291806 -10.0 0.000234750482787598 -10.0 0.008787411098754914 -10.0 0.0515132921322595 -10.0 0.011028020390507681 -10.0 1.0882011018684853e-05 -10.0 1.0588257623722672e-06 -10.0 0.00027044817176109554 -10.0 0.000262112392467961 -10.0 2.0707648529746893e-05 -10.0 -10.0 -10.0 1.3806577785135176e-05 -10.0 0.0010077009726691265 -10.0 0.004313097771132342 -10.0 0.001335621430311088 -10.0 3.792209399652396e-05 -10.0 0.0022057970761624767 -10.0 0.1884234453311008 -10.0 1.1510120013926417 -10.0 0.1825795827020865 -10.0 0.0020848309220162036 -10.0 0.013332554437480326 -10.0 4.931708164307665 -10.0 -10.0 -10.0 4.899952354672477 -10.0 0.014957033281168012 -10.0 0.01550036616828061 -10.0 4.897735047310072 -10.0 -10.0 -10.0 5.0 -10.0 0.011076796092102187 -10.0 0.002792896409558745 -10.0 0.17218062957363772 -10.0 1.1891251244906933 -10.0 0.19040707071165303 -10.0 0.0017329528628152924 -10.0 4.670673837764874e-07 -10.0 0.0012637534695610975 -10.0 0.0027052054298385255 -10.0 0.001497958445994315 -10.0 3.2478301680021856e-07 -10.0 7.239087311622819e-07 -10.0 0.004669378458601891 -10.0 0.01537590300149361 -10.0 0.002368681880710174 -10.0 8.61602729455546e-06 -10.0 0.002362355168421952 -10.0 0.5708498338352204 -10.0 4.237271368372502 -10.0 0.5490281661912204 -10.0 0.0030002326388383245 -10.0 0.023295401596005315 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.027847329307350423 -10.0 0.03432919201293737 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.026729237733633893 -10.0 0.0031821087819554777 -10.0 0.5639071613735579 -10.0 4.346984808472855 -10.0 0.5500108683629957 -10.0 0.0024175998138228046 -10.0 2.774067049392004e-06 -10.0 0.0032576461348374514 -10.0 0.012648333883989995 -10.0 0.002981891705231209 -10.0 4.986698316296507e-05 -10.0 3.419181071650816e-05 -10.0 0.0010814452764860557 -10.0 0.006934466049804711 -10.0 0.0025106741008066318 -10.0 5.515522196186723e-05 -10.0 0.0014242053195529865 -10.0 0.18541112907970003 -10.0 1.2364069326350118 -10.0 0.17602971074583987 -10.0 0.0021305826462238594 -10.0 0.015016500045374082 -10.0 4.903495510314233 -10.0 -10.0 -10.0 4.952432605379829 -10.0 0.01769327994909422 -10.0 0.00930449789620512 -10.0 4.873897581604287 -10.0 -10.0 -10.0 4.981497862127628 -10.0 0.011273340972061077 -10.0 0.0014126153603265096 -10.0 0.1729816946709781 -10.0 1.1819165666519222 -10.0 0.1780262484403569 -10.0 0.001319677450153934 -10.0 2.210707325798542e-06 -10.0 0.0017287873387910357 -10.0 0.0051970818427099184 -10.0 0.0009256616392487858 -10.0 1.0325207105027347e-07 -10.0 2.027381220364608e-15 -10.0 0.00012257360246712473 -10.0 0.00038561696337086434 -10.0 0.00018064550990294753 -10.0 7.6915277818290365e-16 -10.0 0.00012980629616179268 -10.0 0.01178616843705956 -10.0 0.04441328419270369 -10.0 0.008919466185572301 -10.0 5.272021975060514e-05 -10.0 0.0016079768514218546 -10.0 0.11128424196387618 -10.0 0.6433819434431045 -10.0 0.10955637485319249 -10.0 0.0008370896020975689 -10.0 0.0022234471595443312 -10.0 0.1102706140784316 -10.0 0.6684484191345574 -10.0 0.11113024641218336 -10.0 0.0012558879474108074 -10.0 0.00010044390728858278 -10.0 0.00808100901275472 -10.0 0.05384625561469684 -10.0 0.01146714816952061 -10.0 3.574060778841494e-05 -10.0 2.2512327083641864e-09 -10.0 0.0006717625881826168 -10.0 0.0006949587369646498 -10.0 0.0002909334597507523 -10.0 -10.0 -10.0 -10.0 -10.0 8.582011716859219e-14 -10.0 8.304845400451923e-07 -10.0 4.5757238372058235e-10 -10.0 -10.0 -10.0 1.3116807133030034e-14 -10.0 0.00026866894852481903 -10.0 0.00043166052799897375 -10.0 6.401055165502385e-05 -10.0 5.726152701849347e-15 -10.0 8.541606727879512e-06 -10.0 0.0020293965453828133 -10.0 0.004299195570308035 -10.0 0.0008544159282151438 -10.0 1.0995322456277382e-05 -10.0 1.289814511028015e-05 -10.0 0.0011042047857307254 -10.0 0.006870228272606287 -10.0 0.0013998074566164962 -10.0 4.279460329782799e-08 -10.0 1.2907171695294846e-12 -10.0 0.00019257248009114364 -10.0 0.0009332371598523186 -10.0 0.000131063355181338 -10.0 6.574706543646946e-15 -10.0 -10.0 -10.0 3.8270536025799805e-14 -10.0 2.101790478097517e-08 -10.0 9.904481358675478e-12 -10.0 -10.0 + 3 + 1.5 + 10 + 1e-38 + + 200 + + + + + 5 10 15 + -240 -240 -240 + 240 240 240 + + + 1 + + + 0.0 0.5 20000000.0 + + + neutron photon + + + 1 2 3 + flux + + diff --git a/tests/regression_tests/weightwindows/local/inputs_true.dat b/tests/regression_tests/weightwindows/local/inputs_true.dat deleted file mode 100644 index 57dc42ca4..000000000 --- a/tests/regression_tests/weightwindows/local/inputs_true.dat +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 500 - 2 - - - 0.001 0.001 0.001 - - - 14000000.0 1.0 - - - true - - 2 - neutron - 0.0 0.5 20000000.0 - -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0008758251780046591 -1.0 -1.0 -1.0 -1.0 0.00044494017319042853 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.6620271125067025e-05 0.0006278777700923334 3.3816651814344154e-05 -1.0 -1.0 0.0024363004681119066 0.04404124277352227 0.002389900091734746 -1.0 -1.0 0.001096572213298872 0.04862206884590391 0.0011530054432113332 -1.0 -1.0 -1.0 0.00029204950777272335 2.2332845991385424e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0001298973206651331 0.0028826281529980655 0.00018941326535850932 -1.0 5.4657521927731274e-05 0.014670839729146354 0.49999999999999994 0.011271060592765664 -1.0 -1.0 0.014846491082523524 0.4897211700090108 0.013284874451810723 -1.0 -1.0 5.14657989105535e-05 0.0010115278438204965 0.0008429411802845685 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0009344129479768359 -1.0 -1.0 -1.0 0.0024828273390431962 0.04299740304329489 0.0020539079252555113 -1.0 -1.0 0.003034165905819096 0.04870927636605937 0.00313101668086297 -1.0 -1.0 -1.0 6.339910999436737e-05 7.442176086066386e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.00011276372995589871 0.0002236100157024887 9.56304298913265e-08 -1.0 -1.0 0.0001596955110781239 9.960576598335084e-06 5.3833030623153676e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 4.0453018186074215e-05 4.6013290110121894e-05 2.709738801641897e-05 -1.0 -1.0 -1.0 9.538410811938703e-05 1.992978141244964e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.0723231851298364e-05 -1.0 -1.0 -1.0 -1.0 0.0008030100296698905 0.017386220476187222 0.0005027758935317528 -1.0 -1.0 0.00103568411326969 0.015609071124009234 0.0007473731339616588 -1.0 -1.0 -1.0 6.979537549963374e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0014257756927429828 5.9098070539559466e-05 -1.0 5.0168071459366625e-06 0.005588863190166347 0.5 0.003930588100414563 -1.0 -1.0 0.005163345217476071 0.48250750993887326 0.003510432129522241 -1.0 -1.0 3.371977841720992e-05 0.0006640103276501794 9.554899988419713e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.000187872910697387 -1.0 -1.0 -1.0 0.0009134587866163143 0.017081858078684467 0.0002972747357542354 -1.0 -1.0 0.0007973472495507653 0.019300903254809747 0.000902203032280694 -1.0 -1.0 6.170015233787292e-05 1.898984300674969e-05 9.85411583595722e-07 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.0173913765490095e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 - -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.008758251780046591 -10.0 -10.0 -10.0 -10.0 0.004449401731904285 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00016620271125067024 0.006278777700923334 0.00033816651814344155 -10.0 -10.0 0.024363004681119065 0.4404124277352227 0.02389900091734746 -10.0 -10.0 0.01096572213298872 0.4862206884590391 0.011530054432113333 -10.0 -10.0 -10.0 0.0029204950777272335 0.00022332845991385425 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.0012989732066513312 0.028826281529980655 0.0018941326535850931 -10.0 0.0005465752192773128 0.14670839729146354 4.999999999999999 0.11271060592765664 -10.0 -10.0 0.14846491082523525 4.897211700090108 0.13284874451810724 -10.0 -10.0 0.000514657989105535 0.010115278438204964 0.008429411802845685 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00934412947976836 -10.0 -10.0 -10.0 0.024828273390431962 0.4299740304329489 0.020539079252555114 -10.0 -10.0 0.03034165905819096 0.48709276366059373 0.0313101668086297 -10.0 -10.0 -10.0 0.0006339910999436737 0.0007442176086066385 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.0011276372995589871 0.002236100157024887 9.56304298913265e-07 -10.0 -10.0 0.001596955110781239 9.960576598335084e-05 0.0005383303062315367 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00040453018186074213 0.00046013290110121896 0.0002709738801641897 -10.0 -10.0 -10.0 0.0009538410811938703 0.00019929781412449641 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00010723231851298364 -10.0 -10.0 -10.0 -10.0 0.008030100296698905 0.17386220476187222 0.0050277589353175285 -10.0 -10.0 0.010356841132696899 0.15609071124009233 0.007473731339616587 -10.0 -10.0 -10.0 0.0006979537549963374 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.014257756927429827 0.0005909807053955946 -10.0 5.016807145936663e-05 0.055888631901663474 5.0 0.039305881004145636 -10.0 -10.0 0.05163345217476071 4.825075099388733 0.03510432129522241 -10.0 -10.0 0.00033719778417209923 0.006640103276501793 0.0009554899988419713 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00187872910697387 -10.0 -10.0 -10.0 0.009134587866163143 0.17081858078684467 0.002972747357542354 -10.0 -10.0 0.007973472495507653 0.19300903254809748 0.009022030322806941 -10.0 -10.0 0.0006170015233787292 0.0001898984300674969 9.85411583595722e-06 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00010173913765490096 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 - 3.0 - 1.5 - 10 - 1e-38 - - - 5 6 7 - -240 -240 -240 - 240 240 240 - - - 2 - photon - 0.0 0.5 20000000.0 - -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 2.0445691096074744e-05 -1.0 -1.0 -1.0 0.00013281328509288383 0.0006267128082339883 -1.0 -1.0 -1.0 -1.0 0.0004209808495056742 5.340221214300681e-05 -1.0 -1.0 -1.0 1.553693492042344e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 3.7096847855980484e-05 -1.0 -1.0 5.41969614042385e-05 0.0007918090215756442 9.763572147337743e-05 -1.0 -1.0 0.0026398319229115233 0.04039871468258457 0.002806654735003014 -1.0 -1.0 0.0027608366482897244 0.040190978087723005 0.0025084416103979975 -1.0 -1.0 9.774868433298412e-05 0.0006126404916879651 0.00014841730774317252 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 9.75342408717107e-06 1.7610849405640072e-05 -1.0 -1.0 0.0001160370359598608 0.002822592083222468 0.0003897177301239376 -1.0 -1.0 0.014965179733172532 0.5 0.011723491704290401 -1.0 2.260493623875525e-05 0.015157364795884922 0.49376993953402387 0.013111419473204967 -1.0 -1.0 0.00014919915366377564 0.002197964829133137 0.0003209711829219673 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.4806422867046436e-05 -1.0 -1.0 -1.0 9.207268175745281e-05 0.0007066033561638983 -1.0 -1.0 -1.0 0.003246064903858183 0.03905493028065908 0.0025380574501073605 -1.0 -1.0 0.0032499260211917933 0.04335567738779479 0.0031577214557017056 4.521352809838806e-05 -1.0 0.00018268090756001903 0.0004353654810741932 0.00011273259573092372 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 9.650194311662424e-06 0.00029403373970835075 0.00013506203419326438 -1.0 -1.0 4.5065302725431816e-06 0.00027725323638744237 3.547290864255937e-05 -1.0 -1.0 -1.0 8.786172732576295e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 - -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00020445691096074745 -10.0 -10.0 -10.0 0.0013281328509288383 0.006267128082339883 -10.0 -10.0 -10.0 -10.0 0.004209808495056742 0.0005340221214300681 -10.0 -10.0 -10.0 0.00015536934920423439 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00037096847855980485 -10.0 -10.0 0.000541969614042385 0.007918090215756443 0.0009763572147337743 -10.0 -10.0 0.026398319229115234 0.4039871468258457 0.02806654735003014 -10.0 -10.0 0.027608366482897245 0.40190978087723006 0.025084416103979976 -10.0 -10.0 0.0009774868433298411 0.0061264049168796506 0.0014841730774317252 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 9.753424087171071e-05 0.00017610849405640073 -10.0 -10.0 0.001160370359598608 0.02822592083222468 0.003897177301239376 -10.0 -10.0 0.14965179733172532 5.0 0.11723491704290401 -10.0 0.0002260493623875525 0.15157364795884923 4.937699395340239 0.13111419473204966 -10.0 -10.0 0.0014919915366377564 0.02197964829133137 0.003209711829219673 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00014806422867046437 -10.0 -10.0 -10.0 0.0009207268175745281 0.007066033561638983 -10.0 -10.0 -10.0 0.03246064903858183 0.39054930280659084 0.025380574501073606 -10.0 -10.0 0.03249926021191793 0.4335567738779479 0.03157721455701706 0.0004521352809838806 -10.0 0.0018268090756001904 0.004353654810741932 0.001127325957309237 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 9.650194311662424e-05 0.0029403373970835075 0.0013506203419326437 -10.0 -10.0 4.5065302725431816e-05 0.002772532363874424 0.0003547290864255937 -10.0 -10.0 -10.0 0.0008786172732576295 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 - 3.0 - 1.5 - 10 - 1e-38 - - false - - true - true - - 200 - - - - 5 10 15 - -240 -240 -240 - 240 240 240 - - - 1 - - - 0.0 0.5 20000000.0 - - - neutron photon - - - 1 2 3 - flux - - - diff --git a/tests/regression_tests/weightwindows/local/results_true.dat b/tests/regression_tests/weightwindows/local/results_true.dat deleted file mode 100644 index d3dfa119d..000000000 --- a/tests/regression_tests/weightwindows/local/results_true.dat +++ /dev/null @@ -1 +0,0 @@ -a78972fe3c0dadfc256cfb139c5ca8c7b634738e1895ad2d6286ed5e2567c6dc518e499363908e9058432684148a706a179a39110f703d5322491184a1d0c3e4 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows/results_true.dat b/tests/regression_tests/weightwindows/results_true.dat new file mode 100644 index 000000000..971401995 --- /dev/null +++ b/tests/regression_tests/weightwindows/results_true.dat @@ -0,0 +1 @@ +f10c722e27d1f0a69f700bc72c4b7751f375dc0a74e049c9abb4b261d2265155c0e516e7e38f9751b83a24eac07e944e51740d398b720524cf8cd6bf0b8c51fc \ No newline at end of file diff --git a/tests/regression_tests/weightwindows/shared/inputs_true.dat b/tests/regression_tests/weightwindows/shared/inputs_true.dat deleted file mode 100644 index 6ec7d12e3..000000000 --- a/tests/regression_tests/weightwindows/shared/inputs_true.dat +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 500 - 2 - - - 0.001 0.001 0.001 - - - 14000000.0 1.0 - - - true - - 2 - neutron - 0.0 0.5 20000000.0 - -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0008758251780046591 -1.0 -1.0 -1.0 -1.0 0.00044494017319042853 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.6620271125067025e-05 0.0006278777700923334 3.3816651814344154e-05 -1.0 -1.0 0.0024363004681119066 0.04404124277352227 0.002389900091734746 -1.0 -1.0 0.001096572213298872 0.04862206884590391 0.0011530054432113332 -1.0 -1.0 -1.0 0.00029204950777272335 2.2332845991385424e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0001298973206651331 0.0028826281529980655 0.00018941326535850932 -1.0 5.4657521927731274e-05 0.014670839729146354 0.49999999999999994 0.011271060592765664 -1.0 -1.0 0.014846491082523524 0.4897211700090108 0.013284874451810723 -1.0 -1.0 5.14657989105535e-05 0.0010115278438204965 0.0008429411802845685 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0009344129479768359 -1.0 -1.0 -1.0 0.0024828273390431962 0.04299740304329489 0.0020539079252555113 -1.0 -1.0 0.003034165905819096 0.04870927636605937 0.00313101668086297 -1.0 -1.0 -1.0 6.339910999436737e-05 7.442176086066386e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.00011276372995589871 0.0002236100157024887 9.56304298913265e-08 -1.0 -1.0 0.0001596955110781239 9.960576598335084e-06 5.3833030623153676e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 4.0453018186074215e-05 4.6013290110121894e-05 2.709738801641897e-05 -1.0 -1.0 -1.0 9.538410811938703e-05 1.992978141244964e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.0723231851298364e-05 -1.0 -1.0 -1.0 -1.0 0.0008030100296698905 0.017386220476187222 0.0005027758935317528 -1.0 -1.0 0.00103568411326969 0.015609071124009234 0.0007473731339616588 -1.0 -1.0 -1.0 6.979537549963374e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.0014257756927429828 5.9098070539559466e-05 -1.0 5.0168071459366625e-06 0.005588863190166347 0.5 0.003930588100414563 -1.0 -1.0 0.005163345217476071 0.48250750993887326 0.003510432129522241 -1.0 -1.0 3.371977841720992e-05 0.0006640103276501794 9.554899988419713e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.000187872910697387 -1.0 -1.0 -1.0 0.0009134587866163143 0.017081858078684467 0.0002972747357542354 -1.0 -1.0 0.0007973472495507653 0.019300903254809747 0.000902203032280694 -1.0 -1.0 6.170015233787292e-05 1.898984300674969e-05 9.85411583595722e-07 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.0173913765490095e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 - -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.008758251780046591 -10.0 -10.0 -10.0 -10.0 0.004449401731904285 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00016620271125067024 0.006278777700923334 0.00033816651814344155 -10.0 -10.0 0.024363004681119065 0.4404124277352227 0.02389900091734746 -10.0 -10.0 0.01096572213298872 0.4862206884590391 0.011530054432113333 -10.0 -10.0 -10.0 0.0029204950777272335 0.00022332845991385425 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.0012989732066513312 0.028826281529980655 0.0018941326535850931 -10.0 0.0005465752192773128 0.14670839729146354 4.999999999999999 0.11271060592765664 -10.0 -10.0 0.14846491082523525 4.897211700090108 0.13284874451810724 -10.0 -10.0 0.000514657989105535 0.010115278438204964 0.008429411802845685 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00934412947976836 -10.0 -10.0 -10.0 0.024828273390431962 0.4299740304329489 0.020539079252555114 -10.0 -10.0 0.03034165905819096 0.48709276366059373 0.0313101668086297 -10.0 -10.0 -10.0 0.0006339910999436737 0.0007442176086066385 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.0011276372995589871 0.002236100157024887 9.56304298913265e-07 -10.0 -10.0 0.001596955110781239 9.960576598335084e-05 0.0005383303062315367 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00040453018186074213 0.00046013290110121896 0.0002709738801641897 -10.0 -10.0 -10.0 0.0009538410811938703 0.00019929781412449641 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00010723231851298364 -10.0 -10.0 -10.0 -10.0 0.008030100296698905 0.17386220476187222 0.0050277589353175285 -10.0 -10.0 0.010356841132696899 0.15609071124009233 0.007473731339616587 -10.0 -10.0 -10.0 0.0006979537549963374 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.014257756927429827 0.0005909807053955946 -10.0 5.016807145936663e-05 0.055888631901663474 5.0 0.039305881004145636 -10.0 -10.0 0.05163345217476071 4.825075099388733 0.03510432129522241 -10.0 -10.0 0.00033719778417209923 0.006640103276501793 0.0009554899988419713 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00187872910697387 -10.0 -10.0 -10.0 0.009134587866163143 0.17081858078684467 0.002972747357542354 -10.0 -10.0 0.007973472495507653 0.19300903254809748 0.009022030322806941 -10.0 -10.0 0.0006170015233787292 0.0001898984300674969 9.85411583595722e-06 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00010173913765490096 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 - 3.0 - 1.5 - 10 - 1e-38 - - - 5 6 7 - -240 -240 -240 - 240 240 240 - - - 2 - photon - 0.0 0.5 20000000.0 - -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 2.0445691096074744e-05 -1.0 -1.0 -1.0 0.00013281328509288383 0.0006267128082339883 -1.0 -1.0 -1.0 -1.0 0.0004209808495056742 5.340221214300681e-05 -1.0 -1.0 -1.0 1.553693492042344e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 3.7096847855980484e-05 -1.0 -1.0 5.41969614042385e-05 0.0007918090215756442 9.763572147337743e-05 -1.0 -1.0 0.0026398319229115233 0.04039871468258457 0.002806654735003014 -1.0 -1.0 0.0027608366482897244 0.040190978087723005 0.0025084416103979975 -1.0 -1.0 9.774868433298412e-05 0.0006126404916879651 0.00014841730774317252 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 9.75342408717107e-06 1.7610849405640072e-05 -1.0 -1.0 0.0001160370359598608 0.002822592083222468 0.0003897177301239376 -1.0 -1.0 0.014965179733172532 0.5 0.011723491704290401 -1.0 2.260493623875525e-05 0.015157364795884922 0.49376993953402387 0.013111419473204967 -1.0 -1.0 0.00014919915366377564 0.002197964829133137 0.0003209711829219673 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 1.4806422867046436e-05 -1.0 -1.0 -1.0 9.207268175745281e-05 0.0007066033561638983 -1.0 -1.0 -1.0 0.003246064903858183 0.03905493028065908 0.0025380574501073605 -1.0 -1.0 0.0032499260211917933 0.04335567738779479 0.0031577214557017056 4.521352809838806e-05 -1.0 0.00018268090756001903 0.0004353654810741932 0.00011273259573092372 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 9.650194311662424e-06 0.00029403373970835075 0.00013506203419326438 -1.0 -1.0 4.5065302725431816e-06 0.00027725323638744237 3.547290864255937e-05 -1.0 -1.0 -1.0 8.786172732576295e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 - -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00020445691096074745 -10.0 -10.0 -10.0 0.0013281328509288383 0.006267128082339883 -10.0 -10.0 -10.0 -10.0 0.004209808495056742 0.0005340221214300681 -10.0 -10.0 -10.0 0.00015536934920423439 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00037096847855980485 -10.0 -10.0 0.000541969614042385 0.007918090215756443 0.0009763572147337743 -10.0 -10.0 0.026398319229115234 0.4039871468258457 0.02806654735003014 -10.0 -10.0 0.027608366482897245 0.40190978087723006 0.025084416103979976 -10.0 -10.0 0.0009774868433298411 0.0061264049168796506 0.0014841730774317252 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 9.753424087171071e-05 0.00017610849405640073 -10.0 -10.0 0.001160370359598608 0.02822592083222468 0.003897177301239376 -10.0 -10.0 0.14965179733172532 5.0 0.11723491704290401 -10.0 0.0002260493623875525 0.15157364795884923 4.937699395340239 0.13111419473204966 -10.0 -10.0 0.0014919915366377564 0.02197964829133137 0.003209711829219673 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.00014806422867046437 -10.0 -10.0 -10.0 0.0009207268175745281 0.007066033561638983 -10.0 -10.0 -10.0 0.03246064903858183 0.39054930280659084 0.025380574501073606 -10.0 -10.0 0.03249926021191793 0.4335567738779479 0.03157721455701706 0.0004521352809838806 -10.0 0.0018268090756001904 0.004353654810741932 0.001127325957309237 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 9.650194311662424e-05 0.0029403373970835075 0.0013506203419326437 -10.0 -10.0 4.5065302725431816e-05 0.002772532363874424 0.0003547290864255937 -10.0 -10.0 -10.0 0.0008786172732576295 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 - 3.0 - 1.5 - 10 - 1e-38 - - true - - true - true - - 200 - - - - 5 10 15 - -240 -240 -240 - 240 240 240 - - - 1 - - - 0.0 0.5 20000000.0 - - - neutron photon - - - 1 2 3 - flux - - - diff --git a/tests/regression_tests/weightwindows/shared/results_true.dat b/tests/regression_tests/weightwindows/shared/results_true.dat deleted file mode 100644 index 01381db32..000000000 --- a/tests/regression_tests/weightwindows/shared/results_true.dat +++ /dev/null @@ -1 +0,0 @@ -27c2d218ecf46161088003fbb39ccd63495f80d6e0b27dbc3b3e845b49b282dabf0eaba4fb619be15c6116fc963ec5ce1fe4197efbe4084972ec761e02e70eb5 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows/survival_biasing/__init__.py b/tests/regression_tests/weightwindows/survival_biasing/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/weightwindows/survival_biasing/local/inputs_true.dat b/tests/regression_tests/weightwindows/survival_biasing/local/inputs_true.dat deleted file mode 100644 index fe144dc62..000000000 --- a/tests/regression_tests/weightwindows/survival_biasing/local/inputs_true.dat +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - fixed source - 50 - 5 - - - - 0.01 1.0 - - - - - - - 14100000.0 1.0 - - - true - - 1 - neutron - 0.46135961568957096 0.2874485390202603 0.13256013950494605 0.052765209609807295 0.020958440832685638 0.006317250035749876 0.002627037175682506 0.00030032343592437284 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4611178493390162 0.28624862560842024 0.13999870622621136 0.05508479408959756 0.018281241958254993 0.0055577764872361555 0.0015265432226293397 0.00024298772352636966 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.46294957913063317 0.2857734367546051 0.13365623190336945 0.05034742166227103 0.017525851812913266 0.005096725451851077 0.0026297640951531403 0.00033732424392026144 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.45772598750472554 0.281494921471495 0.13604397962762246 0.054792881472295364 0.019802376898755525 0.0073351745579128495 0.002067392946066426 9.529474085926143e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4739762983490318 0.28419061537046764 0.12757509901507888 0.0516920293019733 0.01919167874787235 0.007593035964707848 0.0017488176314107277 9.678267909681988e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.47560199098558276 0.27728389146956994 0.12760802572535623 0.05251965811713552 0.022498960644951632 0.01063372459325151 0.004242071054914633 0.00045603112202665183 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.47659199471934693 0.28886666944252215 0.1258637573398161 0.05818862375955657 0.020476313720744762 0.007143193244018263 0.0022364083022515273 0.0003953123781408474 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4693487369606823 0.27180862139490125 0.12833455570423483 0.055146743559938344 0.020667403529470333 0.007891508723137146 0.001643551705407358 0.0006501416781353278 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4538724931023337 0.2824491421084296 0.1275341706351566 0.055027501141893705 0.02305114640508087 0.008599303158607198 0.0025082611194161804 0.000518530311231696 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.45258444753220123 0.26839102466484255 0.12991633918797083 0.05442263709947767 0.019695895223471486 0.005353204961887518 0.0015074698293840157 0.0001598680898180058 8.872047880811405e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4482467985982804 0.2813276470183359 0.13449860790768647 0.056103278190533436 0.026274320334196962 0.006884071908429303 0.0033099390738735458 0.0005337454397674922 0.0001386380399465575 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4875748950139487 0.2908586705316248 0.14212060658392278 0.06068108009637272 0.019467970468789477 0.00637102427946399 0.0028510425266191687 0.0012184421778115488 0.00029404541567146187 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.5 0.2852101551297824 0.13622307172321643 0.058302519884339946 0.023124734915152625 0.007401527839638796 0.002527635652743992 0.0008509612315162482 0.00018213334574554768 7.815977984795461e-06 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.47706397688984176 0.28313436859495966 0.13170624744221976 0.0525453512766549 0.021111753158319105 0.0067451713955609645 0.003204270539718037 0.0010308107242263192 0.0002759210144794204 0.00013727805365387318 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.48641988659284513 0.2816173231471242 0.131541850061199 0.054793200248327956 0.016517701691156576 0.006757591781856257 0.0025425350750908644 0.0006383278085839443 2.279421641064226e-05 0.0003597432472224371 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4307755159245372 0.2652713784080849 0.12753857957535653 0.05470396852881577 0.02049817309420563 0.00566559741247352 0.0007213846765465147 6.848024591311009e-05 -1.0 8.609308814924014e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.43631324024956025 0.2639077825530567 0.13368737962742414 0.05213531603720763 0.020628860469743833 0.008268384844678654 0.0028599221013934375 0.00013059757129982714 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.45926287238219 0.2635824148883888 0.13104280996799478 0.055379812186041905 0.019255042561941074 0.007252095690246872 0.0018026593488140996 0.0003215836458542421 9.14840176000331e-06 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4574378998400604 0.28714971179927723 0.1363507911051337 0.05010315954654347 0.017963278989571074 0.0058998176297971605 0.0021393135666168 0.00015677575033083482 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4821442782978812 0.27704132233083506 0.14149074035662307 0.05546042815834048 0.016800649382269998 0.004096804603054233 0.0019161108398578026 0.0005289600253155307 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 - 2.306798078447855 1.4372426951013015 0.6628006975247303 0.2638260480490365 0.10479220416342819 0.03158625017874938 0.013135185878412529 0.0015016171796218643 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.3055892466950807 1.4312431280421012 0.6999935311310568 0.2754239704479878 0.09140620979127496 0.027788882436180776 0.007632716113146698 0.0012149386176318483 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.314747895653166 1.4288671837730256 0.6682811595168472 0.25173710831135515 0.08762925906456634 0.025483627259255386 0.013148820475765701 0.0016866212196013073 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.288629937523628 1.407474607357475 0.6802198981381123 0.2739644073614768 0.09901188449377762 0.036675872789564246 0.01033696473033213 0.00047647370429630714 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.369881491745159 1.4209530768523382 0.6378754950753944 0.2584601465098665 0.09595839373936176 0.03796517982353924 0.008744088157053638 0.00048391339548409945 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.3780099549279137 1.3864194573478497 0.6380401286267812 0.26259829058567763 0.11249480322475816 0.053168622966257545 0.021210355274573163 0.0022801556101332593 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.382959973596735 1.4443333472126108 0.6293187866990806 0.29094311879778284 0.10238156860372381 0.035715966220091315 0.011182041511257637 0.001976561890704237 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.3467436848034113 1.3590431069745064 0.6416727785211741 0.2757337177996917 0.10333701764735166 0.03945754361568573 0.00821775852703679 0.0032507083906766388 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.2693624655116684 1.412245710542148 0.637670853175783 0.27513750570946854 0.11525573202540434 0.04299651579303599 0.012541305597080901 0.00259265155615848 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.262922237661006 1.3419551233242126 0.6495816959398542 0.2721131854973884 0.09847947611735743 0.02676602480943759 0.007537349146920078 0.000799340449090029 0.0004436023940405703 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.2412339929914022 1.4066382350916795 0.6724930395384323 0.28051639095266717 0.1313716016709848 0.03442035954214652 0.016549695369367727 0.0026687271988374613 0.0006931901997327875 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.4378744750697434 1.4542933526581239 0.7106030329196139 0.3034054004818636 0.09733985234394739 0.03185512139731995 0.014255212633095843 0.006092210889057744 0.0014702270783573093 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.5 1.4260507756489118 0.6811153586160822 0.2915125994216997 0.11562367457576313 0.03700763919819398 0.012638178263719959 0.004254806157581241 0.0009106667287277384 3.9079889923977307e-05 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.385319884449209 1.4156718429747983 0.6585312372110987 0.2627267563832745 0.10555876579159552 0.03372585697780482 0.016021352698590185 0.005154053621131596 0.001379605072397102 0.000686390268269366 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.432099432964226 1.4080866157356209 0.657709250305995 0.2739660012416398 0.08258850845578287 0.03378795890928128 0.012712675375454322 0.0031916390429197216 0.0001139710820532113 0.0017987162361121855 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.1538775796226863 1.3263568920404245 0.6376928978767826 0.27351984264407886 0.10249086547102815 0.028327987062367603 0.0036069233827325737 0.0003424012295655504 -5.0 0.0004304654407462007 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.181566201247801 1.3195389127652835 0.6684368981371207 0.2606765801860381 0.10314430234871916 0.041341924223393264 0.014299610506967188 0.0006529878564991358 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.29631436191095 1.317912074441944 0.6552140498399739 0.27689906093020955 0.09627521280970537 0.03626047845123436 0.009013296744070498 0.0016079182292712106 4.574200880001655e-05 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.287189499200302 1.435748558996386 0.6817539555256685 0.25051579773271737 0.08981639494785537 0.029499088148985803 0.010696567833083998 0.0007838787516541741 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.410721391489406 1.3852066116541752 0.7074537017831153 0.2773021407917024 0.08400324691134999 0.020484023015271167 0.009580554199289014 0.0026448001265776534 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 - 3.0 - 10 - 1e-38 - - - 20 20 1 - 0.0 0.0 0.0 - 160.0 160.0 160.0 - - false - - true - true - - - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/weightwindows/survival_biasing/local/results_true.dat b/tests/regression_tests/weightwindows/survival_biasing/local/results_true.dat deleted file mode 100644 index b457a245c..000000000 --- a/tests/regression_tests/weightwindows/survival_biasing/local/results_true.dat +++ /dev/null @@ -1 +0,0 @@ -386e507008ed3c72c6e1a101aafc01cfaaff2c0b10555558d1eab6332441f7b17264b55002d721151bac2f3e7c1a8aac4c5ed243f5270533d171850f985206ed \ No newline at end of file diff --git a/tests/regression_tests/weightwindows/survival_biasing/shared/inputs_true.dat b/tests/regression_tests/weightwindows/survival_biasing/shared/inputs_true.dat deleted file mode 100644 index bafff89c1..000000000 --- a/tests/regression_tests/weightwindows/survival_biasing/shared/inputs_true.dat +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - fixed source - 50 - 5 - - - - 0.01 1.0 - - - - - - - 14100000.0 1.0 - - - true - - 1 - neutron - 0.46135961568957096 0.2874485390202603 0.13256013950494605 0.052765209609807295 0.020958440832685638 0.006317250035749876 0.002627037175682506 0.00030032343592437284 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4611178493390162 0.28624862560842024 0.13999870622621136 0.05508479408959756 0.018281241958254993 0.0055577764872361555 0.0015265432226293397 0.00024298772352636966 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.46294957913063317 0.2857734367546051 0.13365623190336945 0.05034742166227103 0.017525851812913266 0.005096725451851077 0.0026297640951531403 0.00033732424392026144 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.45772598750472554 0.281494921471495 0.13604397962762246 0.054792881472295364 0.019802376898755525 0.0073351745579128495 0.002067392946066426 9.529474085926143e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4739762983490318 0.28419061537046764 0.12757509901507888 0.0516920293019733 0.01919167874787235 0.007593035964707848 0.0017488176314107277 9.678267909681988e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.47560199098558276 0.27728389146956994 0.12760802572535623 0.05251965811713552 0.022498960644951632 0.01063372459325151 0.004242071054914633 0.00045603112202665183 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.47659199471934693 0.28886666944252215 0.1258637573398161 0.05818862375955657 0.020476313720744762 0.007143193244018263 0.0022364083022515273 0.0003953123781408474 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4693487369606823 0.27180862139490125 0.12833455570423483 0.055146743559938344 0.020667403529470333 0.007891508723137146 0.001643551705407358 0.0006501416781353278 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4538724931023337 0.2824491421084296 0.1275341706351566 0.055027501141893705 0.02305114640508087 0.008599303158607198 0.0025082611194161804 0.000518530311231696 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.45258444753220123 0.26839102466484255 0.12991633918797083 0.05442263709947767 0.019695895223471486 0.005353204961887518 0.0015074698293840157 0.0001598680898180058 8.872047880811405e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4482467985982804 0.2813276470183359 0.13449860790768647 0.056103278190533436 0.026274320334196962 0.006884071908429303 0.0033099390738735458 0.0005337454397674922 0.0001386380399465575 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4875748950139487 0.2908586705316248 0.14212060658392278 0.06068108009637272 0.019467970468789477 0.00637102427946399 0.0028510425266191687 0.0012184421778115488 0.00029404541567146187 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.5 0.2852101551297824 0.13622307172321643 0.058302519884339946 0.023124734915152625 0.007401527839638796 0.002527635652743992 0.0008509612315162482 0.00018213334574554768 7.815977984795461e-06 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.47706397688984176 0.28313436859495966 0.13170624744221976 0.0525453512766549 0.021111753158319105 0.0067451713955609645 0.003204270539718037 0.0010308107242263192 0.0002759210144794204 0.00013727805365387318 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.48641988659284513 0.2816173231471242 0.131541850061199 0.054793200248327956 0.016517701691156576 0.006757591781856257 0.0025425350750908644 0.0006383278085839443 2.279421641064226e-05 0.0003597432472224371 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4307755159245372 0.2652713784080849 0.12753857957535653 0.05470396852881577 0.02049817309420563 0.00566559741247352 0.0007213846765465147 6.848024591311009e-05 -1.0 8.609308814924014e-05 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.43631324024956025 0.2639077825530567 0.13368737962742414 0.05213531603720763 0.020628860469743833 0.008268384844678654 0.0028599221013934375 0.00013059757129982714 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.45926287238219 0.2635824148883888 0.13104280996799478 0.055379812186041905 0.019255042561941074 0.007252095690246872 0.0018026593488140996 0.0003215836458542421 9.14840176000331e-06 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4574378998400604 0.28714971179927723 0.1363507911051337 0.05010315954654347 0.017963278989571074 0.0058998176297971605 0.0021393135666168 0.00015677575033083482 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.4821442782978812 0.27704132233083506 0.14149074035662307 0.05546042815834048 0.016800649382269998 0.004096804603054233 0.0019161108398578026 0.0005289600253155307 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 - 2.306798078447855 1.4372426951013015 0.6628006975247303 0.2638260480490365 0.10479220416342819 0.03158625017874938 0.013135185878412529 0.0015016171796218643 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.3055892466950807 1.4312431280421012 0.6999935311310568 0.2754239704479878 0.09140620979127496 0.027788882436180776 0.007632716113146698 0.0012149386176318483 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.314747895653166 1.4288671837730256 0.6682811595168472 0.25173710831135515 0.08762925906456634 0.025483627259255386 0.013148820475765701 0.0016866212196013073 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.288629937523628 1.407474607357475 0.6802198981381123 0.2739644073614768 0.09901188449377762 0.036675872789564246 0.01033696473033213 0.00047647370429630714 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.369881491745159 1.4209530768523382 0.6378754950753944 0.2584601465098665 0.09595839373936176 0.03796517982353924 0.008744088157053638 0.00048391339548409945 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.3780099549279137 1.3864194573478497 0.6380401286267812 0.26259829058567763 0.11249480322475816 0.053168622966257545 0.021210355274573163 0.0022801556101332593 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.382959973596735 1.4443333472126108 0.6293187866990806 0.29094311879778284 0.10238156860372381 0.035715966220091315 0.011182041511257637 0.001976561890704237 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.3467436848034113 1.3590431069745064 0.6416727785211741 0.2757337177996917 0.10333701764735166 0.03945754361568573 0.00821775852703679 0.0032507083906766388 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.2693624655116684 1.412245710542148 0.637670853175783 0.27513750570946854 0.11525573202540434 0.04299651579303599 0.012541305597080901 0.00259265155615848 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.262922237661006 1.3419551233242126 0.6495816959398542 0.2721131854973884 0.09847947611735743 0.02676602480943759 0.007537349146920078 0.000799340449090029 0.0004436023940405703 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.2412339929914022 1.4066382350916795 0.6724930395384323 0.28051639095266717 0.1313716016709848 0.03442035954214652 0.016549695369367727 0.0026687271988374613 0.0006931901997327875 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.4378744750697434 1.4542933526581239 0.7106030329196139 0.3034054004818636 0.09733985234394739 0.03185512139731995 0.014255212633095843 0.006092210889057744 0.0014702270783573093 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.5 1.4260507756489118 0.6811153586160822 0.2915125994216997 0.11562367457576313 0.03700763919819398 0.012638178263719959 0.004254806157581241 0.0009106667287277384 3.9079889923977307e-05 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.385319884449209 1.4156718429747983 0.6585312372110987 0.2627267563832745 0.10555876579159552 0.03372585697780482 0.016021352698590185 0.005154053621131596 0.001379605072397102 0.000686390268269366 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.432099432964226 1.4080866157356209 0.657709250305995 0.2739660012416398 0.08258850845578287 0.03378795890928128 0.012712675375454322 0.0031916390429197216 0.0001139710820532113 0.0017987162361121855 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.1538775796226863 1.3263568920404245 0.6376928978767826 0.27351984264407886 0.10249086547102815 0.028327987062367603 0.0036069233827325737 0.0003424012295655504 -5.0 0.0004304654407462007 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.181566201247801 1.3195389127652835 0.6684368981371207 0.2606765801860381 0.10314430234871916 0.041341924223393264 0.014299610506967188 0.0006529878564991358 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.29631436191095 1.317912074441944 0.6552140498399739 0.27689906093020955 0.09627521280970537 0.03626047845123436 0.009013296744070498 0.0016079182292712106 4.574200880001655e-05 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.287189499200302 1.435748558996386 0.6817539555256685 0.25051579773271737 0.08981639494785537 0.029499088148985803 0.010696567833083998 0.0007838787516541741 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 2.410721391489406 1.3852066116541752 0.7074537017831153 0.2773021407917024 0.08400324691134999 0.020484023015271167 0.009580554199289014 0.0026448001265776534 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 -5.0 - 3.0 - 10 - 1e-38 - - - 20 20 1 - 0.0 0.0 0.0 - 160.0 160.0 160.0 - - true - - true - true - - - - - 1 - - - 1 - flux - - - diff --git a/tests/regression_tests/weightwindows/survival_biasing/shared/results_true.dat b/tests/regression_tests/weightwindows/survival_biasing/shared/results_true.dat deleted file mode 100644 index 11e5ffa77..000000000 --- a/tests/regression_tests/weightwindows/survival_biasing/shared/results_true.dat +++ /dev/null @@ -1 +0,0 @@ -d17a437262d3316985fba4b48e21a7fcd5f32ac2d96ef0e66849f567deaeadc1e0f18d5d0bf5e9cab4246dbf823e7f43f249a1f67e928b27ae8c70b89f3cefbf \ No newline at end of file diff --git a/tests/regression_tests/weightwindows/survival_biasing/test.py b/tests/regression_tests/weightwindows/survival_biasing/test.py deleted file mode 100644 index c3a3e91a2..000000000 --- a/tests/regression_tests/weightwindows/survival_biasing/test.py +++ /dev/null @@ -1,91 +0,0 @@ -from pathlib import Path - -import pytest -import numpy as np -import openmc -from openmc.utility_funcs import change_directory - -from tests.testing_harness import HashedPyAPITestHarness - - -def build_model(shared_secondary): - openmc.reset_auto_ids() - - # Material - w = openmc.Material(name='Tungsten') - w.add_element('W', 1.0) - w.set_density('g/cm3', 19.25) - - materials = openmc.Materials([w]) - - # Geometry surfaces - x0 = openmc.XPlane(x0=0.0, boundary_type='reflective') - x1 = openmc.XPlane(x0=160.0, boundary_type='vacuum') - y0 = openmc.YPlane(y0=0.0, boundary_type='reflective') - y1 = openmc.YPlane(y0=160.0, boundary_type='reflective') - z0 = openmc.ZPlane(z0=0.0, boundary_type='reflective') - z1 = openmc.ZPlane(z0=160.0, boundary_type='reflective') - - region = +x0 & -x1 & +y0 & -y1 & +z0 & -z1 - cell = openmc.Cell(region=region, fill=w) - root = openmc.Universe(cells=[cell]) - geometry = openmc.Geometry(root) - - # Source: planar on x=0, mono-directional along +x, 14.1 MeV neutrons - space = openmc.stats.CartesianIndependent( - openmc.stats.Discrete([0.01], [1.0]), - openmc.stats.Uniform(0.0, 160.0), - openmc.stats.Uniform(0.0, 160.0), - ) - angle = openmc.stats.Monodirectional((1.0, 0.0, 0.0)) - energy = openmc.stats.Discrete([14.1e6], [1.0]) - - source = openmc.IndependentSource(space=space, angle=angle, energy=energy) - - settings = openmc.Settings() - settings.run_mode = 'fixed source' - settings.batches = 5 - settings.particles = 50 - settings.source = source - settings.shared_secondary_bank = shared_secondary - - model = openmc.Model(geometry=geometry, materials=materials, settings=settings) - - # Mesh tally: 1 cm voxels, flux only - mesh = openmc.RegularMesh() - mesh.dimension = (20, 20, 1) - mesh.lower_left = (0.0, 0.0, 0.0) - mesh.upper_right = (160.0, 160.0, 160.0) - - mesh_filter = openmc.MeshFilter(mesh) - flux_tally = openmc.Tally(name='flux') - flux_tally.filters = [mesh_filter] - flux_tally.scores = ['flux'] - tallies = openmc.Tallies([flux_tally]) - model.tallies = tallies - - parent_dir = Path(__file__).parent - lower_ww_bounds = np.loadtxt(parent_dir / 'ww_n.txt') - - weight_windows = openmc.WeightWindows(mesh, - lower_ww_bounds, - upper_bound_ratio=5.0, - particle_type='neutron') - - model.settings.weight_windows = weight_windows - model.settings.weight_window_checkpoints = {'surface': True, - 'collision': True} - model.settings.survival_biasing = True - - return model - - -@pytest.mark.parametrize("shared_secondary,subdir", [ - (False, "local"), - (True, "shared"), -]) -def test_weight_windows_with_survival_biasing(shared_secondary, subdir): - with change_directory(subdir): - model = build_model(shared_secondary) - harness = HashedPyAPITestHarness('statepoint.5.h5', model) - harness.main() diff --git a/tests/regression_tests/weightwindows/survival_biasing/ww_n.txt b/tests/regression_tests/weightwindows/survival_biasing/ww_n.txt deleted file mode 100644 index aea1ff132..000000000 --- a/tests/regression_tests/weightwindows/survival_biasing/ww_n.txt +++ /dev/null @@ -1,400 +0,0 @@ -4.613596156895709566e-01 -4.611178493390161726e-01 -4.629495791306331709e-01 -4.577259875047255400e-01 -4.739762983490318216e-01 -4.756019909855827565e-01 -4.765919947193469342e-01 -4.693487369606823001e-01 -4.538724931023336850e-01 -4.525844475322012284e-01 -4.482467985982804271e-01 -4.875748950139486837e-01 -5.000000000000000000e-01 -4.770639768898417565e-01 -4.864198865928451299e-01 -4.307755159245372223e-01 -4.363132402495602524e-01 -4.592628723821899905e-01 -4.574378998400603913e-01 -4.821442782978812014e-01 -2.874485390202602964e-01 -2.862486256084202374e-01 -2.857734367546050924e-01 -2.814949214714950187e-01 -2.841906153704676363e-01 -2.772838914695699430e-01 -2.888666694425221504e-01 -2.718086213949012508e-01 -2.824491421084295850e-01 -2.683910246648425479e-01 -2.813276470183359024e-01 -2.908586705316247856e-01 -2.852101551297823723e-01 -2.831343685949596622e-01 -2.816173231471241767e-01 -2.652713784080849013e-01 -2.639077825530566912e-01 -2.635824148883887941e-01 -2.871497117992772297e-01 -2.770413223308350603e-01 -1.325601395049460507e-01 -1.399987062262113557e-01 -1.336562319033694490e-01 -1.360439796276224633e-01 -1.275750990150788799e-01 -1.276080257253562333e-01 -1.258637573398161125e-01 -1.283345557042348262e-01 -1.275341706351565962e-01 -1.299163391879708251e-01 -1.344986079076864738e-01 -1.421206065839227817e-01 -1.362230717232164323e-01 -1.317062474422197593e-01 -1.315418500611990060e-01 -1.275385795753565255e-01 -1.336873796274241355e-01 -1.310428099679947778e-01 -1.363507911051337063e-01 -1.414907403566230681e-01 -5.276520960980729535e-02 -5.508479408959755796e-02 -5.034742166227103299e-02 -5.479288147229536415e-02 -5.169202930197330098e-02 -5.251965811713552035e-02 -5.818862375955657223e-02 -5.514674355993834376e-02 -5.502750114189370462e-02 -5.442263709947767203e-02 -5.610327819053343573e-02 -6.068108009637272066e-02 -5.830251988433994559e-02 -5.254535127665489747e-02 -5.479320024832795566e-02 -5.470396852881576760e-02 -5.213531603720762686e-02 -5.537981218604190459e-02 -5.010315954654347148e-02 -5.546042815834047873e-02 -2.095844083268563751e-02 -1.828124195825499287e-02 -1.752585181291326649e-02 -1.980237689875552487e-02 -1.919167874787235106e-02 -2.249896064495163217e-02 -2.047631372074476194e-02 -2.066740352947033302e-02 -2.305114640508086968e-02 -1.969589522347148583e-02 -2.627432033419696208e-02 -1.946797046878947710e-02 -2.312473491515262478e-02 -2.111175315831910482e-02 -1.651770169115657563e-02 -2.049817309420563088e-02 -2.062886046974383297e-02 -1.925504256194107353e-02 -1.796327898957107358e-02 -1.680064938226999774e-02 -6.317250035749876098e-03 -5.557776487236155451e-03 -5.096725451851077254e-03 -7.335174557912849461e-03 -7.593035964707848043e-03 -1.063372459325150933e-02 -7.143193244018263000e-03 -7.891508723137145853e-03 -8.599303158607197670e-03 -5.353204961887517849e-03 -6.884071908429303423e-03 -6.371024279463989581e-03 -7.401527839638795750e-03 -6.745171395560964518e-03 -6.757591781856257113e-03 -5.665597412473520264e-03 -8.268384844678653561e-03 -7.252095690246871881e-03 -5.899817629797160512e-03 -4.096804603054233183e-03 -2.627037175682505905e-03 -1.526543222629339657e-03 -2.629764095153140288e-03 -2.067392946066426082e-03 -1.748817631410727689e-03 -4.242071054914632773e-03 -2.236408302251527251e-03 -1.643551705407358000e-03 -2.508261119416180414e-03 -1.507469829384015672e-03 -3.309939073873545759e-03 -2.851042526619168658e-03 -2.527635652743991969e-03 -3.204270539718037138e-03 -2.542535075090864363e-03 -7.213846765465147101e-04 -2.859922101393437468e-03 -1.802659348814099642e-03 -2.139313566616799812e-03 -1.916110839857802610e-03 -3.003234359243728432e-04 -2.429877235263696591e-04 -3.373242439202614419e-04 -9.529474085926143009e-05 -9.678267909681988429e-05 -4.560311220266518293e-04 -3.953123781408473961e-04 -6.501416781353277531e-04 -5.185303112316960250e-04 -1.598680898180058108e-04 -5.337454397674922446e-04 -1.218442177811548824e-03 -8.509612315162482432e-04 -1.030810724226319166e-03 -6.383278085839443235e-04 -6.848024591311008757e-05 -1.305975712998271444e-04 -3.215836458542421176e-04 -1.567757503308348204e-04 -5.289600253155306818e-04 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -8.872047880811405188e-05 -1.386380399465574921e-04 -2.940454156714618719e-04 -1.821333457455476831e-04 -2.759210144794204192e-04 -2.279421641064226044e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 -9.148401760003310179e-06 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -7.815977984795461318e-06 -1.372780536538731832e-04 -3.597432472224371168e-04 -8.609308814924013556e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 diff --git a/tests/regression_tests/weightwindows/test.py b/tests/regression_tests/weightwindows/test.py index c5b6bd889..3d3cf9d7a 100644 --- a/tests/regression_tests/weightwindows/test.py +++ b/tests/regression_tests/weightwindows/test.py @@ -1,23 +1,22 @@ -from pathlib import Path - +from copy import deepcopy import pytest import numpy as np import openmc from openmc.stats import Discrete, Point -from openmc.utility_funcs import change_directory from tests.testing_harness import HashedPyAPITestHarness -def build_model(shared_secondary): - openmc.reset_auto_ids() +@pytest.fixture +def model(): model = openmc.Model() # materials (M4 steel alloy) m4 = openmc.Material() m4.set_density('g/cc', 2.3) m4.add_nuclide('H1', 0.168018676) + m4.add_nuclide("H2", 1.93244e-05) m4.add_nuclide("O16", 0.561814465) m4.add_nuclide("O17", 0.00021401) m4.add_nuclide("Na23", 0.021365) @@ -27,9 +26,14 @@ def build_model(shared_secondary): m4.add_nuclide("Si30", 0.006273944) m4.add_nuclide("Ca40", 0.018026179) m4.add_nuclide("Ca42", 0.00012031) + m4.add_nuclide("Ca43", 2.51033e-05) m4.add_nuclide("Ca44", 0.000387892) + m4.add_nuclide("Ca46", 7.438e-07) + m4.add_nuclide("Ca48", 3.47727e-05) m4.add_nuclide("Fe54", 0.000248179) m4.add_nuclide("Fe56", 0.003895875) + m4.add_nuclide("Fe57", 8.99727e-05) + m4.add_nuclide("Fe58", 1.19737e-05) s0 = openmc.Sphere(r=240) s1 = openmc.Sphere(r=250, boundary_type='vacuum') @@ -42,17 +46,14 @@ def build_model(shared_secondary): # settings settings = model.settings settings.run_mode = 'fixed source' - settings.particles = 500 + settings.particles = 200 settings.batches = 2 - settings.max_history_splits = 200 + settings.max_splits = 200 settings.photon_transport = True - settings.shared_secondary_bank = shared_secondary - settings.weight_window_checkpoints = {'surface': True, - 'collision': True} space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) - settings.source = openmc.IndependentSource(space=space, energy=energy) + settings.source = openmc.Source(space=space, energy=energy) # tally mesh = openmc.RegularMesh() @@ -75,10 +76,10 @@ def build_model(shared_secondary): # weight windows - # load pre-generated weight windows from parent directory - parent_dir = Path(__file__).parent - ww_n_lower_bnds = np.loadtxt(parent_dir / 'ww_n.txt') - ww_p_lower_bnds = np.loadtxt(parent_dir / 'ww_p.txt') + # load pre-generated weight windows + # (created using the same tally as above) + ww_n_lower_bnds = np.loadtxt('ww_n.txt') + ww_p_lower_bnds = np.loadtxt('ww_p.txt') # create a mesh matching the one used # to generate the weight windows @@ -92,7 +93,6 @@ def build_model(shared_secondary): None, 10.0, e_bnds, - 'neutron', max_lower_bound_ratio=1.5) ww_p = openmc.WeightWindows(ww_mesh, @@ -100,7 +100,6 @@ def build_model(shared_secondary): None, 10.0, e_bnds, - 'photon', max_lower_bound_ratio=1.5) model.settings.weight_windows = [ww_n, ww_p] @@ -108,129 +107,6 @@ def build_model(shared_secondary): return model -@pytest.mark.parametrize("shared_secondary,subdir", [ - (False, "local"), - (True, "shared"), -]) -def test_weightwindows(shared_secondary, subdir): - with change_directory(subdir): - model = build_model(shared_secondary) - test = HashedPyAPITestHarness('statepoint.2.h5', model) - test.main() - - -def test_zero_bound_windows_play_no_game(tmp_path): - # A weight window lower bound of zero means no weight window information - # exists there (MCNP wwinp files use zero to turn the game off in a cell), - # so transport must proceed as if weight windows were disabled. Previously, - # zero-bound windows demanded a split at every checkpoint (weight/0 -> - # max_split), multiplying the particle population until terminated by the - # split or weight cutoff limits. - model = build_model(False) - for ww in model.settings.weight_windows: - ww.lower_ww_bounds = np.zeros_like(ww.lower_ww_bounds) - ww.upper_ww_bounds = np.zeros_like(ww.upper_ww_bounds) - sp_zero = model.run(cwd=tmp_path / 'zero_windows') - - model.settings.weight_windows_on = False - sp_off = model.run(cwd=tmp_path / 'windows_off') - - with openmc.StatePoint(sp_zero) as sp: - flux_zero = list(sp.tallies.values())[0].mean - with openmc.StatePoint(sp_off) as sp: - flux_off = list(sp.tallies.values())[0].mean - - np.testing.assert_allclose(flux_zero, flux_off, rtol=1e-12) - - -def test_zero_and_negative_bounds_equivalent(tmp_path): - # Zero and negative lower bounds both mean that no weight window - # information exists in a cell (generators mark such cells with -1, and - # MCNP wwinp files use zero), so they must produce identical transport. - # Unlike the all-zero case above, here particles are born under valid - # windows and encounter the no-information region in flight; previously a - # zero lower bound in that situation demanded a split at every checkpoint - # in the cell (weight/0 -> max_split), multiplying the particle population, - # while -1 played no game. - def run_with(bound_value, subdir): - model = build_model(False) - for ww in model.settings.weight_windows: - lb = np.array(ww.lower_ww_bounds, copy=True) - ub = np.array(ww.upper_ww_bounds, copy=True) - lb[3:, :, :, :] = bound_value - ub[3:, :, :, :] = bound_value - ww.lower_ww_bounds = lb - ww.upper_ww_bounds = ub - return model.run(cwd=tmp_path / subdir) - - sp_zero = run_with(0.0, 'zero_region') - sp_negative = run_with(-1.0, 'negative_region') - - with openmc.StatePoint(sp_zero) as sp: - flux_zero = list(sp.tallies.values())[0].mean - with openmc.StatePoint(sp_negative) as sp: - flux_negative = list(sp.tallies.values())[0].mean - - np.testing.assert_allclose(flux_zero, flux_negative, rtol=1e-12) - - -def test_wwinp_cylindrical(): - - ww = openmc.WeightWindowsList.from_wwinp('ww_n_cyl.txt')[0] - - mesh = ww.mesh - - assert mesh.dimension == (8, 8, 7) - - # make sure that the mesh grids are correct - exp_r_grid = np.hstack((np.linspace(0.0, 3.02, 3, endpoint=False), - np.linspace(3.02, 6.0001, 6))).flatten() - - exp_phi_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), - np.linspace(0.25, 1.5707, 1, endpoint=False), - np.linspace(1.5707, 3.1415, 2, endpoint=False), - np.linspace(3.1415, 4.7124, 4))).flatten() - - exp_z_grid = np.hstack((np.linspace(0.0, 8.008, 4, endpoint=False), - np.linspace(8.008, 14.002, 4))).flatten() - - assert isinstance(mesh, openmc.CylindricalMesh) - - np.testing.assert_equal(mesh.r_grid, exp_r_grid) - np.testing.assert_equal(mesh.phi_grid, exp_phi_grid) - np.testing.assert_equal(mesh.z_grid, exp_z_grid) - np.testing.assert_equal(mesh.origin, (0, 0, -9.0001)) - assert ww.lower_ww_bounds.flat[0] == 0.0 - assert ww.lower_ww_bounds.flat[-1] == np.prod(mesh.dimension) - 1 - - -def test_wwinp_spherical(): - - ww = openmc.WeightWindowsList.from_wwinp('ww_n_sph.txt')[0] - - mesh = ww.mesh - - assert mesh.dimension == (8, 7, 8) - - # make sure that the mesh grids are correct - exp_r_grid = np.hstack((np.linspace(0.0, 3.02, 3, endpoint=False), - np.linspace(3.02, 6.0001, 6))).flatten() - - exp_theta_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), - np.linspace(0.25, 0.5, 1, endpoint=False), - np.linspace(0.5, 0.75, 2, endpoint=False), - np.linspace(0.75, 1.5707, 3))).flatten() - - exp_phi_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), - np.linspace(0.25, 0.5, 1, endpoint=False), - np.linspace(0.5, 1.5707, 2, endpoint=False), - np.linspace(1.5707, 3.1415, 4))).flatten() - - assert isinstance(mesh, openmc.SphericalMesh) - - np.testing.assert_equal(mesh.r_grid, exp_r_grid) - np.testing.assert_equal(mesh.theta_grid, exp_theta_grid) - np.testing.assert_equal(mesh.phi_grid, exp_phi_grid) - np.testing.assert_equal(mesh.origin, (0, 0, -9.0001)) - assert ww.lower_ww_bounds.flat[0] == 0.0 - assert ww.lower_ww_bounds.flat[-1] == np.prod(mesh.dimension) - 1 +def test_weightwindows(model): + test = HashedPyAPITestHarness('statepoint.2.h5', model) + test.main() diff --git a/tests/regression_tests/weightwindows/ww_n.txt b/tests/regression_tests/weightwindows/ww_n.txt index 36d7673c6..dbb49537b 100644 --- a/tests/regression_tests/weightwindows/ww_n.txt +++ b/tests/regression_tests/weightwindows/ww_n.txt @@ -10,30 +10,43 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +7.695031155172815952e-14 -1.000000000000000000e+00 +7.476545089278482294e-06 -1.000000000000000000e+00 +2.161215042522170282e-06 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.136040178434497494e-18 -1.000000000000000000e+00 +1.345534130616238158e-05 -1.000000000000000000e+00 +3.353295403842037074e-05 -1.000000000000000000e+00 +3.016075845432365699e-07 -1.000000000000000000e+00 +1.026243155073153453e-13 -1.000000000000000000e+00 +1.685921961405802360e-19 -1.000000000000000000e+00 +3.853097455417877125e-06 -1.000000000000000000e+00 +4.354946981329799215e-05 -1.000000000000000000e+00 +7.002861620919231721e-08 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.620506488302619488e-11 -1.000000000000000000e+00 +1.704166922479738429e-09 -1.000000000000000000e+00 +1.874782466747863741e-14 -1.000000000000000000e+00 -1.000000000000000000e+00 -5.465752192773127422e-05 -5.016807145936662541e-06 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 @@ -47,329 +60,301 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +5.619835883512352867e-14 -1.000000000000000000e+00 +1.951356547084204088e-15 -1.000000000000000000e+00 +8.481761456712739755e-10 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.450826207325665860e-13 -1.000000000000000000e+00 +4.109066205029878035e-05 -1.000000000000000000e+00 +2.057318145024078612e-04 -1.000000000000000000e+00 +2.124999182004654892e-05 -1.000000000000000000e+00 +5.537915413446233643e-08 -1.000000000000000000e+00 +1.555045595917848555e-06 -1.000000000000000000e+00 +7.213722022489493227e-04 -1.000000000000000000e+00 +7.673145137236566868e-03 -1.000000000000000000e+00 +8.175033526488423340e-04 -1.000000000000000000e+00 +1.008394964750946906e-06 -1.000000000000000000e+00 +6.848642863465584904e-07 -1.000000000000000000e+00 +1.073708183250235556e-03 -1.000000000000000000e+00 +7.197662162700776967e-03 -1.000000000000000000e+00 +7.151459162818185784e-04 -1.000000000000000000e+00 +2.253382683081525085e-06 -1.000000000000000000e+00 +1.318156235244509166e-10 -1.000000000000000000e+00 +1.938470818929409920e-05 -1.000000000000000000e+00 +4.602961711512755646e-04 -1.000000000000000000e+00 +2.562906833044621533e-05 -1.000000000000000000e+00 +5.504813693036932910e-12 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +3.316482534950376351e-16 -1.000000000000000000e+00 +3.937160538176268057e-07 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.517291205731239772e-14 -1.000000000000000000e+00 +6.315154082213375425e-07 -1.000000000000000000e+00 +3.855884234344844889e-06 -1.000000000000000000e+00 +1.777013641125591191e-05 -1.000000000000000000e+00 +1.642149199375171522e-11 -1.000000000000000000e+00 +5.976538141107809983e-06 -1.000000000000000000e+00 +1.959411999677113103e-03 -1.000000000000000000e+00 +1.333061985337931354e-02 -1.000000000000000000e+00 +1.795061316935990395e-03 -1.000000000000000000e+00 +2.430637569372220458e-06 -1.000000000000000000e+00 +6.922231352729155390e-05 -1.000000000000000000e+00 +8.657573566388353237e-02 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +8.356487100743359431e-02 -1.000000000000000000e+00 +1.641903115049591277e-04 -1.000000000000000000e+00 +9.031085518264690009e-05 -1.000000000000000000e+00 +8.488729673818780352e-02 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.662027112506702498e-05 -1.072323185129836366e-05 -1.298973206651331117e-04 +8.288806458368344621e-02 -1.000000000000000000e+00 +5.694959706678497628e-05 -1.000000000000000000e+00 +8.037131813528500897e-07 -1.000000000000000000e+00 +1.663712654332187308e-03 -1.000000000000000000e+00 +1.664109232689093068e-02 -1.000000000000000000e+00 +1.832759343760799985e-03 -1.000000000000000000e+00 +6.542700644645626997e-07 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +6.655926357459274907e-08 -1.000000000000000000e+00 -4.045301818607421548e-05 -2.436300468111906627e-03 -8.030100296698905113e-04 -1.467083972914635416e-02 -5.588863190166347417e-03 -2.482827339043196246e-03 -9.134587866163143164e-04 -1.127637299558987091e-04 +5.783974359937856763e-06 -1.000000000000000000e+00 +2.679340942769232109e-06 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.104060901286513389e-05 -1.000000000000000000e+00 -1.096572213298871923e-03 -1.035684113269689892e-03 -1.484649108252352433e-02 -5.163345217476070746e-03 -3.034165905819096072e-03 -7.973472495507652599e-04 -1.596955110781238946e-04 +2.928209794781622450e-05 -1.000000000000000000e+00 +1.284759166582201940e-05 -1.000000000000000000e+00 +1.009290508315880392e-11 -1.000000000000000000e+00 +1.322801376552501482e-05 -1.000000000000000000e+00 +7.136750029575815620e-03 -1.000000000000000000e+00 +6.539005235506369085e-02 -1.000000000000000000e+00 +6.480331412016533503e-03 -1.000000000000000000e+00 +2.601178739391680563e-06 -1.000000000000000000e+00 +8.887234042637683843e-05 -1.000000000000000000e+00 -5.146579891055349870e-05 -3.371977841720992210e-05 --1.000000000000000000e+00 -6.170015233787291603e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -6.278777700923334273e-04 --1.000000000000000000e+00 -2.882628152998065532e-03 -1.425775692742982772e-03 -9.344129479768359435e-04 -1.878729106973870018e-04 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -8.758251780046590789e-04 -4.601329011012189428e-05 -4.404124277352226835e-02 -1.738622047618722244e-02 -4.999999999999999445e-01 5.000000000000000000e-01 -4.299740304329489199e-02 -1.708185807868446704e-02 -2.236100157024886888e-04 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +4.877856021170283163e-01 -1.000000000000000000e+00 +1.769985835774446302e-04 -1.000000000000000000e+00 -4.449401731904285297e-04 -9.538410811938702620e-05 -4.862206884590390688e-02 -1.560907112400923384e-02 -4.897211700090107755e-01 -4.825075099388732580e-01 -4.870927636605937305e-02 -1.930090325480974742e-02 -9.960576598335083693e-06 +1.670700632870335029e-04 -1.000000000000000000e+00 +4.899999304038166192e-01 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +4.857384221387814338e-01 -1.000000000000000000e+00 +2.153456869915780514e-04 -1.000000000000000000e+00 +7.842896894949250204e-06 -1.000000000000000000e+00 -2.920495077727233452e-04 -6.979537549963373846e-05 -1.011527843820496462e-03 -6.640103276501793748e-04 -6.339910999436736800e-05 -1.898984300674969044e-05 +6.379065450759913505e-03 -1.000000000000000000e+00 +6.550426960512012453e-02 -1.000000000000000000e+00 +6.639379668946672301e-03 -1.000000000000000000e+00 +7.754700849337902260e-06 -1.000000000000000000e+00 +2.720743316579670241e-11 -1.000000000000000000e+00 +5.985108617124988932e-06 -1.000000000000000000e+00 +3.634644995026691954e-05 -1.000000000000000000e+00 +3.932389299316284718e-06 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.271128669411294917e-07 -1.000000000000000000e+00 +8.846493399850662704e-06 -1.000000000000000000e+00 +2.499931357628383163e-07 -1.000000000000000000e+00 +8.533030345699353466e-17 -1.000000000000000000e+00 +1.669925427773410862e-06 -1.000000000000000000e+00 +1.754138009689378778e-03 -1.000000000000000000e+00 +1.514897842827161306e-02 -1.000000000000000000e+00 +1.627979455242757438e-03 -1.000000000000000000e+00 +2.380955631371225994e-06 -1.000000000000000000e+00 +2.164891804046736287e-05 -1.000000000000000000e+00 +8.339317973815890683e-02 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +8.285899874014539257e-02 -1.000000000000000000e+00 +2.762955748645507000e-05 -1.000000000000000000e+00 +5.116174051620571477e-05 -1.000000000000000000e+00 +8.095280568305474045e-02 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +8.636569925236790846e-02 -1.000000000000000000e+00 +3.452537179033895228e-05 -1.000000000000000000e+00 +3.598103176641614321e-06 -1.000000000000000000e+00 +1.570829313580840913e-03 -1.000000000000000000e+00 +1.621821782442112170e-02 -1.000000000000000000e+00 -3.381665181434415378e-05 --1.000000000000000000e+00 -1.894132653585093196e-04 -5.909807053955946611e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -2.709738801641897098e-05 -2.389900091734746025e-03 -5.027758935317528299e-04 -1.127106059276566409e-02 -3.930588100414563434e-03 -2.053907925255511312e-03 -2.972747357542354098e-04 -9.563042989132649486e-08 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -1.992978141244964075e-05 -1.153005443211333218e-03 -7.473731339616587841e-04 -1.328487445181072285e-02 -3.510432129522240985e-03 -3.131016680862970091e-03 -9.022030322806940360e-04 -5.383303062315367556e-05 -1.017391376549009493e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -2.233284599138542407e-05 --1.000000000000000000e+00 -8.429411802845684617e-04 -9.554899988419712775e-05 -7.442176086066385897e-05 -9.854115835957219834e-07 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 +1.544782399547004175e-03 -1.000000000000000000e+00 +7.989579285134733983e-06 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.594951085377587857e-06 -1.000000000000000000e+00 +4.323138781337962887e-05 -1.000000000000000000e+00 +6.948292975998465777e-07 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.446945600849361415e-09 -1.000000000000000000e+00 +9.041149893307805599e-07 -1.000000000000000000e+00 +2.206099258062212484e-11 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.681305446488883933e-11 -1.000000000000000000e+00 +7.091263906557290927e-05 -1.000000000000000000e+00 +2.746424406288768276e-04 -1.000000000000000000e+00 +1.285845570921339974e-05 -1.000000000000000000e+00 +2.029521362171670568e-09 -1.000000000000000000e+00 +1.291182719850037242e-08 -1.000000000000000000e+00 +9.127050763987511325e-04 -1.000000000000000000e+00 +7.385384405891665810e-03 -1.000000000000000000e+00 +1.001943240150808675e-03 -1.000000000000000000e+00 +1.080711295768550941e-05 -1.000000000000000000e+00 +8.020767115181573972e-07 -1.000000000000000000e+00 +9.252532821720597109e-04 -1.000000000000000000e+00 +7.188410694198127913e-03 -1.000000000000000000e+00 +7.245451610090619275e-04 -1.000000000000000000e+00 +2.515735579020177281e-07 -1.000000000000000000e+00 +1.482521919913335348e-12 -1.000000000000000000e+00 +4.756872959630257218e-05 -1.000000000000000000e+00 +2.668579837809080925e-04 -1.000000000000000000e+00 +2.822627694453269613e-05 -1.000000000000000000e+00 +5.182269672663266089e-10 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.936268747135548187e-14 -1.000000000000000000e+00 +2.544728124173036570e-07 -1.000000000000000000e+00 +3.898416671385980035e-08 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 @@ -385,27 +370,41 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.639268952045578987e-10 -1.000000000000000000e+00 +3.705151822008388643e-06 -1.000000000000000000e+00 +1.133362760482367266e-09 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.229674726063540458e-06 -1.000000000000000000e+00 +7.962899789920809096e-06 -1.000000000000000000e+00 +8.211982683649991481e-09 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.563965686625045276e-06 -1.000000000000000000e+00 +2.248761782893832567e-05 -1.000000000000000000e+00 +3.279904588337207471e-06 -1.000000000000000000e+00 +4.076762579823379031e-17 -1.000000000000000000e+00 +1.547676923757129466e-14 -1.000000000000000000e+00 +1.030567269874565733e-11 -1.000000000000000000e+00 +1.957092814065688094e-05 -1.000000000000000000e+00 +3.852324755037881526e-12 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 @@ -413,6 +412,7 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.769723317139941641e-13 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 diff --git a/tests/regression_tests/weightwindows/ww_n_cyl.txt b/tests/regression_tests/weightwindows/ww_n_cyl.txt deleted file mode 100644 index 6f6144ca3..000000000 --- a/tests/regression_tests/weightwindows/ww_n_cyl.txt +++ /dev/null @@ -1,88 +0,0 @@ -1 1 1 16 -1 -8.0000 7.0000 8.0000 0.0000 0.0000 -9.0001 -2.0000 2.0000 4.0000 0.0000 0.0000 0.0000 -1.0000 0.0000 -9.0001 2.0000 -0.0000 3.0000 3.0200 1.0000 5.0000 6.0001 -1.0000 -0.0000 4.0000 8.0080 1.0000 3.0000 14.002 -1.0000 -0.0000 2.0000 0.25000 1.0000 1.0000 1.57070 -1.0000 2.0000 3.1415 1.0000 3.0000 4.7124 -1.0000 -100.00 -0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 -6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 -12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 -18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 -24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 -30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 -36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 -42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 -48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 -54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 -60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 -66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 -72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 -78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 -84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 -90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 -96.000000 97.000000 98.000000 99.000000 100.000000 101.000000 -102.000000 103.000000 104.000000 105.000000 106.000000 107.000000 -108.000000 109.000000 110.000000 111.000000 112.000000 113.000000 -114.000000 115.000000 116.000000 117.000000 118.000000 119.000000 -120.000000 121.000000 122.000000 123.000000 124.000000 125.000000 -126.000000 127.000000 128.000000 129.000000 130.000000 131.000000 -132.000000 133.000000 134.000000 135.000000 136.000000 137.000000 -138.000000 139.000000 140.000000 141.000000 142.000000 143.000000 -144.000000 145.000000 146.000000 147.000000 148.000000 149.000000 -150.000000 151.000000 152.000000 153.000000 154.000000 155.000000 -156.000000 157.000000 158.000000 159.000000 160.000000 161.000000 -162.000000 163.000000 164.000000 165.000000 166.000000 167.000000 -168.000000 169.000000 170.000000 171.000000 172.000000 173.000000 -174.000000 175.000000 176.000000 177.000000 178.000000 179.000000 -180.000000 181.000000 182.000000 183.000000 184.000000 185.000000 -186.000000 187.000000 188.000000 189.000000 190.000000 191.000000 -192.000000 193.000000 194.000000 195.000000 196.000000 197.000000 -198.000000 199.000000 200.000000 201.000000 202.000000 203.000000 -204.000000 205.000000 206.000000 207.000000 208.000000 209.000000 -210.000000 211.000000 212.000000 213.000000 214.000000 215.000000 -216.000000 217.000000 218.000000 219.000000 220.000000 221.000000 -222.000000 223.000000 224.000000 225.000000 226.000000 227.000000 -228.000000 229.000000 230.000000 231.000000 232.000000 233.000000 -234.000000 235.000000 236.000000 237.000000 238.000000 239.000000 -240.000000 241.000000 242.000000 243.000000 244.000000 245.000000 -246.000000 247.000000 248.000000 249.000000 250.000000 251.000000 -252.000000 253.000000 254.000000 255.000000 256.000000 257.000000 -258.000000 259.000000 260.000000 261.000000 262.000000 263.000000 -264.000000 265.000000 266.000000 267.000000 268.000000 269.000000 -270.000000 271.000000 272.000000 273.000000 274.000000 275.000000 -276.000000 277.000000 278.000000 279.000000 280.000000 281.000000 -282.000000 283.000000 284.000000 285.000000 286.000000 287.000000 -288.000000 289.000000 290.000000 291.000000 292.000000 293.000000 -294.000000 295.000000 296.000000 297.000000 298.000000 299.000000 -300.000000 301.000000 302.000000 303.000000 304.000000 305.000000 -306.000000 307.000000 308.000000 309.000000 310.000000 311.000000 -312.000000 313.000000 314.000000 315.000000 316.000000 317.000000 -318.000000 319.000000 320.000000 321.000000 322.000000 323.000000 -324.000000 325.000000 326.000000 327.000000 328.000000 329.000000 -330.000000 331.000000 332.000000 333.000000 334.000000 335.000000 -336.000000 337.000000 338.000000 339.000000 340.000000 341.000000 -342.000000 343.000000 344.000000 345.000000 346.000000 347.000000 -348.000000 349.000000 350.000000 351.000000 352.000000 353.000000 -354.000000 355.000000 356.000000 357.000000 358.000000 359.000000 -360.000000 361.000000 362.000000 363.000000 364.000000 365.000000 -366.000000 367.000000 368.000000 369.000000 370.000000 371.000000 -372.000000 373.000000 374.000000 375.000000 376.000000 377.000000 -378.000000 379.000000 380.000000 381.000000 382.000000 383.000000 -384.000000 385.000000 386.000000 387.000000 388.000000 389.000000 -390.000000 391.000000 392.000000 393.000000 394.000000 395.000000 -396.000000 397.000000 398.000000 399.000000 400.000000 401.000000 -402.000000 403.000000 404.000000 405.000000 406.000000 407.000000 -408.000000 409.000000 410.000000 411.000000 412.000000 413.000000 -414.000000 415.000000 416.000000 417.000000 418.000000 419.000000 -420.000000 421.000000 422.000000 423.000000 424.000000 425.000000 -426.000000 427.000000 428.000000 429.000000 430.000000 431.000000 -432.000000 433.000000 434.000000 435.000000 436.000000 437.000000 -438.000000 439.000000 440.000000 441.000000 442.000000 443.000000 -444.000000 445.000000 446.000000 447.000000 diff --git a/tests/regression_tests/weightwindows/ww_n_sph.txt b/tests/regression_tests/weightwindows/ww_n_sph.txt deleted file mode 100644 index a4418ceeb..000000000 --- a/tests/regression_tests/weightwindows/ww_n_sph.txt +++ /dev/null @@ -1,89 +0,0 @@ -1 1 1 16 -1 -8.0000 7.0000 8.0000 0.0000 0.0000 -9.0001 -2.0000 4.0000 4.0000 0.0000 0.0000 0.0000 -1.0000 0.0000 -9.0001 3.0000 -0.0000 3.0000 3.0200 1.0000 5.0000 6.0001 -1.0000 -0.0000 2.0000 0.25000 1.0000 1.0000 0.50000 -1.0000 2.0000 0.75000 1.0000 2.0000 1.5707 -1.0000 -0.0000 2.0000 0.25000 1.0000 1.0000 0.50000 -1.0000 2.0000 1.5707 1.0000 3.0000 3.1415 -1.0000 -100.00 -0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 -6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 -12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 -18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 -24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 -30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 -36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 -42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 -48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 -54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 -60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 -66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 -72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 -78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 -84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 -90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 -96.000000 97.000000 98.000000 99.000000 100.000000 101.000000 -102.000000 103.000000 104.000000 105.000000 106.000000 107.000000 -108.000000 109.000000 110.000000 111.000000 112.000000 113.000000 -114.000000 115.000000 116.000000 117.000000 118.000000 119.000000 -120.000000 121.000000 122.000000 123.000000 124.000000 125.000000 -126.000000 127.000000 128.000000 129.000000 130.000000 131.000000 -132.000000 133.000000 134.000000 135.000000 136.000000 137.000000 -138.000000 139.000000 140.000000 141.000000 142.000000 143.000000 -144.000000 145.000000 146.000000 147.000000 148.000000 149.000000 -150.000000 151.000000 152.000000 153.000000 154.000000 155.000000 -156.000000 157.000000 158.000000 159.000000 160.000000 161.000000 -162.000000 163.000000 164.000000 165.000000 166.000000 167.000000 -168.000000 169.000000 170.000000 171.000000 172.000000 173.000000 -174.000000 175.000000 176.000000 177.000000 178.000000 179.000000 -180.000000 181.000000 182.000000 183.000000 184.000000 185.000000 -186.000000 187.000000 188.000000 189.000000 190.000000 191.000000 -192.000000 193.000000 194.000000 195.000000 196.000000 197.000000 -198.000000 199.000000 200.000000 201.000000 202.000000 203.000000 -204.000000 205.000000 206.000000 207.000000 208.000000 209.000000 -210.000000 211.000000 212.000000 213.000000 214.000000 215.000000 -216.000000 217.000000 218.000000 219.000000 220.000000 221.000000 -222.000000 223.000000 224.000000 225.000000 226.000000 227.000000 -228.000000 229.000000 230.000000 231.000000 232.000000 233.000000 -234.000000 235.000000 236.000000 237.000000 238.000000 239.000000 -240.000000 241.000000 242.000000 243.000000 244.000000 245.000000 -246.000000 247.000000 248.000000 249.000000 250.000000 251.000000 -252.000000 253.000000 254.000000 255.000000 256.000000 257.000000 -258.000000 259.000000 260.000000 261.000000 262.000000 263.000000 -264.000000 265.000000 266.000000 267.000000 268.000000 269.000000 -270.000000 271.000000 272.000000 273.000000 274.000000 275.000000 -276.000000 277.000000 278.000000 279.000000 280.000000 281.000000 -282.000000 283.000000 284.000000 285.000000 286.000000 287.000000 -288.000000 289.000000 290.000000 291.000000 292.000000 293.000000 -294.000000 295.000000 296.000000 297.000000 298.000000 299.000000 -300.000000 301.000000 302.000000 303.000000 304.000000 305.000000 -306.000000 307.000000 308.000000 309.000000 310.000000 311.000000 -312.000000 313.000000 314.000000 315.000000 316.000000 317.000000 -318.000000 319.000000 320.000000 321.000000 322.000000 323.000000 -324.000000 325.000000 326.000000 327.000000 328.000000 329.000000 -330.000000 331.000000 332.000000 333.000000 334.000000 335.000000 -336.000000 337.000000 338.000000 339.000000 340.000000 341.000000 -342.000000 343.000000 344.000000 345.000000 346.000000 347.000000 -348.000000 349.000000 350.000000 351.000000 352.000000 353.000000 -354.000000 355.000000 356.000000 357.000000 358.000000 359.000000 -360.000000 361.000000 362.000000 363.000000 364.000000 365.000000 -366.000000 367.000000 368.000000 369.000000 370.000000 371.000000 -372.000000 373.000000 374.000000 375.000000 376.000000 377.000000 -378.000000 379.000000 380.000000 381.000000 382.000000 383.000000 -384.000000 385.000000 386.000000 387.000000 388.000000 389.000000 -390.000000 391.000000 392.000000 393.000000 394.000000 395.000000 -396.000000 397.000000 398.000000 399.000000 400.000000 401.000000 -402.000000 403.000000 404.000000 405.000000 406.000000 407.000000 -408.000000 409.000000 410.000000 411.000000 412.000000 413.000000 -414.000000 415.000000 416.000000 417.000000 418.000000 419.000000 -420.000000 421.000000 422.000000 423.000000 424.000000 425.000000 -426.000000 427.000000 428.000000 429.000000 430.000000 431.000000 -432.000000 433.000000 434.000000 435.000000 436.000000 437.000000 -438.000000 439.000000 440.000000 441.000000 442.000000 443.000000 -444.000000 445.000000 446.000000 447.000000 diff --git a/tests/regression_tests/weightwindows/ww_p.txt b/tests/regression_tests/weightwindows/ww_p.txt index da69b9e13..09ff01ebd 100644 --- a/tests/regression_tests/weightwindows/ww_p.txt +++ b/tests/regression_tests/weightwindows/ww_p.txt @@ -1,241 +1,205 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +5.447493368067179064e-10 -1.000000000000000000e+00 +4.040462614734400249e-13 -1.000000000000000000e+00 +9.382800796426366364e-17 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +5.752120832330885919e-11 -1.000000000000000000e+00 +3.520674728719278012e-05 -1.000000000000000000e+00 +8.760419353035269667e-05 -1.000000000000000000e+00 +3.136829920007008993e-05 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +4.233410073487771971e-06 -1.000000000000000000e+00 +2.551963224311764450e-04 -1.000000000000000000e+00 +4.777967757842694024e-04 -1.000000000000000000e+00 +3.598354799974066488e-04 -1.000000000000000000e+00 +4.625859206051786618e-07 -1.000000000000000000e+00 +4.587143797469485258e-08 -1.000000000000000000e+00 +1.291843367759397518e-04 -1.000000000000000000e+00 +4.695895684632649786e-04 -1.000000000000000000e+00 +8.862760180332873163e-05 -1.000000000000000000e+00 +3.279091474401153391e-06 -1.000000000000000000e+00 +1.151457911727229161e-10 -1.000000000000000000e+00 +2.295071617064146262e-05 -1.000000000000000000e+00 +6.922962992428139458e-05 -1.000000000000000000e+00 +2.160655073217069276e-05 -1.000000000000000000e+00 +2.617878055106949035e-16 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.722191123879781983e-08 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.123498061876322157e-13 -1.000000000000000000e+00 +1.462884795971722476e-05 -1.000000000000000000e+00 +2.777791741571173956e-05 -1.000000000000000000e+00 +9.533806586698390583e-06 -1.000000000000000000e+00 +1.078687446476880940e-14 -1.000000000000000000e+00 +3.057105085570708401e-06 -1.000000000000000000e+00 +8.231482263927564300e-04 -1.000000000000000000e+00 +3.881102561422505696e-03 -1.000000000000000000e+00 +1.229730308180539307e-03 -1.000000000000000000e+00 +4.684235088236766580e-05 -1.000000000000000000e+00 +1.675799759004882713e-04 -1.000000000000000000e+00 -2.260493623875524987e-05 +1.172471437684818700e-02 -1.000000000000000000e+00 +6.827568359008943932e-02 -1.000000000000000000e+00 +1.144038101286408600e-02 -1.000000000000000000e+00 +3.782322077390032930e-04 -1.000000000000000000e+00 +5.098747893974247782e-05 -1.000000000000000000e+00 +1.208261392046878005e-02 -1.000000000000000000e+00 +6.428782790571178907e-02 -1.000000000000000000e+00 +1.129470856680416663e-02 -1.000000000000000000e+00 +8.168081568291806404e-05 -1.000000000000000000e+00 +2.347504827875979927e-05 -1.000000000000000000e+00 +8.787411098754914583e-04 -1.000000000000000000e+00 +5.151329213225949548e-03 -1.000000000000000000e+00 +1.102802039050768210e-03 -1.000000000000000000e+00 +1.088201101868485208e-06 -1.000000000000000000e+00 +1.058825762372267240e-07 -1.000000000000000000e+00 +2.704481717610955638e-05 -1.000000000000000000e+00 +2.621123924679610439e-05 -1.000000000000000000e+00 +2.070764852974689408e-06 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.380657778513517658e-06 -1.000000000000000000e+00 +1.007700972669126494e-04 -1.000000000000000000e+00 +4.313097771132341687e-04 -1.000000000000000000e+00 +1.335621430311087867e-04 -1.000000000000000000e+00 +3.792209399652395984e-06 -1.000000000000000000e+00 +2.205797076162476780e-04 -1.000000000000000000e+00 +1.884234453311008084e-02 -1.000000000000000000e+00 +1.151012001392641704e-01 -1.000000000000000000e+00 +1.825795827020864834e-02 -1.000000000000000000e+00 +2.084830922016203648e-04 -1.000000000000000000e+00 +1.333255443748032664e-03 -1.000000000000000000e+00 +4.931708164307664344e-01 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +4.899952354672477139e-01 -1.000000000000000000e+00 +1.495703328116801227e-03 -1.000000000000000000e+00 +1.550036616828060930e-03 -1.000000000000000000e+00 +4.897735047310072254e-01 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -5.419696140423850144e-05 --1.000000000000000000e+00 -1.160370359598607949e-04 --1.000000000000000000e+00 -9.207268175745281452e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -1.328132850928838340e-04 --1.000000000000000000e+00 -2.639831922911523281e-03 --1.000000000000000000e+00 -1.496517973317253170e-02 --1.000000000000000000e+00 -3.246064903858183071e-03 --1.000000000000000000e+00 -9.650194311662423557e-06 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -2.760836648289724440e-03 --1.000000000000000000e+00 -1.515736479588492176e-02 --1.000000000000000000e+00 -3.249926021191793316e-03 --1.000000000000000000e+00 -4.506530272543181565e-06 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -9.774868433298411941e-05 --1.000000000000000000e+00 -1.491991536637756388e-04 --1.000000000000000000e+00 -1.826809075600190318e-04 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -9.753424087171070478e-06 --1.000000000000000000e+00 -1.480642286704643632e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -2.044569109607474437e-05 --1.000000000000000000e+00 -7.918090215756442467e-04 --1.000000000000000000e+00 -2.822592083222468049e-03 --1.000000000000000000e+00 -7.066033561638982710e-04 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -6.267128082339882807e-04 --1.000000000000000000e+00 -4.039871468258456749e-02 --1.000000000000000000e+00 5.000000000000000000e-01 -1.000000000000000000e+00 -3.905493028065908090e-02 +1.107679609210218599e-03 -1.000000000000000000e+00 -2.940337397083507467e-04 +2.792896409558744781e-04 -1.000000000000000000e+00 +1.721806295736377085e-02 -1.000000000000000000e+00 +1.189125124490693353e-01 -1.000000000000000000e+00 +1.904070707116530328e-02 -1.000000000000000000e+00 +1.732952862815292309e-04 -1.000000000000000000e+00 -4.209808495056741907e-04 +4.670673837764873805e-08 -1.000000000000000000e+00 -4.019097808772300467e-02 +1.263753469561097525e-04 -1.000000000000000000e+00 -4.937699395340238717e-01 +2.705205429838525473e-04 -1.000000000000000000e+00 -4.335567738779479152e-02 +1.497958445994315019e-04 -1.000000000000000000e+00 -2.772532363874423726e-04 +3.247830168002185438e-08 -1.000000000000000000e+00 +7.239087311622818554e-08 -1.000000000000000000e+00 +4.669378458601891341e-04 -1.000000000000000000e+00 +1.537590300149361015e-03 -1.000000000000000000e+00 +2.368681880710174145e-04 -1.000000000000000000e+00 -1.553693492042343928e-05 +8.616027294555461632e-07 -1.000000000000000000e+00 -6.126404916879650987e-04 +2.362355168421952122e-04 -1.000000000000000000e+00 -2.197964829133136882e-03 +5.708498338352203244e-02 -1.000000000000000000e+00 -4.353654810741931802e-04 +4.237271368372501623e-01 -1.000000000000000000e+00 -8.786172732576294898e-05 +5.490281661912204542e-02 -1.000000000000000000e+00 +3.000232638838324392e-04 -1.000000000000000000e+00 +2.329540159600531311e-03 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 @@ -243,7 +207,9 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.784732930735042255e-03 -1.000000000000000000e+00 +3.432919201293736875e-03 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 @@ -251,170 +217,204 @@ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +2.672923773363389179e-03 -1.000000000000000000e+00 +3.182108781955477806e-04 -1.000000000000000000e+00 +5.639071613735578692e-02 -1.000000000000000000e+00 +4.346984808472855177e-01 -1.000000000000000000e+00 -3.709684785598048377e-05 +5.500108683629956891e-02 -1.000000000000000000e+00 -1.761084940564007186e-05 +2.417599813822804812e-04 -1.000000000000000000e+00 +2.774067049392004042e-07 -1.000000000000000000e+00 +3.257646134837451210e-04 -1.000000000000000000e+00 +1.264833388398999524e-03 -1.000000000000000000e+00 +2.981891705231208794e-04 -1.000000000000000000e+00 +4.986698316296506713e-06 -1.000000000000000000e+00 +3.419181071650815928e-06 -1.000000000000000000e+00 +1.081445276486055809e-04 -1.000000000000000000e+00 +6.934466049804711161e-04 -1.000000000000000000e+00 +2.510674100806631662e-04 -1.000000000000000000e+00 +5.515522196186722918e-06 -1.000000000000000000e+00 -9.763572147337742902e-05 +1.424205319552986396e-04 -1.000000000000000000e+00 -3.897177301239375825e-04 +1.854111290797000322e-02 -1.000000000000000000e+00 +1.236406932635011752e-01 -1.000000000000000000e+00 +1.760297107458398680e-02 -1.000000000000000000e+00 +2.130582646223859260e-04 -1.000000000000000000e+00 +1.501650004537408200e-03 -1.000000000000000000e+00 +4.903495510314233030e-01 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +4.952432605379828989e-01 -1.000000000000000000e+00 +1.769327994909421784e-03 -1.000000000000000000e+00 +9.304497896205120647e-04 -1.000000000000000000e+00 -2.806654735003014187e-03 +4.873897581604286766e-01 -1.000000000000000000e+00 -1.172349170429040112e-02 -1.000000000000000000e+00 -2.538057450107360485e-03 -1.000000000000000000e+00 -1.350620341932643788e-04 +4.981497862127627907e-01 -1.000000000000000000e+00 +1.127334097206107765e-03 -1.000000000000000000e+00 +1.412615360326509664e-04 -1.000000000000000000e+00 +1.729816946709781048e-02 -1.000000000000000000e+00 +1.181916566651922268e-01 -1.000000000000000000e+00 -5.340221214300680991e-05 +1.780262484403568810e-02 -1.000000000000000000e+00 -2.508441610397997481e-03 +1.319677450153934042e-04 -1.000000000000000000e+00 -1.311141947320496742e-02 +2.210707325798542070e-07 -1.000000000000000000e+00 -3.157721455701705589e-03 +1.728787338791035720e-04 -1.000000000000000000e+00 -3.547290864255936898e-05 +5.197081842709918220e-04 -1.000000000000000000e+00 +9.256616392487857544e-05 -1.000000000000000000e+00 +1.032520710502734699e-08 -1.000000000000000000e+00 +2.027381220364608057e-16 -1.000000000000000000e+00 +1.225736024671247218e-05 -1.000000000000000000e+00 +3.856169633708643398e-05 -1.000000000000000000e+00 +1.806455099029475317e-05 -1.000000000000000000e+00 -1.484173077431725238e-04 +7.691527781829036254e-17 -1.000000000000000000e+00 -3.209711829219673144e-04 +1.298062961617926916e-05 -1.000000000000000000e+00 -1.127325957309237157e-04 +1.178616843705955963e-03 -1.000000000000000000e+00 +4.441328419270368887e-03 -1.000000000000000000e+00 +8.919466185572301909e-04 -1.000000000000000000e+00 +5.272021975060514019e-06 -1.000000000000000000e+00 +1.607976851421854571e-04 -1.000000000000000000e+00 +1.112842419638761758e-02 -1.000000000000000000e+00 +6.433819434431045647e-02 -1.000000000000000000e+00 +1.095563748531924904e-02 -1.000000000000000000e+00 +8.370896020975688591e-05 -1.000000000000000000e+00 +2.223447159544331337e-04 -1.000000000000000000e+00 +1.102706140784315975e-02 -1.000000000000000000e+00 +6.684484191345574366e-02 -1.000000000000000000e+00 +1.111302464121833623e-02 -1.000000000000000000e+00 +1.255887947410807431e-04 -1.000000000000000000e+00 +1.004439072885827748e-05 -1.000000000000000000e+00 +8.081009012754719698e-04 -1.000000000000000000e+00 +5.384625561469683769e-03 -1.000000000000000000e+00 +1.146714816952060971e-03 -1.000000000000000000e+00 +3.574060778841494232e-06 -1.000000000000000000e+00 +2.251232708364186507e-10 -1.000000000000000000e+00 +6.717625881826167172e-05 -1.000000000000000000e+00 +6.949587369646497293e-05 -1.000000000000000000e+00 +2.909334597507522605e-05 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +8.582011716859218622e-15 -1.000000000000000000e+00 +8.304845400451923449e-08 -1.000000000000000000e+00 +4.575723837205823402e-11 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +1.311680713303003522e-15 -1.000000000000000000e+00 +2.686689485248190559e-05 -1.000000000000000000e+00 +4.316605279989737501e-05 -1.000000000000000000e+00 +6.401055165502384025e-06 -1.000000000000000000e+00 +5.726152701849347207e-16 -1.000000000000000000e+00 +8.541606727879512040e-07 -1.000000000000000000e+00 +2.029396545382813118e-04 -1.000000000000000000e+00 +4.299195570308034968e-04 -1.000000000000000000e+00 +8.544159282151438236e-05 -1.000000000000000000e+00 +1.099532245627738225e-06 -1.000000000000000000e+00 +1.289814511028014912e-06 -1.000000000000000000e+00 +1.104204785730725317e-04 -1.000000000000000000e+00 +6.870228272606287295e-04 -1.000000000000000000e+00 +1.399807456616496116e-04 -1.000000000000000000e+00 +4.279460329782799377e-09 -1.000000000000000000e+00 +1.290717169529484602e-13 -1.000000000000000000e+00 +1.925724800911436302e-05 -1.000000000000000000e+00 +9.332371598523186474e-05 -1.000000000000000000e+00 +1.310633551813380206e-05 -1.000000000000000000e+00 +6.574706543646946099e-16 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 +3.827053602579980514e-15 -1.000000000000000000e+00 +2.101790478097516960e-09 -1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 -4.521352809838806062e-05 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 --1.000000000000000000e+00 +9.904481358675477728e-13 -1.000000000000000000e+00 -1.000000000000000000e+00 diff --git a/tests/regression_tests/weightwindows_fw_cadis/__init__.py b/tests/regression_tests/weightwindows_fw_cadis/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat deleted file mode 100644 index 6bdabfbee..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat +++ /dev/null @@ -1,262 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 90 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - - 1 - neutron - 10 - 1 - true - fw_cadis - - - - 6 6 6 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - naive - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/weightwindows_fw_cadis/results_true.dat b/tests/regression_tests/weightwindows_fw_cadis/results_true.dat deleted file mode 100644 index e39b2e239..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis/results_true.dat +++ /dev/null @@ -1,442 +0,0 @@ -RegularMesh - ID = 1 - Name = - Dimensions = 3 - Voxels = [6 6 6] - Lower left = [0. 0. 0.] - Upper Right = [np.float64(30.0), np.float64(30.0), np.float64(30.0)] - Width = [5. 5. 5.] -Lower Bounds -1.50e-01 -1.54e-01 -1.43e-01 -1.30e-01 -1.30e-01 -1.97e-01 -1.46e-01 -1.25e-01 -1.34e-01 -1.32e-01 -1.27e-01 -3.40e-01 -1.36e-01 -1.13e-01 -1.09e-01 -1.19e-01 -1.25e-01 -3.08e-01 -1.38e-01 -1.18e-01 -9.49e-02 -1.19e-01 -1.35e-01 -1.96e-01 -1.12e-01 -9.60e-02 -9.33e-02 -9.74e-02 -1.37e-01 -2.76e-01 -4.53e-02 -1.31e-01 -2.47e-01 -7.36e-02 -1.72e-01 -1.38e-01 -1.55e-01 -1.54e-01 -1.48e-01 -1.36e-01 -1.29e-01 -1.88e-01 -1.40e-01 -1.51e-01 -1.28e-01 -1.18e-01 -1.29e-01 -2.86e-01 -1.42e-01 -1.26e-01 -1.28e-01 -1.16e-01 -1.22e-01 -2.81e-01 -1.38e-01 -1.22e-01 -1.04e-01 -9.81e-02 -1.08e-01 -1.97e-01 -1.34e-01 -1.32e-01 -1.10e-01 -8.69e-02 -1.03e-01 -1.33e-01 -2.51e-01 -3.39e-01 -1.13e-01 -6.92e-02 -1.54e-01 -5.71e-02 -1.60e-01 -1.52e-01 -1.34e-01 -1.32e-01 -1.28e-01 -2.53e-01 -1.33e-01 -1.35e-01 -1.15e-01 -1.32e-01 -1.37e-01 -3.13e-01 -1.27e-01 -1.36e-01 -1.35e-01 -1.10e-01 -1.08e-01 -8.81e-02 -1.51e-01 -1.32e-01 -1.13e-01 -9.89e-02 -9.25e-02 -5.04e-02 -1.40e-01 -1.56e-01 -1.40e-01 -9.19e-02 -6.54e-02 -2.05e-02 -3.35e-01 -1.88e-01 -3.16e-01 -1.80e-01 -5.78e-02 -5.36e-03 -1.43e-01 -1.35e-01 -1.47e-01 -1.33e-01 -1.47e-01 -4.95e-01 -1.42e-01 -1.45e-01 -1.27e-01 -1.31e-01 -1.26e-01 -1.43e-01 -1.49e-01 -1.23e-01 -1.24e-01 -1.13e-01 -9.69e-02 -1.07e-01 -1.65e-01 -1.50e-01 -1.24e-01 -1.07e-01 -8.90e-02 -8.81e-02 -1.48e-01 -1.58e-01 -1.20e-01 -7.93e-02 -7.19e-02 -3.94e-02 -2.29e-01 -1.95e-01 -2.66e-01 -1.51e-01 -3.52e-02 -3.68e-03 -1.48e-01 -1.18e-01 -1.47e-01 -1.41e-01 -1.37e-01 -2.71e-01 -1.70e-01 -1.70e-01 -1.29e-01 -1.33e-01 -1.28e-01 -2.79e-01 -1.84e-01 -1.42e-01 -1.18e-01 -1.25e-01 -1.26e-01 -1.64e-01 -1.73e-01 -1.37e-01 -1.12e-01 -9.01e-02 -1.13e-01 -1.68e-01 -1.60e-01 -1.52e-01 -1.30e-01 -8.71e-02 -7.72e-02 -3.76e-02 -1.57e-01 -9.31e-02 -1.63e-01 -6.80e-02 -6.22e-02 -3.37e-03 -2.47e-01 -2.17e-01 -1.48e-01 -2.01e-01 -1.54e-01 -5.69e-02 -2.89e-01 -3.59e-01 -1.17e-01 -8.64e-02 -3.34e-01 -1.50e-01 -5.00e-01 -2.16e-01 -1.22e-01 -1.66e-01 -1.44e-01 -4.98e-02 -4.28e-01 -1.17e-01 -8.73e-02 -1.11e-01 -1.09e-01 -9.69e-02 -3.26e-01 -2.28e-01 -2.49e-01 -3.55e-02 -1.69e-02 -3.95e-03 -1.03e-01 -4.89e-02 -1.90e-01 -4.61e-02 -9.75e-03 -3.00e-04 -Upper Bounds -7.49e-01 -7.71e-01 -7.13e-01 -6.51e-01 -6.48e-01 -9.85e-01 -7.31e-01 -6.26e-01 -6.69e-01 -6.59e-01 -6.33e-01 -1.70e+00 -6.82e-01 -5.67e-01 -5.45e-01 -5.94e-01 -6.24e-01 -1.54e+00 -6.92e-01 -5.91e-01 -4.75e-01 -5.96e-01 -6.77e-01 -9.82e-01 -5.59e-01 -4.80e-01 -4.67e-01 -4.87e-01 -6.84e-01 -1.38e+00 -2.26e-01 -6.55e-01 -1.24e+00 -3.68e-01 -8.59e-01 -6.88e-01 -7.73e-01 -7.70e-01 -7.42e-01 -6.78e-01 -6.46e-01 -9.40e-01 -7.00e-01 -7.57e-01 -6.39e-01 -5.92e-01 -6.43e-01 -1.43e+00 -7.12e-01 -6.29e-01 -6.40e-01 -5.78e-01 -6.09e-01 -1.40e+00 -6.90e-01 -6.10e-01 -5.21e-01 -4.91e-01 -5.42e-01 -9.87e-01 -6.71e-01 -6.60e-01 -5.52e-01 -4.35e-01 -5.14e-01 -6.65e-01 -1.26e+00 -1.70e+00 -5.63e-01 -3.46e-01 -7.72e-01 -2.86e-01 -8.00e-01 -7.58e-01 -6.70e-01 -6.59e-01 -6.41e-01 -1.26e+00 -6.65e-01 -6.76e-01 -5.76e-01 -6.60e-01 -6.86e-01 -1.57e+00 -6.35e-01 -6.81e-01 -6.75e-01 -5.51e-01 -5.39e-01 -4.40e-01 -7.56e-01 -6.62e-01 -5.67e-01 -4.95e-01 -4.63e-01 -2.52e-01 -6.98e-01 -7.78e-01 -6.99e-01 -4.59e-01 -3.27e-01 -1.02e-01 -1.67e+00 -9.38e-01 -1.58e+00 -9.00e-01 -2.89e-01 -2.68e-02 -7.16e-01 -6.75e-01 -7.35e-01 -6.63e-01 -7.34e-01 -2.47e+00 -7.11e-01 -7.23e-01 -6.34e-01 -6.54e-01 -6.32e-01 -7.14e-01 -7.45e-01 -6.15e-01 -6.19e-01 -5.64e-01 -4.85e-01 -5.37e-01 -8.26e-01 -7.51e-01 -6.21e-01 -5.36e-01 -4.45e-01 -4.40e-01 -7.40e-01 -7.92e-01 -5.99e-01 -3.96e-01 -3.60e-01 -1.97e-01 -1.14e+00 -9.76e-01 -1.33e+00 -7.55e-01 -1.76e-01 -1.84e-02 -7.42e-01 -5.90e-01 -7.37e-01 -7.07e-01 -6.84e-01 -1.36e+00 -8.52e-01 -8.49e-01 -6.46e-01 -6.63e-01 -6.42e-01 -1.40e+00 -9.19e-01 -7.08e-01 -5.89e-01 -6.24e-01 -6.28e-01 -8.21e-01 -8.64e-01 -6.87e-01 -5.58e-01 -4.50e-01 -5.64e-01 -8.40e-01 -7.99e-01 -7.62e-01 -6.51e-01 -4.36e-01 -3.86e-01 -1.88e-01 -7.85e-01 -4.66e-01 -8.13e-01 -3.40e-01 -3.11e-01 -1.68e-02 -1.24e+00 -1.09e+00 -7.40e-01 -1.00e+00 -7.72e-01 -2.85e-01 -1.44e+00 -1.79e+00 -5.85e-01 -4.32e-01 -1.67e+00 -7.50e-01 -2.50e+00 -1.08e+00 -6.10e-01 -8.32e-01 -7.19e-01 -2.49e-01 -2.14e+00 -5.87e-01 -4.36e-01 -5.57e-01 -5.47e-01 -4.84e-01 -1.63e+00 -1.14e+00 -1.25e+00 -1.78e-01 -8.43e-02 -1.97e-02 -5.17e-01 -2.44e-01 -9.49e-01 -2.31e-01 -4.87e-02 -1.50e-03 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows_fw_cadis/test.py b/tests/regression_tests/weightwindows_fw_cadis/test.py deleted file mode 100644 index 7a4718ed5..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis/test.py +++ /dev/null @@ -1,33 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_three_region_cube - -from tests.testing_harness import WeightWindowPyAPITestHarness - - -class MGXSTestHarness(WeightWindowPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_random_ray_adjoint_fixed_source(): - model = random_ray_three_region_cube() - - ww_mesh = openmc.RegularMesh() - n = 6 - width = 30.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=model.settings.batches) - model.settings.weight_window_generators = wwg - model.settings.random_ray['volume_estimator'] = 'naive' - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/weightwindows_fw_cadis_local/__init__.py b/tests/regression_tests/weightwindows_fw_cadis_local/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/weightwindows_fw_cadis_local/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_local/inputs_true.dat deleted file mode 100644 index ffdd977ec..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_local/inputs_true.dat +++ /dev/null @@ -1,273 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - - - - - - fixed source - 500 - 10 - 5 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - - 2 - neutron - 10 - 1 - true - fw_cadis - 1 2 - - - - 7 7 7 - 0.0 0.0 0.0 - 35.0 35.0 35.0 - - - 800.0 - 100.0 - - - - 0.0 0.0 0.0 35.0 35.0 35.0 - - - - true - - - - - - naive - - - 14 14 14 - 0.0 0.0 0.0 - 35.0 35.0 35.0 - - - - - 6 - - - 7 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - - diff --git a/tests/regression_tests/weightwindows_fw_cadis_local/results_true.dat b/tests/regression_tests/weightwindows_fw_cadis_local/results_true.dat deleted file mode 100644 index 5991fc621..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_local/results_true.dat +++ /dev/null @@ -1,696 +0,0 @@ -RegularMesh - ID = 2 - Name = - Dimensions = 3 - Voxels = [7 7 7] - Lower left = [0. 0. 0.] - Upper Right = [np.float64(35.0), np.float64(35.0), np.float64(35.0)] - Width = [5. 5. 5.] -Lower Bounds -1.52e-01 -1.53e-01 -1.78e-01 -1.97e-01 -2.41e-01 -3.94e-01 -2.26e-03 -1.43e-01 -1.58e-01 -1.75e-01 -1.86e-01 -2.06e-01 -4.83e-02 -2.11e-03 -1.31e-01 -1.37e-01 -1.61e-01 -1.76e-01 -2.04e-01 -1.15e-01 -5.04e-03 -1.05e-01 -1.31e-01 -1.49e-01 -1.72e-01 -1.81e-01 -4.24e-02 -5.31e-03 -6.79e-02 -9.98e-02 -1.56e-01 -1.68e-01 -1.78e-01 -1.39e-02 -5.49e-03 -2.69e-03 -6.66e-03 -2.36e-02 -1.65e-02 -1.71e-02 -1.12e-02 -1.94e-03 -1.12e-04 -5.43e-04 -1.23e-03 -1.51e-03 -1.51e-03 -1.31e-03 -1.21e-03 -1.52e-01 -1.60e-01 -1.81e-01 -2.03e-01 -2.16e-01 -2.58e-02 -2.07e-03 -1.45e-01 -1.59e-01 -1.84e-01 -2.07e-01 -2.14e-01 -8.82e-02 -2.92e-03 -1.36e-01 -1.53e-01 -1.61e-01 -1.92e-01 -2.28e-01 -1.82e-01 -2.70e-03 -1.18e-01 -1.42e-01 -1.52e-01 -1.81e-01 -1.98e-01 -2.87e-02 -6.46e-03 -1.00e-01 -1.41e-01 -1.80e-01 -1.73e-01 -2.05e-01 -1.09e-01 -3.29e-03 -5.37e-03 -1.44e-02 -4.53e-02 -2.16e-02 -7.53e-02 -2.38e-02 -1.38e-03 -4.52e-04 -1.11e-03 -1.39e-03 -1.33e-03 -1.26e-03 -1.22e-03 -9.78e-04 -1.83e-01 -1.77e-01 -1.83e-01 -2.03e-01 -2.27e-01 -7.70e-02 -3.55e-03 -1.63e-01 -1.80e-01 -1.87e-01 -1.86e-01 -2.20e-01 -4.43e-02 -2.00e-03 -1.68e-01 -1.60e-01 -1.63e-01 -1.78e-01 -2.12e-01 -9.86e-02 -2.96e-03 -1.56e-01 -1.59e-01 -1.63e-01 -1.72e-01 -1.81e-01 -7.15e-02 -1.77e-03 -1.58e-01 -1.80e-01 -1.87e-01 -1.66e-01 -1.66e-01 -1.22e-02 -2.65e-03 -2.11e-02 -3.01e-02 -4.85e-02 -1.48e-02 -4.67e-02 -5.38e-03 -1.01e-03 -8.10e-04 -8.55e-04 -1.43e-03 -1.63e-03 -1.05e-03 -1.04e-03 -6.84e-04 -2.01e-01 -2.17e-01 -2.26e-01 -2.37e-01 -2.45e-01 -3.25e-02 -2.68e-02 -2.09e-01 -2.09e-01 -2.07e-01 -2.02e-01 -2.15e-01 -2.42e-02 -2.97e-03 -2.01e-01 -1.94e-01 -1.93e-01 -1.80e-01 -1.72e-01 -1.32e-02 -1.54e-03 -1.84e-01 -1.87e-01 -1.63e-01 -1.49e-01 -1.50e-01 -6.42e-02 -1.91e-03 -1.93e-01 -2.15e-01 -1.93e-01 -1.42e-01 -1.22e-01 -7.21e-03 -9.37e-04 -1.67e-02 -5.33e-02 -5.24e-02 -1.13e-02 -1.23e-02 -4.44e-03 -6.14e-04 -7.25e-04 -6.85e-04 -8.30e-04 -9.75e-04 -6.78e-04 -5.52e-04 -5.29e-04 -2.82e-01 -2.73e-01 -2.85e-01 -2.57e-01 -2.70e-01 -2.24e-02 -2.57e-03 -2.52e-01 -2.49e-01 -2.38e-01 -2.53e-01 -2.37e-01 -1.48e-02 -2.30e-03 -2.18e-01 -2.22e-01 -2.20e-01 -1.96e-01 -1.80e-01 -1.93e-02 -1.53e-03 -2.21e-01 -2.39e-01 -1.99e-01 -1.67e-01 -1.45e-01 -1.11e-02 -8.58e-04 -2.57e-01 -2.32e-01 -1.89e-01 -1.26e-01 -8.31e-02 -8.12e-03 -6.25e-04 -8.53e-02 -7.87e-02 -1.53e-02 -1.22e-02 -7.53e-03 -1.75e-03 -3.39e-04 -1.08e-03 -8.97e-04 -6.11e-04 -5.24e-04 -4.33e-04 -2.49e-04 -2.36e-04 -4.78e-01 -1.38e-01 -5.00e-01 -2.99e-02 -3.12e-02 -1.07e-01 -1.42e-03 -3.01e-01 -4.37e-02 -1.79e-01 -2.39e-01 -7.54e-02 -1.13e-02 -1.17e-03 -3.44e-01 -2.30e-01 -5.55e-02 -5.69e-02 -1.70e-02 -8.02e-03 -8.18e-04 -1.77e-01 -6.57e-02 -6.14e-02 -3.20e-02 -1.32e-02 -6.75e-03 -6.17e-04 -3.49e-02 -1.65e-02 -1.95e-02 -8.71e-03 -9.02e-03 -2.07e-03 -3.41e-04 -7.97e-02 -2.60e-02 -1.65e-02 -6.67e-03 -2.61e-03 -5.74e-04 -1.41e-04 -1.62e-03 -1.49e-03 -8.36e-04 -3.95e-04 -2.37e-04 -1.32e-04 -5.59e-05 -1.07e-03 -9.93e-04 -1.63e-03 -6.02e-03 -1.30e-03 -2.86e-03 -2.98e-03 -1.02e-03 -1.31e-03 -1.39e-03 -2.62e-03 -1.69e-03 -2.40e-03 -3.96e-03 -1.26e-03 -1.78e-03 -1.30e-03 -1.06e-03 -1.79e-03 -1.40e-03 -3.18e-03 -1.93e-03 -1.72e-03 -1.78e-03 -8.41e-04 -8.66e-04 -8.00e-04 -1.01e-03 -1.54e-03 -1.30e-03 -1.11e-03 -9.80e-04 -5.02e-04 -3.11e-04 -3.49e-04 -1.24e-03 -1.66e-03 -8.20e-04 -5.29e-04 -3.62e-04 -1.27e-04 -6.03e-05 -6.28e-04 -6.20e-04 -5.01e-04 -4.28e-04 -2.95e-04 -5.38e-05 -6.24e-06 -Upper Bounds -7.61e-01 -7.65e-01 -8.88e-01 -9.87e-01 -1.21e+00 -1.97e+00 -1.13e-02 -7.17e-01 -7.88e-01 -8.74e-01 -9.32e-01 -1.03e+00 -2.41e-01 -1.06e-02 -6.53e-01 -6.86e-01 -8.03e-01 -8.82e-01 -1.02e+00 -5.77e-01 -2.52e-02 -5.23e-01 -6.53e-01 -7.46e-01 -8.58e-01 -9.06e-01 -2.12e-01 -2.66e-02 -3.40e-01 -4.99e-01 -7.82e-01 -8.41e-01 -8.89e-01 -6.94e-02 -2.75e-02 -1.34e-02 -3.33e-02 -1.18e-01 -8.26e-02 -8.54e-02 -5.62e-02 -9.71e-03 -5.62e-04 -2.72e-03 -6.16e-03 -7.54e-03 -7.55e-03 -6.53e-03 -6.05e-03 -7.58e-01 -7.99e-01 -9.04e-01 -1.01e+00 -1.08e+00 -1.29e-01 -1.03e-02 -7.25e-01 -7.95e-01 -9.18e-01 -1.03e+00 -1.07e+00 -4.41e-01 -1.46e-02 -6.80e-01 -7.67e-01 -8.04e-01 -9.61e-01 -1.14e+00 -9.09e-01 -1.35e-02 -5.92e-01 -7.08e-01 -7.60e-01 -9.05e-01 -9.92e-01 -1.43e-01 -3.23e-02 -5.02e-01 -7.06e-01 -9.01e-01 -8.64e-01 -1.02e+00 -5.44e-01 -1.64e-02 -2.68e-02 -7.22e-02 -2.27e-01 -1.08e-01 -3.77e-01 -1.19e-01 -6.91e-03 -2.26e-03 -5.54e-03 -6.95e-03 -6.66e-03 -6.32e-03 -6.08e-03 -4.89e-03 -9.15e-01 -8.87e-01 -9.13e-01 -1.02e+00 -1.13e+00 -3.85e-01 -1.78e-02 -8.13e-01 -9.00e-01 -9.37e-01 -9.28e-01 -1.10e+00 -2.22e-01 -9.99e-03 -8.40e-01 -8.02e-01 -8.17e-01 -8.90e-01 -1.06e+00 -4.93e-01 -1.48e-02 -7.81e-01 -7.93e-01 -8.16e-01 -8.61e-01 -9.05e-01 -3.58e-01 -8.84e-03 -7.91e-01 -9.00e-01 -9.34e-01 -8.31e-01 -8.31e-01 -6.09e-02 -1.33e-02 -1.06e-01 -1.50e-01 -2.43e-01 -7.38e-02 -2.33e-01 -2.69e-02 -5.07e-03 -4.05e-03 -4.28e-03 -7.13e-03 -8.17e-03 -5.26e-03 -5.20e-03 -3.42e-03 -1.01e+00 -1.09e+00 -1.13e+00 -1.18e+00 -1.22e+00 -1.62e-01 -1.34e-01 -1.05e+00 -1.04e+00 -1.03e+00 -1.01e+00 -1.07e+00 -1.21e-01 -1.49e-02 -1.00e+00 -9.68e-01 -9.64e-01 -9.01e-01 -8.62e-01 -6.59e-02 -7.71e-03 -9.19e-01 -9.37e-01 -8.13e-01 -7.43e-01 -7.51e-01 -3.21e-01 -9.55e-03 -9.63e-01 -1.07e+00 -9.67e-01 -7.12e-01 -6.10e-01 -3.60e-02 -4.68e-03 -8.33e-02 -2.66e-01 -2.62e-01 -5.67e-02 -6.16e-02 -2.22e-02 -3.07e-03 -3.63e-03 -3.42e-03 -4.15e-03 -4.88e-03 -3.39e-03 -2.76e-03 -2.65e-03 -1.41e+00 -1.36e+00 -1.42e+00 -1.28e+00 -1.35e+00 -1.12e-01 -1.28e-02 -1.26e+00 -1.24e+00 -1.19e+00 -1.26e+00 -1.18e+00 -7.42e-02 -1.15e-02 -1.09e+00 -1.11e+00 -1.10e+00 -9.79e-01 -9.01e-01 -9.64e-02 -7.63e-03 -1.11e+00 -1.19e+00 -9.95e-01 -8.35e-01 -7.23e-01 -5.53e-02 -4.29e-03 -1.28e+00 -1.16e+00 -9.47e-01 -6.30e-01 -4.16e-01 -4.06e-02 -3.13e-03 -4.27e-01 -3.94e-01 -7.67e-02 -6.12e-02 -3.77e-02 -8.74e-03 -1.70e-03 -5.41e-03 -4.48e-03 -3.06e-03 -2.62e-03 -2.16e-03 -1.25e-03 -1.18e-03 -2.39e+00 -6.90e-01 -2.50e+00 -1.50e-01 -1.56e-01 -5.36e-01 -7.11e-03 -1.50e+00 -2.18e-01 -8.93e-01 -1.20e+00 -3.77e-01 -5.66e-02 -5.84e-03 -1.72e+00 -1.15e+00 -2.77e-01 -2.84e-01 -8.51e-02 -4.01e-02 -4.09e-03 -8.84e-01 -3.28e-01 -3.07e-01 -1.60e-01 -6.60e-02 -3.37e-02 -3.08e-03 -1.74e-01 -8.27e-02 -9.77e-02 -4.36e-02 -4.51e-02 -1.03e-02 -1.71e-03 -3.98e-01 -1.30e-01 -8.25e-02 -3.33e-02 -1.30e-02 -2.87e-03 -7.05e-04 -8.08e-03 -7.43e-03 -4.18e-03 -1.97e-03 -1.18e-03 -6.58e-04 -2.80e-04 -5.36e-03 -4.96e-03 -8.16e-03 -3.01e-02 -6.48e-03 -1.43e-02 -1.49e-02 -5.08e-03 -6.57e-03 -6.95e-03 -1.31e-02 -8.44e-03 -1.20e-02 -1.98e-02 -6.30e-03 -8.90e-03 -6.49e-03 -5.28e-03 -8.94e-03 -7.00e-03 -1.59e-02 -9.64e-03 -8.62e-03 -8.88e-03 -4.21e-03 -4.33e-03 -4.00e-03 -5.04e-03 -7.71e-03 -6.51e-03 -5.56e-03 -4.90e-03 -2.51e-03 -1.55e-03 -1.75e-03 -6.19e-03 -8.31e-03 -4.10e-03 -2.65e-03 -1.81e-03 -6.34e-04 -3.01e-04 -3.14e-03 -3.10e-03 -2.51e-03 -2.14e-03 -1.47e-03 -2.69e-04 -3.12e-05 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows_fw_cadis_local/test.py b/tests/regression_tests/weightwindows_fw_cadis_local/test.py deleted file mode 100644 index abd3f2098..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_local/test.py +++ /dev/null @@ -1,42 +0,0 @@ -import os - -import openmc -from openmc.examples import random_ray_three_region_cube_with_detectors - -from tests.testing_harness import WeightWindowPyAPITestHarness - - -class MGXSTestHarness(WeightWindowPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -def test_weight_windows_fw_cadis_local(): - model = random_ray_three_region_cube_with_detectors() - - for tally in list(model.tallies): - if tally.name in {"Source Tally", "Absorber Tally", "Cavity Tally"}: - # leave only the tallies of interest - model.tallies.remove(tally) - - 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", - targets=model.tallies, - mesh=ww_mesh, - max_realizations=model.settings.batches - ) - model.settings.weight_window_generators = wwg - model.settings.random_ray['volume_estimator'] = 'naive' - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/__init__.py b/tests/regression_tests/weightwindows_fw_cadis_mesh/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat deleted file mode 100644 index a0d84257a..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat +++ /dev/null @@ -1,267 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 750 - 30 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - - 1 - neutron - 10 - 1 - true - fw_cadis - - - - 15 15 15 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - - flat - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/results_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/results_true.dat deleted file mode 100644 index 0354501d1..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/results_true.dat +++ /dev/null @@ -1,6760 +0,0 @@ -RegularMesh - ID = 1 - Name = - Dimensions = 3 - Voxels = [15 15 15] - Lower left = [0. 0. 0.] - Upper Right = [np.float64(30.0), np.float64(30.0), np.float64(30.0)] - Width = [2. 2. 2.] -Lower Bounds -1.71e-01 -1.73e-01 -1.72e-01 -1.73e-01 -1.71e-01 -1.63e-01 -1.66e-01 -1.70e-01 -1.68e-01 -1.76e-01 -1.73e-01 -1.79e-01 -2.62e-01 -4.44e-01 -1.68e-01 -1.63e-01 -1.76e-01 -1.73e-01 -1.52e-01 -1.66e-01 -1.72e-01 -1.68e-01 -1.68e-01 -1.66e-01 -1.67e-01 -1.76e-01 -1.73e-01 -2.44e-01 -3.63e-01 -1.22e-01 -1.71e-01 -1.66e-01 -1.69e-01 -1.70e-01 -1.67e-01 -1.71e-01 -1.64e-01 -1.55e-01 -1.67e-01 -1.64e-01 -1.68e-01 -1.82e-01 -2.60e-01 -4.13e-01 -1.55e-01 -1.68e-01 -1.62e-01 -1.66e-01 -1.65e-01 -1.62e-01 -1.64e-01 -1.63e-01 -1.66e-01 -1.63e-01 -1.67e-01 -1.58e-01 -1.79e-01 -2.52e-01 -4.10e-01 -1.35e-01 -1.65e-01 -1.74e-01 -1.67e-01 -1.71e-01 -1.66e-01 -1.62e-01 -1.60e-01 -1.66e-01 -1.55e-01 -1.67e-01 -1.66e-01 -1.82e-01 -2.68e-01 -3.46e-01 -1.32e-01 -1.70e-01 -1.70e-01 -1.68e-01 -1.68e-01 -1.69e-01 -1.59e-01 -1.62e-01 -1.59e-01 -1.57e-01 -1.55e-01 -1.72e-01 -1.80e-01 -2.59e-01 -2.97e-01 -1.06e-01 -1.68e-01 -1.60e-01 -1.58e-01 -1.61e-01 -1.58e-01 -1.59e-01 -1.56e-01 -1.53e-01 -1.57e-01 -1.52e-01 -1.59e-01 -1.54e-01 -2.42e-01 -3.30e-01 -1.22e-01 -1.64e-01 -1.65e-01 -1.69e-01 -1.64e-01 -1.60e-01 -1.66e-01 -1.60e-01 -1.52e-01 -1.45e-01 -1.53e-01 -1.57e-01 -1.40e-01 -2.08e-01 -1.90e-01 -7.93e-02 -1.65e-01 -1.65e-01 -1.71e-01 -1.72e-01 -1.63e-01 -1.61e-01 -1.57e-01 -1.54e-01 -1.49e-01 -1.41e-01 -1.45e-01 -1.53e-01 -2.36e-01 -1.80e-01 -5.76e-02 -1.67e-01 -1.75e-01 -1.74e-01 -1.71e-01 -1.66e-01 -1.54e-01 -1.55e-01 -1.52e-01 -1.53e-01 -1.41e-01 -1.53e-01 -1.49e-01 -2.14e-01 -1.76e-01 -6.70e-02 -1.72e-01 -1.66e-01 -1.74e-01 -1.70e-01 -1.69e-01 -1.57e-01 -1.50e-01 -1.53e-01 -1.48e-01 -1.47e-01 -1.62e-01 -1.49e-01 -2.03e-01 -1.35e-01 -4.07e-02 -1.81e-01 -1.80e-01 -1.72e-01 -1.65e-01 -1.84e-01 -1.74e-01 -1.58e-01 -1.68e-01 -1.59e-01 -1.57e-01 -1.58e-01 -1.48e-01 -2.16e-01 -1.05e-01 -3.37e-02 -2.61e-01 -2.52e-01 -2.37e-01 -2.51e-01 -2.64e-01 -2.42e-01 -2.39e-01 -2.32e-01 -2.32e-01 -2.29e-01 -2.22e-01 -2.19e-01 -2.07e-01 -8.02e-02 -2.21e-02 -5.00e-01 -3.68e-01 -3.88e-01 -2.65e-01 -2.86e-01 -3.17e-01 -2.60e-01 -2.38e-01 -1.88e-01 -1.97e-01 -1.84e-01 -1.50e-01 -9.98e-02 -3.88e-02 -1.90e-02 -2.18e-01 -1.48e-01 -1.61e-01 -8.76e-02 -9.43e-02 -1.16e-01 -8.45e-02 -8.13e-02 -7.00e-02 -6.16e-02 -6.49e-02 -4.46e-02 -3.71e-02 -1.62e-02 -7.33e-03 -1.70e-01 -1.69e-01 -1.70e-01 -1.68e-01 -1.63e-01 -1.59e-01 -1.75e-01 -1.69e-01 -1.59e-01 -1.64e-01 -1.77e-01 -1.79e-01 -2.63e-01 -3.92e-01 -1.48e-01 -1.73e-01 -1.74e-01 -1.70e-01 -1.66e-01 -1.68e-01 -1.62e-01 -1.62e-01 -1.67e-01 -1.60e-01 -1.64e-01 -1.67e-01 -1.80e-01 -2.42e-01 -3.72e-01 -1.45e-01 -1.71e-01 -1.65e-01 -1.67e-01 -1.65e-01 -1.69e-01 -1.70e-01 -1.64e-01 -1.68e-01 -1.60e-01 -1.70e-01 -1.70e-01 -1.74e-01 -2.62e-01 -3.29e-01 -1.15e-01 -1.73e-01 -1.75e-01 -1.70e-01 -1.69e-01 -1.69e-01 -1.63e-01 -1.66e-01 -1.63e-01 -1.61e-01 -1.61e-01 -1.70e-01 -1.79e-01 -2.47e-01 -3.64e-01 -1.32e-01 -1.72e-01 -1.73e-01 -1.71e-01 -1.66e-01 -1.63e-01 -1.63e-01 -1.67e-01 -1.60e-01 -1.56e-01 -1.63e-01 -1.72e-01 -1.71e-01 -2.52e-01 -3.43e-01 -1.40e-01 -1.68e-01 -1.70e-01 -1.67e-01 -1.66e-01 -1.72e-01 -1.61e-01 -1.56e-01 -1.56e-01 -1.53e-01 -1.55e-01 -1.65e-01 -1.78e-01 -2.53e-01 -3.66e-01 -1.33e-01 -1.70e-01 -1.69e-01 -1.60e-01 -1.64e-01 -1.70e-01 -1.63e-01 -1.53e-01 -1.50e-01 -1.50e-01 -1.48e-01 -1.53e-01 -1.66e-01 -2.34e-01 -2.99e-01 -1.15e-01 -1.65e-01 -1.63e-01 -1.59e-01 -1.57e-01 -1.59e-01 -1.54e-01 -1.54e-01 -1.47e-01 -1.40e-01 -1.38e-01 -1.27e-01 -1.22e-01 -1.99e-01 -1.77e-01 -7.13e-02 -1.58e-01 -1.75e-01 -1.68e-01 -1.66e-01 -1.66e-01 -1.58e-01 -1.56e-01 -1.44e-01 -1.48e-01 -1.45e-01 -1.37e-01 -1.40e-01 -2.01e-01 -1.36e-01 -4.17e-02 -1.65e-01 -1.76e-01 -1.69e-01 -1.69e-01 -1.57e-01 -1.67e-01 -1.56e-01 -1.50e-01 -1.53e-01 -1.43e-01 -1.51e-01 -1.41e-01 -2.04e-01 -1.50e-01 -4.51e-02 -1.69e-01 -1.75e-01 -1.71e-01 -1.63e-01 -1.69e-01 -1.67e-01 -1.60e-01 -1.50e-01 -1.53e-01 -1.44e-01 -1.57e-01 -1.49e-01 -2.02e-01 -1.35e-01 -4.08e-02 -1.79e-01 -1.72e-01 -1.73e-01 -1.70e-01 -1.74e-01 -1.78e-01 -1.68e-01 -1.59e-01 -1.57e-01 -1.62e-01 -1.62e-01 -1.57e-01 -1.95e-01 -9.20e-02 -3.15e-02 -2.48e-01 -2.65e-01 -2.54e-01 -2.58e-01 -2.80e-01 -2.53e-01 -2.33e-01 -2.40e-01 -2.16e-01 -2.19e-01 -2.43e-01 -2.22e-01 -1.99e-01 -6.18e-02 -1.77e-02 -3.13e-01 -2.98e-01 -2.98e-01 -3.16e-01 -3.67e-01 -3.51e-01 -2.81e-01 -2.76e-01 -2.24e-01 -1.66e-01 -1.70e-01 -1.65e-01 -1.10e-01 -3.67e-02 -1.54e-02 -1.11e-01 -1.10e-01 -1.18e-01 -1.08e-01 -1.34e-01 -1.41e-01 -9.92e-02 -9.96e-02 -9.39e-02 -5.19e-02 -5.40e-02 -5.45e-02 -4.22e-02 -1.88e-02 -7.33e-03 -1.73e-01 -1.68e-01 -1.74e-01 -1.68e-01 -1.60e-01 -1.60e-01 -1.61e-01 -1.59e-01 -1.70e-01 -1.61e-01 -1.62e-01 -1.76e-01 -2.90e-01 -4.08e-01 -1.58e-01 -1.72e-01 -1.68e-01 -1.62e-01 -1.66e-01 -1.59e-01 -1.63e-01 -1.58e-01 -1.60e-01 -1.59e-01 -1.65e-01 -1.63e-01 -1.77e-01 -2.45e-01 -3.92e-01 -1.64e-01 -1.71e-01 -1.74e-01 -1.72e-01 -1.57e-01 -1.65e-01 -1.63e-01 -1.63e-01 -1.69e-01 -1.58e-01 -1.61e-01 -1.61e-01 -1.77e-01 -2.45e-01 -3.36e-01 -1.29e-01 -1.57e-01 -1.67e-01 -1.66e-01 -1.63e-01 -1.63e-01 -1.59e-01 -1.61e-01 -1.65e-01 -1.56e-01 -1.59e-01 -1.65e-01 -1.59e-01 -2.43e-01 -3.30e-01 -1.08e-01 -1.62e-01 -1.62e-01 -1.61e-01 -1.54e-01 -1.63e-01 -1.64e-01 -1.50e-01 -1.57e-01 -1.51e-01 -1.50e-01 -1.67e-01 -1.72e-01 -2.44e-01 -2.79e-01 -8.59e-02 -1.61e-01 -1.64e-01 -1.57e-01 -1.55e-01 -1.57e-01 -1.57e-01 -1.51e-01 -1.49e-01 -1.54e-01 -1.56e-01 -1.67e-01 -1.69e-01 -2.42e-01 -3.48e-01 -1.32e-01 -1.67e-01 -1.73e-01 -1.64e-01 -1.62e-01 -1.60e-01 -1.61e-01 -1.56e-01 -1.47e-01 -1.51e-01 -1.54e-01 -1.57e-01 -1.59e-01 -2.26e-01 -2.53e-01 -9.32e-02 -1.63e-01 -1.63e-01 -1.60e-01 -1.55e-01 -1.57e-01 -1.58e-01 -1.54e-01 -1.47e-01 -1.46e-01 -1.48e-01 -1.43e-01 -1.50e-01 -2.09e-01 -1.68e-01 -6.28e-02 -1.57e-01 -1.64e-01 -1.64e-01 -1.60e-01 -1.60e-01 -1.58e-01 -1.58e-01 -1.57e-01 -1.47e-01 -1.50e-01 -1.52e-01 -1.43e-01 -2.11e-01 -1.66e-01 -6.17e-02 -1.65e-01 -1.72e-01 -1.62e-01 -1.64e-01 -1.66e-01 -1.57e-01 -1.57e-01 -1.50e-01 -1.40e-01 -1.48e-01 -1.46e-01 -1.44e-01 -1.95e-01 -1.25e-01 -4.98e-02 -1.61e-01 -1.66e-01 -1.70e-01 -1.64e-01 -1.67e-01 -1.67e-01 -1.68e-01 -1.58e-01 -1.43e-01 -1.45e-01 -1.46e-01 -1.43e-01 -1.94e-01 -1.25e-01 -3.60e-02 -1.61e-01 -1.74e-01 -1.74e-01 -1.76e-01 -1.73e-01 -1.72e-01 -1.68e-01 -1.61e-01 -1.59e-01 -1.56e-01 -1.59e-01 -1.57e-01 -1.77e-01 -1.09e-01 -3.74e-02 -2.48e-01 -2.48e-01 -2.49e-01 -2.42e-01 -2.47e-01 -2.55e-01 -2.19e-01 -2.25e-01 -2.25e-01 -2.17e-01 -2.21e-01 -2.26e-01 -2.15e-01 -6.24e-02 -1.90e-02 -3.68e-01 -2.72e-01 -3.41e-01 -3.58e-01 -3.64e-01 -2.32e-01 -2.34e-01 -2.20e-01 -1.88e-01 -1.77e-01 -1.34e-01 -1.25e-01 -1.07e-01 -4.68e-02 -1.29e-02 -1.29e-01 -8.63e-02 -1.42e-01 -1.36e-01 -1.37e-01 -8.94e-02 -8.09e-02 -8.37e-02 -5.69e-02 -6.45e-02 -3.15e-02 -3.86e-02 -3.51e-02 -2.57e-02 -1.29e-02 -1.69e-01 -1.62e-01 -1.66e-01 -1.70e-01 -1.69e-01 -1.61e-01 -1.58e-01 -1.51e-01 -1.52e-01 -1.53e-01 -1.52e-01 -1.73e-01 -2.54e-01 -4.12e-01 -1.51e-01 -1.68e-01 -1.75e-01 -1.65e-01 -1.59e-01 -1.62e-01 -1.56e-01 -1.57e-01 -1.55e-01 -1.59e-01 -1.66e-01 -1.59e-01 -1.67e-01 -2.35e-01 -3.25e-01 -1.29e-01 -1.62e-01 -1.64e-01 -1.68e-01 -1.59e-01 -1.51e-01 -1.59e-01 -1.53e-01 -1.53e-01 -1.55e-01 -1.63e-01 -1.60e-01 -1.65e-01 -2.33e-01 -2.78e-01 -1.07e-01 -1.62e-01 -1.63e-01 -1.60e-01 -1.61e-01 -1.54e-01 -1.57e-01 -1.59e-01 -1.51e-01 -1.51e-01 -1.58e-01 -1.54e-01 -1.61e-01 -2.39e-01 -2.48e-01 -1.01e-01 -1.55e-01 -1.54e-01 -1.61e-01 -1.66e-01 -1.55e-01 -1.53e-01 -1.56e-01 -1.51e-01 -1.48e-01 -1.53e-01 -1.63e-01 -1.62e-01 -2.42e-01 -3.21e-01 -1.18e-01 -1.66e-01 -1.52e-01 -1.62e-01 -1.62e-01 -1.56e-01 -1.52e-01 -1.55e-01 -1.57e-01 -1.55e-01 -1.53e-01 -1.53e-01 -1.64e-01 -2.46e-01 -3.02e-01 -1.11e-01 -1.63e-01 -1.59e-01 -1.68e-01 -1.59e-01 -1.52e-01 -1.54e-01 -1.56e-01 -1.49e-01 -1.49e-01 -1.51e-01 -1.45e-01 -1.49e-01 -2.22e-01 -2.88e-01 -1.02e-01 -1.66e-01 -1.62e-01 -1.61e-01 -1.50e-01 -1.50e-01 -1.51e-01 -1.59e-01 -1.46e-01 -1.43e-01 -1.42e-01 -1.41e-01 -1.51e-01 -2.22e-01 -1.88e-01 -6.51e-02 -1.60e-01 -1.59e-01 -1.57e-01 -1.61e-01 -1.55e-01 -1.57e-01 -1.53e-01 -1.53e-01 -1.45e-01 -1.44e-01 -1.47e-01 -1.59e-01 -2.35e-01 -1.91e-01 -5.69e-02 -1.62e-01 -1.59e-01 -1.63e-01 -1.59e-01 -1.55e-01 -1.54e-01 -1.50e-01 -1.47e-01 -1.50e-01 -1.46e-01 -1.43e-01 -1.43e-01 -2.21e-01 -1.37e-01 -5.36e-02 -1.66e-01 -1.65e-01 -1.50e-01 -1.68e-01 -1.65e-01 -1.61e-01 -1.55e-01 -1.49e-01 -1.47e-01 -1.51e-01 -1.43e-01 -1.50e-01 -1.92e-01 -9.97e-02 -2.93e-02 -1.73e-01 -1.65e-01 -1.70e-01 -1.66e-01 -1.73e-01 -1.78e-01 -1.65e-01 -1.50e-01 -1.60e-01 -1.55e-01 -1.57e-01 -1.55e-01 -1.89e-01 -8.91e-02 -2.68e-02 -2.32e-01 -2.36e-01 -2.40e-01 -2.31e-01 -2.41e-01 -2.39e-01 -2.01e-01 -2.12e-01 -2.21e-01 -2.12e-01 -2.04e-01 -2.02e-01 -2.14e-01 -8.26e-02 -2.65e-02 -3.06e-01 -2.51e-01 -2.10e-01 -2.95e-01 -2.86e-01 -2.41e-01 -1.69e-01 -1.21e-01 -1.92e-01 -1.82e-01 -1.29e-01 -1.24e-01 -1.04e-01 -4.53e-02 -1.74e-02 -1.16e-01 -8.31e-02 -8.94e-02 -9.43e-02 -1.16e-01 -9.01e-02 -7.46e-02 -3.83e-02 -6.35e-02 -6.43e-02 -4.23e-02 -4.16e-02 -3.17e-02 -2.60e-02 -1.26e-02 -1.63e-01 -1.58e-01 -1.60e-01 -1.62e-01 -1.60e-01 -1.59e-01 -1.60e-01 -1.51e-01 -1.47e-01 -1.55e-01 -1.51e-01 -1.68e-01 -2.47e-01 -3.18e-01 -1.27e-01 -1.64e-01 -1.61e-01 -1.56e-01 -1.63e-01 -1.63e-01 -1.54e-01 -1.50e-01 -1.49e-01 -1.56e-01 -1.58e-01 -1.58e-01 -1.64e-01 -2.39e-01 -3.04e-01 -1.13e-01 -1.65e-01 -1.63e-01 -1.62e-01 -1.57e-01 -1.57e-01 -1.57e-01 -1.53e-01 -1.49e-01 -1.57e-01 -1.63e-01 -1.63e-01 -1.70e-01 -2.39e-01 -2.29e-01 -8.46e-02 -1.62e-01 -1.63e-01 -1.58e-01 -1.58e-01 -1.56e-01 -1.55e-01 -1.50e-01 -1.51e-01 -1.52e-01 -1.60e-01 -1.57e-01 -1.64e-01 -2.46e-01 -2.16e-01 -7.36e-02 -1.56e-01 -1.54e-01 -1.56e-01 -1.62e-01 -1.52e-01 -1.50e-01 -1.55e-01 -1.52e-01 -1.52e-01 -1.50e-01 -1.58e-01 -1.67e-01 -2.47e-01 -3.21e-01 -1.15e-01 -1.57e-01 -1.55e-01 -1.56e-01 -1.58e-01 -1.48e-01 -1.43e-01 -1.42e-01 -1.56e-01 -1.49e-01 -1.52e-01 -1.51e-01 -1.58e-01 -2.31e-01 -2.63e-01 -9.53e-02 -1.48e-01 -1.56e-01 -1.59e-01 -1.52e-01 -1.60e-01 -1.43e-01 -1.43e-01 -1.44e-01 -1.45e-01 -1.43e-01 -1.48e-01 -1.51e-01 -2.09e-01 -2.10e-01 -7.84e-02 -1.57e-01 -1.60e-01 -1.55e-01 -1.53e-01 -1.57e-01 -1.44e-01 -1.44e-01 -1.36e-01 -1.36e-01 -1.46e-01 -1.43e-01 -1.46e-01 -2.17e-01 -1.67e-01 -7.08e-02 -1.59e-01 -1.56e-01 -1.56e-01 -1.54e-01 -1.53e-01 -1.52e-01 -1.50e-01 -1.42e-01 -1.37e-01 -1.39e-01 -1.41e-01 -1.47e-01 -2.03e-01 -1.75e-01 -5.51e-02 -1.63e-01 -1.62e-01 -1.57e-01 -1.53e-01 -1.45e-01 -1.52e-01 -1.52e-01 -1.43e-01 -1.41e-01 -1.38e-01 -1.39e-01 -1.52e-01 -2.05e-01 -1.61e-01 -6.97e-02 -1.62e-01 -1.56e-01 -1.58e-01 -1.55e-01 -1.58e-01 -1.56e-01 -1.53e-01 -1.53e-01 -1.49e-01 -1.41e-01 -1.44e-01 -1.57e-01 -2.11e-01 -1.22e-01 -4.27e-02 -1.66e-01 -1.69e-01 -1.61e-01 -1.62e-01 -1.68e-01 -1.74e-01 -1.60e-01 -1.57e-01 -1.57e-01 -1.62e-01 -1.48e-01 -1.54e-01 -2.17e-01 -1.14e-01 -3.49e-02 -2.43e-01 -2.30e-01 -2.33e-01 -2.43e-01 -2.45e-01 -2.48e-01 -2.46e-01 -2.21e-01 -2.22e-01 -2.12e-01 -2.00e-01 -2.02e-01 -2.14e-01 -8.94e-02 -3.01e-02 -2.79e-01 -2.63e-01 -2.52e-01 -2.63e-01 -3.00e-01 -2.68e-01 -2.93e-01 -1.90e-01 -2.03e-01 -1.54e-01 -1.13e-01 -1.27e-01 -8.82e-02 -3.87e-02 -1.55e-02 -1.03e-01 -9.09e-02 -9.09e-02 -8.99e-02 -1.07e-01 -8.75e-02 -1.17e-01 -5.67e-02 -7.16e-02 -5.22e-02 -3.31e-02 -3.49e-02 -2.69e-02 -1.66e-02 -1.14e-02 -1.46e-01 -1.55e-01 -1.57e-01 -1.59e-01 -1.63e-01 -1.54e-01 -1.49e-01 -1.48e-01 -1.45e-01 -1.48e-01 -1.48e-01 -1.54e-01 -2.45e-01 -2.69e-01 -8.34e-02 -1.54e-01 -1.59e-01 -1.57e-01 -1.51e-01 -1.55e-01 -1.57e-01 -1.60e-01 -1.49e-01 -1.54e-01 -1.50e-01 -1.54e-01 -1.62e-01 -2.41e-01 -2.97e-01 -1.15e-01 -1.60e-01 -1.61e-01 -1.61e-01 -1.53e-01 -1.56e-01 -1.52e-01 -1.53e-01 -1.57e-01 -1.52e-01 -1.52e-01 -1.55e-01 -1.69e-01 -2.49e-01 -2.52e-01 -8.15e-02 -1.59e-01 -1.59e-01 -1.52e-01 -1.50e-01 -1.53e-01 -1.59e-01 -1.47e-01 -1.51e-01 -1.51e-01 -1.56e-01 -1.56e-01 -1.64e-01 -2.40e-01 -2.46e-01 -8.06e-02 -1.58e-01 -1.59e-01 -1.58e-01 -1.56e-01 -1.53e-01 -1.46e-01 -1.48e-01 -1.48e-01 -1.47e-01 -1.53e-01 -1.48e-01 -1.62e-01 -2.39e-01 -2.66e-01 -1.02e-01 -1.55e-01 -1.54e-01 -1.57e-01 -1.52e-01 -1.48e-01 -1.50e-01 -1.40e-01 -1.37e-01 -1.50e-01 -1.50e-01 -1.46e-01 -1.52e-01 -2.23e-01 -2.22e-01 -8.99e-02 -1.58e-01 -1.60e-01 -1.54e-01 -1.47e-01 -1.47e-01 -1.45e-01 -1.42e-01 -1.28e-01 -1.33e-01 -1.40e-01 -1.51e-01 -1.53e-01 -2.08e-01 -1.44e-01 -5.19e-02 -1.57e-01 -1.54e-01 -1.54e-01 -1.42e-01 -1.51e-01 -1.44e-01 -1.35e-01 -1.28e-01 -1.11e-01 -1.40e-01 -1.49e-01 -1.55e-01 -2.22e-01 -1.31e-01 -4.13e-02 -1.56e-01 -1.53e-01 -1.57e-01 -1.42e-01 -1.52e-01 -1.49e-01 -1.45e-01 -1.32e-01 -1.30e-01 -1.27e-01 -1.41e-01 -1.41e-01 -2.11e-01 -1.55e-01 -4.43e-02 -1.49e-01 -1.52e-01 -1.53e-01 -1.56e-01 -1.47e-01 -1.45e-01 -1.40e-01 -1.37e-01 -1.43e-01 -1.35e-01 -1.34e-01 -1.42e-01 -1.98e-01 -1.25e-01 -3.99e-02 -1.57e-01 -1.48e-01 -1.49e-01 -1.52e-01 -1.50e-01 -1.48e-01 -1.50e-01 -1.48e-01 -1.44e-01 -1.43e-01 -1.35e-01 -1.39e-01 -1.94e-01 -1.07e-01 -3.11e-02 -1.62e-01 -1.61e-01 -1.61e-01 -1.63e-01 -1.63e-01 -1.60e-01 -1.55e-01 -1.55e-01 -1.50e-01 -1.56e-01 -1.43e-01 -1.32e-01 -1.83e-01 -1.02e-01 -2.51e-02 -2.34e-01 -2.25e-01 -2.20e-01 -2.27e-01 -2.41e-01 -2.34e-01 -2.13e-01 -2.04e-01 -2.13e-01 -2.16e-01 -2.20e-01 -1.80e-01 -1.76e-01 -9.68e-02 -3.54e-02 -3.12e-01 -2.64e-01 -2.26e-01 -2.68e-01 -2.60e-01 -2.43e-01 -2.35e-01 -1.81e-01 -1.60e-01 -1.47e-01 -1.51e-01 -1.34e-01 -7.35e-02 -4.05e-02 -2.19e-02 -1.06e-01 -9.90e-02 -8.77e-02 -9.61e-02 -9.91e-02 -7.56e-02 -1.05e-01 -6.20e-02 -5.67e-02 -3.97e-02 -4.31e-02 -4.78e-02 -2.87e-02 -1.59e-02 -8.92e-03 -1.61e-01 -1.59e-01 -1.56e-01 -1.59e-01 -1.51e-01 -1.49e-01 -1.54e-01 -1.51e-01 -1.53e-01 -1.48e-01 -1.52e-01 -1.48e-01 -2.27e-01 -1.82e-01 -8.22e-02 -1.61e-01 -1.54e-01 -1.57e-01 -1.56e-01 -1.53e-01 -1.49e-01 -1.46e-01 -1.41e-01 -1.51e-01 -1.51e-01 -1.52e-01 -1.52e-01 -2.22e-01 -2.08e-01 -7.81e-02 -1.54e-01 -1.58e-01 -1.52e-01 -1.53e-01 -1.48e-01 -1.49e-01 -1.45e-01 -1.43e-01 -1.44e-01 -1.48e-01 -1.58e-01 -1.55e-01 -2.25e-01 -2.48e-01 -1.01e-01 -1.57e-01 -1.48e-01 -1.51e-01 -1.47e-01 -1.46e-01 -1.52e-01 -1.48e-01 -1.47e-01 -1.46e-01 -1.48e-01 -1.49e-01 -1.57e-01 -2.21e-01 -1.69e-01 -6.52e-02 -1.57e-01 -1.55e-01 -1.55e-01 -1.53e-01 -1.51e-01 -1.55e-01 -1.46e-01 -1.49e-01 -1.42e-01 -1.45e-01 -1.45e-01 -1.57e-01 -2.19e-01 -1.36e-01 -4.96e-02 -1.57e-01 -1.50e-01 -1.53e-01 -1.57e-01 -1.54e-01 -1.50e-01 -1.45e-01 -1.40e-01 -1.30e-01 -1.38e-01 -1.42e-01 -1.51e-01 -2.13e-01 -1.41e-01 -4.31e-02 -1.56e-01 -1.57e-01 -1.53e-01 -1.52e-01 -1.51e-01 -1.44e-01 -1.42e-01 -1.28e-01 -1.21e-01 -1.26e-01 -1.40e-01 -1.53e-01 -2.16e-01 -1.61e-01 -4.81e-02 -1.48e-01 -1.48e-01 -1.47e-01 -1.49e-01 -1.49e-01 -1.43e-01 -1.40e-01 -1.23e-01 -8.97e-02 -1.34e-01 -1.43e-01 -1.48e-01 -2.10e-01 -1.68e-01 -5.02e-02 -1.53e-01 -1.48e-01 -1.47e-01 -1.48e-01 -1.43e-01 -1.46e-01 -1.42e-01 -1.27e-01 -1.24e-01 -1.31e-01 -1.42e-01 -1.48e-01 -2.01e-01 -1.56e-01 -5.15e-02 -1.50e-01 -1.52e-01 -1.52e-01 -1.47e-01 -1.42e-01 -1.35e-01 -1.39e-01 -1.38e-01 -1.37e-01 -1.35e-01 -1.36e-01 -1.36e-01 -1.92e-01 -1.22e-01 -4.76e-02 -1.52e-01 -1.61e-01 -1.49e-01 -1.45e-01 -1.40e-01 -1.40e-01 -1.34e-01 -1.35e-01 -1.38e-01 -1.38e-01 -1.27e-01 -1.35e-01 -1.77e-01 -7.50e-02 -2.64e-02 -1.58e-01 -1.55e-01 -1.50e-01 -1.45e-01 -1.50e-01 -1.50e-01 -1.42e-01 -1.42e-01 -1.52e-01 -1.46e-01 -1.38e-01 -1.30e-01 -1.44e-01 -6.83e-02 -2.86e-02 -2.28e-01 -2.11e-01 -2.08e-01 -2.12e-01 -2.17e-01 -2.09e-01 -2.06e-01 -1.89e-01 -2.08e-01 -1.88e-01 -1.88e-01 -1.66e-01 -1.33e-01 -4.13e-02 -1.70e-02 -2.67e-01 -2.70e-01 -2.31e-01 -1.72e-01 -1.66e-01 -2.16e-01 -1.96e-01 -1.52e-01 -1.41e-01 -1.31e-01 -1.44e-01 -1.17e-01 -4.82e-02 -2.09e-02 -8.63e-03 -9.47e-02 -1.04e-01 -9.02e-02 -5.55e-02 -5.39e-02 -6.95e-02 -7.10e-02 -4.92e-02 -4.73e-02 -3.52e-02 -4.69e-02 -4.03e-02 -1.69e-02 -9.25e-03 -5.98e-03 -1.46e-01 -1.50e-01 -1.48e-01 -1.53e-01 -1.56e-01 -1.57e-01 -1.56e-01 -1.54e-01 -1.44e-01 -1.42e-01 -1.44e-01 -1.52e-01 -2.10e-01 -1.56e-01 -5.53e-02 -1.50e-01 -1.57e-01 -1.57e-01 -1.57e-01 -1.54e-01 -1.51e-01 -1.52e-01 -1.42e-01 -1.42e-01 -1.39e-01 -1.45e-01 -1.50e-01 -2.11e-01 -1.18e-01 -3.92e-02 -1.49e-01 -1.48e-01 -1.55e-01 -1.54e-01 -1.51e-01 -1.50e-01 -1.48e-01 -1.48e-01 -1.41e-01 -1.38e-01 -1.45e-01 -1.54e-01 -2.08e-01 -1.62e-01 -5.89e-02 -1.48e-01 -1.49e-01 -1.51e-01 -1.50e-01 -1.51e-01 -1.49e-01 -1.48e-01 -1.47e-01 -1.34e-01 -1.33e-01 -1.53e-01 -1.54e-01 -1.96e-01 -1.55e-01 -6.15e-02 -1.51e-01 -1.53e-01 -1.59e-01 -1.48e-01 -1.51e-01 -1.48e-01 -1.45e-01 -1.41e-01 -1.38e-01 -1.37e-01 -1.49e-01 -1.46e-01 -2.06e-01 -1.25e-01 -3.47e-02 -1.51e-01 -1.47e-01 -1.52e-01 -1.53e-01 -1.44e-01 -1.40e-01 -1.45e-01 -1.38e-01 -1.39e-01 -1.34e-01 -1.36e-01 -1.50e-01 -1.95e-01 -1.29e-01 -4.48e-02 -1.49e-01 -1.43e-01 -1.49e-01 -1.46e-01 -1.48e-01 -1.42e-01 -1.35e-01 -1.27e-01 -1.24e-01 -1.26e-01 -1.29e-01 -1.38e-01 -1.87e-01 -1.53e-01 -5.84e-02 -1.46e-01 -1.51e-01 -1.44e-01 -1.45e-01 -1.45e-01 -1.41e-01 -1.31e-01 -1.24e-01 -1.29e-01 -1.30e-01 -1.43e-01 -1.42e-01 -1.91e-01 -1.36e-01 -5.08e-02 -1.39e-01 -1.40e-01 -1.43e-01 -1.39e-01 -1.43e-01 -1.39e-01 -1.35e-01 -1.27e-01 -1.23e-01 -1.22e-01 -1.41e-01 -1.37e-01 -1.86e-01 -1.09e-01 -3.41e-02 -1.44e-01 -1.41e-01 -1.44e-01 -1.37e-01 -1.37e-01 -1.39e-01 -1.29e-01 -1.33e-01 -1.20e-01 -1.18e-01 -1.29e-01 -1.36e-01 -1.94e-01 -1.23e-01 -3.96e-02 -1.50e-01 -1.47e-01 -1.48e-01 -1.39e-01 -1.35e-01 -1.36e-01 -1.34e-01 -1.40e-01 -1.32e-01 -1.27e-01 -1.23e-01 -1.26e-01 -1.61e-01 -8.34e-02 -2.18e-02 -1.58e-01 -1.51e-01 -1.50e-01 -1.46e-01 -1.45e-01 -1.35e-01 -1.30e-01 -1.41e-01 -1.39e-01 -1.36e-01 -1.32e-01 -1.22e-01 -1.45e-01 -5.48e-02 -1.56e-02 -2.28e-01 -2.05e-01 -2.09e-01 -1.89e-01 -2.03e-01 -1.97e-01 -1.63e-01 -1.67e-01 -1.68e-01 -1.92e-01 -1.83e-01 -1.55e-01 -1.14e-01 -3.43e-02 -1.15e-02 -2.24e-01 -2.31e-01 -1.67e-01 -1.43e-01 -1.53e-01 -1.76e-01 -1.13e-01 -9.76e-02 -8.62e-02 -1.49e-01 -1.29e-01 -8.35e-02 -4.44e-02 -1.21e-02 -4.84e-03 -7.75e-02 -7.83e-02 -5.37e-02 -5.23e-02 -4.63e-02 -6.06e-02 -4.19e-02 -3.16e-02 -2.72e-02 -5.09e-02 -4.06e-02 -2.76e-02 -1.94e-02 -8.81e-03 -2.34e-03 -1.54e-01 -1.58e-01 -1.62e-01 -1.48e-01 -1.57e-01 -1.52e-01 -1.49e-01 -1.54e-01 -1.42e-01 -1.36e-01 -1.36e-01 -1.50e-01 -2.08e-01 -1.23e-01 -3.56e-02 -1.51e-01 -1.53e-01 -1.59e-01 -1.57e-01 -1.46e-01 -1.55e-01 -1.50e-01 -1.49e-01 -1.41e-01 -1.41e-01 -1.42e-01 -1.48e-01 -2.00e-01 -1.32e-01 -4.13e-02 -1.48e-01 -1.50e-01 -1.53e-01 -1.52e-01 -1.54e-01 -1.42e-01 -1.48e-01 -1.50e-01 -1.40e-01 -1.37e-01 -1.38e-01 -1.53e-01 -2.20e-01 -1.65e-01 -5.51e-02 -1.52e-01 -1.44e-01 -1.49e-01 -1.46e-01 -1.48e-01 -1.48e-01 -1.45e-01 -1.46e-01 -1.38e-01 -1.40e-01 -1.43e-01 -1.39e-01 -1.95e-01 -1.78e-01 -7.38e-02 -1.48e-01 -1.45e-01 -1.44e-01 -1.47e-01 -1.46e-01 -1.44e-01 -1.42e-01 -1.45e-01 -1.43e-01 -1.37e-01 -1.43e-01 -1.49e-01 -1.94e-01 -1.37e-01 -4.11e-02 -1.52e-01 -1.48e-01 -1.45e-01 -1.38e-01 -1.38e-01 -1.40e-01 -1.41e-01 -1.32e-01 -1.36e-01 -1.36e-01 -1.37e-01 -1.48e-01 -2.02e-01 -1.53e-01 -5.25e-02 -1.45e-01 -1.44e-01 -1.44e-01 -1.36e-01 -1.36e-01 -1.36e-01 -1.33e-01 -1.32e-01 -1.26e-01 -1.32e-01 -1.37e-01 -1.38e-01 -1.71e-01 -1.19e-01 -4.26e-02 -1.40e-01 -1.43e-01 -1.46e-01 -1.39e-01 -1.38e-01 -1.34e-01 -1.29e-01 -1.26e-01 -1.28e-01 -1.28e-01 -1.34e-01 -1.39e-01 -1.70e-01 -7.71e-02 -3.01e-02 -1.38e-01 -1.35e-01 -1.38e-01 -1.41e-01 -1.44e-01 -1.46e-01 -1.34e-01 -1.28e-01 -1.24e-01 -1.20e-01 -1.22e-01 -1.33e-01 -1.84e-01 -8.77e-02 -2.26e-02 -1.45e-01 -1.37e-01 -1.37e-01 -1.29e-01 -1.34e-01 -1.37e-01 -1.34e-01 -1.29e-01 -1.23e-01 -1.19e-01 -1.21e-01 -1.25e-01 -1.84e-01 -9.18e-02 -2.31e-02 -1.48e-01 -1.32e-01 -1.36e-01 -1.34e-01 -1.41e-01 -1.34e-01 -1.32e-01 -1.27e-01 -1.27e-01 -1.20e-01 -1.10e-01 -1.17e-01 -1.65e-01 -9.68e-02 -2.83e-02 -1.48e-01 -1.35e-01 -1.35e-01 -1.43e-01 -1.44e-01 -1.40e-01 -1.43e-01 -1.35e-01 -1.34e-01 -1.29e-01 -1.17e-01 -9.99e-02 -9.90e-02 -5.49e-02 -1.66e-02 -2.22e-01 -2.00e-01 -2.03e-01 -2.10e-01 -2.09e-01 -1.99e-01 -1.86e-01 -1.93e-01 -1.79e-01 -1.90e-01 -1.70e-01 -1.45e-01 -1.22e-01 -4.35e-02 -1.22e-02 -2.30e-01 -1.84e-01 -1.79e-01 -1.67e-01 -1.72e-01 -1.61e-01 -1.13e-01 -1.16e-01 -1.06e-01 -1.13e-01 -1.20e-01 -8.32e-02 -4.37e-02 -1.70e-02 -5.87e-03 -7.01e-02 -5.48e-02 -4.65e-02 -4.76e-02 -5.00e-02 -5.48e-02 -3.77e-02 -3.45e-02 -3.12e-02 -3.14e-02 -3.88e-02 -2.77e-02 -1.27e-02 -6.38e-03 -1.50e-03 -1.48e-01 -1.54e-01 -1.58e-01 -1.56e-01 -1.55e-01 -1.46e-01 -1.44e-01 -1.47e-01 -1.42e-01 -1.44e-01 -1.40e-01 -1.54e-01 -1.94e-01 -1.38e-01 -5.04e-02 -1.51e-01 -1.53e-01 -1.49e-01 -1.49e-01 -1.49e-01 -1.53e-01 -1.51e-01 -1.50e-01 -1.45e-01 -1.36e-01 -1.42e-01 -1.57e-01 -2.09e-01 -1.55e-01 -4.56e-02 -1.55e-01 -1.48e-01 -1.43e-01 -1.44e-01 -1.46e-01 -1.53e-01 -1.50e-01 -1.51e-01 -1.54e-01 -1.38e-01 -1.36e-01 -1.52e-01 -2.10e-01 -1.66e-01 -5.44e-02 -1.48e-01 -1.47e-01 -1.46e-01 -1.43e-01 -1.49e-01 -1.48e-01 -1.51e-01 -1.49e-01 -1.42e-01 -1.38e-01 -1.39e-01 -1.49e-01 -1.94e-01 -1.42e-01 -5.42e-02 -1.43e-01 -1.39e-01 -1.46e-01 -1.48e-01 -1.48e-01 -1.42e-01 -1.41e-01 -1.46e-01 -1.40e-01 -1.38e-01 -1.43e-01 -1.43e-01 -1.95e-01 -1.20e-01 -3.81e-02 -1.49e-01 -1.42e-01 -1.47e-01 -1.42e-01 -1.43e-01 -1.43e-01 -1.42e-01 -1.41e-01 -1.36e-01 -1.33e-01 -1.38e-01 -1.42e-01 -1.87e-01 -1.10e-01 -4.00e-02 -1.46e-01 -1.44e-01 -1.42e-01 -1.42e-01 -1.42e-01 -1.43e-01 -1.36e-01 -1.37e-01 -1.32e-01 -1.37e-01 -1.30e-01 -1.42e-01 -1.97e-01 -1.41e-01 -4.74e-02 -1.42e-01 -1.46e-01 -1.45e-01 -1.44e-01 -1.40e-01 -1.37e-01 -1.29e-01 -1.32e-01 -1.28e-01 -1.22e-01 -1.29e-01 -1.44e-01 -1.79e-01 -8.11e-02 -2.49e-02 -1.36e-01 -1.40e-01 -1.42e-01 -1.45e-01 -1.42e-01 -1.35e-01 -1.28e-01 -1.25e-01 -1.21e-01 -1.20e-01 -1.24e-01 -1.37e-01 -1.76e-01 -8.67e-02 -2.55e-02 -1.41e-01 -1.39e-01 -1.39e-01 -1.42e-01 -1.37e-01 -1.33e-01 -1.30e-01 -1.23e-01 -1.22e-01 -1.24e-01 -1.16e-01 -1.28e-01 -1.68e-01 -1.03e-01 -3.30e-02 -1.41e-01 -1.35e-01 -1.34e-01 -1.33e-01 -1.33e-01 -1.34e-01 -1.37e-01 -1.31e-01 -1.21e-01 -1.17e-01 -1.11e-01 -1.13e-01 -1.57e-01 -8.80e-02 -2.97e-02 -1.53e-01 -1.39e-01 -1.45e-01 -1.45e-01 -1.38e-01 -1.49e-01 -1.41e-01 -1.36e-01 -1.24e-01 -1.23e-01 -1.14e-01 -9.70e-02 -1.01e-01 -5.74e-02 -1.83e-02 -2.39e-01 -1.91e-01 -1.80e-01 -2.07e-01 -1.97e-01 -2.03e-01 -1.92e-01 -2.07e-01 -1.99e-01 -2.04e-01 -1.76e-01 -1.35e-01 -1.07e-01 -3.67e-02 -1.30e-02 -1.91e-01 -1.54e-01 -1.49e-01 -1.68e-01 -1.82e-01 -1.72e-01 -1.48e-01 -1.49e-01 -1.30e-01 -1.06e-01 -9.60e-02 -7.06e-02 -4.00e-02 -1.71e-02 -7.45e-03 -7.31e-02 -6.14e-02 -6.36e-02 -5.75e-02 -6.28e-02 -5.80e-02 -4.73e-02 -4.31e-02 -4.49e-02 -3.41e-02 -3.27e-02 -2.30e-02 -1.26e-02 -7.67e-03 -3.56e-03 -1.42e-01 -1.47e-01 -1.56e-01 -1.59e-01 -1.58e-01 -1.56e-01 -1.58e-01 -1.63e-01 -1.48e-01 -1.51e-01 -1.49e-01 -1.44e-01 -1.75e-01 -9.73e-02 -3.77e-02 -1.45e-01 -1.50e-01 -1.49e-01 -1.50e-01 -1.53e-01 -1.52e-01 -1.51e-01 -1.54e-01 -1.52e-01 -1.51e-01 -1.48e-01 -1.46e-01 -1.93e-01 -1.30e-01 -4.16e-02 -1.46e-01 -1.48e-01 -1.46e-01 -1.53e-01 -1.47e-01 -1.54e-01 -1.58e-01 -1.45e-01 -1.47e-01 -1.46e-01 -1.45e-01 -1.50e-01 -1.99e-01 -1.42e-01 -4.85e-02 -1.46e-01 -1.48e-01 -1.56e-01 -1.44e-01 -1.54e-01 -1.56e-01 -1.52e-01 -1.46e-01 -1.44e-01 -1.37e-01 -1.38e-01 -1.46e-01 -1.94e-01 -1.11e-01 -3.61e-02 -1.45e-01 -1.48e-01 -1.51e-01 -1.46e-01 -1.54e-01 -1.54e-01 -1.45e-01 -1.44e-01 -1.48e-01 -1.40e-01 -1.46e-01 -1.49e-01 -1.93e-01 -1.06e-01 -3.16e-02 -1.45e-01 -1.48e-01 -1.50e-01 -1.56e-01 -1.46e-01 -1.51e-01 -1.44e-01 -1.41e-01 -1.32e-01 -1.41e-01 -1.41e-01 -1.39e-01 -2.04e-01 -1.15e-01 -3.10e-02 -1.41e-01 -1.46e-01 -1.41e-01 -1.48e-01 -1.45e-01 -1.45e-01 -1.44e-01 -1.38e-01 -1.34e-01 -1.34e-01 -1.38e-01 -1.42e-01 -1.85e-01 -1.26e-01 -3.53e-02 -1.38e-01 -1.45e-01 -1.45e-01 -1.49e-01 -1.41e-01 -1.40e-01 -1.33e-01 -1.34e-01 -1.33e-01 -1.36e-01 -1.35e-01 -1.37e-01 -1.76e-01 -1.16e-01 -4.10e-02 -1.35e-01 -1.39e-01 -1.44e-01 -1.43e-01 -1.44e-01 -1.40e-01 -1.27e-01 -1.29e-01 -1.24e-01 -1.24e-01 -1.21e-01 -1.25e-01 -1.74e-01 -9.17e-02 -2.60e-02 -1.39e-01 -1.35e-01 -1.40e-01 -1.43e-01 -1.45e-01 -1.32e-01 -1.32e-01 -1.29e-01 -1.20e-01 -1.22e-01 -1.14e-01 -1.15e-01 -1.43e-01 -8.26e-02 -2.82e-02 -1.37e-01 -1.36e-01 -1.37e-01 -1.38e-01 -1.39e-01 -1.32e-01 -1.34e-01 -1.31e-01 -1.19e-01 -1.18e-01 -1.10e-01 -1.13e-01 -1.51e-01 -5.50e-02 -1.63e-02 -1.36e-01 -1.38e-01 -1.40e-01 -1.44e-01 -1.37e-01 -1.43e-01 -1.44e-01 -1.39e-01 -1.26e-01 -1.21e-01 -1.14e-01 -1.05e-01 -1.24e-01 -4.77e-02 -1.43e-02 -1.96e-01 -1.79e-01 -1.80e-01 -1.95e-01 -1.99e-01 -1.94e-01 -1.81e-01 -1.92e-01 -1.80e-01 -1.60e-01 -1.61e-01 -1.34e-01 -7.13e-02 -2.07e-02 -7.42e-03 -1.76e-01 -9.49e-02 -1.22e-01 -1.31e-01 -1.35e-01 -1.34e-01 -1.06e-01 -1.42e-01 -1.15e-01 -7.49e-02 -8.42e-02 -5.97e-02 -2.86e-02 -1.13e-02 -3.88e-03 -5.74e-02 -3.06e-02 -3.68e-02 -4.09e-02 -5.26e-02 -4.71e-02 -3.30e-02 -4.67e-02 -3.85e-02 -2.55e-02 -2.40e-02 -1.51e-02 -1.04e-02 -6.23e-03 -3.39e-03 -1.51e-01 -1.61e-01 -1.68e-01 -1.62e-01 -1.62e-01 -1.64e-01 -1.64e-01 -1.55e-01 -1.53e-01 -1.51e-01 -1.54e-01 -1.44e-01 -1.43e-01 -3.50e-02 -1.38e-02 -1.65e-01 -1.68e-01 -1.64e-01 -1.54e-01 -1.51e-01 -1.54e-01 -1.57e-01 -1.50e-01 -1.50e-01 -1.49e-01 -1.55e-01 -1.49e-01 -1.60e-01 -6.68e-02 -2.43e-02 -1.59e-01 -1.68e-01 -1.59e-01 -1.54e-01 -1.55e-01 -1.66e-01 -1.64e-01 -1.60e-01 -1.47e-01 -1.49e-01 -1.42e-01 -1.60e-01 -2.06e-01 -1.03e-01 -2.77e-02 -1.56e-01 -1.59e-01 -1.54e-01 -1.54e-01 -1.59e-01 -1.65e-01 -1.63e-01 -1.43e-01 -1.52e-01 -1.45e-01 -1.35e-01 -1.44e-01 -1.79e-01 -9.16e-02 -3.06e-02 -1.50e-01 -1.51e-01 -1.54e-01 -1.55e-01 -1.59e-01 -1.59e-01 -1.54e-01 -1.47e-01 -1.53e-01 -1.51e-01 -1.40e-01 -1.45e-01 -1.90e-01 -1.07e-01 -2.94e-02 -1.50e-01 -1.52e-01 -1.48e-01 -1.54e-01 -1.52e-01 -1.51e-01 -1.50e-01 -1.43e-01 -1.47e-01 -1.46e-01 -1.38e-01 -1.35e-01 -1.78e-01 -9.46e-02 -3.09e-02 -1.41e-01 -1.42e-01 -1.53e-01 -1.56e-01 -1.53e-01 -1.48e-01 -1.48e-01 -1.41e-01 -1.38e-01 -1.40e-01 -1.40e-01 -1.30e-01 -1.49e-01 -9.60e-02 -3.33e-02 -1.42e-01 -1.46e-01 -1.40e-01 -1.50e-01 -1.45e-01 -1.45e-01 -1.50e-01 -1.45e-01 -1.41e-01 -1.33e-01 -1.36e-01 -1.37e-01 -1.71e-01 -7.74e-02 -2.54e-02 -1.45e-01 -1.43e-01 -1.47e-01 -1.51e-01 -1.49e-01 -1.54e-01 -1.42e-01 -1.37e-01 -1.34e-01 -1.33e-01 -1.27e-01 -1.27e-01 -1.66e-01 -7.29e-02 -2.38e-02 -1.44e-01 -1.39e-01 -1.51e-01 -1.49e-01 -1.48e-01 -1.46e-01 -1.38e-01 -1.29e-01 -1.23e-01 -1.18e-01 -1.23e-01 -1.14e-01 -1.60e-01 -7.60e-02 -2.69e-02 -1.34e-01 -1.33e-01 -1.39e-01 -1.41e-01 -1.50e-01 -1.43e-01 -1.31e-01 -1.28e-01 -1.23e-01 -1.19e-01 -1.12e-01 -1.08e-01 -1.37e-01 -5.02e-02 -1.48e-02 -1.33e-01 -1.31e-01 -1.34e-01 -1.36e-01 -1.35e-01 -1.30e-01 -1.37e-01 -1.40e-01 -1.27e-01 -1.22e-01 -1.08e-01 -1.01e-01 -1.15e-01 -4.47e-02 -1.28e-02 -1.73e-01 -1.60e-01 -1.60e-01 -1.70e-01 -1.65e-01 -1.66e-01 -1.67e-01 -1.80e-01 -1.81e-01 -1.46e-01 -1.35e-01 -1.18e-01 -6.95e-02 -2.21e-02 -7.42e-03 -1.30e-01 -7.02e-02 -8.47e-02 -1.05e-01 -8.11e-02 -8.16e-02 -7.32e-02 -7.94e-02 -1.08e-01 -7.59e-02 -5.62e-02 -4.38e-02 -2.63e-02 -6.47e-03 -2.09e-03 -5.13e-02 -2.67e-02 -3.48e-02 -3.62e-02 -2.93e-02 -2.83e-02 -2.47e-02 -2.60e-02 -3.29e-02 -2.55e-02 -1.63e-02 -1.59e-02 -1.02e-02 -3.46e-03 -1.50e-03 -2.17e-01 -2.25e-01 -2.43e-01 -2.43e-01 -2.31e-01 -2.22e-01 -2.22e-01 -2.12e-01 -2.21e-01 -1.98e-01 -1.99e-01 -2.04e-01 -1.57e-01 -3.11e-02 -7.85e-03 -2.30e-01 -2.10e-01 -2.47e-01 -2.20e-01 -2.20e-01 -2.29e-01 -2.22e-01 -2.06e-01 -1.98e-01 -2.04e-01 -1.90e-01 -1.83e-01 -1.78e-01 -5.75e-02 -1.61e-02 -2.24e-01 -2.08e-01 -2.36e-01 -2.21e-01 -2.12e-01 -2.36e-01 -2.08e-01 -2.30e-01 -2.06e-01 -2.08e-01 -1.93e-01 -1.84e-01 -2.10e-01 -9.89e-02 -3.10e-02 -2.25e-01 -2.06e-01 -2.18e-01 -2.25e-01 -2.19e-01 -2.39e-01 -2.22e-01 -2.20e-01 -2.12e-01 -2.02e-01 -1.75e-01 -1.62e-01 -1.73e-01 -6.25e-02 -1.80e-02 -2.16e-01 -2.06e-01 -2.12e-01 -2.21e-01 -2.09e-01 -2.25e-01 -2.54e-01 -2.18e-01 -2.16e-01 -2.23e-01 -1.99e-01 -1.77e-01 -1.57e-01 -7.90e-02 -2.92e-02 -2.13e-01 -1.96e-01 -2.07e-01 -2.04e-01 -2.00e-01 -2.17e-01 -2.17e-01 -2.01e-01 -2.06e-01 -2.15e-01 -1.92e-01 -1.66e-01 -1.68e-01 -8.03e-02 -2.44e-02 -1.90e-01 -1.93e-01 -2.12e-01 -2.07e-01 -2.00e-01 -2.08e-01 -2.04e-01 -1.97e-01 -1.68e-01 -1.90e-01 -1.82e-01 -1.49e-01 -1.55e-01 -6.10e-02 -1.96e-02 -1.94e-01 -1.89e-01 -2.00e-01 -2.16e-01 -2.22e-01 -2.06e-01 -2.02e-01 -1.99e-01 -1.77e-01 -1.77e-01 -1.83e-01 -1.68e-01 -1.29e-01 -3.50e-02 -1.16e-02 -1.93e-01 -2.00e-01 -2.02e-01 -2.11e-01 -2.16e-01 -1.93e-01 -2.15e-01 -2.05e-01 -1.80e-01 -1.82e-01 -1.71e-01 -1.65e-01 -1.61e-01 -4.47e-02 -1.50e-02 -1.94e-01 -2.06e-01 -2.19e-01 -2.03e-01 -2.12e-01 -1.96e-01 -2.02e-01 -1.81e-01 -1.66e-01 -1.60e-01 -1.62e-01 -1.62e-01 -1.56e-01 -4.92e-02 -1.53e-02 -1.78e-01 -1.86e-01 -2.05e-01 -2.04e-01 -1.97e-01 -2.15e-01 -1.88e-01 -1.63e-01 -1.57e-01 -1.38e-01 -1.47e-01 -1.39e-01 -1.01e-01 -4.20e-02 -1.54e-02 -1.47e-01 -1.52e-01 -1.77e-01 -1.74e-01 -1.84e-01 -1.91e-01 -2.00e-01 -1.85e-01 -1.68e-01 -1.42e-01 -1.34e-01 -1.28e-01 -9.77e-02 -2.94e-02 -1.17e-02 -1.28e-01 -1.39e-01 -1.56e-01 -1.44e-01 -1.64e-01 -1.66e-01 -1.39e-01 -1.87e-01 -1.87e-01 -1.57e-01 -1.18e-01 -9.64e-02 -6.30e-02 -1.82e-02 -8.08e-03 -7.18e-02 -4.39e-02 -5.20e-02 -6.11e-02 -4.96e-02 -4.82e-02 -4.41e-02 -5.38e-02 -8.79e-02 -5.77e-02 -2.70e-02 -2.61e-02 -1.49e-02 -4.93e-03 -2.78e-03 -2.74e-02 -1.41e-02 -1.81e-02 -1.93e-02 -1.48e-02 -1.51e-02 -1.60e-02 -1.57e-02 -2.80e-02 -2.17e-02 -1.10e-02 -8.28e-03 -4.76e-03 -2.53e-03 -9.95e-04 -2.15e-01 -2.13e-01 -2.69e-01 -1.97e-01 -2.97e-01 -2.44e-01 -2.16e-01 -2.27e-01 -1.95e-01 -1.69e-01 -1.21e-01 -1.27e-01 -1.07e-01 -2.85e-02 -7.97e-03 -2.71e-01 -1.94e-01 -3.20e-01 -3.60e-01 -2.90e-01 -2.34e-01 -1.99e-01 -2.04e-01 -1.73e-01 -1.40e-01 -1.29e-01 -1.08e-01 -8.99e-02 -4.08e-02 -1.48e-02 -2.36e-01 -2.27e-01 -2.95e-01 -2.38e-01 -1.88e-01 -2.38e-01 -1.95e-01 -2.03e-01 -1.85e-01 -1.65e-01 -1.78e-01 -1.40e-01 -7.70e-02 -4.33e-02 -2.87e-02 -2.64e-01 -2.27e-01 -2.72e-01 -3.07e-01 -2.33e-01 -2.58e-01 -2.71e-01 -2.36e-01 -2.17e-01 -1.73e-01 -1.26e-01 -9.14e-02 -6.26e-02 -3.03e-02 -1.37e-02 -2.60e-01 -1.95e-01 -2.57e-01 -3.08e-01 -2.65e-01 -2.75e-01 -2.70e-01 -2.25e-01 -1.83e-01 -1.71e-01 -1.54e-01 -8.13e-02 -5.27e-02 -2.61e-02 -1.31e-02 -2.09e-01 -1.59e-01 -2.23e-01 -2.30e-01 -1.63e-01 -1.84e-01 -2.17e-01 -1.62e-01 -1.39e-01 -1.79e-01 -1.60e-01 -1.05e-01 -5.74e-02 -2.47e-02 -1.55e-02 -1.50e-01 -1.80e-01 -2.09e-01 -2.09e-01 -1.82e-01 -2.00e-01 -1.82e-01 -1.57e-01 -1.32e-01 -1.22e-01 -9.76e-02 -6.91e-02 -4.61e-02 -2.65e-02 -1.49e-02 -1.12e-01 -1.42e-01 -1.70e-01 -1.73e-01 -1.86e-01 -1.93e-01 -1.34e-01 -1.27e-01 -9.53e-02 -8.75e-02 -9.91e-02 -7.87e-02 -4.52e-02 -2.11e-02 -7.92e-03 -1.22e-01 -1.39e-01 -1.69e-01 -2.22e-01 -1.74e-01 -1.60e-01 -1.21e-01 -1.47e-01 -1.19e-01 -1.07e-01 -9.89e-02 -8.43e-02 -5.88e-02 -2.01e-02 -8.74e-03 -9.13e-02 -1.61e-01 -2.14e-01 -1.61e-01 -1.43e-01 -1.01e-01 -1.25e-01 -1.42e-01 -1.15e-01 -9.15e-02 -8.87e-02 -6.91e-02 -5.19e-02 -2.72e-02 -8.44e-03 -9.87e-02 -1.23e-01 -1.61e-01 -1.11e-01 -1.42e-01 -1.45e-01 -1.19e-01 -1.11e-01 -8.68e-02 -5.91e-02 -7.60e-02 -6.84e-02 -4.18e-02 -2.17e-02 -9.67e-03 -8.56e-02 -7.21e-02 -1.04e-01 -9.72e-02 -9.63e-02 -1.38e-01 -1.19e-01 -7.48e-02 -6.52e-02 -5.51e-02 -5.18e-02 -5.14e-02 -3.71e-02 -9.91e-03 -3.65e-03 -4.31e-02 -5.32e-02 -6.28e-02 -4.91e-02 -5.90e-02 -8.59e-02 -7.51e-02 -7.34e-02 -6.10e-02 -6.19e-02 -4.42e-02 -3.60e-02 -2.68e-02 -1.01e-02 -4.00e-03 -1.92e-02 -2.02e-02 -2.30e-02 -1.98e-02 -2.54e-02 -3.35e-02 -2.56e-02 -3.19e-02 -3.49e-02 -2.85e-02 -1.72e-02 -1.18e-02 -8.37e-03 -4.19e-03 -2.02e-03 -1.38e-02 -7.42e-03 -8.36e-03 -8.57e-03 -9.08e-03 -1.23e-02 -8.17e-03 -1.02e-02 -1.45e-02 -1.35e-02 -6.28e-03 -3.59e-03 -3.28e-03 -1.49e-03 -5.93e-04 -7.32e-02 -7.34e-02 -9.95e-02 -6.68e-02 -1.09e-01 -8.20e-02 -7.49e-02 -7.93e-02 -7.32e-02 -5.71e-02 -3.93e-02 -3.97e-02 -3.57e-02 -2.10e-02 -7.29e-03 -1.10e-01 -5.23e-02 -1.07e-01 -1.46e-01 -1.24e-01 -8.85e-02 -7.13e-02 -6.52e-02 -6.37e-02 -5.06e-02 -3.96e-02 -3.23e-02 -2.70e-02 -1.79e-02 -8.68e-03 -8.76e-02 -6.93e-02 -1.01e-01 -9.79e-02 -5.28e-02 -8.50e-02 -7.16e-02 -6.22e-02 -6.61e-02 -4.64e-02 -6.19e-02 -5.31e-02 -2.85e-02 -1.22e-02 -1.28e-02 -8.68e-02 -7.27e-02 -1.06e-01 -1.20e-01 -8.06e-02 -8.67e-02 -9.61e-02 -8.95e-02 -8.71e-02 -6.56e-02 -4.39e-02 -3.10e-02 -2.08e-02 -1.24e-02 -5.85e-03 -1.06e-01 -7.84e-02 -9.79e-02 -1.14e-01 -1.02e-01 -9.64e-02 -1.00e-01 -7.46e-02 -7.16e-02 -5.01e-02 -5.24e-02 -2.38e-02 -1.47e-02 -8.69e-03 -5.50e-03 -6.48e-02 -5.48e-02 -7.05e-02 -7.64e-02 -6.18e-02 -5.28e-02 -6.84e-02 -5.17e-02 -4.47e-02 -5.44e-02 -5.78e-02 -4.35e-02 -2.02e-02 -8.44e-03 -4.29e-03 -6.15e-02 -5.80e-02 -7.42e-02 -8.23e-02 -4.82e-02 -5.80e-02 -5.99e-02 -5.52e-02 -5.07e-02 -4.11e-02 -3.25e-02 -2.74e-02 -1.58e-02 -7.93e-03 -7.33e-03 -3.07e-02 -5.33e-02 -5.17e-02 -5.32e-02 -5.86e-02 -6.36e-02 -3.92e-02 -4.20e-02 -3.02e-02 -2.37e-02 -2.60e-02 -2.49e-02 -1.38e-02 -1.14e-02 -8.22e-03 -3.87e-02 -4.20e-02 -5.55e-02 -6.88e-02 -6.66e-02 -6.23e-02 -3.77e-02 -4.86e-02 -4.16e-02 -3.47e-02 -2.92e-02 -2.68e-02 -2.21e-02 -9.30e-03 -3.87e-03 -2.33e-02 -4.93e-02 -6.49e-02 -6.24e-02 -4.58e-02 -2.96e-02 -4.02e-02 -4.66e-02 -4.25e-02 -2.79e-02 -2.67e-02 -2.26e-02 -1.37e-02 -1.36e-02 -7.38e-03 -3.11e-02 -5.02e-02 -5.87e-02 -3.06e-02 -4.64e-02 -4.05e-02 -2.71e-02 -3.77e-02 -3.09e-02 -2.18e-02 -2.34e-02 -1.91e-02 -1.39e-02 -1.02e-02 -7.91e-03 -2.26e-02 -2.44e-02 -3.23e-02 -2.90e-02 -2.99e-02 -4.72e-02 -4.07e-02 -3.01e-02 -2.01e-02 -1.70e-02 -1.57e-02 -1.51e-02 -1.50e-02 -4.17e-03 -1.63e-03 -1.86e-02 -1.84e-02 -2.18e-02 -2.46e-02 -1.84e-02 -3.15e-02 -2.72e-02 -2.27e-02 -1.73e-02 -2.03e-02 -1.19e-02 -1.20e-02 -1.14e-02 -4.19e-03 -1.45e-03 -6.21e-03 -9.69e-03 -9.74e-03 -7.36e-03 -1.15e-02 -1.57e-02 -1.41e-02 -1.64e-02 -1.88e-02 -1.03e-02 -1.09e-02 -6.84e-03 -4.29e-03 -2.69e-03 -2.28e-03 -4.54e-03 -5.03e-03 -5.40e-03 -5.12e-03 -6.04e-03 -1.01e-02 -6.83e-03 -6.36e-03 -1.16e-02 -7.66e-03 -5.81e-03 -3.71e-03 -1.48e-03 -1.00e-03 -1.45e-03 -Upper Bounds -8.55e-01 -8.64e-01 -8.59e-01 -8.67e-01 -8.53e-01 -8.16e-01 -8.31e-01 -8.50e-01 -8.39e-01 -8.80e-01 -8.66e-01 -8.96e-01 -1.31e+00 -2.22e+00 -8.38e-01 -8.15e-01 -8.82e-01 -8.67e-01 -7.61e-01 -8.32e-01 -8.60e-01 -8.41e-01 -8.42e-01 -8.32e-01 -8.34e-01 -8.80e-01 -8.65e-01 -1.22e+00 -1.82e+00 -6.12e-01 -8.56e-01 -8.31e-01 -8.43e-01 -8.52e-01 -8.33e-01 -8.57e-01 -8.19e-01 -7.77e-01 -8.33e-01 -8.19e-01 -8.41e-01 -9.08e-01 -1.30e+00 -2.06e+00 -7.76e-01 -8.38e-01 -8.08e-01 -8.28e-01 -8.25e-01 -8.10e-01 -8.21e-01 -8.13e-01 -8.31e-01 -8.17e-01 -8.36e-01 -7.91e-01 -8.95e-01 -1.26e+00 -2.05e+00 -6.73e-01 -8.25e-01 -8.69e-01 -8.34e-01 -8.56e-01 -8.29e-01 -8.11e-01 -8.01e-01 -8.32e-01 -7.75e-01 -8.33e-01 -8.31e-01 -9.11e-01 -1.34e+00 -1.73e+00 -6.60e-01 -8.48e-01 -8.49e-01 -8.41e-01 -8.41e-01 -8.43e-01 -7.95e-01 -8.08e-01 -7.96e-01 -7.85e-01 -7.74e-01 -8.58e-01 -8.98e-01 -1.29e+00 -1.49e+00 -5.32e-01 -8.39e-01 -7.98e-01 -7.91e-01 -8.03e-01 -7.88e-01 -7.96e-01 -7.81e-01 -7.66e-01 -7.83e-01 -7.62e-01 -7.93e-01 -7.72e-01 -1.21e+00 -1.65e+00 -6.11e-01 -8.18e-01 -8.25e-01 -8.44e-01 -8.18e-01 -8.00e-01 -8.28e-01 -8.00e-01 -7.60e-01 -7.23e-01 -7.65e-01 -7.83e-01 -7.01e-01 -1.04e+00 -9.49e-01 -3.97e-01 -8.24e-01 -8.27e-01 -8.57e-01 -8.58e-01 -8.13e-01 -8.03e-01 -7.83e-01 -7.70e-01 -7.46e-01 -7.07e-01 -7.24e-01 -7.65e-01 -1.18e+00 -9.01e-01 -2.88e-01 -8.34e-01 -8.73e-01 -8.70e-01 -8.56e-01 -8.29e-01 -7.71e-01 -7.75e-01 -7.58e-01 -7.63e-01 -7.06e-01 -7.64e-01 -7.43e-01 -1.07e+00 -8.82e-01 -3.35e-01 -8.58e-01 -8.29e-01 -8.72e-01 -8.48e-01 -8.46e-01 -7.87e-01 -7.50e-01 -7.65e-01 -7.38e-01 -7.34e-01 -8.10e-01 -7.43e-01 -1.02e+00 -6.73e-01 -2.03e-01 -9.03e-01 -9.01e-01 -8.60e-01 -8.26e-01 -9.18e-01 -8.72e-01 -7.91e-01 -8.39e-01 -7.94e-01 -7.87e-01 -7.88e-01 -7.38e-01 -1.08e+00 -5.23e-01 -1.69e-01 -1.31e+00 -1.26e+00 -1.18e+00 -1.25e+00 -1.32e+00 -1.21e+00 -1.20e+00 -1.16e+00 -1.16e+00 -1.14e+00 -1.11e+00 -1.10e+00 -1.03e+00 -4.01e-01 -1.10e-01 -2.50e+00 -1.84e+00 -1.94e+00 -1.32e+00 -1.43e+00 -1.59e+00 -1.30e+00 -1.19e+00 -9.40e-01 -9.83e-01 -9.19e-01 -7.51e-01 -4.99e-01 -1.94e-01 -9.48e-02 -1.09e+00 -7.40e-01 -8.05e-01 -4.38e-01 -4.72e-01 -5.81e-01 -4.22e-01 -4.06e-01 -3.50e-01 -3.08e-01 -3.25e-01 -2.23e-01 -1.85e-01 -8.09e-02 -3.66e-02 -8.48e-01 -8.45e-01 -8.50e-01 -8.39e-01 -8.13e-01 -7.97e-01 -8.76e-01 -8.44e-01 -7.95e-01 -8.18e-01 -8.84e-01 -8.93e-01 -1.31e+00 -1.96e+00 -7.41e-01 -8.63e-01 -8.69e-01 -8.49e-01 -8.32e-01 -8.42e-01 -8.08e-01 -8.09e-01 -8.36e-01 -7.99e-01 -8.20e-01 -8.33e-01 -9.00e-01 -1.21e+00 -1.86e+00 -7.23e-01 -8.57e-01 -8.27e-01 -8.35e-01 -8.27e-01 -8.44e-01 -8.48e-01 -8.19e-01 -8.39e-01 -8.01e-01 -8.48e-01 -8.52e-01 -8.70e-01 -1.31e+00 -1.65e+00 -5.73e-01 -8.64e-01 -8.75e-01 -8.50e-01 -8.46e-01 -8.43e-01 -8.17e-01 -8.28e-01 -8.15e-01 -8.07e-01 -8.04e-01 -8.51e-01 -8.94e-01 -1.24e+00 -1.82e+00 -6.58e-01 -8.61e-01 -8.65e-01 -8.57e-01 -8.28e-01 -8.15e-01 -8.13e-01 -8.36e-01 -8.01e-01 -7.82e-01 -8.17e-01 -8.58e-01 -8.55e-01 -1.26e+00 -1.71e+00 -6.99e-01 -8.39e-01 -8.48e-01 -8.35e-01 -8.30e-01 -8.61e-01 -8.03e-01 -7.79e-01 -7.79e-01 -7.65e-01 -7.73e-01 -8.23e-01 -8.92e-01 -1.26e+00 -1.83e+00 -6.65e-01 -8.50e-01 -8.43e-01 -8.01e-01 -8.18e-01 -8.51e-01 -8.15e-01 -7.63e-01 -7.50e-01 -7.52e-01 -7.40e-01 -7.66e-01 -8.29e-01 -1.17e+00 -1.50e+00 -5.74e-01 -8.23e-01 -8.15e-01 -7.95e-01 -7.87e-01 -7.97e-01 -7.70e-01 -7.69e-01 -7.35e-01 -6.98e-01 -6.91e-01 -6.35e-01 -6.08e-01 -9.93e-01 -8.87e-01 -3.56e-01 -7.90e-01 -8.73e-01 -8.38e-01 -8.31e-01 -8.29e-01 -7.89e-01 -7.80e-01 -7.18e-01 -7.42e-01 -7.23e-01 -6.87e-01 -7.01e-01 -1.01e+00 -6.82e-01 -2.08e-01 -8.24e-01 -8.78e-01 -8.46e-01 -8.43e-01 -7.84e-01 -8.35e-01 -7.79e-01 -7.48e-01 -7.63e-01 -7.14e-01 -7.56e-01 -7.03e-01 -1.02e+00 -7.48e-01 -2.25e-01 -8.45e-01 -8.73e-01 -8.56e-01 -8.15e-01 -8.44e-01 -8.36e-01 -7.99e-01 -7.51e-01 -7.67e-01 -7.20e-01 -7.86e-01 -7.45e-01 -1.01e+00 -6.73e-01 -2.04e-01 -8.93e-01 -8.60e-01 -8.64e-01 -8.51e-01 -8.70e-01 -8.90e-01 -8.41e-01 -7.94e-01 -7.85e-01 -8.08e-01 -8.08e-01 -7.83e-01 -9.73e-01 -4.60e-01 -1.58e-01 -1.24e+00 -1.32e+00 -1.27e+00 -1.29e+00 -1.40e+00 -1.26e+00 -1.17e+00 -1.20e+00 -1.08e+00 -1.09e+00 -1.21e+00 -1.11e+00 -9.96e-01 -3.09e-01 -8.83e-02 -1.56e+00 -1.49e+00 -1.49e+00 -1.58e+00 -1.83e+00 -1.75e+00 -1.41e+00 -1.38e+00 -1.12e+00 -8.28e-01 -8.50e-01 -8.27e-01 -5.48e-01 -1.84e-01 -7.71e-02 -5.56e-01 -5.50e-01 -5.89e-01 -5.41e-01 -6.72e-01 -7.04e-01 -4.96e-01 -4.98e-01 -4.70e-01 -2.59e-01 -2.70e-01 -2.72e-01 -2.11e-01 -9.38e-02 -3.66e-02 -8.67e-01 -8.42e-01 -8.70e-01 -8.39e-01 -7.98e-01 -8.02e-01 -8.06e-01 -7.94e-01 -8.48e-01 -8.04e-01 -8.10e-01 -8.81e-01 -1.45e+00 -2.04e+00 -7.89e-01 -8.58e-01 -8.42e-01 -8.10e-01 -8.30e-01 -7.96e-01 -8.14e-01 -7.91e-01 -8.00e-01 -7.94e-01 -8.24e-01 -8.16e-01 -8.86e-01 -1.22e+00 -1.96e+00 -8.18e-01 -8.56e-01 -8.69e-01 -8.58e-01 -7.87e-01 -8.24e-01 -8.16e-01 -8.16e-01 -8.43e-01 -7.92e-01 -8.05e-01 -8.03e-01 -8.83e-01 -1.22e+00 -1.68e+00 -6.47e-01 -7.87e-01 -8.37e-01 -8.29e-01 -8.15e-01 -8.16e-01 -7.97e-01 -8.04e-01 -8.23e-01 -7.82e-01 -7.95e-01 -8.24e-01 -7.97e-01 -1.22e+00 -1.65e+00 -5.42e-01 -8.09e-01 -8.09e-01 -8.04e-01 -7.72e-01 -8.14e-01 -8.20e-01 -7.50e-01 -7.87e-01 -7.53e-01 -7.48e-01 -8.36e-01 -8.59e-01 -1.22e+00 -1.39e+00 -4.29e-01 -8.07e-01 -8.21e-01 -7.86e-01 -7.76e-01 -7.84e-01 -7.85e-01 -7.56e-01 -7.44e-01 -7.72e-01 -7.80e-01 -8.33e-01 -8.47e-01 -1.21e+00 -1.74e+00 -6.61e-01 -8.36e-01 -8.64e-01 -8.19e-01 -8.11e-01 -8.00e-01 -8.07e-01 -7.80e-01 -7.34e-01 -7.56e-01 -7.70e-01 -7.83e-01 -7.96e-01 -1.13e+00 -1.26e+00 -4.66e-01 -8.16e-01 -8.15e-01 -7.98e-01 -7.75e-01 -7.87e-01 -7.91e-01 -7.70e-01 -7.35e-01 -7.31e-01 -7.42e-01 -7.14e-01 -7.50e-01 -1.05e+00 -8.42e-01 -3.14e-01 -7.86e-01 -8.18e-01 -8.21e-01 -8.01e-01 -7.99e-01 -7.90e-01 -7.88e-01 -7.83e-01 -7.33e-01 -7.48e-01 -7.58e-01 -7.15e-01 -1.06e+00 -8.32e-01 -3.09e-01 -8.27e-01 -8.58e-01 -8.09e-01 -8.21e-01 -8.32e-01 -7.85e-01 -7.86e-01 -7.50e-01 -7.01e-01 -7.38e-01 -7.30e-01 -7.22e-01 -9.77e-01 -6.23e-01 -2.49e-01 -8.03e-01 -8.31e-01 -8.48e-01 -8.19e-01 -8.34e-01 -8.33e-01 -8.42e-01 -7.89e-01 -7.16e-01 -7.24e-01 -7.28e-01 -7.16e-01 -9.71e-01 -6.27e-01 -1.80e-01 -8.04e-01 -8.69e-01 -8.69e-01 -8.82e-01 -8.64e-01 -8.59e-01 -8.38e-01 -8.03e-01 -7.94e-01 -7.80e-01 -7.95e-01 -7.83e-01 -8.87e-01 -5.44e-01 -1.87e-01 -1.24e+00 -1.24e+00 -1.24e+00 -1.21e+00 -1.24e+00 -1.28e+00 -1.10e+00 -1.13e+00 -1.12e+00 -1.09e+00 -1.11e+00 -1.13e+00 -1.07e+00 -3.12e-01 -9.52e-02 -1.84e+00 -1.36e+00 -1.70e+00 -1.79e+00 -1.82e+00 -1.16e+00 -1.17e+00 -1.10e+00 -9.39e-01 -8.87e-01 -6.70e-01 -6.23e-01 -5.35e-01 -2.34e-01 -6.47e-02 -6.44e-01 -4.31e-01 -7.11e-01 -6.80e-01 -6.87e-01 -4.47e-01 -4.04e-01 -4.19e-01 -2.85e-01 -3.23e-01 -1.57e-01 -1.93e-01 -1.76e-01 -1.29e-01 -6.44e-02 -8.45e-01 -8.09e-01 -8.31e-01 -8.52e-01 -8.43e-01 -8.05e-01 -7.88e-01 -7.57e-01 -7.58e-01 -7.66e-01 -7.61e-01 -8.67e-01 -1.27e+00 -2.06e+00 -7.56e-01 -8.40e-01 -8.74e-01 -8.23e-01 -7.97e-01 -8.08e-01 -7.78e-01 -7.85e-01 -7.76e-01 -7.95e-01 -8.30e-01 -7.95e-01 -8.37e-01 -1.18e+00 -1.62e+00 -6.44e-01 -8.11e-01 -8.19e-01 -8.40e-01 -7.94e-01 -7.57e-01 -7.93e-01 -7.66e-01 -7.66e-01 -7.76e-01 -8.15e-01 -7.99e-01 -8.24e-01 -1.16e+00 -1.39e+00 -5.36e-01 -8.08e-01 -8.15e-01 -7.99e-01 -8.03e-01 -7.68e-01 -7.86e-01 -7.93e-01 -7.55e-01 -7.56e-01 -7.89e-01 -7.68e-01 -8.06e-01 -1.20e+00 -1.24e+00 -5.05e-01 -7.77e-01 -7.72e-01 -8.04e-01 -8.28e-01 -7.74e-01 -7.64e-01 -7.80e-01 -7.54e-01 -7.38e-01 -7.65e-01 -8.13e-01 -8.11e-01 -1.21e+00 -1.61e+00 -5.92e-01 -8.28e-01 -7.61e-01 -8.10e-01 -8.12e-01 -7.80e-01 -7.60e-01 -7.76e-01 -7.84e-01 -7.75e-01 -7.67e-01 -7.63e-01 -8.21e-01 -1.23e+00 -1.51e+00 -5.55e-01 -8.13e-01 -7.95e-01 -8.40e-01 -7.97e-01 -7.59e-01 -7.72e-01 -7.80e-01 -7.46e-01 -7.44e-01 -7.55e-01 -7.27e-01 -7.44e-01 -1.11e+00 -1.44e+00 -5.11e-01 -8.31e-01 -8.12e-01 -8.03e-01 -7.49e-01 -7.48e-01 -7.53e-01 -7.93e-01 -7.32e-01 -7.17e-01 -7.10e-01 -7.05e-01 -7.55e-01 -1.11e+00 -9.42e-01 -3.25e-01 -8.00e-01 -7.96e-01 -7.87e-01 -8.07e-01 -7.73e-01 -7.86e-01 -7.64e-01 -7.65e-01 -7.27e-01 -7.21e-01 -7.35e-01 -7.93e-01 -1.18e+00 -9.54e-01 -2.85e-01 -8.11e-01 -7.95e-01 -8.15e-01 -7.97e-01 -7.74e-01 -7.69e-01 -7.52e-01 -7.33e-01 -7.51e-01 -7.28e-01 -7.13e-01 -7.16e-01 -1.10e+00 -6.86e-01 -2.68e-01 -8.31e-01 -8.25e-01 -7.50e-01 -8.42e-01 -8.24e-01 -8.05e-01 -7.74e-01 -7.47e-01 -7.33e-01 -7.57e-01 -7.16e-01 -7.50e-01 -9.60e-01 -4.98e-01 -1.46e-01 -8.65e-01 -8.27e-01 -8.48e-01 -8.31e-01 -8.65e-01 -8.92e-01 -8.23e-01 -7.50e-01 -8.02e-01 -7.77e-01 -7.85e-01 -7.73e-01 -9.44e-01 -4.45e-01 -1.34e-01 -1.16e+00 -1.18e+00 -1.20e+00 -1.16e+00 -1.20e+00 -1.19e+00 -1.01e+00 -1.06e+00 -1.10e+00 -1.06e+00 -1.02e+00 -1.01e+00 -1.07e+00 -4.13e-01 -1.32e-01 -1.53e+00 -1.26e+00 -1.05e+00 -1.47e+00 -1.43e+00 -1.20e+00 -8.45e-01 -6.05e-01 -9.60e-01 -9.09e-01 -6.43e-01 -6.18e-01 -5.18e-01 -2.26e-01 -8.71e-02 -5.78e-01 -4.15e-01 -4.47e-01 -4.72e-01 -5.79e-01 -4.50e-01 -3.73e-01 -1.91e-01 -3.18e-01 -3.21e-01 -2.12e-01 -2.08e-01 -1.59e-01 -1.30e-01 -6.29e-02 -8.13e-01 -7.92e-01 -7.98e-01 -8.10e-01 -8.01e-01 -7.94e-01 -7.98e-01 -7.55e-01 -7.35e-01 -7.76e-01 -7.54e-01 -8.38e-01 -1.23e+00 -1.59e+00 -6.35e-01 -8.22e-01 -8.05e-01 -7.80e-01 -8.16e-01 -8.13e-01 -7.71e-01 -7.48e-01 -7.45e-01 -7.82e-01 -7.91e-01 -7.88e-01 -8.20e-01 -1.19e+00 -1.52e+00 -5.64e-01 -8.23e-01 -8.14e-01 -8.08e-01 -7.83e-01 -7.86e-01 -7.83e-01 -7.67e-01 -7.43e-01 -7.86e-01 -8.17e-01 -8.13e-01 -8.52e-01 -1.19e+00 -1.15e+00 -4.23e-01 -8.08e-01 -8.13e-01 -7.88e-01 -7.92e-01 -7.82e-01 -7.73e-01 -7.50e-01 -7.57e-01 -7.60e-01 -8.01e-01 -7.85e-01 -8.21e-01 -1.23e+00 -1.08e+00 -3.68e-01 -7.79e-01 -7.72e-01 -7.80e-01 -8.09e-01 -7.59e-01 -7.50e-01 -7.76e-01 -7.62e-01 -7.59e-01 -7.48e-01 -7.90e-01 -8.33e-01 -1.23e+00 -1.60e+00 -5.75e-01 -7.85e-01 -7.73e-01 -7.79e-01 -7.88e-01 -7.39e-01 -7.13e-01 -7.08e-01 -7.78e-01 -7.45e-01 -7.61e-01 -7.55e-01 -7.92e-01 -1.16e+00 -1.31e+00 -4.76e-01 -7.40e-01 -7.79e-01 -7.94e-01 -7.59e-01 -7.99e-01 -7.16e-01 -7.14e-01 -7.21e-01 -7.25e-01 -7.16e-01 -7.41e-01 -7.53e-01 -1.04e+00 -1.05e+00 -3.92e-01 -7.83e-01 -8.02e-01 -7.76e-01 -7.66e-01 -7.84e-01 -7.21e-01 -7.22e-01 -6.78e-01 -6.82e-01 -7.30e-01 -7.15e-01 -7.28e-01 -1.08e+00 -8.33e-01 -3.54e-01 -7.96e-01 -7.79e-01 -7.80e-01 -7.68e-01 -7.67e-01 -7.60e-01 -7.52e-01 -7.12e-01 -6.86e-01 -6.95e-01 -7.05e-01 -7.37e-01 -1.02e+00 -8.76e-01 -2.76e-01 -8.13e-01 -8.09e-01 -7.86e-01 -7.66e-01 -7.26e-01 -7.62e-01 -7.59e-01 -7.17e-01 -7.04e-01 -6.89e-01 -6.94e-01 -7.59e-01 -1.02e+00 -8.04e-01 -3.49e-01 -8.12e-01 -7.81e-01 -7.92e-01 -7.74e-01 -7.90e-01 -7.78e-01 -7.64e-01 -7.66e-01 -7.45e-01 -7.07e-01 -7.19e-01 -7.86e-01 -1.05e+00 -6.12e-01 -2.13e-01 -8.28e-01 -8.45e-01 -8.05e-01 -8.12e-01 -8.40e-01 -8.71e-01 -8.00e-01 -7.85e-01 -7.85e-01 -8.08e-01 -7.39e-01 -7.70e-01 -1.09e+00 -5.71e-01 -1.75e-01 -1.22e+00 -1.15e+00 -1.17e+00 -1.21e+00 -1.23e+00 -1.24e+00 -1.23e+00 -1.10e+00 -1.11e+00 -1.06e+00 -1.00e+00 -1.01e+00 -1.07e+00 -4.47e-01 -1.50e-01 -1.39e+00 -1.31e+00 -1.26e+00 -1.31e+00 -1.50e+00 -1.34e+00 -1.46e+00 -9.51e-01 -1.01e+00 -7.68e-01 -5.65e-01 -6.36e-01 -4.41e-01 -1.94e-01 -7.74e-02 -5.17e-01 -4.55e-01 -4.54e-01 -4.50e-01 -5.33e-01 -4.37e-01 -5.86e-01 -2.84e-01 -3.58e-01 -2.61e-01 -1.66e-01 -1.75e-01 -1.34e-01 -8.28e-02 -5.70e-02 -7.29e-01 -7.75e-01 -7.84e-01 -7.97e-01 -8.15e-01 -7.72e-01 -7.47e-01 -7.39e-01 -7.27e-01 -7.42e-01 -7.41e-01 -7.72e-01 -1.22e+00 -1.35e+00 -4.17e-01 -7.68e-01 -7.93e-01 -7.83e-01 -7.57e-01 -7.76e-01 -7.86e-01 -7.98e-01 -7.43e-01 -7.68e-01 -7.51e-01 -7.70e-01 -8.08e-01 -1.20e+00 -1.48e+00 -5.74e-01 -7.98e-01 -8.06e-01 -8.03e-01 -7.63e-01 -7.79e-01 -7.61e-01 -7.64e-01 -7.83e-01 -7.61e-01 -7.60e-01 -7.76e-01 -8.43e-01 -1.25e+00 -1.26e+00 -4.08e-01 -7.94e-01 -7.94e-01 -7.59e-01 -7.50e-01 -7.63e-01 -7.94e-01 -7.36e-01 -7.53e-01 -7.57e-01 -7.78e-01 -7.78e-01 -8.22e-01 -1.20e+00 -1.23e+00 -4.03e-01 -7.88e-01 -7.93e-01 -7.89e-01 -7.79e-01 -7.63e-01 -7.30e-01 -7.40e-01 -7.42e-01 -7.36e-01 -7.64e-01 -7.39e-01 -8.10e-01 -1.19e+00 -1.33e+00 -5.12e-01 -7.75e-01 -7.68e-01 -7.84e-01 -7.62e-01 -7.39e-01 -7.49e-01 -7.00e-01 -6.85e-01 -7.48e-01 -7.48e-01 -7.30e-01 -7.60e-01 -1.12e+00 -1.11e+00 -4.49e-01 -7.89e-01 -8.02e-01 -7.72e-01 -7.35e-01 -7.33e-01 -7.24e-01 -7.11e-01 -6.42e-01 -6.64e-01 -7.00e-01 -7.57e-01 -7.64e-01 -1.04e+00 -7.18e-01 -2.59e-01 -7.83e-01 -7.69e-01 -7.68e-01 -7.09e-01 -7.54e-01 -7.20e-01 -6.74e-01 -6.39e-01 -5.53e-01 -6.99e-01 -7.47e-01 -7.76e-01 -1.11e+00 -6.53e-01 -2.06e-01 -7.78e-01 -7.65e-01 -7.86e-01 -7.09e-01 -7.60e-01 -7.43e-01 -7.27e-01 -6.62e-01 -6.51e-01 -6.35e-01 -7.03e-01 -7.07e-01 -1.06e+00 -7.73e-01 -2.21e-01 -7.46e-01 -7.60e-01 -7.63e-01 -7.80e-01 -7.34e-01 -7.24e-01 -7.02e-01 -6.87e-01 -7.13e-01 -6.75e-01 -6.69e-01 -7.11e-01 -9.92e-01 -6.25e-01 -1.99e-01 -7.86e-01 -7.39e-01 -7.47e-01 -7.61e-01 -7.48e-01 -7.41e-01 -7.50e-01 -7.38e-01 -7.18e-01 -7.15e-01 -6.76e-01 -6.94e-01 -9.71e-01 -5.36e-01 -1.55e-01 -8.10e-01 -8.03e-01 -8.04e-01 -8.15e-01 -8.13e-01 -8.02e-01 -7.77e-01 -7.76e-01 -7.50e-01 -7.78e-01 -7.13e-01 -6.60e-01 -9.13e-01 -5.08e-01 -1.25e-01 -1.17e+00 -1.12e+00 -1.10e+00 -1.13e+00 -1.21e+00 -1.17e+00 -1.07e+00 -1.02e+00 -1.07e+00 -1.08e+00 -1.10e+00 -8.99e-01 -8.82e-01 -4.84e-01 -1.77e-01 -1.56e+00 -1.32e+00 -1.13e+00 -1.34e+00 -1.30e+00 -1.22e+00 -1.17e+00 -9.07e-01 -7.99e-01 -7.33e-01 -7.55e-01 -6.69e-01 -3.68e-01 -2.03e-01 -1.10e-01 -5.31e-01 -4.95e-01 -4.39e-01 -4.81e-01 -4.96e-01 -3.78e-01 -5.25e-01 -3.10e-01 -2.83e-01 -1.99e-01 -2.15e-01 -2.39e-01 -1.44e-01 -7.93e-02 -4.46e-02 -8.04e-01 -7.95e-01 -7.82e-01 -7.95e-01 -7.54e-01 -7.47e-01 -7.72e-01 -7.56e-01 -7.67e-01 -7.42e-01 -7.58e-01 -7.40e-01 -1.14e+00 -9.11e-01 -4.11e-01 -8.04e-01 -7.68e-01 -7.85e-01 -7.81e-01 -7.65e-01 -7.45e-01 -7.31e-01 -7.07e-01 -7.56e-01 -7.56e-01 -7.59e-01 -7.59e-01 -1.11e+00 -1.04e+00 -3.91e-01 -7.71e-01 -7.89e-01 -7.60e-01 -7.67e-01 -7.41e-01 -7.47e-01 -7.26e-01 -7.15e-01 -7.19e-01 -7.39e-01 -7.88e-01 -7.73e-01 -1.12e+00 -1.24e+00 -5.06e-01 -7.87e-01 -7.40e-01 -7.55e-01 -7.36e-01 -7.30e-01 -7.59e-01 -7.40e-01 -7.37e-01 -7.32e-01 -7.38e-01 -7.44e-01 -7.85e-01 -1.11e+00 -8.43e-01 -3.26e-01 -7.83e-01 -7.76e-01 -7.73e-01 -7.64e-01 -7.54e-01 -7.73e-01 -7.28e-01 -7.45e-01 -7.11e-01 -7.24e-01 -7.27e-01 -7.83e-01 -1.10e+00 -6.80e-01 -2.48e-01 -7.83e-01 -7.52e-01 -7.66e-01 -7.85e-01 -7.69e-01 -7.48e-01 -7.23e-01 -6.99e-01 -6.49e-01 -6.92e-01 -7.08e-01 -7.57e-01 -1.07e+00 -7.05e-01 -2.16e-01 -7.82e-01 -7.85e-01 -7.66e-01 -7.58e-01 -7.56e-01 -7.22e-01 -7.09e-01 -6.42e-01 -6.03e-01 -6.32e-01 -6.99e-01 -7.64e-01 -1.08e+00 -8.03e-01 -2.40e-01 -7.40e-01 -7.41e-01 -7.33e-01 -7.45e-01 -7.43e-01 -7.15e-01 -6.99e-01 -6.15e-01 -4.48e-01 -6.70e-01 -7.13e-01 -7.40e-01 -1.05e+00 -8.40e-01 -2.51e-01 -7.67e-01 -7.41e-01 -7.36e-01 -7.41e-01 -7.16e-01 -7.28e-01 -7.11e-01 -6.33e-01 -6.18e-01 -6.57e-01 -7.08e-01 -7.42e-01 -1.00e+00 -7.79e-01 -2.57e-01 -7.51e-01 -7.62e-01 -7.59e-01 -7.36e-01 -7.09e-01 -6.77e-01 -6.94e-01 -6.91e-01 -6.86e-01 -6.77e-01 -6.81e-01 -6.82e-01 -9.60e-01 -6.08e-01 -2.38e-01 -7.58e-01 -8.07e-01 -7.45e-01 -7.27e-01 -7.02e-01 -6.98e-01 -6.68e-01 -6.74e-01 -6.92e-01 -6.88e-01 -6.37e-01 -6.76e-01 -8.84e-01 -3.75e-01 -1.32e-01 -7.90e-01 -7.77e-01 -7.49e-01 -7.25e-01 -7.49e-01 -7.50e-01 -7.08e-01 -7.12e-01 -7.61e-01 -7.28e-01 -6.88e-01 -6.51e-01 -7.19e-01 -3.41e-01 -1.43e-01 -1.14e+00 -1.06e+00 -1.04e+00 -1.06e+00 -1.09e+00 -1.05e+00 -1.03e+00 -9.47e-01 -1.04e+00 -9.40e-01 -9.42e-01 -8.31e-01 -6.65e-01 -2.06e-01 -8.49e-02 -1.33e+00 -1.35e+00 -1.16e+00 -8.61e-01 -8.28e-01 -1.08e+00 -9.81e-01 -7.58e-01 -7.04e-01 -6.54e-01 -7.20e-01 -5.86e-01 -2.41e-01 -1.04e-01 -4.32e-02 -4.74e-01 -5.21e-01 -4.51e-01 -2.77e-01 -2.70e-01 -3.48e-01 -3.55e-01 -2.46e-01 -2.37e-01 -1.76e-01 -2.35e-01 -2.02e-01 -8.43e-02 -4.62e-02 -2.99e-02 -7.31e-01 -7.48e-01 -7.39e-01 -7.66e-01 -7.81e-01 -7.83e-01 -7.79e-01 -7.68e-01 -7.20e-01 -7.09e-01 -7.19e-01 -7.61e-01 -1.05e+00 -7.78e-01 -2.76e-01 -7.52e-01 -7.85e-01 -7.84e-01 -7.87e-01 -7.71e-01 -7.57e-01 -7.62e-01 -7.09e-01 -7.08e-01 -6.96e-01 -7.23e-01 -7.49e-01 -1.06e+00 -5.92e-01 -1.96e-01 -7.43e-01 -7.38e-01 -7.76e-01 -7.70e-01 -7.56e-01 -7.48e-01 -7.41e-01 -7.42e-01 -7.06e-01 -6.90e-01 -7.25e-01 -7.69e-01 -1.04e+00 -8.10e-01 -2.94e-01 -7.40e-01 -7.47e-01 -7.57e-01 -7.48e-01 -7.55e-01 -7.44e-01 -7.42e-01 -7.35e-01 -6.70e-01 -6.64e-01 -7.63e-01 -7.71e-01 -9.80e-01 -7.74e-01 -3.07e-01 -7.55e-01 -7.66e-01 -7.97e-01 -7.40e-01 -7.53e-01 -7.39e-01 -7.26e-01 -7.07e-01 -6.89e-01 -6.87e-01 -7.44e-01 -7.30e-01 -1.03e+00 -6.26e-01 -1.73e-01 -7.55e-01 -7.36e-01 -7.61e-01 -7.64e-01 -7.21e-01 -7.01e-01 -7.26e-01 -6.89e-01 -6.95e-01 -6.71e-01 -6.81e-01 -7.49e-01 -9.77e-01 -6.44e-01 -2.24e-01 -7.44e-01 -7.16e-01 -7.45e-01 -7.32e-01 -7.41e-01 -7.10e-01 -6.77e-01 -6.35e-01 -6.21e-01 -6.30e-01 -6.43e-01 -6.90e-01 -9.34e-01 -7.67e-01 -2.92e-01 -7.32e-01 -7.55e-01 -7.18e-01 -7.24e-01 -7.26e-01 -7.05e-01 -6.53e-01 -6.21e-01 -6.43e-01 -6.52e-01 -7.13e-01 -7.09e-01 -9.53e-01 -6.82e-01 -2.54e-01 -6.97e-01 -7.00e-01 -7.14e-01 -6.97e-01 -7.15e-01 -6.93e-01 -6.77e-01 -6.33e-01 -6.17e-01 -6.11e-01 -7.05e-01 -6.87e-01 -9.29e-01 -5.46e-01 -1.70e-01 -7.20e-01 -7.06e-01 -7.18e-01 -6.87e-01 -6.85e-01 -6.94e-01 -6.44e-01 -6.64e-01 -5.99e-01 -5.89e-01 -6.44e-01 -6.80e-01 -9.68e-01 -6.14e-01 -1.98e-01 -7.51e-01 -7.34e-01 -7.39e-01 -6.97e-01 -6.75e-01 -6.82e-01 -6.70e-01 -7.02e-01 -6.60e-01 -6.35e-01 -6.16e-01 -6.32e-01 -8.05e-01 -4.17e-01 -1.09e-01 -7.89e-01 -7.57e-01 -7.50e-01 -7.29e-01 -7.26e-01 -6.77e-01 -6.48e-01 -7.04e-01 -6.97e-01 -6.79e-01 -6.60e-01 -6.12e-01 -7.24e-01 -2.74e-01 -7.82e-02 -1.14e+00 -1.03e+00 -1.04e+00 -9.43e-01 -1.02e+00 -9.87e-01 -8.16e-01 -8.35e-01 -8.39e-01 -9.59e-01 -9.15e-01 -7.74e-01 -5.71e-01 -1.72e-01 -5.75e-02 -1.12e+00 -1.16e+00 -8.35e-01 -7.13e-01 -7.64e-01 -8.80e-01 -5.67e-01 -4.88e-01 -4.31e-01 -7.46e-01 -6.47e-01 -4.18e-01 -2.22e-01 -6.04e-02 -2.42e-02 -3.88e-01 -3.92e-01 -2.68e-01 -2.61e-01 -2.31e-01 -3.03e-01 -2.09e-01 -1.58e-01 -1.36e-01 -2.55e-01 -2.03e-01 -1.38e-01 -9.69e-02 -4.41e-02 -1.17e-02 -7.71e-01 -7.88e-01 -8.12e-01 -7.42e-01 -7.85e-01 -7.60e-01 -7.46e-01 -7.71e-01 -7.11e-01 -6.80e-01 -6.82e-01 -7.51e-01 -1.04e+00 -6.16e-01 -1.78e-01 -7.57e-01 -7.66e-01 -7.96e-01 -7.87e-01 -7.31e-01 -7.75e-01 -7.52e-01 -7.45e-01 -7.07e-01 -7.05e-01 -7.08e-01 -7.39e-01 -9.99e-01 -6.60e-01 -2.06e-01 -7.40e-01 -7.48e-01 -7.67e-01 -7.62e-01 -7.72e-01 -7.12e-01 -7.41e-01 -7.52e-01 -6.99e-01 -6.87e-01 -6.89e-01 -7.63e-01 -1.10e+00 -8.27e-01 -2.75e-01 -7.59e-01 -7.19e-01 -7.47e-01 -7.32e-01 -7.40e-01 -7.41e-01 -7.25e-01 -7.31e-01 -6.89e-01 -7.01e-01 -7.16e-01 -6.95e-01 -9.76e-01 -8.88e-01 -3.69e-01 -7.39e-01 -7.23e-01 -7.22e-01 -7.34e-01 -7.32e-01 -7.19e-01 -7.08e-01 -7.23e-01 -7.13e-01 -6.86e-01 -7.13e-01 -7.47e-01 -9.68e-01 -6.85e-01 -2.05e-01 -7.59e-01 -7.40e-01 -7.23e-01 -6.89e-01 -6.89e-01 -6.98e-01 -7.04e-01 -6.61e-01 -6.79e-01 -6.79e-01 -6.86e-01 -7.42e-01 -1.01e+00 -7.65e-01 -2.63e-01 -7.27e-01 -7.22e-01 -7.21e-01 -6.82e-01 -6.82e-01 -6.79e-01 -6.66e-01 -6.58e-01 -6.31e-01 -6.61e-01 -6.87e-01 -6.88e-01 -8.56e-01 -5.97e-01 -2.13e-01 -7.02e-01 -7.13e-01 -7.28e-01 -6.93e-01 -6.91e-01 -6.69e-01 -6.46e-01 -6.28e-01 -6.40e-01 -6.38e-01 -6.71e-01 -6.96e-01 -8.50e-01 -3.86e-01 -1.50e-01 -6.91e-01 -6.77e-01 -6.91e-01 -7.07e-01 -7.18e-01 -7.31e-01 -6.70e-01 -6.39e-01 -6.18e-01 -6.02e-01 -6.11e-01 -6.66e-01 -9.21e-01 -4.38e-01 -1.13e-01 -7.24e-01 -6.84e-01 -6.84e-01 -6.47e-01 -6.69e-01 -6.83e-01 -6.69e-01 -6.47e-01 -6.14e-01 -5.97e-01 -6.05e-01 -6.26e-01 -9.22e-01 -4.59e-01 -1.15e-01 -7.38e-01 -6.58e-01 -6.82e-01 -6.72e-01 -7.05e-01 -6.71e-01 -6.60e-01 -6.37e-01 -6.35e-01 -6.02e-01 -5.50e-01 -5.85e-01 -8.26e-01 -4.84e-01 -1.41e-01 -7.40e-01 -6.73e-01 -6.74e-01 -7.15e-01 -7.22e-01 -6.98e-01 -7.17e-01 -6.74e-01 -6.70e-01 -6.46e-01 -5.85e-01 -5.00e-01 -4.95e-01 -2.74e-01 -8.29e-02 -1.11e+00 -9.99e-01 -1.02e+00 -1.05e+00 -1.05e+00 -9.96e-01 -9.29e-01 -9.64e-01 -8.97e-01 -9.51e-01 -8.48e-01 -7.23e-01 -6.11e-01 -2.17e-01 -6.09e-02 -1.15e+00 -9.21e-01 -8.94e-01 -8.34e-01 -8.60e-01 -8.05e-01 -5.65e-01 -5.80e-01 -5.28e-01 -5.64e-01 -6.00e-01 -4.16e-01 -2.18e-01 -8.48e-02 -2.93e-02 -3.50e-01 -2.74e-01 -2.33e-01 -2.38e-01 -2.50e-01 -2.74e-01 -1.88e-01 -1.72e-01 -1.56e-01 -1.57e-01 -1.94e-01 -1.39e-01 -6.35e-02 -3.19e-02 -7.49e-03 -7.41e-01 -7.68e-01 -7.90e-01 -7.78e-01 -7.76e-01 -7.30e-01 -7.18e-01 -7.37e-01 -7.09e-01 -7.20e-01 -7.00e-01 -7.72e-01 -9.68e-01 -6.90e-01 -2.52e-01 -7.57e-01 -7.64e-01 -7.45e-01 -7.47e-01 -7.46e-01 -7.65e-01 -7.54e-01 -7.52e-01 -7.26e-01 -6.82e-01 -7.09e-01 -7.86e-01 -1.04e+00 -7.77e-01 -2.28e-01 -7.74e-01 -7.42e-01 -7.17e-01 -7.21e-01 -7.29e-01 -7.67e-01 -7.52e-01 -7.57e-01 -7.68e-01 -6.89e-01 -6.78e-01 -7.59e-01 -1.05e+00 -8.28e-01 -2.72e-01 -7.40e-01 -7.34e-01 -7.31e-01 -7.16e-01 -7.44e-01 -7.39e-01 -7.56e-01 -7.44e-01 -7.10e-01 -6.88e-01 -6.97e-01 -7.44e-01 -9.71e-01 -7.11e-01 -2.71e-01 -7.13e-01 -6.97e-01 -7.29e-01 -7.42e-01 -7.39e-01 -7.08e-01 -7.05e-01 -7.31e-01 -6.98e-01 -6.88e-01 -7.17e-01 -7.13e-01 -9.73e-01 -6.01e-01 -1.91e-01 -7.45e-01 -7.09e-01 -7.35e-01 -7.10e-01 -7.14e-01 -7.15e-01 -7.08e-01 -7.06e-01 -6.78e-01 -6.67e-01 -6.90e-01 -7.12e-01 -9.35e-01 -5.48e-01 -2.00e-01 -7.32e-01 -7.22e-01 -7.10e-01 -7.08e-01 -7.09e-01 -7.14e-01 -6.79e-01 -6.85e-01 -6.58e-01 -6.83e-01 -6.50e-01 -7.09e-01 -9.87e-01 -7.05e-01 -2.37e-01 -7.08e-01 -7.29e-01 -7.25e-01 -7.21e-01 -7.00e-01 -6.83e-01 -6.43e-01 -6.62e-01 -6.42e-01 -6.10e-01 -6.47e-01 -7.20e-01 -8.94e-01 -4.05e-01 -1.25e-01 -6.82e-01 -6.98e-01 -7.11e-01 -7.24e-01 -7.09e-01 -6.74e-01 -6.40e-01 -6.25e-01 -6.06e-01 -6.01e-01 -6.22e-01 -6.85e-01 -8.81e-01 -4.33e-01 -1.27e-01 -7.04e-01 -6.95e-01 -6.94e-01 -7.08e-01 -6.83e-01 -6.66e-01 -6.52e-01 -6.14e-01 -6.08e-01 -6.22e-01 -5.79e-01 -6.40e-01 -8.39e-01 -5.15e-01 -1.65e-01 -7.06e-01 -6.74e-01 -6.69e-01 -6.66e-01 -6.63e-01 -6.70e-01 -6.87e-01 -6.53e-01 -6.03e-01 -5.84e-01 -5.54e-01 -5.65e-01 -7.87e-01 -4.40e-01 -1.48e-01 -7.67e-01 -6.97e-01 -7.26e-01 -7.26e-01 -6.91e-01 -7.44e-01 -7.07e-01 -6.80e-01 -6.22e-01 -6.16e-01 -5.70e-01 -4.85e-01 -5.06e-01 -2.87e-01 -9.16e-02 -1.20e+00 -9.57e-01 -8.98e-01 -1.03e+00 -9.83e-01 -1.01e+00 -9.58e-01 -1.03e+00 -9.95e-01 -1.02e+00 -8.79e-01 -6.76e-01 -5.34e-01 -1.83e-01 -6.50e-02 -9.53e-01 -7.68e-01 -7.45e-01 -8.42e-01 -9.10e-01 -8.62e-01 -7.39e-01 -7.46e-01 -6.49e-01 -5.31e-01 -4.80e-01 -3.53e-01 -2.00e-01 -8.55e-02 -3.73e-02 -3.66e-01 -3.07e-01 -3.18e-01 -2.87e-01 -3.14e-01 -2.90e-01 -2.36e-01 -2.15e-01 -2.24e-01 -1.70e-01 -1.63e-01 -1.15e-01 -6.32e-02 -3.84e-02 -1.78e-02 -7.11e-01 -7.35e-01 -7.78e-01 -7.95e-01 -7.89e-01 -7.78e-01 -7.90e-01 -8.15e-01 -7.38e-01 -7.56e-01 -7.46e-01 -7.19e-01 -8.73e-01 -4.87e-01 -1.89e-01 -7.24e-01 -7.51e-01 -7.47e-01 -7.52e-01 -7.63e-01 -7.61e-01 -7.53e-01 -7.69e-01 -7.59e-01 -7.54e-01 -7.39e-01 -7.28e-01 -9.65e-01 -6.51e-01 -2.08e-01 -7.30e-01 -7.39e-01 -7.32e-01 -7.64e-01 -7.35e-01 -7.69e-01 -7.88e-01 -7.27e-01 -7.35e-01 -7.32e-01 -7.27e-01 -7.49e-01 -9.97e-01 -7.08e-01 -2.42e-01 -7.30e-01 -7.41e-01 -7.80e-01 -7.20e-01 -7.72e-01 -7.80e-01 -7.58e-01 -7.29e-01 -7.22e-01 -6.85e-01 -6.91e-01 -7.32e-01 -9.70e-01 -5.55e-01 -1.80e-01 -7.25e-01 -7.42e-01 -7.54e-01 -7.29e-01 -7.69e-01 -7.68e-01 -7.23e-01 -7.19e-01 -7.39e-01 -6.99e-01 -7.30e-01 -7.43e-01 -9.67e-01 -5.29e-01 -1.58e-01 -7.27e-01 -7.38e-01 -7.50e-01 -7.78e-01 -7.29e-01 -7.53e-01 -7.20e-01 -7.07e-01 -6.58e-01 -7.03e-01 -7.03e-01 -6.97e-01 -1.02e+00 -5.77e-01 -1.55e-01 -7.04e-01 -7.29e-01 -7.04e-01 -7.41e-01 -7.23e-01 -7.27e-01 -7.22e-01 -6.89e-01 -6.68e-01 -6.72e-01 -6.90e-01 -7.11e-01 -9.24e-01 -6.32e-01 -1.76e-01 -6.92e-01 -7.24e-01 -7.27e-01 -7.47e-01 -7.06e-01 -7.02e-01 -6.65e-01 -6.69e-01 -6.63e-01 -6.78e-01 -6.76e-01 -6.84e-01 -8.81e-01 -5.82e-01 -2.05e-01 -6.77e-01 -6.97e-01 -7.18e-01 -7.16e-01 -7.22e-01 -6.99e-01 -6.33e-01 -6.46e-01 -6.22e-01 -6.20e-01 -6.04e-01 -6.27e-01 -8.72e-01 -4.58e-01 -1.30e-01 -6.94e-01 -6.76e-01 -6.98e-01 -7.16e-01 -7.24e-01 -6.61e-01 -6.58e-01 -6.43e-01 -5.98e-01 -6.12e-01 -5.72e-01 -5.75e-01 -7.13e-01 -4.13e-01 -1.41e-01 -6.83e-01 -6.80e-01 -6.85e-01 -6.92e-01 -6.94e-01 -6.60e-01 -6.70e-01 -6.56e-01 -5.95e-01 -5.92e-01 -5.52e-01 -5.66e-01 -7.57e-01 -2.75e-01 -8.14e-02 -6.80e-01 -6.88e-01 -6.98e-01 -7.21e-01 -6.86e-01 -7.14e-01 -7.21e-01 -6.93e-01 -6.28e-01 -6.06e-01 -5.69e-01 -5.25e-01 -6.18e-01 -2.39e-01 -7.13e-02 -9.78e-01 -8.94e-01 -9.02e-01 -9.75e-01 -9.93e-01 -9.72e-01 -9.04e-01 -9.60e-01 -9.01e-01 -8.02e-01 -8.03e-01 -6.71e-01 -3.57e-01 -1.04e-01 -3.71e-02 -8.79e-01 -4.74e-01 -6.09e-01 -6.57e-01 -6.73e-01 -6.70e-01 -5.29e-01 -7.08e-01 -5.73e-01 -3.74e-01 -4.21e-01 -2.98e-01 -1.43e-01 -5.64e-02 -1.94e-02 -2.87e-01 -1.53e-01 -1.84e-01 -2.04e-01 -2.63e-01 -2.36e-01 -1.65e-01 -2.34e-01 -1.92e-01 -1.28e-01 -1.20e-01 -7.57e-02 -5.20e-02 -3.12e-02 -1.69e-02 -7.55e-01 -8.03e-01 -8.38e-01 -8.11e-01 -8.12e-01 -8.21e-01 -8.19e-01 -7.76e-01 -7.65e-01 -7.57e-01 -7.69e-01 -7.22e-01 -7.14e-01 -1.75e-01 -6.92e-02 -8.24e-01 -8.38e-01 -8.21e-01 -7.68e-01 -7.55e-01 -7.68e-01 -7.83e-01 -7.52e-01 -7.51e-01 -7.46e-01 -7.74e-01 -7.44e-01 -8.02e-01 -3.34e-01 -1.21e-01 -7.93e-01 -8.41e-01 -7.94e-01 -7.70e-01 -7.76e-01 -8.31e-01 -8.21e-01 -7.99e-01 -7.37e-01 -7.45e-01 -7.12e-01 -8.00e-01 -1.03e+00 -5.16e-01 -1.38e-01 -7.80e-01 -7.93e-01 -7.72e-01 -7.70e-01 -7.94e-01 -8.27e-01 -8.15e-01 -7.14e-01 -7.62e-01 -7.24e-01 -6.76e-01 -7.22e-01 -8.97e-01 -4.58e-01 -1.53e-01 -7.51e-01 -7.55e-01 -7.71e-01 -7.75e-01 -7.94e-01 -7.94e-01 -7.68e-01 -7.35e-01 -7.64e-01 -7.55e-01 -7.00e-01 -7.25e-01 -9.50e-01 -5.35e-01 -1.47e-01 -7.48e-01 -7.62e-01 -7.42e-01 -7.69e-01 -7.62e-01 -7.55e-01 -7.49e-01 -7.15e-01 -7.33e-01 -7.29e-01 -6.88e-01 -6.77e-01 -8.92e-01 -4.73e-01 -1.54e-01 -7.07e-01 -7.12e-01 -7.63e-01 -7.78e-01 -7.67e-01 -7.38e-01 -7.39e-01 -7.04e-01 -6.90e-01 -7.02e-01 -7.00e-01 -6.50e-01 -7.45e-01 -4.80e-01 -1.67e-01 -7.10e-01 -7.31e-01 -7.02e-01 -7.48e-01 -7.25e-01 -7.23e-01 -7.48e-01 -7.26e-01 -7.06e-01 -6.63e-01 -6.82e-01 -6.87e-01 -8.55e-01 -3.87e-01 -1.27e-01 -7.27e-01 -7.16e-01 -7.34e-01 -7.54e-01 -7.46e-01 -7.70e-01 -7.11e-01 -6.87e-01 -6.70e-01 -6.64e-01 -6.35e-01 -6.35e-01 -8.28e-01 -3.65e-01 -1.19e-01 -7.19e-01 -6.95e-01 -7.56e-01 -7.46e-01 -7.40e-01 -7.30e-01 -6.89e-01 -6.43e-01 -6.17e-01 -5.90e-01 -6.17e-01 -5.70e-01 -7.99e-01 -3.80e-01 -1.34e-01 -6.68e-01 -6.64e-01 -6.96e-01 -7.05e-01 -7.48e-01 -7.14e-01 -6.55e-01 -6.42e-01 -6.17e-01 -5.96e-01 -5.59e-01 -5.39e-01 -6.83e-01 -2.51e-01 -7.41e-02 -6.65e-01 -6.54e-01 -6.72e-01 -6.79e-01 -6.77e-01 -6.50e-01 -6.85e-01 -6.99e-01 -6.33e-01 -6.12e-01 -5.40e-01 -5.07e-01 -5.77e-01 -2.24e-01 -6.42e-02 -8.66e-01 -8.00e-01 -8.01e-01 -8.48e-01 -8.27e-01 -8.32e-01 -8.36e-01 -9.02e-01 -9.05e-01 -7.29e-01 -6.75e-01 -5.88e-01 -3.48e-01 -1.10e-01 -3.71e-02 -6.49e-01 -3.51e-01 -4.24e-01 -5.24e-01 -4.05e-01 -4.08e-01 -3.66e-01 -3.97e-01 -5.38e-01 -3.80e-01 -2.81e-01 -2.19e-01 -1.32e-01 -3.23e-02 -1.05e-02 -2.57e-01 -1.34e-01 -1.74e-01 -1.81e-01 -1.46e-01 -1.42e-01 -1.23e-01 -1.30e-01 -1.65e-01 -1.27e-01 -8.17e-02 -7.95e-02 -5.09e-02 -1.73e-02 -7.50e-03 -1.08e+00 -1.13e+00 -1.22e+00 -1.22e+00 -1.16e+00 -1.11e+00 -1.11e+00 -1.06e+00 -1.11e+00 -9.89e-01 -9.97e-01 -1.02e+00 -7.84e-01 -1.55e-01 -3.93e-02 -1.15e+00 -1.05e+00 -1.23e+00 -1.10e+00 -1.10e+00 -1.14e+00 -1.11e+00 -1.03e+00 -9.91e-01 -1.02e+00 -9.48e-01 -9.15e-01 -8.91e-01 -2.88e-01 -8.05e-02 -1.12e+00 -1.04e+00 -1.18e+00 -1.10e+00 -1.06e+00 -1.18e+00 -1.04e+00 -1.15e+00 -1.03e+00 -1.04e+00 -9.63e-01 -9.19e-01 -1.05e+00 -4.94e-01 -1.55e-01 -1.12e+00 -1.03e+00 -1.09e+00 -1.12e+00 -1.10e+00 -1.19e+00 -1.11e+00 -1.10e+00 -1.06e+00 -1.01e+00 -8.73e-01 -8.08e-01 -8.67e-01 -3.12e-01 -9.00e-02 -1.08e+00 -1.03e+00 -1.06e+00 -1.10e+00 -1.05e+00 -1.13e+00 -1.27e+00 -1.09e+00 -1.08e+00 -1.12e+00 -9.93e-01 -8.86e-01 -7.84e-01 -3.95e-01 -1.46e-01 -1.07e+00 -9.78e-01 -1.03e+00 -1.02e+00 -1.00e+00 -1.09e+00 -1.08e+00 -1.01e+00 -1.03e+00 -1.07e+00 -9.59e-01 -8.28e-01 -8.42e-01 -4.01e-01 -1.22e-01 -9.48e-01 -9.63e-01 -1.06e+00 -1.04e+00 -9.98e-01 -1.04e+00 -1.02e+00 -9.83e-01 -8.41e-01 -9.51e-01 -9.08e-01 -7.45e-01 -7.77e-01 -3.05e-01 -9.78e-02 -9.70e-01 -9.47e-01 -9.99e-01 -1.08e+00 -1.11e+00 -1.03e+00 -1.01e+00 -9.93e-01 -8.83e-01 -8.87e-01 -9.14e-01 -8.38e-01 -6.43e-01 -1.75e-01 -5.80e-02 -9.67e-01 -9.99e-01 -1.01e+00 -1.06e+00 -1.08e+00 -9.67e-01 -1.08e+00 -1.02e+00 -8.98e-01 -9.10e-01 -8.57e-01 -8.25e-01 -8.06e-01 -2.24e-01 -7.49e-02 -9.69e-01 -1.03e+00 -1.10e+00 -1.01e+00 -1.06e+00 -9.81e-01 -1.01e+00 -9.04e-01 -8.30e-01 -8.02e-01 -8.09e-01 -8.11e-01 -7.80e-01 -2.46e-01 -7.63e-02 -8.90e-01 -9.28e-01 -1.02e+00 -1.02e+00 -9.83e-01 -1.07e+00 -9.40e-01 -8.16e-01 -7.84e-01 -6.91e-01 -7.33e-01 -6.96e-01 -5.05e-01 -2.10e-01 -7.72e-02 -7.36e-01 -7.62e-01 -8.86e-01 -8.71e-01 -9.21e-01 -9.57e-01 -1.00e+00 -9.26e-01 -8.38e-01 -7.10e-01 -6.68e-01 -6.38e-01 -4.88e-01 -1.47e-01 -5.84e-02 -6.38e-01 -6.97e-01 -7.81e-01 -7.21e-01 -8.22e-01 -8.29e-01 -6.94e-01 -9.33e-01 -9.36e-01 -7.85e-01 -5.91e-01 -4.82e-01 -3.15e-01 -9.11e-02 -4.04e-02 -3.59e-01 -2.19e-01 -2.60e-01 -3.06e-01 -2.48e-01 -2.41e-01 -2.20e-01 -2.69e-01 -4.39e-01 -2.88e-01 -1.35e-01 -1.30e-01 -7.47e-02 -2.46e-02 -1.39e-02 -1.37e-01 -7.05e-02 -9.05e-02 -9.63e-02 -7.38e-02 -7.57e-02 -7.98e-02 -7.83e-02 -1.40e-01 -1.09e-01 -5.52e-02 -4.14e-02 -2.38e-02 -1.27e-02 -4.98e-03 -1.08e+00 -1.06e+00 -1.34e+00 -9.87e-01 -1.49e+00 -1.22e+00 -1.08e+00 -1.13e+00 -9.74e-01 -8.45e-01 -6.07e-01 -6.33e-01 -5.34e-01 -1.43e-01 -3.98e-02 -1.35e+00 -9.68e-01 -1.60e+00 -1.80e+00 -1.45e+00 -1.17e+00 -9.94e-01 -1.02e+00 -8.65e-01 -7.01e-01 -6.46e-01 -5.40e-01 -4.49e-01 -2.04e-01 -7.38e-02 -1.18e+00 -1.14e+00 -1.48e+00 -1.19e+00 -9.38e-01 -1.19e+00 -9.74e-01 -1.01e+00 -9.23e-01 -8.23e-01 -8.89e-01 -7.01e-01 -3.85e-01 -2.16e-01 -1.44e-01 -1.32e+00 -1.14e+00 -1.36e+00 -1.53e+00 -1.16e+00 -1.29e+00 -1.36e+00 -1.18e+00 -1.09e+00 -8.66e-01 -6.32e-01 -4.57e-01 -3.13e-01 -1.52e-01 -6.87e-02 -1.30e+00 -9.74e-01 -1.29e+00 -1.54e+00 -1.33e+00 -1.38e+00 -1.35e+00 -1.13e+00 -9.14e-01 -8.56e-01 -7.71e-01 -4.06e-01 -2.63e-01 -1.30e-01 -6.54e-02 -1.05e+00 -7.94e-01 -1.12e+00 -1.15e+00 -8.13e-01 -9.20e-01 -1.09e+00 -8.11e-01 -6.93e-01 -8.96e-01 -8.00e-01 -5.26e-01 -2.87e-01 -1.23e-01 -7.75e-02 -7.48e-01 -9.01e-01 -1.04e+00 -1.05e+00 -9.12e-01 -1.00e+00 -9.12e-01 -7.83e-01 -6.62e-01 -6.12e-01 -4.88e-01 -3.46e-01 -2.31e-01 -1.33e-01 -7.44e-02 -5.62e-01 -7.11e-01 -8.51e-01 -8.66e-01 -9.29e-01 -9.65e-01 -6.70e-01 -6.37e-01 -4.77e-01 -4.37e-01 -4.96e-01 -3.94e-01 -2.26e-01 -1.06e-01 -3.96e-02 -6.10e-01 -6.97e-01 -8.44e-01 -1.11e+00 -8.69e-01 -7.98e-01 -6.03e-01 -7.36e-01 -5.96e-01 -5.37e-01 -4.95e-01 -4.22e-01 -2.94e-01 -1.01e-01 -4.37e-02 -4.56e-01 -8.07e-01 -1.07e+00 -8.05e-01 -7.16e-01 -5.03e-01 -6.26e-01 -7.10e-01 -5.73e-01 -4.58e-01 -4.44e-01 -3.45e-01 -2.60e-01 -1.36e-01 -4.22e-02 -4.93e-01 -6.13e-01 -8.04e-01 -5.55e-01 -7.11e-01 -7.23e-01 -5.94e-01 -5.56e-01 -4.34e-01 -2.96e-01 -3.80e-01 -3.42e-01 -2.09e-01 -1.08e-01 -4.84e-02 -4.28e-01 -3.61e-01 -5.20e-01 -4.86e-01 -4.81e-01 -6.92e-01 -5.95e-01 -3.74e-01 -3.26e-01 -2.76e-01 -2.59e-01 -2.57e-01 -1.85e-01 -4.96e-02 -1.83e-02 -2.15e-01 -2.66e-01 -3.14e-01 -2.45e-01 -2.95e-01 -4.30e-01 -3.75e-01 -3.67e-01 -3.05e-01 -3.09e-01 -2.21e-01 -1.80e-01 -1.34e-01 -5.03e-02 -2.00e-02 -9.60e-02 -1.01e-01 -1.15e-01 -9.88e-02 -1.27e-01 -1.67e-01 -1.28e-01 -1.60e-01 -1.75e-01 -1.43e-01 -8.60e-02 -5.91e-02 -4.18e-02 -2.09e-02 -1.01e-02 -6.92e-02 -3.71e-02 -4.18e-02 -4.29e-02 -4.54e-02 -6.16e-02 -4.09e-02 -5.12e-02 -7.23e-02 -6.74e-02 -3.14e-02 -1.80e-02 -1.64e-02 -7.47e-03 -2.97e-03 -3.66e-01 -3.67e-01 -4.98e-01 -3.34e-01 -5.46e-01 -4.10e-01 -3.75e-01 -3.97e-01 -3.66e-01 -2.85e-01 -1.96e-01 -1.98e-01 -1.79e-01 -1.05e-01 -3.65e-02 -5.51e-01 -2.62e-01 -5.35e-01 -7.29e-01 -6.22e-01 -4.43e-01 -3.56e-01 -3.26e-01 -3.18e-01 -2.53e-01 -1.98e-01 -1.61e-01 -1.35e-01 -8.96e-02 -4.34e-02 -4.38e-01 -3.47e-01 -5.06e-01 -4.90e-01 -2.64e-01 -4.25e-01 -3.58e-01 -3.11e-01 -3.30e-01 -2.32e-01 -3.09e-01 -2.65e-01 -1.43e-01 -6.12e-02 -6.39e-02 -4.34e-01 -3.64e-01 -5.30e-01 -6.02e-01 -4.03e-01 -4.34e-01 -4.80e-01 -4.48e-01 -4.35e-01 -3.28e-01 -2.19e-01 -1.55e-01 -1.04e-01 -6.22e-02 -2.93e-02 -5.28e-01 -3.92e-01 -4.89e-01 -5.69e-01 -5.08e-01 -4.82e-01 -5.01e-01 -3.73e-01 -3.58e-01 -2.50e-01 -2.62e-01 -1.19e-01 -7.33e-02 -4.35e-02 -2.75e-02 -3.24e-01 -2.74e-01 -3.53e-01 -3.82e-01 -3.09e-01 -2.64e-01 -3.42e-01 -2.59e-01 -2.24e-01 -2.72e-01 -2.89e-01 -2.17e-01 -1.01e-01 -4.22e-02 -2.14e-02 -3.08e-01 -2.90e-01 -3.71e-01 -4.11e-01 -2.41e-01 -2.90e-01 -2.99e-01 -2.76e-01 -2.53e-01 -2.06e-01 -1.62e-01 -1.37e-01 -7.91e-02 -3.97e-02 -3.67e-02 -1.54e-01 -2.66e-01 -2.58e-01 -2.66e-01 -2.93e-01 -3.18e-01 -1.96e-01 -2.10e-01 -1.51e-01 -1.19e-01 -1.30e-01 -1.25e-01 -6.88e-02 -5.68e-02 -4.11e-02 -1.94e-01 -2.10e-01 -2.78e-01 -3.44e-01 -3.33e-01 -3.12e-01 -1.89e-01 -2.43e-01 -2.08e-01 -1.74e-01 -1.46e-01 -1.34e-01 -1.11e-01 -4.65e-02 -1.94e-02 -1.16e-01 -2.46e-01 -3.24e-01 -3.12e-01 -2.29e-01 -1.48e-01 -2.01e-01 -2.33e-01 -2.12e-01 -1.40e-01 -1.33e-01 -1.13e-01 -6.83e-02 -6.78e-02 -3.69e-02 -1.55e-01 -2.51e-01 -2.94e-01 -1.53e-01 -2.32e-01 -2.02e-01 -1.35e-01 -1.89e-01 -1.55e-01 -1.09e-01 -1.17e-01 -9.56e-02 -6.95e-02 -5.08e-02 -3.96e-02 -1.13e-01 -1.22e-01 -1.62e-01 -1.45e-01 -1.49e-01 -2.36e-01 -2.03e-01 -1.50e-01 -1.01e-01 -8.51e-02 -7.83e-02 -7.56e-02 -7.49e-02 -2.08e-02 -8.15e-03 -9.29e-02 -9.19e-02 -1.09e-01 -1.23e-01 -9.19e-02 -1.58e-01 -1.36e-01 -1.13e-01 -8.64e-02 -1.01e-01 -5.95e-02 -6.00e-02 -5.68e-02 -2.10e-02 -7.24e-03 -3.10e-02 -4.84e-02 -4.87e-02 -3.68e-02 -5.75e-02 -7.85e-02 -7.07e-02 -8.18e-02 -9.39e-02 -5.13e-02 -5.46e-02 -3.42e-02 -2.14e-02 -1.34e-02 -1.14e-02 -2.27e-02 -2.51e-02 -2.70e-02 -2.56e-02 -3.02e-02 -5.07e-02 -3.42e-02 -3.18e-02 -5.82e-02 -3.83e-02 -2.90e-02 -1.85e-02 -7.38e-03 -5.00e-03 -7.27e-03 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat deleted file mode 100644 index 62f847858..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat +++ /dev/null @@ -1,267 +0,0 @@ - - - - mgxs.h5 - - - - - - - - - - - - - - - - - - - - - 2.5 2.5 2.5 - 12 12 12 - 0.0 0.0 0.0 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 -1 1 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 -2 2 2 2 2 2 2 2 2 2 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 -3 3 3 3 3 3 3 3 3 3 3 3 - - - - - - - - - - fixed source - 750 - 30 - 20 - - - 100.0 1.0 - - - universe - 1 - - - multi-group - - - 1 - neutron - 10 - 1 - true - fw_cadis - - - - 15 15 15 - 0.0 0.0 0.0 - 30.0 30.0 30.0 - - - 500.0 - 100.0 - - - - 0.0 0.0 0.0 30.0 30.0 30.0 - - - - true - - - - - - linear - - - - - 1 - - - 2 - - - 3 - - - 3 - flux - tracklength - - - 2 - flux - tracklength - - - 1 - flux - tracklength - - - diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/results_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/results_true.dat deleted file mode 100644 index c1066ae82..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/results_true.dat +++ /dev/null @@ -1,6760 +0,0 @@ -RegularMesh - ID = 1 - Name = - Dimensions = 3 - Voxels = [15 15 15] - Lower left = [0. 0. 0.] - Upper Right = [np.float64(30.0), np.float64(30.0), np.float64(30.0)] - Width = [2. 2. 2.] -Lower Bounds -1.77e-01 -1.81e-01 -1.81e-01 -1.81e-01 -1.78e-01 -1.74e-01 -1.70e-01 -1.76e-01 -1.80e-01 -1.88e-01 -1.75e-01 -1.93e-01 -2.76e-01 -4.28e-01 -1.58e-01 -1.74e-01 -1.82e-01 -1.81e-01 -1.63e-01 -1.78e-01 -1.81e-01 -1.77e-01 -1.77e-01 -1.74e-01 -1.72e-01 -1.81e-01 -1.82e-01 -2.58e-01 -3.27e-01 -1.07e-01 -1.82e-01 -1.75e-01 -1.81e-01 -1.82e-01 -1.76e-01 -1.77e-01 -1.74e-01 -1.66e-01 -1.66e-01 -1.69e-01 -1.76e-01 -1.87e-01 -2.67e-01 -4.16e-01 -1.57e-01 -1.76e-01 -1.74e-01 -1.72e-01 -1.76e-01 -1.67e-01 -1.68e-01 -1.70e-01 -1.75e-01 -1.72e-01 -1.73e-01 -1.65e-01 -1.84e-01 -2.67e-01 -3.99e-01 -1.28e-01 -1.75e-01 -1.82e-01 -1.82e-01 -1.84e-01 -1.72e-01 -1.72e-01 -1.67e-01 -1.67e-01 -1.66e-01 -1.74e-01 -1.69e-01 -1.90e-01 -2.82e-01 -3.31e-01 -1.29e-01 -1.80e-01 -1.79e-01 -1.79e-01 -1.78e-01 -1.76e-01 -1.69e-01 -1.68e-01 -1.63e-01 -1.70e-01 -1.66e-01 -1.71e-01 -1.92e-01 -2.70e-01 -2.88e-01 -1.02e-01 -1.76e-01 -1.72e-01 -1.68e-01 -1.71e-01 -1.66e-01 -1.68e-01 -1.65e-01 -1.66e-01 -1.62e-01 -1.60e-01 -1.61e-01 -1.66e-01 -2.39e-01 -3.32e-01 -1.23e-01 -1.82e-01 -1.81e-01 -1.79e-01 -1.70e-01 -1.67e-01 -1.72e-01 -1.65e-01 -1.62e-01 -1.47e-01 -1.56e-01 -1.56e-01 -1.44e-01 -2.01e-01 -1.76e-01 -7.55e-02 -1.76e-01 -1.76e-01 -1.80e-01 -1.82e-01 -1.71e-01 -1.67e-01 -1.65e-01 -1.62e-01 -1.54e-01 -1.55e-01 -1.54e-01 -1.55e-01 -2.28e-01 -1.67e-01 -5.36e-02 -1.77e-01 -1.85e-01 -1.83e-01 -1.81e-01 -1.79e-01 -1.61e-01 -1.64e-01 -1.58e-01 -1.61e-01 -1.60e-01 -1.55e-01 -1.53e-01 -2.33e-01 -1.74e-01 -6.51e-02 -1.81e-01 -1.79e-01 -1.83e-01 -1.79e-01 -1.80e-01 -1.69e-01 -1.58e-01 -1.66e-01 -1.59e-01 -1.59e-01 -1.70e-01 -1.56e-01 -2.11e-01 -1.28e-01 -3.74e-02 -1.90e-01 -1.90e-01 -1.82e-01 -1.71e-01 -1.90e-01 -1.82e-01 -1.72e-01 -1.79e-01 -1.69e-01 -1.69e-01 -1.66e-01 -1.51e-01 -2.22e-01 -9.62e-02 -3.14e-02 -2.75e-01 -2.73e-01 -2.51e-01 -2.62e-01 -2.73e-01 -2.67e-01 -2.53e-01 -2.43e-01 -2.41e-01 -2.42e-01 -2.39e-01 -2.23e-01 -2.12e-01 -7.28e-02 -2.10e-02 -5.00e-01 -3.50e-01 -3.91e-01 -2.55e-01 -2.81e-01 -3.18e-01 -2.54e-01 -2.37e-01 -1.86e-01 -1.97e-01 -1.81e-01 -1.50e-01 -9.74e-02 -3.76e-02 -1.86e-02 -2.17e-01 -1.42e-01 -1.63e-01 -8.18e-02 -9.18e-02 -1.14e-01 -8.12e-02 -7.94e-02 -6.97e-02 -6.23e-02 -6.28e-02 -4.48e-02 -3.69e-02 -1.59e-02 -7.16e-03 -1.71e-01 -1.76e-01 -1.78e-01 -1.74e-01 -1.77e-01 -1.76e-01 -1.81e-01 -1.77e-01 -1.69e-01 -1.76e-01 -1.83e-01 -1.84e-01 -2.71e-01 -3.99e-01 -1.54e-01 -1.79e-01 -1.79e-01 -1.80e-01 -1.75e-01 -1.76e-01 -1.71e-01 -1.74e-01 -1.74e-01 -1.72e-01 -1.73e-01 -1.77e-01 -1.85e-01 -2.54e-01 -3.67e-01 -1.34e-01 -1.80e-01 -1.76e-01 -1.74e-01 -1.77e-01 -1.76e-01 -1.77e-01 -1.74e-01 -1.78e-01 -1.72e-01 -1.80e-01 -1.81e-01 -1.81e-01 -2.66e-01 -3.32e-01 -1.15e-01 -1.82e-01 -1.86e-01 -1.81e-01 -1.83e-01 -1.74e-01 -1.67e-01 -1.72e-01 -1.75e-01 -1.70e-01 -1.69e-01 -1.75e-01 -1.84e-01 -2.58e-01 -3.55e-01 -1.26e-01 -1.80e-01 -1.82e-01 -1.79e-01 -1.73e-01 -1.66e-01 -1.70e-01 -1.77e-01 -1.69e-01 -1.68e-01 -1.69e-01 -1.78e-01 -1.83e-01 -2.75e-01 -3.02e-01 -1.32e-01 -1.75e-01 -1.78e-01 -1.77e-01 -1.69e-01 -1.79e-01 -1.69e-01 -1.65e-01 -1.63e-01 -1.63e-01 -1.67e-01 -1.74e-01 -1.87e-01 -2.69e-01 -3.43e-01 -1.20e-01 -1.80e-01 -1.82e-01 -1.68e-01 -1.67e-01 -1.77e-01 -1.70e-01 -1.59e-01 -1.60e-01 -1.58e-01 -1.61e-01 -1.65e-01 -1.67e-01 -2.34e-01 -2.93e-01 -1.13e-01 -1.71e-01 -1.72e-01 -1.65e-01 -1.65e-01 -1.65e-01 -1.60e-01 -1.57e-01 -1.46e-01 -1.43e-01 -1.50e-01 -1.48e-01 -1.06e-01 -1.93e-01 -1.68e-01 -7.02e-02 -1.69e-01 -1.86e-01 -1.75e-01 -1.74e-01 -1.77e-01 -1.65e-01 -1.61e-01 -1.54e-01 -1.53e-01 -1.55e-01 -1.47e-01 -1.41e-01 -1.98e-01 -1.23e-01 -3.84e-02 -1.78e-01 -1.86e-01 -1.76e-01 -1.77e-01 -1.65e-01 -1.75e-01 -1.66e-01 -1.54e-01 -1.59e-01 -1.54e-01 -1.63e-01 -1.52e-01 -2.17e-01 -1.45e-01 -4.33e-02 -1.80e-01 -1.87e-01 -1.79e-01 -1.73e-01 -1.81e-01 -1.76e-01 -1.67e-01 -1.60e-01 -1.63e-01 -1.60e-01 -1.69e-01 -1.55e-01 -2.16e-01 -1.34e-01 -4.11e-02 -1.88e-01 -1.80e-01 -1.84e-01 -1.81e-01 -1.84e-01 -1.87e-01 -1.74e-01 -1.69e-01 -1.66e-01 -1.73e-01 -1.70e-01 -1.62e-01 -2.01e-01 -8.29e-02 -2.86e-02 -2.58e-01 -2.81e-01 -2.59e-01 -2.69e-01 -2.95e-01 -2.69e-01 -2.46e-01 -2.56e-01 -2.33e-01 -2.31e-01 -2.59e-01 -2.41e-01 -2.08e-01 -5.36e-02 -1.40e-02 -3.12e-01 -2.97e-01 -2.71e-01 -3.04e-01 -3.70e-01 -3.54e-01 -2.77e-01 -2.79e-01 -2.19e-01 -1.62e-01 -1.62e-01 -1.63e-01 -1.08e-01 -3.47e-02 -1.48e-02 -1.09e-01 -1.08e-01 -1.05e-01 -1.01e-01 -1.35e-01 -1.42e-01 -9.52e-02 -9.99e-02 -9.32e-02 -5.18e-02 -5.18e-02 -5.34e-02 -4.23e-02 -1.87e-02 -7.19e-03 -1.80e-01 -1.75e-01 -1.82e-01 -1.75e-01 -1.71e-01 -1.70e-01 -1.69e-01 -1.65e-01 -1.75e-01 -1.71e-01 -1.68e-01 -1.86e-01 -3.12e-01 -4.27e-01 -1.66e-01 -1.81e-01 -1.77e-01 -1.70e-01 -1.73e-01 -1.73e-01 -1.72e-01 -1.64e-01 -1.66e-01 -1.66e-01 -1.73e-01 -1.70e-01 -1.89e-01 -2.63e-01 -4.02e-01 -1.64e-01 -1.79e-01 -1.80e-01 -1.83e-01 -1.71e-01 -1.73e-01 -1.71e-01 -1.70e-01 -1.75e-01 -1.69e-01 -1.68e-01 -1.68e-01 -1.80e-01 -2.49e-01 -3.42e-01 -1.29e-01 -1.63e-01 -1.73e-01 -1.74e-01 -1.71e-01 -1.68e-01 -1.65e-01 -1.68e-01 -1.73e-01 -1.72e-01 -1.65e-01 -1.72e-01 -1.69e-01 -2.52e-01 -3.19e-01 -1.06e-01 -1.67e-01 -1.70e-01 -1.72e-01 -1.64e-01 -1.71e-01 -1.71e-01 -1.57e-01 -1.64e-01 -1.61e-01 -1.62e-01 -1.73e-01 -1.79e-01 -2.63e-01 -2.66e-01 -7.74e-02 -1.68e-01 -1.72e-01 -1.64e-01 -1.66e-01 -1.65e-01 -1.66e-01 -1.58e-01 -1.59e-01 -1.63e-01 -1.63e-01 -1.70e-01 -1.75e-01 -2.51e-01 -3.47e-01 -1.31e-01 -1.72e-01 -1.79e-01 -1.70e-01 -1.70e-01 -1.69e-01 -1.71e-01 -1.70e-01 -1.55e-01 -1.59e-01 -1.65e-01 -1.70e-01 -1.71e-01 -2.43e-01 -2.46e-01 -9.20e-02 -1.70e-01 -1.70e-01 -1.66e-01 -1.63e-01 -1.66e-01 -1.63e-01 -1.59e-01 -1.58e-01 -1.57e-01 -1.60e-01 -1.55e-01 -1.53e-01 -2.20e-01 -1.63e-01 -6.37e-02 -1.70e-01 -1.70e-01 -1.73e-01 -1.69e-01 -1.66e-01 -1.64e-01 -1.63e-01 -1.64e-01 -1.52e-01 -1.54e-01 -1.53e-01 -1.49e-01 -2.12e-01 -1.64e-01 -6.14e-02 -1.74e-01 -1.78e-01 -1.73e-01 -1.75e-01 -1.74e-01 -1.65e-01 -1.67e-01 -1.59e-01 -1.48e-01 -1.57e-01 -1.55e-01 -1.59e-01 -2.06e-01 -1.23e-01 -4.80e-02 -1.69e-01 -1.78e-01 -1.77e-01 -1.74e-01 -1.77e-01 -1.73e-01 -1.74e-01 -1.68e-01 -1.52e-01 -1.58e-01 -1.58e-01 -1.55e-01 -2.12e-01 -1.22e-01 -3.34e-02 -1.75e-01 -1.85e-01 -1.86e-01 -1.90e-01 -1.80e-01 -1.79e-01 -1.76e-01 -1.71e-01 -1.67e-01 -1.71e-01 -1.69e-01 -1.69e-01 -1.86e-01 -1.02e-01 -3.54e-02 -2.66e-01 -2.66e-01 -2.64e-01 -2.50e-01 -2.60e-01 -2.58e-01 -2.34e-01 -2.42e-01 -2.35e-01 -2.29e-01 -2.33e-01 -2.42e-01 -2.28e-01 -5.44e-02 -1.71e-02 -3.77e-01 -2.75e-01 -3.41e-01 -3.51e-01 -3.64e-01 -2.31e-01 -2.32e-01 -2.18e-01 -1.82e-01 -1.77e-01 -1.28e-01 -1.16e-01 -1.03e-01 -4.16e-02 -1.06e-02 -1.33e-01 -8.71e-02 -1.41e-01 -1.34e-01 -1.37e-01 -8.83e-02 -7.82e-02 -8.36e-02 -5.61e-02 -6.39e-02 -2.90e-02 -3.69e-02 -3.46e-02 -2.60e-02 -1.24e-02 -1.77e-01 -1.71e-01 -1.75e-01 -1.79e-01 -1.73e-01 -1.71e-01 -1.64e-01 -1.66e-01 -1.59e-01 -1.61e-01 -1.55e-01 -1.79e-01 -2.67e-01 -4.26e-01 -1.56e-01 -1.75e-01 -1.82e-01 -1.71e-01 -1.65e-01 -1.69e-01 -1.66e-01 -1.69e-01 -1.63e-01 -1.65e-01 -1.74e-01 -1.69e-01 -1.76e-01 -2.47e-01 -3.31e-01 -1.30e-01 -1.69e-01 -1.73e-01 -1.77e-01 -1.67e-01 -1.55e-01 -1.67e-01 -1.59e-01 -1.63e-01 -1.58e-01 -1.70e-01 -1.69e-01 -1.84e-01 -2.44e-01 -2.71e-01 -1.02e-01 -1.69e-01 -1.70e-01 -1.73e-01 -1.69e-01 -1.66e-01 -1.67e-01 -1.64e-01 -1.60e-01 -1.62e-01 -1.63e-01 -1.63e-01 -1.67e-01 -2.48e-01 -2.40e-01 -9.84e-02 -1.62e-01 -1.64e-01 -1.69e-01 -1.71e-01 -1.62e-01 -1.58e-01 -1.62e-01 -1.58e-01 -1.62e-01 -1.61e-01 -1.71e-01 -1.67e-01 -2.50e-01 -3.22e-01 -1.17e-01 -1.74e-01 -1.60e-01 -1.69e-01 -1.72e-01 -1.67e-01 -1.60e-01 -1.65e-01 -1.68e-01 -1.62e-01 -1.60e-01 -1.63e-01 -1.76e-01 -2.53e-01 -2.99e-01 -1.10e-01 -1.69e-01 -1.67e-01 -1.76e-01 -1.64e-01 -1.59e-01 -1.58e-01 -1.64e-01 -1.59e-01 -1.55e-01 -1.59e-01 -1.51e-01 -1.60e-01 -2.50e-01 -2.88e-01 -1.01e-01 -1.72e-01 -1.71e-01 -1.68e-01 -1.63e-01 -1.59e-01 -1.61e-01 -1.66e-01 -1.56e-01 -1.54e-01 -1.51e-01 -1.49e-01 -1.58e-01 -2.33e-01 -1.85e-01 -6.62e-02 -1.69e-01 -1.65e-01 -1.63e-01 -1.67e-01 -1.62e-01 -1.63e-01 -1.63e-01 -1.61e-01 -1.55e-01 -1.53e-01 -1.59e-01 -1.69e-01 -2.48e-01 -1.87e-01 -5.29e-02 -1.71e-01 -1.66e-01 -1.73e-01 -1.68e-01 -1.65e-01 -1.64e-01 -1.59e-01 -1.52e-01 -1.60e-01 -1.52e-01 -1.48e-01 -1.54e-01 -2.32e-01 -1.35e-01 -5.41e-02 -1.76e-01 -1.78e-01 -1.68e-01 -1.79e-01 -1.73e-01 -1.69e-01 -1.62e-01 -1.61e-01 -1.59e-01 -1.61e-01 -1.58e-01 -1.60e-01 -2.06e-01 -9.41e-02 -2.78e-02 -1.88e-01 -1.77e-01 -1.78e-01 -1.76e-01 -1.82e-01 -1.90e-01 -1.76e-01 -1.62e-01 -1.69e-01 -1.69e-01 -1.69e-01 -1.68e-01 -1.97e-01 -7.83e-02 -2.27e-02 -2.47e-01 -2.50e-01 -2.59e-01 -2.51e-01 -2.57e-01 -2.55e-01 -2.15e-01 -2.28e-01 -2.42e-01 -2.25e-01 -2.12e-01 -2.14e-01 -2.28e-01 -7.82e-02 -2.46e-02 -3.10e-01 -2.49e-01 -2.07e-01 -2.92e-01 -2.88e-01 -2.33e-01 -1.62e-01 -1.13e-01 -1.90e-01 -1.80e-01 -1.16e-01 -1.07e-01 -9.41e-02 -4.21e-02 -1.63e-02 -1.17e-01 -8.58e-02 -8.78e-02 -9.13e-02 -1.15e-01 -8.57e-02 -6.78e-02 -3.63e-02 -6.34e-02 -6.38e-02 -4.06e-02 -3.60e-02 -2.77e-02 -2.56e-02 -1.21e-02 -1.71e-01 -1.68e-01 -1.63e-01 -1.68e-01 -1.72e-01 -1.66e-01 -1.65e-01 -1.51e-01 -1.57e-01 -1.63e-01 -1.57e-01 -1.78e-01 -2.58e-01 -3.15e-01 -1.24e-01 -1.72e-01 -1.71e-01 -1.66e-01 -1.69e-01 -1.71e-01 -1.63e-01 -1.58e-01 -1.51e-01 -1.62e-01 -1.68e-01 -1.67e-01 -1.76e-01 -2.54e-01 -3.04e-01 -1.12e-01 -1.75e-01 -1.72e-01 -1.70e-01 -1.68e-01 -1.63e-01 -1.64e-01 -1.63e-01 -1.54e-01 -1.65e-01 -1.69e-01 -1.68e-01 -1.76e-01 -2.52e-01 -2.21e-01 -8.02e-02 -1.68e-01 -1.71e-01 -1.65e-01 -1.66e-01 -1.63e-01 -1.64e-01 -1.61e-01 -1.62e-01 -1.61e-01 -1.66e-01 -1.64e-01 -1.72e-01 -2.60e-01 -2.09e-01 -7.14e-02 -1.63e-01 -1.61e-01 -1.63e-01 -1.69e-01 -1.61e-01 -1.62e-01 -1.62e-01 -1.61e-01 -1.58e-01 -1.54e-01 -1.64e-01 -1.76e-01 -2.59e-01 -3.27e-01 -1.16e-01 -1.60e-01 -1.60e-01 -1.63e-01 -1.68e-01 -1.62e-01 -1.54e-01 -1.50e-01 -1.64e-01 -1.63e-01 -1.58e-01 -1.58e-01 -1.68e-01 -2.43e-01 -2.59e-01 -9.33e-02 -1.61e-01 -1.63e-01 -1.68e-01 -1.62e-01 -1.69e-01 -1.53e-01 -1.53e-01 -1.57e-01 -1.50e-01 -1.54e-01 -1.57e-01 -1.59e-01 -2.17e-01 -2.06e-01 -7.58e-02 -1.71e-01 -1.70e-01 -1.63e-01 -1.57e-01 -1.61e-01 -1.53e-01 -1.56e-01 -1.49e-01 -1.49e-01 -1.59e-01 -1.49e-01 -1.55e-01 -2.27e-01 -1.62e-01 -6.88e-02 -1.71e-01 -1.67e-01 -1.66e-01 -1.60e-01 -1.61e-01 -1.62e-01 -1.63e-01 -1.54e-01 -1.50e-01 -1.48e-01 -1.51e-01 -1.55e-01 -2.15e-01 -1.65e-01 -4.95e-02 -1.71e-01 -1.73e-01 -1.68e-01 -1.62e-01 -1.57e-01 -1.62e-01 -1.59e-01 -1.56e-01 -1.53e-01 -1.47e-01 -1.49e-01 -1.62e-01 -2.14e-01 -1.58e-01 -6.86e-02 -1.70e-01 -1.66e-01 -1.69e-01 -1.66e-01 -1.67e-01 -1.62e-01 -1.63e-01 -1.63e-01 -1.58e-01 -1.52e-01 -1.54e-01 -1.67e-01 -2.26e-01 -1.15e-01 -4.03e-02 -1.74e-01 -1.82e-01 -1.70e-01 -1.72e-01 -1.77e-01 -1.85e-01 -1.68e-01 -1.65e-01 -1.63e-01 -1.74e-01 -1.63e-01 -1.66e-01 -2.29e-01 -1.07e-01 -3.27e-02 -2.58e-01 -2.47e-01 -2.50e-01 -2.57e-01 -2.60e-01 -2.66e-01 -2.59e-01 -2.39e-01 -2.35e-01 -2.29e-01 -2.16e-01 -2.25e-01 -2.33e-01 -8.96e-02 -3.01e-02 -2.73e-01 -2.51e-01 -2.52e-01 -2.63e-01 -3.05e-01 -2.69e-01 -2.91e-01 -1.85e-01 -2.00e-01 -1.47e-01 -1.01e-01 -1.17e-01 -8.80e-02 -3.85e-02 -1.53e-02 -1.00e-01 -8.71e-02 -9.09e-02 -9.00e-02 -1.08e-01 -8.70e-02 -1.17e-01 -5.47e-02 -7.04e-02 -5.07e-02 -3.08e-02 -3.14e-02 -2.64e-02 -1.69e-02 -1.16e-02 -1.60e-01 -1.64e-01 -1.63e-01 -1.67e-01 -1.70e-01 -1.62e-01 -1.54e-01 -1.52e-01 -1.52e-01 -1.55e-01 -1.57e-01 -1.63e-01 -2.61e-01 -2.58e-01 -7.58e-02 -1.59e-01 -1.68e-01 -1.63e-01 -1.58e-01 -1.65e-01 -1.65e-01 -1.67e-01 -1.52e-01 -1.58e-01 -1.56e-01 -1.60e-01 -1.69e-01 -2.49e-01 -2.88e-01 -1.11e-01 -1.66e-01 -1.69e-01 -1.70e-01 -1.63e-01 -1.63e-01 -1.59e-01 -1.63e-01 -1.65e-01 -1.58e-01 -1.58e-01 -1.60e-01 -1.75e-01 -2.57e-01 -2.53e-01 -8.19e-02 -1.67e-01 -1.68e-01 -1.58e-01 -1.58e-01 -1.61e-01 -1.67e-01 -1.54e-01 -1.55e-01 -1.61e-01 -1.61e-01 -1.63e-01 -1.70e-01 -2.53e-01 -2.35e-01 -7.59e-02 -1.63e-01 -1.66e-01 -1.68e-01 -1.64e-01 -1.59e-01 -1.59e-01 -1.57e-01 -1.58e-01 -1.58e-01 -1.56e-01 -1.58e-01 -1.66e-01 -2.50e-01 -2.58e-01 -9.81e-02 -1.60e-01 -1.61e-01 -1.64e-01 -1.61e-01 -1.60e-01 -1.56e-01 -1.51e-01 -1.50e-01 -1.63e-01 -1.64e-01 -1.57e-01 -1.64e-01 -2.37e-01 -2.18e-01 -9.03e-02 -1.68e-01 -1.69e-01 -1.64e-01 -1.56e-01 -1.58e-01 -1.53e-01 -1.51e-01 -1.43e-01 -1.51e-01 -1.53e-01 -1.55e-01 -1.63e-01 -2.19e-01 -1.33e-01 -4.89e-02 -1.67e-01 -1.60e-01 -1.61e-01 -1.55e-01 -1.64e-01 -1.56e-01 -1.49e-01 -1.45e-01 -1.44e-01 -1.51e-01 -1.57e-01 -1.64e-01 -2.32e-01 -1.18e-01 -3.65e-02 -1.62e-01 -1.67e-01 -1.68e-01 -1.55e-01 -1.59e-01 -1.57e-01 -1.58e-01 -1.46e-01 -1.43e-01 -1.39e-01 -1.48e-01 -1.54e-01 -2.26e-01 -1.45e-01 -4.05e-02 -1.55e-01 -1.63e-01 -1.63e-01 -1.67e-01 -1.56e-01 -1.53e-01 -1.50e-01 -1.49e-01 -1.49e-01 -1.45e-01 -1.47e-01 -1.53e-01 -2.10e-01 -1.20e-01 -3.82e-02 -1.65e-01 -1.59e-01 -1.61e-01 -1.61e-01 -1.56e-01 -1.56e-01 -1.60e-01 -1.59e-01 -1.54e-01 -1.53e-01 -1.48e-01 -1.52e-01 -2.07e-01 -1.01e-01 -3.00e-02 -1.77e-01 -1.71e-01 -1.68e-01 -1.71e-01 -1.75e-01 -1.69e-01 -1.64e-01 -1.68e-01 -1.61e-01 -1.61e-01 -1.53e-01 -1.46e-01 -1.95e-01 -9.40e-02 -2.21e-02 -2.46e-01 -2.38e-01 -2.31e-01 -2.41e-01 -2.54e-01 -2.50e-01 -2.28e-01 -2.20e-01 -2.21e-01 -2.26e-01 -2.35e-01 -2.02e-01 -1.88e-01 -9.58e-02 -3.52e-02 -3.06e-01 -2.59e-01 -2.23e-01 -2.61e-01 -2.57e-01 -2.36e-01 -2.32e-01 -1.78e-01 -1.53e-01 -1.37e-01 -1.47e-01 -1.36e-01 -7.24e-02 -4.03e-02 -2.23e-02 -1.04e-01 -9.82e-02 -8.79e-02 -9.20e-02 -9.75e-02 -7.29e-02 -1.04e-01 -6.06e-02 -5.37e-02 -3.67e-02 -4.29e-02 -4.85e-02 -2.87e-02 -1.59e-02 -9.17e-03 -1.71e-01 -1.67e-01 -1.65e-01 -1.69e-01 -1.59e-01 -1.60e-01 -1.62e-01 -1.62e-01 -1.57e-01 -1.49e-01 -1.52e-01 -1.53e-01 -2.42e-01 -1.80e-01 -8.19e-02 -1.68e-01 -1.63e-01 -1.67e-01 -1.65e-01 -1.63e-01 -1.54e-01 -1.59e-01 -1.52e-01 -1.59e-01 -1.52e-01 -1.48e-01 -1.55e-01 -2.25e-01 -2.01e-01 -7.57e-02 -1.63e-01 -1.59e-01 -1.62e-01 -1.61e-01 -1.57e-01 -1.56e-01 -1.50e-01 -1.51e-01 -1.48e-01 -1.53e-01 -1.61e-01 -1.58e-01 -2.32e-01 -2.49e-01 -1.01e-01 -1.67e-01 -1.54e-01 -1.55e-01 -1.52e-01 -1.55e-01 -1.61e-01 -1.57e-01 -1.54e-01 -1.54e-01 -1.54e-01 -1.56e-01 -1.64e-01 -2.25e-01 -1.56e-01 -6.14e-02 -1.67e-01 -1.65e-01 -1.61e-01 -1.57e-01 -1.58e-01 -1.62e-01 -1.55e-01 -1.57e-01 -1.50e-01 -1.54e-01 -1.55e-01 -1.68e-01 -2.32e-01 -1.28e-01 -4.68e-02 -1.63e-01 -1.57e-01 -1.60e-01 -1.63e-01 -1.61e-01 -1.58e-01 -1.50e-01 -1.46e-01 -1.43e-01 -1.52e-01 -1.55e-01 -1.61e-01 -2.25e-01 -1.35e-01 -4.13e-02 -1.64e-01 -1.62e-01 -1.60e-01 -1.62e-01 -1.61e-01 -1.51e-01 -1.50e-01 -1.41e-01 -1.46e-01 -1.49e-01 -1.51e-01 -1.64e-01 -2.31e-01 -1.50e-01 -4.56e-02 -1.53e-01 -1.55e-01 -1.54e-01 -1.57e-01 -1.55e-01 -1.49e-01 -1.50e-01 -1.44e-01 -1.43e-01 -1.47e-01 -1.51e-01 -1.57e-01 -2.19e-01 -1.63e-01 -4.89e-02 -1.64e-01 -1.55e-01 -1.57e-01 -1.53e-01 -1.48e-01 -1.53e-01 -1.52e-01 -1.40e-01 -1.38e-01 -1.40e-01 -1.50e-01 -1.57e-01 -2.10e-01 -1.54e-01 -5.14e-02 -1.56e-01 -1.58e-01 -1.61e-01 -1.57e-01 -1.52e-01 -1.47e-01 -1.51e-01 -1.48e-01 -1.44e-01 -1.48e-01 -1.44e-01 -1.43e-01 -2.07e-01 -1.20e-01 -4.74e-02 -1.62e-01 -1.71e-01 -1.62e-01 -1.57e-01 -1.52e-01 -1.51e-01 -1.44e-01 -1.43e-01 -1.46e-01 -1.46e-01 -1.36e-01 -1.45e-01 -1.86e-01 -7.07e-02 -2.51e-02 -1.70e-01 -1.71e-01 -1.63e-01 -1.56e-01 -1.60e-01 -1.61e-01 -1.56e-01 -1.55e-01 -1.59e-01 -1.53e-01 -1.48e-01 -1.41e-01 -1.55e-01 -6.13e-02 -2.68e-02 -2.40e-01 -2.25e-01 -2.22e-01 -2.27e-01 -2.31e-01 -2.20e-01 -2.21e-01 -1.99e-01 -2.15e-01 -1.98e-01 -2.02e-01 -1.80e-01 -1.35e-01 -3.74e-02 -1.62e-02 -2.64e-01 -2.69e-01 -2.32e-01 -1.55e-01 -1.50e-01 -1.99e-01 -1.79e-01 -1.44e-01 -1.30e-01 -1.25e-01 -1.44e-01 -1.15e-01 -4.22e-02 -1.96e-02 -8.51e-03 -9.50e-02 -1.04e-01 -8.97e-02 -4.80e-02 -4.87e-02 -6.43e-02 -6.38e-02 -4.70e-02 -4.40e-02 -3.28e-02 -4.72e-02 -4.03e-02 -1.52e-02 -8.66e-03 -6.14e-03 -1.56e-01 -1.57e-01 -1.54e-01 -1.60e-01 -1.65e-01 -1.66e-01 -1.65e-01 -1.58e-01 -1.47e-01 -1.40e-01 -1.36e-01 -1.59e-01 -2.22e-01 -1.52e-01 -5.31e-02 -1.61e-01 -1.62e-01 -1.69e-01 -1.63e-01 -1.58e-01 -1.58e-01 -1.59e-01 -1.47e-01 -1.45e-01 -1.39e-01 -1.30e-01 -1.48e-01 -2.15e-01 -1.09e-01 -3.46e-02 -1.58e-01 -1.57e-01 -1.62e-01 -1.63e-01 -1.59e-01 -1.57e-01 -1.56e-01 -1.58e-01 -1.52e-01 -1.45e-01 -1.50e-01 -1.60e-01 -2.17e-01 -1.56e-01 -5.66e-02 -1.60e-01 -1.57e-01 -1.60e-01 -1.57e-01 -1.60e-01 -1.58e-01 -1.54e-01 -1.53e-01 -1.47e-01 -1.42e-01 -1.56e-01 -1.66e-01 -2.10e-01 -1.46e-01 -6.02e-02 -1.62e-01 -1.61e-01 -1.68e-01 -1.54e-01 -1.54e-01 -1.59e-01 -1.50e-01 -1.49e-01 -1.50e-01 -1.46e-01 -1.58e-01 -1.59e-01 -2.16e-01 -1.18e-01 -3.24e-02 -1.61e-01 -1.55e-01 -1.60e-01 -1.59e-01 -1.50e-01 -1.45e-01 -1.50e-01 -1.45e-01 -1.47e-01 -1.46e-01 -1.48e-01 -1.58e-01 -2.13e-01 -1.24e-01 -4.33e-02 -1.58e-01 -1.55e-01 -1.58e-01 -1.51e-01 -1.57e-01 -1.54e-01 -1.50e-01 -1.39e-01 -1.40e-01 -1.40e-01 -1.39e-01 -1.49e-01 -2.03e-01 -1.50e-01 -5.78e-02 -1.51e-01 -1.59e-01 -1.53e-01 -1.53e-01 -1.52e-01 -1.52e-01 -1.46e-01 -1.43e-01 -1.42e-01 -1.41e-01 -1.52e-01 -1.52e-01 -2.06e-01 -1.37e-01 -5.13e-02 -1.55e-01 -1.52e-01 -1.56e-01 -1.49e-01 -1.53e-01 -1.49e-01 -1.45e-01 -1.39e-01 -1.35e-01 -1.33e-01 -1.48e-01 -1.46e-01 -1.98e-01 -1.08e-01 -3.36e-02 -1.53e-01 -1.53e-01 -1.49e-01 -1.43e-01 -1.45e-01 -1.48e-01 -1.38e-01 -1.42e-01 -1.29e-01 -1.29e-01 -1.38e-01 -1.45e-01 -2.11e-01 -1.20e-01 -3.89e-02 -1.60e-01 -1.55e-01 -1.59e-01 -1.49e-01 -1.48e-01 -1.48e-01 -1.47e-01 -1.50e-01 -1.41e-01 -1.37e-01 -1.31e-01 -1.36e-01 -1.77e-01 -7.63e-02 -1.94e-02 -1.69e-01 -1.64e-01 -1.65e-01 -1.57e-01 -1.52e-01 -1.48e-01 -1.44e-01 -1.54e-01 -1.48e-01 -1.49e-01 -1.40e-01 -1.31e-01 -1.53e-01 -4.85e-02 -1.42e-02 -2.42e-01 -2.23e-01 -2.24e-01 -2.03e-01 -2.18e-01 -2.15e-01 -1.75e-01 -1.74e-01 -1.73e-01 -2.02e-01 -2.01e-01 -1.69e-01 -1.22e-01 -3.16e-02 -1.08e-02 -2.16e-01 -2.25e-01 -1.60e-01 -1.34e-01 -1.44e-01 -1.68e-01 -1.02e-01 -8.69e-02 -7.20e-02 -1.43e-01 -1.29e-01 -8.21e-02 -4.29e-02 -1.08e-02 -4.27e-03 -7.45e-02 -7.65e-02 -5.07e-02 -4.76e-02 -4.31e-02 -5.72e-02 -3.77e-02 -2.92e-02 -2.28e-02 -4.79e-02 -4.01e-02 -2.76e-02 -1.93e-02 -8.26e-03 -2.13e-03 -1.63e-01 -1.66e-01 -1.71e-01 -1.63e-01 -1.67e-01 -1.59e-01 -1.56e-01 -1.61e-01 -1.49e-01 -1.45e-01 -1.38e-01 -1.54e-01 -2.17e-01 -1.17e-01 -3.57e-02 -1.59e-01 -1.61e-01 -1.68e-01 -1.63e-01 -1.62e-01 -1.62e-01 -1.60e-01 -1.56e-01 -1.49e-01 -1.47e-01 -1.44e-01 -1.52e-01 -2.09e-01 -1.26e-01 -3.94e-02 -1.57e-01 -1.61e-01 -1.58e-01 -1.59e-01 -1.60e-01 -1.51e-01 -1.56e-01 -1.60e-01 -1.49e-01 -1.45e-01 -1.44e-01 -1.61e-01 -2.41e-01 -1.63e-01 -5.31e-02 -1.60e-01 -1.54e-01 -1.60e-01 -1.53e-01 -1.56e-01 -1.57e-01 -1.55e-01 -1.53e-01 -1.46e-01 -1.47e-01 -1.49e-01 -1.47e-01 -2.08e-01 -1.76e-01 -7.44e-02 -1.55e-01 -1.52e-01 -1.53e-01 -1.52e-01 -1.52e-01 -1.51e-01 -1.51e-01 -1.53e-01 -1.48e-01 -1.40e-01 -1.50e-01 -1.61e-01 -2.05e-01 -1.29e-01 -4.01e-02 -1.60e-01 -1.58e-01 -1.50e-01 -1.47e-01 -1.42e-01 -1.46e-01 -1.50e-01 -1.46e-01 -1.45e-01 -1.42e-01 -1.48e-01 -1.60e-01 -2.17e-01 -1.50e-01 -5.21e-02 -1.53e-01 -1.53e-01 -1.52e-01 -1.45e-01 -1.45e-01 -1.43e-01 -1.40e-01 -1.38e-01 -1.37e-01 -1.36e-01 -1.46e-01 -1.49e-01 -1.88e-01 -1.14e-01 -4.21e-02 -1.48e-01 -1.50e-01 -1.52e-01 -1.43e-01 -1.48e-01 -1.44e-01 -1.36e-01 -1.34e-01 -1.37e-01 -1.37e-01 -1.46e-01 -1.47e-01 -1.84e-01 -7.19e-02 -2.90e-02 -1.48e-01 -1.44e-01 -1.48e-01 -1.48e-01 -1.49e-01 -1.54e-01 -1.45e-01 -1.38e-01 -1.29e-01 -1.30e-01 -1.31e-01 -1.39e-01 -1.93e-01 -7.96e-02 -2.03e-02 -1.53e-01 -1.46e-01 -1.46e-01 -1.41e-01 -1.47e-01 -1.45e-01 -1.42e-01 -1.37e-01 -1.29e-01 -1.27e-01 -1.30e-01 -1.33e-01 -1.95e-01 -8.81e-02 -2.19e-02 -1.56e-01 -1.42e-01 -1.45e-01 -1.43e-01 -1.52e-01 -1.48e-01 -1.44e-01 -1.40e-01 -1.41e-01 -1.31e-01 -1.18e-01 -1.31e-01 -1.83e-01 -9.55e-02 -2.75e-02 -1.63e-01 -1.47e-01 -1.48e-01 -1.57e-01 -1.55e-01 -1.50e-01 -1.56e-01 -1.42e-01 -1.44e-01 -1.39e-01 -1.29e-01 -1.20e-01 -1.52e-01 -5.41e-02 -1.62e-02 -2.32e-01 -2.08e-01 -2.20e-01 -2.22e-01 -2.23e-01 -2.17e-01 -1.99e-01 -2.05e-01 -1.92e-01 -2.03e-01 -1.97e-01 -1.60e-01 -1.37e-01 -4.00e-02 -1.07e-02 -2.25e-01 -1.79e-01 -1.71e-01 -1.67e-01 -1.69e-01 -1.54e-01 -1.02e-01 -1.09e-01 -9.88e-02 -1.08e-01 -1.18e-01 -8.29e-02 -4.15e-02 -1.49e-02 -5.20e-03 -6.83e-02 -5.09e-02 -4.28e-02 -4.83e-02 -4.92e-02 -5.19e-02 -3.56e-02 -3.22e-02 -2.88e-02 -3.04e-02 -3.83e-02 -2.79e-02 -1.21e-02 -5.81e-03 -1.30e-03 -1.57e-01 -1.62e-01 -1.67e-01 -1.62e-01 -1.61e-01 -1.50e-01 -1.52e-01 -1.57e-01 -1.53e-01 -1.51e-01 -1.43e-01 -1.61e-01 -2.04e-01 -1.43e-01 -5.22e-02 -1.59e-01 -1.63e-01 -1.58e-01 -1.58e-01 -1.58e-01 -1.62e-01 -1.60e-01 -1.58e-01 -1.58e-01 -1.43e-01 -1.49e-01 -1.59e-01 -2.21e-01 -1.56e-01 -4.57e-02 -1.63e-01 -1.57e-01 -1.51e-01 -1.54e-01 -1.53e-01 -1.60e-01 -1.55e-01 -1.60e-01 -1.60e-01 -1.45e-01 -1.40e-01 -1.59e-01 -2.23e-01 -1.66e-01 -5.44e-02 -1.53e-01 -1.54e-01 -1.54e-01 -1.50e-01 -1.57e-01 -1.53e-01 -1.59e-01 -1.56e-01 -1.48e-01 -1.45e-01 -1.45e-01 -1.58e-01 -2.07e-01 -1.44e-01 -5.45e-02 -1.50e-01 -1.46e-01 -1.56e-01 -1.56e-01 -1.54e-01 -1.48e-01 -1.50e-01 -1.54e-01 -1.46e-01 -1.46e-01 -1.50e-01 -1.52e-01 -2.09e-01 -1.16e-01 -3.68e-02 -1.56e-01 -1.50e-01 -1.56e-01 -1.48e-01 -1.50e-01 -1.51e-01 -1.48e-01 -1.49e-01 -1.43e-01 -1.41e-01 -1.46e-01 -1.53e-01 -2.02e-01 -1.07e-01 -3.92e-02 -1.55e-01 -1.55e-01 -1.53e-01 -1.49e-01 -1.47e-01 -1.48e-01 -1.41e-01 -1.44e-01 -1.41e-01 -1.41e-01 -1.37e-01 -1.51e-01 -2.06e-01 -1.37e-01 -4.68e-02 -1.52e-01 -1.53e-01 -1.54e-01 -1.53e-01 -1.48e-01 -1.43e-01 -1.32e-01 -1.41e-01 -1.35e-01 -1.27e-01 -1.35e-01 -1.52e-01 -1.90e-01 -7.26e-02 -2.22e-02 -1.47e-01 -1.47e-01 -1.49e-01 -1.50e-01 -1.49e-01 -1.42e-01 -1.39e-01 -1.32e-01 -1.28e-01 -1.26e-01 -1.34e-01 -1.45e-01 -1.87e-01 -8.17e-02 -2.42e-02 -1.49e-01 -1.48e-01 -1.47e-01 -1.50e-01 -1.45e-01 -1.43e-01 -1.38e-01 -1.30e-01 -1.29e-01 -1.31e-01 -1.22e-01 -1.36e-01 -1.78e-01 -1.04e-01 -3.33e-02 -1.48e-01 -1.45e-01 -1.44e-01 -1.42e-01 -1.41e-01 -1.43e-01 -1.46e-01 -1.38e-01 -1.29e-01 -1.25e-01 -1.18e-01 -1.25e-01 -1.79e-01 -8.54e-02 -2.89e-02 -1.64e-01 -1.47e-01 -1.55e-01 -1.56e-01 -1.47e-01 -1.59e-01 -1.48e-01 -1.44e-01 -1.36e-01 -1.33e-01 -1.26e-01 -1.11e-01 -1.31e-01 -5.72e-02 -1.80e-02 -2.46e-01 -2.05e-01 -1.90e-01 -2.18e-01 -2.16e-01 -2.14e-01 -2.02e-01 -2.24e-01 -2.13e-01 -2.23e-01 -1.86e-01 -1.51e-01 -1.18e-01 -3.41e-02 -1.21e-02 -1.87e-01 -1.53e-01 -1.50e-01 -1.67e-01 -1.83e-01 -1.69e-01 -1.39e-01 -1.42e-01 -1.29e-01 -1.05e-01 -9.27e-02 -6.73e-02 -3.93e-02 -1.65e-02 -7.05e-03 -7.21e-02 -6.08e-02 -6.40e-02 -5.53e-02 -6.28e-02 -5.59e-02 -4.39e-02 -4.02e-02 -4.46e-02 -3.36e-02 -3.13e-02 -2.12e-02 -1.23e-02 -7.79e-03 -3.56e-03 -1.51e-01 -1.56e-01 -1.63e-01 -1.66e-01 -1.67e-01 -1.65e-01 -1.66e-01 -1.70e-01 -1.53e-01 -1.56e-01 -1.51e-01 -1.51e-01 -1.83e-01 -9.73e-02 -3.81e-02 -1.53e-01 -1.59e-01 -1.54e-01 -1.57e-01 -1.61e-01 -1.59e-01 -1.57e-01 -1.58e-01 -1.58e-01 -1.58e-01 -1.52e-01 -1.52e-01 -2.00e-01 -1.30e-01 -4.17e-02 -1.54e-01 -1.56e-01 -1.53e-01 -1.62e-01 -1.55e-01 -1.59e-01 -1.66e-01 -1.53e-01 -1.56e-01 -1.56e-01 -1.52e-01 -1.57e-01 -2.13e-01 -1.42e-01 -4.79e-02 -1.53e-01 -1.59e-01 -1.67e-01 -1.55e-01 -1.64e-01 -1.66e-01 -1.61e-01 -1.55e-01 -1.54e-01 -1.50e-01 -1.45e-01 -1.54e-01 -2.09e-01 -1.08e-01 -3.44e-02 -1.54e-01 -1.57e-01 -1.60e-01 -1.54e-01 -1.62e-01 -1.59e-01 -1.56e-01 -1.54e-01 -1.57e-01 -1.52e-01 -1.52e-01 -1.56e-01 -2.03e-01 -9.74e-02 -2.86e-02 -1.52e-01 -1.57e-01 -1.58e-01 -1.62e-01 -1.56e-01 -1.57e-01 -1.52e-01 -1.48e-01 -1.44e-01 -1.47e-01 -1.50e-01 -1.51e-01 -2.12e-01 -1.09e-01 -2.91e-02 -1.51e-01 -1.54e-01 -1.48e-01 -1.58e-01 -1.54e-01 -1.52e-01 -1.51e-01 -1.44e-01 -1.44e-01 -1.43e-01 -1.45e-01 -1.51e-01 -1.99e-01 -1.23e-01 -3.39e-02 -1.48e-01 -1.50e-01 -1.55e-01 -1.59e-01 -1.47e-01 -1.46e-01 -1.37e-01 -1.40e-01 -1.41e-01 -1.47e-01 -1.42e-01 -1.45e-01 -1.87e-01 -1.10e-01 -3.91e-02 -1.43e-01 -1.48e-01 -1.52e-01 -1.52e-01 -1.56e-01 -1.49e-01 -1.38e-01 -1.38e-01 -1.34e-01 -1.30e-01 -1.26e-01 -1.34e-01 -1.85e-01 -8.58e-02 -2.44e-02 -1.48e-01 -1.45e-01 -1.47e-01 -1.50e-01 -1.53e-01 -1.41e-01 -1.37e-01 -1.35e-01 -1.27e-01 -1.27e-01 -1.23e-01 -1.24e-01 -1.55e-01 -8.15e-02 -2.87e-02 -1.44e-01 -1.47e-01 -1.45e-01 -1.44e-01 -1.45e-01 -1.40e-01 -1.42e-01 -1.37e-01 -1.27e-01 -1.29e-01 -1.17e-01 -1.21e-01 -1.63e-01 -5.00e-02 -1.53e-02 -1.47e-01 -1.48e-01 -1.47e-01 -1.53e-01 -1.45e-01 -1.50e-01 -1.52e-01 -1.47e-01 -1.34e-01 -1.29e-01 -1.22e-01 -1.13e-01 -1.35e-01 -4.55e-02 -1.41e-02 -2.05e-01 -1.89e-01 -1.85e-01 -2.07e-01 -2.14e-01 -2.10e-01 -1.91e-01 -1.99e-01 -1.97e-01 -1.79e-01 -1.74e-01 -1.47e-01 -7.71e-02 -1.94e-02 -6.96e-03 -1.71e-01 -9.07e-02 -1.18e-01 -1.23e-01 -1.31e-01 -1.29e-01 -1.02e-01 -1.39e-01 -1.15e-01 -7.59e-02 -8.17e-02 -5.28e-02 -2.69e-02 -1.04e-02 -3.19e-03 -5.55e-02 -2.88e-02 -3.51e-02 -3.72e-02 -5.09e-02 -4.45e-02 -3.21e-02 -4.62e-02 -3.95e-02 -2.61e-02 -2.32e-02 -1.25e-02 -9.62e-03 -6.12e-03 -3.33e-03 -1.57e-01 -1.68e-01 -1.76e-01 -1.71e-01 -1.70e-01 -1.76e-01 -1.72e-01 -1.62e-01 -1.62e-01 -1.58e-01 -1.58e-01 -1.48e-01 -1.49e-01 -3.17e-02 -1.30e-02 -1.73e-01 -1.78e-01 -1.74e-01 -1.61e-01 -1.60e-01 -1.64e-01 -1.67e-01 -1.62e-01 -1.58e-01 -1.56e-01 -1.59e-01 -1.53e-01 -1.62e-01 -5.38e-02 -2.31e-02 -1.66e-01 -1.78e-01 -1.66e-01 -1.64e-01 -1.63e-01 -1.71e-01 -1.77e-01 -1.69e-01 -1.55e-01 -1.57e-01 -1.50e-01 -1.66e-01 -2.15e-01 -9.77e-02 -2.59e-02 -1.65e-01 -1.70e-01 -1.68e-01 -1.65e-01 -1.69e-01 -1.74e-01 -1.78e-01 -1.61e-01 -1.64e-01 -1.57e-01 -1.44e-01 -1.50e-01 -1.92e-01 -8.51e-02 -2.93e-02 -1.60e-01 -1.58e-01 -1.61e-01 -1.66e-01 -1.68e-01 -1.71e-01 -1.64e-01 -1.61e-01 -1.62e-01 -1.60e-01 -1.44e-01 -1.42e-01 -1.97e-01 -1.03e-01 -2.80e-02 -1.55e-01 -1.62e-01 -1.58e-01 -1.62e-01 -1.63e-01 -1.64e-01 -1.60e-01 -1.52e-01 -1.55e-01 -1.57e-01 -1.44e-01 -1.41e-01 -1.88e-01 -9.04e-02 -2.91e-02 -1.49e-01 -1.51e-01 -1.62e-01 -1.64e-01 -1.61e-01 -1.56e-01 -1.57e-01 -1.49e-01 -1.46e-01 -1.48e-01 -1.45e-01 -1.41e-01 -1.63e-01 -9.25e-02 -3.25e-02 -1.52e-01 -1.51e-01 -1.52e-01 -1.59e-01 -1.57e-01 -1.54e-01 -1.55e-01 -1.52e-01 -1.48e-01 -1.42e-01 -1.43e-01 -1.45e-01 -1.82e-01 -6.97e-02 -2.31e-02 -1.55e-01 -1.54e-01 -1.58e-01 -1.59e-01 -1.58e-01 -1.62e-01 -1.50e-01 -1.47e-01 -1.42e-01 -1.42e-01 -1.33e-01 -1.37e-01 -1.74e-01 -6.53e-02 -2.18e-02 -1.52e-01 -1.45e-01 -1.60e-01 -1.58e-01 -1.58e-01 -1.54e-01 -1.50e-01 -1.37e-01 -1.30e-01 -1.26e-01 -1.30e-01 -1.23e-01 -1.71e-01 -7.09e-02 -2.53e-02 -1.42e-01 -1.41e-01 -1.47e-01 -1.47e-01 -1.58e-01 -1.48e-01 -1.36e-01 -1.35e-01 -1.33e-01 -1.29e-01 -1.19e-01 -1.14e-01 -1.45e-01 -4.24e-02 -1.27e-02 -1.43e-01 -1.40e-01 -1.44e-01 -1.45e-01 -1.42e-01 -1.37e-01 -1.42e-01 -1.47e-01 -1.33e-01 -1.30e-01 -1.15e-01 -1.07e-01 -1.24e-01 -3.91e-02 -1.19e-02 -1.85e-01 -1.70e-01 -1.73e-01 -1.81e-01 -1.77e-01 -1.76e-01 -1.75e-01 -1.93e-01 -1.94e-01 -1.58e-01 -1.45e-01 -1.24e-01 -7.16e-02 -2.05e-02 -7.17e-03 -1.27e-01 -6.46e-02 -8.27e-02 -1.04e-01 -7.86e-02 -7.86e-02 -7.04e-02 -6.74e-02 -1.02e-01 -7.60e-02 -5.37e-02 -4.16e-02 -2.54e-02 -6.01e-03 -1.97e-03 -5.06e-02 -2.49e-02 -3.45e-02 -3.64e-02 -2.84e-02 -2.70e-02 -2.34e-02 -2.43e-02 -3.12e-02 -2.55e-02 -1.56e-02 -1.52e-02 -9.91e-03 -3.26e-03 -1.47e-03 -2.30e-01 -2.43e-01 -2.55e-01 -2.55e-01 -2.51e-01 -2.39e-01 -2.30e-01 -2.27e-01 -2.29e-01 -2.07e-01 -2.02e-01 -2.14e-01 -1.61e-01 -2.95e-02 -7.43e-03 -2.45e-01 -2.22e-01 -2.61e-01 -2.31e-01 -2.30e-01 -2.40e-01 -2.34e-01 -2.18e-01 -2.03e-01 -2.11e-01 -1.97e-01 -1.92e-01 -1.80e-01 -4.88e-02 -1.49e-02 -2.38e-01 -2.17e-01 -2.52e-01 -2.29e-01 -2.25e-01 -2.44e-01 -2.15e-01 -2.39e-01 -2.19e-01 -2.19e-01 -2.01e-01 -1.92e-01 -2.20e-01 -9.45e-02 -2.94e-02 -2.36e-01 -2.27e-01 -2.34e-01 -2.40e-01 -2.35e-01 -2.56e-01 -2.38e-01 -2.37e-01 -2.25e-01 -2.08e-01 -1.82e-01 -1.60e-01 -1.81e-01 -5.67e-02 -1.61e-02 -2.29e-01 -2.18e-01 -2.26e-01 -2.37e-01 -2.21e-01 -2.35e-01 -2.69e-01 -2.31e-01 -2.30e-01 -2.32e-01 -2.01e-01 -1.47e-01 -1.58e-01 -7.81e-02 -2.93e-02 -2.28e-01 -2.05e-01 -2.20e-01 -2.25e-01 -2.12e-01 -2.31e-01 -2.33e-01 -2.13e-01 -2.09e-01 -2.24e-01 -1.97e-01 -1.71e-01 -1.79e-01 -7.52e-02 -2.31e-02 -2.03e-01 -2.07e-01 -2.27e-01 -2.19e-01 -2.11e-01 -2.22e-01 -2.17e-01 -2.08e-01 -1.77e-01 -2.01e-01 -1.89e-01 -1.57e-01 -1.63e-01 -5.48e-02 -1.75e-02 -2.07e-01 -2.13e-01 -2.09e-01 -2.25e-01 -2.36e-01 -2.27e-01 -2.11e-01 -2.10e-01 -1.87e-01 -1.89e-01 -1.88e-01 -1.79e-01 -1.33e-01 -3.03e-02 -1.06e-02 -2.08e-01 -2.14e-01 -2.12e-01 -2.27e-01 -2.27e-01 -2.05e-01 -2.29e-01 -2.21e-01 -1.93e-01 -2.02e-01 -1.81e-01 -1.73e-01 -1.67e-01 -4.08e-02 -1.39e-02 -2.00e-01 -2.19e-01 -2.28e-01 -2.14e-01 -2.28e-01 -2.06e-01 -2.17e-01 -1.92e-01 -1.79e-01 -1.74e-01 -1.72e-01 -1.71e-01 -1.60e-01 -4.62e-02 -1.43e-02 -1.82e-01 -1.92e-01 -2.16e-01 -2.14e-01 -2.12e-01 -2.26e-01 -1.94e-01 -1.68e-01 -1.64e-01 -1.50e-01 -1.55e-01 -1.48e-01 -1.04e-01 -4.02e-02 -1.44e-02 -1.56e-01 -1.60e-01 -1.93e-01 -1.87e-01 -1.94e-01 -2.01e-01 -2.07e-01 -1.85e-01 -1.76e-01 -1.49e-01 -1.39e-01 -1.38e-01 -1.04e-01 -2.84e-02 -1.17e-02 -1.33e-01 -1.46e-01 -1.65e-01 -1.58e-01 -1.74e-01 -1.70e-01 -1.37e-01 -1.94e-01 -1.93e-01 -1.64e-01 -1.20e-01 -1.02e-01 -6.63e-02 -1.85e-02 -8.29e-03 -6.84e-02 -4.09e-02 -5.11e-02 -6.13e-02 -4.88e-02 -4.65e-02 -3.93e-02 -4.74e-02 -8.51e-02 -5.59e-02 -2.40e-02 -2.44e-02 -1.30e-02 -4.68e-03 -2.65e-03 -2.59e-02 -1.30e-02 -1.81e-02 -1.96e-02 -1.49e-02 -1.49e-02 -1.50e-02 -1.42e-02 -2.71e-02 -2.16e-02 -1.05e-02 -7.72e-03 -4.11e-03 -2.35e-03 -9.64e-04 -2.21e-01 -2.15e-01 -2.72e-01 -1.92e-01 -3.01e-01 -2.43e-01 -2.13e-01 -2.18e-01 -1.88e-01 -1.66e-01 -1.13e-01 -1.21e-01 -1.08e-01 -2.92e-02 -8.37e-03 -2.75e-01 -1.89e-01 -3.28e-01 -3.64e-01 -2.91e-01 -2.34e-01 -1.86e-01 -1.90e-01 -1.53e-01 -1.35e-01 -1.21e-01 -1.01e-01 -8.79e-02 -3.91e-02 -1.37e-02 -2.37e-01 -2.28e-01 -2.92e-01 -2.21e-01 -1.70e-01 -2.29e-01 -1.86e-01 -1.95e-01 -1.65e-01 -1.42e-01 -1.73e-01 -1.38e-01 -7.39e-02 -4.16e-02 -2.91e-02 -2.73e-01 -2.33e-01 -2.78e-01 -3.06e-01 -2.31e-01 -2.52e-01 -2.69e-01 -2.39e-01 -2.13e-01 -1.63e-01 -1.20e-01 -8.39e-02 -5.83e-02 -2.86e-02 -1.32e-02 -2.63e-01 -1.92e-01 -2.54e-01 -3.11e-01 -2.65e-01 -2.75e-01 -2.71e-01 -2.21e-01 -1.81e-01 -1.68e-01 -1.49e-01 -7.05e-02 -5.03e-02 -2.54e-02 -1.28e-02 -2.09e-01 -1.61e-01 -2.21e-01 -2.28e-01 -1.55e-01 -1.78e-01 -2.16e-01 -1.50e-01 -1.32e-01 -1.76e-01 -1.57e-01 -1.01e-01 -5.61e-02 -2.32e-02 -1.53e-02 -1.50e-01 -1.81e-01 -2.03e-01 -2.04e-01 -1.79e-01 -1.94e-01 -1.81e-01 -1.52e-01 -1.26e-01 -1.13e-01 -9.16e-02 -6.72e-02 -3.94e-02 -2.35e-02 -1.45e-02 -1.06e-01 -1.43e-01 -1.61e-01 -1.57e-01 -1.80e-01 -1.80e-01 -1.23e-01 -1.22e-01 -8.18e-02 -7.30e-02 -9.33e-02 -7.39e-02 -3.89e-02 -2.07e-02 -8.17e-03 -1.13e-01 -1.37e-01 -1.61e-01 -2.20e-01 -1.71e-01 -1.51e-01 -1.16e-01 -1.45e-01 -1.13e-01 -1.05e-01 -9.41e-02 -7.14e-02 -5.35e-02 -1.91e-02 -7.31e-03 -8.55e-02 -1.58e-01 -2.08e-01 -1.60e-01 -1.37e-01 -8.33e-02 -1.16e-01 -1.39e-01 -1.15e-01 -9.22e-02 -8.69e-02 -6.24e-02 -4.30e-02 -2.48e-02 -7.57e-03 -9.22e-02 -1.13e-01 -1.60e-01 -1.04e-01 -1.40e-01 -1.35e-01 -1.08e-01 -1.02e-01 -8.56e-02 -5.91e-02 -7.46e-02 -6.28e-02 -3.81e-02 -2.04e-02 -9.21e-03 -7.85e-02 -6.83e-02 -1.01e-01 -9.42e-02 -9.47e-02 -1.38e-01 -1.13e-01 -6.40e-02 -6.03e-02 -5.21e-02 -4.63e-02 -4.67e-02 -3.57e-02 -9.24e-03 -3.46e-03 -3.82e-02 -4.99e-02 -6.21e-02 -4.80e-02 -5.79e-02 -8.37e-02 -6.86e-02 -6.66e-02 -5.19e-02 -5.77e-02 -4.00e-02 -3.46e-02 -2.69e-02 -9.16e-03 -3.73e-03 -1.66e-02 -1.94e-02 -2.26e-02 -1.79e-02 -2.45e-02 -3.08e-02 -2.00e-02 -2.89e-02 -3.35e-02 -2.83e-02 -1.58e-02 -1.10e-02 -7.32e-03 -3.83e-03 -1.85e-03 -1.35e-02 -7.32e-03 -8.41e-03 -8.10e-03 -9.00e-03 -1.12e-02 -5.57e-03 -9.30e-03 -1.48e-02 -1.39e-02 -6.30e-03 -3.42e-03 -2.99e-03 -1.40e-03 -5.26e-04 -7.56e-02 -7.51e-02 -1.02e-01 -6.63e-02 -1.09e-01 -8.00e-02 -7.46e-02 -7.69e-02 -7.23e-02 -5.75e-02 -3.77e-02 -3.71e-02 -3.59e-02 -2.14e-02 -7.54e-03 -1.13e-01 -5.14e-02 -1.11e-01 -1.48e-01 -1.23e-01 -8.67e-02 -6.58e-02 -5.93e-02 -5.79e-02 -5.00e-02 -3.78e-02 -2.92e-02 -2.64e-02 -1.76e-02 -8.34e-03 -8.71e-02 -6.82e-02 -1.03e-01 -9.93e-02 -4.68e-02 -8.00e-02 -6.54e-02 -5.73e-02 -5.88e-02 -4.17e-02 -6.05e-02 -5.26e-02 -2.82e-02 -1.18e-02 -1.25e-02 -8.93e-02 -6.93e-02 -1.05e-01 -1.22e-01 -7.82e-02 -8.44e-02 -9.53e-02 -9.08e-02 -8.61e-02 -6.38e-02 -4.26e-02 -2.94e-02 -1.95e-02 -1.16e-02 -5.85e-03 -1.07e-01 -7.48e-02 -9.61e-02 -1.16e-01 -1.00e-01 -9.56e-02 -1.01e-01 -7.22e-02 -7.15e-02 -4.92e-02 -5.10e-02 -2.14e-02 -1.39e-02 -8.55e-03 -5.42e-03 -6.30e-02 -5.46e-02 -6.94e-02 -7.56e-02 -5.76e-02 -4.99e-02 -6.77e-02 -4.79e-02 -4.29e-02 -5.31e-02 -5.73e-02 -4.32e-02 -2.01e-02 -8.20e-03 -4.18e-03 -6.21e-02 -5.98e-02 -7.34e-02 -7.91e-02 -4.60e-02 -5.72e-02 -6.01e-02 -5.26e-02 -5.01e-02 -3.98e-02 -3.12e-02 -2.62e-02 -1.44e-02 -6.44e-03 -6.95e-03 -2.95e-02 -5.38e-02 -4.94e-02 -4.81e-02 -5.65e-02 -6.07e-02 -3.70e-02 -3.88e-02 -2.59e-02 -2.05e-02 -2.51e-02 -2.29e-02 -1.19e-02 -1.08e-02 -8.34e-03 -3.62e-02 -4.00e-02 -5.20e-02 -6.63e-02 -6.42e-02 -5.90e-02 -3.69e-02 -4.87e-02 -4.00e-02 -3.31e-02 -2.85e-02 -2.46e-02 -2.05e-02 -8.72e-03 -3.45e-03 -2.17e-02 -4.81e-02 -6.28e-02 -6.24e-02 -4.43e-02 -2.41e-02 -3.73e-02 -4.41e-02 -4.25e-02 -2.80e-02 -2.62e-02 -2.10e-02 -1.12e-02 -1.28e-02 -6.90e-03 -2.96e-02 -4.88e-02 -5.84e-02 -2.83e-02 -4.58e-02 -3.78e-02 -2.43e-02 -3.47e-02 -3.08e-02 -2.18e-02 -2.32e-02 -1.70e-02 -1.26e-02 -9.95e-03 -8.03e-03 -2.02e-02 -2.21e-02 -3.09e-02 -2.79e-02 -2.92e-02 -4.73e-02 -3.85e-02 -2.69e-02 -1.89e-02 -1.70e-02 -1.44e-02 -1.42e-02 -1.51e-02 -4.21e-03 -1.55e-03 -1.72e-02 -1.70e-02 -2.18e-02 -2.50e-02 -1.84e-02 -3.18e-02 -2.53e-02 -2.01e-02 -1.37e-02 -1.89e-02 -1.02e-02 -1.15e-02 -1.16e-02 -3.85e-03 -1.22e-03 -5.45e-03 -9.53e-03 -9.49e-03 -6.68e-03 -1.08e-02 -1.59e-02 -1.34e-02 -1.53e-02 -1.86e-02 -1.03e-02 -1.07e-02 -6.50e-03 -3.98e-03 -2.38e-03 -2.29e-03 -4.46e-03 -5.06e-03 -5.22e-03 -4.55e-03 -5.72e-03 -1.00e-02 -6.07e-03 -5.95e-03 -1.20e-02 -8.03e-03 -5.95e-03 -3.61e-03 -1.35e-03 -8.82e-04 -1.47e-03 -Upper Bounds -8.83e-01 -9.04e-01 -9.04e-01 -9.06e-01 -8.90e-01 -8.71e-01 -8.51e-01 -8.82e-01 -8.99e-01 -9.42e-01 -8.75e-01 -9.67e-01 -1.38e+00 -2.14e+00 -7.89e-01 -8.70e-01 -9.11e-01 -9.06e-01 -8.15e-01 -8.92e-01 -9.06e-01 -8.84e-01 -8.83e-01 -8.68e-01 -8.58e-01 -9.07e-01 -9.12e-01 -1.29e+00 -1.63e+00 -5.33e-01 -9.10e-01 -8.73e-01 -9.05e-01 -9.08e-01 -8.81e-01 -8.85e-01 -8.70e-01 -8.31e-01 -8.30e-01 -8.46e-01 -8.79e-01 -9.36e-01 -1.33e+00 -2.08e+00 -7.86e-01 -8.80e-01 -8.72e-01 -8.61e-01 -8.81e-01 -8.35e-01 -8.38e-01 -8.52e-01 -8.74e-01 -8.62e-01 -8.63e-01 -8.27e-01 -9.20e-01 -1.33e+00 -2.00e+00 -6.39e-01 -8.76e-01 -9.10e-01 -9.11e-01 -9.20e-01 -8.60e-01 -8.61e-01 -8.34e-01 -8.36e-01 -8.28e-01 -8.72e-01 -8.44e-01 -9.49e-01 -1.41e+00 -1.65e+00 -6.46e-01 -9.01e-01 -8.97e-01 -8.94e-01 -8.90e-01 -8.81e-01 -8.46e-01 -8.38e-01 -8.15e-01 -8.49e-01 -8.29e-01 -8.56e-01 -9.61e-01 -1.35e+00 -1.44e+00 -5.12e-01 -8.79e-01 -8.59e-01 -8.42e-01 -8.55e-01 -8.31e-01 -8.41e-01 -8.24e-01 -8.31e-01 -8.11e-01 -7.99e-01 -8.06e-01 -8.32e-01 -1.19e+00 -1.66e+00 -6.17e-01 -9.09e-01 -9.03e-01 -8.95e-01 -8.51e-01 -8.33e-01 -8.62e-01 -8.26e-01 -8.10e-01 -7.35e-01 -7.80e-01 -7.82e-01 -7.20e-01 -1.00e+00 -8.79e-01 -3.78e-01 -8.81e-01 -8.79e-01 -8.98e-01 -9.09e-01 -8.56e-01 -8.36e-01 -8.26e-01 -8.10e-01 -7.69e-01 -7.73e-01 -7.71e-01 -7.76e-01 -1.14e+00 -8.33e-01 -2.68e-01 -8.83e-01 -9.23e-01 -9.16e-01 -9.05e-01 -8.94e-01 -8.03e-01 -8.19e-01 -7.89e-01 -8.04e-01 -7.99e-01 -7.77e-01 -7.67e-01 -1.16e+00 -8.69e-01 -3.26e-01 -9.04e-01 -8.93e-01 -9.15e-01 -8.96e-01 -8.99e-01 -8.47e-01 -7.92e-01 -8.32e-01 -7.94e-01 -7.96e-01 -8.49e-01 -7.81e-01 -1.06e+00 -6.40e-01 -1.87e-01 -9.49e-01 -9.48e-01 -9.08e-01 -8.57e-01 -9.51e-01 -9.10e-01 -8.62e-01 -8.93e-01 -8.43e-01 -8.47e-01 -8.29e-01 -7.55e-01 -1.11e+00 -4.81e-01 -1.57e-01 -1.38e+00 -1.37e+00 -1.26e+00 -1.31e+00 -1.37e+00 -1.34e+00 -1.26e+00 -1.21e+00 -1.21e+00 -1.21e+00 -1.20e+00 -1.12e+00 -1.06e+00 -3.64e-01 -1.05e-01 -2.50e+00 -1.75e+00 -1.96e+00 -1.28e+00 -1.40e+00 -1.59e+00 -1.27e+00 -1.18e+00 -9.31e-01 -9.87e-01 -9.06e-01 -7.50e-01 -4.87e-01 -1.88e-01 -9.31e-02 -1.08e+00 -7.08e-01 -8.14e-01 -4.09e-01 -4.59e-01 -5.72e-01 -4.06e-01 -3.97e-01 -3.49e-01 -3.11e-01 -3.14e-01 -2.24e-01 -1.84e-01 -7.93e-02 -3.58e-02 -8.56e-01 -8.80e-01 -8.90e-01 -8.72e-01 -8.83e-01 -8.79e-01 -9.07e-01 -8.87e-01 -8.46e-01 -8.81e-01 -9.13e-01 -9.22e-01 -1.35e+00 -1.99e+00 -7.68e-01 -8.95e-01 -8.96e-01 -9.01e-01 -8.77e-01 -8.78e-01 -8.57e-01 -8.71e-01 -8.72e-01 -8.61e-01 -8.65e-01 -8.84e-01 -9.25e-01 -1.27e+00 -1.84e+00 -6.71e-01 -9.00e-01 -8.80e-01 -8.68e-01 -8.83e-01 -8.82e-01 -8.83e-01 -8.68e-01 -8.89e-01 -8.61e-01 -9.00e-01 -9.04e-01 -9.06e-01 -1.33e+00 -1.66e+00 -5.75e-01 -9.10e-01 -9.28e-01 -9.04e-01 -9.15e-01 -8.68e-01 -8.37e-01 -8.58e-01 -8.74e-01 -8.49e-01 -8.43e-01 -8.73e-01 -9.20e-01 -1.29e+00 -1.77e+00 -6.31e-01 -8.99e-01 -9.11e-01 -8.97e-01 -8.66e-01 -8.29e-01 -8.48e-01 -8.85e-01 -8.47e-01 -8.39e-01 -8.47e-01 -8.91e-01 -9.17e-01 -1.38e+00 -1.51e+00 -6.62e-01 -8.74e-01 -8.88e-01 -8.84e-01 -8.46e-01 -8.97e-01 -8.43e-01 -8.27e-01 -8.17e-01 -8.15e-01 -8.35e-01 -8.69e-01 -9.33e-01 -1.35e+00 -1.72e+00 -6.01e-01 -9.01e-01 -9.12e-01 -8.41e-01 -8.34e-01 -8.86e-01 -8.49e-01 -7.94e-01 -7.99e-01 -7.91e-01 -8.03e-01 -8.26e-01 -8.34e-01 -1.17e+00 -1.46e+00 -5.66e-01 -8.53e-01 -8.62e-01 -8.25e-01 -8.26e-01 -8.26e-01 -7.99e-01 -7.85e-01 -7.29e-01 -7.14e-01 -7.51e-01 -7.41e-01 -5.28e-01 -9.65e-01 -8.41e-01 -3.51e-01 -8.43e-01 -9.30e-01 -8.75e-01 -8.72e-01 -8.86e-01 -8.25e-01 -8.05e-01 -7.70e-01 -7.66e-01 -7.77e-01 -7.36e-01 -7.06e-01 -9.91e-01 -6.14e-01 -1.92e-01 -8.89e-01 -9.28e-01 -8.82e-01 -8.85e-01 -8.26e-01 -8.77e-01 -8.28e-01 -7.72e-01 -7.97e-01 -7.70e-01 -8.14e-01 -7.60e-01 -1.08e+00 -7.25e-01 -2.17e-01 -8.99e-01 -9.33e-01 -8.95e-01 -8.67e-01 -9.07e-01 -8.80e-01 -8.33e-01 -7.98e-01 -8.16e-01 -7.99e-01 -8.47e-01 -7.75e-01 -1.08e+00 -6.72e-01 -2.06e-01 -9.39e-01 -8.99e-01 -9.19e-01 -9.05e-01 -9.21e-01 -9.37e-01 -8.70e-01 -8.47e-01 -8.32e-01 -8.66e-01 -8.48e-01 -8.12e-01 -1.00e+00 -4.14e-01 -1.43e-01 -1.29e+00 -1.41e+00 -1.29e+00 -1.35e+00 -1.47e+00 -1.34e+00 -1.23e+00 -1.28e+00 -1.17e+00 -1.16e+00 -1.29e+00 -1.20e+00 -1.04e+00 -2.68e-01 -6.98e-02 -1.56e+00 -1.49e+00 -1.36e+00 -1.52e+00 -1.85e+00 -1.77e+00 -1.39e+00 -1.40e+00 -1.09e+00 -8.12e-01 -8.12e-01 -8.15e-01 -5.39e-01 -1.74e-01 -7.42e-02 -5.46e-01 -5.41e-01 -5.27e-01 -5.05e-01 -6.76e-01 -7.08e-01 -4.76e-01 -5.00e-01 -4.66e-01 -2.59e-01 -2.59e-01 -2.67e-01 -2.12e-01 -9.34e-02 -3.59e-02 -8.98e-01 -8.76e-01 -9.11e-01 -8.74e-01 -8.57e-01 -8.49e-01 -8.45e-01 -8.23e-01 -8.73e-01 -8.56e-01 -8.41e-01 -9.32e-01 -1.56e+00 -2.14e+00 -8.32e-01 -9.04e-01 -8.85e-01 -8.48e-01 -8.66e-01 -8.66e-01 -8.58e-01 -8.22e-01 -8.28e-01 -8.32e-01 -8.65e-01 -8.49e-01 -9.47e-01 -1.32e+00 -2.01e+00 -8.20e-01 -8.96e-01 -9.02e-01 -9.15e-01 -8.55e-01 -8.63e-01 -8.56e-01 -8.51e-01 -8.73e-01 -8.47e-01 -8.41e-01 -8.38e-01 -8.99e-01 -1.24e+00 -1.71e+00 -6.45e-01 -8.13e-01 -8.67e-01 -8.68e-01 -8.57e-01 -8.41e-01 -8.27e-01 -8.41e-01 -8.63e-01 -8.60e-01 -8.27e-01 -8.62e-01 -8.45e-01 -1.26e+00 -1.59e+00 -5.28e-01 -8.37e-01 -8.48e-01 -8.61e-01 -8.18e-01 -8.55e-01 -8.57e-01 -7.87e-01 -8.18e-01 -8.05e-01 -8.09e-01 -8.66e-01 -8.95e-01 -1.31e+00 -1.33e+00 -3.87e-01 -8.40e-01 -8.59e-01 -8.21e-01 -8.32e-01 -8.27e-01 -8.30e-01 -7.89e-01 -7.95e-01 -8.16e-01 -8.14e-01 -8.48e-01 -8.74e-01 -1.25e+00 -1.74e+00 -6.56e-01 -8.62e-01 -8.97e-01 -8.49e-01 -8.48e-01 -8.43e-01 -8.56e-01 -8.49e-01 -7.73e-01 -7.97e-01 -8.23e-01 -8.50e-01 -8.53e-01 -1.22e+00 -1.23e+00 -4.60e-01 -8.51e-01 -8.51e-01 -8.30e-01 -8.17e-01 -8.30e-01 -8.17e-01 -7.95e-01 -7.91e-01 -7.83e-01 -7.99e-01 -7.74e-01 -7.63e-01 -1.10e+00 -8.15e-01 -3.18e-01 -8.51e-01 -8.51e-01 -8.64e-01 -8.45e-01 -8.30e-01 -8.19e-01 -8.14e-01 -8.18e-01 -7.60e-01 -7.72e-01 -7.64e-01 -7.45e-01 -1.06e+00 -8.19e-01 -3.07e-01 -8.70e-01 -8.92e-01 -8.63e-01 -8.73e-01 -8.70e-01 -8.23e-01 -8.34e-01 -7.96e-01 -7.41e-01 -7.85e-01 -7.76e-01 -7.97e-01 -1.03e+00 -6.15e-01 -2.40e-01 -8.46e-01 -8.88e-01 -8.83e-01 -8.69e-01 -8.83e-01 -8.65e-01 -8.68e-01 -8.40e-01 -7.58e-01 -7.91e-01 -7.91e-01 -7.77e-01 -1.06e+00 -6.09e-01 -1.67e-01 -8.76e-01 -9.27e-01 -9.32e-01 -9.51e-01 -9.02e-01 -8.97e-01 -8.78e-01 -8.56e-01 -8.35e-01 -8.55e-01 -8.47e-01 -8.43e-01 -9.29e-01 -5.11e-01 -1.77e-01 -1.33e+00 -1.33e+00 -1.32e+00 -1.25e+00 -1.30e+00 -1.29e+00 -1.17e+00 -1.21e+00 -1.18e+00 -1.15e+00 -1.16e+00 -1.21e+00 -1.14e+00 -2.72e-01 -8.55e-02 -1.89e+00 -1.37e+00 -1.71e+00 -1.75e+00 -1.82e+00 -1.16e+00 -1.16e+00 -1.09e+00 -9.10e-01 -8.87e-01 -6.38e-01 -5.79e-01 -5.13e-01 -2.08e-01 -5.28e-02 -6.66e-01 -4.35e-01 -7.04e-01 -6.72e-01 -6.85e-01 -4.41e-01 -3.91e-01 -4.18e-01 -2.80e-01 -3.20e-01 -1.45e-01 -1.85e-01 -1.73e-01 -1.30e-01 -6.20e-02 -8.83e-01 -8.54e-01 -8.74e-01 -8.97e-01 -8.66e-01 -8.53e-01 -8.20e-01 -8.29e-01 -7.95e-01 -8.07e-01 -7.74e-01 -8.95e-01 -1.34e+00 -2.13e+00 -7.78e-01 -8.75e-01 -9.11e-01 -8.53e-01 -8.24e-01 -8.43e-01 -8.30e-01 -8.44e-01 -8.16e-01 -8.23e-01 -8.70e-01 -8.45e-01 -8.80e-01 -1.24e+00 -1.66e+00 -6.51e-01 -8.43e-01 -8.65e-01 -8.86e-01 -8.33e-01 -7.75e-01 -8.33e-01 -7.93e-01 -8.14e-01 -7.91e-01 -8.49e-01 -8.47e-01 -9.21e-01 -1.22e+00 -1.35e+00 -5.11e-01 -8.45e-01 -8.50e-01 -8.67e-01 -8.43e-01 -8.32e-01 -8.35e-01 -8.18e-01 -8.02e-01 -8.09e-01 -8.16e-01 -8.13e-01 -8.33e-01 -1.24e+00 -1.20e+00 -4.92e-01 -8.11e-01 -8.21e-01 -8.46e-01 -8.56e-01 -8.12e-01 -7.90e-01 -8.09e-01 -7.88e-01 -8.08e-01 -8.07e-01 -8.57e-01 -8.34e-01 -1.25e+00 -1.61e+00 -5.85e-01 -8.68e-01 -7.99e-01 -8.45e-01 -8.59e-01 -8.33e-01 -7.98e-01 -8.23e-01 -8.40e-01 -8.11e-01 -8.01e-01 -8.15e-01 -8.78e-01 -1.27e+00 -1.49e+00 -5.48e-01 -8.43e-01 -8.36e-01 -8.81e-01 -8.18e-01 -7.95e-01 -7.90e-01 -8.20e-01 -7.94e-01 -7.74e-01 -7.96e-01 -7.56e-01 -8.00e-01 -1.25e+00 -1.44e+00 -5.06e-01 -8.60e-01 -8.53e-01 -8.41e-01 -8.13e-01 -7.94e-01 -8.04e-01 -8.30e-01 -7.78e-01 -7.68e-01 -7.54e-01 -7.46e-01 -7.89e-01 -1.17e+00 -9.24e-01 -3.31e-01 -8.47e-01 -8.25e-01 -8.14e-01 -8.34e-01 -8.09e-01 -8.13e-01 -8.14e-01 -8.04e-01 -7.77e-01 -7.65e-01 -7.94e-01 -8.47e-01 -1.24e+00 -9.33e-01 -2.64e-01 -8.55e-01 -8.28e-01 -8.67e-01 -8.38e-01 -8.25e-01 -8.22e-01 -7.96e-01 -7.62e-01 -7.99e-01 -7.61e-01 -7.38e-01 -7.68e-01 -1.16e+00 -6.75e-01 -2.70e-01 -8.80e-01 -8.88e-01 -8.39e-01 -8.93e-01 -8.67e-01 -8.43e-01 -8.12e-01 -8.07e-01 -7.97e-01 -8.03e-01 -7.88e-01 -8.01e-01 -1.03e+00 -4.71e-01 -1.39e-01 -9.42e-01 -8.84e-01 -8.89e-01 -8.81e-01 -9.12e-01 -9.52e-01 -8.80e-01 -8.12e-01 -8.44e-01 -8.47e-01 -8.47e-01 -8.42e-01 -9.87e-01 -3.92e-01 -1.14e-01 -1.24e+00 -1.25e+00 -1.29e+00 -1.25e+00 -1.29e+00 -1.28e+00 -1.08e+00 -1.14e+00 -1.21e+00 -1.12e+00 -1.06e+00 -1.07e+00 -1.14e+00 -3.91e-01 -1.23e-01 -1.55e+00 -1.24e+00 -1.03e+00 -1.46e+00 -1.44e+00 -1.17e+00 -8.10e-01 -5.67e-01 -9.52e-01 -9.00e-01 -5.78e-01 -5.33e-01 -4.71e-01 -2.10e-01 -8.15e-02 -5.84e-01 -4.29e-01 -4.39e-01 -4.57e-01 -5.73e-01 -4.28e-01 -3.39e-01 -1.82e-01 -3.17e-01 -3.19e-01 -2.03e-01 -1.80e-01 -1.39e-01 -1.28e-01 -6.06e-02 -8.53e-01 -8.41e-01 -8.16e-01 -8.39e-01 -8.62e-01 -8.30e-01 -8.25e-01 -7.57e-01 -7.84e-01 -8.17e-01 -7.85e-01 -8.91e-01 -1.29e+00 -1.58e+00 -6.19e-01 -8.62e-01 -8.53e-01 -8.28e-01 -8.47e-01 -8.54e-01 -8.13e-01 -7.89e-01 -7.56e-01 -8.10e-01 -8.39e-01 -8.37e-01 -8.80e-01 -1.27e+00 -1.52e+00 -5.61e-01 -8.76e-01 -8.58e-01 -8.51e-01 -8.40e-01 -8.16e-01 -8.22e-01 -8.17e-01 -7.68e-01 -8.23e-01 -8.47e-01 -8.38e-01 -8.80e-01 -1.26e+00 -1.11e+00 -4.01e-01 -8.41e-01 -8.55e-01 -8.26e-01 -8.31e-01 -8.17e-01 -8.22e-01 -8.05e-01 -8.08e-01 -8.05e-01 -8.32e-01 -8.20e-01 -8.61e-01 -1.30e+00 -1.05e+00 -3.57e-01 -8.15e-01 -8.06e-01 -8.14e-01 -8.44e-01 -8.05e-01 -8.12e-01 -8.12e-01 -8.06e-01 -7.90e-01 -7.71e-01 -8.19e-01 -8.79e-01 -1.29e+00 -1.63e+00 -5.79e-01 -7.99e-01 -7.98e-01 -8.14e-01 -8.39e-01 -8.09e-01 -7.70e-01 -7.51e-01 -8.22e-01 -8.15e-01 -7.92e-01 -7.89e-01 -8.42e-01 -1.22e+00 -1.30e+00 -4.67e-01 -8.04e-01 -8.15e-01 -8.41e-01 -8.12e-01 -8.44e-01 -7.64e-01 -7.65e-01 -7.83e-01 -7.51e-01 -7.69e-01 -7.83e-01 -7.94e-01 -1.09e+00 -1.03e+00 -3.79e-01 -8.53e-01 -8.48e-01 -8.17e-01 -7.87e-01 -8.03e-01 -7.66e-01 -7.80e-01 -7.47e-01 -7.47e-01 -7.94e-01 -7.46e-01 -7.73e-01 -1.13e+00 -8.10e-01 -3.44e-01 -8.55e-01 -8.35e-01 -8.31e-01 -8.01e-01 -8.04e-01 -8.11e-01 -8.17e-01 -7.71e-01 -7.52e-01 -7.41e-01 -7.55e-01 -7.73e-01 -1.08e+00 -8.26e-01 -2.48e-01 -8.55e-01 -8.65e-01 -8.39e-01 -8.10e-01 -7.84e-01 -8.10e-01 -7.97e-01 -7.80e-01 -7.63e-01 -7.36e-01 -7.45e-01 -8.12e-01 -1.07e+00 -7.90e-01 -3.43e-01 -8.52e-01 -8.31e-01 -8.47e-01 -8.29e-01 -8.34e-01 -8.10e-01 -8.15e-01 -8.13e-01 -7.91e-01 -7.58e-01 -7.69e-01 -8.34e-01 -1.13e+00 -5.77e-01 -2.01e-01 -8.71e-01 -9.08e-01 -8.51e-01 -8.61e-01 -8.87e-01 -9.24e-01 -8.39e-01 -8.24e-01 -8.13e-01 -8.68e-01 -8.13e-01 -8.31e-01 -1.14e+00 -5.34e-01 -1.63e-01 -1.29e+00 -1.23e+00 -1.25e+00 -1.29e+00 -1.30e+00 -1.33e+00 -1.29e+00 -1.19e+00 -1.17e+00 -1.14e+00 -1.08e+00 -1.12e+00 -1.16e+00 -4.48e-01 -1.51e-01 -1.37e+00 -1.25e+00 -1.26e+00 -1.31e+00 -1.52e+00 -1.34e+00 -1.46e+00 -9.26e-01 -1.00e+00 -7.33e-01 -5.03e-01 -5.86e-01 -4.40e-01 -1.93e-01 -7.63e-02 -5.00e-01 -4.36e-01 -4.55e-01 -4.50e-01 -5.38e-01 -4.35e-01 -5.87e-01 -2.73e-01 -3.52e-01 -2.53e-01 -1.54e-01 -1.57e-01 -1.32e-01 -8.46e-02 -5.80e-02 -7.99e-01 -8.20e-01 -8.15e-01 -8.33e-01 -8.51e-01 -8.10e-01 -7.68e-01 -7.62e-01 -7.58e-01 -7.77e-01 -7.87e-01 -8.14e-01 -1.30e+00 -1.29e+00 -3.79e-01 -7.97e-01 -8.41e-01 -8.13e-01 -7.89e-01 -8.26e-01 -8.24e-01 -8.37e-01 -7.59e-01 -7.92e-01 -7.78e-01 -7.98e-01 -8.46e-01 -1.24e+00 -1.44e+00 -5.54e-01 -8.32e-01 -8.44e-01 -8.48e-01 -8.16e-01 -8.13e-01 -7.97e-01 -8.17e-01 -8.24e-01 -7.90e-01 -7.89e-01 -7.98e-01 -8.75e-01 -1.29e+00 -1.26e+00 -4.10e-01 -8.34e-01 -8.40e-01 -7.91e-01 -7.91e-01 -8.06e-01 -8.33e-01 -7.71e-01 -7.76e-01 -8.05e-01 -8.07e-01 -8.15e-01 -8.50e-01 -1.26e+00 -1.18e+00 -3.80e-01 -8.13e-01 -8.32e-01 -8.39e-01 -8.18e-01 -7.93e-01 -7.93e-01 -7.84e-01 -7.91e-01 -7.91e-01 -7.82e-01 -7.90e-01 -8.30e-01 -1.25e+00 -1.29e+00 -4.90e-01 -8.01e-01 -8.04e-01 -8.21e-01 -8.03e-01 -7.98e-01 -7.82e-01 -7.55e-01 -7.51e-01 -8.14e-01 -8.19e-01 -7.83e-01 -8.19e-01 -1.18e+00 -1.09e+00 -4.51e-01 -8.40e-01 -8.47e-01 -8.18e-01 -7.81e-01 -7.89e-01 -7.65e-01 -7.53e-01 -7.17e-01 -7.54e-01 -7.65e-01 -7.76e-01 -8.17e-01 -1.09e+00 -6.64e-01 -2.45e-01 -8.36e-01 -7.99e-01 -8.04e-01 -7.74e-01 -8.20e-01 -7.78e-01 -7.45e-01 -7.25e-01 -7.18e-01 -7.55e-01 -7.86e-01 -8.22e-01 -1.16e+00 -5.88e-01 -1.82e-01 -8.12e-01 -8.33e-01 -8.42e-01 -7.73e-01 -7.95e-01 -7.85e-01 -7.91e-01 -7.28e-01 -7.16e-01 -6.95e-01 -7.39e-01 -7.71e-01 -1.13e+00 -7.23e-01 -2.02e-01 -7.76e-01 -8.13e-01 -8.17e-01 -8.37e-01 -7.81e-01 -7.65e-01 -7.51e-01 -7.47e-01 -7.44e-01 -7.26e-01 -7.33e-01 -7.63e-01 -1.05e+00 -6.00e-01 -1.91e-01 -8.26e-01 -7.94e-01 -8.07e-01 -8.05e-01 -7.80e-01 -7.80e-01 -8.00e-01 -7.93e-01 -7.69e-01 -7.64e-01 -7.39e-01 -7.58e-01 -1.04e+00 -5.07e-01 -1.50e-01 -8.87e-01 -8.55e-01 -8.41e-01 -8.56e-01 -8.73e-01 -8.47e-01 -8.19e-01 -8.38e-01 -8.05e-01 -8.07e-01 -7.65e-01 -7.30e-01 -9.77e-01 -4.70e-01 -1.10e-01 -1.23e+00 -1.19e+00 -1.16e+00 -1.21e+00 -1.27e+00 -1.25e+00 -1.14e+00 -1.10e+00 -1.11e+00 -1.13e+00 -1.17e+00 -1.01e+00 -9.39e-01 -4.79e-01 -1.76e-01 -1.53e+00 -1.30e+00 -1.11e+00 -1.31e+00 -1.28e+00 -1.18e+00 -1.16e+00 -8.91e-01 -7.64e-01 -6.86e-01 -7.35e-01 -6.78e-01 -3.62e-01 -2.02e-01 -1.12e-01 -5.19e-01 -4.91e-01 -4.40e-01 -4.60e-01 -4.87e-01 -3.65e-01 -5.18e-01 -3.03e-01 -2.69e-01 -1.84e-01 -2.14e-01 -2.43e-01 -1.44e-01 -7.93e-02 -4.59e-02 -8.53e-01 -8.34e-01 -8.24e-01 -8.44e-01 -7.93e-01 -7.98e-01 -8.11e-01 -8.08e-01 -7.84e-01 -7.45e-01 -7.60e-01 -7.66e-01 -1.21e+00 -9.01e-01 -4.10e-01 -8.39e-01 -8.13e-01 -8.33e-01 -8.25e-01 -8.17e-01 -7.68e-01 -7.94e-01 -7.61e-01 -7.94e-01 -7.58e-01 -7.42e-01 -7.76e-01 -1.12e+00 -1.01e+00 -3.78e-01 -8.15e-01 -7.96e-01 -8.12e-01 -8.03e-01 -7.86e-01 -7.79e-01 -7.51e-01 -7.57e-01 -7.42e-01 -7.66e-01 -8.04e-01 -7.92e-01 -1.16e+00 -1.25e+00 -5.04e-01 -8.34e-01 -7.68e-01 -7.75e-01 -7.60e-01 -7.73e-01 -8.04e-01 -7.86e-01 -7.68e-01 -7.69e-01 -7.72e-01 -7.79e-01 -8.19e-01 -1.12e+00 -7.80e-01 -3.07e-01 -8.35e-01 -8.24e-01 -8.03e-01 -7.87e-01 -7.88e-01 -8.12e-01 -7.74e-01 -7.87e-01 -7.48e-01 -7.70e-01 -7.77e-01 -8.41e-01 -1.16e+00 -6.39e-01 -2.34e-01 -8.17e-01 -7.87e-01 -7.98e-01 -8.15e-01 -8.06e-01 -7.88e-01 -7.52e-01 -7.32e-01 -7.17e-01 -7.60e-01 -7.74e-01 -8.04e-01 -1.13e+00 -6.75e-01 -2.06e-01 -8.22e-01 -8.10e-01 -8.02e-01 -8.08e-01 -8.05e-01 -7.56e-01 -7.48e-01 -7.03e-01 -7.31e-01 -7.43e-01 -7.54e-01 -8.22e-01 -1.16e+00 -7.52e-01 -2.28e-01 -7.64e-01 -7.75e-01 -7.68e-01 -7.87e-01 -7.73e-01 -7.45e-01 -7.48e-01 -7.22e-01 -7.13e-01 -7.34e-01 -7.57e-01 -7.86e-01 -1.10e+00 -8.15e-01 -2.44e-01 -8.21e-01 -7.75e-01 -7.87e-01 -7.66e-01 -7.39e-01 -7.65e-01 -7.62e-01 -6.99e-01 -6.88e-01 -6.98e-01 -7.52e-01 -7.85e-01 -1.05e+00 -7.70e-01 -2.57e-01 -7.79e-01 -7.89e-01 -8.06e-01 -7.85e-01 -7.59e-01 -7.34e-01 -7.57e-01 -7.39e-01 -7.18e-01 -7.39e-01 -7.21e-01 -7.16e-01 -1.03e+00 -6.02e-01 -2.37e-01 -8.09e-01 -8.54e-01 -8.12e-01 -7.85e-01 -7.60e-01 -7.56e-01 -7.18e-01 -7.13e-01 -7.31e-01 -7.31e-01 -6.81e-01 -7.25e-01 -9.31e-01 -3.54e-01 -1.26e-01 -8.50e-01 -8.54e-01 -8.14e-01 -7.80e-01 -8.02e-01 -8.05e-01 -7.81e-01 -7.77e-01 -7.97e-01 -7.65e-01 -7.40e-01 -7.05e-01 -7.73e-01 -3.06e-01 -1.34e-01 -1.20e+00 -1.12e+00 -1.11e+00 -1.13e+00 -1.15e+00 -1.10e+00 -1.10e+00 -9.95e-01 -1.08e+00 -9.88e-01 -1.01e+00 -9.01e-01 -6.74e-01 -1.87e-01 -8.09e-02 -1.32e+00 -1.34e+00 -1.16e+00 -7.75e-01 -7.51e-01 -9.97e-01 -8.93e-01 -7.22e-01 -6.51e-01 -6.25e-01 -7.18e-01 -5.73e-01 -2.11e-01 -9.82e-02 -4.26e-02 -4.75e-01 -5.18e-01 -4.49e-01 -2.40e-01 -2.44e-01 -3.22e-01 -3.19e-01 -2.35e-01 -2.20e-01 -1.64e-01 -2.36e-01 -2.02e-01 -7.60e-02 -4.33e-02 -3.07e-02 -7.81e-01 -7.87e-01 -7.72e-01 -8.00e-01 -8.24e-01 -8.30e-01 -8.27e-01 -7.88e-01 -7.35e-01 -7.02e-01 -6.79e-01 -7.96e-01 -1.11e+00 -7.59e-01 -2.66e-01 -8.05e-01 -8.08e-01 -8.45e-01 -8.16e-01 -7.90e-01 -7.90e-01 -7.97e-01 -7.35e-01 -7.24e-01 -6.97e-01 -6.50e-01 -7.41e-01 -1.08e+00 -5.46e-01 -1.73e-01 -7.91e-01 -7.84e-01 -8.12e-01 -8.13e-01 -7.93e-01 -7.86e-01 -7.80e-01 -7.88e-01 -7.62e-01 -7.25e-01 -7.48e-01 -8.00e-01 -1.08e+00 -7.80e-01 -2.83e-01 -7.99e-01 -7.86e-01 -8.00e-01 -7.83e-01 -8.01e-01 -7.89e-01 -7.68e-01 -7.67e-01 -7.34e-01 -7.08e-01 -7.82e-01 -8.28e-01 -1.05e+00 -7.28e-01 -3.01e-01 -8.10e-01 -8.05e-01 -8.41e-01 -7.70e-01 -7.70e-01 -7.93e-01 -7.51e-01 -7.44e-01 -7.48e-01 -7.29e-01 -7.92e-01 -7.97e-01 -1.08e+00 -5.90e-01 -1.62e-01 -8.06e-01 -7.76e-01 -8.01e-01 -7.96e-01 -7.50e-01 -7.27e-01 -7.51e-01 -7.26e-01 -7.36e-01 -7.31e-01 -7.40e-01 -7.92e-01 -1.07e+00 -6.18e-01 -2.17e-01 -7.91e-01 -7.77e-01 -7.90e-01 -7.54e-01 -7.85e-01 -7.70e-01 -7.48e-01 -6.96e-01 -6.99e-01 -7.02e-01 -6.96e-01 -7.43e-01 -1.02e+00 -7.52e-01 -2.89e-01 -7.56e-01 -7.94e-01 -7.67e-01 -7.64e-01 -7.61e-01 -7.60e-01 -7.28e-01 -7.14e-01 -7.09e-01 -7.03e-01 -7.62e-01 -7.59e-01 -1.03e+00 -6.86e-01 -2.56e-01 -7.75e-01 -7.59e-01 -7.81e-01 -7.45e-01 -7.66e-01 -7.46e-01 -7.25e-01 -6.93e-01 -6.75e-01 -6.66e-01 -7.38e-01 -7.31e-01 -9.88e-01 -5.41e-01 -1.68e-01 -7.63e-01 -7.64e-01 -7.46e-01 -7.17e-01 -7.23e-01 -7.40e-01 -6.88e-01 -7.11e-01 -6.45e-01 -6.43e-01 -6.92e-01 -7.27e-01 -1.06e+00 -5.99e-01 -1.94e-01 -7.99e-01 -7.77e-01 -7.94e-01 -7.47e-01 -7.40e-01 -7.39e-01 -7.34e-01 -7.52e-01 -7.06e-01 -6.86e-01 -6.55e-01 -6.81e-01 -8.86e-01 -3.82e-01 -9.69e-02 -8.46e-01 -8.18e-01 -8.26e-01 -7.84e-01 -7.60e-01 -7.38e-01 -7.20e-01 -7.68e-01 -7.41e-01 -7.47e-01 -7.02e-01 -6.54e-01 -7.66e-01 -2.43e-01 -7.12e-02 -1.21e+00 -1.12e+00 -1.12e+00 -1.01e+00 -1.09e+00 -1.07e+00 -8.74e-01 -8.72e-01 -8.67e-01 -1.01e+00 -1.01e+00 -8.47e-01 -6.09e-01 -1.58e-01 -5.39e-02 -1.08e+00 -1.12e+00 -8.01e-01 -6.68e-01 -7.20e-01 -8.39e-01 -5.11e-01 -4.35e-01 -3.60e-01 -7.14e-01 -6.43e-01 -4.11e-01 -2.15e-01 -5.39e-02 -2.14e-02 -3.73e-01 -3.83e-01 -2.54e-01 -2.38e-01 -2.15e-01 -2.86e-01 -1.89e-01 -1.46e-01 -1.14e-01 -2.39e-01 -2.00e-01 -1.38e-01 -9.65e-02 -4.13e-02 -1.06e-02 -8.16e-01 -8.31e-01 -8.55e-01 -8.17e-01 -8.37e-01 -7.96e-01 -7.81e-01 -8.05e-01 -7.46e-01 -7.27e-01 -6.91e-01 -7.68e-01 -1.08e+00 -5.87e-01 -1.78e-01 -7.93e-01 -8.07e-01 -8.40e-01 -8.16e-01 -8.12e-01 -8.09e-01 -7.98e-01 -7.79e-01 -7.43e-01 -7.35e-01 -7.18e-01 -7.62e-01 -1.05e+00 -6.30e-01 -1.97e-01 -7.86e-01 -8.04e-01 -7.90e-01 -7.96e-01 -8.02e-01 -7.57e-01 -7.79e-01 -7.99e-01 -7.43e-01 -7.26e-01 -7.20e-01 -8.04e-01 -1.21e+00 -8.14e-01 -2.65e-01 -8.01e-01 -7.70e-01 -8.02e-01 -7.66e-01 -7.78e-01 -7.86e-01 -7.74e-01 -7.63e-01 -7.30e-01 -7.36e-01 -7.45e-01 -7.37e-01 -1.04e+00 -8.80e-01 -3.72e-01 -7.76e-01 -7.61e-01 -7.65e-01 -7.59e-01 -7.59e-01 -7.54e-01 -7.53e-01 -7.66e-01 -7.40e-01 -7.01e-01 -7.50e-01 -8.07e-01 -1.03e+00 -6.47e-01 -2.01e-01 -8.00e-01 -7.91e-01 -7.50e-01 -7.33e-01 -7.09e-01 -7.28e-01 -7.48e-01 -7.31e-01 -7.26e-01 -7.09e-01 -7.38e-01 -8.00e-01 -1.08e+00 -7.50e-01 -2.61e-01 -7.64e-01 -7.65e-01 -7.60e-01 -7.25e-01 -7.24e-01 -7.17e-01 -6.99e-01 -6.92e-01 -6.87e-01 -6.82e-01 -7.32e-01 -7.47e-01 -9.42e-01 -5.70e-01 -2.11e-01 -7.38e-01 -7.50e-01 -7.58e-01 -7.14e-01 -7.38e-01 -7.21e-01 -6.80e-01 -6.69e-01 -6.84e-01 -6.84e-01 -7.32e-01 -7.33e-01 -9.18e-01 -3.59e-01 -1.45e-01 -7.38e-01 -7.18e-01 -7.38e-01 -7.39e-01 -7.46e-01 -7.70e-01 -7.25e-01 -6.90e-01 -6.46e-01 -6.49e-01 -6.56e-01 -6.97e-01 -9.65e-01 -3.98e-01 -1.02e-01 -7.64e-01 -7.31e-01 -7.32e-01 -7.05e-01 -7.34e-01 -7.26e-01 -7.09e-01 -6.85e-01 -6.43e-01 -6.34e-01 -6.51e-01 -6.67e-01 -9.76e-01 -4.41e-01 -1.09e-01 -7.80e-01 -7.12e-01 -7.26e-01 -7.17e-01 -7.58e-01 -7.39e-01 -7.19e-01 -7.02e-01 -7.03e-01 -6.55e-01 -5.91e-01 -6.53e-01 -9.17e-01 -4.78e-01 -1.37e-01 -8.17e-01 -7.34e-01 -7.39e-01 -7.85e-01 -7.75e-01 -7.52e-01 -7.79e-01 -7.11e-01 -7.19e-01 -6.96e-01 -6.43e-01 -6.00e-01 -7.61e-01 -2.70e-01 -8.10e-02 -1.16e+00 -1.04e+00 -1.10e+00 -1.11e+00 -1.11e+00 -1.08e+00 -9.95e-01 -1.02e+00 -9.59e-01 -1.01e+00 -9.84e-01 -7.98e-01 -6.84e-01 -2.00e-01 -5.36e-02 -1.12e+00 -8.97e-01 -8.53e-01 -8.36e-01 -8.45e-01 -7.72e-01 -5.11e-01 -5.45e-01 -4.94e-01 -5.38e-01 -5.92e-01 -4.14e-01 -2.08e-01 -7.44e-02 -2.60e-02 -3.41e-01 -2.55e-01 -2.14e-01 -2.42e-01 -2.46e-01 -2.60e-01 -1.78e-01 -1.61e-01 -1.44e-01 -1.52e-01 -1.91e-01 -1.39e-01 -6.05e-02 -2.90e-02 -6.48e-03 -7.87e-01 -8.11e-01 -8.37e-01 -8.09e-01 -8.06e-01 -7.52e-01 -7.59e-01 -7.86e-01 -7.65e-01 -7.53e-01 -7.16e-01 -8.07e-01 -1.02e+00 -7.17e-01 -2.61e-01 -7.93e-01 -8.13e-01 -7.88e-01 -7.89e-01 -7.88e-01 -8.08e-01 -8.00e-01 -7.90e-01 -7.89e-01 -7.16e-01 -7.47e-01 -7.97e-01 -1.11e+00 -7.82e-01 -2.29e-01 -8.16e-01 -7.85e-01 -7.57e-01 -7.70e-01 -7.67e-01 -7.99e-01 -7.75e-01 -7.99e-01 -8.00e-01 -7.26e-01 -7.00e-01 -7.95e-01 -1.12e+00 -8.32e-01 -2.72e-01 -7.66e-01 -7.71e-01 -7.72e-01 -7.50e-01 -7.83e-01 -7.66e-01 -7.97e-01 -7.79e-01 -7.41e-01 -7.26e-01 -7.24e-01 -7.90e-01 -1.04e+00 -7.19e-01 -2.72e-01 -7.50e-01 -7.28e-01 -7.78e-01 -7.78e-01 -7.70e-01 -7.41e-01 -7.52e-01 -7.68e-01 -7.29e-01 -7.30e-01 -7.52e-01 -7.62e-01 -1.04e+00 -5.78e-01 -1.84e-01 -7.79e-01 -7.50e-01 -7.82e-01 -7.38e-01 -7.48e-01 -7.53e-01 -7.41e-01 -7.47e-01 -7.17e-01 -7.06e-01 -7.29e-01 -7.63e-01 -1.01e+00 -5.33e-01 -1.96e-01 -7.73e-01 -7.74e-01 -7.65e-01 -7.47e-01 -7.35e-01 -7.39e-01 -7.07e-01 -7.21e-01 -7.07e-01 -7.06e-01 -6.86e-01 -7.53e-01 -1.03e+00 -6.87e-01 -2.34e-01 -7.58e-01 -7.65e-01 -7.72e-01 -7.64e-01 -7.41e-01 -7.16e-01 -6.58e-01 -7.03e-01 -6.75e-01 -6.34e-01 -6.76e-01 -7.61e-01 -9.52e-01 -3.63e-01 -1.11e-01 -7.33e-01 -7.35e-01 -7.46e-01 -7.50e-01 -7.43e-01 -7.09e-01 -6.97e-01 -6.61e-01 -6.39e-01 -6.31e-01 -6.70e-01 -7.26e-01 -9.35e-01 -4.08e-01 -1.21e-01 -7.44e-01 -7.40e-01 -7.34e-01 -7.49e-01 -7.23e-01 -7.13e-01 -6.92e-01 -6.51e-01 -6.43e-01 -6.54e-01 -6.11e-01 -6.81e-01 -8.92e-01 -5.18e-01 -1.67e-01 -7.39e-01 -7.24e-01 -7.18e-01 -7.10e-01 -7.07e-01 -7.17e-01 -7.28e-01 -6.89e-01 -6.45e-01 -6.27e-01 -5.89e-01 -6.27e-01 -8.94e-01 -4.27e-01 -1.44e-01 -8.20e-01 -7.35e-01 -7.73e-01 -7.79e-01 -7.33e-01 -7.94e-01 -7.38e-01 -7.21e-01 -6.82e-01 -6.66e-01 -6.30e-01 -5.53e-01 -6.56e-01 -2.86e-01 -9.02e-02 -1.23e+00 -1.02e+00 -9.49e-01 -1.09e+00 -1.08e+00 -1.07e+00 -1.01e+00 -1.12e+00 -1.07e+00 -1.12e+00 -9.32e-01 -7.55e-01 -5.90e-01 -1.70e-01 -6.04e-02 -9.34e-01 -7.67e-01 -7.48e-01 -8.36e-01 -9.13e-01 -8.43e-01 -6.94e-01 -7.11e-01 -6.45e-01 -5.23e-01 -4.64e-01 -3.36e-01 -1.97e-01 -8.24e-02 -3.52e-02 -3.61e-01 -3.04e-01 -3.20e-01 -2.77e-01 -3.14e-01 -2.79e-01 -2.19e-01 -2.01e-01 -2.23e-01 -1.68e-01 -1.56e-01 -1.06e-01 -6.15e-02 -3.90e-02 -1.78e-02 -7.55e-01 -7.78e-01 -8.17e-01 -8.31e-01 -8.37e-01 -8.23e-01 -8.31e-01 -8.49e-01 -7.67e-01 -7.79e-01 -7.53e-01 -7.56e-01 -9.13e-01 -4.87e-01 -1.90e-01 -7.63e-01 -7.96e-01 -7.72e-01 -7.84e-01 -8.07e-01 -7.97e-01 -7.85e-01 -7.92e-01 -7.90e-01 -7.89e-01 -7.62e-01 -7.60e-01 -9.99e-01 -6.50e-01 -2.08e-01 -7.70e-01 -7.78e-01 -7.67e-01 -8.10e-01 -7.76e-01 -7.97e-01 -8.29e-01 -7.63e-01 -7.81e-01 -7.78e-01 -7.59e-01 -7.86e-01 -1.06e+00 -7.09e-01 -2.39e-01 -7.64e-01 -7.94e-01 -8.36e-01 -7.73e-01 -8.21e-01 -8.29e-01 -8.06e-01 -7.74e-01 -7.69e-01 -7.48e-01 -7.26e-01 -7.70e-01 -1.04e+00 -5.38e-01 -1.72e-01 -7.68e-01 -7.86e-01 -7.98e-01 -7.72e-01 -8.10e-01 -7.96e-01 -7.80e-01 -7.69e-01 -7.86e-01 -7.59e-01 -7.61e-01 -7.80e-01 -1.02e+00 -4.87e-01 -1.43e-01 -7.60e-01 -7.84e-01 -7.88e-01 -8.10e-01 -7.80e-01 -7.87e-01 -7.60e-01 -7.40e-01 -7.18e-01 -7.35e-01 -7.48e-01 -7.57e-01 -1.06e+00 -5.45e-01 -1.46e-01 -7.56e-01 -7.71e-01 -7.41e-01 -7.88e-01 -7.68e-01 -7.62e-01 -7.57e-01 -7.22e-01 -7.18e-01 -7.13e-01 -7.27e-01 -7.54e-01 -9.95e-01 -6.13e-01 -1.70e-01 -7.39e-01 -7.50e-01 -7.74e-01 -7.93e-01 -7.34e-01 -7.32e-01 -6.83e-01 -7.01e-01 -7.06e-01 -7.36e-01 -7.12e-01 -7.25e-01 -9.34e-01 -5.51e-01 -1.95e-01 -7.17e-01 -7.39e-01 -7.59e-01 -7.62e-01 -7.78e-01 -7.43e-01 -6.89e-01 -6.89e-01 -6.69e-01 -6.52e-01 -6.30e-01 -6.68e-01 -9.23e-01 -4.29e-01 -1.22e-01 -7.39e-01 -7.23e-01 -7.35e-01 -7.50e-01 -7.65e-01 -7.07e-01 -6.87e-01 -6.74e-01 -6.35e-01 -6.34e-01 -6.14e-01 -6.22e-01 -7.74e-01 -4.07e-01 -1.43e-01 -7.20e-01 -7.36e-01 -7.25e-01 -7.20e-01 -7.27e-01 -7.02e-01 -7.08e-01 -6.86e-01 -6.37e-01 -6.43e-01 -5.84e-01 -6.05e-01 -8.14e-01 -2.50e-01 -7.65e-02 -7.35e-01 -7.38e-01 -7.34e-01 -7.63e-01 -7.24e-01 -7.52e-01 -7.60e-01 -7.35e-01 -6.72e-01 -6.44e-01 -6.12e-01 -5.65e-01 -6.76e-01 -2.27e-01 -7.04e-02 -1.03e+00 -9.44e-01 -9.23e-01 -1.03e+00 -1.07e+00 -1.05e+00 -9.55e-01 -9.95e-01 -9.86e-01 -8.94e-01 -8.68e-01 -7.36e-01 -3.85e-01 -9.70e-02 -3.48e-02 -8.54e-01 -4.54e-01 -5.88e-01 -6.14e-01 -6.53e-01 -6.43e-01 -5.10e-01 -6.95e-01 -5.75e-01 -3.80e-01 -4.09e-01 -2.64e-01 -1.34e-01 -5.20e-02 -1.59e-02 -2.77e-01 -1.44e-01 -1.76e-01 -1.86e-01 -2.54e-01 -2.23e-01 -1.61e-01 -2.31e-01 -1.97e-01 -1.30e-01 -1.16e-01 -6.26e-02 -4.81e-02 -3.06e-02 -1.67e-02 -7.86e-01 -8.39e-01 -8.82e-01 -8.55e-01 -8.50e-01 -8.79e-01 -8.60e-01 -8.12e-01 -8.09e-01 -7.89e-01 -7.90e-01 -7.42e-01 -7.44e-01 -1.58e-01 -6.48e-02 -8.67e-01 -8.89e-01 -8.72e-01 -8.03e-01 -7.98e-01 -8.19e-01 -8.35e-01 -8.10e-01 -7.91e-01 -7.79e-01 -7.97e-01 -7.65e-01 -8.12e-01 -2.69e-01 -1.15e-01 -8.28e-01 -8.91e-01 -8.28e-01 -8.22e-01 -8.14e-01 -8.56e-01 -8.86e-01 -8.46e-01 -7.76e-01 -7.84e-01 -7.49e-01 -8.31e-01 -1.07e+00 -4.88e-01 -1.30e-01 -8.26e-01 -8.49e-01 -8.39e-01 -8.27e-01 -8.44e-01 -8.70e-01 -8.88e-01 -8.04e-01 -8.19e-01 -7.85e-01 -7.20e-01 -7.52e-01 -9.62e-01 -4.26e-01 -1.46e-01 -8.01e-01 -7.89e-01 -8.03e-01 -8.28e-01 -8.39e-01 -8.53e-01 -8.18e-01 -8.07e-01 -8.12e-01 -8.02e-01 -7.19e-01 -7.09e-01 -9.85e-01 -5.13e-01 -1.40e-01 -7.74e-01 -8.11e-01 -7.91e-01 -8.10e-01 -8.13e-01 -8.20e-01 -7.99e-01 -7.62e-01 -7.73e-01 -7.84e-01 -7.21e-01 -7.04e-01 -9.41e-01 -4.52e-01 -1.46e-01 -7.47e-01 -7.56e-01 -8.11e-01 -8.22e-01 -8.04e-01 -7.79e-01 -7.83e-01 -7.46e-01 -7.28e-01 -7.40e-01 -7.25e-01 -7.07e-01 -8.17e-01 -4.63e-01 -1.62e-01 -7.58e-01 -7.56e-01 -7.60e-01 -7.96e-01 -7.87e-01 -7.69e-01 -7.75e-01 -7.58e-01 -7.39e-01 -7.10e-01 -7.14e-01 -7.27e-01 -9.10e-01 -3.49e-01 -1.16e-01 -7.76e-01 -7.69e-01 -7.90e-01 -7.93e-01 -7.91e-01 -8.11e-01 -7.48e-01 -7.33e-01 -7.10e-01 -7.10e-01 -6.65e-01 -6.83e-01 -8.72e-01 -3.27e-01 -1.09e-01 -7.58e-01 -7.27e-01 -8.00e-01 -7.89e-01 -7.90e-01 -7.69e-01 -7.48e-01 -6.87e-01 -6.49e-01 -6.32e-01 -6.50e-01 -6.16e-01 -8.53e-01 -3.55e-01 -1.26e-01 -7.12e-01 -7.03e-01 -7.35e-01 -7.34e-01 -7.90e-01 -7.42e-01 -6.78e-01 -6.75e-01 -6.64e-01 -6.43e-01 -5.93e-01 -5.68e-01 -7.24e-01 -2.12e-01 -6.37e-02 -7.13e-01 -6.99e-01 -7.21e-01 -7.24e-01 -7.11e-01 -6.84e-01 -7.09e-01 -7.37e-01 -6.65e-01 -6.48e-01 -5.74e-01 -5.37e-01 -6.18e-01 -1.95e-01 -5.93e-02 -9.23e-01 -8.49e-01 -8.63e-01 -9.07e-01 -8.87e-01 -8.82e-01 -8.74e-01 -9.65e-01 -9.71e-01 -7.90e-01 -7.23e-01 -6.21e-01 -3.58e-01 -1.02e-01 -3.58e-02 -6.33e-01 -3.23e-01 -4.14e-01 -5.18e-01 -3.93e-01 -3.93e-01 -3.52e-01 -3.37e-01 -5.09e-01 -3.80e-01 -2.69e-01 -2.08e-01 -1.27e-01 -3.00e-02 -9.83e-03 -2.53e-01 -1.24e-01 -1.72e-01 -1.82e-01 -1.42e-01 -1.35e-01 -1.17e-01 -1.22e-01 -1.56e-01 -1.28e-01 -7.82e-02 -7.58e-02 -4.95e-02 -1.63e-02 -7.34e-03 -1.15e+00 -1.21e+00 -1.27e+00 -1.27e+00 -1.26e+00 -1.19e+00 -1.15e+00 -1.14e+00 -1.15e+00 -1.04e+00 -1.01e+00 -1.07e+00 -8.04e-01 -1.47e-01 -3.71e-02 -1.23e+00 -1.11e+00 -1.30e+00 -1.15e+00 -1.15e+00 -1.20e+00 -1.17e+00 -1.09e+00 -1.02e+00 -1.06e+00 -9.84e-01 -9.61e-01 -9.02e-01 -2.44e-01 -7.45e-02 -1.19e+00 -1.09e+00 -1.26e+00 -1.15e+00 -1.13e+00 -1.22e+00 -1.07e+00 -1.19e+00 -1.10e+00 -1.09e+00 -1.01e+00 -9.62e-01 -1.10e+00 -4.73e-01 -1.47e-01 -1.18e+00 -1.14e+00 -1.17e+00 -1.20e+00 -1.17e+00 -1.28e+00 -1.19e+00 -1.18e+00 -1.12e+00 -1.04e+00 -9.10e-01 -8.02e-01 -9.06e-01 -2.84e-01 -8.05e-02 -1.14e+00 -1.09e+00 -1.13e+00 -1.18e+00 -1.11e+00 -1.18e+00 -1.35e+00 -1.16e+00 -1.15e+00 -1.16e+00 -1.00e+00 -7.35e-01 -7.88e-01 -3.90e-01 -1.47e-01 -1.14e+00 -1.03e+00 -1.10e+00 -1.12e+00 -1.06e+00 -1.15e+00 -1.16e+00 -1.07e+00 -1.05e+00 -1.12e+00 -9.87e-01 -8.55e-01 -8.93e-01 -3.76e-01 -1.15e-01 -1.02e+00 -1.04e+00 -1.14e+00 -1.09e+00 -1.05e+00 -1.11e+00 -1.08e+00 -1.04e+00 -8.85e-01 -1.00e+00 -9.45e-01 -7.84e-01 -8.14e-01 -2.74e-01 -8.75e-02 -1.04e+00 -1.06e+00 -1.04e+00 -1.12e+00 -1.18e+00 -1.13e+00 -1.06e+00 -1.05e+00 -9.34e-01 -9.47e-01 -9.38e-01 -8.93e-01 -6.67e-01 -1.52e-01 -5.28e-02 -1.04e+00 -1.07e+00 -1.06e+00 -1.13e+00 -1.13e+00 -1.03e+00 -1.15e+00 -1.11e+00 -9.63e-01 -1.01e+00 -9.05e-01 -8.67e-01 -8.37e-01 -2.04e-01 -6.93e-02 -1.00e+00 -1.10e+00 -1.14e+00 -1.07e+00 -1.14e+00 -1.03e+00 -1.08e+00 -9.61e-01 -8.93e-01 -8.70e-01 -8.58e-01 -8.57e-01 -8.01e-01 -2.31e-01 -7.13e-02 -9.12e-01 -9.60e-01 -1.08e+00 -1.07e+00 -1.06e+00 -1.13e+00 -9.68e-01 -8.42e-01 -8.21e-01 -7.51e-01 -7.76e-01 -7.41e-01 -5.22e-01 -2.01e-01 -7.22e-02 -7.80e-01 -7.99e-01 -9.64e-01 -9.33e-01 -9.70e-01 -1.00e+00 -1.03e+00 -9.27e-01 -8.81e-01 -7.47e-01 -6.96e-01 -6.90e-01 -5.22e-01 -1.42e-01 -5.84e-02 -6.66e-01 -7.30e-01 -8.24e-01 -7.89e-01 -8.68e-01 -8.50e-01 -6.87e-01 -9.72e-01 -9.67e-01 -8.19e-01 -6.02e-01 -5.08e-01 -3.32e-01 -9.24e-02 -4.14e-02 -3.42e-01 -2.04e-01 -2.56e-01 -3.06e-01 -2.44e-01 -2.32e-01 -1.97e-01 -2.37e-01 -4.25e-01 -2.80e-01 -1.20e-01 -1.22e-01 -6.52e-02 -2.34e-02 -1.33e-02 -1.30e-01 -6.51e-02 -9.03e-02 -9.81e-02 -7.43e-02 -7.44e-02 -7.50e-02 -7.08e-02 -1.36e-01 -1.08e-01 -5.23e-02 -3.86e-02 -2.05e-02 -1.18e-02 -4.82e-03 -1.10e+00 -1.08e+00 -1.36e+00 -9.59e-01 -1.50e+00 -1.22e+00 -1.06e+00 -1.09e+00 -9.39e-01 -8.29e-01 -5.63e-01 -6.05e-01 -5.41e-01 -1.46e-01 -4.18e-02 -1.38e+00 -9.47e-01 -1.64e+00 -1.82e+00 -1.45e+00 -1.17e+00 -9.32e-01 -9.52e-01 -7.63e-01 -6.75e-01 -6.06e-01 -5.05e-01 -4.40e-01 -1.95e-01 -6.83e-02 -1.18e+00 -1.14e+00 -1.46e+00 -1.11e+00 -8.51e-01 -1.15e+00 -9.29e-01 -9.75e-01 -8.23e-01 -7.12e-01 -8.66e-01 -6.90e-01 -3.69e-01 -2.08e-01 -1.46e-01 -1.36e+00 -1.17e+00 -1.39e+00 -1.53e+00 -1.15e+00 -1.26e+00 -1.34e+00 -1.20e+00 -1.06e+00 -8.13e-01 -6.01e-01 -4.19e-01 -2.92e-01 -1.43e-01 -6.62e-02 -1.31e+00 -9.58e-01 -1.27e+00 -1.56e+00 -1.32e+00 -1.38e+00 -1.36e+00 -1.10e+00 -9.06e-01 -8.42e-01 -7.44e-01 -3.53e-01 -2.51e-01 -1.27e-01 -6.42e-02 -1.05e+00 -8.06e-01 -1.10e+00 -1.14e+00 -7.77e-01 -8.88e-01 -1.08e+00 -7.49e-01 -6.61e-01 -8.78e-01 -7.85e-01 -5.07e-01 -2.81e-01 -1.16e-01 -7.65e-02 -7.49e-01 -9.07e-01 -1.01e+00 -1.02e+00 -8.96e-01 -9.71e-01 -9.06e-01 -7.59e-01 -6.31e-01 -5.64e-01 -4.58e-01 -3.36e-01 -1.97e-01 -1.17e-01 -7.24e-02 -5.31e-01 -7.16e-01 -8.03e-01 -7.87e-01 -9.01e-01 -9.00e-01 -6.17e-01 -6.08e-01 -4.09e-01 -3.65e-01 -4.67e-01 -3.69e-01 -1.95e-01 -1.03e-01 -4.09e-02 -5.66e-01 -6.84e-01 -8.03e-01 -1.10e+00 -8.56e-01 -7.53e-01 -5.80e-01 -7.25e-01 -5.65e-01 -5.23e-01 -4.71e-01 -3.57e-01 -2.67e-01 -9.56e-02 -3.66e-02 -4.28e-01 -7.89e-01 -1.04e+00 -7.98e-01 -6.86e-01 -4.17e-01 -5.80e-01 -6.93e-01 -5.76e-01 -4.61e-01 -4.35e-01 -3.12e-01 -2.15e-01 -1.24e-01 -3.78e-02 -4.61e-01 -5.64e-01 -7.98e-01 -5.21e-01 -7.00e-01 -6.75e-01 -5.39e-01 -5.12e-01 -4.28e-01 -2.95e-01 -3.73e-01 -3.14e-01 -1.91e-01 -1.02e-01 -4.60e-02 -3.92e-01 -3.42e-01 -5.06e-01 -4.71e-01 -4.73e-01 -6.89e-01 -5.67e-01 -3.20e-01 -3.01e-01 -2.61e-01 -2.32e-01 -2.34e-01 -1.79e-01 -4.62e-02 -1.73e-02 -1.91e-01 -2.50e-01 -3.10e-01 -2.40e-01 -2.89e-01 -4.18e-01 -3.43e-01 -3.33e-01 -2.60e-01 -2.88e-01 -2.00e-01 -1.73e-01 -1.35e-01 -4.58e-02 -1.87e-02 -8.30e-02 -9.70e-02 -1.13e-01 -8.94e-02 -1.22e-01 -1.54e-01 -1.00e-01 -1.45e-01 -1.68e-01 -1.41e-01 -7.91e-02 -5.48e-02 -3.66e-02 -1.92e-02 -9.23e-03 -6.77e-02 -3.66e-02 -4.21e-02 -4.05e-02 -4.50e-02 -5.61e-02 -2.78e-02 -4.65e-02 -7.38e-02 -6.93e-02 -3.15e-02 -1.71e-02 -1.50e-02 -7.02e-03 -2.63e-03 -3.78e-01 -3.76e-01 -5.09e-01 -3.31e-01 -5.46e-01 -4.00e-01 -3.73e-01 -3.85e-01 -3.61e-01 -2.87e-01 -1.88e-01 -1.85e-01 -1.79e-01 -1.07e-01 -3.77e-02 -5.65e-01 -2.57e-01 -5.55e-01 -7.39e-01 -6.13e-01 -4.33e-01 -3.29e-01 -2.97e-01 -2.89e-01 -2.50e-01 -1.89e-01 -1.46e-01 -1.32e-01 -8.81e-02 -4.17e-02 -4.36e-01 -3.41e-01 -5.13e-01 -4.96e-01 -2.34e-01 -4.00e-01 -3.27e-01 -2.87e-01 -2.94e-01 -2.08e-01 -3.02e-01 -2.63e-01 -1.41e-01 -5.88e-02 -6.26e-02 -4.46e-01 -3.47e-01 -5.27e-01 -6.11e-01 -3.91e-01 -4.22e-01 -4.76e-01 -4.54e-01 -4.31e-01 -3.19e-01 -2.13e-01 -1.47e-01 -9.76e-02 -5.82e-02 -2.92e-02 -5.35e-01 -3.74e-01 -4.80e-01 -5.78e-01 -5.02e-01 -4.78e-01 -5.06e-01 -3.61e-01 -3.58e-01 -2.46e-01 -2.55e-01 -1.07e-01 -6.95e-02 -4.27e-02 -2.71e-02 -3.15e-01 -2.73e-01 -3.47e-01 -3.78e-01 -2.88e-01 -2.50e-01 -3.39e-01 -2.40e-01 -2.15e-01 -2.65e-01 -2.87e-01 -2.16e-01 -1.00e-01 -4.10e-02 -2.09e-02 -3.10e-01 -2.99e-01 -3.67e-01 -3.96e-01 -2.30e-01 -2.86e-01 -3.00e-01 -2.63e-01 -2.50e-01 -1.99e-01 -1.56e-01 -1.31e-01 -7.20e-02 -3.22e-02 -3.48e-02 -1.47e-01 -2.69e-01 -2.47e-01 -2.40e-01 -2.82e-01 -3.03e-01 -1.85e-01 -1.94e-01 -1.29e-01 -1.02e-01 -1.25e-01 -1.15e-01 -5.95e-02 -5.42e-02 -4.17e-02 -1.81e-01 -2.00e-01 -2.60e-01 -3.31e-01 -3.21e-01 -2.95e-01 -1.85e-01 -2.44e-01 -2.00e-01 -1.66e-01 -1.43e-01 -1.23e-01 -1.02e-01 -4.36e-02 -1.72e-02 -1.08e-01 -2.40e-01 -3.14e-01 -3.12e-01 -2.21e-01 -1.20e-01 -1.86e-01 -2.21e-01 -2.13e-01 -1.40e-01 -1.31e-01 -1.05e-01 -5.58e-02 -6.38e-02 -3.45e-02 -1.48e-01 -2.44e-01 -2.92e-01 -1.42e-01 -2.29e-01 -1.89e-01 -1.21e-01 -1.73e-01 -1.54e-01 -1.09e-01 -1.16e-01 -8.49e-02 -6.30e-02 -4.98e-02 -4.02e-02 -1.01e-01 -1.10e-01 -1.55e-01 -1.40e-01 -1.46e-01 -2.37e-01 -1.93e-01 -1.34e-01 -9.47e-02 -8.48e-02 -7.21e-02 -7.09e-02 -7.53e-02 -2.10e-02 -7.74e-03 -8.60e-02 -8.49e-02 -1.09e-01 -1.25e-01 -9.19e-02 -1.59e-01 -1.27e-01 -1.01e-01 -6.87e-02 -9.44e-02 -5.12e-02 -5.73e-02 -5.81e-02 -1.92e-02 -6.09e-03 -2.72e-02 -4.77e-02 -4.74e-02 -3.34e-02 -5.41e-02 -7.93e-02 -6.69e-02 -7.67e-02 -9.31e-02 -5.17e-02 -5.34e-02 -3.25e-02 -1.99e-02 -1.19e-02 -1.14e-02 -2.23e-02 -2.53e-02 -2.61e-02 -2.28e-02 -2.86e-02 -5.00e-02 -3.04e-02 -2.98e-02 -5.98e-02 -4.02e-02 -2.97e-02 -1.80e-02 -6.73e-03 -4.41e-03 -7.35e-03 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/test.py b/tests/regression_tests/weightwindows_fw_cadis_mesh/test.py deleted file mode 100644 index 680e9dc6d..000000000 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/test.py +++ /dev/null @@ -1,49 +0,0 @@ -import os - -import openmc -from openmc.utility_funcs import change_directory -from openmc.examples import random_ray_three_region_cube -import pytest - -from tests.testing_harness import WeightWindowPyAPITestHarness - - -class MGXSTestHarness(WeightWindowPyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) - - -@pytest.mark.parametrize("shape", ["flat", "linear"]) -def test_weight_windows_fw_cadis_mesh(shape): - with change_directory(shape): - openmc.reset_auto_ids() - - model = random_ray_three_region_cube() - - # The base model has a resolution of 12, so we overlay - # something else for FW-CADIS - n = 15 - width = 30.0 - ww_mesh = openmc.RegularMesh() - 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=model.settings.batches) - model.settings.weight_window_generators = wwg - - root = model.geometry.root_universe - model.settings.random_ray['source_region_meshes'] = [(ww_mesh, [root])] - - model.settings.particles = 750 - model.settings.batches = 30 - model.settings.inactive = 20 - - model.settings.random_ray['source_shape'] = shape - - harness = MGXSTestHarness('statepoint.30.h5', model) - harness.main() diff --git a/tests/regression_tests/weightwindows_pulse_height/__init__.py b/tests/regression_tests/weightwindows_pulse_height/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/weightwindows_pulse_height/local/inputs_true.dat b/tests/regression_tests/weightwindows_pulse_height/local/inputs_true.dat deleted file mode 100644 index 4cd24d529..000000000 --- a/tests/regression_tests/weightwindows_pulse_height/local/inputs_true.dat +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - fixed source - 100 - 5 - - - 1000000.0 1.0 - - - true - - 1 - photon - 0.0 2000000.0 - 0.01 - 0.05 - 3.0 - 10 - 1e-38 - - - 1 1 1 - -2 -2 -2 - 2 2 2 - - false - - true - true - - 50 - - - - 1 - - - 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 - - - 1 2 - pulse-height - - - diff --git a/tests/regression_tests/weightwindows_pulse_height/local/results_true.dat b/tests/regression_tests/weightwindows_pulse_height/local/results_true.dat deleted file mode 100644 index c57e8ff1c..000000000 --- a/tests/regression_tests/weightwindows_pulse_height/local/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -4.140000E+00 -3.443000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -2.000000E-02 -4.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.000000E-02 -3.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.000000E-02 -6.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.600000E-03 diff --git a/tests/regression_tests/weightwindows_pulse_height/shared/inputs_true.dat b/tests/regression_tests/weightwindows_pulse_height/shared/inputs_true.dat deleted file mode 100644 index 8bb499a73..000000000 --- a/tests/regression_tests/weightwindows_pulse_height/shared/inputs_true.dat +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - fixed source - 100 - 5 - - - 1000000.0 1.0 - - - true - - 1 - photon - 0.0 2000000.0 - 0.01 - 0.05 - 3.0 - 10 - 1e-38 - - - 1 1 1 - -2 -2 -2 - 2 2 2 - - true - - true - true - - 50 - - - - 1 - - - 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 - - - 1 2 - pulse-height - - - diff --git a/tests/regression_tests/weightwindows_pulse_height/shared/results_true.dat b/tests/regression_tests/weightwindows_pulse_height/shared/results_true.dat deleted file mode 100644 index c57e8ff1c..000000000 --- a/tests/regression_tests/weightwindows_pulse_height/shared/results_true.dat +++ /dev/null @@ -1,201 +0,0 @@ -tally 1: -4.140000E+00 -3.443000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -2.000000E-02 -4.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.000000E-02 -3.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -4.000000E-02 -6.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -4.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -2.000000E-02 -2.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -3.000000E-02 -5.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -1.000000E-02 -1.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-02 -2.000000E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.000000E-01 -8.600000E-03 diff --git a/tests/regression_tests/weightwindows_pulse_height/test.py b/tests/regression_tests/weightwindows_pulse_height/test.py deleted file mode 100644 index b6b49be26..000000000 --- a/tests/regression_tests/weightwindows_pulse_height/test.py +++ /dev/null @@ -1,73 +0,0 @@ -import numpy as np -import openmc -import pytest -from openmc.utility_funcs import change_directory - -from tests.testing_harness import PyAPITestHarness - - -@pytest.mark.parametrize("shared_secondary,subdir", [ - (False, "local"), - (True, "shared"), -]) -def test_weightwindows_pulse_height(shared_secondary, subdir): - with change_directory(subdir): - openmc.reset_auto_ids() - model = openmc.Model() - - # Define materials (NaI scintillator) - NaI = openmc.Material() - NaI.set_density('g/cc', 3.7) - NaI.add_element('Na', 1.0) - NaI.add_element('I', 1.0) - - model.materials = openmc.Materials([NaI]) - - # Define geometry: NaI sphere inside vacuum sphere - s1 = openmc.Sphere(r=1) - s2 = openmc.Sphere(r=2, boundary_type='vacuum') - inner_sphere = openmc.Cell(name='inner sphere', fill=NaI, region=-s1) - outer_sphere = openmc.Cell(name='outer sphere', region=+s1 & -s2) - model.geometry = openmc.Geometry([inner_sphere, outer_sphere]) - - # Define settings - model.settings.run_mode = 'fixed source' - model.settings.batches = 5 - model.settings.particles = 100 - model.settings.photon_transport = True - model.settings.shared_secondary_bank = shared_secondary - model.settings.max_history_splits = 50 - model.settings.weight_window_checkpoints = { - 'surface': True, - 'collision': True, - } - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(1e6), - particle='photon' - ) - - # Define pulse-height tally - tally = openmc.Tally(name="pht tally") - tally.scores = ['pulse-height'] - cell_filter = openmc.CellFilter(inner_sphere) - energy_filter = openmc.EnergyFilter(np.linspace(0, 1_000_000, 101)) - tally.filters = [cell_filter, energy_filter] - model.tallies = [tally] - - # Define weight windows on a simple mesh covering the geometry - ww_mesh = openmc.RegularMesh() - ww_mesh.lower_left = (-2, -2, -2) - ww_mesh.upper_right = (2, 2, 2) - ww_mesh.dimension = (1, 1, 1) - - # Single energy bin for photons - e_bnds = [0.0, 2e6] - - # Uniform weight window bounds (low enough to trigger some splitting) - lower_bounds = np.array([0.01]) - - ww = openmc.WeightWindows(ww_mesh, lower_bounds, None, 5.0, e_bnds, 'photon') - model.settings.weight_windows = [ww] - - harness = PyAPITestHarness('statepoint.5.h5', model) - harness.main() diff --git a/tests/regression_tests/white_plane/results_true.dat b/tests/regression_tests/white_plane/results_true.dat index ffb19491d..dea369205 100644 --- a/tests/regression_tests/white_plane/results_true.dat +++ b/tests/regression_tests/white_plane/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.274312E+00 4.223342E-03 +2.279902E+00 3.262078E-03 diff --git a/tests/test_matplotlib_import.py b/tests/test_matplotlib_import.py deleted file mode 100644 index d319976c4..000000000 --- a/tests/test_matplotlib_import.py +++ /dev/null @@ -1,6 +0,0 @@ -import sys -import openmc - -def test_matplotlib_presence(): - """Checks that matplotlib remains a deferred import""" - assert 'matplotlib' not in sys.modules diff --git a/tests/testing_harness.py b/tests/testing_harness.py index c1977556d..9a6db2a2e 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -1,7 +1,6 @@ from difflib import unified_diff import filecmp import glob -import h5py import hashlib import os import shutil @@ -68,7 +67,7 @@ class TestHarness: if config['mpi']: mpi_args = [config['mpiexec'], '-n', config['mpi_np']] openmc.run(openmc_exec=config['exe'], mpi_args=mpi_args, - event_based=config['event']) + event_based=config['event']) else: openmc.run(openmc_exec=config['exe'], event_based=config['event']) @@ -143,8 +142,7 @@ class TestHarness: def _cleanup(self): """Delete statepoints, tally, and test files.""" output = glob.glob('statepoint.*.h5') - output += ['tallies.out', 'tallies.forward.out'] - output += ['results_test.dat', 'summary.h5'] + output += ['tallies.out', 'results_test.dat', 'summary.h5'] output += glob.glob('volume_*.h5') for f in output: if os.path.exists(f): @@ -181,7 +179,7 @@ class CMFDTestHarness(TestHarness): outstr += '\ncmfd openmc source comparison\n' outstr += '\n'.join(['{:.6E}'.format(x) for x in cmfd_run.src_cmp]) outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.prod(cmfd_run.indices), + cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.product(cmfd_run.indices), order='F') outstr += '\n'.join(['{:.6E}'.format(x) for x in cmfdsrc]) outstr += '\n' @@ -278,13 +276,6 @@ class ParticleRestartTestHarness(TestHarness): return outstr - def _cleanup(self): - """Delete particle restart files.""" - super()._cleanup() - output = glob.glob('particle*.h5') - for f in output: - os.remove(f) - class PyAPITestHarness(TestHarness): def __init__(self, statepoint_name, model=None, inputs_true=None): @@ -306,12 +297,9 @@ class PyAPITestHarness(TestHarness): else: self.execute_test() - def execute_test(self, change_dir=False): + def execute_test(self): """Build input XMLs, run OpenMC, and verify correct results.""" - base_dir = os.getcwd() if change_dir else None try: - if change_dir: - os.chdir(self.workdir) self._build_inputs() inputs = self._get_inputs() self._write_inputs(inputs) @@ -323,15 +311,10 @@ class PyAPITestHarness(TestHarness): self._compare_results() finally: self._cleanup() - if base_dir: - os.chdir(base_dir) - def update_results(self, change_dir=False): + def update_results(self): """Update results_true.dat and inputs_true.dat""" - base_dir = os.getcwd() if change_dir else None try: - if change_dir: - os.chdir(self.workdir) self._build_inputs() inputs = self._get_inputs() self._write_inputs(inputs) @@ -343,16 +326,15 @@ class PyAPITestHarness(TestHarness): self._overwrite_results() finally: self._cleanup() - if base_dir: - os.chdir(base_dir) def _build_inputs(self): """Write input XML files.""" - self._model.export_to_model_xml() + self._model.export_to_xml() def _get_inputs(self): """Return a hash digest of the input XML files.""" - xmls = ['model.xml', 'plots.xml'] + xmls = ['geometry.xml', 'materials.xml', 'settings.xml', + 'tallies.xml', 'plots.xml'] return ''.join([open(fname).read() for fname in xmls if os.path.exists(fname)]) @@ -382,8 +364,7 @@ class PyAPITestHarness(TestHarness): """Delete XMLs, statepoints, tally, and test files.""" super()._cleanup() output = ['materials.xml', 'geometry.xml', 'settings.xml', - 'tallies.xml', 'plots.xml', 'inputs_test.dat', 'model.xml', - 'collision_track.h5', 'collision_track.mcpl'] + 'tallies.xml', 'plots.xml', 'inputs_test.dat'] for f in output: if os.path.exists(f): os.remove(f) @@ -393,269 +374,3 @@ class HashedPyAPITestHarness(PyAPITestHarness): def _get_results(self): """Digest info in the statepoint and return as a string.""" return super()._get_results(True) - - -class TolerantPyAPITestHarness(PyAPITestHarness): - """Specialized harness for running tests that involve significant levels - of floating point non-associativity when using shared memory parallelism - due to single precision usage (e.g., as in the random ray solver). - - """ - - def _are_files_equal(self, actual_path, expected_path, tolerance): - def isfloat(value): - try: - float(value) - return True - except ValueError: - return False - - def tokenize(line): - return line.strip().split() - - def compare_tokens(token1, token2): - if isfloat(token1) and isfloat(token2): - float1, float2 = float(token1), float(token2) - return abs(float1 - float2) <= tolerance * max(abs(float1), abs(float2)) - else: - return token1 == token2 - - expected = open(expected_path).readlines() - actual = open(actual_path).readlines() - - if len(expected) != len(actual): - return False - - for line1, line2 in zip(expected, actual): - tokens1 = tokenize(line1) - tokens2 = tokenize(line2) - - if len(tokens1) != len(tokens2): - return False - - for token1, token2 in zip(tokens1, tokens2): - if not compare_tokens(token1, token2): - return False - - return True - - def _compare_results(self): - """Make sure the current results agree with the reference.""" - compare = self._are_files_equal( - 'results_test.dat', 'results_true.dat', 1e-6) - if not compare: - expected = open('results_true.dat').readlines() - actual = open('results_test.dat').readlines() - diff = unified_diff(expected, actual, 'results_true.dat', - 'results_test.dat') - print('Result differences:') - print(''.join(colorize(diff))) - os.rename('results_test.dat', 'results_error.dat') - assert compare, 'Results do not agree' - - -class WeightWindowPyAPITestHarness(PyAPITestHarness): - def _get_results(self): - """Digest info in the weight window file and return as a string.""" - ww = openmc.WeightWindowsList.from_hdf5()[0] - - # Access the weight window bounds - lower_bound = ww.lower_ww_bounds - upper_bound = ww.upper_ww_bounds - - # Flatten both arrays - flattened_lower_bound = lower_bound.flatten() - flattened_upper_bound = upper_bound.flatten() - - # Convert each element to a string in scientific notation with 2 decimal places - formatted_lower_bound = [f'{x:.2e}' for x in flattened_lower_bound] - formatted_upper_bound = [f'{x:.2e}' for x in flattened_upper_bound] - - # Concatenate the formatted arrays - concatenated_strings = ["Lower Bounds"] + formatted_lower_bound + \ - ["Upper Bounds"] + formatted_upper_bound - - # Join the concatenated strings into a single string with newline characters - final_string = '\n'.join(concatenated_strings) - - # Prepend the mesh text description and return final string - return str(ww.mesh) + final_string - - def _cleanup(self): - super()._cleanup() - f = 'weight_windows.h5' - if os.path.exists(f): - os.remove(f) - - -class PlotTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC plotting tests.""" - - def __init__(self, plot_names, voxel_convert_checks=[]): - super().__init__(None) - self._plot_names = plot_names - self._voxel_convert_checks = voxel_convert_checks - - def _run_openmc(self): - openmc.plot_geometry(openmc_exec=config['exe']) - - # Check that voxel h5 can be converted to vtk - for voxel_h5_filename in self._voxel_convert_checks: - openmc.voxel_to_vtk(voxel_h5_filename) - - def _test_output_created(self): - """Make sure *.png has been created.""" - for fname in self._plot_names: - assert os.path.exists(fname), 'Plot output file does not exist.' - - def _cleanup(self): - super()._cleanup() - for fname in self._plot_names: - if os.path.exists(fname): - os.remove(fname) - - def _get_results(self): - """Return a string hash of the plot files.""" - outstr = bytes() - - for fname in self._plot_names: - if fname.endswith('.png'): - # Add PNG output to results - with open(fname, 'rb') as fh: - outstr += fh.read() - elif fname.endswith('.h5'): - # Add voxel data to results - with h5py.File(fname, 'r') as fh: - outstr += fh.attrs['filetype'] - outstr += fh.attrs['num_voxels'].tobytes() - outstr += fh.attrs['lower_left'].tobytes() - outstr += fh.attrs['voxel_width'].tobytes() - outstr += fh['data'][()].tobytes() - - # Hash the information and return. - sha512 = hashlib.sha512() - sha512.update(outstr) - outstr = sha512.hexdigest() - - return outstr - - -class CollisionTrackTestHarness(PyAPITestHarness): - def __init__(self, statepoint_name, model=None, inputs_true=None, workdir=None): - super().__init__(statepoint_name, model, inputs_true) - self.workdir = workdir - - def _test_output_created(self): - """Make sure collision_track.h5 has also been created.""" - if self._model.settings.collision_track: - assert os.path.exists( - "collision_track.h5" - ), "collision_track file has not been created." - - def _compare_results(self): - """Compare collision_track.h5 files.""" - if self._model.settings.collision_track: - collision_track_true = self._return_collision_track_data( - "collision_track_true.h5") - collision_track_test = self._return_collision_track_data( - "collision_track.h5") - assert collision_track_true.shape == collision_track_test.shape - np.testing.assert_allclose( - collision_track_true, collision_track_test, rtol=1e-07) - - def main(self): - """Accept commandline arguments and either run or update tests.""" - if config["build_inputs"]: - self.build_inputs() - elif config["update"]: - self.update_results(change_dir=True) - else: - self.execute_test(change_dir=True) - - def build_inputs(self): - """Build inputs.""" - base_dir = os.getcwd() - try: - os.chdir(self.workdir) - self._build_inputs() - finally: - os.chdir(base_dir) - - def _overwrite_results(self): - """Also add the 'collision_track.h5' file during overwriting.""" - if os.path.exists("collision_track.h5"): - shutil.copyfile("collision_track.h5", "collision_track_true.h5") - - def _write_results(self, results_string): - # The result file for this test are written by the OpenMC executable itself - pass - - @staticmethod - def _return_collision_track_data(filepath): - """ - Read a collision_track file and return a sorted array composed of - flattened collision records. - - Parameters - ---------- - filepath : str - Path to the collision_track file - - Returns - ------- - data : np.array - Sorted array composed of flattened collision-track records. - """ - source = openmc.read_collision_track_file(filepath) - columns = [ - source['r']['x'], - source['r']['y'], - source['r']['z'], - source['u']['x'], - source['u']['y'], - source['u']['z'], - source['E'], - source['dE'], - source['time'], - source['wgt'], - source['event_mt'], - source['delayed_group'], - source['cell_id'], - source['nuclide_id'], - source['material_id'], - source['universe_id'], - source['n_collision'], - source['particle'], - source['parent_id'], - source['progeny_id'], - ] - data = np.column_stack(columns) - - # Sort by the complete record, prioritizing stable integer identifiers - # before floating-point fields. This removes dependence on the order in - # which threads append otherwise reproducible collision records. - sort_columns = [ - source['parent_id'], - source['progeny_id'], - source['n_collision'], - source['particle'], - source['cell_id'], - source['material_id'], - source['universe_id'], - source['nuclide_id'], - source['event_mt'], - source['delayed_group'], - source['r']['x'], - source['r']['y'], - source['r']['z'], - source['u']['x'], - source['u']['y'], - source['u']['z'], - source['E'], - source['dE'], - source['time'], - source['wgt'], - ] - sorted_idx = np.lexsort(tuple(reversed(sort_columns))) - - return data[sorted_idx] diff --git a/tests/unit_tests/__init__.py b/tests/unit_tests/__init__.py index 44b5a5018..e97ab13e2 100644 --- a/tests/unit_tests/__init__.py +++ b/tests/unit_tests/__init__.py @@ -14,12 +14,3 @@ def assert_unbounded(obj): ll, ur = obj.bounding_box assert ll == pytest.approx((-np.inf, -np.inf, -np.inf)) assert ur == pytest.approx((np.inf, np.inf, np.inf)) - - -def assert_sample_mean(samples, expected_mean): - # Calculate sample standard deviation - std_dev = samples.std() / np.sqrt(samples.size - 1) - - # Means should agree within 4 sigma 99.993% of the time. Note that this is - # expected to fail about 1 out of 16,000 times - assert np.abs(expected_mean - samples.mean()) < 4*std_dev diff --git a/tests/unit_tests/cell_instances/test_hex_multilattice.py b/tests/unit_tests/cell_instances/test_hex_multilattice.py deleted file mode 100644 index 3f503fe9b..000000000 --- a/tests/unit_tests/cell_instances/test_hex_multilattice.py +++ /dev/null @@ -1,119 +0,0 @@ -from math import sqrt - -import pytest -import numpy as np -import openmc -import openmc.lib - -from tests import cdtemp - - -@pytest.fixture(scope='module', autouse=True) -def double_hex_lattice_model(): - openmc.reset_auto_ids() - radius = 0.9 - pin_lattice_pitch = 2.0 - # make the hex prism a little larger to make sure test - # locations are definitively in the model - hex_prism_edge = 1.2 * pin_lattice_pitch - - model = openmc.Model() - - # materials - nat_u = openmc.Material() - nat_u.set_density('g/cm3', 12.0) - nat_u.add_element('U', 1.0) - - graphite = openmc.Material() - graphite.set_density('g/cm3', 1.1995) - graphite.add_element('C', 1.0) - - # zplanes to define lower and upper region - z_low = openmc.ZPlane(-10, boundary_type='vacuum') - z_mid = openmc.ZPlane(0) - z_high = openmc.ZPlane(10, boundary_type='vacuum') - hex_prism = openmc.model.HexagonalPrism( - edge_length=hex_prism_edge, boundary_type='reflective') - - # geometry - cyl = openmc.ZCylinder(r=radius) - univ = openmc.model.pin([cyl], [nat_u, graphite]) - - # create a hexagonal lattice of compacts - hex_lattice = openmc.HexLattice() - hex_lattice.orientation = 'y' - hex_lattice.pitch = (pin_lattice_pitch,) - hex_lattice.center = (0., 0.) - center = [univ] - ring = [univ, univ, univ, univ, univ, univ] - hex_lattice.universes = [ring, center] - lower_hex_cell = openmc.Cell(fill=hex_lattice, region=-hex_prism & +z_low & -z_mid) - upper_hex_cell = openmc.Cell(fill=hex_lattice, region=-hex_prism & +z_mid & -z_high) - hex_cells = [lower_hex_cell, upper_hex_cell] - model.geometry = openmc.Geometry(hex_cells) - - # moderator - cell = next(iter(univ.get_all_cells().values())) - tally = openmc.Tally(tally_id=1) - filter = openmc.DistribcellFilter(cell) - tally.filters = [filter] - tally.scores = ['flux'] - model.tallies = [tally] - - # settings - # source definition. fission source given bounding box of graphite active region - system_LL = (-pin_lattice_pitch*sqrt(3)/2, -pin_lattice_pitch, -5) - system_UR = (pin_lattice_pitch*sqrt(3)/2, pin_lattice_pitch, 5) - source_dist = openmc.stats.Box(system_LL, system_UR) - model.settings.source = openmc.IndependentSource(space=source_dist) - model.settings.particles = 100 - model.settings.inactive = 2 - model.settings.batches = 10 - - with cdtemp(): - model.export_to_xml() - openmc.lib.init() - yield - openmc.lib.finalize() - - -# Lower cell instances -# 6 -# 5 4 -# 3 -# 2 1 -# 0 -# Upper cell instances -# 13 -# 12 11 -# 10 -# 9 8 -# 7 -hex_expected_results = [ - ((0.0, -2.0, -5.0), 0), - ((1.732, -1.0, -5.0), 1), - ((-1.732, -1.0, -5.0), 2), - ((0.0, 0.0, -0.1), 3), - ((1.732, 1.0, -5.0), 4), - ((-1.732, 1.0, -5.0), 5), - ((0.0, 2.0, -0.1), 6), - ((0.0, -2.0, 5.0), 7), - ((1.732, -1.0, 5.0), 8), - ((-1.732, -1.0, 5.0), 9), - ((0.0, 0.0, 5.0), 10), - ((1.732, 1.0, 5.0), 11), - ((-1.732, 1.0, 5.0), 12), - ((0.0, 2.0, 5.0), 13), -] - - -@pytest.mark.parametrize("r,expected_cell_instance", hex_expected_results, ids=str) -def test_cell_instance_hex_multilattice(r, expected_cell_instance): - _, cell_instance = openmc.lib.find_cell(r) - assert cell_instance == expected_cell_instance - - -def test_cell_instance_multilattice_results(): - openmc.lib.run() - tally_results = openmc.lib.tallies[1].mean - assert (tally_results != 0.0).all() diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 6041d8982..51d1b19a3 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -48,7 +48,7 @@ def sphere_model(): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + model.settings.source = openmc.Source(space=openmc.stats.Point()) return model diff --git a/tests/unit_tests/dagmc/broken_model.h5m b/tests/unit_tests/dagmc/broken_model.h5m deleted file mode 100644 index 4bc6c7d42..000000000 Binary files a/tests/unit_tests/dagmc/broken_model.h5m and /dev/null differ diff --git a/tests/unit_tests/dagmc/dagmc_tetrahedral_no_graveyard.h5m b/tests/unit_tests/dagmc/dagmc_tetrahedral_no_graveyard.h5m deleted file mode 100644 index 2aa72956b..000000000 Binary files a/tests/unit_tests/dagmc/dagmc_tetrahedral_no_graveyard.h5m and /dev/null differ diff --git a/tests/unit_tests/dagmc/test.py b/tests/unit_tests/dagmc/test.py index e84b5317e..b3e2c390f 100644 --- a/tests/unit_tests/dagmc/test.py +++ b/tests/unit_tests/dagmc/test.py @@ -1,7 +1,6 @@ import shutil import numpy as np -from pathlib import Path import pytest import openmc @@ -27,22 +26,13 @@ def dagmc_model(request): model.settings.verbosity = 1 source_box = openmc.stats.Box([ -4, -4, -4 ], [ 4, 4, 4 ]) - source = openmc.IndependentSource(space=source_box) + source = openmc.Source(space=source_box) model.settings.source = source # geometry - dagmc_file = Path(request.fspath).parent / 'dagmc.h5m' - dagmc_universe = openmc.DAGMCUniverse(dagmc_file) + dagmc_universe = openmc.DAGMCUniverse('dagmc.h5m') model.geometry = openmc.Geometry(dagmc_universe) - # check number of surfaces and volumes for this pincell model there should - # be 5 volumes: two fuel regions, water, graveyard, implicit complement (the - # implicit complement cell is created automatically at runtime) - # and 21 surfaces: 3 cylinders (9 surfaces) and a bounding cubic shell - # (12 surfaces) - assert dagmc_universe.n_cells == 5 - assert dagmc_universe.n_surfaces == 21 - # tally tally = openmc.Tally() tally.scores = ['total'] diff --git a/tests/unit_tests/dagmc/test_bounds.py b/tests/unit_tests/dagmc/test_bounds.py index 35e1dd340..dbca3ca25 100644 --- a/tests/unit_tests/dagmc/test_bounds.py +++ b/tests/unit_tests/dagmc/test_bounds.py @@ -23,38 +23,23 @@ def test_bounding_region(request): assert isinstance(region, openmc.Region) assert len(region) == 6 assert region[0].surface.type == "x-plane" - assert region[0].surface.x0 == -25. assert region[1].surface.type == "x-plane" - assert region[1].surface.x0 == 25. assert region[2].surface.type == "y-plane" - assert region[2].surface.y0 == -25. assert region[3].surface.type == "y-plane" - assert region[3].surface.y0 == 25. assert region[4].surface.type == "z-plane" - assert region[4].surface.z0 == -25. assert region[5].surface.type == "z-plane" - assert region[5].surface.z0 == 25. assert region[0].surface.boundary_type == "vacuum" assert region[1].surface.boundary_type == "vacuum" assert region[2].surface.boundary_type == "vacuum" assert region[3].surface.boundary_type == "vacuum" assert region[4].surface.boundary_type == "vacuum" assert region[5].surface.boundary_type == "vacuum" - region = u.bounding_region(padding_distance=5) - assert region[0].surface.x0 == -30. - assert region[1].surface.x0 == 30. - assert region[2].surface.y0 == -30. - assert region[3].surface.y0 == 30. - assert region[4].surface.z0 == -30. - assert region[5].surface.z0 == 30. region = u.bounding_region(bounded_type="sphere", boundary_type="reflective") assert isinstance(region, openmc.Region) assert isinstance(region, openmc.Halfspace) assert region.surface.type == "sphere" assert region.surface.boundary_type == "reflective" - larger_region = u.bounding_region(bounded_type="sphere", padding_distance=10) - assert larger_region.surface.r > region.surface.r def test_bounded_universe(request): @@ -86,12 +71,3 @@ def test_bounded_universe(request): surfaces = list(cells[0][1].region.get_surfaces().items()) assert surfaces[0][1].type == "sphere" assert surfaces[0][1].id == 43 - - -def test_material_names(request): - """Checks that the DAGMCUniverse.material_names() returns a list of the - name present in the dagmc.h5m file in the expected order""" - - u = openmc.DAGMCUniverse(Path(request.fspath).parent / "dagmc.h5m") - - assert u.material_names == ['41', 'Graveyard', 'no-void fuel'] diff --git a/tests/unit_tests/dagmc/test_convert_to_multigroup.py b/tests/unit_tests/dagmc/test_convert_to_multigroup.py deleted file mode 100644 index 069dc658e..000000000 --- a/tests/unit_tests/dagmc/test_convert_to_multigroup.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Test that convert_to_multigroup works with DAGMC models without requiring -particles/batches to be set beforehand. -""" - -from pathlib import Path -import pytest -import openmc -import openmc.lib - -pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), - reason="DAGMC CAD geometry is not enabled.") - - -def test_convert_to_multigroup_without_particles_batches(run_in_tmpdir): - """Test that convert_to_multigroup works with DAGMC model without - setting particles/batches beforehand.""" - openmc.reset_auto_ids() - - mat = openmc.Material(name="mat") - mat.add_nuclide("Fe56", 1.0) - mat.set_density("g/cm3", 7.0) - - # Use minimal tetrahedral DAGMC file - dagmc_file = Path(__file__).parent / "dagmc_tetrahedral_no_graveyard.h5m" - dagmc_univ = openmc.DAGMCUniverse(dagmc_file, auto_geom_ids=True) - bound_dagmc_univ = dagmc_univ.bounded_universe(padding_distance=1) - - # Create model WITHOUT setting particles or batches - model = openmc.Model() - model.materials = openmc.Materials([mat]) - model.geometry = openmc.Geometry(bound_dagmc_univ) - model.settings = openmc.Settings() # Note: no particles or batches set! - - model.settings.run_mode = 'fixed source' - - # Create a point source - my_source = openmc.IndependentSource() - my_source.space = openmc.stats.Point((0.25, 0.25, 0.25)) - my_source.energy = openmc.stats.delta_function(14e6) - model.settings.source = my_source - - # This should work without requiring particles/batches to be set - # convert_to_multigroup handles initialization internally using non-transport mode - model.convert_to_multigroup( - method='material_wise', - groups='CASMO-2', - nparticles=10, - overwrite_mgxs_library=True - ) - - # Verify the model was converted successfully - assert model.settings.energy_mode == 'multi-group' diff --git a/tests/unit_tests/dagmc/test_h5m_subdir.py b/tests/unit_tests/dagmc/test_h5m_subdir.py deleted file mode 100644 index dd9c6b043..000000000 --- a/tests/unit_tests/dagmc/test_h5m_subdir.py +++ /dev/null @@ -1,40 +0,0 @@ -import shutil -from pathlib import Path - -import openmc -import openmc.lib -import pytest - -pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled." -) - - -@pytest.mark.parametrize("absolute", [True, False]) -def test_model_h5m_in_subdirectory(run_in_tmpdir, request, absolute): - # Create new subdirectory and copy h5m file there - h5m = Path(request.fspath).parent / "dagmc.h5m" - subdir = Path("h5m") - subdir.mkdir() - shutil.copy(h5m, subdir) - - # Create simple model with h5m file in subdirectory - if absolute: - dag_univ = openmc.DAGMCUniverse((subdir / "dagmc.h5m").absolute()) - else: - dag_univ = openmc.DAGMCUniverse(subdir / "dagmc.h5m") - model = openmc.Model() - model.geometry = openmc.Geometry(dag_univ.bounded_universe()) - mat1 = openmc.Material(name="41") - mat1.add_nuclide("H1", 1.0) - mat2 = openmc.Material(name="no-void fuel") - mat2.add_nuclide("U235", 1.0) - model.materials = [mat1, mat2] - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 1000 - - # Make sure model can load - model.export_to_model_xml() - openmc.lib.init(["model.xml"]) - openmc.lib.finalize() diff --git a/tests/unit_tests/dagmc/test_lost_particles.py b/tests/unit_tests/dagmc/test_lost_particles.py deleted file mode 100644 index 48b6cf165..000000000 --- a/tests/unit_tests/dagmc/test_lost_particles.py +++ /dev/null @@ -1,86 +0,0 @@ -import numpy as np -from pathlib import Path - -import openmc -import openmc.lib - -import pytest - -pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), - reason="DAGMC CAD geometry is not enabled.") - - -@pytest.fixture -def broken_dagmc_model(request): - openmc.reset_auto_ids() - model = openmc.Model() - - ### MATERIALS ### - fuel = openmc.Material(name='no-void fuel') - fuel.set_density('g/cc', 10.29769) - fuel.add_nuclide('U233', 1.0) - - cladding = openmc.Material(name='clad') - cladding.set_density('g/cc', 6.55) - cladding.add_nuclide('Zr90', 1.0) - - h1 = openmc.Material(name='water') - h1.set_density('g/cc', 0.75) - h1.add_nuclide('H1', 1.0) - - model.materials = openmc.Materials([fuel, cladding, h1]) - - ### GEOMETRY ### - # create the DAGMC universe using a model that has many triangles - # removed - dagmc_file = Path(request.fspath).parent / "broken_model.h5m" - pincell_univ = openmc.DAGMCUniverse(filename=dagmc_file, auto_geom_ids=True) - - # create a 2 x 2 lattice using the DAGMC pincell - pitch = np.asarray((24.0, 24.0)) - lattice = openmc.RectLattice() - lattice.pitch = pitch - lattice.universes = [[pincell_univ] * 2] * 2 - lattice.lower_left = -pitch - - # clip the DAGMC geometry at +/- 10 cm w/ CSG planes - rpp = openmc.model.RectangularParallelepiped( - -pitch[0], pitch[0], -pitch[1], pitch[1], -10.0, 10.0, boundary_type='reflective') - bounding_cell = openmc.Cell(fill=lattice, region=-rpp) - - model.geometry = openmc.Geometry(root=[bounding_cell]) - - # settings - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.inactive = 2 - model.settings.output = {'summary': False} - - # Limit max particle events to prevent particles from getting stuck in the - # implicit complement of the non-root DAGMC universe. - model.settings.max_particle_events = 100 - - model.export_to_xml() - - return model - - -@pytest.mark.skip(reason="Test causes CI to hang intermittently") -def test_lost_particles(run_in_tmpdir, broken_dagmc_model): - broken_dagmc_model.export_to_xml() - # ensure that particles will be lost when cell intersections can't be found - # due to the removed triangles in this model - with pytest.raises(RuntimeError, match='Maximum number of lost particles has been reached.'): - openmc.run() - - # run this again, but with the dagmc universe as the root unvierse - # to ensure that lost particles are still caught in this case - for univ in broken_dagmc_model.geometry.get_all_universes().values(): - if isinstance(univ, openmc.DAGMCUniverse): - broken_dagmc_model.geometry.root_universe = univ - break - - broken_dagmc_model.export_to_xml() - with pytest.raises(RuntimeError, match='Maximum number of lost particles has been reached.'): - openmc.run() diff --git a/tests/unit_tests/dagmc/test_model.py b/tests/unit_tests/dagmc/test_model.py deleted file mode 100644 index 5889fa542..000000000 --- a/tests/unit_tests/dagmc/test_model.py +++ /dev/null @@ -1,365 +0,0 @@ -from pathlib import Path - -import lxml.etree as ET -import numpy as np -import pytest -import openmc -import openmc.lib -from openmc.utility_funcs import change_directory - -pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), - reason="DAGMC CAD geometry is not enabled.") - - -@pytest.fixture() -def model(request): - pitch = 1.26 - - mats = {} - mats["no-void fuel"] = openmc.Material(1, name="no-void fuel") - mats["no-void fuel"].add_nuclide("U235", 0.03) - mats["no-void fuel"].add_nuclide("U238", 0.97) - mats["no-void fuel"].add_nuclide("O16", 2.0) - mats["no-void fuel"].set_density("g/cm3", 10.0) - - mats["41"] = openmc.Material(name="41") - mats["41"].add_nuclide("H1", 2.0) - mats["41"].add_element("O", 1.0) - mats["41"].set_density("g/cm3", 1.0) - mats["41"].add_s_alpha_beta("c_H_in_H2O") - - p = Path(request.fspath).parent / "dagmc.h5m" - - daguniv = openmc.DAGMCUniverse(p, name='simple-dagmc', auto_geom_ids=True) - - lattice = openmc.RectLattice() - lattice.dimension = [2, 2] - lattice.lower_left = [-pitch, -pitch] - lattice.pitch = [pitch, pitch] - lattice.universes = [ - [daguniv, daguniv], - [daguniv, daguniv]] - - box = openmc.model.RectangularParallelepiped(-pitch, pitch, -pitch, pitch, -5, 5) - - root = openmc.Universe(cells=[openmc.Cell(region=-box, fill=lattice)]) - - settings = openmc.Settings() - settings.batches = 100 - settings.inactive = 10 - settings.particles = 1000 - - ll, ur = root.bounding_box - mat_vol = openmc.VolumeCalculation([mats["no-void fuel"]], 1000000, ll, ur) - cell_vol = openmc.VolumeCalculation(list(root.cells.values()), 1000000, ll, ur) - settings.volume_calculations = [mat_vol, cell_vol] - - model = openmc.Model() - model.materials = openmc.Materials(mats.values()) - model.geometry = openmc.Geometry(root=root) - model.settings = settings - - with change_directory(tmpdir=True): - try: - model.init_lib() - model.sync_dagmc_universes() - yield model - finally: - model.finalize_lib() - openmc.reset_auto_ids() - - -def test_dagmc_sync_cell_names(model): - dag_univ = None - for univ in model.geometry.get_all_universes().values(): - if isinstance(univ, openmc.DAGMCUniverse): - dag_univ = univ - break - - assert dag_univ is not None - - for cell_id, cell in dag_univ.cells.items(): - assert cell.name == openmc.lib.cells[cell_id].name - - assert any(cell.name == "implicit complement" - for cell in dag_univ.cells.values()) - - -def test_dagmc_add_material_override_with_id(model): - mats = {} - mats["foo"] = openmc.Material(name="foo") - mats["foo"].add_nuclide("H1", 2.0) - mats["foo"].add_element("O", 1.0) - mats["foo"].set_density("g/cm3", 1.0) - mats["foo"].add_s_alpha_beta("c_H_in_H2O") - - for univ in model.geometry.get_all_universes().values(): - if not isinstance(univ, openmc.DAGMCUniverse): - break - - cells_with_41 = [] - for cell in univ.cells.values(): - if cell.fill is None: - continue - if cell.fill.name == "41": - cells_with_41.append(cell.id) - univ.add_material_override(cell.id, mats["foo"]) - for cell_id in cells_with_41: - assert univ.cells[cell_id].fill == mats["foo"] - - -def test_dagmc_add_material_override_with_cell(model): - mats = {} - mats["foo"] = openmc.Material(name="foo") - mats["foo"].add_nuclide("H1", 2.0) - mats["foo"].add_element("O", 1.0) - mats["foo"].set_density("g/cm3", 1.0) - mats["foo"].add_s_alpha_beta("c_H_in_H2O") - - for univ in model.geometry.get_all_universes().values(): - if not isinstance(univ, openmc.DAGMCUniverse): - break - - cells_with_41 = [] - for cell in univ.cells.values(): - if cell.fill is None: - continue - if cell.fill.name == "41": - cells_with_41.append(cell.id) - univ.add_material_override(cell, mats["foo"]) - for cell_id in cells_with_41: - assert univ.cells[cell_id].fill == mats["foo"] - - -def test_model_differentiate_depletable_with_dagmc(model, run_in_tmpdir): - model.calculate_volumes() - - # Get the volume of the no-void fuel material before differentiation - volume_before = np.sum([m.volume for m in model.materials if m.name == "no-void fuel"]) - - # Differentiate the depletable materials - model.differentiate_depletable_mats(diff_volume_method="divide equally") - # Get the volume of the no-void fuel material after differentiation - volume_after = np.sum([m.volume for m in model.materials if "fuel" in m.name]) - assert np.isclose(volume_before, volume_after) - assert len(model.materials) == 4*2 +1 - - -def test_model_differentiate_with_dagmc(model): - root = model.geometry.root_universe - ll, ur = root.bounding_box - model.calculate_volumes() - # Get the volume of the no-void fuel material before differentiation - volume_before = np.sum([m.volume for m in model.materials if m.name == "no-void fuel"]) - - # Differentiate all the materials - model.differentiate_mats(depletable_only=False) - - # Get the volume of the no-void fuel material after differentiation - mat_vol = openmc.VolumeCalculation(model.materials, 1000000, ll, ur) - model.settings.volume_calculations = [mat_vol] - model.init_lib() # need to reinitialize the lib after differentiating the materials - model.calculate_volumes() - volume_after = np.sum([m.volume for m in model.materials if "fuel" in m.name]) - assert np.isclose(volume_before, volume_after) - assert len(model.materials) == 4*2 + 4 - - -def test_dagmc_xml(model): - override_mat = openmc.Material(name="41") - override_mat.add_nuclide("H1", 2.0) - override_mat.add_element("O", 1.0) - override_mat.set_density("g/cm3", 1.0) - override_mat.add_s_alpha_beta("c_H_in_H2O") - model.materials.append(override_mat) - - for univ in model.geometry.get_all_universes().values(): - if isinstance(univ, openmc.DAGMCUniverse): - dag_univ = univ - break - - dag_univ.add_material_override(5, override_mat) - - # Tesing the XML subelement generation - root = ET.Element('dagmc_universe') - dag_univ.create_xml_subelement(root) - dagmc_ele = root.find('dagmc_universe') - - assert dagmc_ele.get('id') == str(dag_univ.id) - assert dagmc_ele.get('name') == str(dag_univ.name) - assert dagmc_ele.get('filename') == str(dag_univ.filename) - assert dagmc_ele.get('auto_geom_ids') == str(dag_univ.auto_geom_ids).lower() - - assert dagmc_ele.find('material_overrides') is None - - override_elements = dagmc_ele.findall('cell') - assert len(override_elements) == len(dag_univ.cells) - xml_cells = {int(elem.get('id')): elem for elem in override_elements} - for cell_id, cell in dag_univ.cells.items(): - assert cell_id in xml_cells - xml_cell = xml_cells[cell_id] - if cell.fill_type == 'void': - assert xml_cell.get('material') == 'void' - elif cell.fill_type == 'material': - assert xml_cell.get('material') == str(cell.fill.id) - elif cell.fill_type == 'distribmat': - mat_list = xml_cell.find('material').text.split() - expected = ["void" if m is None else str(m.id) for m in cell.fill] - assert mat_list == expected - else: - pytest.fail(f"Unexpected DAGMC cell fill type: {cell.fill_type}") - - model.export_to_model_xml() - - xml_model = openmc.Model.from_model_xml() - - for univ in xml_model.geometry.get_all_universes().values(): - if isinstance(univ, openmc.DAGMCUniverse): - xml_dagmc_univ = univ - break - - assert xml_dagmc_univ.cells.keys() == dag_univ.cells.keys() - - for cell_id, cell in dag_univ.cells.items(): - xml_cell = xml_dagmc_univ.cells[cell_id] - assert xml_cell.fill_type == cell.fill_type - if cell.fill_type == 'void': - assert xml_cell.fill is None - elif cell.fill_type == 'material': - assert xml_cell.fill.id == cell.fill.id - elif cell.fill_type == 'distribmat': - xml_ids = [m.id if m is not None else None for m in xml_cell.fill] - model_ids = [m.id if m is not None else None for m in cell.fill] - assert xml_ids == model_ids - else: - pytest.fail(f"Unexpected DAGMC cell fill type: {cell.fill_type}") - - -def test_dagmc_xml_reject_fill_override(): - mats = {'1': openmc.Material(1), 'void': None} - elem = ET.fromstring( - '' - '' - '' - ) - with pytest.raises(ValueError, match="cannot specify 'fill'"): - openmc.DAGMCUniverse.from_xml_element(elem, mats) - - -def test_dagmc_xml_reject_region_override(): - mats = {'1': openmc.Material(1), 'void': None} - elem = ET.fromstring( - '' - '' - '' - ) - with pytest.raises(ValueError, match="cannot specify 'region'"): - openmc.DAGMCUniverse.from_xml_element(elem, mats) - - -def _legacy_xml(cell_overrides): - """Helper to build a with old-format .""" - inner = ''.join( - f'{mids}' - for cid, mids in cell_overrides.items() - ) - return ET.fromstring( - f'' - f'{inner}' - f'' - ) - - -def test_dagmc_xml_legacy_single_material_compat(): - mat = openmc.Material(1) - mats = {'1': mat, 'void': None} - elem = _legacy_xml({3: '1'}) - with pytest.warns(DeprecationWarning, match="deprecated"): - univ = openmc.DAGMCUniverse.from_xml_element(elem, mats) - assert 3 in univ.cells - assert univ.cells[3].fill is mat - - -def test_dagmc_xml_legacy_distribmat_compat(): - mat1, mat2 = openmc.Material(2), openmc.Material(3) - mats = {'2': mat1, '3': mat2, 'void': None} - elem = _legacy_xml({5: '2 3'}) - with pytest.warns(DeprecationWarning): - univ = openmc.DAGMCUniverse.from_xml_element(elem, mats) - assert univ.cells[5].fill_type == 'distribmat' - assert list(univ.cells[5].fill) == [mat1, mat2] - - -def test_dagmc_xml_legacy_void_compat(): - mats = {'void': None} - elem = _legacy_xml({7: 'void'}) - with pytest.warns(DeprecationWarning): - univ = openmc.DAGMCUniverse.from_xml_element(elem, mats) - assert univ.cells[7].fill_type == 'void' - - -def test_dagmc_xml_legacy_both_raises(): - mat = openmc.Material(1) - mats = {'1': mat, 'void': None} - elem = ET.fromstring( - '' - '' - '1' - '' - '' - '' - ) - with pytest.raises(ValueError, match="both"): - openmc.DAGMCUniverse.from_xml_element(elem, mats) - - -def test_dagmc_xml_legacy_deprecation_warning(): - mats = {'1': openmc.Material(1), 'void': None} - elem = _legacy_xml({3: '1'}) - with pytest.warns(DeprecationWarning): - openmc.DAGMCUniverse.from_xml_element(elem, mats) - - -def test_dagmc_xml_legacy_roundtrip(): - """Old-format XML loads correctly and re-exports using the new format.""" - mat = openmc.Material(1) - mats = {'1': mat, 'void': None} - elem = _legacy_xml({3: '1'}) - with pytest.warns(DeprecationWarning): - univ = openmc.DAGMCUniverse.from_xml_element(elem, mats) - - root = ET.Element('geometry') - univ.create_xml_subelement(root) - dagmc_elem = root.find('dagmc_universe') - - assert dagmc_elem.find('material_overrides') is None - cell_elems = dagmc_elem.findall('cell') - assert len(cell_elems) == 1 - assert int(cell_elems[0].get('id')) == 3 - assert cell_elems[0].get('material') == '1' - - -def test_dagmc_xml_temperature_roundtrip(): - mat = openmc.Material(1) - mats = {'1': mat, 'void': None} - - elem = ET.fromstring( - '' - '' - '' - ) - - dag_univ = openmc.DAGMCUniverse.from_xml_element(elem, mats) - assert dag_univ.cells[7].fill.id == 1 - assert dag_univ.cells[7].temperature == pytest.approx(825.0) - - root = ET.Element('geometry') - dag_univ.create_xml_subelement(root) - dagmc_elem = root.find('dagmc_universe') - xml_cell = dagmc_elem.find('cell') - assert xml_cell.get('temperature') == '825.0' - - dag_univ_roundtrip = openmc.DAGMCUniverse.from_xml_element(dagmc_elem, mats) - assert dag_univ_roundtrip.cells[7].fill.id == 1 - assert dag_univ_roundtrip.cells[7].temperature == pytest.approx(825.0) diff --git a/tests/unit_tests/dagmc/test_plot.py b/tests/unit_tests/dagmc/test_plot.py deleted file mode 100644 index 6ce1d79a2..000000000 --- a/tests/unit_tests/dagmc/test_plot.py +++ /dev/null @@ -1,71 +0,0 @@ -import pytest -import openmc -import openmc.lib - - -pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled." -) - -def test_plotting_dagmc_model(request): - """Test plotting a DAGMC model with OpenMC. This is different to CSG - model plotting as the path to the DAGMC file needs handling.""" - - dag_universe = openmc.DAGMCUniverse(request.path.parent / 'dagmc.h5m') - csg_with_dag_inside = dag_universe.bounded_universe() - model = openmc.Model() - model.geometry = openmc.Geometry(csg_with_dag_inside) - - for mat_name in dag_universe.material_names: - material = openmc.Material(name=mat_name) - material.add_nuclide("Fe56", 1.0) - material.set_density("g/cm3", 7.0) - model.materials.append(material) - - # putting the source at the center of the bounding box of the DAGMC - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point(dag_universe.bounding_box.center) - ) - model.settings.batches = 10 - model.settings.particles = 50 - - model.plot() - - -def test_plotting_dagmc_universe(request): - """Test plotting a DAGMCUniverse with OpenMC. This is different to plotting - UniverseBase as the materials are not defined withing the DAGMCUniverse.""" - - dag_universe = openmc.DAGMCUniverse(request.path.parent / 'dagmc.h5m') - dag_universe.plot() - - -def test_plotting_geometry_filled_with_dagmc_universe(request): - """Test plotting a geometry with OpenMC. This is an edge case when plotting - geometry as often geometry objects don't include a DAGMCUniverse. The - inclusion of a DAGMCUniverse requires special handling for the materials.""" - - dag_universe = openmc.DAGMCUniverse(request.path.parent / 'dagmc.h5m', auto_geom_ids=True) - - sphere1 = openmc.Sphere(r=50.0) - sphere2 = openmc.Sphere(r=60.0) - sphere2 = openmc.Sphere(r=70.0, boundary_type='vacuum') - - # Adding a material to the CSG Universe to check universe materials are accounted for - csg_material = openmc.Material(name='csg_material') - csg_material.add_nuclide("H1", 1.0) - - # Adding a material with the same name as a dagmc material to check that - # the plot can handel two materials with the same name from different universes - csg_material = openmc.Material(name=dag_universe.material_names[0]) - csg_material.add_nuclide("H1", 1.0) - - cell1 = openmc.Cell(fill=dag_universe, region=-sphere1) - cell2 = openmc.Cell(fill=csg_material, region=+sphere1 & -sphere2) - - geometry = openmc.Geometry([cell1, cell2]) - geometry.plot() - - # Close plot to avoid warning - import matplotlib.pyplot as plt - plt.close() diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk deleted file mode 100644 index 801a02b3e..000000000 --- a/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk +++ /dev/null @@ -1,41 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET STRUCTURED_GRID -DIMENSIONS 5 4 4 -POINTS 80 double -10 10 -10 11.25 10 -10 12.5 10 -10 -13.75 10 -10 15 10 -10 10 10 -10 -9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 -7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 -8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 -10 10 -10 11.25 10 -10 12.5 10 -10 -13.75 10 -10 15 10 -10 10 10 -9.3333333333 -11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 -15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 -8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 -10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 -8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 -11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 -15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 -12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 -10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 -8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 -9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 -7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 -12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 -10 10 -8 11.25 10 -8 12.5 10 -8 -13.75 10 -8 15 10 -8 10 10 -8 -9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 -7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 -8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 -10 10 -8 11.25 10 -8 12.5 10 -8 -13.75 10 -8 15 10 -8 -CELL_DATA 36 -FIELD FieldData 1 -ascending_data 1 36 double -0 100 200 300 400 500 600 700 800 -900 1000 1100 1200 1300 1400 1500 1600 1700 -1800 1900 2000 2100 2200 2300 2400 2500 2600 -2700 2800 2900 3000 3100 3200 3300 3400 3500 - diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk deleted file mode 100644 index 332d37db0..000000000 --- a/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk +++ /dev/null @@ -1,329 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET UNSTRUCTURED_GRID -POINTS 323 double --4.0450849719 -2.9389262615 0 -4.0450849719 -2.9389262615 0.66666666667 -4.0450849719 -2.9389262615 1.3333333333 --4.0450849719 -2.9389262615 2 -4.0450849719 2.9389262615 0 -4.0450849719 2.9389262615 0.66666666667 --4.0450849719 2.9389262615 1.3333333333 -4.0450849719 2.9389262615 2 -3.0338137289 -2.2041946961 0 --3.0338137289 -2.2041946961 0.66666666667 -3.0338137289 -2.2041946961 1.3333333333 -3.0338137289 -2.2041946961 2 --3.0338137289 2.2041946961 0 -3.0338137289 2.2041946961 0.66666666667 -3.0338137289 2.2041946961 1.3333333333 --3.0338137289 2.2041946961 2 -2.0225424859 -1.4694631307 0 -2.0225424859 -1.4694631307 0.66666666667 --2.0225424859 -1.4694631307 1.3333333333 -2.0225424859 -1.4694631307 2 -2.0225424859 1.4694631307 0 --2.0225424859 1.4694631307 0.66666666667 -2.0225424859 1.4694631307 1.3333333333 -2.0225424859 1.4694631307 2 --1.011271243 -0.73473156537 0 -1.011271243 -0.73473156537 0.66666666667 -1.011271243 -0.73473156537 1.3333333333 --1.011271243 -0.73473156537 2 -1.011271243 0.73473156537 0 -1.011271243 0.73473156537 0.66666666667 --1.011271243 0.73473156537 1.3333333333 -1.011271243 0.73473156537 2 0 0 0 -0 0 0.66666666667 0 0 1.3333333333 0 0 2 -0.38627124297 -1.1888206454 0 0.38627124297 -1.1888206454 0.66666666667 0.38627124297 -1.1888206454 1.3333333333 -0.38627124297 -1.1888206454 2 0.38627124297 1.1888206454 0 0.38627124297 1.1888206454 0.66666666667 -0.38627124297 1.1888206454 1.3333333333 0.38627124297 1.1888206454 2 0.77254248594 -2.3776412907 0 -0.77254248594 -2.3776412907 0.66666666667 0.77254248594 -2.3776412907 1.3333333333 0.77254248594 -2.3776412907 2 -0.77254248594 2.3776412907 0 0.77254248594 2.3776412907 0.66666666667 0.77254248594 2.3776412907 1.3333333333 -0.77254248594 2.3776412907 2 1.1588137289 -3.5664619361 0 1.1588137289 -3.5664619361 0.66666666667 -1.1588137289 -3.5664619361 1.3333333333 1.1588137289 -3.5664619361 2 1.1588137289 3.5664619361 0 -1.1588137289 3.5664619361 0.66666666667 1.1588137289 3.5664619361 1.3333333333 1.1588137289 3.5664619361 2 -1.25 -3.0616169979e-16 0 1.25 -3.0616169979e-16 0.66666666667 1.25 -3.0616169979e-16 1.3333333333 -1.25 -3.0616169979e-16 2 1.25 0 0 1.25 0 0.66666666667 -1.25 0 1.3333333333 1.25 0 2 1.5450849719 -4.7552825815 0 -1.5450849719 -4.7552825815 0.66666666667 1.5450849719 -4.7552825815 1.3333333333 1.5450849719 -4.7552825815 2 -1.5450849719 4.7552825815 0 1.5450849719 4.7552825815 0.66666666667 1.5450849719 4.7552825815 1.3333333333 -1.5450849719 4.7552825815 2 2.5 -6.1232339957e-16 0 2.5 -6.1232339957e-16 0.66666666667 -2.5 -6.1232339957e-16 1.3333333333 2.5 -6.1232339957e-16 2 2.5 0 0 -2.5 0 0.66666666667 2.5 0 1.3333333333 2.5 0 2 -3.75 -9.1848509936e-16 0 3.75 -9.1848509936e-16 0.66666666667 3.75 -9.1848509936e-16 1.3333333333 -3.75 -9.1848509936e-16 2 3.75 0 0 3.75 0 0.66666666667 -3.75 0 1.3333333333 3.75 0 2 5 -1.2246467991e-15 0 -5 -1.2246467991e-15 0.66666666667 5 -1.2246467991e-15 1.3333333333 5 -1.2246467991e-15 2 -5 0 0 5 0 0.66666666667 5 0 1.3333333333 -5 0 2 0.625 0 0 1.875 0 0 -3.125 0 0 4.375 0 0 0.19313562148 0.59441032268 0 -0.57940686445 1.7832309681 0 0.96567810742 2.9720516134 0 1.3519493504 4.1608722588 0 --0.50563562148 0.36736578268 0 -1.5169068645 1.102097348 0 -2.5281781074 1.8368289134 0 --3.5394493504 2.5715604788 0 -0.50563562148 -0.36736578268 0 -1.5169068645 -1.102097348 0 --2.5281781074 -1.8368289134 0 -3.5394493504 -2.5715604788 0 0.19313562148 -0.59441032268 0 -0.57940686445 -1.7832309681 0 0.96567810742 -2.9720516134 0 1.3519493504 -4.1608722588 0 -0.625 0 0.66666666667 1.875 0 0.66666666667 3.125 0 0.66666666667 -4.375 0 0.66666666667 0.19313562148 0.59441032268 0.66666666667 0.57940686445 1.7832309681 0.66666666667 -0.96567810742 2.9720516134 0.66666666667 1.3519493504 4.1608722588 0.66666666667 -0.50563562148 0.36736578268 0.66666666667 --1.5169068645 1.102097348 0.66666666667 -2.5281781074 1.8368289134 0.66666666667 -3.5394493504 2.5715604788 0.66666666667 --0.50563562148 -0.36736578268 0.66666666667 -1.5169068645 -1.102097348 0.66666666667 -2.5281781074 -1.8368289134 0.66666666667 --3.5394493504 -2.5715604788 0.66666666667 0.19313562148 -0.59441032268 0.66666666667 0.57940686445 -1.7832309681 0.66666666667 -0.96567810742 -2.9720516134 0.66666666667 1.3519493504 -4.1608722588 0.66666666667 0.625 0 1.3333333333 -1.875 0 1.3333333333 3.125 0 1.3333333333 4.375 0 1.3333333333 -0.19313562148 0.59441032268 1.3333333333 0.57940686445 1.7832309681 1.3333333333 0.96567810742 2.9720516134 1.3333333333 -1.3519493504 4.1608722588 1.3333333333 -0.50563562148 0.36736578268 1.3333333333 -1.5169068645 1.102097348 1.3333333333 --2.5281781074 1.8368289134 1.3333333333 -3.5394493504 2.5715604788 1.3333333333 -0.50563562148 -0.36736578268 1.3333333333 --1.5169068645 -1.102097348 1.3333333333 -2.5281781074 -1.8368289134 1.3333333333 -3.5394493504 -2.5715604788 1.3333333333 -0.19313562148 -0.59441032268 1.3333333333 0.57940686445 -1.7832309681 1.3333333333 0.96567810742 -2.9720516134 1.3333333333 -1.3519493504 -4.1608722588 1.3333333333 0.625 0 2 1.875 0 2 -3.125 0 2 4.375 0 2 0.19313562148 0.59441032268 2 -0.57940686445 1.7832309681 2 0.96567810742 2.9720516134 2 1.3519493504 4.1608722588 2 --0.50563562148 0.36736578268 2 -1.5169068645 1.102097348 2 -2.5281781074 1.8368289134 2 --3.5394493504 2.5715604788 2 -0.50563562148 -0.36736578268 2 -1.5169068645 -1.102097348 2 --2.5281781074 -1.8368289134 2 -3.5394493504 -2.5715604788 2 0.19313562148 -0.59441032268 2 -0.57940686445 -1.7832309681 2 0.96567810742 -2.9720516134 2 1.3519493504 -4.1608722588 2 -1.011271243 0.73473156537 0 2.0225424859 1.4694631307 0 3.0338137289 2.2041946961 0 -4.0450849719 2.9389262615 0 -0.38627124297 1.1888206454 0 -0.77254248594 2.3776412907 0 --1.1588137289 3.5664619361 0 -1.5450849719 4.7552825815 0 -1.25 1.5308084989e-16 0 --2.5 3.0616169979e-16 0 -3.75 4.5924254968e-16 0 -5 6.1232339957e-16 0 --0.38627124297 -1.1888206454 0 -0.77254248594 -2.3776412907 0 -1.1588137289 -3.5664619361 0 --1.5450849719 -4.7552825815 0 1.011271243 -0.73473156537 0 2.0225424859 -1.4694631307 0 -3.0338137289 -2.2041946961 0 4.0450849719 -2.9389262615 0 1.011271243 0.73473156537 0.66666666667 -2.0225424859 1.4694631307 0.66666666667 3.0338137289 2.2041946961 0.66666666667 4.0450849719 2.9389262615 0.66666666667 --0.38627124297 1.1888206454 0.66666666667 -0.77254248594 2.3776412907 0.66666666667 -1.1588137289 3.5664619361 0.66666666667 --1.5450849719 4.7552825815 0.66666666667 -1.25 1.5308084989e-16 0.66666666667 -2.5 3.0616169979e-16 0.66666666667 --3.75 4.5924254968e-16 0.66666666667 -5 6.1232339957e-16 0.66666666667 -0.38627124297 -1.1888206454 0.66666666667 --0.77254248594 -2.3776412907 0.66666666667 -1.1588137289 -3.5664619361 0.66666666667 -1.5450849719 -4.7552825815 0.66666666667 -1.011271243 -0.73473156537 0.66666666667 2.0225424859 -1.4694631307 0.66666666667 3.0338137289 -2.2041946961 0.66666666667 -4.0450849719 -2.9389262615 0.66666666667 1.011271243 0.73473156537 1.3333333333 2.0225424859 1.4694631307 1.3333333333 -3.0338137289 2.2041946961 1.3333333333 4.0450849719 2.9389262615 1.3333333333 -0.38627124297 1.1888206454 1.3333333333 --0.77254248594 2.3776412907 1.3333333333 -1.1588137289 3.5664619361 1.3333333333 -1.5450849719 4.7552825815 1.3333333333 --1.25 1.5308084989e-16 1.3333333333 -2.5 3.0616169979e-16 1.3333333333 -3.75 4.5924254968e-16 1.3333333333 --5 6.1232339957e-16 1.3333333333 -0.38627124297 -1.1888206454 1.3333333333 -0.77254248594 -2.3776412907 1.3333333333 --1.1588137289 -3.5664619361 1.3333333333 -1.5450849719 -4.7552825815 1.3333333333 1.011271243 -0.73473156537 1.3333333333 -2.0225424859 -1.4694631307 1.3333333333 3.0338137289 -2.2041946961 1.3333333333 4.0450849719 -2.9389262615 1.3333333333 -1.011271243 0.73473156537 2 2.0225424859 1.4694631307 2 3.0338137289 2.2041946961 2 -4.0450849719 2.9389262615 2 -0.38627124297 1.1888206454 2 -0.77254248594 2.3776412907 2 --1.1588137289 3.5664619361 2 -1.5450849719 4.7552825815 2 -1.25 1.5308084989e-16 2 --2.5 3.0616169979e-16 2 -3.75 4.5924254968e-16 2 -5 6.1232339957e-16 2 --0.38627124297 -1.1888206454 2 -0.77254248594 -2.3776412907 2 -1.1588137289 -3.5664619361 2 --1.5450849719 -4.7552825815 2 1.011271243 -0.73473156537 2 2.0225424859 -1.4694631307 2 -3.0338137289 -2.2041946961 2 4.0450849719 -2.9389262615 2 0 0 0.33333333333 -1.25 0 0.33333333333 2.5 0 0.33333333333 3.75 0 0.33333333333 -5 0 0.33333333333 0.38627124297 1.1888206454 0.33333333333 0.77254248594 2.3776412907 0.33333333333 -1.1588137289 3.5664619361 0.33333333333 1.5450849719 4.7552825815 0.33333333333 -1.011271243 0.73473156537 0.33333333333 --2.0225424859 1.4694631307 0.33333333333 -3.0338137289 2.2041946961 0.33333333333 -4.0450849719 2.9389262615 0.33333333333 --1.011271243 -0.73473156537 0.33333333333 -2.0225424859 -1.4694631307 0.33333333333 -3.0338137289 -2.2041946961 0.33333333333 --4.0450849719 -2.9389262615 0.33333333333 0.38627124297 -1.1888206454 0.33333333333 0.77254248594 -2.3776412907 0.33333333333 -1.1588137289 -3.5664619361 0.33333333333 1.5450849719 -4.7552825815 0.33333333333 0 0 1 -1.25 0 1 2.5 0 1 3.75 0 1 -5 0 1 0.38627124297 1.1888206454 1 0.77254248594 2.3776412907 1 -1.1588137289 3.5664619361 1 1.5450849719 4.7552825815 1 -1.011271243 0.73473156537 1 --2.0225424859 1.4694631307 1 -3.0338137289 2.2041946961 1 -4.0450849719 2.9389262615 1 --1.011271243 -0.73473156537 1 -2.0225424859 -1.4694631307 1 -3.0338137289 -2.2041946961 1 --4.0450849719 -2.9389262615 1 0.38627124297 -1.1888206454 1 0.77254248594 -2.3776412907 1 -1.1588137289 -3.5664619361 1 1.5450849719 -4.7552825815 1 0 0 1.6666666667 -1.25 0 1.6666666667 2.5 0 1.6666666667 3.75 0 1.6666666667 -5 0 1.6666666667 0.38627124297 1.1888206454 1.6666666667 0.77254248594 2.3776412907 1.6666666667 -1.1588137289 3.5664619361 1.6666666667 1.5450849719 4.7552825815 1.6666666667 -1.011271243 0.73473156537 1.6666666667 --2.0225424859 1.4694631307 1.6666666667 -3.0338137289 2.2041946961 1.6666666667 -4.0450849719 2.9389262615 1.6666666667 --1.011271243 -0.73473156537 1.6666666667 -2.0225424859 -1.4694631307 1.6666666667 -3.0338137289 -2.2041946961 1.6666666667 --4.0450849719 -2.9389262615 1.6666666667 0.38627124297 -1.1888206454 1.6666666667 0.77254248594 -2.3776412907 1.6666666667 -1.1588137289 -3.5664619361 1.6666666667 1.5450849719 -4.7552825815 1.6666666667 -CELLS 61 1200 -OFFSETS vtktypeint64 -0 20 40 60 80 100 120 140 160 -180 200 220 240 260 280 300 320 340 -360 380 400 420 440 460 480 500 520 -540 560 580 600 620 640 660 680 700 -720 740 760 780 800 820 840 860 880 -900 920 940 960 980 1000 1020 1040 1060 -1080 1100 1120 1140 1160 1180 1200 -CONNECTIVITY vtktypeint64 -32 60 40 32 33 61 41 33 100 -180 104 32 120 200 124 33 260 261 -265 260 60 76 48 40 61 77 49 -41 101 181 105 180 121 201 125 200 -261 262 266 265 76 84 56 48 77 -85 57 49 102 182 106 181 122 202 -126 201 262 263 267 266 84 92 72 -56 85 93 73 57 103 183 107 182 -123 203 127 202 263 264 268 267 32 -40 28 32 33 41 29 33 104 184 -108 32 124 204 128 33 260 265 269 -260 40 48 20 28 41 49 21 29 -105 185 109 184 125 205 129 204 265 -266 270 269 48 56 12 20 49 57 -13 21 106 186 110 185 126 206 130 -205 266 267 271 270 56 72 4 12 -57 73 5 13 107 187 111 186 127 -207 131 206 267 268 272 271 32 28 -24 32 33 29 25 33 108 188 112 -32 128 208 132 33 260 269 273 260 -28 20 16 24 29 21 17 25 109 -189 113 188 129 209 133 208 269 270 -274 273 20 12 8 16 21 13 9 -17 110 190 114 189 130 210 134 209 -270 271 275 274 12 4 0 8 13 -5 1 9 111 191 115 190 131 211 -135 210 271 272 276 275 32 24 36 -32 33 25 37 33 112 192 116 32 -132 212 136 33 260 273 277 260 24 -16 44 36 25 17 45 37 113 193 -117 192 133 213 137 212 273 274 278 -277 16 8 52 44 17 9 53 45 -114 194 118 193 134 214 138 213 274 -275 279 278 8 0 68 52 9 1 -69 53 115 195 119 194 135 215 139 -214 275 276 280 279 32 36 60 32 -33 37 61 33 116 196 100 32 136 -216 120 33 260 277 261 260 36 44 -76 60 37 45 77 61 117 197 101 -196 137 217 121 216 277 278 262 261 -44 52 84 76 45 53 85 77 118 -198 102 197 138 218 122 217 278 279 -263 262 52 68 92 84 53 69 93 -85 119 199 103 198 139 219 123 218 -279 280 264 263 33 61 41 33 34 -62 42 34 120 200 124 33 140 220 -144 34 281 282 286 281 61 77 49 -41 62 78 50 42 121 201 125 200 -141 221 145 220 282 283 287 286 77 -85 57 49 78 86 58 50 122 202 -126 201 142 222 146 221 283 284 288 -287 85 93 73 57 86 94 74 58 -123 203 127 202 143 223 147 222 284 -285 289 288 33 41 29 33 34 42 -30 34 124 204 128 33 144 224 148 -34 281 286 290 281 41 49 21 29 -42 50 22 30 125 205 129 204 145 -225 149 224 286 287 291 290 49 57 -13 21 50 58 14 22 126 206 130 -205 146 226 150 225 287 288 292 291 -57 73 5 13 58 74 6 14 127 -207 131 206 147 227 151 226 288 289 -293 292 33 29 25 33 34 30 26 -34 128 208 132 33 148 228 152 34 -281 290 294 281 29 21 17 25 30 -22 18 26 129 209 133 208 149 229 -153 228 290 291 295 294 21 13 9 -17 22 14 10 18 130 210 134 209 -150 230 154 229 291 292 296 295 13 -5 1 9 14 6 2 10 131 211 -135 210 151 231 155 230 292 293 297 -296 33 25 37 33 34 26 38 34 -132 212 136 33 152 232 156 34 281 -294 298 281 25 17 45 37 26 18 -46 38 133 213 137 212 153 233 157 -232 294 295 299 298 17 9 53 45 -18 10 54 46 134 214 138 213 154 -234 158 233 295 296 300 299 9 1 -69 53 10 2 70 54 135 215 139 -214 155 235 159 234 296 297 301 300 -33 37 61 33 34 38 62 34 136 -216 120 33 156 236 140 34 281 298 -282 281 37 45 77 61 38 46 78 -62 137 217 121 216 157 237 141 236 -298 299 283 282 45 53 85 77 46 -54 86 78 138 218 122 217 158 238 -142 237 299 300 284 283 53 69 93 -85 54 70 94 86 139 219 123 218 -159 239 143 238 300 301 285 284 34 -62 42 34 35 63 43 35 140 220 -144 34 160 240 164 35 302 303 307 -302 62 78 50 42 63 79 51 43 -141 221 145 220 161 241 165 240 303 -304 308 307 78 86 58 50 79 87 -59 51 142 222 146 221 162 242 166 -241 304 305 309 308 86 94 74 58 -87 95 75 59 143 223 147 222 163 -243 167 242 305 306 310 309 34 42 -30 34 35 43 31 35 144 224 148 -34 164 244 168 35 302 307 311 302 -42 50 22 30 43 51 23 31 145 -225 149 224 165 245 169 244 307 308 -312 311 50 58 14 22 51 59 15 -23 146 226 150 225 166 246 170 245 -308 309 313 312 58 74 6 14 59 -75 7 15 147 227 151 226 167 247 -171 246 309 310 314 313 34 30 26 -34 35 31 27 35 148 228 152 34 -168 248 172 35 302 311 315 302 30 -22 18 26 31 23 19 27 149 229 -153 228 169 249 173 248 311 312 316 -315 22 14 10 18 23 15 11 19 -150 230 154 229 170 250 174 249 312 -313 317 316 14 6 2 10 15 7 -3 11 151 231 155 230 171 251 175 -250 313 314 318 317 34 26 38 34 -35 27 39 35 152 232 156 34 172 -252 176 35 302 315 319 302 26 18 -46 38 27 19 47 39 153 233 157 -232 173 253 177 252 315 316 320 319 -18 10 54 46 19 11 55 47 154 -234 158 233 174 254 178 253 316 317 -321 320 10 2 70 54 11 3 71 -55 155 235 159 234 175 255 179 254 -317 318 322 321 34 38 62 34 35 -39 63 35 156 236 140 34 176 256 -160 35 302 319 303 302 38 46 78 -62 39 47 79 63 157 237 141 236 -177 257 161 256 319 320 304 303 46 -54 86 78 47 55 87 79 158 238 -142 237 178 258 162 257 320 321 305 -304 54 70 94 86 55 71 95 87 -159 239 143 238 179 259 163 258 321 -322 306 305 -CELL_TYPES 60 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 - -CELL_DATA 60 -FIELD FieldData 1 -ascending_data 1 60 double -0 100 200 300 400 500 600 700 800 -900 1000 1100 1200 1300 1400 1500 1600 1700 -1800 1900 2000 2100 2200 2300 2400 2500 2600 -2700 2800 2900 3000 3100 3200 3300 3400 3500 -3600 3700 3800 3900 4000 4100 4200 4300 4400 -4500 4600 4700 4800 4900 5000 5100 5200 5300 -5400 5500 5600 5700 5800 5900 diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data.vtk deleted file mode 100644 index 801a02b3e..000000000 --- a/tests/unit_tests/mesh_to_vtk/cyl-data.vtk +++ /dev/null @@ -1,41 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET STRUCTURED_GRID -DIMENSIONS 5 4 4 -POINTS 80 double -10 10 -10 11.25 10 -10 12.5 10 -10 -13.75 10 -10 15 10 -10 10 10 -10 -9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 -7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 -8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 -10 10 -10 11.25 10 -10 12.5 10 -10 -13.75 10 -10 15 10 -10 10 10 -9.3333333333 -11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 -15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 -8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 -10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 -8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 -11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 -15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 -12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 -10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 -8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 -9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 -7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 -12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 -10 10 -8 11.25 10 -8 12.5 10 -8 -13.75 10 -8 15 10 -8 10 10 -8 -9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 -7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 -8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 -10 10 -8 11.25 10 -8 12.5 10 -8 -13.75 10 -8 15 10 -8 -CELL_DATA 36 -FIELD FieldData 1 -ascending_data 1 36 double -0 100 200 300 400 500 600 700 800 -900 1000 1100 1200 1300 1400 1500 1600 1700 -1800 1900 2000 2100 2200 2300 2400 2500 2600 -2700 2800 2900 3000 3100 3200 3300 3400 3500 - diff --git a/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk deleted file mode 100644 index 24bdd7f14..000000000 --- a/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk +++ /dev/null @@ -1,198 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET UNSTRUCTURED_GRID -POINTS 195 double -7.5 5.6698729811 -10 7.5 5.6698729811 -9.3333333333 7.5 5.6698729811 -8.6666666667 -7.5 5.6698729811 -8 7.5 14.330127019 -10 7.5 14.330127019 -9.3333333333 -7.5 14.330127019 -8.6666666667 7.5 14.330127019 -8 8.125 6.7524047358 -10 -8.125 6.7524047358 -9.3333333333 8.125 6.7524047358 -8.6666666667 8.125 6.7524047358 -8 -8.125 13.247595264 -10 8.125 13.247595264 -9.3333333333 8.125 13.247595264 -8.6666666667 -8.125 13.247595264 -8 8.75 7.8349364905 -10 8.75 7.8349364905 -9.3333333333 -8.75 7.8349364905 -8.6666666667 8.75 7.8349364905 -8 8.75 12.165063509 -10 -8.75 12.165063509 -9.3333333333 8.75 12.165063509 -8.6666666667 8.75 12.165063509 -8 -9.375 8.9174682453 -10 9.375 8.9174682453 -9.3333333333 9.375 8.9174682453 -8.6666666667 -9.375 8.9174682453 -8 9.375 11.082531755 -10 9.375 11.082531755 -9.3333333333 -9.375 11.082531755 -8.6666666667 9.375 11.082531755 -8 10 10 -10 -10 10 -9.3333333333 10 10 -8.6666666667 10 10 -8 -11.25 10 -10 11.25 10 -9.3333333333 11.25 10 -8.6666666667 -11.25 10 -8 12.5 10 -10 12.5 10 -9.3333333333 -12.5 10 -8.6666666667 12.5 10 -8 13.75 10 -10 -13.75 10 -9.3333333333 13.75 10 -8.6666666667 13.75 10 -8 -13.75 10 -10 13.75 10 -9.3333333333 13.75 10 -8.6666666667 -13.75 10 -8 15 10 -10 15 10 -9.3333333333 -15 10 -8.6666666667 15 10 -8 15 10 -10 -15 10 -9.3333333333 15 10 -8.6666666667 15 10 -8 -10.625 10 -10 11.875 10 -10 13.125 10 -10 -14.375 10 -10 9.6875 10.541265877 -10 9.0625 11.623797632 -10 -8.4375 12.706329387 -10 7.8125 13.788861142 -10 9.6875 9.4587341226 -10 -9.0625 8.3762023679 -10 8.4375 7.2936706132 -10 7.8125 6.2111388584 -10 -10.625 10 -9.3333333333 11.875 10 -9.3333333333 13.125 10 -9.3333333333 -14.375 10 -9.3333333333 9.6875 10.541265877 -9.3333333333 9.0625 11.623797632 -9.3333333333 -8.4375 12.706329387 -9.3333333333 7.8125 13.788861142 -9.3333333333 9.6875 9.4587341226 -9.3333333333 -9.0625 8.3762023679 -9.3333333333 8.4375 7.2936706132 -9.3333333333 7.8125 6.2111388584 -9.3333333333 -10.625 10 -8.6666666667 11.875 10 -8.6666666667 13.125 10 -8.6666666667 -14.375 10 -8.6666666667 9.6875 10.541265877 -8.6666666667 9.0625 11.623797632 -8.6666666667 -8.4375 12.706329387 -8.6666666667 7.8125 13.788861142 -8.6666666667 9.6875 9.4587341226 -8.6666666667 -9.0625 8.3762023679 -8.6666666667 8.4375 7.2936706132 -8.6666666667 7.8125 6.2111388584 -8.6666666667 -10.625 10 -8 11.875 10 -8 13.125 10 -8 -14.375 10 -8 9.6875 10.541265877 -8 9.0625 11.623797632 -8 -8.4375 12.706329387 -8 7.8125 13.788861142 -8 9.6875 9.4587341226 -8 -9.0625 8.3762023679 -8 8.4375 7.2936706132 -8 7.8125 6.2111388584 -8 -10.625 11.082531755 -10 11.25 12.165063509 -10 11.875 13.247595264 -10 -12.5 14.330127019 -10 8.75 10 -10 7.5 10 -10 -6.25 10 -10 5 10 -10 10.625 8.9174682453 -10 -11.25 7.8349364905 -10 11.875 6.7524047358 -10 12.5 5.6698729811 -10 -10.625 11.082531755 -9.3333333333 11.25 12.165063509 -9.3333333333 11.875 13.247595264 -9.3333333333 -12.5 14.330127019 -9.3333333333 8.75 10 -9.3333333333 7.5 10 -9.3333333333 -6.25 10 -9.3333333333 5 10 -9.3333333333 10.625 8.9174682453 -9.3333333333 -11.25 7.8349364905 -9.3333333333 11.875 6.7524047358 -9.3333333333 12.5 5.6698729811 -9.3333333333 -10.625 11.082531755 -8.6666666667 11.25 12.165063509 -8.6666666667 11.875 13.247595264 -8.6666666667 -12.5 14.330127019 -8.6666666667 8.75 10 -8.6666666667 7.5 10 -8.6666666667 -6.25 10 -8.6666666667 5 10 -8.6666666667 10.625 8.9174682453 -8.6666666667 -11.25 7.8349364905 -8.6666666667 11.875 6.7524047358 -8.6666666667 12.5 5.6698729811 -8.6666666667 -10.625 11.082531755 -8 11.25 12.165063509 -8 11.875 13.247595264 -8 -12.5 14.330127019 -8 8.75 10 -8 7.5 10 -8 -6.25 10 -8 5 10 -8 10.625 8.9174682453 -8 -11.25 7.8349364905 -8 11.875 6.7524047358 -8 12.5 5.6698729811 -8 -10 10 -9.6666666667 11.25 10 -9.6666666667 12.5 10 -9.6666666667 -13.75 10 -9.6666666667 15 10 -9.6666666667 9.375 11.082531755 -9.6666666667 -8.75 12.165063509 -9.6666666667 8.125 13.247595264 -9.6666666667 7.5 14.330127019 -9.6666666667 -9.375 8.9174682453 -9.6666666667 8.75 7.8349364905 -9.6666666667 8.125 6.7524047358 -9.6666666667 -7.5 5.6698729811 -9.6666666667 10 10 -9 11.25 10 -9 -12.5 10 -9 13.75 10 -9 15 10 -9 -9.375 11.082531755 -9 8.75 12.165063509 -9 8.125 13.247595264 -9 -7.5 14.330127019 -9 9.375 8.9174682453 -9 8.75 7.8349364905 -9 -8.125 6.7524047358 -9 7.5 5.6698729811 -9 10 10 -8.3333333333 -11.25 10 -8.3333333333 12.5 10 -8.3333333333 13.75 10 -8.3333333333 -15 10 -8.3333333333 9.375 11.082531755 -8.3333333333 8.75 12.165063509 -8.3333333333 -8.125 13.247595264 -8.3333333333 7.5 14.330127019 -8.3333333333 9.375 8.9174682453 -8.3333333333 -8.75 7.8349364905 -8.3333333333 8.125 6.7524047358 -8.3333333333 7.5 5.6698729811 -8.3333333333 - -CELLS 37 720 -OFFSETS vtktypeint64 -0 20 40 60 80 100 120 140 160 -180 200 220 240 260 280 300 320 340 -360 380 400 420 440 460 480 500 520 -540 560 580 600 620 640 660 680 700 -720 -CONNECTIVITY vtktypeint64 -32 36 28 32 33 37 29 33 60 -108 64 32 72 120 76 33 156 157 -161 156 36 40 20 28 37 41 21 -29 61 109 65 108 73 121 77 120 -157 158 162 161 40 44 12 20 41 -45 13 21 62 110 66 109 74 122 -78 121 158 159 163 162 44 52 4 -12 45 53 5 13 63 111 67 110 -75 123 79 122 159 160 164 163 32 -28 24 32 33 29 25 33 64 112 -68 32 76 124 80 33 156 161 165 -156 28 20 16 24 29 21 17 25 -65 113 69 112 77 125 81 124 161 -162 166 165 20 12 8 16 21 13 -9 17 66 114 70 113 78 126 82 -125 162 163 167 166 12 4 0 8 -13 5 1 9 67 115 71 114 79 -127 83 126 163 164 168 167 32 24 -36 32 33 25 37 33 68 116 60 -32 80 128 72 33 156 165 157 156 -24 16 40 36 25 17 41 37 69 -117 61 116 81 129 73 128 165 166 -158 157 16 8 44 40 17 9 45 -41 70 118 62 117 82 130 74 129 -166 167 159 158 8 0 52 44 9 -1 53 45 71 119 63 118 83 131 -75 130 167 168 160 159 33 37 29 -33 34 38 30 34 72 120 76 33 -84 132 88 34 169 170 174 169 37 -41 21 29 38 42 22 30 73 121 -77 120 85 133 89 132 170 171 175 -174 41 45 13 21 42 46 14 22 -74 122 78 121 86 134 90 133 171 -172 176 175 45 53 5 13 46 54 -6 14 75 123 79 122 87 135 91 -134 172 173 177 176 33 29 25 33 -34 30 26 34 76 124 80 33 88 -136 92 34 169 174 178 169 29 21 -17 25 30 22 18 26 77 125 81 -124 89 137 93 136 174 175 179 178 -21 13 9 17 22 14 10 18 78 -126 82 125 90 138 94 137 175 176 -180 179 13 5 1 9 14 6 2 -10 79 127 83 126 91 139 95 138 -176 177 181 180 33 25 37 33 34 -26 38 34 80 128 72 33 92 140 -84 34 169 178 170 169 25 17 41 -37 26 18 42 38 81 129 73 128 -93 141 85 140 178 179 171 170 17 -9 45 41 18 10 46 42 82 130 -74 129 94 142 86 141 179 180 172 -171 9 1 53 45 10 2 54 46 -83 131 75 130 95 143 87 142 180 -181 173 172 34 38 30 34 35 39 -31 35 84 132 88 34 96 144 100 -35 182 183 187 182 38 42 22 30 -39 43 23 31 85 133 89 132 97 -145 101 144 183 184 188 187 42 46 -14 22 43 47 15 23 86 134 90 -133 98 146 102 145 184 185 189 188 -46 54 6 14 47 55 7 15 87 -135 91 134 99 147 103 146 185 186 -190 189 34 30 26 34 35 31 27 -35 88 136 92 34 100 148 104 35 -182 187 191 182 30 22 18 26 31 -23 19 27 89 137 93 136 101 149 -105 148 187 188 192 191 22 14 10 -18 23 15 11 19 90 138 94 137 -102 150 106 149 188 189 193 192 14 -6 2 10 15 7 3 11 91 139 -95 138 103 151 107 150 189 190 194 -193 34 26 38 34 35 27 39 35 -92 140 84 34 104 152 96 35 182 -191 183 182 26 18 42 38 27 19 -43 39 93 141 85 140 105 153 97 -152 191 192 184 183 18 10 46 42 -19 11 47 43 94 142 86 141 106 -154 98 153 192 193 185 184 10 2 -54 46 11 3 55 47 95 143 87 -142 107 155 99 154 193 194 186 185 - -CELL_TYPES 36 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 - diff --git a/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk b/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk deleted file mode 100644 index 33d1ce497..000000000 --- a/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk +++ /dev/null @@ -1,33 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET STRUCTURED_GRID -DIMENSIONS 5 4 4 -POINTS 80 double -10 10 -10 11.25 10 -10 12.5 10 -10 -13.75 10 -10 15 10 -10 10 10 -10 -9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 -7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 -8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 -10 10 -10 11.25 10 -10 12.5 10 -10 -13.75 10 -10 15 10 -10 10 10 -9.3333333333 -11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 -15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 -8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 -10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 -8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 -11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 -15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 -12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 -10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 -8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 -9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 -7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 -12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 -10 10 -8 11.25 10 -8 12.5 10 -8 -13.75 10 -8 15 10 -8 10 10 -8 -9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 -7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 -8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 -10 10 -8 11.25 10 -8 12.5 10 -8 -13.75 10 -8 15 10 -8 diff --git a/tests/unit_tests/mesh_to_vtk/rectilinear.vtk b/tests/unit_tests/mesh_to_vtk/rectilinear.vtk deleted file mode 100644 index 71826392e..000000000 --- a/tests/unit_tests/mesh_to_vtk/rectilinear.vtk +++ /dev/null @@ -1,340 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET STRUCTURED_GRID -DIMENSIONS 5 10 20 -POINTS 1000 double -0 5 1 2.5 5 1 5 5 1 -7.5 5 1 10 5 1 0 5.8326451979 1 -2.5 5.8326451979 1 5 5.8326451979 1 7.5 5.8326451979 1 -10 5.8326451979 1 0 6.8039500009 1 2.5 6.8039500009 1 -5 6.8039500009 1 7.5 6.8039500009 1 10 6.8039500009 1 -0 7.9370052598 1 2.5 7.9370052598 1 5 7.9370052598 1 -7.5 7.9370052598 1 10 7.9370052598 1 0 9.2587471229 1 -2.5 9.2587471229 1 5 9.2587471229 1 7.5 9.2587471229 1 -10 9.2587471229 1 0 10.800597389 1 2.5 10.800597389 1 -5 10.800597389 1 7.5 10.800597389 1 10 10.800597389 1 -0 12.599210499 1 2.5 12.599210499 1 5 12.599210499 1 -7.5 12.599210499 1 10 12.599210499 1 0 14.697344923 1 -2.5 14.697344923 1 5 14.697344923 1 7.5 14.697344923 1 -10 14.697344923 1 0 17.144879657 1 2.5 17.144879657 1 -5 17.144879657 1 7.5 17.144879657 1 10 17.144879657 1 -0 20 1 2.5 20 1 5 20 1 -7.5 20 1 10 20 1 0 5 6.2105263158 -2.5 5 6.2105263158 5 5 6.2105263158 7.5 5 6.2105263158 -10 5 6.2105263158 0 5.8326451979 6.2105263158 2.5 5.8326451979 6.2105263158 -5 5.8326451979 6.2105263158 7.5 5.8326451979 6.2105263158 10 5.8326451979 6.2105263158 -0 6.8039500009 6.2105263158 2.5 6.8039500009 6.2105263158 5 6.8039500009 6.2105263158 -7.5 6.8039500009 6.2105263158 10 6.8039500009 6.2105263158 0 7.9370052598 6.2105263158 -2.5 7.9370052598 6.2105263158 5 7.9370052598 6.2105263158 7.5 7.9370052598 6.2105263158 -10 7.9370052598 6.2105263158 0 9.2587471229 6.2105263158 2.5 9.2587471229 6.2105263158 -5 9.2587471229 6.2105263158 7.5 9.2587471229 6.2105263158 10 9.2587471229 6.2105263158 -0 10.800597389 6.2105263158 2.5 10.800597389 6.2105263158 5 10.800597389 6.2105263158 -7.5 10.800597389 6.2105263158 10 10.800597389 6.2105263158 0 12.599210499 6.2105263158 -2.5 12.599210499 6.2105263158 5 12.599210499 6.2105263158 7.5 12.599210499 6.2105263158 -10 12.599210499 6.2105263158 0 14.697344923 6.2105263158 2.5 14.697344923 6.2105263158 -5 14.697344923 6.2105263158 7.5 14.697344923 6.2105263158 10 14.697344923 6.2105263158 -0 17.144879657 6.2105263158 2.5 17.144879657 6.2105263158 5 17.144879657 6.2105263158 -7.5 17.144879657 6.2105263158 10 17.144879657 6.2105263158 0 20 6.2105263158 -2.5 20 6.2105263158 5 20 6.2105263158 7.5 20 6.2105263158 -10 20 6.2105263158 0 5 11.421052632 2.5 5 11.421052632 -5 5 11.421052632 7.5 5 11.421052632 10 5 11.421052632 -0 5.8326451979 11.421052632 2.5 5.8326451979 11.421052632 5 5.8326451979 11.421052632 -7.5 5.8326451979 11.421052632 10 5.8326451979 11.421052632 0 6.8039500009 11.421052632 -2.5 6.8039500009 11.421052632 5 6.8039500009 11.421052632 7.5 6.8039500009 11.421052632 -10 6.8039500009 11.421052632 0 7.9370052598 11.421052632 2.5 7.9370052598 11.421052632 -5 7.9370052598 11.421052632 7.5 7.9370052598 11.421052632 10 7.9370052598 11.421052632 -0 9.2587471229 11.421052632 2.5 9.2587471229 11.421052632 5 9.2587471229 11.421052632 -7.5 9.2587471229 11.421052632 10 9.2587471229 11.421052632 0 10.800597389 11.421052632 -2.5 10.800597389 11.421052632 5 10.800597389 11.421052632 7.5 10.800597389 11.421052632 -10 10.800597389 11.421052632 0 12.599210499 11.421052632 2.5 12.599210499 11.421052632 -5 12.599210499 11.421052632 7.5 12.599210499 11.421052632 10 12.599210499 11.421052632 -0 14.697344923 11.421052632 2.5 14.697344923 11.421052632 5 14.697344923 11.421052632 -7.5 14.697344923 11.421052632 10 14.697344923 11.421052632 0 17.144879657 11.421052632 -2.5 17.144879657 11.421052632 5 17.144879657 11.421052632 7.5 17.144879657 11.421052632 -10 17.144879657 11.421052632 0 20 11.421052632 2.5 20 11.421052632 -5 20 11.421052632 7.5 20 11.421052632 10 20 11.421052632 -0 5 16.631578947 2.5 5 16.631578947 5 5 16.631578947 -7.5 5 16.631578947 10 5 16.631578947 0 5.8326451979 16.631578947 -2.5 5.8326451979 16.631578947 5 5.8326451979 16.631578947 7.5 5.8326451979 16.631578947 -10 5.8326451979 16.631578947 0 6.8039500009 16.631578947 2.5 6.8039500009 16.631578947 -5 6.8039500009 16.631578947 7.5 6.8039500009 16.631578947 10 6.8039500009 16.631578947 -0 7.9370052598 16.631578947 2.5 7.9370052598 16.631578947 5 7.9370052598 16.631578947 -7.5 7.9370052598 16.631578947 10 7.9370052598 16.631578947 0 9.2587471229 16.631578947 -2.5 9.2587471229 16.631578947 5 9.2587471229 16.631578947 7.5 9.2587471229 16.631578947 -10 9.2587471229 16.631578947 0 10.800597389 16.631578947 2.5 10.800597389 16.631578947 -5 10.800597389 16.631578947 7.5 10.800597389 16.631578947 10 10.800597389 16.631578947 -0 12.599210499 16.631578947 2.5 12.599210499 16.631578947 5 12.599210499 16.631578947 -7.5 12.599210499 16.631578947 10 12.599210499 16.631578947 0 14.697344923 16.631578947 -2.5 14.697344923 16.631578947 5 14.697344923 16.631578947 7.5 14.697344923 16.631578947 -10 14.697344923 16.631578947 0 17.144879657 16.631578947 2.5 17.144879657 16.631578947 -5 17.144879657 16.631578947 7.5 17.144879657 16.631578947 10 17.144879657 16.631578947 -0 20 16.631578947 2.5 20 16.631578947 5 20 16.631578947 -7.5 20 16.631578947 10 20 16.631578947 0 5 21.842105263 -2.5 5 21.842105263 5 5 21.842105263 7.5 5 21.842105263 -10 5 21.842105263 0 5.8326451979 21.842105263 2.5 5.8326451979 21.842105263 -5 5.8326451979 21.842105263 7.5 5.8326451979 21.842105263 10 5.8326451979 21.842105263 -0 6.8039500009 21.842105263 2.5 6.8039500009 21.842105263 5 6.8039500009 21.842105263 -7.5 6.8039500009 21.842105263 10 6.8039500009 21.842105263 0 7.9370052598 21.842105263 -2.5 7.9370052598 21.842105263 5 7.9370052598 21.842105263 7.5 7.9370052598 21.842105263 -10 7.9370052598 21.842105263 0 9.2587471229 21.842105263 2.5 9.2587471229 21.842105263 -5 9.2587471229 21.842105263 7.5 9.2587471229 21.842105263 10 9.2587471229 21.842105263 -0 10.800597389 21.842105263 2.5 10.800597389 21.842105263 5 10.800597389 21.842105263 -7.5 10.800597389 21.842105263 10 10.800597389 21.842105263 0 12.599210499 21.842105263 -2.5 12.599210499 21.842105263 5 12.599210499 21.842105263 7.5 12.599210499 21.842105263 -10 12.599210499 21.842105263 0 14.697344923 21.842105263 2.5 14.697344923 21.842105263 -5 14.697344923 21.842105263 7.5 14.697344923 21.842105263 10 14.697344923 21.842105263 -0 17.144879657 21.842105263 2.5 17.144879657 21.842105263 5 17.144879657 21.842105263 -7.5 17.144879657 21.842105263 10 17.144879657 21.842105263 0 20 21.842105263 -2.5 20 21.842105263 5 20 21.842105263 7.5 20 21.842105263 -10 20 21.842105263 0 5 27.052631579 2.5 5 27.052631579 -5 5 27.052631579 7.5 5 27.052631579 10 5 27.052631579 -0 5.8326451979 27.052631579 2.5 5.8326451979 27.052631579 5 5.8326451979 27.052631579 -7.5 5.8326451979 27.052631579 10 5.8326451979 27.052631579 0 6.8039500009 27.052631579 -2.5 6.8039500009 27.052631579 5 6.8039500009 27.052631579 7.5 6.8039500009 27.052631579 -10 6.8039500009 27.052631579 0 7.9370052598 27.052631579 2.5 7.9370052598 27.052631579 -5 7.9370052598 27.052631579 7.5 7.9370052598 27.052631579 10 7.9370052598 27.052631579 -0 9.2587471229 27.052631579 2.5 9.2587471229 27.052631579 5 9.2587471229 27.052631579 -7.5 9.2587471229 27.052631579 10 9.2587471229 27.052631579 0 10.800597389 27.052631579 -2.5 10.800597389 27.052631579 5 10.800597389 27.052631579 7.5 10.800597389 27.052631579 -10 10.800597389 27.052631579 0 12.599210499 27.052631579 2.5 12.599210499 27.052631579 -5 12.599210499 27.052631579 7.5 12.599210499 27.052631579 10 12.599210499 27.052631579 -0 14.697344923 27.052631579 2.5 14.697344923 27.052631579 5 14.697344923 27.052631579 -7.5 14.697344923 27.052631579 10 14.697344923 27.052631579 0 17.144879657 27.052631579 -2.5 17.144879657 27.052631579 5 17.144879657 27.052631579 7.5 17.144879657 27.052631579 -10 17.144879657 27.052631579 0 20 27.052631579 2.5 20 27.052631579 -5 20 27.052631579 7.5 20 27.052631579 10 20 27.052631579 -0 5 32.263157895 2.5 5 32.263157895 5 5 32.263157895 -7.5 5 32.263157895 10 5 32.263157895 0 5.8326451979 32.263157895 -2.5 5.8326451979 32.263157895 5 5.8326451979 32.263157895 7.5 5.8326451979 32.263157895 -10 5.8326451979 32.263157895 0 6.8039500009 32.263157895 2.5 6.8039500009 32.263157895 -5 6.8039500009 32.263157895 7.5 6.8039500009 32.263157895 10 6.8039500009 32.263157895 -0 7.9370052598 32.263157895 2.5 7.9370052598 32.263157895 5 7.9370052598 32.263157895 -7.5 7.9370052598 32.263157895 10 7.9370052598 32.263157895 0 9.2587471229 32.263157895 -2.5 9.2587471229 32.263157895 5 9.2587471229 32.263157895 7.5 9.2587471229 32.263157895 -10 9.2587471229 32.263157895 0 10.800597389 32.263157895 2.5 10.800597389 32.263157895 -5 10.800597389 32.263157895 7.5 10.800597389 32.263157895 10 10.800597389 32.263157895 -0 12.599210499 32.263157895 2.5 12.599210499 32.263157895 5 12.599210499 32.263157895 -7.5 12.599210499 32.263157895 10 12.599210499 32.263157895 0 14.697344923 32.263157895 -2.5 14.697344923 32.263157895 5 14.697344923 32.263157895 7.5 14.697344923 32.263157895 -10 14.697344923 32.263157895 0 17.144879657 32.263157895 2.5 17.144879657 32.263157895 -5 17.144879657 32.263157895 7.5 17.144879657 32.263157895 10 17.144879657 32.263157895 -0 20 32.263157895 2.5 20 32.263157895 5 20 32.263157895 -7.5 20 32.263157895 10 20 32.263157895 0 5 37.473684211 -2.5 5 37.473684211 5 5 37.473684211 7.5 5 37.473684211 -10 5 37.473684211 0 5.8326451979 37.473684211 2.5 5.8326451979 37.473684211 -5 5.8326451979 37.473684211 7.5 5.8326451979 37.473684211 10 5.8326451979 37.473684211 -0 6.8039500009 37.473684211 2.5 6.8039500009 37.473684211 5 6.8039500009 37.473684211 -7.5 6.8039500009 37.473684211 10 6.8039500009 37.473684211 0 7.9370052598 37.473684211 -2.5 7.9370052598 37.473684211 5 7.9370052598 37.473684211 7.5 7.9370052598 37.473684211 -10 7.9370052598 37.473684211 0 9.2587471229 37.473684211 2.5 9.2587471229 37.473684211 -5 9.2587471229 37.473684211 7.5 9.2587471229 37.473684211 10 9.2587471229 37.473684211 -0 10.800597389 37.473684211 2.5 10.800597389 37.473684211 5 10.800597389 37.473684211 -7.5 10.800597389 37.473684211 10 10.800597389 37.473684211 0 12.599210499 37.473684211 -2.5 12.599210499 37.473684211 5 12.599210499 37.473684211 7.5 12.599210499 37.473684211 -10 12.599210499 37.473684211 0 14.697344923 37.473684211 2.5 14.697344923 37.473684211 -5 14.697344923 37.473684211 7.5 14.697344923 37.473684211 10 14.697344923 37.473684211 -0 17.144879657 37.473684211 2.5 17.144879657 37.473684211 5 17.144879657 37.473684211 -7.5 17.144879657 37.473684211 10 17.144879657 37.473684211 0 20 37.473684211 -2.5 20 37.473684211 5 20 37.473684211 7.5 20 37.473684211 -10 20 37.473684211 0 5 42.684210526 2.5 5 42.684210526 -5 5 42.684210526 7.5 5 42.684210526 10 5 42.684210526 -0 5.8326451979 42.684210526 2.5 5.8326451979 42.684210526 5 5.8326451979 42.684210526 -7.5 5.8326451979 42.684210526 10 5.8326451979 42.684210526 0 6.8039500009 42.684210526 -2.5 6.8039500009 42.684210526 5 6.8039500009 42.684210526 7.5 6.8039500009 42.684210526 -10 6.8039500009 42.684210526 0 7.9370052598 42.684210526 2.5 7.9370052598 42.684210526 -5 7.9370052598 42.684210526 7.5 7.9370052598 42.684210526 10 7.9370052598 42.684210526 -0 9.2587471229 42.684210526 2.5 9.2587471229 42.684210526 5 9.2587471229 42.684210526 -7.5 9.2587471229 42.684210526 10 9.2587471229 42.684210526 0 10.800597389 42.684210526 -2.5 10.800597389 42.684210526 5 10.800597389 42.684210526 7.5 10.800597389 42.684210526 -10 10.800597389 42.684210526 0 12.599210499 42.684210526 2.5 12.599210499 42.684210526 -5 12.599210499 42.684210526 7.5 12.599210499 42.684210526 10 12.599210499 42.684210526 -0 14.697344923 42.684210526 2.5 14.697344923 42.684210526 5 14.697344923 42.684210526 -7.5 14.697344923 42.684210526 10 14.697344923 42.684210526 0 17.144879657 42.684210526 -2.5 17.144879657 42.684210526 5 17.144879657 42.684210526 7.5 17.144879657 42.684210526 -10 17.144879657 42.684210526 0 20 42.684210526 2.5 20 42.684210526 -5 20 42.684210526 7.5 20 42.684210526 10 20 42.684210526 -0 5 47.894736842 2.5 5 47.894736842 5 5 47.894736842 -7.5 5 47.894736842 10 5 47.894736842 0 5.8326451979 47.894736842 -2.5 5.8326451979 47.894736842 5 5.8326451979 47.894736842 7.5 5.8326451979 47.894736842 -10 5.8326451979 47.894736842 0 6.8039500009 47.894736842 2.5 6.8039500009 47.894736842 -5 6.8039500009 47.894736842 7.5 6.8039500009 47.894736842 10 6.8039500009 47.894736842 -0 7.9370052598 47.894736842 2.5 7.9370052598 47.894736842 5 7.9370052598 47.894736842 -7.5 7.9370052598 47.894736842 10 7.9370052598 47.894736842 0 9.2587471229 47.894736842 -2.5 9.2587471229 47.894736842 5 9.2587471229 47.894736842 7.5 9.2587471229 47.894736842 -10 9.2587471229 47.894736842 0 10.800597389 47.894736842 2.5 10.800597389 47.894736842 -5 10.800597389 47.894736842 7.5 10.800597389 47.894736842 10 10.800597389 47.894736842 -0 12.599210499 47.894736842 2.5 12.599210499 47.894736842 5 12.599210499 47.894736842 -7.5 12.599210499 47.894736842 10 12.599210499 47.894736842 0 14.697344923 47.894736842 -2.5 14.697344923 47.894736842 5 14.697344923 47.894736842 7.5 14.697344923 47.894736842 -10 14.697344923 47.894736842 0 17.144879657 47.894736842 2.5 17.144879657 47.894736842 -5 17.144879657 47.894736842 7.5 17.144879657 47.894736842 10 17.144879657 47.894736842 -0 20 47.894736842 2.5 20 47.894736842 5 20 47.894736842 -7.5 20 47.894736842 10 20 47.894736842 0 5 53.105263158 -2.5 5 53.105263158 5 5 53.105263158 7.5 5 53.105263158 -10 5 53.105263158 0 5.8326451979 53.105263158 2.5 5.8326451979 53.105263158 -5 5.8326451979 53.105263158 7.5 5.8326451979 53.105263158 10 5.8326451979 53.105263158 -0 6.8039500009 53.105263158 2.5 6.8039500009 53.105263158 5 6.8039500009 53.105263158 -7.5 6.8039500009 53.105263158 10 6.8039500009 53.105263158 0 7.9370052598 53.105263158 -2.5 7.9370052598 53.105263158 5 7.9370052598 53.105263158 7.5 7.9370052598 53.105263158 -10 7.9370052598 53.105263158 0 9.2587471229 53.105263158 2.5 9.2587471229 53.105263158 -5 9.2587471229 53.105263158 7.5 9.2587471229 53.105263158 10 9.2587471229 53.105263158 -0 10.800597389 53.105263158 2.5 10.800597389 53.105263158 5 10.800597389 53.105263158 -7.5 10.800597389 53.105263158 10 10.800597389 53.105263158 0 12.599210499 53.105263158 -2.5 12.599210499 53.105263158 5 12.599210499 53.105263158 7.5 12.599210499 53.105263158 -10 12.599210499 53.105263158 0 14.697344923 53.105263158 2.5 14.697344923 53.105263158 -5 14.697344923 53.105263158 7.5 14.697344923 53.105263158 10 14.697344923 53.105263158 -0 17.144879657 53.105263158 2.5 17.144879657 53.105263158 5 17.144879657 53.105263158 -7.5 17.144879657 53.105263158 10 17.144879657 53.105263158 0 20 53.105263158 -2.5 20 53.105263158 5 20 53.105263158 7.5 20 53.105263158 -10 20 53.105263158 0 5 58.315789474 2.5 5 58.315789474 -5 5 58.315789474 7.5 5 58.315789474 10 5 58.315789474 -0 5.8326451979 58.315789474 2.5 5.8326451979 58.315789474 5 5.8326451979 58.315789474 -7.5 5.8326451979 58.315789474 10 5.8326451979 58.315789474 0 6.8039500009 58.315789474 -2.5 6.8039500009 58.315789474 5 6.8039500009 58.315789474 7.5 6.8039500009 58.315789474 -10 6.8039500009 58.315789474 0 7.9370052598 58.315789474 2.5 7.9370052598 58.315789474 -5 7.9370052598 58.315789474 7.5 7.9370052598 58.315789474 10 7.9370052598 58.315789474 -0 9.2587471229 58.315789474 2.5 9.2587471229 58.315789474 5 9.2587471229 58.315789474 -7.5 9.2587471229 58.315789474 10 9.2587471229 58.315789474 0 10.800597389 58.315789474 -2.5 10.800597389 58.315789474 5 10.800597389 58.315789474 7.5 10.800597389 58.315789474 -10 10.800597389 58.315789474 0 12.599210499 58.315789474 2.5 12.599210499 58.315789474 -5 12.599210499 58.315789474 7.5 12.599210499 58.315789474 10 12.599210499 58.315789474 -0 14.697344923 58.315789474 2.5 14.697344923 58.315789474 5 14.697344923 58.315789474 -7.5 14.697344923 58.315789474 10 14.697344923 58.315789474 0 17.144879657 58.315789474 -2.5 17.144879657 58.315789474 5 17.144879657 58.315789474 7.5 17.144879657 58.315789474 -10 17.144879657 58.315789474 0 20 58.315789474 2.5 20 58.315789474 -5 20 58.315789474 7.5 20 58.315789474 10 20 58.315789474 -0 5 63.526315789 2.5 5 63.526315789 5 5 63.526315789 -7.5 5 63.526315789 10 5 63.526315789 0 5.8326451979 63.526315789 -2.5 5.8326451979 63.526315789 5 5.8326451979 63.526315789 7.5 5.8326451979 63.526315789 -10 5.8326451979 63.526315789 0 6.8039500009 63.526315789 2.5 6.8039500009 63.526315789 -5 6.8039500009 63.526315789 7.5 6.8039500009 63.526315789 10 6.8039500009 63.526315789 -0 7.9370052598 63.526315789 2.5 7.9370052598 63.526315789 5 7.9370052598 63.526315789 -7.5 7.9370052598 63.526315789 10 7.9370052598 63.526315789 0 9.2587471229 63.526315789 -2.5 9.2587471229 63.526315789 5 9.2587471229 63.526315789 7.5 9.2587471229 63.526315789 -10 9.2587471229 63.526315789 0 10.800597389 63.526315789 2.5 10.800597389 63.526315789 -5 10.800597389 63.526315789 7.5 10.800597389 63.526315789 10 10.800597389 63.526315789 -0 12.599210499 63.526315789 2.5 12.599210499 63.526315789 5 12.599210499 63.526315789 -7.5 12.599210499 63.526315789 10 12.599210499 63.526315789 0 14.697344923 63.526315789 -2.5 14.697344923 63.526315789 5 14.697344923 63.526315789 7.5 14.697344923 63.526315789 -10 14.697344923 63.526315789 0 17.144879657 63.526315789 2.5 17.144879657 63.526315789 -5 17.144879657 63.526315789 7.5 17.144879657 63.526315789 10 17.144879657 63.526315789 -0 20 63.526315789 2.5 20 63.526315789 5 20 63.526315789 -7.5 20 63.526315789 10 20 63.526315789 0 5 68.736842105 -2.5 5 68.736842105 5 5 68.736842105 7.5 5 68.736842105 -10 5 68.736842105 0 5.8326451979 68.736842105 2.5 5.8326451979 68.736842105 -5 5.8326451979 68.736842105 7.5 5.8326451979 68.736842105 10 5.8326451979 68.736842105 -0 6.8039500009 68.736842105 2.5 6.8039500009 68.736842105 5 6.8039500009 68.736842105 -7.5 6.8039500009 68.736842105 10 6.8039500009 68.736842105 0 7.9370052598 68.736842105 -2.5 7.9370052598 68.736842105 5 7.9370052598 68.736842105 7.5 7.9370052598 68.736842105 -10 7.9370052598 68.736842105 0 9.2587471229 68.736842105 2.5 9.2587471229 68.736842105 -5 9.2587471229 68.736842105 7.5 9.2587471229 68.736842105 10 9.2587471229 68.736842105 -0 10.800597389 68.736842105 2.5 10.800597389 68.736842105 5 10.800597389 68.736842105 -7.5 10.800597389 68.736842105 10 10.800597389 68.736842105 0 12.599210499 68.736842105 -2.5 12.599210499 68.736842105 5 12.599210499 68.736842105 7.5 12.599210499 68.736842105 -10 12.599210499 68.736842105 0 14.697344923 68.736842105 2.5 14.697344923 68.736842105 -5 14.697344923 68.736842105 7.5 14.697344923 68.736842105 10 14.697344923 68.736842105 -0 17.144879657 68.736842105 2.5 17.144879657 68.736842105 5 17.144879657 68.736842105 -7.5 17.144879657 68.736842105 10 17.144879657 68.736842105 0 20 68.736842105 -2.5 20 68.736842105 5 20 68.736842105 7.5 20 68.736842105 -10 20 68.736842105 0 5 73.947368421 2.5 5 73.947368421 -5 5 73.947368421 7.5 5 73.947368421 10 5 73.947368421 -0 5.8326451979 73.947368421 2.5 5.8326451979 73.947368421 5 5.8326451979 73.947368421 -7.5 5.8326451979 73.947368421 10 5.8326451979 73.947368421 0 6.8039500009 73.947368421 -2.5 6.8039500009 73.947368421 5 6.8039500009 73.947368421 7.5 6.8039500009 73.947368421 -10 6.8039500009 73.947368421 0 7.9370052598 73.947368421 2.5 7.9370052598 73.947368421 -5 7.9370052598 73.947368421 7.5 7.9370052598 73.947368421 10 7.9370052598 73.947368421 -0 9.2587471229 73.947368421 2.5 9.2587471229 73.947368421 5 9.2587471229 73.947368421 -7.5 9.2587471229 73.947368421 10 9.2587471229 73.947368421 0 10.800597389 73.947368421 -2.5 10.800597389 73.947368421 5 10.800597389 73.947368421 7.5 10.800597389 73.947368421 -10 10.800597389 73.947368421 0 12.599210499 73.947368421 2.5 12.599210499 73.947368421 -5 12.599210499 73.947368421 7.5 12.599210499 73.947368421 10 12.599210499 73.947368421 -0 14.697344923 73.947368421 2.5 14.697344923 73.947368421 5 14.697344923 73.947368421 -7.5 14.697344923 73.947368421 10 14.697344923 73.947368421 0 17.144879657 73.947368421 -2.5 17.144879657 73.947368421 5 17.144879657 73.947368421 7.5 17.144879657 73.947368421 -10 17.144879657 73.947368421 0 20 73.947368421 2.5 20 73.947368421 -5 20 73.947368421 7.5 20 73.947368421 10 20 73.947368421 -0 5 79.157894737 2.5 5 79.157894737 5 5 79.157894737 -7.5 5 79.157894737 10 5 79.157894737 0 5.8326451979 79.157894737 -2.5 5.8326451979 79.157894737 5 5.8326451979 79.157894737 7.5 5.8326451979 79.157894737 -10 5.8326451979 79.157894737 0 6.8039500009 79.157894737 2.5 6.8039500009 79.157894737 -5 6.8039500009 79.157894737 7.5 6.8039500009 79.157894737 10 6.8039500009 79.157894737 -0 7.9370052598 79.157894737 2.5 7.9370052598 79.157894737 5 7.9370052598 79.157894737 -7.5 7.9370052598 79.157894737 10 7.9370052598 79.157894737 0 9.2587471229 79.157894737 -2.5 9.2587471229 79.157894737 5 9.2587471229 79.157894737 7.5 9.2587471229 79.157894737 -10 9.2587471229 79.157894737 0 10.800597389 79.157894737 2.5 10.800597389 79.157894737 -5 10.800597389 79.157894737 7.5 10.800597389 79.157894737 10 10.800597389 79.157894737 -0 12.599210499 79.157894737 2.5 12.599210499 79.157894737 5 12.599210499 79.157894737 -7.5 12.599210499 79.157894737 10 12.599210499 79.157894737 0 14.697344923 79.157894737 -2.5 14.697344923 79.157894737 5 14.697344923 79.157894737 7.5 14.697344923 79.157894737 -10 14.697344923 79.157894737 0 17.144879657 79.157894737 2.5 17.144879657 79.157894737 -5 17.144879657 79.157894737 7.5 17.144879657 79.157894737 10 17.144879657 79.157894737 -0 20 79.157894737 2.5 20 79.157894737 5 20 79.157894737 -7.5 20 79.157894737 10 20 79.157894737 0 5 84.368421053 -2.5 5 84.368421053 5 5 84.368421053 7.5 5 84.368421053 -10 5 84.368421053 0 5.8326451979 84.368421053 2.5 5.8326451979 84.368421053 -5 5.8326451979 84.368421053 7.5 5.8326451979 84.368421053 10 5.8326451979 84.368421053 -0 6.8039500009 84.368421053 2.5 6.8039500009 84.368421053 5 6.8039500009 84.368421053 -7.5 6.8039500009 84.368421053 10 6.8039500009 84.368421053 0 7.9370052598 84.368421053 -2.5 7.9370052598 84.368421053 5 7.9370052598 84.368421053 7.5 7.9370052598 84.368421053 -10 7.9370052598 84.368421053 0 9.2587471229 84.368421053 2.5 9.2587471229 84.368421053 -5 9.2587471229 84.368421053 7.5 9.2587471229 84.368421053 10 9.2587471229 84.368421053 -0 10.800597389 84.368421053 2.5 10.800597389 84.368421053 5 10.800597389 84.368421053 -7.5 10.800597389 84.368421053 10 10.800597389 84.368421053 0 12.599210499 84.368421053 -2.5 12.599210499 84.368421053 5 12.599210499 84.368421053 7.5 12.599210499 84.368421053 -10 12.599210499 84.368421053 0 14.697344923 84.368421053 2.5 14.697344923 84.368421053 -5 14.697344923 84.368421053 7.5 14.697344923 84.368421053 10 14.697344923 84.368421053 -0 17.144879657 84.368421053 2.5 17.144879657 84.368421053 5 17.144879657 84.368421053 -7.5 17.144879657 84.368421053 10 17.144879657 84.368421053 0 20 84.368421053 -2.5 20 84.368421053 5 20 84.368421053 7.5 20 84.368421053 -10 20 84.368421053 0 5 89.578947368 2.5 5 89.578947368 -5 5 89.578947368 7.5 5 89.578947368 10 5 89.578947368 -0 5.8326451979 89.578947368 2.5 5.8326451979 89.578947368 5 5.8326451979 89.578947368 -7.5 5.8326451979 89.578947368 10 5.8326451979 89.578947368 0 6.8039500009 89.578947368 -2.5 6.8039500009 89.578947368 5 6.8039500009 89.578947368 7.5 6.8039500009 89.578947368 -10 6.8039500009 89.578947368 0 7.9370052598 89.578947368 2.5 7.9370052598 89.578947368 -5 7.9370052598 89.578947368 7.5 7.9370052598 89.578947368 10 7.9370052598 89.578947368 -0 9.2587471229 89.578947368 2.5 9.2587471229 89.578947368 5 9.2587471229 89.578947368 -7.5 9.2587471229 89.578947368 10 9.2587471229 89.578947368 0 10.800597389 89.578947368 -2.5 10.800597389 89.578947368 5 10.800597389 89.578947368 7.5 10.800597389 89.578947368 -10 10.800597389 89.578947368 0 12.599210499 89.578947368 2.5 12.599210499 89.578947368 -5 12.599210499 89.578947368 7.5 12.599210499 89.578947368 10 12.599210499 89.578947368 -0 14.697344923 89.578947368 2.5 14.697344923 89.578947368 5 14.697344923 89.578947368 -7.5 14.697344923 89.578947368 10 14.697344923 89.578947368 0 17.144879657 89.578947368 -2.5 17.144879657 89.578947368 5 17.144879657 89.578947368 7.5 17.144879657 89.578947368 -10 17.144879657 89.578947368 0 20 89.578947368 2.5 20 89.578947368 -5 20 89.578947368 7.5 20 89.578947368 10 20 89.578947368 -0 5 94.789473684 2.5 5 94.789473684 5 5 94.789473684 -7.5 5 94.789473684 10 5 94.789473684 0 5.8326451979 94.789473684 -2.5 5.8326451979 94.789473684 5 5.8326451979 94.789473684 7.5 5.8326451979 94.789473684 -10 5.8326451979 94.789473684 0 6.8039500009 94.789473684 2.5 6.8039500009 94.789473684 -5 6.8039500009 94.789473684 7.5 6.8039500009 94.789473684 10 6.8039500009 94.789473684 -0 7.9370052598 94.789473684 2.5 7.9370052598 94.789473684 5 7.9370052598 94.789473684 -7.5 7.9370052598 94.789473684 10 7.9370052598 94.789473684 0 9.2587471229 94.789473684 -2.5 9.2587471229 94.789473684 5 9.2587471229 94.789473684 7.5 9.2587471229 94.789473684 -10 9.2587471229 94.789473684 0 10.800597389 94.789473684 2.5 10.800597389 94.789473684 -5 10.800597389 94.789473684 7.5 10.800597389 94.789473684 10 10.800597389 94.789473684 -0 12.599210499 94.789473684 2.5 12.599210499 94.789473684 5 12.599210499 94.789473684 -7.5 12.599210499 94.789473684 10 12.599210499 94.789473684 0 14.697344923 94.789473684 -2.5 14.697344923 94.789473684 5 14.697344923 94.789473684 7.5 14.697344923 94.789473684 -10 14.697344923 94.789473684 0 17.144879657 94.789473684 2.5 17.144879657 94.789473684 -5 17.144879657 94.789473684 7.5 17.144879657 94.789473684 10 17.144879657 94.789473684 -0 20 94.789473684 2.5 20 94.789473684 5 20 94.789473684 -7.5 20 94.789473684 10 20 94.789473684 0 5 100 -2.5 5 100 5 5 100 7.5 5 100 -10 5 100 0 5.8326451979 100 2.5 5.8326451979 100 -5 5.8326451979 100 7.5 5.8326451979 100 10 5.8326451979 100 -0 6.8039500009 100 2.5 6.8039500009 100 5 6.8039500009 100 -7.5 6.8039500009 100 10 6.8039500009 100 0 7.9370052598 100 -2.5 7.9370052598 100 5 7.9370052598 100 7.5 7.9370052598 100 -10 7.9370052598 100 0 9.2587471229 100 2.5 9.2587471229 100 -5 9.2587471229 100 7.5 9.2587471229 100 10 9.2587471229 100 -0 10.800597389 100 2.5 10.800597389 100 5 10.800597389 100 -7.5 10.800597389 100 10 10.800597389 100 0 12.599210499 100 -2.5 12.599210499 100 5 12.599210499 100 7.5 12.599210499 100 -10 12.599210499 100 0 14.697344923 100 2.5 14.697344923 100 -5 14.697344923 100 7.5 14.697344923 100 10 14.697344923 100 -0 17.144879657 100 2.5 17.144879657 100 5 17.144879657 100 -7.5 17.144879657 100 10 17.144879657 100 0 20 100 -2.5 20 100 5 20 100 7.5 20 100 -10 20 100 diff --git a/tests/unit_tests/mesh_to_vtk/regular.vtk b/tests/unit_tests/mesh_to_vtk/regular.vtk deleted file mode 100644 index 8f8aca5a6..000000000 --- a/tests/unit_tests/mesh_to_vtk/regular.vtk +++ /dev/null @@ -1,2394 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET STRUCTURED_GRID -DIMENSIONS 11 21 31 -POINTS 7161 double -0 0 0 2 0 0 4 0 0 -6 0 0 8 0 0 10 0 0 -12 0 0 14 0 0 16 0 0 -18 0 0 20 0 0 0 2.5 0 -2 2.5 0 4 2.5 0 6 2.5 0 -8 2.5 0 10 2.5 0 12 2.5 0 -14 2.5 0 16 2.5 0 18 2.5 0 -20 2.5 0 0 5 0 2 5 0 -4 5 0 6 5 0 8 5 0 -10 5 0 12 5 0 14 5 0 -16 5 0 18 5 0 20 5 0 -0 7.5 0 2 7.5 0 4 7.5 0 -6 7.5 0 8 7.5 0 10 7.5 0 -12 7.5 0 14 7.5 0 16 7.5 0 -18 7.5 0 20 7.5 0 0 10 0 -2 10 0 4 10 0 6 10 0 -8 10 0 10 10 0 12 10 0 -14 10 0 16 10 0 18 10 0 -20 10 0 0 12.5 0 2 12.5 0 -4 12.5 0 6 12.5 0 8 12.5 0 -10 12.5 0 12 12.5 0 14 12.5 0 -16 12.5 0 18 12.5 0 20 12.5 0 -0 15 0 2 15 0 4 15 0 -6 15 0 8 15 0 10 15 0 -12 15 0 14 15 0 16 15 0 -18 15 0 20 15 0 0 17.5 0 -2 17.5 0 4 17.5 0 6 17.5 0 -8 17.5 0 10 17.5 0 12 17.5 0 -14 17.5 0 16 17.5 0 18 17.5 0 -20 17.5 0 0 20 0 2 20 0 -4 20 0 6 20 0 8 20 0 -10 20 0 12 20 0 14 20 0 -16 20 0 18 20 0 20 20 0 -0 22.5 0 2 22.5 0 4 22.5 0 -6 22.5 0 8 22.5 0 10 22.5 0 -12 22.5 0 14 22.5 0 16 22.5 0 -18 22.5 0 20 22.5 0 0 25 0 -2 25 0 4 25 0 6 25 0 -8 25 0 10 25 0 12 25 0 -14 25 0 16 25 0 18 25 0 -20 25 0 0 27.5 0 2 27.5 0 -4 27.5 0 6 27.5 0 8 27.5 0 -10 27.5 0 12 27.5 0 14 27.5 0 -16 27.5 0 18 27.5 0 20 27.5 0 -0 30 0 2 30 0 4 30 0 -6 30 0 8 30 0 10 30 0 -12 30 0 14 30 0 16 30 0 -18 30 0 20 30 0 0 32.5 0 -2 32.5 0 4 32.5 0 6 32.5 0 -8 32.5 0 10 32.5 0 12 32.5 0 -14 32.5 0 16 32.5 0 18 32.5 0 -20 32.5 0 0 35 0 2 35 0 -4 35 0 6 35 0 8 35 0 -10 35 0 12 35 0 14 35 0 -16 35 0 18 35 0 20 35 0 -0 37.5 0 2 37.5 0 4 37.5 0 -6 37.5 0 8 37.5 0 10 37.5 0 -12 37.5 0 14 37.5 0 16 37.5 0 -18 37.5 0 20 37.5 0 0 40 0 -2 40 0 4 40 0 6 40 0 -8 40 0 10 40 0 12 40 0 -14 40 0 16 40 0 18 40 0 -20 40 0 0 42.5 0 2 42.5 0 -4 42.5 0 6 42.5 0 8 42.5 0 -10 42.5 0 12 42.5 0 14 42.5 0 -16 42.5 0 18 42.5 0 20 42.5 0 -0 45 0 2 45 0 4 45 0 -6 45 0 8 45 0 10 45 0 -12 45 0 14 45 0 16 45 0 -18 45 0 20 45 0 0 47.5 0 -2 47.5 0 4 47.5 0 6 47.5 0 -8 47.5 0 10 47.5 0 12 47.5 0 -14 47.5 0 16 47.5 0 18 47.5 0 -20 47.5 0 0 50 0 2 50 0 -4 50 0 6 50 0 8 50 0 -10 50 0 12 50 0 14 50 0 -16 50 0 18 50 0 20 50 0 -0 0 1.6666666667 2 0 1.6666666667 4 0 1.6666666667 -6 0 1.6666666667 8 0 1.6666666667 10 0 1.6666666667 -12 0 1.6666666667 14 0 1.6666666667 16 0 1.6666666667 -18 0 1.6666666667 20 0 1.6666666667 0 2.5 1.6666666667 -2 2.5 1.6666666667 4 2.5 1.6666666667 6 2.5 1.6666666667 -8 2.5 1.6666666667 10 2.5 1.6666666667 12 2.5 1.6666666667 -14 2.5 1.6666666667 16 2.5 1.6666666667 18 2.5 1.6666666667 -20 2.5 1.6666666667 0 5 1.6666666667 2 5 1.6666666667 -4 5 1.6666666667 6 5 1.6666666667 8 5 1.6666666667 -10 5 1.6666666667 12 5 1.6666666667 14 5 1.6666666667 -16 5 1.6666666667 18 5 1.6666666667 20 5 1.6666666667 -0 7.5 1.6666666667 2 7.5 1.6666666667 4 7.5 1.6666666667 -6 7.5 1.6666666667 8 7.5 1.6666666667 10 7.5 1.6666666667 -12 7.5 1.6666666667 14 7.5 1.6666666667 16 7.5 1.6666666667 -18 7.5 1.6666666667 20 7.5 1.6666666667 0 10 1.6666666667 -2 10 1.6666666667 4 10 1.6666666667 6 10 1.6666666667 -8 10 1.6666666667 10 10 1.6666666667 12 10 1.6666666667 -14 10 1.6666666667 16 10 1.6666666667 18 10 1.6666666667 -20 10 1.6666666667 0 12.5 1.6666666667 2 12.5 1.6666666667 -4 12.5 1.6666666667 6 12.5 1.6666666667 8 12.5 1.6666666667 -10 12.5 1.6666666667 12 12.5 1.6666666667 14 12.5 1.6666666667 -16 12.5 1.6666666667 18 12.5 1.6666666667 20 12.5 1.6666666667 -0 15 1.6666666667 2 15 1.6666666667 4 15 1.6666666667 -6 15 1.6666666667 8 15 1.6666666667 10 15 1.6666666667 -12 15 1.6666666667 14 15 1.6666666667 16 15 1.6666666667 -18 15 1.6666666667 20 15 1.6666666667 0 17.5 1.6666666667 -2 17.5 1.6666666667 4 17.5 1.6666666667 6 17.5 1.6666666667 -8 17.5 1.6666666667 10 17.5 1.6666666667 12 17.5 1.6666666667 -14 17.5 1.6666666667 16 17.5 1.6666666667 18 17.5 1.6666666667 -20 17.5 1.6666666667 0 20 1.6666666667 2 20 1.6666666667 -4 20 1.6666666667 6 20 1.6666666667 8 20 1.6666666667 -10 20 1.6666666667 12 20 1.6666666667 14 20 1.6666666667 -16 20 1.6666666667 18 20 1.6666666667 20 20 1.6666666667 -0 22.5 1.6666666667 2 22.5 1.6666666667 4 22.5 1.6666666667 -6 22.5 1.6666666667 8 22.5 1.6666666667 10 22.5 1.6666666667 -12 22.5 1.6666666667 14 22.5 1.6666666667 16 22.5 1.6666666667 -18 22.5 1.6666666667 20 22.5 1.6666666667 0 25 1.6666666667 -2 25 1.6666666667 4 25 1.6666666667 6 25 1.6666666667 -8 25 1.6666666667 10 25 1.6666666667 12 25 1.6666666667 -14 25 1.6666666667 16 25 1.6666666667 18 25 1.6666666667 -20 25 1.6666666667 0 27.5 1.6666666667 2 27.5 1.6666666667 -4 27.5 1.6666666667 6 27.5 1.6666666667 8 27.5 1.6666666667 -10 27.5 1.6666666667 12 27.5 1.6666666667 14 27.5 1.6666666667 -16 27.5 1.6666666667 18 27.5 1.6666666667 20 27.5 1.6666666667 -0 30 1.6666666667 2 30 1.6666666667 4 30 1.6666666667 -6 30 1.6666666667 8 30 1.6666666667 10 30 1.6666666667 -12 30 1.6666666667 14 30 1.6666666667 16 30 1.6666666667 -18 30 1.6666666667 20 30 1.6666666667 0 32.5 1.6666666667 -2 32.5 1.6666666667 4 32.5 1.6666666667 6 32.5 1.6666666667 -8 32.5 1.6666666667 10 32.5 1.6666666667 12 32.5 1.6666666667 -14 32.5 1.6666666667 16 32.5 1.6666666667 18 32.5 1.6666666667 -20 32.5 1.6666666667 0 35 1.6666666667 2 35 1.6666666667 -4 35 1.6666666667 6 35 1.6666666667 8 35 1.6666666667 -10 35 1.6666666667 12 35 1.6666666667 14 35 1.6666666667 -16 35 1.6666666667 18 35 1.6666666667 20 35 1.6666666667 -0 37.5 1.6666666667 2 37.5 1.6666666667 4 37.5 1.6666666667 -6 37.5 1.6666666667 8 37.5 1.6666666667 10 37.5 1.6666666667 -12 37.5 1.6666666667 14 37.5 1.6666666667 16 37.5 1.6666666667 -18 37.5 1.6666666667 20 37.5 1.6666666667 0 40 1.6666666667 -2 40 1.6666666667 4 40 1.6666666667 6 40 1.6666666667 -8 40 1.6666666667 10 40 1.6666666667 12 40 1.6666666667 -14 40 1.6666666667 16 40 1.6666666667 18 40 1.6666666667 -20 40 1.6666666667 0 42.5 1.6666666667 2 42.5 1.6666666667 -4 42.5 1.6666666667 6 42.5 1.6666666667 8 42.5 1.6666666667 -10 42.5 1.6666666667 12 42.5 1.6666666667 14 42.5 1.6666666667 -16 42.5 1.6666666667 18 42.5 1.6666666667 20 42.5 1.6666666667 -0 45 1.6666666667 2 45 1.6666666667 4 45 1.6666666667 -6 45 1.6666666667 8 45 1.6666666667 10 45 1.6666666667 -12 45 1.6666666667 14 45 1.6666666667 16 45 1.6666666667 -18 45 1.6666666667 20 45 1.6666666667 0 47.5 1.6666666667 -2 47.5 1.6666666667 4 47.5 1.6666666667 6 47.5 1.6666666667 -8 47.5 1.6666666667 10 47.5 1.6666666667 12 47.5 1.6666666667 -14 47.5 1.6666666667 16 47.5 1.6666666667 18 47.5 1.6666666667 -20 47.5 1.6666666667 0 50 1.6666666667 2 50 1.6666666667 -4 50 1.6666666667 6 50 1.6666666667 8 50 1.6666666667 -10 50 1.6666666667 12 50 1.6666666667 14 50 1.6666666667 -16 50 1.6666666667 18 50 1.6666666667 20 50 1.6666666667 -0 0 3.3333333333 2 0 3.3333333333 4 0 3.3333333333 -6 0 3.3333333333 8 0 3.3333333333 10 0 3.3333333333 -12 0 3.3333333333 14 0 3.3333333333 16 0 3.3333333333 -18 0 3.3333333333 20 0 3.3333333333 0 2.5 3.3333333333 -2 2.5 3.3333333333 4 2.5 3.3333333333 6 2.5 3.3333333333 -8 2.5 3.3333333333 10 2.5 3.3333333333 12 2.5 3.3333333333 -14 2.5 3.3333333333 16 2.5 3.3333333333 18 2.5 3.3333333333 -20 2.5 3.3333333333 0 5 3.3333333333 2 5 3.3333333333 -4 5 3.3333333333 6 5 3.3333333333 8 5 3.3333333333 -10 5 3.3333333333 12 5 3.3333333333 14 5 3.3333333333 -16 5 3.3333333333 18 5 3.3333333333 20 5 3.3333333333 -0 7.5 3.3333333333 2 7.5 3.3333333333 4 7.5 3.3333333333 -6 7.5 3.3333333333 8 7.5 3.3333333333 10 7.5 3.3333333333 -12 7.5 3.3333333333 14 7.5 3.3333333333 16 7.5 3.3333333333 -18 7.5 3.3333333333 20 7.5 3.3333333333 0 10 3.3333333333 -2 10 3.3333333333 4 10 3.3333333333 6 10 3.3333333333 -8 10 3.3333333333 10 10 3.3333333333 12 10 3.3333333333 -14 10 3.3333333333 16 10 3.3333333333 18 10 3.3333333333 -20 10 3.3333333333 0 12.5 3.3333333333 2 12.5 3.3333333333 -4 12.5 3.3333333333 6 12.5 3.3333333333 8 12.5 3.3333333333 -10 12.5 3.3333333333 12 12.5 3.3333333333 14 12.5 3.3333333333 -16 12.5 3.3333333333 18 12.5 3.3333333333 20 12.5 3.3333333333 -0 15 3.3333333333 2 15 3.3333333333 4 15 3.3333333333 -6 15 3.3333333333 8 15 3.3333333333 10 15 3.3333333333 -12 15 3.3333333333 14 15 3.3333333333 16 15 3.3333333333 -18 15 3.3333333333 20 15 3.3333333333 0 17.5 3.3333333333 -2 17.5 3.3333333333 4 17.5 3.3333333333 6 17.5 3.3333333333 -8 17.5 3.3333333333 10 17.5 3.3333333333 12 17.5 3.3333333333 -14 17.5 3.3333333333 16 17.5 3.3333333333 18 17.5 3.3333333333 -20 17.5 3.3333333333 0 20 3.3333333333 2 20 3.3333333333 -4 20 3.3333333333 6 20 3.3333333333 8 20 3.3333333333 -10 20 3.3333333333 12 20 3.3333333333 14 20 3.3333333333 -16 20 3.3333333333 18 20 3.3333333333 20 20 3.3333333333 -0 22.5 3.3333333333 2 22.5 3.3333333333 4 22.5 3.3333333333 -6 22.5 3.3333333333 8 22.5 3.3333333333 10 22.5 3.3333333333 -12 22.5 3.3333333333 14 22.5 3.3333333333 16 22.5 3.3333333333 -18 22.5 3.3333333333 20 22.5 3.3333333333 0 25 3.3333333333 -2 25 3.3333333333 4 25 3.3333333333 6 25 3.3333333333 -8 25 3.3333333333 10 25 3.3333333333 12 25 3.3333333333 -14 25 3.3333333333 16 25 3.3333333333 18 25 3.3333333333 -20 25 3.3333333333 0 27.5 3.3333333333 2 27.5 3.3333333333 -4 27.5 3.3333333333 6 27.5 3.3333333333 8 27.5 3.3333333333 -10 27.5 3.3333333333 12 27.5 3.3333333333 14 27.5 3.3333333333 -16 27.5 3.3333333333 18 27.5 3.3333333333 20 27.5 3.3333333333 -0 30 3.3333333333 2 30 3.3333333333 4 30 3.3333333333 -6 30 3.3333333333 8 30 3.3333333333 10 30 3.3333333333 -12 30 3.3333333333 14 30 3.3333333333 16 30 3.3333333333 -18 30 3.3333333333 20 30 3.3333333333 0 32.5 3.3333333333 -2 32.5 3.3333333333 4 32.5 3.3333333333 6 32.5 3.3333333333 -8 32.5 3.3333333333 10 32.5 3.3333333333 12 32.5 3.3333333333 -14 32.5 3.3333333333 16 32.5 3.3333333333 18 32.5 3.3333333333 -20 32.5 3.3333333333 0 35 3.3333333333 2 35 3.3333333333 -4 35 3.3333333333 6 35 3.3333333333 8 35 3.3333333333 -10 35 3.3333333333 12 35 3.3333333333 14 35 3.3333333333 -16 35 3.3333333333 18 35 3.3333333333 20 35 3.3333333333 -0 37.5 3.3333333333 2 37.5 3.3333333333 4 37.5 3.3333333333 -6 37.5 3.3333333333 8 37.5 3.3333333333 10 37.5 3.3333333333 -12 37.5 3.3333333333 14 37.5 3.3333333333 16 37.5 3.3333333333 -18 37.5 3.3333333333 20 37.5 3.3333333333 0 40 3.3333333333 -2 40 3.3333333333 4 40 3.3333333333 6 40 3.3333333333 -8 40 3.3333333333 10 40 3.3333333333 12 40 3.3333333333 -14 40 3.3333333333 16 40 3.3333333333 18 40 3.3333333333 -20 40 3.3333333333 0 42.5 3.3333333333 2 42.5 3.3333333333 -4 42.5 3.3333333333 6 42.5 3.3333333333 8 42.5 3.3333333333 -10 42.5 3.3333333333 12 42.5 3.3333333333 14 42.5 3.3333333333 -16 42.5 3.3333333333 18 42.5 3.3333333333 20 42.5 3.3333333333 -0 45 3.3333333333 2 45 3.3333333333 4 45 3.3333333333 -6 45 3.3333333333 8 45 3.3333333333 10 45 3.3333333333 -12 45 3.3333333333 14 45 3.3333333333 16 45 3.3333333333 -18 45 3.3333333333 20 45 3.3333333333 0 47.5 3.3333333333 -2 47.5 3.3333333333 4 47.5 3.3333333333 6 47.5 3.3333333333 -8 47.5 3.3333333333 10 47.5 3.3333333333 12 47.5 3.3333333333 -14 47.5 3.3333333333 16 47.5 3.3333333333 18 47.5 3.3333333333 -20 47.5 3.3333333333 0 50 3.3333333333 2 50 3.3333333333 -4 50 3.3333333333 6 50 3.3333333333 8 50 3.3333333333 -10 50 3.3333333333 12 50 3.3333333333 14 50 3.3333333333 -16 50 3.3333333333 18 50 3.3333333333 20 50 3.3333333333 -0 0 5 2 0 5 4 0 5 -6 0 5 8 0 5 10 0 5 -12 0 5 14 0 5 16 0 5 -18 0 5 20 0 5 0 2.5 5 -2 2.5 5 4 2.5 5 6 2.5 5 -8 2.5 5 10 2.5 5 12 2.5 5 -14 2.5 5 16 2.5 5 18 2.5 5 -20 2.5 5 0 5 5 2 5 5 -4 5 5 6 5 5 8 5 5 -10 5 5 12 5 5 14 5 5 -16 5 5 18 5 5 20 5 5 -0 7.5 5 2 7.5 5 4 7.5 5 -6 7.5 5 8 7.5 5 10 7.5 5 -12 7.5 5 14 7.5 5 16 7.5 5 -18 7.5 5 20 7.5 5 0 10 5 -2 10 5 4 10 5 6 10 5 -8 10 5 10 10 5 12 10 5 -14 10 5 16 10 5 18 10 5 -20 10 5 0 12.5 5 2 12.5 5 -4 12.5 5 6 12.5 5 8 12.5 5 -10 12.5 5 12 12.5 5 14 12.5 5 -16 12.5 5 18 12.5 5 20 12.5 5 -0 15 5 2 15 5 4 15 5 -6 15 5 8 15 5 10 15 5 -12 15 5 14 15 5 16 15 5 -18 15 5 20 15 5 0 17.5 5 -2 17.5 5 4 17.5 5 6 17.5 5 -8 17.5 5 10 17.5 5 12 17.5 5 -14 17.5 5 16 17.5 5 18 17.5 5 -20 17.5 5 0 20 5 2 20 5 -4 20 5 6 20 5 8 20 5 -10 20 5 12 20 5 14 20 5 -16 20 5 18 20 5 20 20 5 -0 22.5 5 2 22.5 5 4 22.5 5 -6 22.5 5 8 22.5 5 10 22.5 5 -12 22.5 5 14 22.5 5 16 22.5 5 -18 22.5 5 20 22.5 5 0 25 5 -2 25 5 4 25 5 6 25 5 -8 25 5 10 25 5 12 25 5 -14 25 5 16 25 5 18 25 5 -20 25 5 0 27.5 5 2 27.5 5 -4 27.5 5 6 27.5 5 8 27.5 5 -10 27.5 5 12 27.5 5 14 27.5 5 -16 27.5 5 18 27.5 5 20 27.5 5 -0 30 5 2 30 5 4 30 5 -6 30 5 8 30 5 10 30 5 -12 30 5 14 30 5 16 30 5 -18 30 5 20 30 5 0 32.5 5 -2 32.5 5 4 32.5 5 6 32.5 5 -8 32.5 5 10 32.5 5 12 32.5 5 -14 32.5 5 16 32.5 5 18 32.5 5 -20 32.5 5 0 35 5 2 35 5 -4 35 5 6 35 5 8 35 5 -10 35 5 12 35 5 14 35 5 -16 35 5 18 35 5 20 35 5 -0 37.5 5 2 37.5 5 4 37.5 5 -6 37.5 5 8 37.5 5 10 37.5 5 -12 37.5 5 14 37.5 5 16 37.5 5 -18 37.5 5 20 37.5 5 0 40 5 -2 40 5 4 40 5 6 40 5 -8 40 5 10 40 5 12 40 5 -14 40 5 16 40 5 18 40 5 -20 40 5 0 42.5 5 2 42.5 5 -4 42.5 5 6 42.5 5 8 42.5 5 -10 42.5 5 12 42.5 5 14 42.5 5 -16 42.5 5 18 42.5 5 20 42.5 5 -0 45 5 2 45 5 4 45 5 -6 45 5 8 45 5 10 45 5 -12 45 5 14 45 5 16 45 5 -18 45 5 20 45 5 0 47.5 5 -2 47.5 5 4 47.5 5 6 47.5 5 -8 47.5 5 10 47.5 5 12 47.5 5 -14 47.5 5 16 47.5 5 18 47.5 5 -20 47.5 5 0 50 5 2 50 5 -4 50 5 6 50 5 8 50 5 -10 50 5 12 50 5 14 50 5 -16 50 5 18 50 5 20 50 5 -0 0 6.6666666667 2 0 6.6666666667 4 0 6.6666666667 -6 0 6.6666666667 8 0 6.6666666667 10 0 6.6666666667 -12 0 6.6666666667 14 0 6.6666666667 16 0 6.6666666667 -18 0 6.6666666667 20 0 6.6666666667 0 2.5 6.6666666667 -2 2.5 6.6666666667 4 2.5 6.6666666667 6 2.5 6.6666666667 -8 2.5 6.6666666667 10 2.5 6.6666666667 12 2.5 6.6666666667 -14 2.5 6.6666666667 16 2.5 6.6666666667 18 2.5 6.6666666667 -20 2.5 6.6666666667 0 5 6.6666666667 2 5 6.6666666667 -4 5 6.6666666667 6 5 6.6666666667 8 5 6.6666666667 -10 5 6.6666666667 12 5 6.6666666667 14 5 6.6666666667 -16 5 6.6666666667 18 5 6.6666666667 20 5 6.6666666667 -0 7.5 6.6666666667 2 7.5 6.6666666667 4 7.5 6.6666666667 -6 7.5 6.6666666667 8 7.5 6.6666666667 10 7.5 6.6666666667 -12 7.5 6.6666666667 14 7.5 6.6666666667 16 7.5 6.6666666667 -18 7.5 6.6666666667 20 7.5 6.6666666667 0 10 6.6666666667 -2 10 6.6666666667 4 10 6.6666666667 6 10 6.6666666667 -8 10 6.6666666667 10 10 6.6666666667 12 10 6.6666666667 -14 10 6.6666666667 16 10 6.6666666667 18 10 6.6666666667 -20 10 6.6666666667 0 12.5 6.6666666667 2 12.5 6.6666666667 -4 12.5 6.6666666667 6 12.5 6.6666666667 8 12.5 6.6666666667 -10 12.5 6.6666666667 12 12.5 6.6666666667 14 12.5 6.6666666667 -16 12.5 6.6666666667 18 12.5 6.6666666667 20 12.5 6.6666666667 -0 15 6.6666666667 2 15 6.6666666667 4 15 6.6666666667 -6 15 6.6666666667 8 15 6.6666666667 10 15 6.6666666667 -12 15 6.6666666667 14 15 6.6666666667 16 15 6.6666666667 -18 15 6.6666666667 20 15 6.6666666667 0 17.5 6.6666666667 -2 17.5 6.6666666667 4 17.5 6.6666666667 6 17.5 6.6666666667 -8 17.5 6.6666666667 10 17.5 6.6666666667 12 17.5 6.6666666667 -14 17.5 6.6666666667 16 17.5 6.6666666667 18 17.5 6.6666666667 -20 17.5 6.6666666667 0 20 6.6666666667 2 20 6.6666666667 -4 20 6.6666666667 6 20 6.6666666667 8 20 6.6666666667 -10 20 6.6666666667 12 20 6.6666666667 14 20 6.6666666667 -16 20 6.6666666667 18 20 6.6666666667 20 20 6.6666666667 -0 22.5 6.6666666667 2 22.5 6.6666666667 4 22.5 6.6666666667 -6 22.5 6.6666666667 8 22.5 6.6666666667 10 22.5 6.6666666667 -12 22.5 6.6666666667 14 22.5 6.6666666667 16 22.5 6.6666666667 -18 22.5 6.6666666667 20 22.5 6.6666666667 0 25 6.6666666667 -2 25 6.6666666667 4 25 6.6666666667 6 25 6.6666666667 -8 25 6.6666666667 10 25 6.6666666667 12 25 6.6666666667 -14 25 6.6666666667 16 25 6.6666666667 18 25 6.6666666667 -20 25 6.6666666667 0 27.5 6.6666666667 2 27.5 6.6666666667 -4 27.5 6.6666666667 6 27.5 6.6666666667 8 27.5 6.6666666667 -10 27.5 6.6666666667 12 27.5 6.6666666667 14 27.5 6.6666666667 -16 27.5 6.6666666667 18 27.5 6.6666666667 20 27.5 6.6666666667 -0 30 6.6666666667 2 30 6.6666666667 4 30 6.6666666667 -6 30 6.6666666667 8 30 6.6666666667 10 30 6.6666666667 -12 30 6.6666666667 14 30 6.6666666667 16 30 6.6666666667 -18 30 6.6666666667 20 30 6.6666666667 0 32.5 6.6666666667 -2 32.5 6.6666666667 4 32.5 6.6666666667 6 32.5 6.6666666667 -8 32.5 6.6666666667 10 32.5 6.6666666667 12 32.5 6.6666666667 -14 32.5 6.6666666667 16 32.5 6.6666666667 18 32.5 6.6666666667 -20 32.5 6.6666666667 0 35 6.6666666667 2 35 6.6666666667 -4 35 6.6666666667 6 35 6.6666666667 8 35 6.6666666667 -10 35 6.6666666667 12 35 6.6666666667 14 35 6.6666666667 -16 35 6.6666666667 18 35 6.6666666667 20 35 6.6666666667 -0 37.5 6.6666666667 2 37.5 6.6666666667 4 37.5 6.6666666667 -6 37.5 6.6666666667 8 37.5 6.6666666667 10 37.5 6.6666666667 -12 37.5 6.6666666667 14 37.5 6.6666666667 16 37.5 6.6666666667 -18 37.5 6.6666666667 20 37.5 6.6666666667 0 40 6.6666666667 -2 40 6.6666666667 4 40 6.6666666667 6 40 6.6666666667 -8 40 6.6666666667 10 40 6.6666666667 12 40 6.6666666667 -14 40 6.6666666667 16 40 6.6666666667 18 40 6.6666666667 -20 40 6.6666666667 0 42.5 6.6666666667 2 42.5 6.6666666667 -4 42.5 6.6666666667 6 42.5 6.6666666667 8 42.5 6.6666666667 -10 42.5 6.6666666667 12 42.5 6.6666666667 14 42.5 6.6666666667 -16 42.5 6.6666666667 18 42.5 6.6666666667 20 42.5 6.6666666667 -0 45 6.6666666667 2 45 6.6666666667 4 45 6.6666666667 -6 45 6.6666666667 8 45 6.6666666667 10 45 6.6666666667 -12 45 6.6666666667 14 45 6.6666666667 16 45 6.6666666667 -18 45 6.6666666667 20 45 6.6666666667 0 47.5 6.6666666667 -2 47.5 6.6666666667 4 47.5 6.6666666667 6 47.5 6.6666666667 -8 47.5 6.6666666667 10 47.5 6.6666666667 12 47.5 6.6666666667 -14 47.5 6.6666666667 16 47.5 6.6666666667 18 47.5 6.6666666667 -20 47.5 6.6666666667 0 50 6.6666666667 2 50 6.6666666667 -4 50 6.6666666667 6 50 6.6666666667 8 50 6.6666666667 -10 50 6.6666666667 12 50 6.6666666667 14 50 6.6666666667 -16 50 6.6666666667 18 50 6.6666666667 20 50 6.6666666667 -0 0 8.3333333333 2 0 8.3333333333 4 0 8.3333333333 -6 0 8.3333333333 8 0 8.3333333333 10 0 8.3333333333 -12 0 8.3333333333 14 0 8.3333333333 16 0 8.3333333333 -18 0 8.3333333333 20 0 8.3333333333 0 2.5 8.3333333333 -2 2.5 8.3333333333 4 2.5 8.3333333333 6 2.5 8.3333333333 -8 2.5 8.3333333333 10 2.5 8.3333333333 12 2.5 8.3333333333 -14 2.5 8.3333333333 16 2.5 8.3333333333 18 2.5 8.3333333333 -20 2.5 8.3333333333 0 5 8.3333333333 2 5 8.3333333333 -4 5 8.3333333333 6 5 8.3333333333 8 5 8.3333333333 -10 5 8.3333333333 12 5 8.3333333333 14 5 8.3333333333 -16 5 8.3333333333 18 5 8.3333333333 20 5 8.3333333333 -0 7.5 8.3333333333 2 7.5 8.3333333333 4 7.5 8.3333333333 -6 7.5 8.3333333333 8 7.5 8.3333333333 10 7.5 8.3333333333 -12 7.5 8.3333333333 14 7.5 8.3333333333 16 7.5 8.3333333333 -18 7.5 8.3333333333 20 7.5 8.3333333333 0 10 8.3333333333 -2 10 8.3333333333 4 10 8.3333333333 6 10 8.3333333333 -8 10 8.3333333333 10 10 8.3333333333 12 10 8.3333333333 -14 10 8.3333333333 16 10 8.3333333333 18 10 8.3333333333 -20 10 8.3333333333 0 12.5 8.3333333333 2 12.5 8.3333333333 -4 12.5 8.3333333333 6 12.5 8.3333333333 8 12.5 8.3333333333 -10 12.5 8.3333333333 12 12.5 8.3333333333 14 12.5 8.3333333333 -16 12.5 8.3333333333 18 12.5 8.3333333333 20 12.5 8.3333333333 -0 15 8.3333333333 2 15 8.3333333333 4 15 8.3333333333 -6 15 8.3333333333 8 15 8.3333333333 10 15 8.3333333333 -12 15 8.3333333333 14 15 8.3333333333 16 15 8.3333333333 -18 15 8.3333333333 20 15 8.3333333333 0 17.5 8.3333333333 -2 17.5 8.3333333333 4 17.5 8.3333333333 6 17.5 8.3333333333 -8 17.5 8.3333333333 10 17.5 8.3333333333 12 17.5 8.3333333333 -14 17.5 8.3333333333 16 17.5 8.3333333333 18 17.5 8.3333333333 -20 17.5 8.3333333333 0 20 8.3333333333 2 20 8.3333333333 -4 20 8.3333333333 6 20 8.3333333333 8 20 8.3333333333 -10 20 8.3333333333 12 20 8.3333333333 14 20 8.3333333333 -16 20 8.3333333333 18 20 8.3333333333 20 20 8.3333333333 -0 22.5 8.3333333333 2 22.5 8.3333333333 4 22.5 8.3333333333 -6 22.5 8.3333333333 8 22.5 8.3333333333 10 22.5 8.3333333333 -12 22.5 8.3333333333 14 22.5 8.3333333333 16 22.5 8.3333333333 -18 22.5 8.3333333333 20 22.5 8.3333333333 0 25 8.3333333333 -2 25 8.3333333333 4 25 8.3333333333 6 25 8.3333333333 -8 25 8.3333333333 10 25 8.3333333333 12 25 8.3333333333 -14 25 8.3333333333 16 25 8.3333333333 18 25 8.3333333333 -20 25 8.3333333333 0 27.5 8.3333333333 2 27.5 8.3333333333 -4 27.5 8.3333333333 6 27.5 8.3333333333 8 27.5 8.3333333333 -10 27.5 8.3333333333 12 27.5 8.3333333333 14 27.5 8.3333333333 -16 27.5 8.3333333333 18 27.5 8.3333333333 20 27.5 8.3333333333 -0 30 8.3333333333 2 30 8.3333333333 4 30 8.3333333333 -6 30 8.3333333333 8 30 8.3333333333 10 30 8.3333333333 -12 30 8.3333333333 14 30 8.3333333333 16 30 8.3333333333 -18 30 8.3333333333 20 30 8.3333333333 0 32.5 8.3333333333 -2 32.5 8.3333333333 4 32.5 8.3333333333 6 32.5 8.3333333333 -8 32.5 8.3333333333 10 32.5 8.3333333333 12 32.5 8.3333333333 -14 32.5 8.3333333333 16 32.5 8.3333333333 18 32.5 8.3333333333 -20 32.5 8.3333333333 0 35 8.3333333333 2 35 8.3333333333 -4 35 8.3333333333 6 35 8.3333333333 8 35 8.3333333333 -10 35 8.3333333333 12 35 8.3333333333 14 35 8.3333333333 -16 35 8.3333333333 18 35 8.3333333333 20 35 8.3333333333 -0 37.5 8.3333333333 2 37.5 8.3333333333 4 37.5 8.3333333333 -6 37.5 8.3333333333 8 37.5 8.3333333333 10 37.5 8.3333333333 -12 37.5 8.3333333333 14 37.5 8.3333333333 16 37.5 8.3333333333 -18 37.5 8.3333333333 20 37.5 8.3333333333 0 40 8.3333333333 -2 40 8.3333333333 4 40 8.3333333333 6 40 8.3333333333 -8 40 8.3333333333 10 40 8.3333333333 12 40 8.3333333333 -14 40 8.3333333333 16 40 8.3333333333 18 40 8.3333333333 -20 40 8.3333333333 0 42.5 8.3333333333 2 42.5 8.3333333333 -4 42.5 8.3333333333 6 42.5 8.3333333333 8 42.5 8.3333333333 -10 42.5 8.3333333333 12 42.5 8.3333333333 14 42.5 8.3333333333 -16 42.5 8.3333333333 18 42.5 8.3333333333 20 42.5 8.3333333333 -0 45 8.3333333333 2 45 8.3333333333 4 45 8.3333333333 -6 45 8.3333333333 8 45 8.3333333333 10 45 8.3333333333 -12 45 8.3333333333 14 45 8.3333333333 16 45 8.3333333333 -18 45 8.3333333333 20 45 8.3333333333 0 47.5 8.3333333333 -2 47.5 8.3333333333 4 47.5 8.3333333333 6 47.5 8.3333333333 -8 47.5 8.3333333333 10 47.5 8.3333333333 12 47.5 8.3333333333 -14 47.5 8.3333333333 16 47.5 8.3333333333 18 47.5 8.3333333333 -20 47.5 8.3333333333 0 50 8.3333333333 2 50 8.3333333333 -4 50 8.3333333333 6 50 8.3333333333 8 50 8.3333333333 -10 50 8.3333333333 12 50 8.3333333333 14 50 8.3333333333 -16 50 8.3333333333 18 50 8.3333333333 20 50 8.3333333333 -0 0 10 2 0 10 4 0 10 -6 0 10 8 0 10 10 0 10 -12 0 10 14 0 10 16 0 10 -18 0 10 20 0 10 0 2.5 10 -2 2.5 10 4 2.5 10 6 2.5 10 -8 2.5 10 10 2.5 10 12 2.5 10 -14 2.5 10 16 2.5 10 18 2.5 10 -20 2.5 10 0 5 10 2 5 10 -4 5 10 6 5 10 8 5 10 -10 5 10 12 5 10 14 5 10 -16 5 10 18 5 10 20 5 10 -0 7.5 10 2 7.5 10 4 7.5 10 -6 7.5 10 8 7.5 10 10 7.5 10 -12 7.5 10 14 7.5 10 16 7.5 10 -18 7.5 10 20 7.5 10 0 10 10 -2 10 10 4 10 10 6 10 10 -8 10 10 10 10 10 12 10 10 -14 10 10 16 10 10 18 10 10 -20 10 10 0 12.5 10 2 12.5 10 -4 12.5 10 6 12.5 10 8 12.5 10 -10 12.5 10 12 12.5 10 14 12.5 10 -16 12.5 10 18 12.5 10 20 12.5 10 -0 15 10 2 15 10 4 15 10 -6 15 10 8 15 10 10 15 10 -12 15 10 14 15 10 16 15 10 -18 15 10 20 15 10 0 17.5 10 -2 17.5 10 4 17.5 10 6 17.5 10 -8 17.5 10 10 17.5 10 12 17.5 10 -14 17.5 10 16 17.5 10 18 17.5 10 -20 17.5 10 0 20 10 2 20 10 -4 20 10 6 20 10 8 20 10 -10 20 10 12 20 10 14 20 10 -16 20 10 18 20 10 20 20 10 -0 22.5 10 2 22.5 10 4 22.5 10 -6 22.5 10 8 22.5 10 10 22.5 10 -12 22.5 10 14 22.5 10 16 22.5 10 -18 22.5 10 20 22.5 10 0 25 10 -2 25 10 4 25 10 6 25 10 -8 25 10 10 25 10 12 25 10 -14 25 10 16 25 10 18 25 10 -20 25 10 0 27.5 10 2 27.5 10 -4 27.5 10 6 27.5 10 8 27.5 10 -10 27.5 10 12 27.5 10 14 27.5 10 -16 27.5 10 18 27.5 10 20 27.5 10 -0 30 10 2 30 10 4 30 10 -6 30 10 8 30 10 10 30 10 -12 30 10 14 30 10 16 30 10 -18 30 10 20 30 10 0 32.5 10 -2 32.5 10 4 32.5 10 6 32.5 10 -8 32.5 10 10 32.5 10 12 32.5 10 -14 32.5 10 16 32.5 10 18 32.5 10 -20 32.5 10 0 35 10 2 35 10 -4 35 10 6 35 10 8 35 10 -10 35 10 12 35 10 14 35 10 -16 35 10 18 35 10 20 35 10 -0 37.5 10 2 37.5 10 4 37.5 10 -6 37.5 10 8 37.5 10 10 37.5 10 -12 37.5 10 14 37.5 10 16 37.5 10 -18 37.5 10 20 37.5 10 0 40 10 -2 40 10 4 40 10 6 40 10 -8 40 10 10 40 10 12 40 10 -14 40 10 16 40 10 18 40 10 -20 40 10 0 42.5 10 2 42.5 10 -4 42.5 10 6 42.5 10 8 42.5 10 -10 42.5 10 12 42.5 10 14 42.5 10 -16 42.5 10 18 42.5 10 20 42.5 10 -0 45 10 2 45 10 4 45 10 -6 45 10 8 45 10 10 45 10 -12 45 10 14 45 10 16 45 10 -18 45 10 20 45 10 0 47.5 10 -2 47.5 10 4 47.5 10 6 47.5 10 -8 47.5 10 10 47.5 10 12 47.5 10 -14 47.5 10 16 47.5 10 18 47.5 10 -20 47.5 10 0 50 10 2 50 10 -4 50 10 6 50 10 8 50 10 -10 50 10 12 50 10 14 50 10 -16 50 10 18 50 10 20 50 10 -0 0 11.666666667 2 0 11.666666667 4 0 11.666666667 -6 0 11.666666667 8 0 11.666666667 10 0 11.666666667 -12 0 11.666666667 14 0 11.666666667 16 0 11.666666667 -18 0 11.666666667 20 0 11.666666667 0 2.5 11.666666667 -2 2.5 11.666666667 4 2.5 11.666666667 6 2.5 11.666666667 -8 2.5 11.666666667 10 2.5 11.666666667 12 2.5 11.666666667 -14 2.5 11.666666667 16 2.5 11.666666667 18 2.5 11.666666667 -20 2.5 11.666666667 0 5 11.666666667 2 5 11.666666667 -4 5 11.666666667 6 5 11.666666667 8 5 11.666666667 -10 5 11.666666667 12 5 11.666666667 14 5 11.666666667 -16 5 11.666666667 18 5 11.666666667 20 5 11.666666667 -0 7.5 11.666666667 2 7.5 11.666666667 4 7.5 11.666666667 -6 7.5 11.666666667 8 7.5 11.666666667 10 7.5 11.666666667 -12 7.5 11.666666667 14 7.5 11.666666667 16 7.5 11.666666667 -18 7.5 11.666666667 20 7.5 11.666666667 0 10 11.666666667 -2 10 11.666666667 4 10 11.666666667 6 10 11.666666667 -8 10 11.666666667 10 10 11.666666667 12 10 11.666666667 -14 10 11.666666667 16 10 11.666666667 18 10 11.666666667 -20 10 11.666666667 0 12.5 11.666666667 2 12.5 11.666666667 -4 12.5 11.666666667 6 12.5 11.666666667 8 12.5 11.666666667 -10 12.5 11.666666667 12 12.5 11.666666667 14 12.5 11.666666667 -16 12.5 11.666666667 18 12.5 11.666666667 20 12.5 11.666666667 -0 15 11.666666667 2 15 11.666666667 4 15 11.666666667 -6 15 11.666666667 8 15 11.666666667 10 15 11.666666667 -12 15 11.666666667 14 15 11.666666667 16 15 11.666666667 -18 15 11.666666667 20 15 11.666666667 0 17.5 11.666666667 -2 17.5 11.666666667 4 17.5 11.666666667 6 17.5 11.666666667 -8 17.5 11.666666667 10 17.5 11.666666667 12 17.5 11.666666667 -14 17.5 11.666666667 16 17.5 11.666666667 18 17.5 11.666666667 -20 17.5 11.666666667 0 20 11.666666667 2 20 11.666666667 -4 20 11.666666667 6 20 11.666666667 8 20 11.666666667 -10 20 11.666666667 12 20 11.666666667 14 20 11.666666667 -16 20 11.666666667 18 20 11.666666667 20 20 11.666666667 -0 22.5 11.666666667 2 22.5 11.666666667 4 22.5 11.666666667 -6 22.5 11.666666667 8 22.5 11.666666667 10 22.5 11.666666667 -12 22.5 11.666666667 14 22.5 11.666666667 16 22.5 11.666666667 -18 22.5 11.666666667 20 22.5 11.666666667 0 25 11.666666667 -2 25 11.666666667 4 25 11.666666667 6 25 11.666666667 -8 25 11.666666667 10 25 11.666666667 12 25 11.666666667 -14 25 11.666666667 16 25 11.666666667 18 25 11.666666667 -20 25 11.666666667 0 27.5 11.666666667 2 27.5 11.666666667 -4 27.5 11.666666667 6 27.5 11.666666667 8 27.5 11.666666667 -10 27.5 11.666666667 12 27.5 11.666666667 14 27.5 11.666666667 -16 27.5 11.666666667 18 27.5 11.666666667 20 27.5 11.666666667 -0 30 11.666666667 2 30 11.666666667 4 30 11.666666667 -6 30 11.666666667 8 30 11.666666667 10 30 11.666666667 -12 30 11.666666667 14 30 11.666666667 16 30 11.666666667 -18 30 11.666666667 20 30 11.666666667 0 32.5 11.666666667 -2 32.5 11.666666667 4 32.5 11.666666667 6 32.5 11.666666667 -8 32.5 11.666666667 10 32.5 11.666666667 12 32.5 11.666666667 -14 32.5 11.666666667 16 32.5 11.666666667 18 32.5 11.666666667 -20 32.5 11.666666667 0 35 11.666666667 2 35 11.666666667 -4 35 11.666666667 6 35 11.666666667 8 35 11.666666667 -10 35 11.666666667 12 35 11.666666667 14 35 11.666666667 -16 35 11.666666667 18 35 11.666666667 20 35 11.666666667 -0 37.5 11.666666667 2 37.5 11.666666667 4 37.5 11.666666667 -6 37.5 11.666666667 8 37.5 11.666666667 10 37.5 11.666666667 -12 37.5 11.666666667 14 37.5 11.666666667 16 37.5 11.666666667 -18 37.5 11.666666667 20 37.5 11.666666667 0 40 11.666666667 -2 40 11.666666667 4 40 11.666666667 6 40 11.666666667 -8 40 11.666666667 10 40 11.666666667 12 40 11.666666667 -14 40 11.666666667 16 40 11.666666667 18 40 11.666666667 -20 40 11.666666667 0 42.5 11.666666667 2 42.5 11.666666667 -4 42.5 11.666666667 6 42.5 11.666666667 8 42.5 11.666666667 -10 42.5 11.666666667 12 42.5 11.666666667 14 42.5 11.666666667 -16 42.5 11.666666667 18 42.5 11.666666667 20 42.5 11.666666667 -0 45 11.666666667 2 45 11.666666667 4 45 11.666666667 -6 45 11.666666667 8 45 11.666666667 10 45 11.666666667 -12 45 11.666666667 14 45 11.666666667 16 45 11.666666667 -18 45 11.666666667 20 45 11.666666667 0 47.5 11.666666667 -2 47.5 11.666666667 4 47.5 11.666666667 6 47.5 11.666666667 -8 47.5 11.666666667 10 47.5 11.666666667 12 47.5 11.666666667 -14 47.5 11.666666667 16 47.5 11.666666667 18 47.5 11.666666667 -20 47.5 11.666666667 0 50 11.666666667 2 50 11.666666667 -4 50 11.666666667 6 50 11.666666667 8 50 11.666666667 -10 50 11.666666667 12 50 11.666666667 14 50 11.666666667 -16 50 11.666666667 18 50 11.666666667 20 50 11.666666667 -0 0 13.333333333 2 0 13.333333333 4 0 13.333333333 -6 0 13.333333333 8 0 13.333333333 10 0 13.333333333 -12 0 13.333333333 14 0 13.333333333 16 0 13.333333333 -18 0 13.333333333 20 0 13.333333333 0 2.5 13.333333333 -2 2.5 13.333333333 4 2.5 13.333333333 6 2.5 13.333333333 -8 2.5 13.333333333 10 2.5 13.333333333 12 2.5 13.333333333 -14 2.5 13.333333333 16 2.5 13.333333333 18 2.5 13.333333333 -20 2.5 13.333333333 0 5 13.333333333 2 5 13.333333333 -4 5 13.333333333 6 5 13.333333333 8 5 13.333333333 -10 5 13.333333333 12 5 13.333333333 14 5 13.333333333 -16 5 13.333333333 18 5 13.333333333 20 5 13.333333333 -0 7.5 13.333333333 2 7.5 13.333333333 4 7.5 13.333333333 -6 7.5 13.333333333 8 7.5 13.333333333 10 7.5 13.333333333 -12 7.5 13.333333333 14 7.5 13.333333333 16 7.5 13.333333333 -18 7.5 13.333333333 20 7.5 13.333333333 0 10 13.333333333 -2 10 13.333333333 4 10 13.333333333 6 10 13.333333333 -8 10 13.333333333 10 10 13.333333333 12 10 13.333333333 -14 10 13.333333333 16 10 13.333333333 18 10 13.333333333 -20 10 13.333333333 0 12.5 13.333333333 2 12.5 13.333333333 -4 12.5 13.333333333 6 12.5 13.333333333 8 12.5 13.333333333 -10 12.5 13.333333333 12 12.5 13.333333333 14 12.5 13.333333333 -16 12.5 13.333333333 18 12.5 13.333333333 20 12.5 13.333333333 -0 15 13.333333333 2 15 13.333333333 4 15 13.333333333 -6 15 13.333333333 8 15 13.333333333 10 15 13.333333333 -12 15 13.333333333 14 15 13.333333333 16 15 13.333333333 -18 15 13.333333333 20 15 13.333333333 0 17.5 13.333333333 -2 17.5 13.333333333 4 17.5 13.333333333 6 17.5 13.333333333 -8 17.5 13.333333333 10 17.5 13.333333333 12 17.5 13.333333333 -14 17.5 13.333333333 16 17.5 13.333333333 18 17.5 13.333333333 -20 17.5 13.333333333 0 20 13.333333333 2 20 13.333333333 -4 20 13.333333333 6 20 13.333333333 8 20 13.333333333 -10 20 13.333333333 12 20 13.333333333 14 20 13.333333333 -16 20 13.333333333 18 20 13.333333333 20 20 13.333333333 -0 22.5 13.333333333 2 22.5 13.333333333 4 22.5 13.333333333 -6 22.5 13.333333333 8 22.5 13.333333333 10 22.5 13.333333333 -12 22.5 13.333333333 14 22.5 13.333333333 16 22.5 13.333333333 -18 22.5 13.333333333 20 22.5 13.333333333 0 25 13.333333333 -2 25 13.333333333 4 25 13.333333333 6 25 13.333333333 -8 25 13.333333333 10 25 13.333333333 12 25 13.333333333 -14 25 13.333333333 16 25 13.333333333 18 25 13.333333333 -20 25 13.333333333 0 27.5 13.333333333 2 27.5 13.333333333 -4 27.5 13.333333333 6 27.5 13.333333333 8 27.5 13.333333333 -10 27.5 13.333333333 12 27.5 13.333333333 14 27.5 13.333333333 -16 27.5 13.333333333 18 27.5 13.333333333 20 27.5 13.333333333 -0 30 13.333333333 2 30 13.333333333 4 30 13.333333333 -6 30 13.333333333 8 30 13.333333333 10 30 13.333333333 -12 30 13.333333333 14 30 13.333333333 16 30 13.333333333 -18 30 13.333333333 20 30 13.333333333 0 32.5 13.333333333 -2 32.5 13.333333333 4 32.5 13.333333333 6 32.5 13.333333333 -8 32.5 13.333333333 10 32.5 13.333333333 12 32.5 13.333333333 -14 32.5 13.333333333 16 32.5 13.333333333 18 32.5 13.333333333 -20 32.5 13.333333333 0 35 13.333333333 2 35 13.333333333 -4 35 13.333333333 6 35 13.333333333 8 35 13.333333333 -10 35 13.333333333 12 35 13.333333333 14 35 13.333333333 -16 35 13.333333333 18 35 13.333333333 20 35 13.333333333 -0 37.5 13.333333333 2 37.5 13.333333333 4 37.5 13.333333333 -6 37.5 13.333333333 8 37.5 13.333333333 10 37.5 13.333333333 -12 37.5 13.333333333 14 37.5 13.333333333 16 37.5 13.333333333 -18 37.5 13.333333333 20 37.5 13.333333333 0 40 13.333333333 -2 40 13.333333333 4 40 13.333333333 6 40 13.333333333 -8 40 13.333333333 10 40 13.333333333 12 40 13.333333333 -14 40 13.333333333 16 40 13.333333333 18 40 13.333333333 -20 40 13.333333333 0 42.5 13.333333333 2 42.5 13.333333333 -4 42.5 13.333333333 6 42.5 13.333333333 8 42.5 13.333333333 -10 42.5 13.333333333 12 42.5 13.333333333 14 42.5 13.333333333 -16 42.5 13.333333333 18 42.5 13.333333333 20 42.5 13.333333333 -0 45 13.333333333 2 45 13.333333333 4 45 13.333333333 -6 45 13.333333333 8 45 13.333333333 10 45 13.333333333 -12 45 13.333333333 14 45 13.333333333 16 45 13.333333333 -18 45 13.333333333 20 45 13.333333333 0 47.5 13.333333333 -2 47.5 13.333333333 4 47.5 13.333333333 6 47.5 13.333333333 -8 47.5 13.333333333 10 47.5 13.333333333 12 47.5 13.333333333 -14 47.5 13.333333333 16 47.5 13.333333333 18 47.5 13.333333333 -20 47.5 13.333333333 0 50 13.333333333 2 50 13.333333333 -4 50 13.333333333 6 50 13.333333333 8 50 13.333333333 -10 50 13.333333333 12 50 13.333333333 14 50 13.333333333 -16 50 13.333333333 18 50 13.333333333 20 50 13.333333333 -0 0 15 2 0 15 4 0 15 -6 0 15 8 0 15 10 0 15 -12 0 15 14 0 15 16 0 15 -18 0 15 20 0 15 0 2.5 15 -2 2.5 15 4 2.5 15 6 2.5 15 -8 2.5 15 10 2.5 15 12 2.5 15 -14 2.5 15 16 2.5 15 18 2.5 15 -20 2.5 15 0 5 15 2 5 15 -4 5 15 6 5 15 8 5 15 -10 5 15 12 5 15 14 5 15 -16 5 15 18 5 15 20 5 15 -0 7.5 15 2 7.5 15 4 7.5 15 -6 7.5 15 8 7.5 15 10 7.5 15 -12 7.5 15 14 7.5 15 16 7.5 15 -18 7.5 15 20 7.5 15 0 10 15 -2 10 15 4 10 15 6 10 15 -8 10 15 10 10 15 12 10 15 -14 10 15 16 10 15 18 10 15 -20 10 15 0 12.5 15 2 12.5 15 -4 12.5 15 6 12.5 15 8 12.5 15 -10 12.5 15 12 12.5 15 14 12.5 15 -16 12.5 15 18 12.5 15 20 12.5 15 -0 15 15 2 15 15 4 15 15 -6 15 15 8 15 15 10 15 15 -12 15 15 14 15 15 16 15 15 -18 15 15 20 15 15 0 17.5 15 -2 17.5 15 4 17.5 15 6 17.5 15 -8 17.5 15 10 17.5 15 12 17.5 15 -14 17.5 15 16 17.5 15 18 17.5 15 -20 17.5 15 0 20 15 2 20 15 -4 20 15 6 20 15 8 20 15 -10 20 15 12 20 15 14 20 15 -16 20 15 18 20 15 20 20 15 -0 22.5 15 2 22.5 15 4 22.5 15 -6 22.5 15 8 22.5 15 10 22.5 15 -12 22.5 15 14 22.5 15 16 22.5 15 -18 22.5 15 20 22.5 15 0 25 15 -2 25 15 4 25 15 6 25 15 -8 25 15 10 25 15 12 25 15 -14 25 15 16 25 15 18 25 15 -20 25 15 0 27.5 15 2 27.5 15 -4 27.5 15 6 27.5 15 8 27.5 15 -10 27.5 15 12 27.5 15 14 27.5 15 -16 27.5 15 18 27.5 15 20 27.5 15 -0 30 15 2 30 15 4 30 15 -6 30 15 8 30 15 10 30 15 -12 30 15 14 30 15 16 30 15 -18 30 15 20 30 15 0 32.5 15 -2 32.5 15 4 32.5 15 6 32.5 15 -8 32.5 15 10 32.5 15 12 32.5 15 -14 32.5 15 16 32.5 15 18 32.5 15 -20 32.5 15 0 35 15 2 35 15 -4 35 15 6 35 15 8 35 15 -10 35 15 12 35 15 14 35 15 -16 35 15 18 35 15 20 35 15 -0 37.5 15 2 37.5 15 4 37.5 15 -6 37.5 15 8 37.5 15 10 37.5 15 -12 37.5 15 14 37.5 15 16 37.5 15 -18 37.5 15 20 37.5 15 0 40 15 -2 40 15 4 40 15 6 40 15 -8 40 15 10 40 15 12 40 15 -14 40 15 16 40 15 18 40 15 -20 40 15 0 42.5 15 2 42.5 15 -4 42.5 15 6 42.5 15 8 42.5 15 -10 42.5 15 12 42.5 15 14 42.5 15 -16 42.5 15 18 42.5 15 20 42.5 15 -0 45 15 2 45 15 4 45 15 -6 45 15 8 45 15 10 45 15 -12 45 15 14 45 15 16 45 15 -18 45 15 20 45 15 0 47.5 15 -2 47.5 15 4 47.5 15 6 47.5 15 -8 47.5 15 10 47.5 15 12 47.5 15 -14 47.5 15 16 47.5 15 18 47.5 15 -20 47.5 15 0 50 15 2 50 15 -4 50 15 6 50 15 8 50 15 -10 50 15 12 50 15 14 50 15 -16 50 15 18 50 15 20 50 15 -0 0 16.666666667 2 0 16.666666667 4 0 16.666666667 -6 0 16.666666667 8 0 16.666666667 10 0 16.666666667 -12 0 16.666666667 14 0 16.666666667 16 0 16.666666667 -18 0 16.666666667 20 0 16.666666667 0 2.5 16.666666667 -2 2.5 16.666666667 4 2.5 16.666666667 6 2.5 16.666666667 -8 2.5 16.666666667 10 2.5 16.666666667 12 2.5 16.666666667 -14 2.5 16.666666667 16 2.5 16.666666667 18 2.5 16.666666667 -20 2.5 16.666666667 0 5 16.666666667 2 5 16.666666667 -4 5 16.666666667 6 5 16.666666667 8 5 16.666666667 -10 5 16.666666667 12 5 16.666666667 14 5 16.666666667 -16 5 16.666666667 18 5 16.666666667 20 5 16.666666667 -0 7.5 16.666666667 2 7.5 16.666666667 4 7.5 16.666666667 -6 7.5 16.666666667 8 7.5 16.666666667 10 7.5 16.666666667 -12 7.5 16.666666667 14 7.5 16.666666667 16 7.5 16.666666667 -18 7.5 16.666666667 20 7.5 16.666666667 0 10 16.666666667 -2 10 16.666666667 4 10 16.666666667 6 10 16.666666667 -8 10 16.666666667 10 10 16.666666667 12 10 16.666666667 -14 10 16.666666667 16 10 16.666666667 18 10 16.666666667 -20 10 16.666666667 0 12.5 16.666666667 2 12.5 16.666666667 -4 12.5 16.666666667 6 12.5 16.666666667 8 12.5 16.666666667 -10 12.5 16.666666667 12 12.5 16.666666667 14 12.5 16.666666667 -16 12.5 16.666666667 18 12.5 16.666666667 20 12.5 16.666666667 -0 15 16.666666667 2 15 16.666666667 4 15 16.666666667 -6 15 16.666666667 8 15 16.666666667 10 15 16.666666667 -12 15 16.666666667 14 15 16.666666667 16 15 16.666666667 -18 15 16.666666667 20 15 16.666666667 0 17.5 16.666666667 -2 17.5 16.666666667 4 17.5 16.666666667 6 17.5 16.666666667 -8 17.5 16.666666667 10 17.5 16.666666667 12 17.5 16.666666667 -14 17.5 16.666666667 16 17.5 16.666666667 18 17.5 16.666666667 -20 17.5 16.666666667 0 20 16.666666667 2 20 16.666666667 -4 20 16.666666667 6 20 16.666666667 8 20 16.666666667 -10 20 16.666666667 12 20 16.666666667 14 20 16.666666667 -16 20 16.666666667 18 20 16.666666667 20 20 16.666666667 -0 22.5 16.666666667 2 22.5 16.666666667 4 22.5 16.666666667 -6 22.5 16.666666667 8 22.5 16.666666667 10 22.5 16.666666667 -12 22.5 16.666666667 14 22.5 16.666666667 16 22.5 16.666666667 -18 22.5 16.666666667 20 22.5 16.666666667 0 25 16.666666667 -2 25 16.666666667 4 25 16.666666667 6 25 16.666666667 -8 25 16.666666667 10 25 16.666666667 12 25 16.666666667 -14 25 16.666666667 16 25 16.666666667 18 25 16.666666667 -20 25 16.666666667 0 27.5 16.666666667 2 27.5 16.666666667 -4 27.5 16.666666667 6 27.5 16.666666667 8 27.5 16.666666667 -10 27.5 16.666666667 12 27.5 16.666666667 14 27.5 16.666666667 -16 27.5 16.666666667 18 27.5 16.666666667 20 27.5 16.666666667 -0 30 16.666666667 2 30 16.666666667 4 30 16.666666667 -6 30 16.666666667 8 30 16.666666667 10 30 16.666666667 -12 30 16.666666667 14 30 16.666666667 16 30 16.666666667 -18 30 16.666666667 20 30 16.666666667 0 32.5 16.666666667 -2 32.5 16.666666667 4 32.5 16.666666667 6 32.5 16.666666667 -8 32.5 16.666666667 10 32.5 16.666666667 12 32.5 16.666666667 -14 32.5 16.666666667 16 32.5 16.666666667 18 32.5 16.666666667 -20 32.5 16.666666667 0 35 16.666666667 2 35 16.666666667 -4 35 16.666666667 6 35 16.666666667 8 35 16.666666667 -10 35 16.666666667 12 35 16.666666667 14 35 16.666666667 -16 35 16.666666667 18 35 16.666666667 20 35 16.666666667 -0 37.5 16.666666667 2 37.5 16.666666667 4 37.5 16.666666667 -6 37.5 16.666666667 8 37.5 16.666666667 10 37.5 16.666666667 -12 37.5 16.666666667 14 37.5 16.666666667 16 37.5 16.666666667 -18 37.5 16.666666667 20 37.5 16.666666667 0 40 16.666666667 -2 40 16.666666667 4 40 16.666666667 6 40 16.666666667 -8 40 16.666666667 10 40 16.666666667 12 40 16.666666667 -14 40 16.666666667 16 40 16.666666667 18 40 16.666666667 -20 40 16.666666667 0 42.5 16.666666667 2 42.5 16.666666667 -4 42.5 16.666666667 6 42.5 16.666666667 8 42.5 16.666666667 -10 42.5 16.666666667 12 42.5 16.666666667 14 42.5 16.666666667 -16 42.5 16.666666667 18 42.5 16.666666667 20 42.5 16.666666667 -0 45 16.666666667 2 45 16.666666667 4 45 16.666666667 -6 45 16.666666667 8 45 16.666666667 10 45 16.666666667 -12 45 16.666666667 14 45 16.666666667 16 45 16.666666667 -18 45 16.666666667 20 45 16.666666667 0 47.5 16.666666667 -2 47.5 16.666666667 4 47.5 16.666666667 6 47.5 16.666666667 -8 47.5 16.666666667 10 47.5 16.666666667 12 47.5 16.666666667 -14 47.5 16.666666667 16 47.5 16.666666667 18 47.5 16.666666667 -20 47.5 16.666666667 0 50 16.666666667 2 50 16.666666667 -4 50 16.666666667 6 50 16.666666667 8 50 16.666666667 -10 50 16.666666667 12 50 16.666666667 14 50 16.666666667 -16 50 16.666666667 18 50 16.666666667 20 50 16.666666667 -0 0 18.333333333 2 0 18.333333333 4 0 18.333333333 -6 0 18.333333333 8 0 18.333333333 10 0 18.333333333 -12 0 18.333333333 14 0 18.333333333 16 0 18.333333333 -18 0 18.333333333 20 0 18.333333333 0 2.5 18.333333333 -2 2.5 18.333333333 4 2.5 18.333333333 6 2.5 18.333333333 -8 2.5 18.333333333 10 2.5 18.333333333 12 2.5 18.333333333 -14 2.5 18.333333333 16 2.5 18.333333333 18 2.5 18.333333333 -20 2.5 18.333333333 0 5 18.333333333 2 5 18.333333333 -4 5 18.333333333 6 5 18.333333333 8 5 18.333333333 -10 5 18.333333333 12 5 18.333333333 14 5 18.333333333 -16 5 18.333333333 18 5 18.333333333 20 5 18.333333333 -0 7.5 18.333333333 2 7.5 18.333333333 4 7.5 18.333333333 -6 7.5 18.333333333 8 7.5 18.333333333 10 7.5 18.333333333 -12 7.5 18.333333333 14 7.5 18.333333333 16 7.5 18.333333333 -18 7.5 18.333333333 20 7.5 18.333333333 0 10 18.333333333 -2 10 18.333333333 4 10 18.333333333 6 10 18.333333333 -8 10 18.333333333 10 10 18.333333333 12 10 18.333333333 -14 10 18.333333333 16 10 18.333333333 18 10 18.333333333 -20 10 18.333333333 0 12.5 18.333333333 2 12.5 18.333333333 -4 12.5 18.333333333 6 12.5 18.333333333 8 12.5 18.333333333 -10 12.5 18.333333333 12 12.5 18.333333333 14 12.5 18.333333333 -16 12.5 18.333333333 18 12.5 18.333333333 20 12.5 18.333333333 -0 15 18.333333333 2 15 18.333333333 4 15 18.333333333 -6 15 18.333333333 8 15 18.333333333 10 15 18.333333333 -12 15 18.333333333 14 15 18.333333333 16 15 18.333333333 -18 15 18.333333333 20 15 18.333333333 0 17.5 18.333333333 -2 17.5 18.333333333 4 17.5 18.333333333 6 17.5 18.333333333 -8 17.5 18.333333333 10 17.5 18.333333333 12 17.5 18.333333333 -14 17.5 18.333333333 16 17.5 18.333333333 18 17.5 18.333333333 -20 17.5 18.333333333 0 20 18.333333333 2 20 18.333333333 -4 20 18.333333333 6 20 18.333333333 8 20 18.333333333 -10 20 18.333333333 12 20 18.333333333 14 20 18.333333333 -16 20 18.333333333 18 20 18.333333333 20 20 18.333333333 -0 22.5 18.333333333 2 22.5 18.333333333 4 22.5 18.333333333 -6 22.5 18.333333333 8 22.5 18.333333333 10 22.5 18.333333333 -12 22.5 18.333333333 14 22.5 18.333333333 16 22.5 18.333333333 -18 22.5 18.333333333 20 22.5 18.333333333 0 25 18.333333333 -2 25 18.333333333 4 25 18.333333333 6 25 18.333333333 -8 25 18.333333333 10 25 18.333333333 12 25 18.333333333 -14 25 18.333333333 16 25 18.333333333 18 25 18.333333333 -20 25 18.333333333 0 27.5 18.333333333 2 27.5 18.333333333 -4 27.5 18.333333333 6 27.5 18.333333333 8 27.5 18.333333333 -10 27.5 18.333333333 12 27.5 18.333333333 14 27.5 18.333333333 -16 27.5 18.333333333 18 27.5 18.333333333 20 27.5 18.333333333 -0 30 18.333333333 2 30 18.333333333 4 30 18.333333333 -6 30 18.333333333 8 30 18.333333333 10 30 18.333333333 -12 30 18.333333333 14 30 18.333333333 16 30 18.333333333 -18 30 18.333333333 20 30 18.333333333 0 32.5 18.333333333 -2 32.5 18.333333333 4 32.5 18.333333333 6 32.5 18.333333333 -8 32.5 18.333333333 10 32.5 18.333333333 12 32.5 18.333333333 -14 32.5 18.333333333 16 32.5 18.333333333 18 32.5 18.333333333 -20 32.5 18.333333333 0 35 18.333333333 2 35 18.333333333 -4 35 18.333333333 6 35 18.333333333 8 35 18.333333333 -10 35 18.333333333 12 35 18.333333333 14 35 18.333333333 -16 35 18.333333333 18 35 18.333333333 20 35 18.333333333 -0 37.5 18.333333333 2 37.5 18.333333333 4 37.5 18.333333333 -6 37.5 18.333333333 8 37.5 18.333333333 10 37.5 18.333333333 -12 37.5 18.333333333 14 37.5 18.333333333 16 37.5 18.333333333 -18 37.5 18.333333333 20 37.5 18.333333333 0 40 18.333333333 -2 40 18.333333333 4 40 18.333333333 6 40 18.333333333 -8 40 18.333333333 10 40 18.333333333 12 40 18.333333333 -14 40 18.333333333 16 40 18.333333333 18 40 18.333333333 -20 40 18.333333333 0 42.5 18.333333333 2 42.5 18.333333333 -4 42.5 18.333333333 6 42.5 18.333333333 8 42.5 18.333333333 -10 42.5 18.333333333 12 42.5 18.333333333 14 42.5 18.333333333 -16 42.5 18.333333333 18 42.5 18.333333333 20 42.5 18.333333333 -0 45 18.333333333 2 45 18.333333333 4 45 18.333333333 -6 45 18.333333333 8 45 18.333333333 10 45 18.333333333 -12 45 18.333333333 14 45 18.333333333 16 45 18.333333333 -18 45 18.333333333 20 45 18.333333333 0 47.5 18.333333333 -2 47.5 18.333333333 4 47.5 18.333333333 6 47.5 18.333333333 -8 47.5 18.333333333 10 47.5 18.333333333 12 47.5 18.333333333 -14 47.5 18.333333333 16 47.5 18.333333333 18 47.5 18.333333333 -20 47.5 18.333333333 0 50 18.333333333 2 50 18.333333333 -4 50 18.333333333 6 50 18.333333333 8 50 18.333333333 -10 50 18.333333333 12 50 18.333333333 14 50 18.333333333 -16 50 18.333333333 18 50 18.333333333 20 50 18.333333333 -0 0 20 2 0 20 4 0 20 -6 0 20 8 0 20 10 0 20 -12 0 20 14 0 20 16 0 20 -18 0 20 20 0 20 0 2.5 20 -2 2.5 20 4 2.5 20 6 2.5 20 -8 2.5 20 10 2.5 20 12 2.5 20 -14 2.5 20 16 2.5 20 18 2.5 20 -20 2.5 20 0 5 20 2 5 20 -4 5 20 6 5 20 8 5 20 -10 5 20 12 5 20 14 5 20 -16 5 20 18 5 20 20 5 20 -0 7.5 20 2 7.5 20 4 7.5 20 -6 7.5 20 8 7.5 20 10 7.5 20 -12 7.5 20 14 7.5 20 16 7.5 20 -18 7.5 20 20 7.5 20 0 10 20 -2 10 20 4 10 20 6 10 20 -8 10 20 10 10 20 12 10 20 -14 10 20 16 10 20 18 10 20 -20 10 20 0 12.5 20 2 12.5 20 -4 12.5 20 6 12.5 20 8 12.5 20 -10 12.5 20 12 12.5 20 14 12.5 20 -16 12.5 20 18 12.5 20 20 12.5 20 -0 15 20 2 15 20 4 15 20 -6 15 20 8 15 20 10 15 20 -12 15 20 14 15 20 16 15 20 -18 15 20 20 15 20 0 17.5 20 -2 17.5 20 4 17.5 20 6 17.5 20 -8 17.5 20 10 17.5 20 12 17.5 20 -14 17.5 20 16 17.5 20 18 17.5 20 -20 17.5 20 0 20 20 2 20 20 -4 20 20 6 20 20 8 20 20 -10 20 20 12 20 20 14 20 20 -16 20 20 18 20 20 20 20 20 -0 22.5 20 2 22.5 20 4 22.5 20 -6 22.5 20 8 22.5 20 10 22.5 20 -12 22.5 20 14 22.5 20 16 22.5 20 -18 22.5 20 20 22.5 20 0 25 20 -2 25 20 4 25 20 6 25 20 -8 25 20 10 25 20 12 25 20 -14 25 20 16 25 20 18 25 20 -20 25 20 0 27.5 20 2 27.5 20 -4 27.5 20 6 27.5 20 8 27.5 20 -10 27.5 20 12 27.5 20 14 27.5 20 -16 27.5 20 18 27.5 20 20 27.5 20 -0 30 20 2 30 20 4 30 20 -6 30 20 8 30 20 10 30 20 -12 30 20 14 30 20 16 30 20 -18 30 20 20 30 20 0 32.5 20 -2 32.5 20 4 32.5 20 6 32.5 20 -8 32.5 20 10 32.5 20 12 32.5 20 -14 32.5 20 16 32.5 20 18 32.5 20 -20 32.5 20 0 35 20 2 35 20 -4 35 20 6 35 20 8 35 20 -10 35 20 12 35 20 14 35 20 -16 35 20 18 35 20 20 35 20 -0 37.5 20 2 37.5 20 4 37.5 20 -6 37.5 20 8 37.5 20 10 37.5 20 -12 37.5 20 14 37.5 20 16 37.5 20 -18 37.5 20 20 37.5 20 0 40 20 -2 40 20 4 40 20 6 40 20 -8 40 20 10 40 20 12 40 20 -14 40 20 16 40 20 18 40 20 -20 40 20 0 42.5 20 2 42.5 20 -4 42.5 20 6 42.5 20 8 42.5 20 -10 42.5 20 12 42.5 20 14 42.5 20 -16 42.5 20 18 42.5 20 20 42.5 20 -0 45 20 2 45 20 4 45 20 -6 45 20 8 45 20 10 45 20 -12 45 20 14 45 20 16 45 20 -18 45 20 20 45 20 0 47.5 20 -2 47.5 20 4 47.5 20 6 47.5 20 -8 47.5 20 10 47.5 20 12 47.5 20 -14 47.5 20 16 47.5 20 18 47.5 20 -20 47.5 20 0 50 20 2 50 20 -4 50 20 6 50 20 8 50 20 -10 50 20 12 50 20 14 50 20 -16 50 20 18 50 20 20 50 20 -0 0 21.666666667 2 0 21.666666667 4 0 21.666666667 -6 0 21.666666667 8 0 21.666666667 10 0 21.666666667 -12 0 21.666666667 14 0 21.666666667 16 0 21.666666667 -18 0 21.666666667 20 0 21.666666667 0 2.5 21.666666667 -2 2.5 21.666666667 4 2.5 21.666666667 6 2.5 21.666666667 -8 2.5 21.666666667 10 2.5 21.666666667 12 2.5 21.666666667 -14 2.5 21.666666667 16 2.5 21.666666667 18 2.5 21.666666667 -20 2.5 21.666666667 0 5 21.666666667 2 5 21.666666667 -4 5 21.666666667 6 5 21.666666667 8 5 21.666666667 -10 5 21.666666667 12 5 21.666666667 14 5 21.666666667 -16 5 21.666666667 18 5 21.666666667 20 5 21.666666667 -0 7.5 21.666666667 2 7.5 21.666666667 4 7.5 21.666666667 -6 7.5 21.666666667 8 7.5 21.666666667 10 7.5 21.666666667 -12 7.5 21.666666667 14 7.5 21.666666667 16 7.5 21.666666667 -18 7.5 21.666666667 20 7.5 21.666666667 0 10 21.666666667 -2 10 21.666666667 4 10 21.666666667 6 10 21.666666667 -8 10 21.666666667 10 10 21.666666667 12 10 21.666666667 -14 10 21.666666667 16 10 21.666666667 18 10 21.666666667 -20 10 21.666666667 0 12.5 21.666666667 2 12.5 21.666666667 -4 12.5 21.666666667 6 12.5 21.666666667 8 12.5 21.666666667 -10 12.5 21.666666667 12 12.5 21.666666667 14 12.5 21.666666667 -16 12.5 21.666666667 18 12.5 21.666666667 20 12.5 21.666666667 -0 15 21.666666667 2 15 21.666666667 4 15 21.666666667 -6 15 21.666666667 8 15 21.666666667 10 15 21.666666667 -12 15 21.666666667 14 15 21.666666667 16 15 21.666666667 -18 15 21.666666667 20 15 21.666666667 0 17.5 21.666666667 -2 17.5 21.666666667 4 17.5 21.666666667 6 17.5 21.666666667 -8 17.5 21.666666667 10 17.5 21.666666667 12 17.5 21.666666667 -14 17.5 21.666666667 16 17.5 21.666666667 18 17.5 21.666666667 -20 17.5 21.666666667 0 20 21.666666667 2 20 21.666666667 -4 20 21.666666667 6 20 21.666666667 8 20 21.666666667 -10 20 21.666666667 12 20 21.666666667 14 20 21.666666667 -16 20 21.666666667 18 20 21.666666667 20 20 21.666666667 -0 22.5 21.666666667 2 22.5 21.666666667 4 22.5 21.666666667 -6 22.5 21.666666667 8 22.5 21.666666667 10 22.5 21.666666667 -12 22.5 21.666666667 14 22.5 21.666666667 16 22.5 21.666666667 -18 22.5 21.666666667 20 22.5 21.666666667 0 25 21.666666667 -2 25 21.666666667 4 25 21.666666667 6 25 21.666666667 -8 25 21.666666667 10 25 21.666666667 12 25 21.666666667 -14 25 21.666666667 16 25 21.666666667 18 25 21.666666667 -20 25 21.666666667 0 27.5 21.666666667 2 27.5 21.666666667 -4 27.5 21.666666667 6 27.5 21.666666667 8 27.5 21.666666667 -10 27.5 21.666666667 12 27.5 21.666666667 14 27.5 21.666666667 -16 27.5 21.666666667 18 27.5 21.666666667 20 27.5 21.666666667 -0 30 21.666666667 2 30 21.666666667 4 30 21.666666667 -6 30 21.666666667 8 30 21.666666667 10 30 21.666666667 -12 30 21.666666667 14 30 21.666666667 16 30 21.666666667 -18 30 21.666666667 20 30 21.666666667 0 32.5 21.666666667 -2 32.5 21.666666667 4 32.5 21.666666667 6 32.5 21.666666667 -8 32.5 21.666666667 10 32.5 21.666666667 12 32.5 21.666666667 -14 32.5 21.666666667 16 32.5 21.666666667 18 32.5 21.666666667 -20 32.5 21.666666667 0 35 21.666666667 2 35 21.666666667 -4 35 21.666666667 6 35 21.666666667 8 35 21.666666667 -10 35 21.666666667 12 35 21.666666667 14 35 21.666666667 -16 35 21.666666667 18 35 21.666666667 20 35 21.666666667 -0 37.5 21.666666667 2 37.5 21.666666667 4 37.5 21.666666667 -6 37.5 21.666666667 8 37.5 21.666666667 10 37.5 21.666666667 -12 37.5 21.666666667 14 37.5 21.666666667 16 37.5 21.666666667 -18 37.5 21.666666667 20 37.5 21.666666667 0 40 21.666666667 -2 40 21.666666667 4 40 21.666666667 6 40 21.666666667 -8 40 21.666666667 10 40 21.666666667 12 40 21.666666667 -14 40 21.666666667 16 40 21.666666667 18 40 21.666666667 -20 40 21.666666667 0 42.5 21.666666667 2 42.5 21.666666667 -4 42.5 21.666666667 6 42.5 21.666666667 8 42.5 21.666666667 -10 42.5 21.666666667 12 42.5 21.666666667 14 42.5 21.666666667 -16 42.5 21.666666667 18 42.5 21.666666667 20 42.5 21.666666667 -0 45 21.666666667 2 45 21.666666667 4 45 21.666666667 -6 45 21.666666667 8 45 21.666666667 10 45 21.666666667 -12 45 21.666666667 14 45 21.666666667 16 45 21.666666667 -18 45 21.666666667 20 45 21.666666667 0 47.5 21.666666667 -2 47.5 21.666666667 4 47.5 21.666666667 6 47.5 21.666666667 -8 47.5 21.666666667 10 47.5 21.666666667 12 47.5 21.666666667 -14 47.5 21.666666667 16 47.5 21.666666667 18 47.5 21.666666667 -20 47.5 21.666666667 0 50 21.666666667 2 50 21.666666667 -4 50 21.666666667 6 50 21.666666667 8 50 21.666666667 -10 50 21.666666667 12 50 21.666666667 14 50 21.666666667 -16 50 21.666666667 18 50 21.666666667 20 50 21.666666667 -0 0 23.333333333 2 0 23.333333333 4 0 23.333333333 -6 0 23.333333333 8 0 23.333333333 10 0 23.333333333 -12 0 23.333333333 14 0 23.333333333 16 0 23.333333333 -18 0 23.333333333 20 0 23.333333333 0 2.5 23.333333333 -2 2.5 23.333333333 4 2.5 23.333333333 6 2.5 23.333333333 -8 2.5 23.333333333 10 2.5 23.333333333 12 2.5 23.333333333 -14 2.5 23.333333333 16 2.5 23.333333333 18 2.5 23.333333333 -20 2.5 23.333333333 0 5 23.333333333 2 5 23.333333333 -4 5 23.333333333 6 5 23.333333333 8 5 23.333333333 -10 5 23.333333333 12 5 23.333333333 14 5 23.333333333 -16 5 23.333333333 18 5 23.333333333 20 5 23.333333333 -0 7.5 23.333333333 2 7.5 23.333333333 4 7.5 23.333333333 -6 7.5 23.333333333 8 7.5 23.333333333 10 7.5 23.333333333 -12 7.5 23.333333333 14 7.5 23.333333333 16 7.5 23.333333333 -18 7.5 23.333333333 20 7.5 23.333333333 0 10 23.333333333 -2 10 23.333333333 4 10 23.333333333 6 10 23.333333333 -8 10 23.333333333 10 10 23.333333333 12 10 23.333333333 -14 10 23.333333333 16 10 23.333333333 18 10 23.333333333 -20 10 23.333333333 0 12.5 23.333333333 2 12.5 23.333333333 -4 12.5 23.333333333 6 12.5 23.333333333 8 12.5 23.333333333 -10 12.5 23.333333333 12 12.5 23.333333333 14 12.5 23.333333333 -16 12.5 23.333333333 18 12.5 23.333333333 20 12.5 23.333333333 -0 15 23.333333333 2 15 23.333333333 4 15 23.333333333 -6 15 23.333333333 8 15 23.333333333 10 15 23.333333333 -12 15 23.333333333 14 15 23.333333333 16 15 23.333333333 -18 15 23.333333333 20 15 23.333333333 0 17.5 23.333333333 -2 17.5 23.333333333 4 17.5 23.333333333 6 17.5 23.333333333 -8 17.5 23.333333333 10 17.5 23.333333333 12 17.5 23.333333333 -14 17.5 23.333333333 16 17.5 23.333333333 18 17.5 23.333333333 -20 17.5 23.333333333 0 20 23.333333333 2 20 23.333333333 -4 20 23.333333333 6 20 23.333333333 8 20 23.333333333 -10 20 23.333333333 12 20 23.333333333 14 20 23.333333333 -16 20 23.333333333 18 20 23.333333333 20 20 23.333333333 -0 22.5 23.333333333 2 22.5 23.333333333 4 22.5 23.333333333 -6 22.5 23.333333333 8 22.5 23.333333333 10 22.5 23.333333333 -12 22.5 23.333333333 14 22.5 23.333333333 16 22.5 23.333333333 -18 22.5 23.333333333 20 22.5 23.333333333 0 25 23.333333333 -2 25 23.333333333 4 25 23.333333333 6 25 23.333333333 -8 25 23.333333333 10 25 23.333333333 12 25 23.333333333 -14 25 23.333333333 16 25 23.333333333 18 25 23.333333333 -20 25 23.333333333 0 27.5 23.333333333 2 27.5 23.333333333 -4 27.5 23.333333333 6 27.5 23.333333333 8 27.5 23.333333333 -10 27.5 23.333333333 12 27.5 23.333333333 14 27.5 23.333333333 -16 27.5 23.333333333 18 27.5 23.333333333 20 27.5 23.333333333 -0 30 23.333333333 2 30 23.333333333 4 30 23.333333333 -6 30 23.333333333 8 30 23.333333333 10 30 23.333333333 -12 30 23.333333333 14 30 23.333333333 16 30 23.333333333 -18 30 23.333333333 20 30 23.333333333 0 32.5 23.333333333 -2 32.5 23.333333333 4 32.5 23.333333333 6 32.5 23.333333333 -8 32.5 23.333333333 10 32.5 23.333333333 12 32.5 23.333333333 -14 32.5 23.333333333 16 32.5 23.333333333 18 32.5 23.333333333 -20 32.5 23.333333333 0 35 23.333333333 2 35 23.333333333 -4 35 23.333333333 6 35 23.333333333 8 35 23.333333333 -10 35 23.333333333 12 35 23.333333333 14 35 23.333333333 -16 35 23.333333333 18 35 23.333333333 20 35 23.333333333 -0 37.5 23.333333333 2 37.5 23.333333333 4 37.5 23.333333333 -6 37.5 23.333333333 8 37.5 23.333333333 10 37.5 23.333333333 -12 37.5 23.333333333 14 37.5 23.333333333 16 37.5 23.333333333 -18 37.5 23.333333333 20 37.5 23.333333333 0 40 23.333333333 -2 40 23.333333333 4 40 23.333333333 6 40 23.333333333 -8 40 23.333333333 10 40 23.333333333 12 40 23.333333333 -14 40 23.333333333 16 40 23.333333333 18 40 23.333333333 -20 40 23.333333333 0 42.5 23.333333333 2 42.5 23.333333333 -4 42.5 23.333333333 6 42.5 23.333333333 8 42.5 23.333333333 -10 42.5 23.333333333 12 42.5 23.333333333 14 42.5 23.333333333 -16 42.5 23.333333333 18 42.5 23.333333333 20 42.5 23.333333333 -0 45 23.333333333 2 45 23.333333333 4 45 23.333333333 -6 45 23.333333333 8 45 23.333333333 10 45 23.333333333 -12 45 23.333333333 14 45 23.333333333 16 45 23.333333333 -18 45 23.333333333 20 45 23.333333333 0 47.5 23.333333333 -2 47.5 23.333333333 4 47.5 23.333333333 6 47.5 23.333333333 -8 47.5 23.333333333 10 47.5 23.333333333 12 47.5 23.333333333 -14 47.5 23.333333333 16 47.5 23.333333333 18 47.5 23.333333333 -20 47.5 23.333333333 0 50 23.333333333 2 50 23.333333333 -4 50 23.333333333 6 50 23.333333333 8 50 23.333333333 -10 50 23.333333333 12 50 23.333333333 14 50 23.333333333 -16 50 23.333333333 18 50 23.333333333 20 50 23.333333333 -0 0 25 2 0 25 4 0 25 -6 0 25 8 0 25 10 0 25 -12 0 25 14 0 25 16 0 25 -18 0 25 20 0 25 0 2.5 25 -2 2.5 25 4 2.5 25 6 2.5 25 -8 2.5 25 10 2.5 25 12 2.5 25 -14 2.5 25 16 2.5 25 18 2.5 25 -20 2.5 25 0 5 25 2 5 25 -4 5 25 6 5 25 8 5 25 -10 5 25 12 5 25 14 5 25 -16 5 25 18 5 25 20 5 25 -0 7.5 25 2 7.5 25 4 7.5 25 -6 7.5 25 8 7.5 25 10 7.5 25 -12 7.5 25 14 7.5 25 16 7.5 25 -18 7.5 25 20 7.5 25 0 10 25 -2 10 25 4 10 25 6 10 25 -8 10 25 10 10 25 12 10 25 -14 10 25 16 10 25 18 10 25 -20 10 25 0 12.5 25 2 12.5 25 -4 12.5 25 6 12.5 25 8 12.5 25 -10 12.5 25 12 12.5 25 14 12.5 25 -16 12.5 25 18 12.5 25 20 12.5 25 -0 15 25 2 15 25 4 15 25 -6 15 25 8 15 25 10 15 25 -12 15 25 14 15 25 16 15 25 -18 15 25 20 15 25 0 17.5 25 -2 17.5 25 4 17.5 25 6 17.5 25 -8 17.5 25 10 17.5 25 12 17.5 25 -14 17.5 25 16 17.5 25 18 17.5 25 -20 17.5 25 0 20 25 2 20 25 -4 20 25 6 20 25 8 20 25 -10 20 25 12 20 25 14 20 25 -16 20 25 18 20 25 20 20 25 -0 22.5 25 2 22.5 25 4 22.5 25 -6 22.5 25 8 22.5 25 10 22.5 25 -12 22.5 25 14 22.5 25 16 22.5 25 -18 22.5 25 20 22.5 25 0 25 25 -2 25 25 4 25 25 6 25 25 -8 25 25 10 25 25 12 25 25 -14 25 25 16 25 25 18 25 25 -20 25 25 0 27.5 25 2 27.5 25 -4 27.5 25 6 27.5 25 8 27.5 25 -10 27.5 25 12 27.5 25 14 27.5 25 -16 27.5 25 18 27.5 25 20 27.5 25 -0 30 25 2 30 25 4 30 25 -6 30 25 8 30 25 10 30 25 -12 30 25 14 30 25 16 30 25 -18 30 25 20 30 25 0 32.5 25 -2 32.5 25 4 32.5 25 6 32.5 25 -8 32.5 25 10 32.5 25 12 32.5 25 -14 32.5 25 16 32.5 25 18 32.5 25 -20 32.5 25 0 35 25 2 35 25 -4 35 25 6 35 25 8 35 25 -10 35 25 12 35 25 14 35 25 -16 35 25 18 35 25 20 35 25 -0 37.5 25 2 37.5 25 4 37.5 25 -6 37.5 25 8 37.5 25 10 37.5 25 -12 37.5 25 14 37.5 25 16 37.5 25 -18 37.5 25 20 37.5 25 0 40 25 -2 40 25 4 40 25 6 40 25 -8 40 25 10 40 25 12 40 25 -14 40 25 16 40 25 18 40 25 -20 40 25 0 42.5 25 2 42.5 25 -4 42.5 25 6 42.5 25 8 42.5 25 -10 42.5 25 12 42.5 25 14 42.5 25 -16 42.5 25 18 42.5 25 20 42.5 25 -0 45 25 2 45 25 4 45 25 -6 45 25 8 45 25 10 45 25 -12 45 25 14 45 25 16 45 25 -18 45 25 20 45 25 0 47.5 25 -2 47.5 25 4 47.5 25 6 47.5 25 -8 47.5 25 10 47.5 25 12 47.5 25 -14 47.5 25 16 47.5 25 18 47.5 25 -20 47.5 25 0 50 25 2 50 25 -4 50 25 6 50 25 8 50 25 -10 50 25 12 50 25 14 50 25 -16 50 25 18 50 25 20 50 25 -0 0 26.666666667 2 0 26.666666667 4 0 26.666666667 -6 0 26.666666667 8 0 26.666666667 10 0 26.666666667 -12 0 26.666666667 14 0 26.666666667 16 0 26.666666667 -18 0 26.666666667 20 0 26.666666667 0 2.5 26.666666667 -2 2.5 26.666666667 4 2.5 26.666666667 6 2.5 26.666666667 -8 2.5 26.666666667 10 2.5 26.666666667 12 2.5 26.666666667 -14 2.5 26.666666667 16 2.5 26.666666667 18 2.5 26.666666667 -20 2.5 26.666666667 0 5 26.666666667 2 5 26.666666667 -4 5 26.666666667 6 5 26.666666667 8 5 26.666666667 -10 5 26.666666667 12 5 26.666666667 14 5 26.666666667 -16 5 26.666666667 18 5 26.666666667 20 5 26.666666667 -0 7.5 26.666666667 2 7.5 26.666666667 4 7.5 26.666666667 -6 7.5 26.666666667 8 7.5 26.666666667 10 7.5 26.666666667 -12 7.5 26.666666667 14 7.5 26.666666667 16 7.5 26.666666667 -18 7.5 26.666666667 20 7.5 26.666666667 0 10 26.666666667 -2 10 26.666666667 4 10 26.666666667 6 10 26.666666667 -8 10 26.666666667 10 10 26.666666667 12 10 26.666666667 -14 10 26.666666667 16 10 26.666666667 18 10 26.666666667 -20 10 26.666666667 0 12.5 26.666666667 2 12.5 26.666666667 -4 12.5 26.666666667 6 12.5 26.666666667 8 12.5 26.666666667 -10 12.5 26.666666667 12 12.5 26.666666667 14 12.5 26.666666667 -16 12.5 26.666666667 18 12.5 26.666666667 20 12.5 26.666666667 -0 15 26.666666667 2 15 26.666666667 4 15 26.666666667 -6 15 26.666666667 8 15 26.666666667 10 15 26.666666667 -12 15 26.666666667 14 15 26.666666667 16 15 26.666666667 -18 15 26.666666667 20 15 26.666666667 0 17.5 26.666666667 -2 17.5 26.666666667 4 17.5 26.666666667 6 17.5 26.666666667 -8 17.5 26.666666667 10 17.5 26.666666667 12 17.5 26.666666667 -14 17.5 26.666666667 16 17.5 26.666666667 18 17.5 26.666666667 -20 17.5 26.666666667 0 20 26.666666667 2 20 26.666666667 -4 20 26.666666667 6 20 26.666666667 8 20 26.666666667 -10 20 26.666666667 12 20 26.666666667 14 20 26.666666667 -16 20 26.666666667 18 20 26.666666667 20 20 26.666666667 -0 22.5 26.666666667 2 22.5 26.666666667 4 22.5 26.666666667 -6 22.5 26.666666667 8 22.5 26.666666667 10 22.5 26.666666667 -12 22.5 26.666666667 14 22.5 26.666666667 16 22.5 26.666666667 -18 22.5 26.666666667 20 22.5 26.666666667 0 25 26.666666667 -2 25 26.666666667 4 25 26.666666667 6 25 26.666666667 -8 25 26.666666667 10 25 26.666666667 12 25 26.666666667 -14 25 26.666666667 16 25 26.666666667 18 25 26.666666667 -20 25 26.666666667 0 27.5 26.666666667 2 27.5 26.666666667 -4 27.5 26.666666667 6 27.5 26.666666667 8 27.5 26.666666667 -10 27.5 26.666666667 12 27.5 26.666666667 14 27.5 26.666666667 -16 27.5 26.666666667 18 27.5 26.666666667 20 27.5 26.666666667 -0 30 26.666666667 2 30 26.666666667 4 30 26.666666667 -6 30 26.666666667 8 30 26.666666667 10 30 26.666666667 -12 30 26.666666667 14 30 26.666666667 16 30 26.666666667 -18 30 26.666666667 20 30 26.666666667 0 32.5 26.666666667 -2 32.5 26.666666667 4 32.5 26.666666667 6 32.5 26.666666667 -8 32.5 26.666666667 10 32.5 26.666666667 12 32.5 26.666666667 -14 32.5 26.666666667 16 32.5 26.666666667 18 32.5 26.666666667 -20 32.5 26.666666667 0 35 26.666666667 2 35 26.666666667 -4 35 26.666666667 6 35 26.666666667 8 35 26.666666667 -10 35 26.666666667 12 35 26.666666667 14 35 26.666666667 -16 35 26.666666667 18 35 26.666666667 20 35 26.666666667 -0 37.5 26.666666667 2 37.5 26.666666667 4 37.5 26.666666667 -6 37.5 26.666666667 8 37.5 26.666666667 10 37.5 26.666666667 -12 37.5 26.666666667 14 37.5 26.666666667 16 37.5 26.666666667 -18 37.5 26.666666667 20 37.5 26.666666667 0 40 26.666666667 -2 40 26.666666667 4 40 26.666666667 6 40 26.666666667 -8 40 26.666666667 10 40 26.666666667 12 40 26.666666667 -14 40 26.666666667 16 40 26.666666667 18 40 26.666666667 -20 40 26.666666667 0 42.5 26.666666667 2 42.5 26.666666667 -4 42.5 26.666666667 6 42.5 26.666666667 8 42.5 26.666666667 -10 42.5 26.666666667 12 42.5 26.666666667 14 42.5 26.666666667 -16 42.5 26.666666667 18 42.5 26.666666667 20 42.5 26.666666667 -0 45 26.666666667 2 45 26.666666667 4 45 26.666666667 -6 45 26.666666667 8 45 26.666666667 10 45 26.666666667 -12 45 26.666666667 14 45 26.666666667 16 45 26.666666667 -18 45 26.666666667 20 45 26.666666667 0 47.5 26.666666667 -2 47.5 26.666666667 4 47.5 26.666666667 6 47.5 26.666666667 -8 47.5 26.666666667 10 47.5 26.666666667 12 47.5 26.666666667 -14 47.5 26.666666667 16 47.5 26.666666667 18 47.5 26.666666667 -20 47.5 26.666666667 0 50 26.666666667 2 50 26.666666667 -4 50 26.666666667 6 50 26.666666667 8 50 26.666666667 -10 50 26.666666667 12 50 26.666666667 14 50 26.666666667 -16 50 26.666666667 18 50 26.666666667 20 50 26.666666667 -0 0 28.333333333 2 0 28.333333333 4 0 28.333333333 -6 0 28.333333333 8 0 28.333333333 10 0 28.333333333 -12 0 28.333333333 14 0 28.333333333 16 0 28.333333333 -18 0 28.333333333 20 0 28.333333333 0 2.5 28.333333333 -2 2.5 28.333333333 4 2.5 28.333333333 6 2.5 28.333333333 -8 2.5 28.333333333 10 2.5 28.333333333 12 2.5 28.333333333 -14 2.5 28.333333333 16 2.5 28.333333333 18 2.5 28.333333333 -20 2.5 28.333333333 0 5 28.333333333 2 5 28.333333333 -4 5 28.333333333 6 5 28.333333333 8 5 28.333333333 -10 5 28.333333333 12 5 28.333333333 14 5 28.333333333 -16 5 28.333333333 18 5 28.333333333 20 5 28.333333333 -0 7.5 28.333333333 2 7.5 28.333333333 4 7.5 28.333333333 -6 7.5 28.333333333 8 7.5 28.333333333 10 7.5 28.333333333 -12 7.5 28.333333333 14 7.5 28.333333333 16 7.5 28.333333333 -18 7.5 28.333333333 20 7.5 28.333333333 0 10 28.333333333 -2 10 28.333333333 4 10 28.333333333 6 10 28.333333333 -8 10 28.333333333 10 10 28.333333333 12 10 28.333333333 -14 10 28.333333333 16 10 28.333333333 18 10 28.333333333 -20 10 28.333333333 0 12.5 28.333333333 2 12.5 28.333333333 -4 12.5 28.333333333 6 12.5 28.333333333 8 12.5 28.333333333 -10 12.5 28.333333333 12 12.5 28.333333333 14 12.5 28.333333333 -16 12.5 28.333333333 18 12.5 28.333333333 20 12.5 28.333333333 -0 15 28.333333333 2 15 28.333333333 4 15 28.333333333 -6 15 28.333333333 8 15 28.333333333 10 15 28.333333333 -12 15 28.333333333 14 15 28.333333333 16 15 28.333333333 -18 15 28.333333333 20 15 28.333333333 0 17.5 28.333333333 -2 17.5 28.333333333 4 17.5 28.333333333 6 17.5 28.333333333 -8 17.5 28.333333333 10 17.5 28.333333333 12 17.5 28.333333333 -14 17.5 28.333333333 16 17.5 28.333333333 18 17.5 28.333333333 -20 17.5 28.333333333 0 20 28.333333333 2 20 28.333333333 -4 20 28.333333333 6 20 28.333333333 8 20 28.333333333 -10 20 28.333333333 12 20 28.333333333 14 20 28.333333333 -16 20 28.333333333 18 20 28.333333333 20 20 28.333333333 -0 22.5 28.333333333 2 22.5 28.333333333 4 22.5 28.333333333 -6 22.5 28.333333333 8 22.5 28.333333333 10 22.5 28.333333333 -12 22.5 28.333333333 14 22.5 28.333333333 16 22.5 28.333333333 -18 22.5 28.333333333 20 22.5 28.333333333 0 25 28.333333333 -2 25 28.333333333 4 25 28.333333333 6 25 28.333333333 -8 25 28.333333333 10 25 28.333333333 12 25 28.333333333 -14 25 28.333333333 16 25 28.333333333 18 25 28.333333333 -20 25 28.333333333 0 27.5 28.333333333 2 27.5 28.333333333 -4 27.5 28.333333333 6 27.5 28.333333333 8 27.5 28.333333333 -10 27.5 28.333333333 12 27.5 28.333333333 14 27.5 28.333333333 -16 27.5 28.333333333 18 27.5 28.333333333 20 27.5 28.333333333 -0 30 28.333333333 2 30 28.333333333 4 30 28.333333333 -6 30 28.333333333 8 30 28.333333333 10 30 28.333333333 -12 30 28.333333333 14 30 28.333333333 16 30 28.333333333 -18 30 28.333333333 20 30 28.333333333 0 32.5 28.333333333 -2 32.5 28.333333333 4 32.5 28.333333333 6 32.5 28.333333333 -8 32.5 28.333333333 10 32.5 28.333333333 12 32.5 28.333333333 -14 32.5 28.333333333 16 32.5 28.333333333 18 32.5 28.333333333 -20 32.5 28.333333333 0 35 28.333333333 2 35 28.333333333 -4 35 28.333333333 6 35 28.333333333 8 35 28.333333333 -10 35 28.333333333 12 35 28.333333333 14 35 28.333333333 -16 35 28.333333333 18 35 28.333333333 20 35 28.333333333 -0 37.5 28.333333333 2 37.5 28.333333333 4 37.5 28.333333333 -6 37.5 28.333333333 8 37.5 28.333333333 10 37.5 28.333333333 -12 37.5 28.333333333 14 37.5 28.333333333 16 37.5 28.333333333 -18 37.5 28.333333333 20 37.5 28.333333333 0 40 28.333333333 -2 40 28.333333333 4 40 28.333333333 6 40 28.333333333 -8 40 28.333333333 10 40 28.333333333 12 40 28.333333333 -14 40 28.333333333 16 40 28.333333333 18 40 28.333333333 -20 40 28.333333333 0 42.5 28.333333333 2 42.5 28.333333333 -4 42.5 28.333333333 6 42.5 28.333333333 8 42.5 28.333333333 -10 42.5 28.333333333 12 42.5 28.333333333 14 42.5 28.333333333 -16 42.5 28.333333333 18 42.5 28.333333333 20 42.5 28.333333333 -0 45 28.333333333 2 45 28.333333333 4 45 28.333333333 -6 45 28.333333333 8 45 28.333333333 10 45 28.333333333 -12 45 28.333333333 14 45 28.333333333 16 45 28.333333333 -18 45 28.333333333 20 45 28.333333333 0 47.5 28.333333333 -2 47.5 28.333333333 4 47.5 28.333333333 6 47.5 28.333333333 -8 47.5 28.333333333 10 47.5 28.333333333 12 47.5 28.333333333 -14 47.5 28.333333333 16 47.5 28.333333333 18 47.5 28.333333333 -20 47.5 28.333333333 0 50 28.333333333 2 50 28.333333333 -4 50 28.333333333 6 50 28.333333333 8 50 28.333333333 -10 50 28.333333333 12 50 28.333333333 14 50 28.333333333 -16 50 28.333333333 18 50 28.333333333 20 50 28.333333333 -0 0 30 2 0 30 4 0 30 -6 0 30 8 0 30 10 0 30 -12 0 30 14 0 30 16 0 30 -18 0 30 20 0 30 0 2.5 30 -2 2.5 30 4 2.5 30 6 2.5 30 -8 2.5 30 10 2.5 30 12 2.5 30 -14 2.5 30 16 2.5 30 18 2.5 30 -20 2.5 30 0 5 30 2 5 30 -4 5 30 6 5 30 8 5 30 -10 5 30 12 5 30 14 5 30 -16 5 30 18 5 30 20 5 30 -0 7.5 30 2 7.5 30 4 7.5 30 -6 7.5 30 8 7.5 30 10 7.5 30 -12 7.5 30 14 7.5 30 16 7.5 30 -18 7.5 30 20 7.5 30 0 10 30 -2 10 30 4 10 30 6 10 30 -8 10 30 10 10 30 12 10 30 -14 10 30 16 10 30 18 10 30 -20 10 30 0 12.5 30 2 12.5 30 -4 12.5 30 6 12.5 30 8 12.5 30 -10 12.5 30 12 12.5 30 14 12.5 30 -16 12.5 30 18 12.5 30 20 12.5 30 -0 15 30 2 15 30 4 15 30 -6 15 30 8 15 30 10 15 30 -12 15 30 14 15 30 16 15 30 -18 15 30 20 15 30 0 17.5 30 -2 17.5 30 4 17.5 30 6 17.5 30 -8 17.5 30 10 17.5 30 12 17.5 30 -14 17.5 30 16 17.5 30 18 17.5 30 -20 17.5 30 0 20 30 2 20 30 -4 20 30 6 20 30 8 20 30 -10 20 30 12 20 30 14 20 30 -16 20 30 18 20 30 20 20 30 -0 22.5 30 2 22.5 30 4 22.5 30 -6 22.5 30 8 22.5 30 10 22.5 30 -12 22.5 30 14 22.5 30 16 22.5 30 -18 22.5 30 20 22.5 30 0 25 30 -2 25 30 4 25 30 6 25 30 -8 25 30 10 25 30 12 25 30 -14 25 30 16 25 30 18 25 30 -20 25 30 0 27.5 30 2 27.5 30 -4 27.5 30 6 27.5 30 8 27.5 30 -10 27.5 30 12 27.5 30 14 27.5 30 -16 27.5 30 18 27.5 30 20 27.5 30 -0 30 30 2 30 30 4 30 30 -6 30 30 8 30 30 10 30 30 -12 30 30 14 30 30 16 30 30 -18 30 30 20 30 30 0 32.5 30 -2 32.5 30 4 32.5 30 6 32.5 30 -8 32.5 30 10 32.5 30 12 32.5 30 -14 32.5 30 16 32.5 30 18 32.5 30 -20 32.5 30 0 35 30 2 35 30 -4 35 30 6 35 30 8 35 30 -10 35 30 12 35 30 14 35 30 -16 35 30 18 35 30 20 35 30 -0 37.5 30 2 37.5 30 4 37.5 30 -6 37.5 30 8 37.5 30 10 37.5 30 -12 37.5 30 14 37.5 30 16 37.5 30 -18 37.5 30 20 37.5 30 0 40 30 -2 40 30 4 40 30 6 40 30 -8 40 30 10 40 30 12 40 30 -14 40 30 16 40 30 18 40 30 -20 40 30 0 42.5 30 2 42.5 30 -4 42.5 30 6 42.5 30 8 42.5 30 -10 42.5 30 12 42.5 30 14 42.5 30 -16 42.5 30 18 42.5 30 20 42.5 30 -0 45 30 2 45 30 4 45 30 -6 45 30 8 45 30 10 45 30 -12 45 30 14 45 30 16 45 30 -18 45 30 20 45 30 0 47.5 30 -2 47.5 30 4 47.5 30 6 47.5 30 -8 47.5 30 10 47.5 30 12 47.5 30 -14 47.5 30 16 47.5 30 18 47.5 30 -20 47.5 30 0 50 30 2 50 30 -4 50 30 6 50 30 8 50 30 -10 50 30 12 50 30 14 50 30 -16 50 30 18 50 30 20 50 30 -0 0 31.666666667 2 0 31.666666667 4 0 31.666666667 -6 0 31.666666667 8 0 31.666666667 10 0 31.666666667 -12 0 31.666666667 14 0 31.666666667 16 0 31.666666667 -18 0 31.666666667 20 0 31.666666667 0 2.5 31.666666667 -2 2.5 31.666666667 4 2.5 31.666666667 6 2.5 31.666666667 -8 2.5 31.666666667 10 2.5 31.666666667 12 2.5 31.666666667 -14 2.5 31.666666667 16 2.5 31.666666667 18 2.5 31.666666667 -20 2.5 31.666666667 0 5 31.666666667 2 5 31.666666667 -4 5 31.666666667 6 5 31.666666667 8 5 31.666666667 -10 5 31.666666667 12 5 31.666666667 14 5 31.666666667 -16 5 31.666666667 18 5 31.666666667 20 5 31.666666667 -0 7.5 31.666666667 2 7.5 31.666666667 4 7.5 31.666666667 -6 7.5 31.666666667 8 7.5 31.666666667 10 7.5 31.666666667 -12 7.5 31.666666667 14 7.5 31.666666667 16 7.5 31.666666667 -18 7.5 31.666666667 20 7.5 31.666666667 0 10 31.666666667 -2 10 31.666666667 4 10 31.666666667 6 10 31.666666667 -8 10 31.666666667 10 10 31.666666667 12 10 31.666666667 -14 10 31.666666667 16 10 31.666666667 18 10 31.666666667 -20 10 31.666666667 0 12.5 31.666666667 2 12.5 31.666666667 -4 12.5 31.666666667 6 12.5 31.666666667 8 12.5 31.666666667 -10 12.5 31.666666667 12 12.5 31.666666667 14 12.5 31.666666667 -16 12.5 31.666666667 18 12.5 31.666666667 20 12.5 31.666666667 -0 15 31.666666667 2 15 31.666666667 4 15 31.666666667 -6 15 31.666666667 8 15 31.666666667 10 15 31.666666667 -12 15 31.666666667 14 15 31.666666667 16 15 31.666666667 -18 15 31.666666667 20 15 31.666666667 0 17.5 31.666666667 -2 17.5 31.666666667 4 17.5 31.666666667 6 17.5 31.666666667 -8 17.5 31.666666667 10 17.5 31.666666667 12 17.5 31.666666667 -14 17.5 31.666666667 16 17.5 31.666666667 18 17.5 31.666666667 -20 17.5 31.666666667 0 20 31.666666667 2 20 31.666666667 -4 20 31.666666667 6 20 31.666666667 8 20 31.666666667 -10 20 31.666666667 12 20 31.666666667 14 20 31.666666667 -16 20 31.666666667 18 20 31.666666667 20 20 31.666666667 -0 22.5 31.666666667 2 22.5 31.666666667 4 22.5 31.666666667 -6 22.5 31.666666667 8 22.5 31.666666667 10 22.5 31.666666667 -12 22.5 31.666666667 14 22.5 31.666666667 16 22.5 31.666666667 -18 22.5 31.666666667 20 22.5 31.666666667 0 25 31.666666667 -2 25 31.666666667 4 25 31.666666667 6 25 31.666666667 -8 25 31.666666667 10 25 31.666666667 12 25 31.666666667 -14 25 31.666666667 16 25 31.666666667 18 25 31.666666667 -20 25 31.666666667 0 27.5 31.666666667 2 27.5 31.666666667 -4 27.5 31.666666667 6 27.5 31.666666667 8 27.5 31.666666667 -10 27.5 31.666666667 12 27.5 31.666666667 14 27.5 31.666666667 -16 27.5 31.666666667 18 27.5 31.666666667 20 27.5 31.666666667 -0 30 31.666666667 2 30 31.666666667 4 30 31.666666667 -6 30 31.666666667 8 30 31.666666667 10 30 31.666666667 -12 30 31.666666667 14 30 31.666666667 16 30 31.666666667 -18 30 31.666666667 20 30 31.666666667 0 32.5 31.666666667 -2 32.5 31.666666667 4 32.5 31.666666667 6 32.5 31.666666667 -8 32.5 31.666666667 10 32.5 31.666666667 12 32.5 31.666666667 -14 32.5 31.666666667 16 32.5 31.666666667 18 32.5 31.666666667 -20 32.5 31.666666667 0 35 31.666666667 2 35 31.666666667 -4 35 31.666666667 6 35 31.666666667 8 35 31.666666667 -10 35 31.666666667 12 35 31.666666667 14 35 31.666666667 -16 35 31.666666667 18 35 31.666666667 20 35 31.666666667 -0 37.5 31.666666667 2 37.5 31.666666667 4 37.5 31.666666667 -6 37.5 31.666666667 8 37.5 31.666666667 10 37.5 31.666666667 -12 37.5 31.666666667 14 37.5 31.666666667 16 37.5 31.666666667 -18 37.5 31.666666667 20 37.5 31.666666667 0 40 31.666666667 -2 40 31.666666667 4 40 31.666666667 6 40 31.666666667 -8 40 31.666666667 10 40 31.666666667 12 40 31.666666667 -14 40 31.666666667 16 40 31.666666667 18 40 31.666666667 -20 40 31.666666667 0 42.5 31.666666667 2 42.5 31.666666667 -4 42.5 31.666666667 6 42.5 31.666666667 8 42.5 31.666666667 -10 42.5 31.666666667 12 42.5 31.666666667 14 42.5 31.666666667 -16 42.5 31.666666667 18 42.5 31.666666667 20 42.5 31.666666667 -0 45 31.666666667 2 45 31.666666667 4 45 31.666666667 -6 45 31.666666667 8 45 31.666666667 10 45 31.666666667 -12 45 31.666666667 14 45 31.666666667 16 45 31.666666667 -18 45 31.666666667 20 45 31.666666667 0 47.5 31.666666667 -2 47.5 31.666666667 4 47.5 31.666666667 6 47.5 31.666666667 -8 47.5 31.666666667 10 47.5 31.666666667 12 47.5 31.666666667 -14 47.5 31.666666667 16 47.5 31.666666667 18 47.5 31.666666667 -20 47.5 31.666666667 0 50 31.666666667 2 50 31.666666667 -4 50 31.666666667 6 50 31.666666667 8 50 31.666666667 -10 50 31.666666667 12 50 31.666666667 14 50 31.666666667 -16 50 31.666666667 18 50 31.666666667 20 50 31.666666667 -0 0 33.333333333 2 0 33.333333333 4 0 33.333333333 -6 0 33.333333333 8 0 33.333333333 10 0 33.333333333 -12 0 33.333333333 14 0 33.333333333 16 0 33.333333333 -18 0 33.333333333 20 0 33.333333333 0 2.5 33.333333333 -2 2.5 33.333333333 4 2.5 33.333333333 6 2.5 33.333333333 -8 2.5 33.333333333 10 2.5 33.333333333 12 2.5 33.333333333 -14 2.5 33.333333333 16 2.5 33.333333333 18 2.5 33.333333333 -20 2.5 33.333333333 0 5 33.333333333 2 5 33.333333333 -4 5 33.333333333 6 5 33.333333333 8 5 33.333333333 -10 5 33.333333333 12 5 33.333333333 14 5 33.333333333 -16 5 33.333333333 18 5 33.333333333 20 5 33.333333333 -0 7.5 33.333333333 2 7.5 33.333333333 4 7.5 33.333333333 -6 7.5 33.333333333 8 7.5 33.333333333 10 7.5 33.333333333 -12 7.5 33.333333333 14 7.5 33.333333333 16 7.5 33.333333333 -18 7.5 33.333333333 20 7.5 33.333333333 0 10 33.333333333 -2 10 33.333333333 4 10 33.333333333 6 10 33.333333333 -8 10 33.333333333 10 10 33.333333333 12 10 33.333333333 -14 10 33.333333333 16 10 33.333333333 18 10 33.333333333 -20 10 33.333333333 0 12.5 33.333333333 2 12.5 33.333333333 -4 12.5 33.333333333 6 12.5 33.333333333 8 12.5 33.333333333 -10 12.5 33.333333333 12 12.5 33.333333333 14 12.5 33.333333333 -16 12.5 33.333333333 18 12.5 33.333333333 20 12.5 33.333333333 -0 15 33.333333333 2 15 33.333333333 4 15 33.333333333 -6 15 33.333333333 8 15 33.333333333 10 15 33.333333333 -12 15 33.333333333 14 15 33.333333333 16 15 33.333333333 -18 15 33.333333333 20 15 33.333333333 0 17.5 33.333333333 -2 17.5 33.333333333 4 17.5 33.333333333 6 17.5 33.333333333 -8 17.5 33.333333333 10 17.5 33.333333333 12 17.5 33.333333333 -14 17.5 33.333333333 16 17.5 33.333333333 18 17.5 33.333333333 -20 17.5 33.333333333 0 20 33.333333333 2 20 33.333333333 -4 20 33.333333333 6 20 33.333333333 8 20 33.333333333 -10 20 33.333333333 12 20 33.333333333 14 20 33.333333333 -16 20 33.333333333 18 20 33.333333333 20 20 33.333333333 -0 22.5 33.333333333 2 22.5 33.333333333 4 22.5 33.333333333 -6 22.5 33.333333333 8 22.5 33.333333333 10 22.5 33.333333333 -12 22.5 33.333333333 14 22.5 33.333333333 16 22.5 33.333333333 -18 22.5 33.333333333 20 22.5 33.333333333 0 25 33.333333333 -2 25 33.333333333 4 25 33.333333333 6 25 33.333333333 -8 25 33.333333333 10 25 33.333333333 12 25 33.333333333 -14 25 33.333333333 16 25 33.333333333 18 25 33.333333333 -20 25 33.333333333 0 27.5 33.333333333 2 27.5 33.333333333 -4 27.5 33.333333333 6 27.5 33.333333333 8 27.5 33.333333333 -10 27.5 33.333333333 12 27.5 33.333333333 14 27.5 33.333333333 -16 27.5 33.333333333 18 27.5 33.333333333 20 27.5 33.333333333 -0 30 33.333333333 2 30 33.333333333 4 30 33.333333333 -6 30 33.333333333 8 30 33.333333333 10 30 33.333333333 -12 30 33.333333333 14 30 33.333333333 16 30 33.333333333 -18 30 33.333333333 20 30 33.333333333 0 32.5 33.333333333 -2 32.5 33.333333333 4 32.5 33.333333333 6 32.5 33.333333333 -8 32.5 33.333333333 10 32.5 33.333333333 12 32.5 33.333333333 -14 32.5 33.333333333 16 32.5 33.333333333 18 32.5 33.333333333 -20 32.5 33.333333333 0 35 33.333333333 2 35 33.333333333 -4 35 33.333333333 6 35 33.333333333 8 35 33.333333333 -10 35 33.333333333 12 35 33.333333333 14 35 33.333333333 -16 35 33.333333333 18 35 33.333333333 20 35 33.333333333 -0 37.5 33.333333333 2 37.5 33.333333333 4 37.5 33.333333333 -6 37.5 33.333333333 8 37.5 33.333333333 10 37.5 33.333333333 -12 37.5 33.333333333 14 37.5 33.333333333 16 37.5 33.333333333 -18 37.5 33.333333333 20 37.5 33.333333333 0 40 33.333333333 -2 40 33.333333333 4 40 33.333333333 6 40 33.333333333 -8 40 33.333333333 10 40 33.333333333 12 40 33.333333333 -14 40 33.333333333 16 40 33.333333333 18 40 33.333333333 -20 40 33.333333333 0 42.5 33.333333333 2 42.5 33.333333333 -4 42.5 33.333333333 6 42.5 33.333333333 8 42.5 33.333333333 -10 42.5 33.333333333 12 42.5 33.333333333 14 42.5 33.333333333 -16 42.5 33.333333333 18 42.5 33.333333333 20 42.5 33.333333333 -0 45 33.333333333 2 45 33.333333333 4 45 33.333333333 -6 45 33.333333333 8 45 33.333333333 10 45 33.333333333 -12 45 33.333333333 14 45 33.333333333 16 45 33.333333333 -18 45 33.333333333 20 45 33.333333333 0 47.5 33.333333333 -2 47.5 33.333333333 4 47.5 33.333333333 6 47.5 33.333333333 -8 47.5 33.333333333 10 47.5 33.333333333 12 47.5 33.333333333 -14 47.5 33.333333333 16 47.5 33.333333333 18 47.5 33.333333333 -20 47.5 33.333333333 0 50 33.333333333 2 50 33.333333333 -4 50 33.333333333 6 50 33.333333333 8 50 33.333333333 -10 50 33.333333333 12 50 33.333333333 14 50 33.333333333 -16 50 33.333333333 18 50 33.333333333 20 50 33.333333333 -0 0 35 2 0 35 4 0 35 -6 0 35 8 0 35 10 0 35 -12 0 35 14 0 35 16 0 35 -18 0 35 20 0 35 0 2.5 35 -2 2.5 35 4 2.5 35 6 2.5 35 -8 2.5 35 10 2.5 35 12 2.5 35 -14 2.5 35 16 2.5 35 18 2.5 35 -20 2.5 35 0 5 35 2 5 35 -4 5 35 6 5 35 8 5 35 -10 5 35 12 5 35 14 5 35 -16 5 35 18 5 35 20 5 35 -0 7.5 35 2 7.5 35 4 7.5 35 -6 7.5 35 8 7.5 35 10 7.5 35 -12 7.5 35 14 7.5 35 16 7.5 35 -18 7.5 35 20 7.5 35 0 10 35 -2 10 35 4 10 35 6 10 35 -8 10 35 10 10 35 12 10 35 -14 10 35 16 10 35 18 10 35 -20 10 35 0 12.5 35 2 12.5 35 -4 12.5 35 6 12.5 35 8 12.5 35 -10 12.5 35 12 12.5 35 14 12.5 35 -16 12.5 35 18 12.5 35 20 12.5 35 -0 15 35 2 15 35 4 15 35 -6 15 35 8 15 35 10 15 35 -12 15 35 14 15 35 16 15 35 -18 15 35 20 15 35 0 17.5 35 -2 17.5 35 4 17.5 35 6 17.5 35 -8 17.5 35 10 17.5 35 12 17.5 35 -14 17.5 35 16 17.5 35 18 17.5 35 -20 17.5 35 0 20 35 2 20 35 -4 20 35 6 20 35 8 20 35 -10 20 35 12 20 35 14 20 35 -16 20 35 18 20 35 20 20 35 -0 22.5 35 2 22.5 35 4 22.5 35 -6 22.5 35 8 22.5 35 10 22.5 35 -12 22.5 35 14 22.5 35 16 22.5 35 -18 22.5 35 20 22.5 35 0 25 35 -2 25 35 4 25 35 6 25 35 -8 25 35 10 25 35 12 25 35 -14 25 35 16 25 35 18 25 35 -20 25 35 0 27.5 35 2 27.5 35 -4 27.5 35 6 27.5 35 8 27.5 35 -10 27.5 35 12 27.5 35 14 27.5 35 -16 27.5 35 18 27.5 35 20 27.5 35 -0 30 35 2 30 35 4 30 35 -6 30 35 8 30 35 10 30 35 -12 30 35 14 30 35 16 30 35 -18 30 35 20 30 35 0 32.5 35 -2 32.5 35 4 32.5 35 6 32.5 35 -8 32.5 35 10 32.5 35 12 32.5 35 -14 32.5 35 16 32.5 35 18 32.5 35 -20 32.5 35 0 35 35 2 35 35 -4 35 35 6 35 35 8 35 35 -10 35 35 12 35 35 14 35 35 -16 35 35 18 35 35 20 35 35 -0 37.5 35 2 37.5 35 4 37.5 35 -6 37.5 35 8 37.5 35 10 37.5 35 -12 37.5 35 14 37.5 35 16 37.5 35 -18 37.5 35 20 37.5 35 0 40 35 -2 40 35 4 40 35 6 40 35 -8 40 35 10 40 35 12 40 35 -14 40 35 16 40 35 18 40 35 -20 40 35 0 42.5 35 2 42.5 35 -4 42.5 35 6 42.5 35 8 42.5 35 -10 42.5 35 12 42.5 35 14 42.5 35 -16 42.5 35 18 42.5 35 20 42.5 35 -0 45 35 2 45 35 4 45 35 -6 45 35 8 45 35 10 45 35 -12 45 35 14 45 35 16 45 35 -18 45 35 20 45 35 0 47.5 35 -2 47.5 35 4 47.5 35 6 47.5 35 -8 47.5 35 10 47.5 35 12 47.5 35 -14 47.5 35 16 47.5 35 18 47.5 35 -20 47.5 35 0 50 35 2 50 35 -4 50 35 6 50 35 8 50 35 -10 50 35 12 50 35 14 50 35 -16 50 35 18 50 35 20 50 35 -0 0 36.666666667 2 0 36.666666667 4 0 36.666666667 -6 0 36.666666667 8 0 36.666666667 10 0 36.666666667 -12 0 36.666666667 14 0 36.666666667 16 0 36.666666667 -18 0 36.666666667 20 0 36.666666667 0 2.5 36.666666667 -2 2.5 36.666666667 4 2.5 36.666666667 6 2.5 36.666666667 -8 2.5 36.666666667 10 2.5 36.666666667 12 2.5 36.666666667 -14 2.5 36.666666667 16 2.5 36.666666667 18 2.5 36.666666667 -20 2.5 36.666666667 0 5 36.666666667 2 5 36.666666667 -4 5 36.666666667 6 5 36.666666667 8 5 36.666666667 -10 5 36.666666667 12 5 36.666666667 14 5 36.666666667 -16 5 36.666666667 18 5 36.666666667 20 5 36.666666667 -0 7.5 36.666666667 2 7.5 36.666666667 4 7.5 36.666666667 -6 7.5 36.666666667 8 7.5 36.666666667 10 7.5 36.666666667 -12 7.5 36.666666667 14 7.5 36.666666667 16 7.5 36.666666667 -18 7.5 36.666666667 20 7.5 36.666666667 0 10 36.666666667 -2 10 36.666666667 4 10 36.666666667 6 10 36.666666667 -8 10 36.666666667 10 10 36.666666667 12 10 36.666666667 -14 10 36.666666667 16 10 36.666666667 18 10 36.666666667 -20 10 36.666666667 0 12.5 36.666666667 2 12.5 36.666666667 -4 12.5 36.666666667 6 12.5 36.666666667 8 12.5 36.666666667 -10 12.5 36.666666667 12 12.5 36.666666667 14 12.5 36.666666667 -16 12.5 36.666666667 18 12.5 36.666666667 20 12.5 36.666666667 -0 15 36.666666667 2 15 36.666666667 4 15 36.666666667 -6 15 36.666666667 8 15 36.666666667 10 15 36.666666667 -12 15 36.666666667 14 15 36.666666667 16 15 36.666666667 -18 15 36.666666667 20 15 36.666666667 0 17.5 36.666666667 -2 17.5 36.666666667 4 17.5 36.666666667 6 17.5 36.666666667 -8 17.5 36.666666667 10 17.5 36.666666667 12 17.5 36.666666667 -14 17.5 36.666666667 16 17.5 36.666666667 18 17.5 36.666666667 -20 17.5 36.666666667 0 20 36.666666667 2 20 36.666666667 -4 20 36.666666667 6 20 36.666666667 8 20 36.666666667 -10 20 36.666666667 12 20 36.666666667 14 20 36.666666667 -16 20 36.666666667 18 20 36.666666667 20 20 36.666666667 -0 22.5 36.666666667 2 22.5 36.666666667 4 22.5 36.666666667 -6 22.5 36.666666667 8 22.5 36.666666667 10 22.5 36.666666667 -12 22.5 36.666666667 14 22.5 36.666666667 16 22.5 36.666666667 -18 22.5 36.666666667 20 22.5 36.666666667 0 25 36.666666667 -2 25 36.666666667 4 25 36.666666667 6 25 36.666666667 -8 25 36.666666667 10 25 36.666666667 12 25 36.666666667 -14 25 36.666666667 16 25 36.666666667 18 25 36.666666667 -20 25 36.666666667 0 27.5 36.666666667 2 27.5 36.666666667 -4 27.5 36.666666667 6 27.5 36.666666667 8 27.5 36.666666667 -10 27.5 36.666666667 12 27.5 36.666666667 14 27.5 36.666666667 -16 27.5 36.666666667 18 27.5 36.666666667 20 27.5 36.666666667 -0 30 36.666666667 2 30 36.666666667 4 30 36.666666667 -6 30 36.666666667 8 30 36.666666667 10 30 36.666666667 -12 30 36.666666667 14 30 36.666666667 16 30 36.666666667 -18 30 36.666666667 20 30 36.666666667 0 32.5 36.666666667 -2 32.5 36.666666667 4 32.5 36.666666667 6 32.5 36.666666667 -8 32.5 36.666666667 10 32.5 36.666666667 12 32.5 36.666666667 -14 32.5 36.666666667 16 32.5 36.666666667 18 32.5 36.666666667 -20 32.5 36.666666667 0 35 36.666666667 2 35 36.666666667 -4 35 36.666666667 6 35 36.666666667 8 35 36.666666667 -10 35 36.666666667 12 35 36.666666667 14 35 36.666666667 -16 35 36.666666667 18 35 36.666666667 20 35 36.666666667 -0 37.5 36.666666667 2 37.5 36.666666667 4 37.5 36.666666667 -6 37.5 36.666666667 8 37.5 36.666666667 10 37.5 36.666666667 -12 37.5 36.666666667 14 37.5 36.666666667 16 37.5 36.666666667 -18 37.5 36.666666667 20 37.5 36.666666667 0 40 36.666666667 -2 40 36.666666667 4 40 36.666666667 6 40 36.666666667 -8 40 36.666666667 10 40 36.666666667 12 40 36.666666667 -14 40 36.666666667 16 40 36.666666667 18 40 36.666666667 -20 40 36.666666667 0 42.5 36.666666667 2 42.5 36.666666667 -4 42.5 36.666666667 6 42.5 36.666666667 8 42.5 36.666666667 -10 42.5 36.666666667 12 42.5 36.666666667 14 42.5 36.666666667 -16 42.5 36.666666667 18 42.5 36.666666667 20 42.5 36.666666667 -0 45 36.666666667 2 45 36.666666667 4 45 36.666666667 -6 45 36.666666667 8 45 36.666666667 10 45 36.666666667 -12 45 36.666666667 14 45 36.666666667 16 45 36.666666667 -18 45 36.666666667 20 45 36.666666667 0 47.5 36.666666667 -2 47.5 36.666666667 4 47.5 36.666666667 6 47.5 36.666666667 -8 47.5 36.666666667 10 47.5 36.666666667 12 47.5 36.666666667 -14 47.5 36.666666667 16 47.5 36.666666667 18 47.5 36.666666667 -20 47.5 36.666666667 0 50 36.666666667 2 50 36.666666667 -4 50 36.666666667 6 50 36.666666667 8 50 36.666666667 -10 50 36.666666667 12 50 36.666666667 14 50 36.666666667 -16 50 36.666666667 18 50 36.666666667 20 50 36.666666667 -0 0 38.333333333 2 0 38.333333333 4 0 38.333333333 -6 0 38.333333333 8 0 38.333333333 10 0 38.333333333 -12 0 38.333333333 14 0 38.333333333 16 0 38.333333333 -18 0 38.333333333 20 0 38.333333333 0 2.5 38.333333333 -2 2.5 38.333333333 4 2.5 38.333333333 6 2.5 38.333333333 -8 2.5 38.333333333 10 2.5 38.333333333 12 2.5 38.333333333 -14 2.5 38.333333333 16 2.5 38.333333333 18 2.5 38.333333333 -20 2.5 38.333333333 0 5 38.333333333 2 5 38.333333333 -4 5 38.333333333 6 5 38.333333333 8 5 38.333333333 -10 5 38.333333333 12 5 38.333333333 14 5 38.333333333 -16 5 38.333333333 18 5 38.333333333 20 5 38.333333333 -0 7.5 38.333333333 2 7.5 38.333333333 4 7.5 38.333333333 -6 7.5 38.333333333 8 7.5 38.333333333 10 7.5 38.333333333 -12 7.5 38.333333333 14 7.5 38.333333333 16 7.5 38.333333333 -18 7.5 38.333333333 20 7.5 38.333333333 0 10 38.333333333 -2 10 38.333333333 4 10 38.333333333 6 10 38.333333333 -8 10 38.333333333 10 10 38.333333333 12 10 38.333333333 -14 10 38.333333333 16 10 38.333333333 18 10 38.333333333 -20 10 38.333333333 0 12.5 38.333333333 2 12.5 38.333333333 -4 12.5 38.333333333 6 12.5 38.333333333 8 12.5 38.333333333 -10 12.5 38.333333333 12 12.5 38.333333333 14 12.5 38.333333333 -16 12.5 38.333333333 18 12.5 38.333333333 20 12.5 38.333333333 -0 15 38.333333333 2 15 38.333333333 4 15 38.333333333 -6 15 38.333333333 8 15 38.333333333 10 15 38.333333333 -12 15 38.333333333 14 15 38.333333333 16 15 38.333333333 -18 15 38.333333333 20 15 38.333333333 0 17.5 38.333333333 -2 17.5 38.333333333 4 17.5 38.333333333 6 17.5 38.333333333 -8 17.5 38.333333333 10 17.5 38.333333333 12 17.5 38.333333333 -14 17.5 38.333333333 16 17.5 38.333333333 18 17.5 38.333333333 -20 17.5 38.333333333 0 20 38.333333333 2 20 38.333333333 -4 20 38.333333333 6 20 38.333333333 8 20 38.333333333 -10 20 38.333333333 12 20 38.333333333 14 20 38.333333333 -16 20 38.333333333 18 20 38.333333333 20 20 38.333333333 -0 22.5 38.333333333 2 22.5 38.333333333 4 22.5 38.333333333 -6 22.5 38.333333333 8 22.5 38.333333333 10 22.5 38.333333333 -12 22.5 38.333333333 14 22.5 38.333333333 16 22.5 38.333333333 -18 22.5 38.333333333 20 22.5 38.333333333 0 25 38.333333333 -2 25 38.333333333 4 25 38.333333333 6 25 38.333333333 -8 25 38.333333333 10 25 38.333333333 12 25 38.333333333 -14 25 38.333333333 16 25 38.333333333 18 25 38.333333333 -20 25 38.333333333 0 27.5 38.333333333 2 27.5 38.333333333 -4 27.5 38.333333333 6 27.5 38.333333333 8 27.5 38.333333333 -10 27.5 38.333333333 12 27.5 38.333333333 14 27.5 38.333333333 -16 27.5 38.333333333 18 27.5 38.333333333 20 27.5 38.333333333 -0 30 38.333333333 2 30 38.333333333 4 30 38.333333333 -6 30 38.333333333 8 30 38.333333333 10 30 38.333333333 -12 30 38.333333333 14 30 38.333333333 16 30 38.333333333 -18 30 38.333333333 20 30 38.333333333 0 32.5 38.333333333 -2 32.5 38.333333333 4 32.5 38.333333333 6 32.5 38.333333333 -8 32.5 38.333333333 10 32.5 38.333333333 12 32.5 38.333333333 -14 32.5 38.333333333 16 32.5 38.333333333 18 32.5 38.333333333 -20 32.5 38.333333333 0 35 38.333333333 2 35 38.333333333 -4 35 38.333333333 6 35 38.333333333 8 35 38.333333333 -10 35 38.333333333 12 35 38.333333333 14 35 38.333333333 -16 35 38.333333333 18 35 38.333333333 20 35 38.333333333 -0 37.5 38.333333333 2 37.5 38.333333333 4 37.5 38.333333333 -6 37.5 38.333333333 8 37.5 38.333333333 10 37.5 38.333333333 -12 37.5 38.333333333 14 37.5 38.333333333 16 37.5 38.333333333 -18 37.5 38.333333333 20 37.5 38.333333333 0 40 38.333333333 -2 40 38.333333333 4 40 38.333333333 6 40 38.333333333 -8 40 38.333333333 10 40 38.333333333 12 40 38.333333333 -14 40 38.333333333 16 40 38.333333333 18 40 38.333333333 -20 40 38.333333333 0 42.5 38.333333333 2 42.5 38.333333333 -4 42.5 38.333333333 6 42.5 38.333333333 8 42.5 38.333333333 -10 42.5 38.333333333 12 42.5 38.333333333 14 42.5 38.333333333 -16 42.5 38.333333333 18 42.5 38.333333333 20 42.5 38.333333333 -0 45 38.333333333 2 45 38.333333333 4 45 38.333333333 -6 45 38.333333333 8 45 38.333333333 10 45 38.333333333 -12 45 38.333333333 14 45 38.333333333 16 45 38.333333333 -18 45 38.333333333 20 45 38.333333333 0 47.5 38.333333333 -2 47.5 38.333333333 4 47.5 38.333333333 6 47.5 38.333333333 -8 47.5 38.333333333 10 47.5 38.333333333 12 47.5 38.333333333 -14 47.5 38.333333333 16 47.5 38.333333333 18 47.5 38.333333333 -20 47.5 38.333333333 0 50 38.333333333 2 50 38.333333333 -4 50 38.333333333 6 50 38.333333333 8 50 38.333333333 -10 50 38.333333333 12 50 38.333333333 14 50 38.333333333 -16 50 38.333333333 18 50 38.333333333 20 50 38.333333333 -0 0 40 2 0 40 4 0 40 -6 0 40 8 0 40 10 0 40 -12 0 40 14 0 40 16 0 40 -18 0 40 20 0 40 0 2.5 40 -2 2.5 40 4 2.5 40 6 2.5 40 -8 2.5 40 10 2.5 40 12 2.5 40 -14 2.5 40 16 2.5 40 18 2.5 40 -20 2.5 40 0 5 40 2 5 40 -4 5 40 6 5 40 8 5 40 -10 5 40 12 5 40 14 5 40 -16 5 40 18 5 40 20 5 40 -0 7.5 40 2 7.5 40 4 7.5 40 -6 7.5 40 8 7.5 40 10 7.5 40 -12 7.5 40 14 7.5 40 16 7.5 40 -18 7.5 40 20 7.5 40 0 10 40 -2 10 40 4 10 40 6 10 40 -8 10 40 10 10 40 12 10 40 -14 10 40 16 10 40 18 10 40 -20 10 40 0 12.5 40 2 12.5 40 -4 12.5 40 6 12.5 40 8 12.5 40 -10 12.5 40 12 12.5 40 14 12.5 40 -16 12.5 40 18 12.5 40 20 12.5 40 -0 15 40 2 15 40 4 15 40 -6 15 40 8 15 40 10 15 40 -12 15 40 14 15 40 16 15 40 -18 15 40 20 15 40 0 17.5 40 -2 17.5 40 4 17.5 40 6 17.5 40 -8 17.5 40 10 17.5 40 12 17.5 40 -14 17.5 40 16 17.5 40 18 17.5 40 -20 17.5 40 0 20 40 2 20 40 -4 20 40 6 20 40 8 20 40 -10 20 40 12 20 40 14 20 40 -16 20 40 18 20 40 20 20 40 -0 22.5 40 2 22.5 40 4 22.5 40 -6 22.5 40 8 22.5 40 10 22.5 40 -12 22.5 40 14 22.5 40 16 22.5 40 -18 22.5 40 20 22.5 40 0 25 40 -2 25 40 4 25 40 6 25 40 -8 25 40 10 25 40 12 25 40 -14 25 40 16 25 40 18 25 40 -20 25 40 0 27.5 40 2 27.5 40 -4 27.5 40 6 27.5 40 8 27.5 40 -10 27.5 40 12 27.5 40 14 27.5 40 -16 27.5 40 18 27.5 40 20 27.5 40 -0 30 40 2 30 40 4 30 40 -6 30 40 8 30 40 10 30 40 -12 30 40 14 30 40 16 30 40 -18 30 40 20 30 40 0 32.5 40 -2 32.5 40 4 32.5 40 6 32.5 40 -8 32.5 40 10 32.5 40 12 32.5 40 -14 32.5 40 16 32.5 40 18 32.5 40 -20 32.5 40 0 35 40 2 35 40 -4 35 40 6 35 40 8 35 40 -10 35 40 12 35 40 14 35 40 -16 35 40 18 35 40 20 35 40 -0 37.5 40 2 37.5 40 4 37.5 40 -6 37.5 40 8 37.5 40 10 37.5 40 -12 37.5 40 14 37.5 40 16 37.5 40 -18 37.5 40 20 37.5 40 0 40 40 -2 40 40 4 40 40 6 40 40 -8 40 40 10 40 40 12 40 40 -14 40 40 16 40 40 18 40 40 -20 40 40 0 42.5 40 2 42.5 40 -4 42.5 40 6 42.5 40 8 42.5 40 -10 42.5 40 12 42.5 40 14 42.5 40 -16 42.5 40 18 42.5 40 20 42.5 40 -0 45 40 2 45 40 4 45 40 -6 45 40 8 45 40 10 45 40 -12 45 40 14 45 40 16 45 40 -18 45 40 20 45 40 0 47.5 40 -2 47.5 40 4 47.5 40 6 47.5 40 -8 47.5 40 10 47.5 40 12 47.5 40 -14 47.5 40 16 47.5 40 18 47.5 40 -20 47.5 40 0 50 40 2 50 40 -4 50 40 6 50 40 8 50 40 -10 50 40 12 50 40 14 50 40 -16 50 40 18 50 40 20 50 40 -0 0 41.666666667 2 0 41.666666667 4 0 41.666666667 -6 0 41.666666667 8 0 41.666666667 10 0 41.666666667 -12 0 41.666666667 14 0 41.666666667 16 0 41.666666667 -18 0 41.666666667 20 0 41.666666667 0 2.5 41.666666667 -2 2.5 41.666666667 4 2.5 41.666666667 6 2.5 41.666666667 -8 2.5 41.666666667 10 2.5 41.666666667 12 2.5 41.666666667 -14 2.5 41.666666667 16 2.5 41.666666667 18 2.5 41.666666667 -20 2.5 41.666666667 0 5 41.666666667 2 5 41.666666667 -4 5 41.666666667 6 5 41.666666667 8 5 41.666666667 -10 5 41.666666667 12 5 41.666666667 14 5 41.666666667 -16 5 41.666666667 18 5 41.666666667 20 5 41.666666667 -0 7.5 41.666666667 2 7.5 41.666666667 4 7.5 41.666666667 -6 7.5 41.666666667 8 7.5 41.666666667 10 7.5 41.666666667 -12 7.5 41.666666667 14 7.5 41.666666667 16 7.5 41.666666667 -18 7.5 41.666666667 20 7.5 41.666666667 0 10 41.666666667 -2 10 41.666666667 4 10 41.666666667 6 10 41.666666667 -8 10 41.666666667 10 10 41.666666667 12 10 41.666666667 -14 10 41.666666667 16 10 41.666666667 18 10 41.666666667 -20 10 41.666666667 0 12.5 41.666666667 2 12.5 41.666666667 -4 12.5 41.666666667 6 12.5 41.666666667 8 12.5 41.666666667 -10 12.5 41.666666667 12 12.5 41.666666667 14 12.5 41.666666667 -16 12.5 41.666666667 18 12.5 41.666666667 20 12.5 41.666666667 -0 15 41.666666667 2 15 41.666666667 4 15 41.666666667 -6 15 41.666666667 8 15 41.666666667 10 15 41.666666667 -12 15 41.666666667 14 15 41.666666667 16 15 41.666666667 -18 15 41.666666667 20 15 41.666666667 0 17.5 41.666666667 -2 17.5 41.666666667 4 17.5 41.666666667 6 17.5 41.666666667 -8 17.5 41.666666667 10 17.5 41.666666667 12 17.5 41.666666667 -14 17.5 41.666666667 16 17.5 41.666666667 18 17.5 41.666666667 -20 17.5 41.666666667 0 20 41.666666667 2 20 41.666666667 -4 20 41.666666667 6 20 41.666666667 8 20 41.666666667 -10 20 41.666666667 12 20 41.666666667 14 20 41.666666667 -16 20 41.666666667 18 20 41.666666667 20 20 41.666666667 -0 22.5 41.666666667 2 22.5 41.666666667 4 22.5 41.666666667 -6 22.5 41.666666667 8 22.5 41.666666667 10 22.5 41.666666667 -12 22.5 41.666666667 14 22.5 41.666666667 16 22.5 41.666666667 -18 22.5 41.666666667 20 22.5 41.666666667 0 25 41.666666667 -2 25 41.666666667 4 25 41.666666667 6 25 41.666666667 -8 25 41.666666667 10 25 41.666666667 12 25 41.666666667 -14 25 41.666666667 16 25 41.666666667 18 25 41.666666667 -20 25 41.666666667 0 27.5 41.666666667 2 27.5 41.666666667 -4 27.5 41.666666667 6 27.5 41.666666667 8 27.5 41.666666667 -10 27.5 41.666666667 12 27.5 41.666666667 14 27.5 41.666666667 -16 27.5 41.666666667 18 27.5 41.666666667 20 27.5 41.666666667 -0 30 41.666666667 2 30 41.666666667 4 30 41.666666667 -6 30 41.666666667 8 30 41.666666667 10 30 41.666666667 -12 30 41.666666667 14 30 41.666666667 16 30 41.666666667 -18 30 41.666666667 20 30 41.666666667 0 32.5 41.666666667 -2 32.5 41.666666667 4 32.5 41.666666667 6 32.5 41.666666667 -8 32.5 41.666666667 10 32.5 41.666666667 12 32.5 41.666666667 -14 32.5 41.666666667 16 32.5 41.666666667 18 32.5 41.666666667 -20 32.5 41.666666667 0 35 41.666666667 2 35 41.666666667 -4 35 41.666666667 6 35 41.666666667 8 35 41.666666667 -10 35 41.666666667 12 35 41.666666667 14 35 41.666666667 -16 35 41.666666667 18 35 41.666666667 20 35 41.666666667 -0 37.5 41.666666667 2 37.5 41.666666667 4 37.5 41.666666667 -6 37.5 41.666666667 8 37.5 41.666666667 10 37.5 41.666666667 -12 37.5 41.666666667 14 37.5 41.666666667 16 37.5 41.666666667 -18 37.5 41.666666667 20 37.5 41.666666667 0 40 41.666666667 -2 40 41.666666667 4 40 41.666666667 6 40 41.666666667 -8 40 41.666666667 10 40 41.666666667 12 40 41.666666667 -14 40 41.666666667 16 40 41.666666667 18 40 41.666666667 -20 40 41.666666667 0 42.5 41.666666667 2 42.5 41.666666667 -4 42.5 41.666666667 6 42.5 41.666666667 8 42.5 41.666666667 -10 42.5 41.666666667 12 42.5 41.666666667 14 42.5 41.666666667 -16 42.5 41.666666667 18 42.5 41.666666667 20 42.5 41.666666667 -0 45 41.666666667 2 45 41.666666667 4 45 41.666666667 -6 45 41.666666667 8 45 41.666666667 10 45 41.666666667 -12 45 41.666666667 14 45 41.666666667 16 45 41.666666667 -18 45 41.666666667 20 45 41.666666667 0 47.5 41.666666667 -2 47.5 41.666666667 4 47.5 41.666666667 6 47.5 41.666666667 -8 47.5 41.666666667 10 47.5 41.666666667 12 47.5 41.666666667 -14 47.5 41.666666667 16 47.5 41.666666667 18 47.5 41.666666667 -20 47.5 41.666666667 0 50 41.666666667 2 50 41.666666667 -4 50 41.666666667 6 50 41.666666667 8 50 41.666666667 -10 50 41.666666667 12 50 41.666666667 14 50 41.666666667 -16 50 41.666666667 18 50 41.666666667 20 50 41.666666667 -0 0 43.333333333 2 0 43.333333333 4 0 43.333333333 -6 0 43.333333333 8 0 43.333333333 10 0 43.333333333 -12 0 43.333333333 14 0 43.333333333 16 0 43.333333333 -18 0 43.333333333 20 0 43.333333333 0 2.5 43.333333333 -2 2.5 43.333333333 4 2.5 43.333333333 6 2.5 43.333333333 -8 2.5 43.333333333 10 2.5 43.333333333 12 2.5 43.333333333 -14 2.5 43.333333333 16 2.5 43.333333333 18 2.5 43.333333333 -20 2.5 43.333333333 0 5 43.333333333 2 5 43.333333333 -4 5 43.333333333 6 5 43.333333333 8 5 43.333333333 -10 5 43.333333333 12 5 43.333333333 14 5 43.333333333 -16 5 43.333333333 18 5 43.333333333 20 5 43.333333333 -0 7.5 43.333333333 2 7.5 43.333333333 4 7.5 43.333333333 -6 7.5 43.333333333 8 7.5 43.333333333 10 7.5 43.333333333 -12 7.5 43.333333333 14 7.5 43.333333333 16 7.5 43.333333333 -18 7.5 43.333333333 20 7.5 43.333333333 0 10 43.333333333 -2 10 43.333333333 4 10 43.333333333 6 10 43.333333333 -8 10 43.333333333 10 10 43.333333333 12 10 43.333333333 -14 10 43.333333333 16 10 43.333333333 18 10 43.333333333 -20 10 43.333333333 0 12.5 43.333333333 2 12.5 43.333333333 -4 12.5 43.333333333 6 12.5 43.333333333 8 12.5 43.333333333 -10 12.5 43.333333333 12 12.5 43.333333333 14 12.5 43.333333333 -16 12.5 43.333333333 18 12.5 43.333333333 20 12.5 43.333333333 -0 15 43.333333333 2 15 43.333333333 4 15 43.333333333 -6 15 43.333333333 8 15 43.333333333 10 15 43.333333333 -12 15 43.333333333 14 15 43.333333333 16 15 43.333333333 -18 15 43.333333333 20 15 43.333333333 0 17.5 43.333333333 -2 17.5 43.333333333 4 17.5 43.333333333 6 17.5 43.333333333 -8 17.5 43.333333333 10 17.5 43.333333333 12 17.5 43.333333333 -14 17.5 43.333333333 16 17.5 43.333333333 18 17.5 43.333333333 -20 17.5 43.333333333 0 20 43.333333333 2 20 43.333333333 -4 20 43.333333333 6 20 43.333333333 8 20 43.333333333 -10 20 43.333333333 12 20 43.333333333 14 20 43.333333333 -16 20 43.333333333 18 20 43.333333333 20 20 43.333333333 -0 22.5 43.333333333 2 22.5 43.333333333 4 22.5 43.333333333 -6 22.5 43.333333333 8 22.5 43.333333333 10 22.5 43.333333333 -12 22.5 43.333333333 14 22.5 43.333333333 16 22.5 43.333333333 -18 22.5 43.333333333 20 22.5 43.333333333 0 25 43.333333333 -2 25 43.333333333 4 25 43.333333333 6 25 43.333333333 -8 25 43.333333333 10 25 43.333333333 12 25 43.333333333 -14 25 43.333333333 16 25 43.333333333 18 25 43.333333333 -20 25 43.333333333 0 27.5 43.333333333 2 27.5 43.333333333 -4 27.5 43.333333333 6 27.5 43.333333333 8 27.5 43.333333333 -10 27.5 43.333333333 12 27.5 43.333333333 14 27.5 43.333333333 -16 27.5 43.333333333 18 27.5 43.333333333 20 27.5 43.333333333 -0 30 43.333333333 2 30 43.333333333 4 30 43.333333333 -6 30 43.333333333 8 30 43.333333333 10 30 43.333333333 -12 30 43.333333333 14 30 43.333333333 16 30 43.333333333 -18 30 43.333333333 20 30 43.333333333 0 32.5 43.333333333 -2 32.5 43.333333333 4 32.5 43.333333333 6 32.5 43.333333333 -8 32.5 43.333333333 10 32.5 43.333333333 12 32.5 43.333333333 -14 32.5 43.333333333 16 32.5 43.333333333 18 32.5 43.333333333 -20 32.5 43.333333333 0 35 43.333333333 2 35 43.333333333 -4 35 43.333333333 6 35 43.333333333 8 35 43.333333333 -10 35 43.333333333 12 35 43.333333333 14 35 43.333333333 -16 35 43.333333333 18 35 43.333333333 20 35 43.333333333 -0 37.5 43.333333333 2 37.5 43.333333333 4 37.5 43.333333333 -6 37.5 43.333333333 8 37.5 43.333333333 10 37.5 43.333333333 -12 37.5 43.333333333 14 37.5 43.333333333 16 37.5 43.333333333 -18 37.5 43.333333333 20 37.5 43.333333333 0 40 43.333333333 -2 40 43.333333333 4 40 43.333333333 6 40 43.333333333 -8 40 43.333333333 10 40 43.333333333 12 40 43.333333333 -14 40 43.333333333 16 40 43.333333333 18 40 43.333333333 -20 40 43.333333333 0 42.5 43.333333333 2 42.5 43.333333333 -4 42.5 43.333333333 6 42.5 43.333333333 8 42.5 43.333333333 -10 42.5 43.333333333 12 42.5 43.333333333 14 42.5 43.333333333 -16 42.5 43.333333333 18 42.5 43.333333333 20 42.5 43.333333333 -0 45 43.333333333 2 45 43.333333333 4 45 43.333333333 -6 45 43.333333333 8 45 43.333333333 10 45 43.333333333 -12 45 43.333333333 14 45 43.333333333 16 45 43.333333333 -18 45 43.333333333 20 45 43.333333333 0 47.5 43.333333333 -2 47.5 43.333333333 4 47.5 43.333333333 6 47.5 43.333333333 -8 47.5 43.333333333 10 47.5 43.333333333 12 47.5 43.333333333 -14 47.5 43.333333333 16 47.5 43.333333333 18 47.5 43.333333333 -20 47.5 43.333333333 0 50 43.333333333 2 50 43.333333333 -4 50 43.333333333 6 50 43.333333333 8 50 43.333333333 -10 50 43.333333333 12 50 43.333333333 14 50 43.333333333 -16 50 43.333333333 18 50 43.333333333 20 50 43.333333333 -0 0 45 2 0 45 4 0 45 -6 0 45 8 0 45 10 0 45 -12 0 45 14 0 45 16 0 45 -18 0 45 20 0 45 0 2.5 45 -2 2.5 45 4 2.5 45 6 2.5 45 -8 2.5 45 10 2.5 45 12 2.5 45 -14 2.5 45 16 2.5 45 18 2.5 45 -20 2.5 45 0 5 45 2 5 45 -4 5 45 6 5 45 8 5 45 -10 5 45 12 5 45 14 5 45 -16 5 45 18 5 45 20 5 45 -0 7.5 45 2 7.5 45 4 7.5 45 -6 7.5 45 8 7.5 45 10 7.5 45 -12 7.5 45 14 7.5 45 16 7.5 45 -18 7.5 45 20 7.5 45 0 10 45 -2 10 45 4 10 45 6 10 45 -8 10 45 10 10 45 12 10 45 -14 10 45 16 10 45 18 10 45 -20 10 45 0 12.5 45 2 12.5 45 -4 12.5 45 6 12.5 45 8 12.5 45 -10 12.5 45 12 12.5 45 14 12.5 45 -16 12.5 45 18 12.5 45 20 12.5 45 -0 15 45 2 15 45 4 15 45 -6 15 45 8 15 45 10 15 45 -12 15 45 14 15 45 16 15 45 -18 15 45 20 15 45 0 17.5 45 -2 17.5 45 4 17.5 45 6 17.5 45 -8 17.5 45 10 17.5 45 12 17.5 45 -14 17.5 45 16 17.5 45 18 17.5 45 -20 17.5 45 0 20 45 2 20 45 -4 20 45 6 20 45 8 20 45 -10 20 45 12 20 45 14 20 45 -16 20 45 18 20 45 20 20 45 -0 22.5 45 2 22.5 45 4 22.5 45 -6 22.5 45 8 22.5 45 10 22.5 45 -12 22.5 45 14 22.5 45 16 22.5 45 -18 22.5 45 20 22.5 45 0 25 45 -2 25 45 4 25 45 6 25 45 -8 25 45 10 25 45 12 25 45 -14 25 45 16 25 45 18 25 45 -20 25 45 0 27.5 45 2 27.5 45 -4 27.5 45 6 27.5 45 8 27.5 45 -10 27.5 45 12 27.5 45 14 27.5 45 -16 27.5 45 18 27.5 45 20 27.5 45 -0 30 45 2 30 45 4 30 45 -6 30 45 8 30 45 10 30 45 -12 30 45 14 30 45 16 30 45 -18 30 45 20 30 45 0 32.5 45 -2 32.5 45 4 32.5 45 6 32.5 45 -8 32.5 45 10 32.5 45 12 32.5 45 -14 32.5 45 16 32.5 45 18 32.5 45 -20 32.5 45 0 35 45 2 35 45 -4 35 45 6 35 45 8 35 45 -10 35 45 12 35 45 14 35 45 -16 35 45 18 35 45 20 35 45 -0 37.5 45 2 37.5 45 4 37.5 45 -6 37.5 45 8 37.5 45 10 37.5 45 -12 37.5 45 14 37.5 45 16 37.5 45 -18 37.5 45 20 37.5 45 0 40 45 -2 40 45 4 40 45 6 40 45 -8 40 45 10 40 45 12 40 45 -14 40 45 16 40 45 18 40 45 -20 40 45 0 42.5 45 2 42.5 45 -4 42.5 45 6 42.5 45 8 42.5 45 -10 42.5 45 12 42.5 45 14 42.5 45 -16 42.5 45 18 42.5 45 20 42.5 45 -0 45 45 2 45 45 4 45 45 -6 45 45 8 45 45 10 45 45 -12 45 45 14 45 45 16 45 45 -18 45 45 20 45 45 0 47.5 45 -2 47.5 45 4 47.5 45 6 47.5 45 -8 47.5 45 10 47.5 45 12 47.5 45 -14 47.5 45 16 47.5 45 18 47.5 45 -20 47.5 45 0 50 45 2 50 45 -4 50 45 6 50 45 8 50 45 -10 50 45 12 50 45 14 50 45 -16 50 45 18 50 45 20 50 45 -0 0 46.666666667 2 0 46.666666667 4 0 46.666666667 -6 0 46.666666667 8 0 46.666666667 10 0 46.666666667 -12 0 46.666666667 14 0 46.666666667 16 0 46.666666667 -18 0 46.666666667 20 0 46.666666667 0 2.5 46.666666667 -2 2.5 46.666666667 4 2.5 46.666666667 6 2.5 46.666666667 -8 2.5 46.666666667 10 2.5 46.666666667 12 2.5 46.666666667 -14 2.5 46.666666667 16 2.5 46.666666667 18 2.5 46.666666667 -20 2.5 46.666666667 0 5 46.666666667 2 5 46.666666667 -4 5 46.666666667 6 5 46.666666667 8 5 46.666666667 -10 5 46.666666667 12 5 46.666666667 14 5 46.666666667 -16 5 46.666666667 18 5 46.666666667 20 5 46.666666667 -0 7.5 46.666666667 2 7.5 46.666666667 4 7.5 46.666666667 -6 7.5 46.666666667 8 7.5 46.666666667 10 7.5 46.666666667 -12 7.5 46.666666667 14 7.5 46.666666667 16 7.5 46.666666667 -18 7.5 46.666666667 20 7.5 46.666666667 0 10 46.666666667 -2 10 46.666666667 4 10 46.666666667 6 10 46.666666667 -8 10 46.666666667 10 10 46.666666667 12 10 46.666666667 -14 10 46.666666667 16 10 46.666666667 18 10 46.666666667 -20 10 46.666666667 0 12.5 46.666666667 2 12.5 46.666666667 -4 12.5 46.666666667 6 12.5 46.666666667 8 12.5 46.666666667 -10 12.5 46.666666667 12 12.5 46.666666667 14 12.5 46.666666667 -16 12.5 46.666666667 18 12.5 46.666666667 20 12.5 46.666666667 -0 15 46.666666667 2 15 46.666666667 4 15 46.666666667 -6 15 46.666666667 8 15 46.666666667 10 15 46.666666667 -12 15 46.666666667 14 15 46.666666667 16 15 46.666666667 -18 15 46.666666667 20 15 46.666666667 0 17.5 46.666666667 -2 17.5 46.666666667 4 17.5 46.666666667 6 17.5 46.666666667 -8 17.5 46.666666667 10 17.5 46.666666667 12 17.5 46.666666667 -14 17.5 46.666666667 16 17.5 46.666666667 18 17.5 46.666666667 -20 17.5 46.666666667 0 20 46.666666667 2 20 46.666666667 -4 20 46.666666667 6 20 46.666666667 8 20 46.666666667 -10 20 46.666666667 12 20 46.666666667 14 20 46.666666667 -16 20 46.666666667 18 20 46.666666667 20 20 46.666666667 -0 22.5 46.666666667 2 22.5 46.666666667 4 22.5 46.666666667 -6 22.5 46.666666667 8 22.5 46.666666667 10 22.5 46.666666667 -12 22.5 46.666666667 14 22.5 46.666666667 16 22.5 46.666666667 -18 22.5 46.666666667 20 22.5 46.666666667 0 25 46.666666667 -2 25 46.666666667 4 25 46.666666667 6 25 46.666666667 -8 25 46.666666667 10 25 46.666666667 12 25 46.666666667 -14 25 46.666666667 16 25 46.666666667 18 25 46.666666667 -20 25 46.666666667 0 27.5 46.666666667 2 27.5 46.666666667 -4 27.5 46.666666667 6 27.5 46.666666667 8 27.5 46.666666667 -10 27.5 46.666666667 12 27.5 46.666666667 14 27.5 46.666666667 -16 27.5 46.666666667 18 27.5 46.666666667 20 27.5 46.666666667 -0 30 46.666666667 2 30 46.666666667 4 30 46.666666667 -6 30 46.666666667 8 30 46.666666667 10 30 46.666666667 -12 30 46.666666667 14 30 46.666666667 16 30 46.666666667 -18 30 46.666666667 20 30 46.666666667 0 32.5 46.666666667 -2 32.5 46.666666667 4 32.5 46.666666667 6 32.5 46.666666667 -8 32.5 46.666666667 10 32.5 46.666666667 12 32.5 46.666666667 -14 32.5 46.666666667 16 32.5 46.666666667 18 32.5 46.666666667 -20 32.5 46.666666667 0 35 46.666666667 2 35 46.666666667 -4 35 46.666666667 6 35 46.666666667 8 35 46.666666667 -10 35 46.666666667 12 35 46.666666667 14 35 46.666666667 -16 35 46.666666667 18 35 46.666666667 20 35 46.666666667 -0 37.5 46.666666667 2 37.5 46.666666667 4 37.5 46.666666667 -6 37.5 46.666666667 8 37.5 46.666666667 10 37.5 46.666666667 -12 37.5 46.666666667 14 37.5 46.666666667 16 37.5 46.666666667 -18 37.5 46.666666667 20 37.5 46.666666667 0 40 46.666666667 -2 40 46.666666667 4 40 46.666666667 6 40 46.666666667 -8 40 46.666666667 10 40 46.666666667 12 40 46.666666667 -14 40 46.666666667 16 40 46.666666667 18 40 46.666666667 -20 40 46.666666667 0 42.5 46.666666667 2 42.5 46.666666667 -4 42.5 46.666666667 6 42.5 46.666666667 8 42.5 46.666666667 -10 42.5 46.666666667 12 42.5 46.666666667 14 42.5 46.666666667 -16 42.5 46.666666667 18 42.5 46.666666667 20 42.5 46.666666667 -0 45 46.666666667 2 45 46.666666667 4 45 46.666666667 -6 45 46.666666667 8 45 46.666666667 10 45 46.666666667 -12 45 46.666666667 14 45 46.666666667 16 45 46.666666667 -18 45 46.666666667 20 45 46.666666667 0 47.5 46.666666667 -2 47.5 46.666666667 4 47.5 46.666666667 6 47.5 46.666666667 -8 47.5 46.666666667 10 47.5 46.666666667 12 47.5 46.666666667 -14 47.5 46.666666667 16 47.5 46.666666667 18 47.5 46.666666667 -20 47.5 46.666666667 0 50 46.666666667 2 50 46.666666667 -4 50 46.666666667 6 50 46.666666667 8 50 46.666666667 -10 50 46.666666667 12 50 46.666666667 14 50 46.666666667 -16 50 46.666666667 18 50 46.666666667 20 50 46.666666667 -0 0 48.333333333 2 0 48.333333333 4 0 48.333333333 -6 0 48.333333333 8 0 48.333333333 10 0 48.333333333 -12 0 48.333333333 14 0 48.333333333 16 0 48.333333333 -18 0 48.333333333 20 0 48.333333333 0 2.5 48.333333333 -2 2.5 48.333333333 4 2.5 48.333333333 6 2.5 48.333333333 -8 2.5 48.333333333 10 2.5 48.333333333 12 2.5 48.333333333 -14 2.5 48.333333333 16 2.5 48.333333333 18 2.5 48.333333333 -20 2.5 48.333333333 0 5 48.333333333 2 5 48.333333333 -4 5 48.333333333 6 5 48.333333333 8 5 48.333333333 -10 5 48.333333333 12 5 48.333333333 14 5 48.333333333 -16 5 48.333333333 18 5 48.333333333 20 5 48.333333333 -0 7.5 48.333333333 2 7.5 48.333333333 4 7.5 48.333333333 -6 7.5 48.333333333 8 7.5 48.333333333 10 7.5 48.333333333 -12 7.5 48.333333333 14 7.5 48.333333333 16 7.5 48.333333333 -18 7.5 48.333333333 20 7.5 48.333333333 0 10 48.333333333 -2 10 48.333333333 4 10 48.333333333 6 10 48.333333333 -8 10 48.333333333 10 10 48.333333333 12 10 48.333333333 -14 10 48.333333333 16 10 48.333333333 18 10 48.333333333 -20 10 48.333333333 0 12.5 48.333333333 2 12.5 48.333333333 -4 12.5 48.333333333 6 12.5 48.333333333 8 12.5 48.333333333 -10 12.5 48.333333333 12 12.5 48.333333333 14 12.5 48.333333333 -16 12.5 48.333333333 18 12.5 48.333333333 20 12.5 48.333333333 -0 15 48.333333333 2 15 48.333333333 4 15 48.333333333 -6 15 48.333333333 8 15 48.333333333 10 15 48.333333333 -12 15 48.333333333 14 15 48.333333333 16 15 48.333333333 -18 15 48.333333333 20 15 48.333333333 0 17.5 48.333333333 -2 17.5 48.333333333 4 17.5 48.333333333 6 17.5 48.333333333 -8 17.5 48.333333333 10 17.5 48.333333333 12 17.5 48.333333333 -14 17.5 48.333333333 16 17.5 48.333333333 18 17.5 48.333333333 -20 17.5 48.333333333 0 20 48.333333333 2 20 48.333333333 -4 20 48.333333333 6 20 48.333333333 8 20 48.333333333 -10 20 48.333333333 12 20 48.333333333 14 20 48.333333333 -16 20 48.333333333 18 20 48.333333333 20 20 48.333333333 -0 22.5 48.333333333 2 22.5 48.333333333 4 22.5 48.333333333 -6 22.5 48.333333333 8 22.5 48.333333333 10 22.5 48.333333333 -12 22.5 48.333333333 14 22.5 48.333333333 16 22.5 48.333333333 -18 22.5 48.333333333 20 22.5 48.333333333 0 25 48.333333333 -2 25 48.333333333 4 25 48.333333333 6 25 48.333333333 -8 25 48.333333333 10 25 48.333333333 12 25 48.333333333 -14 25 48.333333333 16 25 48.333333333 18 25 48.333333333 -20 25 48.333333333 0 27.5 48.333333333 2 27.5 48.333333333 -4 27.5 48.333333333 6 27.5 48.333333333 8 27.5 48.333333333 -10 27.5 48.333333333 12 27.5 48.333333333 14 27.5 48.333333333 -16 27.5 48.333333333 18 27.5 48.333333333 20 27.5 48.333333333 -0 30 48.333333333 2 30 48.333333333 4 30 48.333333333 -6 30 48.333333333 8 30 48.333333333 10 30 48.333333333 -12 30 48.333333333 14 30 48.333333333 16 30 48.333333333 -18 30 48.333333333 20 30 48.333333333 0 32.5 48.333333333 -2 32.5 48.333333333 4 32.5 48.333333333 6 32.5 48.333333333 -8 32.5 48.333333333 10 32.5 48.333333333 12 32.5 48.333333333 -14 32.5 48.333333333 16 32.5 48.333333333 18 32.5 48.333333333 -20 32.5 48.333333333 0 35 48.333333333 2 35 48.333333333 -4 35 48.333333333 6 35 48.333333333 8 35 48.333333333 -10 35 48.333333333 12 35 48.333333333 14 35 48.333333333 -16 35 48.333333333 18 35 48.333333333 20 35 48.333333333 -0 37.5 48.333333333 2 37.5 48.333333333 4 37.5 48.333333333 -6 37.5 48.333333333 8 37.5 48.333333333 10 37.5 48.333333333 -12 37.5 48.333333333 14 37.5 48.333333333 16 37.5 48.333333333 -18 37.5 48.333333333 20 37.5 48.333333333 0 40 48.333333333 -2 40 48.333333333 4 40 48.333333333 6 40 48.333333333 -8 40 48.333333333 10 40 48.333333333 12 40 48.333333333 -14 40 48.333333333 16 40 48.333333333 18 40 48.333333333 -20 40 48.333333333 0 42.5 48.333333333 2 42.5 48.333333333 -4 42.5 48.333333333 6 42.5 48.333333333 8 42.5 48.333333333 -10 42.5 48.333333333 12 42.5 48.333333333 14 42.5 48.333333333 -16 42.5 48.333333333 18 42.5 48.333333333 20 42.5 48.333333333 -0 45 48.333333333 2 45 48.333333333 4 45 48.333333333 -6 45 48.333333333 8 45 48.333333333 10 45 48.333333333 -12 45 48.333333333 14 45 48.333333333 16 45 48.333333333 -18 45 48.333333333 20 45 48.333333333 0 47.5 48.333333333 -2 47.5 48.333333333 4 47.5 48.333333333 6 47.5 48.333333333 -8 47.5 48.333333333 10 47.5 48.333333333 12 47.5 48.333333333 -14 47.5 48.333333333 16 47.5 48.333333333 18 47.5 48.333333333 -20 47.5 48.333333333 0 50 48.333333333 2 50 48.333333333 -4 50 48.333333333 6 50 48.333333333 8 50 48.333333333 -10 50 48.333333333 12 50 48.333333333 14 50 48.333333333 -16 50 48.333333333 18 50 48.333333333 20 50 48.333333333 -0 0 50 2 0 50 4 0 50 -6 0 50 8 0 50 10 0 50 -12 0 50 14 0 50 16 0 50 -18 0 50 20 0 50 0 2.5 50 -2 2.5 50 4 2.5 50 6 2.5 50 -8 2.5 50 10 2.5 50 12 2.5 50 -14 2.5 50 16 2.5 50 18 2.5 50 -20 2.5 50 0 5 50 2 5 50 -4 5 50 6 5 50 8 5 50 -10 5 50 12 5 50 14 5 50 -16 5 50 18 5 50 20 5 50 -0 7.5 50 2 7.5 50 4 7.5 50 -6 7.5 50 8 7.5 50 10 7.5 50 -12 7.5 50 14 7.5 50 16 7.5 50 -18 7.5 50 20 7.5 50 0 10 50 -2 10 50 4 10 50 6 10 50 -8 10 50 10 10 50 12 10 50 -14 10 50 16 10 50 18 10 50 -20 10 50 0 12.5 50 2 12.5 50 -4 12.5 50 6 12.5 50 8 12.5 50 -10 12.5 50 12 12.5 50 14 12.5 50 -16 12.5 50 18 12.5 50 20 12.5 50 -0 15 50 2 15 50 4 15 50 -6 15 50 8 15 50 10 15 50 -12 15 50 14 15 50 16 15 50 -18 15 50 20 15 50 0 17.5 50 -2 17.5 50 4 17.5 50 6 17.5 50 -8 17.5 50 10 17.5 50 12 17.5 50 -14 17.5 50 16 17.5 50 18 17.5 50 -20 17.5 50 0 20 50 2 20 50 -4 20 50 6 20 50 8 20 50 -10 20 50 12 20 50 14 20 50 -16 20 50 18 20 50 20 20 50 -0 22.5 50 2 22.5 50 4 22.5 50 -6 22.5 50 8 22.5 50 10 22.5 50 -12 22.5 50 14 22.5 50 16 22.5 50 -18 22.5 50 20 22.5 50 0 25 50 -2 25 50 4 25 50 6 25 50 -8 25 50 10 25 50 12 25 50 -14 25 50 16 25 50 18 25 50 -20 25 50 0 27.5 50 2 27.5 50 -4 27.5 50 6 27.5 50 8 27.5 50 -10 27.5 50 12 27.5 50 14 27.5 50 -16 27.5 50 18 27.5 50 20 27.5 50 -0 30 50 2 30 50 4 30 50 -6 30 50 8 30 50 10 30 50 -12 30 50 14 30 50 16 30 50 -18 30 50 20 30 50 0 32.5 50 -2 32.5 50 4 32.5 50 6 32.5 50 -8 32.5 50 10 32.5 50 12 32.5 50 -14 32.5 50 16 32.5 50 18 32.5 50 -20 32.5 50 0 35 50 2 35 50 -4 35 50 6 35 50 8 35 50 -10 35 50 12 35 50 14 35 50 -16 35 50 18 35 50 20 35 50 -0 37.5 50 2 37.5 50 4 37.5 50 -6 37.5 50 8 37.5 50 10 37.5 50 -12 37.5 50 14 37.5 50 16 37.5 50 -18 37.5 50 20 37.5 50 0 40 50 -2 40 50 4 40 50 6 40 50 -8 40 50 10 40 50 12 40 50 -14 40 50 16 40 50 18 40 50 -20 40 50 0 42.5 50 2 42.5 50 -4 42.5 50 6 42.5 50 8 42.5 50 -10 42.5 50 12 42.5 50 14 42.5 50 -16 42.5 50 18 42.5 50 20 42.5 50 -0 45 50 2 45 50 4 45 50 -6 45 50 8 45 50 10 45 50 -12 45 50 14 45 50 16 45 50 -18 45 50 20 45 50 0 47.5 50 -2 47.5 50 4 47.5 50 6 47.5 50 -8 47.5 50 10 47.5 50 12 47.5 50 -14 47.5 50 16 47.5 50 18 47.5 50 -20 47.5 50 0 50 50 2 50 50 -4 50 50 6 50 50 8 50 50 -10 50 50 12 50 50 14 50 50 -16 50 50 18 50 50 20 50 50 - diff --git a/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk deleted file mode 100644 index 2308432ee..000000000 --- a/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk +++ /dev/null @@ -1,210 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET UNSTRUCTURED_GRID -POINTS 175 double -5.4951556605 7.8305813044 -10 5.4951556605 12.169418696 -10 6.0986903619 8.1212282982 -7.5 -6.0986903619 11.878771702 -7.5 7.7475778302 8.9152906522 -10 7.7475778302 8.9152906522 -5.6698729811 -7.7475778302 11.084709348 -10 7.7475778302 11.084709348 -5.6698729811 8.0493451809 9.0606141491 -8.75 -8.0493451809 10.939385851 -8.75 8.8737889151 9.4576453261 -7.8349364905 8.8737889151 10.542354674 -7.8349364905 -8.8873953302 5.1253604391 -10 8.8873953302 14.874639561 -10 9.0364560916 5.778438306 -7.5 -9.0364560916 14.221561694 -7.5 9.4436976651 7.5626802195 -10 9.4436976651 7.5626802195 -5.6698729811 -9.4436976651 12.43731978 -10 9.4436976651 12.43731978 -5.6698729811 9.5182280458 7.889219153 -8.75 -9.5182280458 12.110780847 -8.75 9.7218488326 8.7813401098 -7.8349364905 9.7218488326 11.21865989 -7.8349364905 -10 10 -10 10 10 -7.5 10 10 -5 -10.779362252 9.0227106469 -7.8349364905 10.779362252 10.977289353 -7.8349364905 11.25 10 -7.8349364905 -11.349895019 8.3072851868 -8.75 11.349895019 11.692714813 -8.75 11.558724505 8.0454212938 -10 -11.558724505 8.0454212938 -5.6698729811 11.558724505 11.954578706 -10 11.558724505 11.954578706 -5.6698729811 -12.165063509 10 -8.75 12.5 10 -10 12.5 10 -5.6698729811 -12.699790037 6.6145703735 -7.5 12.699790037 13.385429626 -7.5 13.117449009 6.0908425877 -10 -13.117449009 13.909157412 -10 14.330127019 10 -7.5 14.330127019 10 -7.5 -15 10 -10 15 10 -10 10 10 -8.75 -10 10 -6.25 10.625 10 -8.9174682453 11.875 10 -6.7524047358 -11.082531755 10 -9.375 13.247595264 10 -8.125 11.25 10 -10 -13.75 10 -10 10.389681126 10.488644677 -8.9174682453 11.169043378 11.46593403 -6.7524047358 -10.674947509 10.846357407 -9.375 12.024842528 12.53907222 -8.125 10.779362252 10.977289353 -10 -12.338086757 12.931868059 -10 9.8609244163 10.609329945 -8.9174682453 9.5827732488 11.827989835 -6.7524047358 -9.7591140229 11.055390424 -9.375 9.2773420687 13.166171271 -8.125 9.7218488326 11.21865989 -10 -9.1655464977 13.655979671 -10 9.4368944576 10.271177337 -8.9174682453 8.3106833727 10.813532011 -6.7524047358 -9.0246725905 10.469692925 -9.375 7.0740177714 11.409078776 -8.125 8.8737889151 10.542354674 -10 -6.6213667454 11.627064022 -10 9.4368944576 9.7288226631 -8.9174682453 8.3106833727 9.1864679892 -6.7524047358 -9.0246725905 9.5303070745 -9.375 7.0740177714 8.5909212236 -8.125 8.8737889151 9.4576453261 -10 -6.6213667454 8.3729359783 -10 9.8609244163 9.3906700549 -8.9174682453 9.5827732488 8.1720101647 -6.7524047358 -9.7591140229 8.9446095765 -9.375 9.2773420687 6.8338287295 -8.125 9.7218488326 8.7813401098 -10 -9.1655464977 6.3440203293 -10 10.389681126 9.5113553235 -8.9174682453 11.169043378 8.5340659704 -6.7524047358 -10.674947509 9.1536425934 -9.375 12.024842528 7.4609277801 -8.125 10.779362252 9.0227106469 -10 -12.338086757 7.0681319407 -10 10.647047613 10 -7.5851854343 11.294095226 10 -5.1703708686 -11.767766953 10 -8.232233047 13.535533906 10 -6.4644660941 12.414814566 10 -9.3529523872 -14.829629131 10 -8.7059047745 10.403427588 10.505882194 -7.5851854343 10.806855176 11.011764389 -5.1703708686 -11.102184667 11.382095857 -8.232233047 12.204369334 12.764191715 -6.4644660941 11.505612255 11.887978052 -9.3529523872 -13.01122451 13.775956104 -8.7059047745 9.8560183609 10.630824778 -7.5851854343 9.7120367218 11.261649556 -5.1703708686 -9.6066348466 11.723445345 -8.232233047 9.2132696932 13.446890689 -6.4644660941 9.4626532075 12.354270123 -9.3529523872 -8.925306415 14.708540246 -8.7059047745 9.4170302449 10.280743438 -7.5851854343 8.8340604897 10.561486875 -5.1703708686 -8.4072970097 10.767005335 -8.232233047 6.8145940193 11.534010671 -6.4644660941 7.8243272545 11.047748773 -9.3529523872 -5.6486545091 12.095497546 -8.7059047745 9.4170302449 9.7192565624 -7.5851854343 8.8340604897 9.4385131248 -5.1703708686 -8.4072970097 9.2329946646 -8.232233047 6.8145940193 8.4659893291 -6.4644660941 7.8243272545 8.9522512269 -9.3529523872 -5.6486545091 7.9045024539 -8.7059047745 9.8560183609 9.3691752218 -7.5851854343 9.7120367218 8.7383504436 -5.1703708686 -9.6066348466 8.2765546553 -8.232233047 9.2132696932 6.5531093106 -6.4644660941 9.4626532075 7.6457298771 -9.3529523872 -8.925306415 5.2914597543 -8.7059047745 10.403427588 9.4941178057 -7.5851854343 10.806855176 8.9882356114 -5.1703708686 -11.102184667 8.6179041425 -8.232233047 12.204369334 7.235808285 -6.4644660941 11.505612255 8.1120219482 -9.3529523872 -13.01122451 6.2240438964 -8.7059047745 11.126211085 10.542354674 -7.8349364905 12.25242217 11.084709348 -5.6698729811 -11.950654819 10.939385851 -8.75 13.901309638 11.878771702 -7.5 12.25242217 11.084709348 -10 -14.50484434 12.169418696 -10 10.278151167 11.21865989 -7.8349364905 10.556302335 12.43731978 -5.6698729811 -10.481771954 12.110780847 -8.75 10.963543908 14.221561694 -7.5 10.556302335 12.43731978 -10 -11.11260467 14.874639561 -10 9.2206377477 10.977289353 -7.8349364905 8.4412754954 11.954578706 -5.6698729811 -8.6501049815 11.692714813 -8.75 7.3002099629 13.385429626 -7.5 8.4412754954 11.954578706 -10 -6.8825509907 13.909157412 -10 8.75 10 -7.8349364905 7.5 10 -5.6698729811 -7.8349364905 10 -8.75 5.6698729811 10 -7.5 7.5 10 -10 -5 10 -10 9.2206377477 9.0227106469 -7.8349364905 8.4412754954 8.0454212938 -5.6698729811 -8.6501049815 8.3072851868 -8.75 7.3002099629 6.6145703735 -7.5 8.4412754954 8.0454212938 -10 -6.8825509907 6.0908425877 -10 10.278151167 8.7813401098 -7.8349364905 10.556302335 7.5626802195 -5.6698729811 -10.481771954 7.889219153 -8.75 10.963543908 5.778438306 -7.5 10.556302335 7.5626802195 -10 -11.11260467 5.1253604391 -10 11.126211085 9.4576453261 -7.8349364905 12.25242217 8.9152906522 -5.6698729811 -11.950654819 9.0606141491 -8.75 13.901309638 8.1212282982 -7.5 12.25242217 8.9152906522 -10 -14.50484434 7.8305813044 -10 -CELLS 43 840 -OFFSETS vtktypeint64 -0 20 40 60 80 100 120 140 160 -180 200 220 240 260 280 300 320 340 -360 380 400 420 440 460 480 500 520 -540 560 580 600 620 640 660 680 700 -720 740 760 780 800 820 840 -CONNECTIVITY vtktypeint64 -24 25 29 24 24 25 28 24 47 -91 49 24 47 97 55 24 24 25 -133 24 25 26 38 29 25 26 35 -28 48 92 50 91 48 98 56 97 -25 26 134 133 24 29 36 24 24 -28 31 24 49 93 51 24 55 99 -57 24 24 133 135 24 29 38 43 -36 28 35 40 31 50 94 52 93 -56 100 58 99 133 134 136 135 24 -36 37 24 24 31 34 24 51 95 -53 24 57 101 59 24 24 135 137 -24 36 43 45 37 31 40 42 34 -52 96 54 95 58 102 60 101 135 -136 138 137 24 25 28 24 24 25 -23 24 47 97 55 24 47 103 61 -24 24 25 139 24 25 26 35 28 -25 26 19 23 48 98 56 97 48 -104 62 103 25 26 140 139 24 28 -31 24 24 23 21 24 55 99 57 -24 61 105 63 24 24 139 141 24 -28 35 40 31 23 19 15 21 56 -100 58 99 62 106 64 105 139 140 -142 141 24 31 34 24 24 21 18 -24 57 101 59 24 63 107 65 24 -24 141 143 24 31 40 42 34 21 -15 13 18 58 102 60 101 64 108 -66 107 141 142 144 143 24 25 23 -24 24 25 11 24 47 103 61 24 -47 109 67 24 24 25 145 24 25 -26 19 23 25 26 7 11 48 104 -62 103 48 110 68 109 25 26 146 -145 24 23 21 24 24 11 9 24 -61 105 63 24 67 111 69 24 24 -145 147 24 23 19 15 21 11 7 -3 9 62 106 64 105 68 112 70 -111 145 146 148 147 24 21 18 24 -24 9 6 24 63 107 65 24 69 -113 71 24 24 147 149 24 21 15 -13 18 9 3 1 6 64 108 66 -107 70 114 72 113 147 148 150 149 -24 25 11 24 24 25 10 24 47 -109 67 24 47 115 73 24 24 25 -151 24 25 26 7 11 25 26 5 -10 48 110 68 109 48 116 74 115 -25 26 152 151 24 11 9 24 24 -10 8 24 67 111 69 24 73 117 -75 24 24 151 153 24 11 7 3 -9 10 5 2 8 68 112 70 111 -74 118 76 117 151 152 154 153 24 -9 6 24 24 8 4 24 69 113 -71 24 75 119 77 24 24 153 155 -24 9 3 1 6 8 2 0 4 -70 114 72 113 76 120 78 119 153 -154 156 155 24 25 10 24 24 25 -22 24 47 115 73 24 47 121 79 -24 24 25 157 24 25 26 5 10 -25 26 17 22 48 116 74 115 48 -122 80 121 25 26 158 157 24 10 -8 24 24 22 20 24 73 117 75 -24 79 123 81 24 24 157 159 24 -10 5 2 8 22 17 14 20 74 -118 76 117 80 124 82 123 157 158 -160 159 24 8 4 24 24 20 16 -24 75 119 77 24 81 125 83 24 -24 159 161 24 8 2 0 4 20 -14 12 16 76 120 78 119 82 126 -84 125 159 160 162 161 24 25 22 -24 24 25 27 24 47 121 79 24 -47 127 85 24 24 25 163 24 25 -26 17 22 25 26 33 27 48 122 -80 121 48 128 86 127 25 26 164 -163 24 22 20 24 24 27 30 24 -79 123 81 24 85 129 87 24 24 -163 165 24 22 17 14 20 27 33 -39 30 80 124 82 123 86 130 88 -129 163 164 166 165 24 20 16 24 -24 30 32 24 81 125 83 24 87 -131 89 24 24 165 167 24 20 14 -12 16 30 39 41 32 82 126 84 -125 88 132 90 131 165 166 168 167 -24 25 27 24 24 25 29 24 47 -127 85 24 47 91 49 24 24 25 -169 24 25 26 33 27 25 26 38 -29 48 128 86 127 48 92 50 91 -25 26 170 169 24 27 30 24 24 -29 36 24 85 129 87 24 49 93 -51 24 24 169 171 24 27 33 39 -30 29 38 43 36 86 130 88 129 -50 94 52 93 169 170 172 171 24 -30 32 24 24 36 37 24 87 131 -89 24 51 95 53 24 24 171 173 -24 30 39 41 32 36 43 45 37 -88 132 90 131 52 96 54 95 171 -172 174 173 -CELL_TYPES 42 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 -25 - diff --git a/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk b/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk deleted file mode 100644 index 3dff18a08..000000000 --- a/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk +++ /dev/null @@ -1,39 +0,0 @@ -# vtk DataFile Version 5.1 -vtk output -ASCII -DATASET STRUCTURED_GRID -DIMENSIONS 3 4 8 -POINTS 96 double -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 11.25 10 -7.8349364905 12.5 10 -5.6698729811 -10 10 -10 12.165063509 10 -8.75 14.330127019 10 -7.5 -10 10 -10 12.5 10 -10 15 10 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 10.779362252 10.977289353 -7.8349364905 11.558724505 11.954578706 -5.6698729811 -10 10 -10 11.349895019 11.692714813 -8.75 12.699790037 13.385429626 -7.5 -10 10 -10 11.558724505 11.954578706 -10 13.117449009 13.909157412 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 9.7218488326 11.21865989 -7.8349364905 9.4436976651 12.43731978 -5.6698729811 -10 10 -10 9.5182280458 12.110780847 -8.75 9.0364560916 14.221561694 -7.5 -10 10 -10 9.4436976651 12.43731978 -10 8.8873953302 14.874639561 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 8.8737889151 10.542354674 -7.8349364905 7.7475778302 11.084709348 -5.6698729811 -10 10 -10 8.0493451809 10.939385851 -8.75 6.0986903619 11.878771702 -7.5 -10 10 -10 7.7475778302 11.084709348 -10 5.4951556605 12.169418696 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 8.8737889151 9.4576453261 -7.8349364905 7.7475778302 8.9152906522 -5.6698729811 -10 10 -10 8.0493451809 9.0606141491 -8.75 6.0986903619 8.1212282982 -7.5 -10 10 -10 7.7475778302 8.9152906522 -10 5.4951556605 7.8305813044 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 9.7218488326 8.7813401098 -7.8349364905 9.4436976651 7.5626802195 -5.6698729811 -10 10 -10 9.5182280458 7.889219153 -8.75 9.0364560916 5.778438306 -7.5 -10 10 -10 9.4436976651 7.5626802195 -10 8.8873953302 5.1253604391 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 10.779362252 9.0227106469 -7.8349364905 11.558724505 8.0454212938 -5.6698729811 -10 10 -10 11.349895019 8.3072851868 -8.75 12.699790037 6.6145703735 -7.5 -10 10 -10 11.558724505 8.0454212938 -10 13.117449009 6.0908425877 -10 -10 10 -10 10 10 -7.5 10 10 -5 -10 10 -10 11.25 10 -7.8349364905 12.5 10 -5.6698729811 -10 10 -10 12.165063509 10 -8.75 14.330127019 10 -7.5 -10 10 -10 12.5 10 -10 15 10 -10 - diff --git a/tests/unit_tests/mesh_to_vtk/test.py b/tests/unit_tests/mesh_to_vtk/test.py index f00aa4626..5f6cd6a41 100644 --- a/tests/unit_tests/mesh_to_vtk/test.py +++ b/tests/unit_tests/mesh_to_vtk/test.py @@ -1,103 +1,69 @@ -import difflib import filecmp -import numpy as np +from itertools import product from pathlib import Path -import openmc -import pytest +import numpy as np -from tests.regression_tests import config +import openmc +import openmc.lib +import pytest pytest.importorskip('vtk') -def full_path(f): - return Path(__file__).parent.absolute() / f -def diff_file(file1, file2): - with open(file1) as fh: - f1_text = fh.readlines() - with open(file2) as fh: - f2_text = fh.readlines() - diff_lines = difflib.unified_diff(f1_text, f2_text) - return ''.join(diff_lines) +def ids_func(param): + return f"{param['library']}_{param['elem_type']}" -# test meshes -reg_mesh = openmc.RegularMesh() -reg_mesh.lower_left = (0, 0, 0) -reg_mesh.upper_right = (20, 50, 50) -reg_mesh.dimension = (10, 20, 30) +test_params = (['libmesh', 'moab'], + ['tets', 'hexes']) -rect_mesh = openmc.RectilinearMesh() -rect_mesh.x_grid = np.linspace(0, 10, 5) -rect_mesh.y_grid = np.geomspace(5., 20., 10) -rect_mesh.z_grid = np.linspace(1, 100, 20) +test_cases = [ + {'library' : library, 'elem_type' : elem_type} + for library, elem_type in product(*test_params) +] -cyl_mesh = openmc.CylindricalMesh( - origin=(10, 10, -10), - r_grid=np.linspace(0, 5, 5), - phi_grid=np.linspace(0, 2 * np.pi, 4), - z_grid=np.linspace(0, 2, 4), -) +@pytest.mark.parametrize("test_opts", test_cases, ids=ids_func) +def test_unstructured_mesh_to_vtk(run_in_tmpdir, request, test_opts): -sphere_mesh = openmc.SphericalMesh( - origin=(10, 10, -10), - r_grid=np.linspace(0, 5, 3), - theta_grid=np.linspace(0, 0.5 * np.pi, 4), - phi_grid=np.linspace(0, 2*np.pi, 8), -) + if test_opts['library'] == 'moab' and test_opts['elem_type'] == 'hexes': + pytest.skip('Hexes are not supported with MOAB') + if test_opts['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): + pytest.skip('LibMesh is not enabled in this build.') -def mesh_data(mesh_dims): - data = 100 * np.arange(np.prod(mesh_dims), dtype=float) - # data is returned reshaped with order 'F' to ensure that - # the resulting data is interpreted correctly by the - # write_data_to_vtk method - return data.reshape(*mesh_dims, order='F') + if test_opts['library'] == 'moab' and not openmc.lib._dagmc_enabled(): + pytest.skip('DAGMC (and MOAB) mesh not enabled in this build.') -test_data = ((reg_mesh, False, 'regular'), - (rect_mesh, False, 'rectilinear'), - (cyl_mesh, False, 'cylindrical-linear'), - (cyl_mesh, True, 'cylindrical-curvilinear'), - (sphere_mesh, False, 'spherical-linear'), - (sphere_mesh, True, 'spherical-curvilinear')) + # pull in a simple model -- just need to create the statepoint file + openmc.reset_auto_ids() + model = openmc.examples.pwr_pin_cell() -@pytest.mark.parametrize('mesh_params', - test_data, - ids=lambda params: params[2]) -def test_mesh_write_vtk(mesh_params, run_in_tmpdir): - mesh, curvilinear, filename = mesh_params + if test_opts['elem_type'] == 'tets': + filename = Path('tets.exo') + else: + filename = Path('hexes.exo') - test_data = full_path(filename + ".vtk") - kwargs = {} - if curvilinear: - kwargs['curvilinear'] = curvilinear - - # set output filename based on test configuration - filename = test_data if config['update'] else filename + "-actual.vtk" - - # write the mesh file and compare to the expected version - mesh.write_data_to_vtk(filename, **kwargs) - - try: - assert filecmp.cmp(test_data, filename) - except AssertionError as e: - diff = diff_file(test_data, filename) - raise AssertionError(diff) from e - -# check data writing -def test_mesh_write_vtk_data(run_in_tmpdir): - data = {'ascending_data': mesh_data(cyl_mesh.dimension)} - filename_expected = full_path('cyl-data.vtk') - filename_actual = full_path('cyl-data-actual.vtk') - # update the test file if requested - filename = filename_expected if config['update'] else filename_actual - cyl_mesh.write_data_to_vtk(filename, datasets=data, volume_normalization=False) - - try: - assert filecmp.cmp(filename, filename_expected) - except AssertionError as e: - diff = diff_file(filename_expected, filename) - raise AssertionError(diff) from e + # create a basic tally using the unstructured mesh + umesh = openmc.UnstructuredMesh(request.node.path.parent / filename, + test_opts['library']) + umesh.output = False + mesh_filter = openmc.MeshFilter(umesh) + tally = openmc.Tally() + tally.filters = [mesh_filter] + tally.scores = ['flux'] + tally.estimator = 'collision' + model.tallies = openmc.Tallies([tally]) + sp_file = model.run() + # check VTK output after reading mesh from statepoint file + with openmc.StatePoint(sp_file) as sp: + umesh = sp.meshes[umesh.id] + test_data = {'ids': np.arange(umesh.n_elements)} + umesh.write_data_to_vtk('umesh.vtk', + datasets=test_data, + volume_normalization=False) + # compare file content with reference file + ref_file = Path(f"{test_opts['library']}_{test_opts['elem_type']}_ref.vtk") + assert filecmp.cmp('umesh.vtk', request.node.path.parent / ref_file) diff --git a/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py deleted file mode 100644 index 366ce18ef..000000000 --- a/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py +++ /dev/null @@ -1,320 +0,0 @@ -from itertools import product - -import numpy as np -from pathlib import Path -import pytest - -vtk = pytest.importorskip("vtk") -from vtk.util import numpy_support as nps - -import openmc - -@pytest.fixture -def model(): - openmc.reset_auto_ids() - - surf1 = openmc.Sphere(r=10, boundary_type='vacuum') - surf2 = openmc.XPlane(x0=-0.001, boundary_type='vacuum') - - cell = openmc.Cell(region=-surf1 & -surf2) - - geometry = openmc.Geometry([cell]) - - settings = openmc.Settings() - settings.batches = 2 - settings.particles = 100 - settings.run_mode = 'fixed source' - - source = openmc.IndependentSource() - source.angle = openmc.stats.Isotropic() - source.energy = openmc.stats.Discrete([1.0e6], [1.0]) - source.space = openmc.stats.Point((-0.01, -0.01, -0.01)) - - settings.source = source - - model = openmc.Model(geometry=geometry, settings=settings) - - return model - - -regular_mesh = openmc.RegularMesh() -regular_mesh.lower_left = (-10, -10, -10) -regular_mesh.upper_right = (10, 10, 10) -regular_mesh.dimension = [30, 20, 10] - -rectilinear_mesh = openmc.RectilinearMesh() -rectilinear_mesh.x_grid = np.linspace(-10, 10, 6) -rectilinear_mesh.y_grid = np.logspace(0, 1, 7) -rectilinear_mesh.y_grid = \ - np.concatenate((-rectilinear_mesh.y_grid[::-1], rectilinear_mesh.y_grid)) -rectilinear_mesh.z_grid = np.linspace(-10, 10, 11) - -cylinder_mesh = openmc.CylindricalMesh( - r_grid=np.linspace(0, 10, 23), - z_grid=np.linspace(0, 1, 15) -) -cylinder_mesh.phi_grid = np.linspace(0, np.pi, 21) - -spherical_mesh = openmc.SphericalMesh( - r_grid=np.linspace(1, 10, 30), - phi_grid=np.linspace(0, 0.8*np.pi, 25), - theta_grid=np.linspace(0, np.pi / 2, 15), -) - -MESHES = [cylinder_mesh, regular_mesh, rectilinear_mesh, spherical_mesh] - -x_plane = openmc.XPlane(x0=-0.001, boundary_type='vacuum') -y_plane = openmc.YPlane(y0=-0.001, boundary_type='vacuum') -z_plane = openmc.ZPlane(z0=-0.001, boundary_type='vacuum') - -SURFS = [x_plane, y_plane, z_plane] - - -def ids(mesh): - if isinstance(mesh, openmc.CylindricalMesh): - return 'cylindrical_mesh' - elif isinstance(mesh, openmc.RegularMesh): - return 'regular_mesh' - elif isinstance(mesh, openmc.RectilinearMesh): - return 'rectilinear_mesh' - elif isinstance(mesh, openmc.SphericalMesh): - return 'spherical_mesh' - - -@pytest.mark.parametrize("mesh", MESHES, ids=ids) -def test_write_data_to_vtk(mesh, tmpdir): - # BUILD - filename = Path(tmpdir) / "out.vtk" - - # use mesh element volumes as data to check volume-normalization ordering - # kji (i changing fastest) orering is expected for input data - # by using the volumes transposed as the data here, we can ensure the - # normalization is happening correctly - data = mesh.volumes - - # RUN - mesh.write_data_to_vtk(filename=filename, datasets={"label1": data, "label2": data}) - - # TEST - assert filename.is_file() - - # read file - reader = vtk.vtkStructuredGridReader() - reader.SetFileName(str(filename)) - reader.Update() - - # check name of datasets - vtk_grid = reader.GetOutput() - array1 = vtk_grid.GetCellData().GetArray(0) - array2 = vtk_grid.GetCellData().GetArray(1) - - assert array1.GetName() == "label1" - assert array2.GetName() == "label2" - - # check size of datasets - data1 = nps.vtk_to_numpy(array1) - data2 = nps.vtk_to_numpy(array2) - assert data1.size == data.size - assert data2.size == data.size - - assert all(data1 == data2) - assert all(data1 == 1.0) - - -@pytest.mark.parametrize("mesh", MESHES, ids=ids) -def test_write_data_to_vtk_size_mismatch(mesh): - """Checks that an error is raised when the size of the dataset - doesn't match the mesh number of cells - - Parameters - ---------- - mesh : openmc.StructuredMesh - The mesh to test - """ - right_size = mesh.n_elements - data = np.random.random(right_size + 1) - - # Error message has \ in to escape characters that are otherwise recognized - # by regex. These are needed to make the test string match the error message - # string when using the match argument as that uses regular expression - expected_error_msg = ( - fr"The size of the dataset 'label' \({len(data)}\) should be equal to " - fr"the number of mesh cells \({mesh.n_elements}\)" - ) - with pytest.raises(ValueError, match=expected_error_msg): - mesh.write_data_to_vtk(filename="out.vtk", datasets={"label": data}) - -def test_write_data_to_vtk_round_trip(run_in_tmpdir): - cmesh = openmc.CylindricalMesh( - r_grid=(0.0, 1.0, 2.0), - z_grid=(0.0, 2.0, 4.0, 5.0), - phi_grid=(0.0, 3.0, 6.0), - ) - - smesh = openmc.SphericalMesh( - r_grid=(0.0, 1.0, 2.0), - theta_grid=(0.0, 0.5, 1.0, 2.0), - phi_grid=(0.0, 3.0, 6.0), - ) - rmesh = openmc.RegularMesh() - rmesh.lower_left = (0.0, 0.0, 0.0) - rmesh.upper_right = (1.0, 3.0, 5.0) - rmesh.dimension = (2, 1, 6) - - for mesh in [smesh, cmesh, rmesh]: - - filename = "mesh.vtk" - data = np.array([1.0] * 12) # there are 12 voxels in each mesh - mesh.write_data_to_vtk( - filename=filename, - datasets={"normalized": data}, - volume_normalization=True - ) - - reader = vtk.vtkStructuredGridReader() - reader.SetFileName(filename) - reader.ReadAllFieldsOn() - reader.Update() - - cell_data = reader.GetOutput().GetCellData() - uniform_array = cell_data.GetArray("normalized") - num_tuples = uniform_array.GetNumberOfTuples() - vtk_values = [uniform_array.GetValue(i) for i in range(num_tuples)] - - # checks that the vtk cell values are equal to the data / mesh volumes - assert np.allclose(vtk_values, data / mesh.volumes.T.flatten()) - - mesh.write_data_to_vtk( - filename=filename, - datasets={"not_normalized": data}, - volume_normalization=False, - ) - - reader = vtk.vtkStructuredGridReader() - reader.SetFileName(filename) - reader.ReadAllFieldsOn() - reader.Update() - - cell_data = reader.GetOutput().GetCellData() - uniform_array = cell_data.GetArray("not_normalized") - num_tuples = uniform_array.GetNumberOfTuples() - vtk_values = [uniform_array.GetValue(i) for i in range(num_tuples)] - - # checks that the vtk cell values are equal to the data - assert np.array_equal(vtk_values, data) - -def mesh_surf_id(param): - if isinstance(param, openmc.MeshBase): - return ids(param) - elif isinstance(param, openmc.XPlane): - return 'XPlane' - elif isinstance(param, openmc.YPlane): - return 'YPlane' - elif isinstance(param, openmc.ZPlane): - return 'ZPlane' - - -@pytest.mark.parametrize("mesh,surface", product(MESHES, SURFS), ids=mesh_surf_id) -def test_vtk_write_ordering(run_in_tmpdir, model, mesh, surface): - - tally = openmc.Tally() - tally.scores = ['flux'] - # use the mesh on the specified tally - mesh_filter = openmc.MeshFilter(mesh) - tally.filters = [mesh_filter] - - model.tallies = openmc.Tallies([tally]) - - # run the problem - sp_filename = model.run() - - with openmc.StatePoint(sp_filename) as sp: - mean = sp.tallies[tally.id].mean - - # write the data to a VTK file - vtk_filename = 'test.vtk' - mesh.write_data_to_vtk(vtk_filename, datasets={'mean': mean}) - - # read file - reader = vtk.vtkStructuredGridReader() - reader.SetFileName(str(vtk_filename)) - reader.Update() - - # check name of datasets - vtk_grid = reader.GetOutput() - array = vtk_grid.GetCellData().GetArray(0) - vtk_data = nps.vtk_to_numpy(array) - - # convenience function for determining if a mesh - # element has vertices in the geometry. This - # particular geometry allows us to assume that tally results - # in the element should be zero if none of its vertices lie in the geometry - def in_geom(cell): - point_ids = cell.GetPointIds() - - for i in range(point_ids.GetNumberOfIds()): - p = vtk_grid.GetPoint(point_ids.GetId(i)) - if model.geometry.find(p): - return True - - return False - - # reshape mean according to mesh dimensions - mean = mean.reshape(mesh.dimension[::-1]).T - centroid = [0.0, 0.0, 0.0] - - # check that tally and vtk array results are zero where expected - for ijk in mesh.indices: - ijk = tuple(n - 1 for n in ijk) - # get the cell from the stuctured mesh object - cell = vtk_grid.GetCell(*ijk) - if not in_geom(cell): - cell.GetCentroid(centroid) - err_msg = f'IJK: {ijk} should be zero but is not. Centroid: {centroid}' - assert mean[ijk] == 0.0, err_msg - - # need to get flat index with axes reversed due to ordering passed into the VTK file - flat_idx = np.ravel_multi_index(tuple(ijk[::-1]), mesh.dimension[::-1]) - assert vtk_data[flat_idx] == 0.0, err_msg - - -def test_sphere_mesh_coordinates(run_in_tmpdir): - mesh = openmc.SphericalMesh( - r_grid=np.linspace(0.1, 10, 30), - phi_grid=np.linspace(0, 1.5*np.pi, 25), - theta_grid=np.linspace(0, np.pi / 2, 15), - ) - # write the data to a VTK file (no data) - vtk_filename = 'test.vtk' - mesh.write_data_to_vtk(vtk_filename, {}) - - # read file - reader = vtk.vtkStructuredGridReader() - reader.SetFileName(str(vtk_filename)) - reader.Update() - - vtk_grid = reader.GetOutput() - - # create a region that matches the spherical mesh description - x = openmc.XPlane() - z = openmc.ZPlane() - y = openmc.YPlane() - s = openmc.Sphere(r=10.0) - - region = +z & +y & -s | -x & -y & +z & -s - - # the VTK interface will update this list when GetCentroid is called - centroid = np.zeros(3) - - # ensure all centroids of the sphere mesh are inside the cell region - for i in range(vtk_grid.GetNumberOfCells()): - # get the cell from the stuctured mesh object - cell = vtk_grid.GetCell(i) - cell.GetCentroid(centroid) - - # if the coordinate conversion is happening correctly, - # every one of the cell centroids should be in the CSG region - assert centroid in region, \ - f'Cell centroid {centroid} not in equivalent ' \ - f'CSG region for spherical mesh {mesh}' - diff --git a/tests/unit_tests/test_bounding_box.py b/tests/unit_tests/test_bounding_box.py deleted file mode 100644 index 57c880092..000000000 --- a/tests/unit_tests/test_bounding_box.py +++ /dev/null @@ -1,190 +0,0 @@ -import numpy as np -import openmc -import pytest - - -test_bb_1 = openmc.BoundingBox((-10.0, -20.0, -30.0), (1.0, 2.0, 3.0)) -test_bb_2 = openmc.BoundingBox((1.0, 2.0, 3.0), (11.0, 22.0, 33.0)) -test_bb_3 = openmc.BoundingBox((-10.0, -20.0, -30.0), (-1.0, -2.0, -3.0)) - - -@pytest.mark.parametrize( - "bb, expected", - [ - (test_bb_1, 7986), # 11 * 22 * 33 - (test_bb_2, 6000), # 10 * 20 * 30 - (test_bb_3, 4374), # 9 * 18 * 27 - ], -) -def test_bounding_box_volume(bb, expected): - assert bb.volume == expected - - -@pytest.mark.parametrize( - "bb, expected", - [ - (test_bb_1, np.array([-10.0, -20.0, -30.0])), - (test_bb_2, np.array([1.0, 2.0, 3.0])), - (test_bb_3, np.array([-10.0, -20.0, -30.0])), - ], -) -def test_bounding_lower_left(bb, expected): - assert np.array_equiv(expected, bb.lower_left) - - -@pytest.mark.parametrize( - "bb, expected", - [ - (test_bb_1, np.array([1.0, 2.0, 3.0])), - (test_bb_2, np.array([11.0, 22.0, 33.0])), - (test_bb_3, np.array([-1.0, -2.0, -3.0])), - ], -) -def test_bounding_upper_right(bb, expected): - assert np.array_equiv(expected, bb.upper_right) - - -@pytest.mark.parametrize( - "bb, expected", - [ - (test_bb_1, np.array([-4.5, -9.0, -13.5])), - (test_bb_2, np.array([6.0, 12.0, 18.0])), - (test_bb_3, np.array([-5.5, -11.0, -16.5])), - ], -) -def test_bounding_box_center(bb, expected): - assert np.array_equiv(expected, bb.center) - - -def test_bounding_box_input_checking(): - # checks that only passing lower_left is not accepted - with pytest.raises(TypeError): - openmc.BoundingBox((-10, -20, -3)) - # checks that a tuple with three entry is not accepted - with pytest.raises(TypeError): - openmc.BoundingBox((-1, -2, -3), (-1, -2, -3), (-1, -2, -3)) - # checks that a numpy array with two entries is not accepted - with pytest.raises(ValueError): - openmc.BoundingBox(np.array([-10, -30]), np.array([1, 2, 3])) - # checks that a numpy array with two entries is not accepted - with pytest.raises(ValueError): - openmc.BoundingBox(np.array([-10, -20, -30]), np.array([1, 3])) - # checks that a numpy array with four entries is not accepted - with pytest.raises(ValueError): - openmc.BoundingBox(np.array([-10, -20, -3, -4]), np.array([1, 2, 3])) - # checks that a numpy array with four entries is not accepted - with pytest.raises(ValueError): - openmc.BoundingBox(np.array([-10, -20, -4]), np.array([1, 2, 3, 4])) - - -def test_bounding_box_extents(): - assert test_bb_1.extent["xy"] == (-10.0, 1.0, -20.0, 2.0) - assert test_bb_1.extent["xz"] == (-10.0, 1.0, -30.0, 3.0) - assert test_bb_1.extent["yz"] == (-20.0, 2.0, -30.0, 3.0) - - -def test_bounding_box_methods(): - test_bb = openmc.BoundingBox.infinite() - - # check assignment operator - test_bb[0] = [-10, -11, -12] - test_bb[1] = [13, 14, 15] - - assert all(test_bb[0] == [-10, -11, -12]) - assert all(test_bb[1] == [13, 14, 15]) - - # check length and iteration - assert len(test_bb) == 2 - ll, ur = test_bb - assert all(ll == [-10, -11, -12]) - assert all(ur == [13, 14, 15]) - - # test expand/reduce methods - other_bb = openmc.BoundingBox([-5, -5, -50], [5, 50, 5]) - - reduced_bb = test_bb & other_bb - - # inplace was False by default. BoundingBox.reduce should return a new object - assert test_bb is not reduced_bb - - # the original bounding box should be unchanged - assert all(test_bb[0] == [-10, -11, -12]) - assert all(test_bb[1] == [13, 14, 15]) - - assert all(reduced_bb[0] == [-5, -5, -12]) - assert all(reduced_bb[1] == [5, 14, 5]) - - test_bb &= other_bb - - assert all(test_bb[0] == [-5, -5, -12]) - assert all(test_bb[1] == [5, 14, 5]) - - other_bb = openmc.BoundingBox([-50, -50, -1], [50, 1, 50]) - - expanded_bb = test_bb | other_bb - - # inplace was False by default. BoundingBox.expand should return a new object - assert test_bb is not expanded_bb - - # the original bounding box should be unchanged - assert all(test_bb[0] == [-5, -5, -12]) - assert all(test_bb[1] == [5, 14, 5]) - - assert all(expanded_bb[0] == [-50, -50, -12]) - assert all(expanded_bb[1] == [50, 14, 50]) - - test_bb |= other_bb - - assert all(test_bb[0] == [-50, -50, -12]) - assert all(test_bb[1] == [50, 14, 50]) - - extended_bbox = test_bb.expand(0.1) - - assert extended_bbox is not test_bb - - # the original bounding box should not be changed with inplace as False - assert all(test_bb[0] == [-50, -50, -12]) - assert all(test_bb[1] == [50, 14, 50]) - - assert all(extended_bbox[0] == [-50.1, -50.1, -12.1]) - assert all(extended_bbox[1] == [50.1, 14.1, 50.1]) - - extended_bbox = test_bb.expand(0.1, True) - - # inplace was set to True. BoundingBox.reduce should return the same object - assert extended_bbox is test_bb - - assert all(test_bb[0] == [-50.1, -50.1, -12.1]) - assert all(test_bb[1] == [50.1, 14.1, 50.1]) - - -@pytest.mark.parametrize( - "bb, other, expected", - [ - (test_bb_1, (0, 0, 0), True), - (test_bb_2, (3, 3, 3), False), - # completely disjoint - (test_bb_1, test_bb_2, False), - # contained but touching border - (test_bb_1, test_bb_3, False), - # Fully contained - (test_bb_1, openmc.BoundingBox((-9, -19, -29), (0, 0, 0)), True), - # intersecting boxes - (test_bb_1, openmc.BoundingBox((-9, -19, -29), (1, 2, 5)), False), - ], -) -def test_bounding_box_contains(bb, other, expected): - assert (other in bb) == expected - - -@pytest.mark.parametrize( - "invalid, ex", - [ - ((1, 0), ValueError), - ((1, 2, 3, 4), ValueError), - ("foo", TypeError), - ], -) -def test_bounding_box_contains_checking(invalid, ex): - with pytest.raises(ex): - invalid in test_bb_1 diff --git a/tests/unit_tests/test_cell.py b/tests/unit_tests/test_cell.py index 8d39c071b..faecf0b63 100644 --- a/tests/unit_tests/test_cell.py +++ b/tests/unit_tests/test_cell.py @@ -1,9 +1,11 @@ -import lxml.etree as ET +import xml.etree. ElementTree as ET + import numpy as np from uncertainties import ufloat import openmc import pytest + from tests.unit_tests import assert_unbounded from openmc.data import atomic_mass, AVOGADRO @@ -20,12 +22,6 @@ def test_contains(): assert (10.0, -4., 2.0) in c -def test_id(): - openmc.Cell(cell_id=0) - with pytest.raises(ValueError): - openmc.Cell(cell_id=-1) - - def test_repr(cell_with_lattice): cells, mats, univ, lattice = cell_with_lattice repr(cells[0]) # cell with distributed materials @@ -61,51 +57,25 @@ def test_clone(): m = openmc.Material() cyl = openmc.ZCylinder() c = openmc.Cell(fill=m, region=-cyl) + c.temperature = 650. - # Check cloning with all optional params as the defaults c2 = c.clone() assert c2.id != c.id assert c2.fill != c.fill assert c2.region != c.region + assert c2.temperature == c.temperature c3 = c.clone(clone_materials=False) assert c3.id != c.id assert c3.fill == c.fill assert c3.region != c.region + assert c3.temperature == c.temperature c4 = c.clone(clone_regions=False) assert c4.id != c.id assert c4.fill != c.fill assert c4.region == c.region - - # Add optional properties to the original cell to ensure they're cloned successfully - c.temperature = 650. - c.translation = (1., 2., 3.) - c.rotation = (4., 5., 6.) - c.volume = 100 - - c5 = c.clone(clone_materials=False, clone_regions=False) - assert c5.id != c.id - assert c5.fill == c.fill - assert c5.region == c.region - assert c5.temperature == c.temperature - assert c5.volume == c.volume - assert all(c5.translation == c.translation) - assert all(c5.rotation == c.rotation) - - # Mutate the original to ensure the changes are not seen in the clones - c.fill = openmc.Material() - c.region = +openmc.ZCylinder() - c.translation = (-1., -2., -3.) - c.rotation = (-4., -5., -6.) - c.temperature = 1 - c.volume = 1 - assert c5.fill != c.fill - assert c5.region != c.region - assert c5.temperature != c.temperature - assert c5.volume != c.volume - assert all(c5.translation != c.translation) - assert all(c5.rotation != c.rotation) + assert c4.temperature == c.temperature def test_temperature(cell_with_lattice): @@ -122,9 +92,6 @@ def test_temperature(cell_with_lattice): assert c2.temperature == 400.0 with pytest.raises(ValueError): c.temperature = -100. - c.temperature = None - assert c1.temperature == None - assert c2.temperature == None # distributed temperature cells, _, _, _ = cell_with_lattice @@ -132,29 +99,6 @@ def test_temperature(cell_with_lattice): c.temperature = (300., 600., 900.) -def test_densities(cell_with_lattice): - # Make sure density propagates through universes - m = openmc.Material() - s = openmc.XPlane() - c1 = openmc.Cell(fill=m, region=+s) - c2 = openmc.Cell(fill=m, region=-s) - u1 = openmc.Universe(cells=[c1, c2]) - c = openmc.Cell(fill=u1) - - c.density = 1. - assert c1.density == 1. - assert c2.density == 1. - with pytest.raises(ValueError): - c.density = -1. - c.density = None - assert c1.density == None - assert c2.density == None - - # distributed density - cells, _, _, _ = cell_with_lattice - c = cells[0] - c.density = (1., 2., 3.) - def test_rotation(): u = openmc.Universe() c = openmc.Cell(fill=u) @@ -350,11 +294,9 @@ def test_to_xml_element(cell_with_lattice): c = cells[0] c.temperature = 900.0 - c.volume = 1.0 elem = c.create_xml_subelement(root) assert elem.get('region') == str(c.region) assert elem.get('temperature') == str(c.temperature) - assert elem.get('volume') == str(c.volume) @pytest.mark.parametrize("rotation", [ @@ -372,64 +314,3 @@ def test_rotation_from_xml(rotation): elem, {s.id: s}, {'void': None}, openmc.Universe ) np.testing.assert_allclose(new_cell.rotation, cell.rotation) - - -def test_dagmccell_from_xml_element(): - """DAGMCCell.from_xml_element parses material, temperature, density, - and volume; rejects unsupported attributes.""" - mat = openmc.Material(1) - mat.add_nuclide('U235', 1.0) - mats = {'1': mat} - # In practice, from_xml_element is always called from DAGMCUniverse - # during XML parsing. A placeholder universe is used here so the test - # can exercise the method directly without a real DAGMC model file. - placeholder_univ = openmc.DAGMCUniverse('model.h5m') - - # material + temperature + density round-trip - xml = '' - cell = openmc.DAGMCCell.from_xml_element(ET.fromstring(xml), mats, placeholder_univ) - assert cell.id == 5 - assert cell.name == 'fuel' - assert cell.fill is mat - assert cell.density == 10.5 - assert cell.temperature == 900.0 - - # volume round-trip - xml = '' - cell = openmc.DAGMCCell.from_xml_element(ET.fromstring(xml), mats, placeholder_univ) - assert cell.volume == 42.0 - - # forbidden: region, fill, universe - for tag, val in [('region', '-1'), ('fill', '2'), ('universe', '0')]: - xml = f'' - with pytest.raises(ValueError, match=tag): - openmc.DAGMCCell.from_xml_element(ET.fromstring(xml), mats, placeholder_univ) - - # forbidden: translation, rotation - for tag, val in [('translation', '1 0 0'), ('rotation', '0 0 90')]: - xml = f'' - with pytest.raises(ValueError, match=tag): - openmc.DAGMCCell.from_xml_element(ET.fromstring(xml), mats, placeholder_univ) - - # missing material raises - xml = '' - with pytest.raises(ValueError, match='material'): - openmc.DAGMCCell.from_xml_element(ET.fromstring(xml), mats, placeholder_univ) - - -def test_plot(run_in_tmpdir): - zcyl = openmc.ZCylinder() - c = openmc.Cell(region=-zcyl) - - # create a universe before the plot - u_before = openmc.Universe() - - # create a plot of the cell - c.plot() - - # create a universe after the plot - u_after = openmc.Universe() - - # ensure that calling the plot method doesn't - # affect the universe ID space - assert u_before.id + 1 == u_after.id diff --git a/tests/unit_tests/cell_instances/test_rect_multilattice.py b/tests/unit_tests/test_cell_instance.py similarity index 70% rename from tests/unit_tests/cell_instances/test_rect_multilattice.py rename to tests/unit_tests/test_cell_instance.py index aaecb3bda..00424f9c5 100644 --- a/tests/unit_tests/cell_instances/test_rect_multilattice.py +++ b/tests/unit_tests/test_cell_instance.py @@ -1,5 +1,5 @@ -import pytest import numpy as np +import pytest import openmc import openmc.lib @@ -8,8 +8,7 @@ from tests import cdtemp @pytest.fixture(scope='module', autouse=True) -def double_rect_lattice_model(): - openmc.reset_auto_ids() +def double_lattice_model(): model = openmc.Model() # Create a single material @@ -40,20 +39,6 @@ def double_rect_lattice_model(): cell_with_lattice2.translation = (2., 0., 0.) model.geometry = openmc.Geometry([cell_with_lattice1, cell_with_lattice2]) - tally = openmc.Tally(tally_id=1) - dcell_filter = openmc.DistribcellFilter(c) - tally.filters = [dcell_filter] - tally.scores = ['flux'] - model.tallies = [tally] - - # Add box source that covers the model space well - bbox = model.geometry.bounding_box - bbox[0][2] = -0.5 - bbox[1][2] = 0.5 - space = openmc.stats.Box(*bbox) - source = openmc.IndependentSource(space=space) - model.settings.source = source - # Add necessary settings and export model.settings.batches = 10 model.settings.inactive = 0 @@ -65,13 +50,14 @@ def double_rect_lattice_model(): yield openmc.lib.finalize() + # This shows the expected cell instance numbers for each lattice position: # ┌─┬─┬─┬─┐ # │2│3│6│7│ # ├─┼─┼─┼─┤ # │0│1│4│5│ # └─┴─┴─┴─┘ -rect_expected_results = [ +expected_results = [ ((0.5, 0.5, 0.0), 0), ((1.5, 0.5, 0.0), 1), ((0.5, 1.5, 0.0), 2), @@ -81,16 +67,7 @@ rect_expected_results = [ ((2.5, 1.5, 0.0), 6), ((3.5, 1.5, 0.0), 7), ] - - -@pytest.mark.parametrize("r,expected_cell_instance", rect_expected_results, ids=lambda p : f'{p}') -def test_cell_instance_rect_multilattice(r, expected_cell_instance): +@pytest.mark.parametrize("r,expected_cell_instance", expected_results) +def test_cell_instance_multilattice(r, expected_cell_instance): _, cell_instance = openmc.lib.find_cell(r) assert cell_instance == expected_cell_instance - - -def test_cell_instance_multilattice_results(): - openmc.run() - openmc.lib.run() - tally_results = openmc.lib.tallies[1].mean - assert (tally_results != 0.0).all() diff --git a/tests/unit_tests/test_collision_track.py b/tests/unit_tests/test_collision_track.py deleted file mode 100644 index 96676e2cd..000000000 --- a/tests/unit_tests/test_collision_track.py +++ /dev/null @@ -1,170 +0,0 @@ -"""Test the 'collision_track' setting used to store particle information -during specified collision conditions in a file for a given simulation.""" - -import openmc -import pytest -import h5py -import numpy as np -import shutil - -from tests.testing_harness import CollisionTrackTestHarness as ctt - - -@pytest.fixture(scope="module") -def geometry(): - """Simple hydrogen sphere geometry""" - openmc.reset_auto_ids() - material = openmc.Material(name="H1") - material.add_element("H", 1.0) - sphere = openmc.Sphere(r=1.0, boundary_type="vacuum") - cell = openmc.Cell(region=-sphere, fill=material) - return openmc.Geometry([cell]) - - -@pytest.mark.parametrize( - "parameter", - [ - {"max_collisions": 200}, - {"max_collisions": 200, "reactions": ["(n,disappear)"]}, - {"max_collisions": 200, "cell_ids": [1]}, - {"max_collisions": 200, "material_ids": [1]}, - {"max_collisions": 200, "universe_ids": [1]}, - {"max_collisions": 200, "nuclides": ["H1"]}, - {"max_collisions": 200, "deposited_E_threshold": 200000.0}, - {"max_collisions": 200, "mcpl": True} - - ], - ids=str -) -def test_xml_serialization(parameter, run_in_tmpdir): - """Check that the different use cases can be written and read in XML.""" - settings = openmc.Settings() - settings.collision_track = parameter - settings.export_to_xml() - - read_settings = openmc.Settings.from_xml() - assert read_settings.collision_track == parameter - - -@pytest.fixture -def model(): - """Simple hydrogen sphere divided in two hemispheres - by a z-plane to form 2 cells.""" - openmc.reset_auto_ids() - model = openmc.Model() - - # Material - material = openmc.Material(name="H1") - material.add_element("H", 1.0) - - # Geometry - radius = 1.0 - sphere = openmc.Sphere(r=radius, boundary_type="reflective") - plane = openmc.ZPlane(0.0) - cell_1 = openmc.Cell(region=-sphere & -plane, fill=material, cell_id=1) - cell_2 = openmc.Cell(region=-sphere & +plane, fill=material, cell_id=2) - root = openmc.Universe(cells=[cell_1, cell_2]) - model.geometry = openmc.Geometry(root) - - # Settings - model.settings = openmc.Settings() - model.settings.run_mode = "fixed source" - model.settings.particles = 1 - model.settings.batches = 1 - model.settings.seed = 2 - - bounds = [-radius, -radius, -radius, radius, radius, radius] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource(space=distribution) - - return model - - -def test_particle_location(run_in_tmpdir, model): - """Test the location of particles with respected to the "cell_ids" - and the location x, y, z of the particle itself. the upper sphere will - have positive z component and the bottom sphere a negative z compnent. - - """ - model.settings.collision_track = { - "max_collisions": 200, - "reactions": ["elastic"], - "cell_ids": [1, 2] - } - model.run() - - with h5py.File("collision_track.h5", "r") as f: - source = f["collision_track_bank"] - - assert len(source) == 60 - - # We want to verify that the collisions happenening are in the right cells - # and the position of the particle is either positive or negative relative - # to the z plane. In this case, we track the position of the particle - # relative to the cell_id already set. - for point in source: - if point['cell_id'] == 1: - assert point['r'][2] < 0.0 # z component negative - elif point['cell_id'] == 2: - assert point["r"][2] > 0.0 # z component positive - else: - assert False - - -@pytest.mark.skipif(shutil.which("mcpl-config") is None, reason="MCPL is not available.") -def test_format_similarity(run_in_tmpdir, model): - model.settings.collision_track = {"max_collisions": 200, "reactions": ['elastic'], - "cell_ids": [1, 2], "mcpl": False} - model.run() - data_h5 = ctt._return_collision_track_data('collision_track.h5') - - model.settings.collision_track["mcpl"] = True - model.run() - data_mcpl = ctt._return_collision_track_data('collision_track.mcpl') - - assert len(data_h5) == 60 - assert len(data_mcpl) == 60 - - np.testing.assert_allclose(data_h5, data_mcpl, rtol=1e-05) - # tolerance not that low due to the strings that is saved in MCPL, - # not enough precision! - - -def test_photon_particles(run_in_tmpdir, model): - """Test that the collision track can be used to track photon particles.""" - model.settings.collision_track = {"max_collisions": 200, "cell_ids": [1, 2]} - - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box(*model.geometry.bounding_box), - energy=openmc.stats.delta_function(1e5), - particle='photon' - ) - model.run() - - with h5py.File("collision_track.h5", "r") as f: - source = f["collision_track_bank"] - - assert len(source) < 200 - - allowed_particles = (openmc.ParticleType.PHOTON, openmc.ParticleType.ELECTRON) - - for point in source: - particle_type = openmc.ParticleType(point['particle']) - assert particle_type in allowed_particles - - if particle_type == openmc.ParticleType.ELECTRON: - assert point['nuclide_id'] == 0 - - -def test_collision_track_two_threads(model, run_in_tmpdir): - # This test checks that the `max_collisions` setting is honored: - # no collisions beyond the specified limit should be recorded. - # - # The exact set of events in the capped bank is not reproducible with - # multiple threads because the bank stores whichever thread appends first - # until capacity is reached. - model.settings.collision_track = {"max_collisions": 200} - model.run(threads=2, particles=500) - - collision_track = openmc.read_collision_track_hdf5("collision_track.h5") - assert len(collision_track) == 200 diff --git a/tests/unit_tests/test_complex_cell_bb.py b/tests/unit_tests/test_complex_cell_bb.py index 8a94d9ddc..ad6491cca 100644 --- a/tests/unit_tests/test_complex_cell_bb.py +++ b/tests/unit_tests/test_complex_cell_bb.py @@ -66,7 +66,7 @@ def complex_cell(run_in_tmpdir, mpi_intracomm): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( + model.settings.source = openmc.Source(space=openmc.stats.Box( [-10., -10., -1.], [10., 10., 1.])) model.settings.verbosity = 1 diff --git a/tests/unit_tests/test_config.py b/tests/unit_tests/test_config.py deleted file mode 100644 index 45e6a7e5a..000000000 --- a/tests/unit_tests/test_config.py +++ /dev/null @@ -1,104 +0,0 @@ -from collections.abc import Mapping -import os -from pathlib import Path - -import openmc -from openmc.config import _default_config -from openmc.data import decay -import pytest - - -@pytest.fixture(autouse=True, scope='function') -def reset_config_and_env(): - """A fixture to ensure each test has a clean config, env, and CWD.""" - original_env = dict(os.environ) - original_cwd = os.getcwd() - original_resolve_paths = openmc.config["resolve_paths"] - - # Reset environment variables that affect config - for key in ['OPENMC_CROSS_SECTIONS', 'OPENMC_MG_CROSS_SECTIONS', 'OPENMC_CHAIN_FILE']: - if key in os.environ: - del os.environ[key] - - # Re-initialize the global config object - openmc.config = _default_config() - - try: - yield - finally: - # Restore environment, CWD and resolve_paths - os.environ.clear() - os.environ.update(original_env) - os.chdir(original_cwd) - - # Restore config one last time for safety between modules - openmc.config = _default_config(resolve_paths=original_resolve_paths) - - -def test_config_basics(): - assert isinstance(openmc.config, Mapping) - with pytest.warns(UserWarning): - openmc.config['cross_sections'] = '/path/to/cross_sections.xml' - del openmc.config['cross_sections'] - assert 'cross_sections' not in openmc.config - assert 'OPENMC_CROSS_SECTIONS' not in os.environ - with pytest.raises(KeyError, match="Unrecognized config key: nuke"): - openmc.config['nuke'] = '/like/to/eat/bacon' - with pytest.raises(TypeError): - openmc.config['resolve_paths'] = 'not a bool' - - -def test_config_path_resolution(tmp_path): - """Test path resolution logic.""" - os.chdir(tmp_path) - relative_path = Path("some/file.xml") - absolute_path = relative_path.resolve() - - # Test with resolve_paths = True (default) - with pytest.warns(UserWarning): - openmc.config['cross_sections'] = relative_path - assert openmc.config['cross_sections'] == absolute_path - assert openmc.config['cross_sections'].is_absolute() - - # Test with resolve_paths = False - with openmc.config.patch('resolve_paths', False): - with pytest.warns(UserWarning): - openmc.config['chain_file'] = relative_path - assert openmc.config['chain_file'] == relative_path - assert not openmc.config['chain_file'].is_absolute() - - assert openmc.config['resolve_paths'] is True - - -def test_config_patch(tmp_path): - file_a = tmp_path / "a.xml"; file_a.touch() - file_b = tmp_path / "b.xml"; file_b.touch() - openmc.config['cross_sections'] = file_a - with openmc.config.patch('cross_sections', file_b): - assert openmc.config['cross_sections'] == file_b.resolve() - assert openmc.config['cross_sections'] == file_a.resolve() - -def test_config_set_envvar(tmp_path): - """Test that setting config also sets environment variables correctly.""" - os.chdir(tmp_path) - relative_path = Path("relative.xml") - with pytest.warns(UserWarning): - openmc.config['cross_sections'] = relative_path - expected_path = str(relative_path.resolve()) - assert os.environ['OPENMC_CROSS_SECTIONS'] == expected_path - - -def test_config_warning_nonexistent_path(tmp_path): - """Test that a warning is issued for a path that does not exist.""" - bad_path = tmp_path / "a/path/that/does/not/exist.xml" - with pytest.warns(UserWarning, match=f"Path '{bad_path}' does not exist."): - openmc.config['chain_file'] = bad_path - - -def test_config_chain_side_effect(tmp_path): - """Test that modifying chain_file clears decay data caches.""" - chain_file = tmp_path / "chain.xml"; chain_file.touch() - decay._DECAY_ENERGY['U235'] = (1.0, 2.0) - decay._DECAY_PHOTON_ENERGY['PU239'] = {} - openmc.config['chain_file'] = chain_file - assert not decay._DECAY_ENERGY and not decay._DECAY_PHOTON_ENERGY diff --git a/tests/unit_tests/test_cylindrical_mesh.py b/tests/unit_tests/test_cylindrical_mesh.py deleted file mode 100644 index 645269825..000000000 --- a/tests/unit_tests/test_cylindrical_mesh.py +++ /dev/null @@ -1,202 +0,0 @@ -from itertools import product, permutations - -import openmc -import numpy as np - -import pytest - -geom_size = 5 - -@pytest.fixture() -def model(): - openmc.reset_auto_ids() - - water = openmc.Material(name='water') - water.add_element('H', 2.0) - water.add_element('O', 1.0) - water.set_density('g/cc', 1.0) - - rpp = openmc.model.RectangularParallelepiped(*([-geom_size, geom_size] * 3), - boundary_type='vacuum') - - cell = openmc.Cell(region=-rpp, fill=water) - - geom = openmc.Geometry([cell]) - - source = openmc.IndependentSource() - source.space = openmc.stats.Point() - source.energy = openmc.stats.Discrete([10000], [1.0]) - - settings = openmc.Settings() - settings.particles = 2000 - settings.batches = 10 - settings.run_mode = 'fixed source' - - # build - mesh = openmc.CylindricalMesh( - phi_grid=np.linspace(0, 2*np.pi, 21), - z_grid=np.linspace(-geom_size, geom_size, 11), - r_grid=np.linspace(0, geom_size, geom_size) - ) - tally = openmc.Tally() - - mesh_filter = openmc.MeshFilter(mesh) - tally.filters.append(mesh_filter) - - tally.scores.append("flux") - - tallies = openmc.Tallies([tally]) - - return openmc.Model(geometry=geom, settings=settings, tallies=tallies) - - -def test_origin_read_write_to_xml(run_in_tmpdir, model): - """Tests that the origin attribute can be written and read back to XML - """ - mesh = model.tallies[0].filters[0].mesh - mesh.origin = [0.1, 0.2, 0.3] - model.tallies.export_to_xml() - - # read back - new_tallies = openmc.Tallies.from_xml() - new_tally = new_tallies[0] - new_mesh = new_tally.filters[0].mesh - np.testing.assert_equal(new_mesh.origin, mesh.origin) - -estimators = ('tracklength', 'collision') -offset = geom_size + 0.001 -origins = set(permutations((-offset , 0, 0))) -origins |= set(permutations((offset, 0, 0))) - -test_cases = product(estimators, origins) - -def label(p): - if isinstance(p, tuple): - return f'origin:{p}' - if isinstance(p, str): - return f'estimator:{p}' - - -@pytest.mark.parametrize('estimator,origin', test_cases, ids=label) -def test_offset_mesh(model, estimator, origin): - """Tests that the mesh has been moved based on tally results - """ - mesh = model.tallies[0].filters[0].mesh - model.tallies[0].estimator = estimator - # move the center of the cylinder mesh upwards - mesh.origin = origin - - sp_filename = model.run() - - with openmc.StatePoint(sp_filename) as sp: - tally = sp.tallies[1] - - # we've translated half of the cylinder mesh above the model, - # so ensure that half of the bins are populated - assert np.count_nonzero(tally.mean) == tally.mean.size / 2 - - # check that the half of the mesh that is outside of the geometry - # contains the zero values - mean = tally.get_reshaped_data('mean', expand_dims=True) - centroids = mesh.centroids - for ijk in mesh.indices: - i, j, k = np.array(ijk) - 1 - if model.geometry.find(centroids[i, j, k]): - mean[i, j, k] == 0.0 - else: - mean[i, j, k] != 0.0 - - -@pytest.fixture() -def void_coincident_geom_model(): - """A model with many geometric boundaries coincident with mesh boundaries - across many scales - """ - openmc.reset_auto_ids() - model = openmc.model.Model() - - model.materials = openmc.Materials() - radii = [0.1,1, 5, 50, 100, 150, 250] - cylinders = [openmc.ZCylinder(r=ri) for ri in radii] - cylinders[-1].boundary_type = 'vacuum' - - regions = openmc.model.subdivide(cylinders)[:-1] - cells = [openmc.Cell(region=r, fill=None) for r in regions] - geom = openmc.Geometry(cells) - - model.geometry = geom - - settings = openmc.Settings(run_mode='fixed source') - settings.batches = 2 - settings.particles = 1000 - model.settings = settings - - mesh = openmc.CylindricalMesh( - r_grid=np.linspace(0, 250, 501), - z_grid=[-250, 250], - phi_grid=np.linspace(0, 2*np.pi, 2), - ) - mesh_filter = openmc.MeshFilter(mesh) - - tally = openmc.Tally() - tally.scores = ['flux'] - tally.filters = [mesh_filter] - - model.tallies = openmc.Tallies([tally]) - - return model - - -# convenience function for checking tally results -# in the following tests -def _check_void_cylindrical_tally(statepoint_filename): - with openmc.StatePoint(statepoint_filename) as sp: - flux_tally = sp.tallies[1] - mesh = flux_tally.find_filter(openmc.MeshFilter).mesh - neutron_flux = flux_tally.get_reshaped_data().squeeze() - # we expect the tally results to be the same as the mesh grid width - # for these cases - d_r = mesh.r_grid[1] - mesh.r_grid[0] - assert neutron_flux == pytest.approx(d_r) - - -def test_void_geom_pnt_src(run_in_tmpdir, void_coincident_geom_model): - src = openmc.IndependentSource() - src.space = openmc.stats.Point() - src.angle = openmc.stats.PolarAzimuthal(mu=openmc.stats.Discrete([0.0], [1.0])) - src.energy = openmc.stats.Discrete([14.06e6], [1]) - void_coincident_geom_model.settings.source = src - - sp_filename = void_coincident_geom_model.run() - _check_void_cylindrical_tally(sp_filename) - - -def test_void_geom_boundary_src(run_in_tmpdir, void_coincident_geom_model): - # update source to a number of points on the outside of the cylinder - # with directions pointing toward the origin - bbox = void_coincident_geom_model.geometry.bounding_box - - # can't source particle directly on the geometry boundary - outer_r = bbox[1][0] - 1e-08 - - n_sources = 100 - radial_vals = np.linspace(0.0, 2.0*np.pi, n_sources) - - sources = [] - - energy = openmc.stats.Discrete([14.06e6], [1]) - for val in radial_vals: - src = openmc.IndependentSource() - src.energy = energy - - pnt = np.array([np.cos(val), np.sin(val), 0.0]) - u = -pnt - src.space = openmc.stats.Point(outer_r*pnt) - src.angle = openmc.stats.Monodirectional(u) - src.strength = 0.5/n_sources - sources.append(src) - - void_coincident_geom_model.settings.source = sources - sp_filename = void_coincident_geom_model.run() - - _check_void_cylindrical_tally(sp_filename) \ No newline at end of file diff --git a/tests/unit_tests/test_d1s.py b/tests/unit_tests/test_d1s.py deleted file mode 100644 index 49c1b3049..000000000 --- a/tests/unit_tests/test_d1s.py +++ /dev/null @@ -1,156 +0,0 @@ -from pathlib import Path -from math import exp - -import numpy as np -import pytest -import openmc -import openmc.deplete -from openmc.deplete import d1s - - -CHAIN_PATH = Path(__file__).parents[1] / "chain_ni.xml" - - -@pytest.fixture -def model(): - """Simple model with natural Ni""" - mat = openmc.Material() - mat.add_element('Ni', 1.0) - geom = openmc.Geometry([openmc.Cell(fill=mat)]) - return openmc.Model(geometry=geom) - - -def test_get_radionuclides(model): - # Check that radionuclides are correct and are unstable - chain = openmc.deplete.Chain.from_xml(CHAIN_PATH) - nuclides = d1s.get_radionuclides(model, chain) - assert sorted(nuclides) == [ - 'Co58', 'Co60', 'Co61', 'Co62', 'Co64', - 'Fe55', 'Fe59', 'Fe61', 'Ni57', 'Ni59', 'Ni63', 'Ni65' - ] - for nuc in nuclides: - assert openmc.data.half_life(nuc) is not None - - -@pytest.mark.parametrize("nuclide", ['Co60', 'Ni63', 'H3', 'Na24', 'K40']) -def test_time_correction_factors(nuclide): - # Irradiation schedule turning unit neutron source on and off - timesteps = [1.0, 1.0, 1.0] - source_rates = [1.0, 0.0, 1.0] - - # Compute expected solution - decay_rate = openmc.data.decay_constant(nuclide) - g = exp(-decay_rate) - expected = [0.0, (1 - g), (1 - g)*g, (1 - g)*(1 + g*g)] - - # Test against expected solution - tcf = d1s.time_correction_factors([nuclide], timesteps, source_rates) - assert tcf[nuclide] == pytest.approx(expected) - - # Make sure all values at first timestep and onward are positive (K40 case - # has very small decay constant that stresses this) - assert np.all(tcf[nuclide][1:] > 0.0) - - # Timesteps as a tuple - timesteps = [(1.0, 's'), (1.0, 's'), (1.0, 's')] - tcf = d1s.time_correction_factors([nuclide], timesteps, source_rates) - assert tcf[nuclide] == pytest.approx(expected) - - # Test changing units - timesteps = [1.0/60.0, 1.0/60.0, 1.0/60.0] - tcf = d1s.time_correction_factors([nuclide], timesteps, source_rates, - timestep_units='min') - assert tcf[nuclide] == pytest.approx(expected) - - -def test_prepare_tallies(model): - tally = openmc.Tally() - tally.filters = [openmc.ParticleFilter('photon')] - tally.scores = ['flux'] - model.tallies = [tally] - - # Check that prepare_tallies adds a ParentNuclideFilter - nuclides = ['Co58', 'Co60', 'Fe55'] - d1s.prepare_tallies(model, nuclides, chain_file=CHAIN_PATH) - assert tally.contains_filter(openmc.ParentNuclideFilter) - assert list(tally.filters[-1].bins) == nuclides - - # Get rid of parent nuclide filter - tally.filters.pop() - - # With no nuclides specified, filter should use get_radionuclides - radionuclides = d1s.get_radionuclides(model, CHAIN_PATH) - d1s.prepare_tallies(model, chain_file=CHAIN_PATH) - assert tally.contains_filter(openmc.ParentNuclideFilter) - assert sorted(tally.filters[-1].bins) == sorted(radionuclides) - - assert len(tally.filters) == 2 - # calling prepare_tallies twice should not add another ParentNuclideFilter - d1s.prepare_tallies(model, chain_file=CHAIN_PATH) - assert len(tally.filters) == 2 - - -def test_apply_time_correction(run_in_tmpdir): - # Make simple sphere model with elemental Ni - mat = openmc.Material() - mat.add_element('Ni', 1.0) - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.run_mode = 'fixed source' - model.settings.batches = 3 - model.settings.particles = 10 - model.settings.photon_transport = True - model.settings.use_decay_photons = True - particle_filter = openmc.ParticleFilter('photon') - tally = openmc.Tally() - tally.filters = [particle_filter] - tally.scores = ['flux'] - model.tallies = [tally] - - # Prepare tallies for D1S and compute time correction factors - nuclides = d1s.prepare_tallies(model, chain_file=CHAIN_PATH) - factors = d1s.time_correction_factors(nuclides, [1.0e10], [1.0]) - - # Run OpenMC and get tally result - with openmc.config.patch('chain_file', CHAIN_PATH): - output_path = model.run() - with openmc.StatePoint(output_path) as sp: - tally = sp.tallies[tally.id] - flux = tally.mean.flatten() - - # Copy attributes from original tally - tally_filters = list(tally.filters) - tally_sum = tally.sum.copy() - tally_sum_sq = tally.sum_sq.copy() - tally_mean = tally.mean.copy() - tally_std_dev = tally.std_dev.copy() - - # Apply TCF and make sure results are consistent - result = d1s.apply_time_correction(tally, factors, sum_nuclides=False) - tcf = np.array([factors[nuc][-1] for nuc in nuclides]) - assert result.mean.flatten() == pytest.approx(tcf * flux) - - # Make sure summed results match a manual sum - result_summed = d1s.apply_time_correction(tally, factors) - assert result_summed.mean.flatten()[0] == pytest.approx(result.mean.sum()) - - # Make sure original tally is unchanged - assert tally.filters == tally_filters - assert np.all(tally.sum == tally_sum) - assert np.all(tally.sum_sq == tally_sum_sq) - assert np.all(tally.mean == tally_mean) - assert np.all(tally.std_dev == tally_std_dev) - - # Make sure various tally methods work - result.get_values() - result_summed.get_values() - result.get_reshaped_data() - result_summed.get_reshaped_data() - result.get_pandas_dataframe() - result_summed.get_pandas_dataframe() - - # The summed tally is derived, so sum/sum_sq are None - assert result_summed.sum is None - assert result_summed.sum_sq is None diff --git a/tests/unit_tests/test_data_decay.py b/tests/unit_tests/test_data_decay.py index f81f857e0..f0bda1bd9 100644 --- a/tests/unit_tests/test_data_decay.py +++ b/tests/unit_tests/test_data_decay.py @@ -1,14 +1,13 @@ #!/usr/bin/env python +from collections.abc import Mapping import os from math import log -from pathlib import Path import numpy as np import pytest from uncertainties import ufloat import openmc.data -from openmc.exceptions import DataError def ufloat_close(a, b): @@ -17,22 +16,25 @@ def ufloat_close(a, b): @pytest.fixture(scope='module') -def nb90(endf_data): +def nb90(): """Nb90 decay data.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'decay', 'dec-041_Nb_090.endf') return openmc.data.Decay.from_endf(filename) @pytest.fixture(scope='module') -def ba137m(endf_data): +def ba137m(): """Ba137_m1 decay data.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'decay', 'dec-056_Ba_137m1.endf') return openmc.data.Decay.from_endf(filename) @pytest.fixture(scope='module') -def u235_yields(endf_data): +def u235_yields(): """U235 fission product yield data.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'nfy', 'nfy-092_U_235.endf') return openmc.data.FissionProductYields.from_endf(filename) @@ -100,28 +102,6 @@ def test_fpy(u235_yields): ufloat_close(thermal['I135'], ufloat(0.0292737, 0.000819663)) -def test_decay_from_endf_material(endf_data): - filename = os.path.join(endf_data, 'decay', 'dec-041_Nb_090.endf') - material = openmc.data.endf.get_evaluations(filename)[0] - - data = openmc.data.Decay.from_endf(material) - - assert data.nuclide['name'] == 'Nb90' - assert not data.nuclide['stable'] - assert len(data.modes) == 2 - - -def test_fpy_from_endf_material(endf_data): - filename = os.path.join(endf_data, 'nfy', 'nfy-092_U_235.endf') - material = openmc.data.endf.get_evaluations(filename)[0] - - data = openmc.data.FissionProductYields.from_endf(material) - - assert data.nuclide['name'] == 'U235' - assert data.energies == pytest.approx([0.0253, 500.e3, 1.4e7]) - assert 'I135' in data.cumulative[0] - - def test_sources(ba137m, nb90): # Running .sources twice should give same objects sources = ba137m.sources @@ -146,25 +126,3 @@ def test_sources(ba137m, nb90): # Nb90 decays by β+ and should emit positrons, electrons, and photons sources = nb90.sources assert len(set(sources.keys()) ^ {'positron', 'electron', 'photon'}) == 0 - - -def test_decay_photon_energy(): - # If chain file is not set, we should get a data error - if 'chain_file' in openmc.config: - del openmc.config['chain_file'] - with pytest.raises(DataError): - openmc.data.decay_photon_energy('I135') - - # Temporarily Set chain file to simple chain - with openmc.config.patch('chain_file', Path(__file__).parents[1] / 'chain_simple.xml'): - - # Check strength of I135 source and presence of specific spectral line - src = openmc.data.decay_photon_energy('I135') - assert isinstance(src, openmc.stats.Discrete) - assert src.integral() == pytest.approx(3.920996223799345e-05) - assert 1260409. in src.x - - # Check Xe135 source, which should be tabular - src = openmc.data.decay_photon_energy('Xe135') - assert isinstance(src, openmc.stats.Tabular) - assert src.integral() == pytest.approx(2.076506258964966e-05) diff --git a/tests/unit_tests/test_data_dose.py b/tests/unit_tests/test_data_dose.py index 32be5eb89..348143e0b 100644 --- a/tests/unit_tests/test_data_dose.py +++ b/tests/unit_tests/test_data_dose.py @@ -22,65 +22,8 @@ def test_dose_coefficients(): assert energy[-1] == approx(10e9) assert dose[-1] == approx(699.0) - energy, dose = dose_coefficients('photon', data_source='icrp74') - assert energy[0] == approx(0.01e6) - assert dose[0] == approx(7.43*0.00653) - assert energy[-1] == approx(10.0e6) - assert dose[-1] == approx(24.0*0.990) - - energy, dose = dose_coefficients('neutron', 'LLAT', data_source='icrp74') - assert energy[0] == approx(1e-3) - assert dose[0] == approx(1.68) - assert energy[-1] == approx(20.0e6) - assert dose[-1] == approx(338.0) - - energy, dose = dose_coefficients( - 'neutron', data_source='icrp74', dose_quantity='ambient') - assert energy[0] == approx(1e-3) - assert dose[0] == approx(6.60) - assert energy[-1] == approx(20.0e6) - assert dose[-1] == approx(600) - - energy, dose = dose_coefficients( - 'photon', data_source='icrp74', dose_quantity='ambient') - assert energy[0] == approx(0.01e6) - assert dose[0] == approx(0.061) - assert energy[-1] == approx(10e6) - assert dose[-1] == approx(25.6) - # Invalid particle/geometry should raise an exception with raises(ValueError): dose_coefficients('slime', 'LAT') with raises(ValueError): dose_coefficients('neutron', 'ZZ') - with raises(ValueError): - dose_coefficients('neutron', data_source='icrp7000') - with raises(ValueError): - dose_coefficients('neutron', dose_quantity='banana') - with raises(ValueError): - dose_coefficients( - 'neutron', data_source='icrp116', dose_quantity='ambient') - with raises(ValueError): - dose_coefficients( - 'neutron', 'ISO', data_source='icrp74', dose_quantity='ambient') - with raises(ValueError) as excinfo: - dose_coefficients("photons", data_source="icrp116") - expected_particles = [ - "electron", - "helium", - "mu+", - "mu-", - "neutron", - "photon", - "photon kerma", - "pi+", - "pi-", - "positron", - "proton", - ] - expected_msg = ( - "'photons' has no effective dose data in data source icrp116. " - "Available particles for icrp116 with dose quantity effective are: " - f"{expected_particles}" - ) - assert str(excinfo.value) == expected_msg diff --git a/tests/unit_tests/test_data_kalbach_mann.py b/tests/unit_tests/test_data_kalbach_mann.py index 5d06669f7..3b837af7d 100644 --- a/tests/unit_tests/test_data_kalbach_mann.py +++ b/tests/unit_tests/test_data_kalbach_mann.py @@ -7,7 +7,6 @@ import pytest import numpy as np -import openmc from openmc.data import IncidentNeutron from openmc.data.kalbach_mann import _separation_energy, _AtomicRepresentation from openmc.data import kalbach_slope @@ -130,7 +129,7 @@ def test_kalbach_slope(): ('Hg204.h5', 'n-080_Hg_204.endf') ] ) -def test_comparison_slope_hdf5(hdf5_filename, endf_filename, endf_data): +def test_comparison_slope_hdf5(hdf5_filename, endf_filename): """Test the calculation of the Kalbach-Mann slope done by OpenMC by comparing it to HDF5 data. The test is based on the first product of MT=5 (neutron). The isotopes tested have been selected because the @@ -148,13 +147,13 @@ def test_comparison_slope_hdf5(hdf5_filename, endf_filename, endf_data): """ # HDF5 data - hdf5_directory = Path(openmc.config.get('cross_sections')).parent + hdf5_directory = Path(os.environ['OPENMC_CROSS_SECTIONS']).parent hdf5_data = IncidentNeutron.from_hdf5(hdf5_directory / hdf5_filename) hdf5_product = hdf5_data[5].products[0] hdf5_distribution = hdf5_product.distribution[0] # ENDF data - endf_directory = Path(endf_data) + endf_directory = Path(os.environ['OPENMC_ENDF_DATA']) endf_path = endf_directory / 'neutrons' / endf_filename endf_data = IncidentNeutron.from_endf(endf_path) endf_product = endf_data[5].products[0] diff --git a/tests/unit_tests/test_data_mass_attenuation.py b/tests/unit_tests/test_data_mass_attenuation.py deleted file mode 100644 index 0fe12a7db..000000000 --- a/tests/unit_tests/test_data_mass_attenuation.py +++ /dev/null @@ -1,53 +0,0 @@ -from pytest import approx, raises - -from openmc.data import mass_energy_absorption_coefficient, mass_attenuation_coefficient -from openmc.data.function import Tabulated1D - - -def test_mass_attenuation_type(): - mu = mass_attenuation_coefficient(26) # Fe - assert isinstance(mu, Tabulated1D) - - -def test_mass_attenuation_spot_values(): - # Spot checks for Fe (Z=26) against NIST data: first/last tabulated points - # and a mid-range value at 1 MeV - mu = mass_attenuation_coefficient(26) - assert mu(1e3) == approx(9085.0) - assert mu(1e6) == approx(0.05995) - assert mu(2e7) == approx(0.03224) - - -def test_mass_attenuation_caching(): - # Repeated calls with the same Z should return the identical object - mu1 = mass_attenuation_coefficient(26) - mu2 = mass_attenuation_coefficient('Fe') - assert mu1 is mu2 - - -def test_mass_attenuation_invalid_z(): - with raises(ValueError, match="Z=0"): - mass_attenuation_coefficient(0) - with raises(ValueError, match="Z=200"): - mass_attenuation_coefficient(200) - - -def test_mass_energy_absorption_type(): - # Spot checks on values from NIST tables - mu_en = mass_energy_absorption_coefficient("air") - assert isinstance(mu_en, Tabulated1D) - - -def test_mass_energy_absorption_spot_values(): - mu_en = mass_energy_absorption_coefficient("air") - assert mu_en(1e3) == approx(3.599e3) - assert mu_en(10.e3) == approx(4.742) - assert mu_en(2e7) == approx(1.311e-2) - - -def test_mass_energy_absorption_invalid(): - # Invalid material/data_source should raise an exception - with raises(ValueError): - mass_energy_absorption_coefficient("pasta") - with raises(ValueError): - mass_energy_absorption_coefficient("air", data_source="nist000") diff --git a/tests/unit_tests/test_data_misc.py b/tests/unit_tests/test_data_misc.py index 320d09eda..c3f7e3cff 100644 --- a/tests/unit_tests/test_data_misc.py +++ b/tests/unit_tests/test_data_misc.py @@ -7,12 +7,11 @@ from pathlib import Path import numpy as np import pytest import openmc.data -from openmc.deplete import Chain, Nuclide def test_data_library(tmpdir): lib = openmc.data.DataLibrary.from_xml() - for f in lib: + for f in lib.libraries: assert sorted(f.keys()) == ['materials', 'path', 'type'] f = lib.get_by_material('U235') @@ -23,19 +22,16 @@ def test_data_library(tmpdir): assert f['type'] == 'thermal' assert 'c_H_in_H2O' in f['materials'] - lib.remove_by_material('Pu239') - assert lib.get_by_material('Pu239') is None - filename = str(tmpdir.join('test.xml')) lib.export_to_xml(filename) assert os.path.exists(filename) new_lib = openmc.data.DataLibrary() - directory = os.path.dirname(openmc.config.get('cross_sections')) + directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS']) new_lib.register_file(os.path.join(directory, 'H1.h5')) - assert new_lib[-1]['type'] == 'neutron' + assert new_lib.libraries[-1]['type'] == 'neutron' new_lib.register_file(os.path.join(directory, 'c_Zr_in_ZrH.h5')) - assert new_lib[-1]['type'] == 'thermal' + assert new_lib.libraries[-1]['type'] == 'thermal' def test_depletion_chain_data_library(run_in_tmpdir): @@ -80,17 +76,15 @@ def test_thin(): def test_atomic_mass(): - assert openmc.data.atomic_mass('H1') == 1.007825031898 - assert openmc.data.atomic_mass('U235') == 235.043928117 - assert openmc.data.atomic_mass('Li6') == 6.01512288742 - assert openmc.data.atomic_mass('Pb220') == 220.025905 + assert openmc.data.atomic_mass('H1') == 1.00782503224 + assert openmc.data.atomic_mass('U235') == 235.04392819 with pytest.raises(KeyError): openmc.data.atomic_mass('U100') def test_atomic_weight(): - assert openmc.data.atomic_weight('C') == 12.011115164865895 - assert openmc.data.atomic_weight('carbon') == 12.011115164865895 + assert openmc.data.atomic_weight('C') == 12.011115164864455 + assert openmc.data.atomic_weight('carbon') == 12.011115164864455 with pytest.raises(ValueError): openmc.data.atomic_weight('Qt') @@ -105,12 +99,12 @@ def test_water_density(): assert dens(500.0, 3.0) == pytest.approx(1e-3/0.120241800e-2, 1e-6) -def test_gnds_name(): - assert openmc.data.gnds_name(1, 1) == 'H1' - assert openmc.data.gnds_name(40, 90) == ('Zr90') - assert openmc.data.gnds_name(95, 242, 0) == ('Am242') - assert openmc.data.gnds_name(95, 242, 1) == ('Am242_m1') - assert openmc.data.gnds_name(95, 242, 10) == ('Am242_m10') +def test_gnd_name(): + assert openmc.data.gnd_name(1, 1) == 'H1' + assert openmc.data.gnd_name(40, 90) == ('Zr90') + assert openmc.data.gnd_name(95, 242, 0) == ('Am242') + assert openmc.data.gnd_name(95, 242, 1) == ('Am242_m1') + assert openmc.data.gnd_name(95, 242, 10) == ('Am242_m10') def test_isotopes(): @@ -132,11 +126,9 @@ def test_zam(): assert openmc.data.zam('Am242_m10') == (95, 242, 10) with pytest.raises(ValueError): openmc.data.zam('garbage') - with pytest.raises(ValueError): - openmc.data.zam('Am242-m1') -def test_half_life(tmp_path): +def test_half_life(): assert openmc.data.half_life('H2') is None assert openmc.data.half_life('U235') == pytest.approx(2.22102e16) assert openmc.data.half_life('Am242') == pytest.approx(57672.0) @@ -145,32 +137,3 @@ def test_half_life(tmp_path): assert openmc.data.decay_constant('U235') == pytest.approx(log(2.0)/2.22102e16) assert openmc.data.decay_constant('Am242') == pytest.approx(log(2.0)/57672.0) assert openmc.data.decay_constant('Am242_m1') == pytest.approx(log(2.0)/4449622000.0) - - # Create minimal chain with H3 and Am242 to test half-life and decay - # constant retrieval from chain file - chain = Chain() - h3 = Nuclide("H3") - h3.half_life = 1.0 - chain.add_nuclide(h3) - am242 = Nuclide("Am242") - chain.add_nuclide(am242) - - assert openmc.data.half_life('H3', chain_file=chain) == 1.0 - assert openmc.data.decay_constant('H3', chain_file=chain) == pytest.approx(log(2.0)) - - # Nuclides that are present but stable in the chain should not fall back to - # ENDF/B-VIII.0 data. - assert openmc.data.half_life('Am242', chain_file=chain) is None - assert openmc.data.decay_constant('Am242', chain_file=chain) == 0.0 - - # Nuclides missing from the chain fall back to ENDF/B-VIII.0 data. - assert openmc.data.half_life('U235', chain_file=chain) == pytest.approx(2.22102e16) - - chain_path = tmp_path / "chain.xml" - chain.export_to_xml(chain_path) - assert openmc.data.half_life('H3', chain_file=chain_path) == 1.0 - - endf_h3 = openmc.data.half_life('H3') - with openmc.config.patch('chain_file', chain_path): - assert openmc.data.half_life('H3', chain_file=None) == 1.0 - assert openmc.data.half_life('H3', chain_file=False) == endf_h3 diff --git a/tests/unit_tests/test_data_multipole.py b/tests/unit_tests/test_data_multipole.py index a58ab4865..4c2ba96d6 100644 --- a/tests/unit_tests/test_data_multipole.py +++ b/tests/unit_tests/test_data_multipole.py @@ -8,14 +8,14 @@ import openmc.data @pytest.fixture(scope='module') def u235(): - directory = pathlib.Path(openmc.config.get('cross_sections')).parent + directory = pathlib.Path(os.environ['OPENMC_CROSS_SECTIONS']).parent u235 = directory / 'wmp' / '092235.h5' return openmc.data.WindowedMultipole.from_hdf5(u235) @pytest.fixture(scope='module') def b10(): - directory = pathlib.Path(openmc.config.get('cross_sections')).parent + directory = pathlib.Path(os.environ['OPENMC_CROSS_SECTIONS']).parent b10 = directory / 'wmp' / '005010.h5' return openmc.data.WindowedMultipole.from_hdf5(b10) @@ -48,41 +48,17 @@ def test_export_to_hdf5(tmpdir, u235): assert os.path.exists(filename) -def test_from_endf(endf_data): +def test_from_endf(): + pytest.importorskip('vectfit') + endf_data = os.environ['OPENMC_ENDF_DATA'] endf_file = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') - assert openmc.data.WindowedMultipole.from_endf( - endf_file, - log=True, - # Keep the test lightweight - vf_options={ - "njoy_error": 5e-3, - "vf_pieces": 1, - "rtol": 5e-2, - "atol": 1e-3, - "orders": [8, 12], - "n_vf_iter": 6, - }, - wmp_options={"n_win": 50, "n_cf": 3, "rtol": 5e-2, "atol": 1e-3}, - ) + return openmc.data.WindowedMultipole.from_endf( + endf_file, log=True, wmp_options={"n_win": 400, "n_cf": 3}) -def test_from_endf_search(endf_data): - endf_file = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') - assert openmc.data.WindowedMultipole.from_endf( - endf_file, - log=True, - vf_options={ - "njoy_error": 5e-3, - "vf_pieces": 1, - "rtol": 5e-2, - "atol": 1e-3, - "orders": [8, 12], - "n_vf_iter": 6, - }, - wmp_options={ - "search": True, - "rtol": 5e-2, - "search_n_win": 3, - "search_cf_orders": [5, 3], - }, - ) +def test_from_endf_search(): + pytest.importorskip('vectfit') + endf_data = os.environ['OPENMC_ENDF_DATA'] + endf_file = os.path.join(endf_data, 'neutrons', 'n-095_Am_244.endf') + return openmc.data.WindowedMultipole.from_endf( + endf_file, log=True, wmp_options={"search": True, 'rtol':1e-2}) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index c767f0171..0b33f05fc 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -14,113 +14,128 @@ _TEMPERATURES = [300., 600., 900.] @pytest.fixture(scope='module') def pu239(): """Pu239 HDF5 data.""" - directory = os.path.dirname(openmc.config.get('cross_sections')) + directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS']) filename = os.path.join(directory, 'Pu239.h5') return openmc.data.IncidentNeutron.from_hdf5(filename) @pytest.fixture(scope='module') -def xe135(endf_data): +def xe135(): """Xe135 ENDF data (contains SLBW resonance range)""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-054_Xe_135.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def sm150(endf_data): +def sm150(): """Sm150 ENDF data (contains MLBW resonance range)""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-062_Sm_150.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def gd154(endf_data): +def gd154(): """Gd154 ENDF data (contains Reich Moore resonance range and reosnance covariance with LCOMP=1).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-064_Gd_154.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @pytest.fixture(scope='module') -def cl35(endf_data): +def cl35(): """Cl35 ENDF data (contains RML resonance range)""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-017_Cl_035.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def am241(endf_data): +def am241(): """Am241 ENDF data (contains Madland-Nix fission energy distribution).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-095_Am_241.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def u233(endf_data): +def u233(): """U233 ENDF data (contains Watt fission energy distribution).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-092_U_233.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def u236(endf_data): +def u236(): """U236 ENDF data (contains Watt fission energy distribution).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-092_U_236.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def na22(endf_data): +def na22(): """Na22 ENDF data (contains evaporation spectrum).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-011_Na_022.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def na23(endf_data): +def na23(): """Na23 ENDF data (contains MLBW resonance covariance with LCOMP=0).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-011_Na_023.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @pytest.fixture(scope='module') -def be9(endf_data): +def be9(): """Be9 ENDF data (contains laboratory angle-energy distribution).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-004_Be_009.endf') return openmc.data.IncidentNeutron.from_endf(filename) @pytest.fixture(scope='module') -def h2(endf_data): +def h2(): + endf_data = os.environ['OPENMC_ENDF_DATA'] endf_file = os.path.join(endf_data, 'neutrons', 'n-001_H_002.endf') return openmc.data.IncidentNeutron.from_njoy( endf_file, temperatures=_TEMPERATURES) @pytest.fixture(scope='module') -def am244(endf_data): +def am244(): + endf_data = os.environ['OPENMC_ENDF_DATA'] endf_file = os.path.join(endf_data, 'neutrons', 'n-095_Am_244.endf') return openmc.data.IncidentNeutron.from_njoy(endf_file) @pytest.fixture(scope='module') -def ti50(endf_data): +def ti50(): """Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range and resonance covariance with LCOMP=1).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-022_Ti_050.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @pytest.fixture(scope='module') -def cf252(endf_data): +def cf252(): """Cf252 ENDF data (contains RM resonance covariance with LCOMP=0).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-098_Cf_252.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @pytest.fixture(scope='module') -def th232(endf_data): +def th232(): """Th232 ENDF data (contains RM resonance covariance with LCOMP=2).""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-090_Th_232.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @@ -133,28 +148,6 @@ def test_attributes(pu239): assert pu239.atomic_weight_ratio == pytest.approx(236.9986) -def test_from_endf_material(endf_data): - filename = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') - material = openmc.data.endf.get_evaluations(filename)[0] - - data = openmc.data.IncidentNeutron.from_endf(material) - - assert data.name == 'H1' - assert data.atomic_number == 1 - assert data.mass_number == 1 - assert 2 in data.reactions - - -def test_fission_energy_from_endf_material(endf_data): - filename = os.path.join(endf_data, 'neutrons', 'n-092_U_235.endf') - material = openmc.data.endf.get_evaluations(filename)[0] - neutron = openmc.data.IncidentNeutron.from_endf(material) - - data = openmc.data.FissionEnergyRelease.from_endf(material, neutron) - - assert data.fragments(0.0) > 0.0 - - def test_fission_energy(pu239): fer = pu239.fission_energy assert isinstance(fer, openmc.data.FissionEnergyRelease) @@ -289,6 +282,10 @@ def test_slbw(xe135): s = resolved.parameters.iloc[0] assert s['energy'] == pytest.approx(0.084) + xs = resolved.reconstruct([10., 30., 100.]) + assert sorted(xs.keys()) == [2, 18, 102] + assert np.all(xs[18] == 0.0) + def test_mlbw(sm150): resolved = sm150.resonances.resolved @@ -297,6 +294,10 @@ def test_mlbw(sm150): assert resolved.energy_max == pytest.approx(1570.) assert resolved.target_spin == 0.0 + xs = resolved.reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] + assert np.all(xs[18] == 0.0) + def test_reichmoore(gd154): res = gd154.resonances @@ -318,6 +319,7 @@ def test_reichmoore(gd154): elastic = gd154.reactions[2].xs['0K'] assert isinstance(elastic, openmc.data.ResonancesWithBackground) + assert elastic(0.0253) == pytest.approx(5.7228949796394524) def test_rml(cl35): @@ -345,6 +347,8 @@ def test_mlbw_cov_lcomp0(cf252): assert not subset.parameters.empty assert (subset.file2res.parameters['energy'] < 100).all() samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] def test_mlbw_cov_lcomp1(ti50): @@ -361,7 +365,9 @@ def test_mlbw_cov_lcomp1(ti50): subset = cov.subset('L', [1, 1]) assert not subset.parameters.empty assert (subset.file2res.parameters['L'] == 1).all() - cov.sample(1) + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] def test_mlbw_cov_lcomp2(na23): @@ -378,7 +384,9 @@ def test_mlbw_cov_lcomp2(na23): subset = cov.subset('L', [1, 1]) assert not subset.parameters.empty assert (subset.file2res.parameters['L'] == 1).all() - cov.sample(1) + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] def test_rmcov_lcomp1(gd154): @@ -395,7 +403,9 @@ def test_rmcov_lcomp1(gd154): subset = cov.subset('energy', [0, 100]) assert not subset.parameters.empty assert (subset.file2res.parameters['energy'] < 100).all() - cov.sample(1) + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] def test_rmcov_lcomp2(th232): @@ -412,7 +422,9 @@ def test_rmcov_lcomp2(th232): subset = cov.subset('energy', [0, 100]) assert not subset.parameters.empty assert (subset.file2res.parameters['energy'] < 100).all() - cov.sample(1) + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] def test_madland_nix(am241): @@ -460,7 +472,8 @@ def test_laboratory(be9): @needs_njoy -def test_correlated(tmpdir, endf_data): +def test_correlated(tmpdir): + endf_data = os.environ['OPENMC_ENDF_DATA'] endf_file = os.path.join(endf_data, 'neutrons', 'n-014_Si_030.endf') si30 = openmc.data.IncidentNeutron.from_njoy(endf_file, heatr=False) @@ -486,7 +499,8 @@ def test_nbody(tmpdir, h2): @needs_njoy -def test_ace_convert(run_in_tmpdir, endf_data): +def test_ace_convert(run_in_tmpdir): + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') ace_ascii = 'ace_ascii' ace_binary = 'ace_binary' @@ -517,11 +531,3 @@ def test_ace_table_types(): assert TT.from_suffix('20t') == TT.THERMAL_SCATTERING with pytest.raises(ValueError): TT.from_suffix('z') - - -@needs_njoy -def test_high_temperature(endf_data): - endf_file = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') - - # Ensure that from_njoy works when given a high temperature - openmc.data.IncidentNeutron.from_njoy(endf_file, temperatures=[123_456.0]) diff --git a/tests/unit_tests/test_data_photon.py b/tests/unit_tests/test_data_photon.py index aceb82c3a..f7274e9c1 100644 --- a/tests/unit_tests/test_data_photon.py +++ b/tests/unit_tests/test_data_photon.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + from collections.abc import Mapping, Callable import os from pathlib import Path @@ -9,8 +11,9 @@ import openmc.data @pytest.fixture(scope='module') -def elements_endf(endf_data): +def elements_endf(): """Dictionary of element ENDF data indexed by atomic symbol.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] elements = {'H': 1, 'O': 8, 'Al': 13, 'Cu': 29, 'Ag': 47, 'U': 92, 'Pu': 94} data = {} for symbol, Z in elements.items(): @@ -143,33 +146,8 @@ def test_export_to_hdf5(tmpdir, element): # Export to hdf5 again element2.export_to_hdf5(filename, 'w') - -def test_photodat_only(run_in_tmpdir, endf_data): - endf_dir = Path(endf_data) +def test_photodat_only(run_in_tmpdir): + endf_dir = Path(os.environ['OPENMC_ENDF_DATA']) photoatomic_file = endf_dir / 'photoat' / 'photoat-001_H_000.endf' data = openmc.data.IncidentPhoton.from_endf(photoatomic_file) - data.export_to_hdf5('tmp.h5', 'w') - - -def test_from_endf_material(endf_data): - endf_dir = Path(endf_data) - photoatomic_file = endf_dir / 'photoat' / 'photoat-001_H_000.endf' - relaxation_file = endf_dir / 'atomic_relax' / 'atom-001_H_000.endf' - photoatomic = openmc.data.endf.get_evaluations(photoatomic_file)[0] - relaxation = openmc.data.endf.get_evaluations(relaxation_file)[0] - - data = openmc.data.IncidentPhoton.from_endf(photoatomic, relaxation) - - assert data.atomic_number == 1 - assert 502 in data.reactions - assert data.atomic_relaxation.binding_energy['K'] == pytest.approx(13.61) - - -def test_atomic_relaxation_from_endf_material(endf_data): - filename = Path(endf_data) / 'atomic_relax' / 'atom-001_H_000.endf' - material = openmc.data.endf.get_evaluations(filename)[0] - - data = openmc.data.AtomicRelaxation.from_endf(material) - - assert data.binding_energy['K'] == pytest.approx(13.61) - assert data.num_electrons['K'] == pytest.approx(1.0) + data.export_to_hdf5('tmp.h5', 'w') \ No newline at end of file diff --git a/tests/unit_tests/test_data_thermal.py b/tests/unit_tests/test_data_thermal.py index 81ed42b41..61ae61b24 100644 --- a/tests/unit_tests/test_data_thermal.py +++ b/tests/unit_tests/test_data_thermal.py @@ -6,8 +6,6 @@ import random import numpy as np import pytest import openmc.data -from openmc.data.thermal import _THERMAL_NAMES -from openmc.data.njoy import _THERMAL_DATA from . import needs_njoy @@ -15,7 +13,7 @@ from . import needs_njoy @pytest.fixture(scope='module') def h2o(): """H in H2O thermal scattering data.""" - directory = os.path.dirname(openmc.config.get('cross_sections')) + directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS']) filename = os.path.join(directory, 'c_H_in_H2O.h5') return openmc.data.ThermalScattering.from_hdf5(filename) @@ -23,14 +21,15 @@ def h2o(): @pytest.fixture(scope='module') def graphite(): """Graphite thermal scattering data.""" - directory = os.path.dirname(openmc.config.get('cross_sections')) + directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS']) filename = os.path.join(directory, 'c_Graphite.h5') return openmc.data.ThermalScattering.from_hdf5(filename) @pytest.fixture(scope='module') -def h2o_njoy(endf_data): +def h2o_njoy(): """H in H2O generated using NJOY.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] path_h1 = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') path_h2o = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinH2O.endf') return openmc.data.ThermalScattering.from_njoy( @@ -38,15 +37,17 @@ def h2o_njoy(endf_data): @pytest.fixture(scope='module') -def hzrh(endf_data): +def hzrh(): """H in ZrH thermal scattering data.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinZrH.endf') - return openmc.data.ThermalScattering.from_endf(filename, divide_incoherent_elastic=True) + return openmc.data.ThermalScattering.from_endf(filename) @pytest.fixture(scope='module') -def hzrh_njoy(endf_data): +def hzrh_njoy(): """H in ZrH generated using NJOY.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] path_h1 = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') path_hzrh = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinZrH.endf') with_endf_data = openmc.data.ThermalScattering.from_njoy( @@ -59,10 +60,11 @@ def hzrh_njoy(endf_data): @pytest.fixture(scope='module') -def sio2(endf_data): +def sio2(): """SiO2 thermal scattering data.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-SiO2.endf') - return openmc.data.ThermalScattering.from_endf(filename, divide_incoherent_elastic=True) + return openmc.data.ThermalScattering.from_endf(filename) def test_h2o_attributes(h2o): @@ -100,7 +102,8 @@ def test_graphite_xs(graphite): assert elastic([1e-3, 1.0]) == pytest.approx([0.0, 0.62586153]) @needs_njoy -def test_graphite_njoy(endf_data): +def test_graphite_njoy(): + endf_data = os.environ['OPENMC_ENDF_DATA'] path_c0 = os.path.join(endf_data, 'neutrons', 'n-006_C_000.endf') path_gr = os.path.join(endf_data, 'thermal_scatt', 'tsl-graphite.endf') graphite = openmc.data.ThermalScattering.from_njoy( @@ -138,9 +141,10 @@ def test_continuous_dist(h2o_njoy): assert isinstance(dist, openmc.data.IncoherentInelasticAE) -def test_h2o_endf(endf_data): +def test_h2o_endf(): + endf_data = os.environ['OPENMC_ENDF_DATA'] filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinH2O.endf') - h2o = openmc.data.ThermalScattering.from_endf(filename, divide_incoherent_elastic=True) + h2o = openmc.data.ThermalScattering.from_endf(filename) assert not h2o.elastic assert h2o.atomic_weight_ratio == pytest.approx(0.99917) assert h2o.energy_max == pytest.approx(3.99993) @@ -148,18 +152,6 @@ def test_h2o_endf(endf_data): '600K', '650K', '800K'] -def test_from_endf_material(endf_data): - filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinH2O.endf') - material = openmc.data.endf.get_evaluations(filename)[0] - - h2o = openmc.data.ThermalScattering.from_endf( - material, divide_incoherent_elastic=True) - - assert not h2o.elastic - assert h2o.atomic_weight_ratio == pytest.approx(0.99917) - assert h2o.temperatures[0] == '294K' - - def test_hzrh_attributes(hzrh): assert hzrh.atomic_weight_ratio == pytest.approx(0.99917) assert hzrh.energy_max == pytest.approx(1.9734) @@ -272,27 +264,6 @@ def test_get_thermal_name(): assert f('boogie_monster') == 'c_boogie_monster' -def test_thermal_names_data_consistency(): - # Check that keys in _THERMAL_NAMES are also in _THERMAL_DATA - names_only = set(_THERMAL_NAMES.keys()) - set(_THERMAL_DATA.keys()) - assert not names_only, f"Keys in _THERMAL_NAMES but not in _THERMAL_DATA: {names_only}" - - # Check that keys in _THERMAL_DATA are also in _THERMAL_NAMES - data_only = set(_THERMAL_DATA.keys()) - set(_THERMAL_NAMES.keys()) - assert not data_only, f"Keys in _THERMAL_DATA but not in _THERMAL_NAMES: {data_only}" - - # Check that the name from each ThermalTuple in _THERMAL_DATA appears as - # a recognized alias in _THERMAL_NAMES for the same key - missing_aliases = [] - for key, thermal_tuple in _THERMAL_DATA.items(): - name = thermal_tuple.name - if name not in _THERMAL_NAMES[key]: - missing_aliases.append((key, name, _THERMAL_NAMES[key])) - assert not missing_aliases, ( - f"ThermalTuple names not in _THERMAL_NAMES aliases: {missing_aliases}" - ) - - @pytest.fixture def fake_mixed_elastic(): fake_tsl = openmc.data.ThermalScattering("c_D_in_7LiD", 1.9968, 4.9, [0.0253]) @@ -392,7 +363,7 @@ def test_mixed_elastic(fake_mixed_elastic, run_in_tmpdir): model.settings.particles = 1000 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( energy=openmc.stats.Discrete([3.0], [1.0]) # 3 eV source ) model.run() diff --git a/tests/unit_tests/test_deplete_activation.py b/tests/unit_tests/test_deplete_activation.py index 2f1713880..1842ad8ac 100644 --- a/tests/unit_tests/test_deplete_activation.py +++ b/tests/unit_tests/test_deplete_activation.py @@ -11,7 +11,7 @@ import pytest @pytest.fixture def model(): """Sphere of single nuclide""" - model = openmc.Model() + model = openmc.model.Model() w = openmc.Material(name='tungsten') w.add_nuclide('W186', 1.0) @@ -27,13 +27,13 @@ def model(): model.settings.batches = 10 model.settings.particles = 1000 - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( space=openmc.stats.Point(), energy=openmc.stats.Discrete([1.0e6], [1.0]) ) model.settings.run_mode = 'fixed source' - rx_tally = openmc.Tally(name='activation tally') + rx_tally = openmc.Tally() rx_tally.scores = ['(n,gamma)'] model.tallies.append(rx_tally) @@ -45,16 +45,15 @@ ENERGIES = np.logspace(log10(1e-5), log10(2e7), 100) @pytest.mark.parametrize("reaction_rate_mode,reaction_rate_opts,tolerance", [ ("direct", {}, 1e-5), - ("flux", {'energies': ENERGIES}, 0.1), + ("flux", {'energies': ENERGIES}, 0.01), ("flux", {'energies': ENERGIES, 'reactions': ['(n,gamma)']}, 1e-5), - ("flux", {'energies': ENERGIES, 'reactions': ['(n,gamma)'], 'nuclides': ['W186', 'H3']}, 1e-2), + ("flux", {'energies': ENERGIES, 'reactions': ['(n,gamma)'], 'nuclides': ['W186']}, 1e-5), ]) -@pytest.mark.flaky(reruns=1) def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts, tolerance): # Determine (n.gamma) reaction rate using initial run sp = model.run() with openmc.StatePoint(sp) as sp: - tally = sp.get_tally(name='activation tally') + tally = sp.tallies[1] capture_rate = tally.mean.flat[0] # Create one-nuclide depletion chain @@ -62,10 +61,11 @@ def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts w186 = openmc.deplete.Nuclide('W186') w186.add_reaction('(n,gamma)', None, 0.0, 1.0) chain.add_nuclide(w186) + chain.export_to_xml('test_chain.xml') # Create transport operator op = openmc.deplete.CoupledOperator( - model, chain, + model, 'test_chain.xml', normalization_mode="source-rate", reaction_rate_mode=reaction_rate_mode, reaction_rate_opts=reaction_rate_opts, @@ -113,11 +113,6 @@ def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts assert atoms[0] == pytest.approx(n0) assert atoms[1] / atoms[0] == pytest.approx(0.5, rel=tolerance) - # Check that material name is preserved in depletion results - step_result = results[0] - mat_from_results = step_result.get_material(f"{w.id}") - assert mat_from_results.name == 'tungsten' - def test_decay(run_in_tmpdir): """Test decay-only timesteps where no transport solve is performed""" @@ -166,30 +161,3 @@ def test_decay(run_in_tmpdir): # Ensure density goes down by a factor of 2 after each half-life assert atoms[1] / atoms[0] == pytest.approx(0.5) assert atoms[2] / atoms[1] == pytest.approx(0.25) - - -def test_flux_rr_missing_nuclide(run_in_tmpdir, model): - # Create two-nuclide depletion chain -- since W184 is not in the model, this - # test ensures that FluxCollapseHelper loads missing nuclides appropriately - chain = openmc.deplete.Chain() - w184 = openmc.deplete.Nuclide('W184') - w184.add_reaction('(n,gamma)', None, 0.0, 1.0) - chain.add_nuclide(w184) - w186 = openmc.deplete.Nuclide('W186') - w186.add_reaction('(n,gamma)', None, 0.0, 1.0) - chain.add_nuclide(w186) - chain.export_to_xml('test_chain.xml') - - # Create transport operator - op = openmc.deplete.CoupledOperator( - model, 'test_chain.xml', - normalization_mode="source-rate", - reaction_rate_mode="flux", - reaction_rate_opts={'energies': [0.0, 20.0e6]}, - ) - - # Deplete with two decay steps - integrator = openmc.deplete.PredictorIntegrator( - op, [100.0], source_rates=[10.0] - ) - integrator.integrate() diff --git a/tests/unit_tests/test_deplete_chain.py b/tests/unit_tests/test_deplete_chain.py index ef8cb9ef2..4bfdaa63e 100644 --- a/tests/unit_tests/test_deplete_chain.py +++ b/tests/unit_tests/test_deplete_chain.py @@ -5,12 +5,10 @@ from itertools import product from math import log import os from pathlib import Path -import warnings import numpy as np from openmc.mpi import comm from openmc.deplete import Chain, reaction_rates, nuclide, cram, pool -from openmc.stats import Discrete import pytest from tests import cdtemp @@ -54,11 +52,11 @@ def simple_chain(): @pytest.fixture(scope='module') -def endf_chain(endf_data): - endf_dir = Path(endf_data) - decay_data = (endf_dir / 'decay').glob('*.endf') - fpy_data = (endf_dir / 'nfy').glob('*.endf') - neutron_data = (endf_dir / 'neutrons').glob('*.endf') +def endf_chain(): + endf_data = Path(os.environ['OPENMC_ENDF_DATA']) + decay_data = (endf_data / 'decay').glob('*.endf') + fpy_data = (endf_data / 'nfy').glob('*.endf') + neutron_data = (endf_data / 'neutrons').glob('*.endf') return Chain.from_endf(decay_data, fpy_data, neutron_data) @@ -86,14 +84,6 @@ def test_from_endf(endf_chain): assert nuc == chain[nuc.name] -def test_unstable_nuclides(simple_chain: Chain): - assert [nuc.name for nuc in simple_chain.unstable_nuclides] == ["A", "B"] - - -def test_stable_nuclides(simple_chain: Chain): - assert [nuc.name for nuc in simple_chain.stable_nuclides] == ["H1", "C"] - - def test_from_xml(simple_chain): """Read chain_test.xml and ensure all values are correct.""" # Unfortunately, this routine touches a lot of the code, but most of @@ -246,29 +236,6 @@ def test_form_matrix(simple_chain): assert new_mat[r, c] == mat[r, c] -def test_decay_matrix(simple_chain): - """Test that decay_matrix contains only radioactive decay terms.""" - # Nuclide order: H1(0), A(1), B(2), C(3) - decay_A = log(2) / 2.36520E+04 - decay_B = log(2) / 3.29040E+04 - - expected = np.zeros((4, 4)) - expected[1, 1] = -decay_A # Loss: A decays - expected[2, 1] = decay_A * 0.6 # A -> B (branching ratio 0.6) - expected[3, 1] = decay_A * 0.4 # A -> C (branching ratio 0.4) - expected[1, 2] = decay_B # B -> A (branching ratio 1.0) - expected[2, 2] = -decay_B # Loss: B decays - - assert np.allclose(expected, simple_chain.decay_matrix.toarray()) - - -def test_decay_matrix_cached(simple_chain): - """Test that decay_matrix is lazily computed and returns the same object.""" - m1 = simple_chain.decay_matrix - m2 = simple_chain.decay_matrix - assert m1 is m2 - - def test_getitem(): """Test nuc_by_ind converter function.""" chain = Chain() @@ -333,7 +300,8 @@ def test_capture_branch_infer_ground(): # Create nuclide to be added into the chain xe136m = nuclide.Nuclide("Xe136_m1") - chain.add_nuclide(xe136m) + chain.nuclides.append(xe136m) + chain.nuclide_dict[xe136m.name] = len(chain.nuclides) - 1 chain.set_branch_ratios(infer_br, "(n,gamma)") @@ -349,7 +317,8 @@ def test_capture_branch_no_rxn(): u5m = nuclide.Nuclide("U235_m1") - chain.add_nuclide(u5m) + chain.nuclides.append(u5m) + chain.nuclide_dict[u5m.name] = len(chain.nuclides) - 1 with pytest.raises(AttributeError, match="U234"): chain.set_branch_ratios(u4br) @@ -468,9 +437,9 @@ def test_validate(simple_chain): simple_chain["C"].yield_data = {0.0253: {"A": 1.4, "B": 0.6}} assert simple_chain.validate(strict=True, tolerance=0.0) - with warnings.catch_warnings(): - warnings.simplefilter("error") + with pytest.warns(None) as record: assert simple_chain.validate(strict=False, quiet=False, tolerance=0.0) + assert len(record) == 0 # Mess up "earlier" nuclide's reactions decay_mode = simple_chain["A"].decay_modes.pop() @@ -507,15 +476,6 @@ def gnd_simple_chain(): return Chain.from_xml(chainfile) -def test_chain_sources(gnd_simple_chain): - i135 = gnd_simple_chain['I135'] - assert isinstance(i135.sources, dict) - assert list(i135.sources.keys()) == ['photon'] - photon_src = i135.sources['photon'] - assert isinstance(photon_src, Discrete) - assert photon_src.integral() == pytest.approx(3.920996223799345e-05) - - def test_reduce(gnd_simple_chain, endf_chain): ref_U5 = gnd_simple_chain["U235"] ref_iodine = gnd_simple_chain["I135"] @@ -530,7 +490,6 @@ def test_reduce(gnd_simple_chain, endf_chain): assert u5_round0.n_decay_modes == ref_U5.n_decay_modes assert u5_round0.half_life == ref_U5.half_life assert u5_round0.decay_energy == ref_U5.decay_energy - assert u5_round0.sources == ref_U5.sources for newmode, refmode in zip(u5_round0.decay_modes, ref_U5.decay_modes): assert newmode.target is None assert newmode.type == refmode.type @@ -553,7 +512,6 @@ def test_reduce(gnd_simple_chain, endf_chain): assert bareI5.n_decay_modes == ref_iodine.n_decay_modes assert bareI5.half_life == ref_iodine.half_life assert bareI5.decay_energy == ref_iodine.decay_energy - assert bareI5.sources == ref_iodine.sources for newmode, refmode in zip(bareI5.decay_modes, ref_iodine.decay_modes): assert newmode.target is None assert newmode.type == refmode.type diff --git a/tests/unit_tests/test_deplete_continue.py b/tests/unit_tests/test_deplete_continue.py deleted file mode 100644 index 1b6eac238..000000000 --- a/tests/unit_tests/test_deplete_continue.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Unit tests for openmc.deplete continue run capability. - -These tests run in two steps: first a normal run and then a continue run using the previous results -""" - -import pytest -import numpy as np -import openmc.deplete - -from tests import dummy_operator - - -def test_continue(run_in_tmpdir): - """Test to ensure that a properly defined continue run works""" - # set up the problem - bundle = dummy_operator.SCHEMES['predictor'] - operator = dummy_operator.DummyOperator() - - # initial depletion - bundle.solver(operator, [1.0, 2.0], [1.0, 2.0]).integrate(write_rates=True) - - # set up continue run - prev_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - operator = dummy_operator.DummyOperator(prev_res) - - # if continue run happens, test passes - bundle.solver(operator, [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], - continue_timesteps=True).integrate(write_rates=True) - - final_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - - assert np.array_equal( - np.diff(final_res.get_times(time_units="s")), - [1.0, 2.0, 3.0, 4.0] - ) - - -def test_continue_continue(run_in_tmpdir): - """Test to ensure that a continue run can be continued""" - # set up the problem - bundle = dummy_operator.SCHEMES['predictor'] - operator = dummy_operator.DummyOperator() - - # initial depletion - bundle.solver(operator, [1.0, 2.0], [1.0, 2.0]).integrate(write_rates=True) - - # set up continue run - prev_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - operator = dummy_operator.DummyOperator(prev_res) - - # first continue run - bundle.solver(operator, [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], - continue_timesteps=True).integrate(write_rates=True) - - prev_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - # second continue run - bundle.solver(operator, [1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0], - continue_timesteps=True).integrate() - - final_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - - assert np.array_equal( - np.diff(final_res.get_times(time_units="s")), - [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] - ) - - -def test_mismatched_initial_times(run_in_tmpdir): - """Test to ensure that a continue run with different initial steps is properly caught""" - # set up the problem - bundle = dummy_operator.SCHEMES['predictor'] - operator = dummy_operator.DummyOperator() - - # perform initial steps - bundle.solver(operator, [0.75, 0.75], [1.0, 1.0]).integrate() - - # restart - prev_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - operator = dummy_operator.DummyOperator(prev_res) - - with pytest.raises( - ValueError, - match="You are attempting to continue a run in which the previous timesteps " - "do not have the same initial timesteps as those provided to the " - "Integrator. Please make sure you are using the correct timesteps.", - ): - bundle.solver( - operator, [0.75, 0.5, 0.75], [1.0, 1.0, 1.0], continue_timesteps=True - ).integrate() - - -def test_mismatched_initial_source_rates(run_in_tmpdir): - """Test to ensure that a continue run with different initial steps is properly caught""" - # set up the problem - bundle = dummy_operator.SCHEMES['predictor'] - operator = dummy_operator.DummyOperator() - - # perform initial steps - bundle.solver(operator, [0.75, 0.75], [1.0, 1.0]).integrate() - - # restart - prev_res = openmc.deplete.Results(operator.output_dir / "depletion_results.h5") - operator = dummy_operator.DummyOperator(prev_res) - - with pytest.raises( - ValueError, - match="You are attempting to continue a run in which the previous results " - "do not have the same initial source rates, powers, or power densities " - "as those provided to the Integrator. Please make sure you are using " - "the correct powers, power densities, or source rates and previous results file.", - ): - bundle.solver( - operator, [0.75, 0.75, 0.75], [1.0, 2.0, 1.0], continue_timesteps=True - ).integrate() diff --git a/tests/unit_tests/test_deplete_coupled_operator.py b/tests/unit_tests/test_deplete_coupled_operator.py index 119a15923..6de0342b0 100644 --- a/tests/unit_tests/test_deplete_coupled_operator.py +++ b/tests/unit_tests/test_deplete_coupled_operator.py @@ -5,13 +5,12 @@ from pathlib import Path import pytest -from openmc.deplete import CoupledOperator, Chain +from openmc.deplete import CoupledOperator import openmc import numpy as np CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" - @pytest.fixture(scope="module") def model(): fuel = openmc.Material(name="uo2") @@ -38,9 +37,8 @@ def model(): pin_surfaces = [openmc.ZCylinder(r=r) for r in radii] pin_univ = openmc.model.pin(pin_surfaces, materials) - bound_box = openmc.model.RectangularPrism( - 1.24, 1.24, boundary_type="reflective") - root_cell = openmc.Cell(fill=pin_univ, region=-bound_box) + bound_box = openmc.rectangular_prism(1.24, 1.24, boundary_type="reflective") + root_cell = openmc.Cell(fill=pin_univ, region=bound_box) geometry = openmc.Geometry([root_cell]) settings = openmc.Settings() @@ -50,73 +48,8 @@ def model(): return openmc.Model(geometry, materials, settings) - -@pytest.fixture() -def model_with_volumes(): - mat1 = openmc.Material() - mat1.add_element("Ag", 1, percent_type="ao") - mat1.set_density("g/cm3", 10.49) - mat1.depletable = True - mat1.volume = 102 - - mat2 = openmc.Material() - mat2.add_element("Ag", 1, percent_type="ao") - mat2.set_density("g/cm3", 10.49) - - sph1 = openmc.Sphere(r=1.0) - sph2 = openmc.Sphere(r=2.0, x0=3) - sph3 = openmc.Sphere(r=5.0, boundary_type="vacuum") - - cell1 = openmc.Cell(region=-sph1, fill=mat1) - cell1.volume = 4.19 - cell2 = openmc.Cell(region=-sph2, fill=mat1) - cell2.volume = 33.51 - cell3 = openmc.Cell(region=-sph3 & +sph1 & +sph2, fill=mat2) - cell3.volume = 485.9 - - geometry = openmc.Geometry([cell1, cell2, cell3]) - - return openmc.Model(geometry) - - def test_operator_init(model): """The test uses a temporary dummy chain. This file will be removed at the end of the test, and only contains a depletion_chain node.""" CoupledOperator(model, CHAIN_PATH) - - -def test_diff_volume_method_match_cell(model_with_volumes): - """Tests the volumes assigned to the materials match the cell volumes""" - - operator = openmc.deplete.CoupledOperator( - model=model_with_volumes, - diff_burnable_mats=True, - diff_volume_method='match cell', - chain_file=CHAIN_PATH - ) - - all_cells = list(operator.model.geometry.get_all_cells().values()) - assert all_cells[0].fill.volume == 4.19 - assert all_cells[1].fill.volume == 33.51 - # mat2 is not depletable - assert all_cells[2].fill.volume is None - - -def test_diff_volume_method_divide_equally(model_with_volumes): - """Tests the volumes assigned to the materials are divided equally""" - - chain = Chain.from_xml(CHAIN_PATH) - - operator = openmc.deplete.CoupledOperator( - model=model_with_volumes, - diff_burnable_mats=True, - diff_volume_method='divide equally', - chain_file=chain - ) - - all_cells = list(operator.model.geometry.get_all_cells().values()) - assert all_cells[0].fill.volume == 51 - assert all_cells[1].fill.volume == 51 - # mat2 is not depletable - assert all_cells[2].fill.volume is None diff --git a/tests/unit_tests/test_deplete_cram.py b/tests/unit_tests/test_deplete_cram.py index 64cff3a8b..8987fbd7a 100644 --- a/tests/unit_tests/test_deplete_cram.py +++ b/tests/unit_tests/test_deplete_cram.py @@ -1,15 +1,12 @@ -"""Tests for cram.py. +""" Tests for cram.py Compares a few Mathematica matrix exponentials to CRAM16/CRAM48. -Tests substep accuracy against self-converged reference solutions. """ -import numpy as np -import pytest -import scipy.sparse as sp from pytest import approx -from openmc.deplete.cram import (CRAM16, CRAM48, Cram16Solver, Cram48Solver, - IPFCramSolver) +import numpy as np +import scipy.sparse as sp +from openmc.deplete.cram import CRAM16, CRAM48 def test_CRAM16(): @@ -38,63 +35,3 @@ def test_CRAM48(): z0 = np.array((0.904837418035960, 0.576799023327476)) assert z == approx(z0) - - -def test_substeps1_matches_original(): - """substeps=1 must be bitwise identical to original spsolve path.""" - x = np.array([1.0, 1.0]) - mat = sp.csr_matrix([[-1.0, 0.0], [-2.0, -3.0]]) - dt = 0.1 - - z_orig = CRAM48(mat, x, dt) - z_sub1 = CRAM48(mat, x, dt, substeps=1) - - np.testing.assert_array_equal(z_sub1, z_orig) - - -def test_substeps2_matches_two_half_steps(): - """substeps=2 must match two independent CRAM calls with dt/2.""" - x = np.array([1.0, 1.0]) - mat = sp.csr_matrix([[-1.0, 0.0], [-2.0, -3.0]]) - dt = 1.0 - - # Two manual half-steps using original spsolve path - z_half = CRAM48(mat, x, dt / 2) - z_two = CRAM48(mat, z_half, dt / 2) - - # Single call with substeps=2 - z_sub2 = CRAM48(mat, x, dt, substeps=2) - - assert z_sub2 == approx(z_two, rel=1e-12) - - -@pytest.mark.parametrize("substeps", [0, -1]) -def test_invalid_substeps(substeps): - """substeps must be a positive integer at call time.""" - x = np.array([1.0, 1.0]) - mat = sp.csr_matrix([[-1.0, 0.0], [-2.0, -3.0]]) - - with pytest.raises(ValueError, match="substeps"): - CRAM48(mat, x, 0.1, substeps=substeps) - - -def test_substeps_self_convergence(): - """Increasing substeps converges toward reference solution. - - Uses CRAM16 (alpha0 ~ 2e-16) where substep convergence is visible. - CRAM48 (alpha0 ~ 2e-47) is already near machine precision for small - systems; its correctness is verified by the other substep tests. - """ - mat = sp.csr_matrix([[-1.0, 0.0], [-2.0, -3.0]]) - x = np.array([1.0, 1.0]) - dt = 50 # lambda*dt = 50 and 150, stresses CRAM16 - - n_ref = CRAM16(mat, x, dt, substeps=128) - - prev_err = np.inf - for s in [1, 2, 4, 8, 16]: - n_s = CRAM16(mat, x, dt, substeps=s) - err = np.linalg.norm(n_s - n_ref) / np.linalg.norm(n_ref) - assert err < prev_err, \ - f"substeps={s} error {err:.2e} not less than previous {prev_err:.2e}" - prev_err = err diff --git a/tests/unit_tests/test_deplete_decay.py b/tests/unit_tests/test_deplete_decay.py deleted file mode 100644 index db96fcbe2..000000000 --- a/tests/unit_tests/test_deplete_decay.py +++ /dev/null @@ -1,89 +0,0 @@ -from pathlib import Path - -import openmc.deplete -import numpy as np -import pytest - - -def test_deplete_decay_products(run_in_tmpdir): - # Create chain file with H1, He4, and Li5 - with open('test_chain.xml', 'w') as chain_file: - chain_file.write(""" - - - - - - - - - """) - - # Create MicroXS object with no cross sections - micro_xs = openmc.deplete.MicroXS(np.empty((0, 0, 0)), [], []) - - # Create depletion operator with no reactions - op = openmc.deplete.IndependentOperator.from_nuclides( - volume=1.0, - nuclides={'Li5': 1.0}, - flux=0.0, - micro_xs=micro_xs, - chain_file='test_chain.xml', - normalization_mode='source-rate' - ) - - # Create time-integrator and integrate - integrator = openmc.deplete.PredictorIntegrator( - op, timesteps=[1.0], source_rates=[0.0], timestep_units='d' - ) - integrator.integrate(final_step=False) - - # Get concentration of H1 and He4 - results = openmc.deplete.Results('depletion_results.h5') - mat_id = op.materials[0].id - _, h1 = results.get_atoms(f"{mat_id}", "H1") - _, he4 = results.get_atoms(f"{mat_id}", "He4") - - # Since we started with 1e24 atoms of Li5, we should have 1e24 atoms of both - # H1 and He4 - assert h1[1] == pytest.approx(1e24) - assert he4[1] == pytest.approx(1e24) - - -def test_deplete_decay_step_fissionable(run_in_tmpdir): - """Ensures that power is not computed in zero power cases with - fissionable material present. This tests decay calculations without - power, although this specific example does not exhibit any decay. - - Proves github issue #2963 is fixed - """ - - # Set up a pure decay operator - micro_xs = openmc.deplete.MicroXS(np.empty((0, 0, 0)), [], []) - mat = openmc.Material() - mat.name = 'I do not decay.' - mat.add_nuclide('U238', 1.0, 'ao') - mat.volume = 10.0 - mat.set_density('g/cc', 1.0) - original_atoms = mat.get_nuclide_atoms()['U238'] - - mats = openmc.Materials([mat]) - op = openmc.deplete.IndependentOperator( - mats, [1.0], [micro_xs], Path(__file__).parents[1] / "chain_simple.xml") - - # Create time integrator and integrate - integrator = openmc.deplete.PredictorIntegrator( - op, [1.0], power=[0.0], timestep_units='s' - ) - integrator.integrate() - - # Get concentration of U238. It should be unchanged since this chain has no U238 decay. - results = openmc.deplete.Results('depletion_results.h5') - _, u238 = results.get_atoms(f"{mat.id}", "U238") - - assert u238[1] == pytest.approx(original_atoms) - - # Check that material name is preserved in depletion results - step_result = results[0] - mat_from_results = step_result.get_material(f"{mat.id}") - assert mat_from_results.name == 'I do not decay.' diff --git a/tests/unit_tests/test_deplete_external_source_rates.py b/tests/unit_tests/test_deplete_external_source_rates.py deleted file mode 100644 index a8cf9dde5..000000000 --- a/tests/unit_tests/test_deplete_external_source_rates.py +++ /dev/null @@ -1,170 +0,0 @@ -""" Tests for ExternalSourceRates class """ - -from pathlib import Path - -import pytest -import numpy as np -import re - -import openmc -from openmc.data import AVOGADRO, atomic_mass -from openmc.deplete import CoupledOperator -from openmc.deplete.transfer_rates import ExternalSourceRates -from openmc.deplete.abc import (_SECONDS_PER_MINUTE, _SECONDS_PER_HOUR, - _SECONDS_PER_DAY, _SECONDS_PER_JULIAN_YEAR) - -CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" - -@pytest.fixture -def model(): - openmc.reset_auto_ids() - f = openmc.Material(name="f") - f.add_element("U", 1, enrichment=4.25) - f.add_element("O", 2) - f.set_density("g/cm3", 10.4) - - w = openmc.Material(name="w") - w.add_element("O", 1) - w.add_element("H", 2) - w.set_density("g/cm3", 1.0) - w.depletable = True - - # material just to test multiple destination material - h = openmc.Material(name="h") - h.add_element("He", 1) - h.set_density("g/cm3", 1.78e-4) - - radii = [0.42, 0.45] - f.volume = np.pi * radii[0] ** 2 - w.volume = np.pi * (radii[1]**2 - radii[0]**2) - h.volume = 1 - materials = openmc.Materials([f, w, h]) - - surf_f = openmc.Sphere(r=radii[0]) - surf_w = openmc.Sphere(r=radii[1], boundary_type='vacuum') - surf_h = openmc.Sphere(x0=10, r=1, boundary_type='vacuum') - cell_f = openmc.Cell(fill=f, region=-surf_f) - cell_w = openmc.Cell(fill=w, region=+surf_f & -surf_w) - cell_h = openmc.Cell(fill=h, region=-surf_h) - geometry = openmc.Geometry([cell_f, cell_w, cell_h]) - - settings = openmc.Settings() - settings.particles = 1000 - settings.inactive = 10 - settings.batches = 50 - - return openmc.Model(geometry, materials, settings) - - -@pytest.mark.parametrize( -"case_name, external_source_vectors, external_source_rate, timesteps", [ - ('elements', [{'U': 0.9, 'Xe': 0.1}], 1, None), - ('nuclides', [{'I135': 0.1, 'Gd156': 0.3, 'Gd157': 0.6}], 1, None), - ('nuclides_elements', [{'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01, 'U': 0.8, - 'Xe': 0.08}], 1, None), - ('elements_nuclides', [{'U': 0.78, 'Xe': 0.1, 'I135': 0.01, 'Gd156': 0.1, - 'Gd157': 0.01}], 1, None), - ('multiple_vectors', [{'U': 1.}, {'Xe': 1}], 1, None), - ('timesteps', [{'U': 0.9, 'Xe': 0.1}], 1, [1]), - ('rates_invalid_1', [{'Gb': 1.}], 1, None), - ('rates_invalid_2', [{'Pu': 1.}], 1, None) - ]) -def test_get_set(model, case_name, external_source_vectors, external_source_rate, - timesteps): - """Tests the get/set methods""" - - op = CoupledOperator(model, CHAIN_PATH) - number_of_timesteps = 2 - transfer = ExternalSourceRates(op, model.materials, number_of_timesteps) - - if timesteps is None: - timesteps = np.arange(number_of_timesteps) - - # Test by Openmc material, material name and material id - material= [m for m in model.materials if m.depletable][0] - - for material_input in [material, material.name, material.id]: - for external_source_vector in external_source_vectors: - if case_name == 'rates_invalid_1': - with pytest.raises(ValueError, match='Gb is not a valid ' - 'nuclide or element.'): - transfer.set_external_source_rate(material_input, - external_source_vector, - external_source_rate) - elif case_name == 'rates_invalid_2': - with pytest.raises(ValueError, match='Cannot add element Pu'): - transfer.set_external_source_rate(material_input, - external_source_vector, - external_source_rate) - else: - transfer.set_external_source_rate(material_input, - external_source_vector, - external_source_rate, - timesteps=timesteps) - for component, percent in external_source_vector.items(): - split_component = re.split(r'\d+', component) - if len(split_component) == 1: - for nuc, frac in openmc.data.isotopes(component): - val = external_source_rate * percent * frac * \ - AVOGADRO / atomic_mass(nuc) - assert transfer.get_external_rate( - material_input, nuc, timesteps)[0] == pytest.approx(val) - else: - val = external_source_rate * percent * AVOGADRO / atomic_mass(component) - assert transfer.get_external_rate( - material_input, component, timesteps)[0] == pytest.approx(val) - - assert np.all(transfer.external_timesteps == timesteps) - - -@pytest.mark.parametrize("units, unit_conv", [ - ('g/s', 1), - ('g/sec', 1), - ('g/min', _SECONDS_PER_MINUTE), - ('g/minute', _SECONDS_PER_MINUTE), - ('g/h', _SECONDS_PER_HOUR), - ('g/hr', _SECONDS_PER_HOUR), - ('g/hour', _SECONDS_PER_HOUR), - ('g/d', _SECONDS_PER_DAY), - ('g/day', _SECONDS_PER_DAY), - ('g/a', _SECONDS_PER_JULIAN_YEAR), - ('g/year', _SECONDS_PER_JULIAN_YEAR), - ]) -def test_units(units, unit_conv, model): - """ Units testing""" - # create external rate Xe - components = ['Xe135', 'U235'] - external_source_rate = 1.0 - number_of_timesteps = 2 - op = CoupledOperator(model, CHAIN_PATH) - transfer = ExternalSourceRates(op, model.materials, number_of_timesteps) - timesteps = np.arange(number_of_timesteps) - - for component in components: - rate = external_source_rate * unit_conv * atomic_mass(component) / AVOGADRO - transfer.set_external_source_rate('f', {component: 1}, rate, rate_units=units) - assert transfer.get_external_rate( - 'f', component, timesteps)[0] == pytest.approx(external_source_rate) - - -def test_external_source(run_in_tmpdir, model): - """Tests external source depletion class without neither reaction rates nor - decay but only external source rates""" - # create transfer rate for U - vector = {'U235': 1} - external_source = 10 # grams - op = CoupledOperator(model, CHAIN_PATH) - integrator = openmc.deplete.PredictorIntegrator( - op, [1, 1], 0.0, timestep_units = 'd') - integrator.add_external_source_rate('f', vector, external_source/(24*3600)) - integrator.integrate() - - # Get number of U238 atoms from results - results = openmc.deplete.Results('depletion_results.h5') - _, atoms = results.get_atoms(model.materials[0], "U235") - - # Ensure number of atoms equal external source - assert atoms[1] - atoms[0] == pytest.approx( - external_source * AVOGADRO / atomic_mass('U235')) - assert atoms[2] - atoms[1] == pytest.approx( - external_source * AVOGADRO / atomic_mass('U235')) diff --git a/tests/unit_tests/test_deplete_fission_yields.py b/tests/unit_tests/test_deplete_fission_yields.py index 1937e61e3..b603710f3 100644 --- a/tests/unit_tests/test_deplete_fission_yields.py +++ b/tests/unit_tests/test_deplete_fission_yields.py @@ -27,8 +27,8 @@ def materials(tmpdir_factory): mfuel.add_nuclide(nuclide, 1.0) openmc.Materials([mfuel]).export_to_xml() # Geometry - box = openmc.model.RectangularPrism(1.0, 1.0, boundary_type="reflective") - cell = openmc.Cell(fill=mfuel, region=-box) + box = openmc.rectangular_prism(1.0, 1.0, boundary_type="reflective") + cell = openmc.Cell(fill=mfuel, region=box) root = openmc.Universe(cells=[cell]) openmc.Geometry(root).export_to_xml() # settings diff --git a/tests/unit_tests/test_deplete_independent_operator.py b/tests/unit_tests/test_deplete_independent_operator.py index aca83399a..f6cc7e200 100644 --- a/tests/unit_tests/test_deplete_independent_operator.py +++ b/tests/unit_tests/test_deplete_independent_operator.py @@ -5,14 +5,13 @@ from pathlib import Path import pytest - -from openmc import Material -from openmc.deplete import IndependentOperator, MicroXS, Chain +from openmc.deplete import IndependentOperator, MicroXS +from openmc import Material, Materials +import numpy as np CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" ONE_GROUP_XS = Path(__file__).parents[1] / "micro_xs_simple.csv" - def test_operator_init(): """The test uses a temporary dummy chain. This file will be removed at the end of the test, and only contains a depletion_chain node.""" @@ -23,33 +22,15 @@ def test_operator_init(): 'U236': 4.5724195495061115e+18, 'O16': 4.639065406771322e+22, 'O17': 1.7588724018066158e+19} - flux = 1.0 micro_xs = MicroXS.from_csv(ONE_GROUP_XS) - chain = Chain.from_xml(CHAIN_PATH) IndependentOperator.from_nuclides( - volume, nuclides, flux, micro_xs, chain, nuc_units='atom/cm3') + volume, nuclides, micro_xs, CHAIN_PATH, nuc_units='atom/cm3') fuel = Material(name="uo2") fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) fuel.add_element("O", 2) fuel.set_density("g/cc", 10.4) - fuel.depletable = True + fuel.depletable=True fuel.volume = 1 - materials = [fuel] - fluxes = [1.0] - micros = [micro_xs] - IndependentOperator(materials, fluxes, micros, CHAIN_PATH) - - -def test_error_handling(): - micro_xs = MicroXS.from_csv(ONE_GROUP_XS) - fuel = Material(name="oxygen") - fuel.add_element("O", 2) - fuel.set_density("g/cc", 1) - fuel.depletable = True - fuel.volume = 1 - materials = [fuel] - fluxes = [1.0, 2.0] - micros = [micro_xs] - with pytest.raises(ValueError, match=r"The length of fluxes \(2\)"): - IndependentOperator(materials, fluxes, micros, CHAIN_PATH) + materials = Materials([fuel]) + IndependentOperator(materials, micro_xs, CHAIN_PATH) diff --git a/tests/unit_tests/test_deplete_integrator.py b/tests/unit_tests/test_deplete_integrator.py index ec886e707..cb6374152 100644 --- a/tests/unit_tests/test_deplete_integrator.py +++ b/tests/unit_tests/test_deplete_integrator.py @@ -10,7 +10,6 @@ import copy from random import uniform from unittest.mock import MagicMock -import h5py import numpy as np from uncertainties import ufloat import pytest @@ -19,7 +18,7 @@ from openmc.mpi import comm from openmc.deplete import ( ReactionRates, StepResult, Results, OperatorResult, PredictorIntegrator, CECMIntegrator, CF4Integrator, CELIIntegrator, EPCRK4Integrator, - LEQIIntegrator, SICELIIntegrator, SILEQIIntegrator, cram, pool) + LEQIIntegrator, SICELIIntegrator, SILEQIIntegrator, cram) from tests import dummy_operator @@ -39,7 +38,9 @@ INTEGRATORS = [ def test_results_save(run_in_tmpdir): """Test data save module""" - rng = np.random.RandomState(comm.rank) + stages = 3 + + np.random.seed(comm.rank) # Mock geometry op = MagicMock() @@ -59,26 +60,34 @@ def test_results_save(run_in_tmpdir): burn_list = full_burn_list[2*comm.rank: 2*comm.rank + 2] nuc_list = ["na", "nb"] - name_list = {mat: "" for mat in full_burn_list} op.get_results_info.return_value = ( - vol_dict, nuc_list, burn_list, full_burn_list, name_list) + vol_dict, nuc_list, burn_list, full_burn_list) - # Construct end-of-step concentrations - x1 = [rng.random(2), rng.random(2)] - x2 = [rng.random(2), rng.random(2)] + # Construct x + x1 = [] + x2 = [] - # Construct reaction rates + for i in range(stages): + x1.append([np.random.rand(2), np.random.rand(2)]) + x2.append([np.random.rand(2), np.random.rand(2)]) + + # Construct r r1 = ReactionRates(burn_list, ["na", "nb"], ["ra", "rb"]) - r1[:] = rng.random((2, 2, 2)) - rate1 = copy.deepcopy(r1) + r1[:] = np.random.rand(2, 2, 2) - r2 = ReactionRates(burn_list, ["na", "nb"], ["ra", "rb"]) - r2[:] = rng.random((2, 2, 2)) - rate2 = copy.deepcopy(r2) + rate1 = [] + rate2 = [] - # Create global terms (eigenvalue and uncertainty) - eigvl1 = rng.random(2) - eigvl2 = rng.random(2) + for i in range(stages): + rate1.append(copy.deepcopy(r1)) + r1[:] = np.random.rand(2, 2, 2) + rate2.append(copy.deepcopy(r1)) + r1[:] = np.random.rand(2, 2, 2) + + # Create global terms + # Col 0: eig, Col 1: uncertainty + eigvl1 = np.random.rand(stages, 2) + eigvl2 = np.random.rand(stages, 2) eigvl1 = comm.bcast(eigvl1, root=0) eigvl2 = comm.bcast(eigvl2, root=0) @@ -86,35 +95,23 @@ def test_results_save(run_in_tmpdir): t1 = [0.0, 1.0] t2 = [1.0, 2.0] - op_result1 = OperatorResult(ufloat(*eigvl1), rate1) - op_result2 = OperatorResult(ufloat(*eigvl2), rate2) - - # saves within a subdirectory - StepResult.save( - op, - x1, - op_result1, - t1, - 0, - 0, - write_rates=True, - path='out/put/depletion.h5' - ) - res = Results('out/put/depletion.h5') - - # saves with default filename - StepResult.save(op, x1, op_result1, t1, 0, 0, write_rates=True) - StepResult.save(op, x2, op_result2, t2, 0, 1, write_rates=True) + op_result1 = [OperatorResult(ufloat(*k), rates) + for k, rates in zip(eigvl1, rate1)] + op_result2 = [OperatorResult(ufloat(*k), rates) + for k, rates in zip(eigvl2, rate2)] + StepResult.save(op, x1, op_result1, t1, 0, 0) + StepResult.save(op, x2, op_result2, t2, 0, 1) # Load the files res = Results("depletion_results.h5") - for mat_i, mat in enumerate(burn_list): - for nuc_i, nuc in enumerate(nuc_list): - assert res[0][mat, nuc] == x1[mat_i][nuc_i] - assert res[1][mat, nuc] == x2[mat_i][nuc_i] - np.testing.assert_array_equal(res[0].rates, rate1) - np.testing.assert_array_equal(res[1].rates, rate2) + for i in range(stages): + for mat_i, mat in enumerate(burn_list): + for nuc_i, nuc in enumerate(nuc_list): + assert res[0][i, mat, nuc] == x1[i][mat_i][nuc_i] + assert res[1][i, mat, nuc] == x2[i][mat_i][nuc_i] + np.testing.assert_array_equal(res[0].rates[i], rate1[i]) + np.testing.assert_array_equal(res[1].rates[i], rate2[i]) np.testing.assert_array_equal(res[0].k, eigvl1) np.testing.assert_array_equal(res[0].time, t1) @@ -123,32 +120,6 @@ def test_results_save(run_in_tmpdir): np.testing.assert_array_equal(res[1].time, t2) -def test_results_save_without_rates(run_in_tmpdir): - """StepResult.save skips reaction-rate datasets by default""" - - op = MagicMock() - op.prev_res = None - vol_dict = {"0": 1.0} - nuc_list = ["na"] - burn_list = ["0"] - name_list = {mat: "" for mat in burn_list} - op.get_results_info.return_value = (vol_dict, nuc_list, burn_list, burn_list, name_list) - - x = [np.array([1.0])] - rates = ReactionRates(burn_list, nuc_list, ["ra"]) - rates[:] = np.array([[[2.0]]]) - op_result = OperatorResult(ufloat(1.0, 0.1), rates) - - StepResult.save(op, x, op_result, [0.0, 1.0], 0.0, 0) - - with h5py.File('depletion_results.h5', 'r') as handle: - assert 'reaction rates' not in handle - assert 'reactions' not in handle - - res = Results('depletion_results.h5') - assert res[0].rates.size == 0 - - def test_bad_integrator_inputs(): """Test failure modes for Integrator inputs""" @@ -183,39 +154,15 @@ def test_bad_integrator_inputs(): with pytest.raises(TypeError, match=".*callable.*NoneType"): PredictorIntegrator(op, timesteps, power=1, solver=None) - with pytest.raises(ValueError, match="four arguments"): + with pytest.raises(ValueError, match=".*arguments"): PredictorIntegrator(op, timesteps, power=1, solver=mock_bad_solver_nargs) - with pytest.raises(ValueError, match="default to 1"): - PredictorIntegrator(op, timesteps, power=1, - solver=mock_bad_solver_fourth_required) - with pytest.raises(ValueError, match="substeps"): - PredictorIntegrator(op, timesteps, power=1, substeps=0) - - with pytest.raises(ValueError, match="substeps"): - PredictorIntegrator(op, timesteps, power=1, substeps=-1) - - -def mock_good_solver(A, n, t, substeps=1): - return n.copy() - - -def mock_good_solver_substeps(A, n, t, substeps=1): - return n + substeps - - -def mock_unsupported_substeps_solver(A, n, t, substeps=1): - if substeps > 1: - raise NotImplementedError("substeps > 1 not supported") - return n.copy() - - -def mock_bad_solver_nargs(A, n): +def mock_good_solver(A, n, t): pass -def mock_bad_solver_fourth_required(A, n, t, substeps): +def mock_bad_solver_nargs(A, n): pass @@ -250,71 +197,13 @@ def test_integrator(run_in_tmpdir, scheme): integrator = bundle.solver(operator, [0.75], 1, solver="cram16") assert integrator.solver is cram.CRAM16 - integrator = bundle.solver(operator, [0.75], 1, solver=cram.Cram48Solver, - substeps=2) - assert integrator.solver is cram.Cram48Solver - assert integrator.substeps == 2 - integrator.solver = mock_good_solver assert integrator.solver is mock_good_solver - lfunc = lambda A, n, t, substeps=1: mock_good_solver(A, n, t, substeps) + lfunc = lambda A, n, t: mock_good_solver(A, n, t) integrator.solver = lfunc assert integrator.solver is lfunc - integrator.solver = mock_good_solver_substeps - assert integrator.solver is mock_good_solver_substeps - - -def test_custom_solver_with_default_substeps(monkeypatch): - operator = dummy_operator.DummyOperator() - n = operator.initial_condition() - rates = operator(n, 1.0).rates - integrator = PredictorIntegrator( - operator, [0.75], power=1.0, solver=mock_good_solver) - monkeypatch.setattr(pool, "USE_MULTIPROCESSING", False) - - _, result = integrator._timed_deplete(n, rates, 0.75) - - np.testing.assert_array_equal(result[0], n[0]) - - -def test_substep_aware_custom_solver_receives_substeps(monkeypatch): - operator = dummy_operator.DummyOperator() - n = operator.initial_condition() - rates = operator(n, 1.0).rates - integrator = PredictorIntegrator( - operator, [0.75], power=1.0, solver=mock_good_solver_substeps, - substeps=3) - monkeypatch.setattr(pool, "USE_MULTIPROCESSING", False) - - _, result = integrator._timed_deplete(n, rates, 0.75) - - np.testing.assert_array_equal(result[0], n[0] + 3) - - -def test_custom_solver_propagates_substeps_error(monkeypatch): - operator = dummy_operator.DummyOperator() - n = operator.initial_condition() - rates = operator(n, 1.0).rates - integrator = PredictorIntegrator( - operator, [0.75], power=1.0, - solver=mock_unsupported_substeps_solver, substeps=2) - monkeypatch.setattr(pool, "USE_MULTIPROCESSING", False) - - with pytest.raises(NotImplementedError, match="not supported"): - integrator._timed_deplete(n, rates, 0.75) - - -def test_custom_solver_requires_four_args(): - op = MagicMock() - op.prev_res = None - op.chain = None - op.heavy_metal = 1.0 - - with pytest.raises(ValueError, match="four arguments"): - PredictorIntegrator(op, [1], power=1, solver=mock_bad_solver_nargs) - @pytest.mark.parametrize("integrator", INTEGRATORS) def test_timesteps(integrator): diff --git a/tests/unit_tests/test_deplete_keff_search_control.py b/tests/unit_tests/test_deplete_keff_search_control.py deleted file mode 100644 index 425b8f840..000000000 --- a/tests/unit_tests/test_deplete_keff_search_control.py +++ /dev/null @@ -1,116 +0,0 @@ -""" Tests for KeffSearchControl class """ - -from pathlib import Path - -import pytest -import numpy as np - -import openmc -import openmc.lib -from openmc.deplete import CoupledOperator - -CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" - - -def make_model(): - f = openmc.Material(name="fuel") - f.add_element("U", 1, percent_type="ao", enrichment=4.25) - f.add_element("O", 2) - f.set_density("g/cc", 10.4) - f.temperature = 293.15 - - w = openmc.Material(name="water") - w.add_element("O", 1) - w.add_element("H", 2) - w.set_density("g/cc", 1.0) - w.temperature = 293.15 - w.depletable = True - - h = openmc.Material(name='helium') - h.add_element('He', 1) - h.set_density('g/cm3', 0.001598) - - radii = [0.42, 0.45] - height = 0.5 - - f.volume = np.pi * radii[0] ** 2 * height - w.volume = np.pi * (radii[1]**2 - radii[0]**2) * height/2 - - materials = openmc.Materials([f, w, h]) - - surf_interface = openmc.ZPlane(z0=0) - surf_top = openmc.ZPlane(z0=height/2) - surf_bot = openmc.ZPlane(z0=-height/2) - surf_in = openmc.Sphere(r=radii[0]) - surf_out = openmc.Sphere(r=radii[1], boundary_type='vacuum') - - cell_water = openmc.Cell(fill=w, region=-surf_interface) - cell_helium = openmc.Cell(fill=h, region=+surf_interface) - universe = openmc.Universe(cells=(cell_water, cell_helium)) - cell_fuel = openmc.Cell(name='fuel_cell', fill=f, - region=-surf_in & -surf_top & +surf_bot) - cell_universe = openmc.Cell(name='universe_cell',fill=universe, - region=+surf_in & -surf_out & -surf_top & +surf_bot) - geometry = openmc.Geometry([cell_fuel, cell_universe]) - - settings = openmc.Settings() - settings.particles = 1000 - settings.inactive = 10 - settings.batches = 50 - - return openmc.Model(geometry, materials, settings) - - -def translate_cell(position): - """Helper function to translate a cell""" - cell = [c for c in openmc.lib.cells.values() if c.name == 'universe_cell'][0] - openmc.lib.cells[cell.id].translation = [0, 0, position] - return position - - -def rotate_cell(angle): - """Helper function to rotate a cell""" - cell = [c for c in openmc.lib.cells.values() if c.name == 'universe_cell'][0] - openmc.lib.cells[cell.id].rotation = [0, 0, angle] - return angle - - -def set_u235_density(u235_density): - """Helper function to set the U235 density directly""" - fuel = [m for m in openmc.lib.materials.values() if m.name == 'fuel'][0] - nuclides = openmc.lib.materials[fuel.id].nuclides - densities = openmc.lib.materials[fuel.id].densities - u235_idx = nuclides.index('U235') - densities[u235_idx] = u235_density - openmc.lib.materials[fuel.id].set_densities(nuclides, densities) - return u235_density - - -@pytest.mark.parametrize("function, x0, x1, bracket", [ - (translate_cell, -1.0, 1.0, (-5.0, 5.0)), - (rotate_cell, -45.0, 45.0, (-90.0, 90.0)), - (set_u235_density, 0.8, 1.2, (0.5, 1.5)) -]) -def test_integrator_add_keff_search_control(run_in_tmpdir, function, x0, x1, bracket): - """Test adding add_keff_search_control to integrator""" - model = make_model() - operator = CoupledOperator(model, CHAIN_PATH) - integrator = openmc.deplete.PredictorIntegrator( - operator, [1, 1], 0.0, timestep_units='d') - - integrator.add_keff_search_control( - function=function, - x0=x0, - x1=x1, - bracket=bracket, - k_tol=0.1, - output=False, - ) - - assert integrator._keff_search_control.x0 == x0 - assert integrator._keff_search_control.x1 == x1 - assert integrator._keff_search_control.function == function - assert integrator._keff_search_control.search_kwargs['x_min'] == bracket[0] - assert integrator._keff_search_control.search_kwargs['x_max'] == bracket[1] - assert integrator._keff_search_control.search_kwargs['k_tol'] == 0.1 - assert not integrator._keff_search_control.search_kwargs['output'] diff --git a/tests/unit_tests/test_deplete_microxs.py b/tests/unit_tests/test_deplete_microxs.py index 0b1937fac..557082eda 100644 --- a/tests/unit_tests/test_deplete_microxs.py +++ b/tests/unit_tests/test_deplete_microxs.py @@ -6,15 +6,12 @@ to a custom file with new depletion_chain node from os import remove from pathlib import Path -from unittest.mock import patch import pytest -import openmc -from openmc.deplete import MicroXS, get_microxs_and_flux +from openmc.deplete import MicroXS import numpy as np ONE_GROUP_XS = Path(__file__).parents[1] / "micro_xs_simple.csv" -CHAIN_FILE = Path(__file__).parents[1] / "chain_simple.xml" def test_from_array(): @@ -46,268 +43,17 @@ def test_from_array(): [0., 0.], [0., 0.1], [0., 0.1]]) - data.shape = (12, 2, 1) - - MicroXS(data, nuclides, reactions) - with pytest.raises(ValueError, match='Data array must be 3D'): - MicroXS(data[:, 0], nuclides, reactions) + MicroXS.from_array(nuclides, reactions, data) + with pytest.raises(ValueError, match=r'Nuclides list of length \d* and ' + r'reactions array of length \d* do not ' + r'match dimensions of data array of shape \(\d*\,d*\)'): + MicroXS.from_array(nuclides, reactions, data[:, 0]) def test_csv(): ref_xs = MicroXS.from_csv(ONE_GROUP_XS) ref_xs.to_csv('temp_xs.csv') temp_xs = MicroXS.from_csv('temp_xs.csv') - assert np.all(ref_xs.data == temp_xs.data) + assert np.all(ref_xs == temp_xs) remove('temp_xs.csv') - -def test_from_multigroup_flux(): - energies = [0., 6.25e-1, 5.53e3, 8.21e5, 2.e7] - flux = [1.1e-7, 1.2e-6, 1.3e-5, 1.4e-4] - chain_file = Path(__file__).parents[1] / 'chain_simple.xml' - kwargs = {'multigroup_flux': flux, 'chain_file': chain_file} - - # test with energy group structure from string - microxs = MicroXS.from_multigroup_flux(energies='CASMO-4', **kwargs) - assert isinstance(microxs, MicroXS) - - # test with energy group structure as floats - microxs = MicroXS.from_multigroup_flux(energies=energies, **kwargs) - assert isinstance(microxs, MicroXS) - - # test with nuclides provided - microxs = MicroXS.from_multigroup_flux( - energies=energies, nuclides=['Gd157', 'H1'], **kwargs - ) - assert isinstance(microxs, MicroXS) - assert microxs.nuclides == ['Gd157', 'H1'] - - # test with reactions provided - microxs = MicroXS.from_multigroup_flux( - energies=energies, reactions=['fission', '(n,2n)'], **kwargs - ) - assert isinstance(microxs, MicroXS) - assert microxs.reactions == ['fission', '(n,2n)'] - - -def test_multigroup_flux_same(): - chain_file = Path(__file__).parents[1] / 'chain_simple.xml' - - # Generate micro XS based on 4-group flux - energies = [0., 6.25e-1, 5.53e3, 8.21e5, 2.e7] - flux_per_ev = [0.3, 0.3, 1.0, 1.0] - flux = flux_per_ev * np.diff(energies) - flux_sum = flux.sum() - microxs_4g = MicroXS.from_multigroup_flux( - energies=energies, multigroup_flux=flux, chain_file=chain_file) - - # from_multigroup_flux should not modify the flux - assert flux.sum() == flux_sum - - # Generate micro XS based on 2-group flux, where the boundaries line up with - # the 4 group flux and have the same flux per eV across the full energy - # range - energies = [0., 5.53e3, 2.0e7] - flux_per_ev = [0.3, 1.0] - flux = flux_per_ev * np.diff(energies) - microxs_2g = MicroXS.from_multigroup_flux( - energies=energies, multigroup_flux=flux, chain_file=chain_file) - - assert microxs_4g.data == pytest.approx(microxs_2g.data) - - -def test_microxs_zero_flux(): - chain_file = Path(__file__).parents[1] / 'chain_simple.xml' - - # Generate micro XS based on zero flux - energies = [0., 6.25e-1, 5.53e3, 8.21e5, 2.e7] - flux = [0.0, 0.0, 0.0, 0.0] - microxs = MicroXS.from_multigroup_flux( - energies=energies, multigroup_flux=flux, chain_file=chain_file) - - # All microscopic cross sections should be zero - assert np.all(microxs.data == 0.0) - - -def test_hybrid_tally_setup(): - """In hybrid mode a 1-group RR tally is added alongside the flux tally.""" - # Create a simple model with one material and a few nuclides for testing - model = openmc.Model() - mat = openmc.Material(components={'U235': 1.0, 'O16': 2.0}) - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere, fill=mat) - model.geometry = openmc.Geometry([cell]) - model.settings.batches = 2 - model.settings.particles = 10 - - # Define 2-group energy structure for the test - energies = [0., 0.625, 2.0e7] - - # Function to replace Model.run and capture the tallies that were created - captured = {} - def capture_run(**kwargs): - captured['tallies'] = list(model.tallies) - raise StopIteration - - # Call get_microxs_and_flux but replace Model.run with a function that - # captures the tallies and raises StopIteration to exit early - with patch.object(model, 'run', side_effect=capture_run): - with pytest.raises(StopIteration): - get_microxs_and_flux( - model, [mat], - nuclides=['U235', 'O16'], - reactions=['fission', '(n,gamma)'], - energies=energies, - reaction_rate_mode='flux', - reaction_rate_opts={'nuclides': ['U235'], 'reactions': ['fission']}, - chain_file=CHAIN_FILE, - ) - - # Check that both tallies were created with the expected properties - tally_names = [t.name for t in captured['tallies']] - assert 'MicroXS flux 0' in tally_names - assert 'MicroXS RR 0' in tally_names - - # Check that the RR tally has the expected nuclides and reactions - rr = next(t for t in captured['tallies'] if t.name == 'MicroXS RR 0') - assert rr.nuclides == ['U235'] - assert rr.scores == ['fission'] - - # RR tally must use a 1-group energy filter spanning the full energy range - ef = next(f for f in rr.filters if isinstance(f, openmc.EnergyFilter)) - assert len(ef.values) == 2 - assert ef.values[0] == pytest.approx(energies[0]) - assert ef.values[-1] == pytest.approx(energies[-1]) - - -def _simple_model(): - model = openmc.Model() - mat = openmc.Material(components={'H1': 1.0, 'H2': 1.0}, - density=5.0, density_units='g/cm3') - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere, fill=mat) - model.geometry = openmc.Geometry([cell]) - model.settings.particles = 100 - model.settings.batches = 5 - model.settings.run_mode = 'fixed source' - return model, mat - - -def test_hybrid_tally_defaults_to_all_nuclides(run_in_tmpdir): - energies = [0., 0.625, 2.0e7] - kwargs = { - 'nuclides': ['H1', 'H2'], - 'reactions': ['(n,2n)', '(n,gamma)'], - 'energies': energies, - 'reaction_rate_mode': 'flux', - 'chain_file': CHAIN_FILE, - } - - model, mat = _simple_model() - default_fluxes, default_micros = get_microxs_and_flux( - model, [mat], reaction_rate_opts={'reactions': ['(n,2n)']}, **kwargs - ) - - model, mat = _simple_model() - explicit_fluxes, explicit_micros = get_microxs_and_flux( - model, [mat], - reaction_rate_opts={ - 'nuclides': ['H1', 'H2'], - 'reactions': ['(n,2n)'] - }, - **kwargs - ) - - np.testing.assert_allclose(default_fluxes[0], explicit_fluxes[0]) - np.testing.assert_allclose(default_micros[0].data, explicit_micros[0].data) - assert default_micros[0].nuclides == explicit_micros[0].nuclides - assert default_micros[0].reactions == explicit_micros[0].reactions - - -def test_flux_mode_returns_one_group_flux(run_in_tmpdir): - model, mat = _simple_model() - fluxes, micros = get_microxs_and_flux( - model, [mat], - nuclides=['H1'], - reactions=['(n,2n)'], - energies=[0., 0.625, 2.0e7], - reaction_rate_mode='flux', - chain_file=CHAIN_FILE, - ) - - assert fluxes[0].shape == (1,) - assert micros[0].data.shape == (1, 1, 1) - assert fluxes[0][0] > 0.0 - -# --------------------------------------------------------------------------- -# Tests for MicroXS.merge() -# --------------------------------------------------------------------------- - -def _make_microxs(nuclides, reactions, values, groups=1): - """Helper: build a MicroXS from a flat list of values (nuclide-major order).""" - data = np.array(values, dtype=float).reshape( - len(nuclides), len(reactions), groups) - return MicroXS(data, nuclides, reactions) - - -def test_merge_disjoint(): - """Merging two MicroXS with no overlapping nuclides or reactions.""" - m1 = _make_microxs(['U235', 'U238'], ['fission', '(n,gamma)'], - [1., 2., 3., 4.]) - m2 = _make_microxs(['Pu239'], ['(n,2n)'], [5.]) - - merged = m1.merge(m2) - - assert merged.nuclides == ['U235', 'U238', 'Pu239'] - assert merged.reactions == ['fission', '(n,gamma)', '(n,2n)'] - assert merged.data.shape == (3, 3, 1) - - # Self data preserved - assert merged['U235', 'fission'] == pytest.approx([1.]) - assert merged['U238', '(n,gamma)'] == pytest.approx([4.]) - # New data from other - assert merged['Pu239', '(n,2n)'] == pytest.approx([5.]) - # Cross-terms that had no data should be zero - assert merged['U235', '(n,2n)'] == pytest.approx([0.]) - assert merged['Pu239', 'fission'] == pytest.approx([0.]) - - -def test_merge_prefer_other(): - """prefer='other': other overwrites shared entries, adds new ones.""" - # m1: U235 and U238, reactions fission and (n,gamma) - m1 = _make_microxs(['U235', 'U238'], ['fission', '(n,gamma)'], - [1., 2., 3., 4.]) - # m2: only U235, reactions fission (overlap) and (n,2n) (new) - m2 = _make_microxs(['U235'], ['fission', '(n,2n)'], [9., 5.]) - - merged = m1.merge(m2) - - # Nuclide/reaction sets - assert set(merged.nuclides) == {'U235', 'U238'} - assert set(merged.reactions) == {'fission', '(n,gamma)', '(n,2n)'} - - # U235/fission overwritten by m2 - assert merged['U235', 'fission'] == pytest.approx([9.]) - # U235/(n,gamma) untouched - assert merged['U235', '(n,gamma)'] == pytest.approx([2.]) - # New reaction added from m2 - assert merged['U235', '(n,2n)'] == pytest.approx([5.]) - # U238 data preserved - assert merged['U238', 'fission'] == pytest.approx([3.]) - assert merged['U238', '(n,gamma)'] == pytest.approx([4.]) - # U238/(n,2n) not in either → zero - assert merged['U238', '(n,2n)'] == pytest.approx([0.]) - - -def test_merge_prefer_self(): - """prefer='self': shared pairs keep self's value; new entries use other's value.""" - m1 = _make_microxs(['U235', 'U238'], ['fission', '(n,gamma)'], - [1., 2., 3., 4.]) - m2 = _make_microxs(['U235'], ['fission', '(n,2n)'], [9., 5.]) - - merged = m1.merge(m2, prefer='self') - - # U235/fission: self wins - assert merged['U235', 'fission'] == pytest.approx([1.]) - # U235/(n,2n): other used - assert merged['U235', '(n,2n)'] == pytest.approx([5.]) diff --git a/tests/unit_tests/test_deplete_nuclide.py b/tests/unit_tests/test_deplete_nuclide.py index f2bb7d1b6..705beb32a 100644 --- a/tests/unit_tests/test_deplete_nuclide.py +++ b/tests/unit_tests/test_deplete_nuclide.py @@ -1,9 +1,7 @@ """Tests for the openmc.deplete.Nuclide class.""" -import copy -import warnings +import xml.etree.ElementTree as ET -import lxml.etree as ET import numpy as np import pytest from openmc.deplete import nuclide @@ -278,9 +276,9 @@ def test_validate(): } # nuclide is good and should have no warnings raise - with warnings.catch_warnings(): - warnings.simplefilter("error") + with pytest.warns(None) as record: assert nuc.validate(strict=True, quiet=False, tolerance=0.0) + assert len(record) == 0 # invalidate decay modes decay = nuc.decay_modes.pop() @@ -337,14 +335,3 @@ def test_validate(): assert "decay mode" in record[0].message.args[0] assert "0 reaction" in record[1].message.args[0] assert "1.0" in record[2].message.args[0] - - -def test_deepcopy(): - """Test deepcopying a FissionYield object""" - nuc = nuclide.FissionYield(products=("I129", "Sm149", "Xe135"), yields=np.array((0.001, 0.0003, 0.002))) - copied_nuc = copy.deepcopy(nuc) - # Check the deepcopy equals the original - assert copied_nuc == nuc - # Mutate the original and verify the copy remains intact - nuc *= 2 - assert copied_nuc != nuc diff --git a/tests/unit_tests/test_deplete_operator.py b/tests/unit_tests/test_deplete_operator.py index 6ea89fc4a..5fe8715ac 100644 --- a/tests/unit_tests/test_deplete_operator.py +++ b/tests/unit_tests/test_deplete_operator.py @@ -1,15 +1,37 @@ """Basic unit tests for openmc.deplete.Operator instantiation +Modifies and resets environment variable OPENMC_CROSS_SECTIONS +to a custom file with new depletion_chain node """ from pathlib import Path +import pytest from openmc.deplete.abc import TransportOperator -from openmc.deplete.chain import Chain +from openmc.deplete.chain import Chain, _find_chain_file +BARE_XS_FILE = "bare_cross_sections.xml" CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" +@pytest.fixture() +def bare_xs(run_in_tmpdir): + """Create a very basic cross_sections file, return simple Chain. + + """ + + bare_xs_contents = """ + + + +""".format(CHAIN_PATH) + + with open(BARE_XS_FILE, "w") as out: + out.write(bare_xs_contents) + + yield BARE_XS_FILE + + class BareDepleteOperator(TransportOperator): """Very basic class for testing the initialization.""" @@ -30,10 +52,10 @@ class BareDepleteOperator(TransportOperator): pass -def test_operator_init(): +def test_operator_init(bare_xs): """The test uses a temporary dummy chain. This file will be removed at the end of the test, and only contains a depletion_chain node.""" - bare_op = BareDepleteOperator(CHAIN_PATH) + bare_op = BareDepleteOperator(_find_chain_file(bare_xs)) act_chain = bare_op.chain ref_chain = Chain.from_xml(CHAIN_PATH) assert len(act_chain) == len(ref_chain) @@ -51,7 +73,8 @@ def test_operator_init(): def test_operator_fiss_q(): """Make sure fission q values can be set""" new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7} - operator = BareDepleteOperator(chain_file=CHAIN_PATH, fission_q=new_q) + chain_file = Path(__file__).parents[1] / "chain_simple.xml" + operator = BareDepleteOperator(chain_file=chain_file, fission_q=new_q) mod_chain = operator.chain for name, q in new_q.items(): chain_nuc = mod_chain[name] diff --git a/tests/unit_tests/test_deplete_restart.py b/tests/unit_tests/test_deplete_restart.py index 1cbff30a5..e8bfc062a 100644 --- a/tests/unit_tests/test_deplete_restart.py +++ b/tests/unit_tests/test_deplete_restart.py @@ -21,7 +21,7 @@ def test_restart_predictor_cecm(run_in_tmpdir): # Perform simulation using the predictor algorithm dt = [0.75] power = 1.0 - openmc.deplete.PredictorIntegrator(op, dt, power).integrate(write_rates=True) + openmc.deplete.PredictorIntegrator(op, dt, power).integrate() # Load the files prev_res = openmc.deplete.Results(op.output_dir / "depletion_results.h5") @@ -30,6 +30,10 @@ def test_restart_predictor_cecm(run_in_tmpdir): op = dummy_operator.DummyOperator(prev_res) op.output_dir = output_dir + # check ValueError is raised, indicating previous and current stages + with pytest.raises(ValueError, match="incompatible.* 1.*2"): + openmc.deplete.CECMIntegrator(op, dt, power) + def test_restart_cecm_predictor(run_in_tmpdir): """Integral regression test of integrator algorithm using CE/CM for the @@ -43,7 +47,7 @@ def test_restart_cecm_predictor(run_in_tmpdir): dt = [0.75] power = 1.0 cecm = openmc.deplete.CECMIntegrator(op, dt, power) - cecm.integrate(write_rates=True) + cecm.integrate() # Load the files prev_res = openmc.deplete.Results(op.output_dir / "depletion_results.h5") @@ -52,6 +56,10 @@ def test_restart_cecm_predictor(run_in_tmpdir): op = dummy_operator.DummyOperator(prev_res) op.output_dir = output_dir + # check ValueError is raised, indicating previous and current stages + with pytest.raises(ValueError, match="incompatible.* 2.*1"): + openmc.deplete.PredictorIntegrator(op, dt, power) + @pytest.mark.parametrize("scheme", dummy_operator.SCHEMES) def test_restart(run_in_tmpdir, scheme): @@ -62,7 +70,7 @@ def test_restart(run_in_tmpdir, scheme): operator = dummy_operator.DummyOperator() # take first step - bundle.solver(operator, [0.75], 1.0).integrate(write_rates=True) + bundle.solver(operator, [0.75], 1.0).integrate() # restart prev_res = openmc.deplete.Results( diff --git a/tests/unit_tests/test_deplete_resultslist.py b/tests/unit_tests/test_deplete_resultslist.py index bc1a078b0..63073cf57 100644 --- a/tests/unit_tests/test_deplete_resultslist.py +++ b/tests/unit_tests/test_deplete_resultslist.py @@ -1,12 +1,10 @@ """Tests the Results class""" -from math import inf from pathlib import Path +from math import inf import numpy as np import pytest - -import openmc import openmc.deplete @@ -17,57 +15,6 @@ def res(): / 'test_reference.h5') return openmc.deplete.Results(filename) -def test_get_activity(res): - """Tests evaluating activity""" - t, a = res.get_activity("1") - - t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) - a_ref = np.array( - [1.25167956e+06, 3.69842310e+11, 3.70099291e+11, 3.53629755e+11]) - - np.testing.assert_allclose(t, t_ref) - np.testing.assert_allclose(a, a_ref) - - # Check by_nuclide - a_xe135_ref = np.array( - [2.10657422e+05, 1.12825236e+11, 1.09055177e+11, 1.07491257e+11]) - t_nuc, a_nuc = res.get_activity("1", by_nuclide=True) - - a_xe135 = np.array([a_nuc_i["Xe135"] for a_nuc_i in a_nuc]) - - np.testing.assert_allclose(t_nuc, t_ref) - np.testing.assert_allclose(a_xe135, a_xe135_ref) - - -def test_get_activity_chain_file(res, tmp_path): - """Tests evaluating activity with chain half-life data""" - _, a_endf = res.get_activity("1", by_nuclide=True, chain_file=False) - xe135_endf = np.array([a["Xe135"] for a in a_endf]) - - chain = openmc.deplete.Chain() - xe135 = openmc.deplete.Nuclide("Xe135") - xe135.half_life = openmc.data.half_life("Xe135") / 2.0 - chain.add_nuclide(xe135) - - t_chain, a_chain = res.get_activity("1", by_nuclide=True, chain_file=chain) - xe135_chain = np.array([a["Xe135"] for a in a_chain]) - - t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) - np.testing.assert_allclose(t_chain, t_ref) - np.testing.assert_allclose(xe135_chain, 2.0 * xe135_endf) - - chain_path = tmp_path / "chain.xml" - chain.export_to_xml(chain_path) - with openmc.config.patch('chain_file', chain_path): - _, a_config = res.get_activity("1", by_nuclide=True) - xe135_config = np.array([a["Xe135"] for a in a_config]) - np.testing.assert_allclose(xe135_config, xe135_chain) - - stable_chain = openmc.deplete.Chain() - stable_chain.add_nuclide(openmc.deplete.Nuclide("Xe135")) - _, a_stable = res.get_activity("1", by_nuclide=True, chain_file=stable_chain) - assert all(a["Xe135"] == 0.0 for a in a_stable) - def test_get_atoms(res): """Tests evaluating single nuclide concentration.""" @@ -75,7 +22,7 @@ def test_get_atoms(res): t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) n_ref = np.array( - [6.67473282e+08, 3.57489567e+14, 3.45544042e+14, 3.40588723e+14]) + [6.67473282e+08, 3.72442707e+14, 3.61129692e+14, 4.01920099e+14]) np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(n, n_ref) @@ -96,67 +43,13 @@ def test_get_atoms(res): assert t_hour == pytest.approx(t_ref / (60 * 60)) -def test_get_decay_heat(res): - """Tests evaluating decay heat.""" - # Set chain file for testing - openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' - - t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) - dh_ref = np.array( - [1.27933813e-09, 5.95370258e-03, 6.01335600e-03, 5.69831173e-03]) - - t, dh = res.get_decay_heat("1") - - np.testing.assert_allclose(t, t_ref) - np.testing.assert_allclose(dh, dh_ref) - - # Check by nuclide - dh_xe135_ref = np.array( - [1.27933813e-09, 6.85196014e-04, 6.62300168e-04, 6.52802366e-04]) - t_nuc, dh_nuc = res.get_decay_heat("1", by_nuclide=True) - - dh_nuc_xe135 = np.array([dh_nuc_i["Xe135"] for dh_nuc_i in dh_nuc]) - - np.testing.assert_allclose(t_nuc, t_ref) - np.testing.assert_allclose(dh_nuc_xe135, dh_xe135_ref) - - -def test_get_mass(res): - """Tests evaluating single nuclide concentration.""" - t, n = res.get_mass("1", "Xe135") - - t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) - n_ref = np.array( - [6.67473282e+08, 3.57489567e+14, 3.45544042e+14, 3.40588723e+14]) - - # Get g - n_ref *= openmc.data.atomic_mass('Xe135') / openmc.data.AVOGADRO - - np.testing.assert_allclose(t, t_ref) - np.testing.assert_allclose(n, n_ref) - - # Check alternate units - volume = res[0].volume["1"] - t_days, n_cm3 = res.get_mass("1", "Xe135", mass_units="g/cm3", time_units="d") - - assert t_days == pytest.approx(t_ref / (60 * 60 * 24)) - assert n_cm3 == pytest.approx(n_ref / volume) - - t_min, n_bcm = res.get_mass("1", "Xe135", mass_units="kg", time_units="min") - assert n_bcm == pytest.approx(n_ref / 1e3) - assert t_min == pytest.approx(t_ref / 60) - - t_hour, _n = res.get_mass("1", "Xe135", time_units="h") - assert t_hour == pytest.approx(t_ref / (60 * 60)) - - def test_get_reaction_rate(res): """Tests evaluating reaction rate.""" t, r = res.get_reaction_rate("1", "Xe135", "(n,gamma)") t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - n_ref = [6.67473282e+08, 3.57489567e+14, 3.45544042e+14, 3.40588723e+14] - xs_ref = [3.10220818e-05, 3.36754072e-05, 3.12740350e-05, 3.86717693e-05] + n_ref = [6.67473282e+08, 3.72442707e+14, 3.61129692e+14, 4.01920099e+14] + xs_ref = [5.10301159e-05, 3.19379638e-05, 4.50543806e-05, 4.71004301e-05] np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(r, np.array(n_ref) * xs_ref) @@ -168,8 +61,8 @@ def test_get_keff(res): t_min, k = res.get_keff(time_units='min') t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - k_ref = [1.1773089172, 1.2231748584, 1.1611455694, 1.1714783649] - u_ref = [0.0384666252, 0.0311915665, 0.0226370102, 0.0315964732] + k_ref = [1.21409662, 1.16518654, 1.25357797, 1.22611968] + u_ref = [0.0278795195, 0.0233141097, 0.0167899218, 0.0246734716] np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(t_min * 60, t_ref) @@ -181,7 +74,7 @@ def test_get_keff(res): def test_get_steps(unit): # Make a Results full of near-empty Result instances # Just fill out a time schedule - results = openmc.deplete.Results(filename=None) + results = openmc.deplete.Results() # Time in units of unit times = np.linspace(0, 100, num=5) if unit == "a": @@ -240,24 +133,3 @@ def test_get_steps(unit): actual = results.get_step_where( times[-1] * 100, time_units=unit, atol=inf, rtol=inf) assert actual == times.size - 1 - - -def test_stepresult_get_material(res): - # Get material at first timestep - step_result = res[0] - mat1 = step_result.get_material("1") - assert mat1.id == 1 - assert mat1.volume == step_result.volume["1"] - - # Spot check number densities - densities = mat1.get_nuclide_atom_densities() - assert densities['Xe135'] == pytest.approx(1e-14) - assert densities['U234'] == pytest.approx(1.00506e-05) - - -def test_stepresult_get_material_mat_id_as_int(res): - # Get material at first timestep using int mat_id - step_result = res[0] - mat1 = step_result.get_material(1) - assert mat1.id == 1 - assert mat1.volume == step_result.volume["1"] diff --git a/tests/unit_tests/test_deplete_transfer_rates.py b/tests/unit_tests/test_deplete_transfer_rates.py deleted file mode 100644 index a6dcb2b27..000000000 --- a/tests/unit_tests/test_deplete_transfer_rates.py +++ /dev/null @@ -1,232 +0,0 @@ -""" Tests for TransferRates class """ - -from pathlib import Path -from math import exp - -import pytest -import numpy as np - -import openmc -from openmc.deplete import CoupledOperator -from openmc.deplete.transfer_rates import TransferRates -from openmc.deplete.abc import (_SECONDS_PER_MINUTE, _SECONDS_PER_HOUR, - _SECONDS_PER_DAY, _SECONDS_PER_JULIAN_YEAR) - -CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" - -@pytest.fixture -def model(): - openmc.reset_auto_ids() - f = openmc.Material(name="f") - f.add_element("U", 1, percent_type="ao", enrichment=4.25) - f.add_element("O", 2) - f.set_density("g/cc", 10.4) - - w = openmc.Material(name="w") - w.add_element("O", 1) - w.add_element("H", 2) - w.set_density("g/cc", 1.0) - w.depletable = True - - # material just to test multiple destination material - h = openmc.Material(name="h") - h.add_element("He", 1) - h.set_density("g/cc", 1.78e-4) - h.depletable = True - - radii = [0.42, 0.45] - f.volume = np.pi * radii[0] ** 2 - w.volume = np.pi * (radii[1]**2 - radii[0]**2) - h.volume = 1 - materials = openmc.Materials([f, w, h]) - - surf_f = openmc.Sphere(r=radii[0]) - surf_w = openmc.Sphere(r=radii[1], boundary_type='vacuum') - surf_h = openmc.Sphere(x0=10, r=1, boundary_type='vacuum') - cell_f = openmc.Cell(fill=f, region=-surf_f) - cell_w = openmc.Cell(fill=w, region=+surf_f & -surf_w) - cell_h = openmc.Cell(fill=h, region=-surf_h) - geometry = openmc.Geometry([cell_f, cell_w, cell_h]) - - settings = openmc.Settings() - settings.particles = 1000 - settings.inactive = 10 - settings.batches = 50 - - return openmc.Model(geometry, materials, settings) - -@pytest.mark.parametrize("case_name, transfer_rates, timesteps", [ - ('elements', {'U': 0.01, 'Xe': 0.1}, None), - ('nuclides', {'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01}, None), - ('nuclides_elements', {'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01, 'U': 0.01, - 'Xe': 0.1}, None), - ('elements_nuclides', {'U': 0.01, 'Xe': 0.1, 'I135': 0.01, 'Gd156': 0.1, - 'Gd157': 0.01}, None), - ('multiple_transfer', {'U': 0.01, 'Xe': 0.1, 'I135': 0.01, 'Gd156': 0.1, - 'Gd157': 0.01}, None), - ('timesteps', {'U': 0.01, 'Xe': 0.1}, [1]), - ('rates_invalid_1', {'Gd': 0.01, 'Gd157': 0.01, 'Gd156': 0.01}, None), - ('rates_invalid_2', {'Gd156': 0.01, 'Gd157': 0.01, 'Gd': 0.01}, None), - ('rates_invalid_3', {'Gb156': 0.01}, None), - ('rates_invalid_4', {'Gb': 0.01}, None) - ]) -def test_get_set(model, case_name, transfer_rates, timesteps): - """Tests the get/set methods""" - op = CoupledOperator(model, CHAIN_PATH) - number_of_timesteps = 2 - transfer = TransferRates(op, model.materials, number_of_timesteps) - - if timesteps is None: - timesteps = np.arange(number_of_timesteps) - - # Test by Openmc material, material name and material id - material, dest_material, dest_material2 = [m for m in model.materials - if m.depletable] - for material_input in [material, material.name, material.id]: - for dest_material_input in [None, dest_material, dest_material.name, - dest_material.id]: - if case_name == 'rates_invalid_1': - with pytest.raises(ValueError, match='Cannot add transfer ' - 'rate for nuclide Gd157 to material 1 ' - 'where element Gd already has a ' - 'transfer rate.'): - for component, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, - [component], - transfer_rate) - elif case_name == 'rates_invalid_2': - with pytest.raises(ValueError, match='Cannot add transfer ' - f'rate for element Gd to material 1 with ' - r'transfer rate\(s\) for nuclide\(s\) ' - 'Gd156, Gd157.'): - for component, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, - [component], - transfer_rate) - elif case_name == 'rates_invalid_3': - with pytest.raises(ValueError, match='Gb156 is not a valid ' - 'nuclide or element.'): - for component, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, - [component], - transfer_rate) - elif case_name == 'rates_invalid_4': - with pytest.raises(ValueError, match='Gb is not a valid ' - 'nuclide or element.'): - for component, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, - [component], - transfer_rate) - else: - for component, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, [component], - transfer_rate, - timesteps=timesteps, - destination_material=\ - dest_material_input) - assert transfer.get_external_rate( - material_input, component, timesteps, - dest_material_input)[0] == transfer_rate - assert np.all(transfer.external_timesteps == timesteps) - - if timesteps is not None: - for timestep in timesteps: - assert transfer.get_components(material_input, timestep, - dest_material_input) == list(transfer_rates.keys()) - else: - assert transfer.get_components(material_input, timesteps, - dest_material_input) == list(transfer_rates.keys()) - - if case_name == 'multiple_transfer': - for dest2_material_input in [dest_material2, dest_material2.name, - dest_material2.id]: - for component, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, [component], - transfer_rate, - destination_material=\ - dest2_material_input) - for id, dest_mat in zip([0,1],[dest_material,dest_material2]): - assert transfer.get_external_rate( - material_input, component, timesteps)[0] == transfer_rate - -@pytest.mark.parametrize("transfer_rate_units, unit_conv", [ - ('1/s', 1), - ('1/sec', 1), - ('1/min', _SECONDS_PER_MINUTE), - ('1/minute', _SECONDS_PER_MINUTE), - ('1/h', _SECONDS_PER_HOUR), - ('1/hr', _SECONDS_PER_HOUR), - ('1/hour', _SECONDS_PER_HOUR), - ('1/d', _SECONDS_PER_DAY), - ('1/day', _SECONDS_PER_DAY), - ('1/a', _SECONDS_PER_JULIAN_YEAR), - ('1/year', _SECONDS_PER_JULIAN_YEAR), - ]) -def test_units(transfer_rate_units, unit_conv, model): - """ Units testing""" - # create transfer rate Xe - components = ['Xe', 'U235'] - transfer_rate = 1e-5 - number_of_timesteps = 2 - op = CoupledOperator(model, CHAIN_PATH) - transfer = TransferRates(op, model.materials, number_of_timesteps) - - for component in components: - transfer.set_transfer_rate('f', [component], transfer_rate * unit_conv, - transfer_rate_units=transfer_rate_units) - for timestep in range(transfer.number_of_timesteps): - assert transfer.get_external_rate('f', component, timestep)[0] == transfer_rate - - -def test_transfer(run_in_tmpdir, model): - """Tests transfer depletion class without neither reaction rates nor decay - but only transfer rates""" - - # create transfer rate for U - element = ['U'] - transfer_rate = 1e-5 - op = CoupledOperator(model, CHAIN_PATH) - integrator = openmc.deplete.PredictorIntegrator( - op, [1,1], 0.0, timestep_units = 'd') - integrator.add_transfer_rate('f', element, transfer_rate) - integrator.integrate() - - # Get number of U238 atoms from results - results = openmc.deplete.Results('depletion_results.h5') - _, atoms = results.get_atoms(model.materials[0], "U238") - - # Ensure number of atoms equal transfer decay - assert atoms[1] == pytest.approx(atoms[0]*exp(-transfer_rate*3600*24)) - assert atoms[2] == pytest.approx(atoms[1]*exp(-transfer_rate*3600*24)) - -@pytest.mark.parametrize("case_name, buffer, ox", [ - ('redox', {'Gd157':1}, {'Gd': 3, 'U': 4}), - ('buffer_invalid', {'Gd158':1}, {'Gd': 3, 'U': 4}), - ('elm_invalid', {'Gd157':1}, {'Gb': 3, 'U': 4}), - ]) -def test_redox(case_name, buffer, ox, model): - op = CoupledOperator(model, CHAIN_PATH) - number_of_timesteps = 2 - transfer = TransferRates(op, model.materials, number_of_timesteps) - - # Test by Openmc material, material name and material id - material, dest_material, dest_material2 = [m for m in model.materials - if m.depletable] - for material_input in [material, material.name, material.id]: - for dest_material_input in [dest_material, dest_material.name, - dest_material.id]: - - if case_name == 'buffer_invalid': - with pytest.raises(ValueError, match='Gd158 is not a valid ' - 'nuclide.'): - transfer.set_redox(material_input, buffer, ox) - - elif case_name == 'elm_invalid': - with pytest.raises(ValueError, match='Gb is not a valid ' - 'element.'): - transfer.set_redox(material_input, buffer, ox) - else: - transfer.set_redox(material_input, buffer, ox) - mat_id = transfer._get_material_id(material_input) - assert transfer.redox[mat_id][0] == buffer - assert transfer.redox[mat_id][1] == ox diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py index 82e526ec3..bacb988b9 100644 --- a/tests/unit_tests/test_element.py +++ b/tests/unit_tests/test_element.py @@ -1,5 +1,5 @@ import openmc -from pytest import approx, raises, warns +from pytest import approx, raises from openmc.data import NATURAL_ABUNDANCE, atomic_mass @@ -37,20 +37,6 @@ def test_expand_enrichment(): assert isotope[1] == approx(ref[isotope[0]]) -def test_expand_no_isotopes(): - """Test that correct warning is raised for elements with no isotopes""" - with warns(UserWarning, match='No naturally occurring'): - element = openmc.Element('Tc') - element.expand(100.0, 'ao') - - -def test_expand_ta(): - ref = {'Ta181': 100.0} - element = openmc.Element('Ta') - for isotope in element.expand(100.0, 'ao'): - assert isotope[1] == approx(ref[isotope[0]]) - - def test_expand_exceptions(): """ Test that correct exceptions are raised for invalid input """ diff --git a/tests/unit_tests/test_endf.py b/tests/unit_tests/test_endf.py index cdd21d7a6..9e6970867 100644 --- a/tests/unit_tests/test_endf.py +++ b/tests/unit_tests/test_endf.py @@ -2,17 +2,6 @@ from openmc.data import endf from pytest import approx -def test_evaluation_from_material(endf_data): - filename = f'{endf_data}/neutrons/n-001_H_001.endf' - material = endf.get_evaluations(filename)[0] - evaluation = endf.Evaluation(material) - - assert evaluation.material == material.MAT - assert evaluation.gnds_name == 'H1' - assert evaluation.section == material.section_text - assert evaluation.reaction_list == material[1, 451]['section_list'] - - def test_float_endf(): assert endf.float_endf('+3.2146') == approx(3.2146) assert endf.float_endf('.12345') == approx(0.12345) @@ -34,7 +23,6 @@ def test_float_endf(): assert endf.float_endf('-1.+2') == approx(-100.0) assert endf.float_endf(' ') == 0.0 assert endf.float_endf('9.876540000000000') == approx(9.87654) - assert endf.float_endf('-2.225002+6') == approx(-2.225002e+6) def test_int_endf(): diff --git a/tests/unit_tests/test_energy_cutoff.py b/tests/unit_tests/test_energy_cutoff.py index 45333f2e1..fb82c579a 100644 --- a/tests/unit_tests/test_energy_cutoff.py +++ b/tests/unit_tests/test_energy_cutoff.py @@ -17,7 +17,7 @@ def inf_medium_model(cutoff_energy, source_energy): model.geometry = openmc.Geometry([cell]) model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( particle='photon', energy=openmc.stats.Discrete([source_energy], [1.0]), ) diff --git a/tests/unit_tests/test_filter_distribcell.py b/tests/unit_tests/test_filter_distribcell.py deleted file mode 100644 index d5734a2c0..000000000 --- a/tests/unit_tests/test_filter_distribcell.py +++ /dev/null @@ -1,53 +0,0 @@ -import openmc -import pandas as pd - - -def test_distribcell_filter_apply_tally_results(run_in_tmpdir): - # Reset IDs to ensure consistent paths - openmc.reset_auto_ids() - - mat = openmc.Material() - mat.add_nuclide("U235", 1.0) - mat.set_density("g/cm3", 1.0) - - # Define 2x2 lattice with a cylinder in each universe - cyl = openmc.ZCylinder(r=1.0) - cell1 = openmc.Cell(fill=mat, region=-cyl) - cell2 = openmc.Cell(fill=None, region=+cyl) - univ = openmc.Universe(cells=[cell1, cell2]) - lattice = openmc.RectLattice() - lattice.lower_left = (-3.0, -3.0) - lattice.pitch = (3.0, 3.0) - lattice.universes = [[univ, univ], [univ, univ]] - box = openmc.model.RectangularPrism(6., 6., boundary_type='reflective') - root_cell = openmc.Cell(region=-box, fill=lattice) - geometry = openmc.Geometry([root_cell]) - - # Create model and add tally with distribcell filter - model = openmc.Model(geometry) - model.settings.batches = 10 - model.settings.particles = 1000 - tally = openmc.Tally() - distribcell_filter = openmc.DistribcellFilter(cell1) - tally.filters = [distribcell_filter] - tally.scores = ['flux'] - model.tallies = [tally] - - # Run OpenMC and apply tally results - model.run(apply_tally_results=True) - - # Check that mean and standard deviation are available on tally - assert tally.mean.shape == (4, 1, 1) - assert tally.std_dev.shape == (4, 1, 1) - - # Make sure paths attribute on filter is correct - assert distribcell_filter.paths == [ - 'u3->c3->l2(0,0)->u1->c1', - 'u3->c3->l2(1,0)->u1->c1', - 'u3->c3->l2(0,1)->u1->c1', - 'u3->c3->l2(1,1)->u1->c1', - ] - - # Check that we can get a DataFrame from the tally - df = tally.get_pandas_dataframe() - assert isinstance(df, pd.DataFrame) diff --git a/tests/unit_tests/test_filter_mesh.py b/tests/unit_tests/test_filter_mesh.py index e26bea337..265642360 100644 --- a/tests/unit_tests/test_filter_mesh.py +++ b/tests/unit_tests/test_filter_mesh.py @@ -1,10 +1,6 @@ -import math - import numpy as np -import pytest -from uncertainties import unumpy - import openmc +from uncertainties import unumpy def test_spherical_mesh_estimators(run_in_tmpdir): @@ -22,17 +18,15 @@ def test_spherical_mesh_estimators(run_in_tmpdir): model.settings.inactive = 10 model.settings.batches = 20 - sph_mesh = openmc.SphericalMesh( - r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3) - ) + sph_mesh = openmc.SphericalMesh() + sph_mesh.r_grid = np.linspace(0.0, 5.0**3, 20)**(1/3) tally1 = openmc.Tally() tally1.filters = [openmc.MeshFilter(sph_mesh)] tally1.scores = ['flux'] tally1.estimator = 'collision' - sph_mesh = openmc.SphericalMesh( - r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3) - ) + sph_mesh = openmc.SphericalMesh() + sph_mesh.r_grid = np.linspace(0.0, 5.0**3, 20)**(1/3) tally2 = openmc.Tally() tally2.filters = [openmc.MeshFilter(sph_mesh)] tally2.scores = ['flux'] @@ -68,8 +62,7 @@ def test_cylindrical_mesh_estimators(run_in_tmpdir): mat.add_nuclide('U235', 1.0) mat.set_density('g/cm3', 10.0) - cyl = openmc.model.RightCircularCylinder((0., 0., -5.), 10., 10.0, - boundary_type='vacuum') + cyl = openmc.model.RightCircularCylinder((0., 0., -5.), 10., 10.0, boundary_type='vacuum') cell = openmc.Cell(fill=mat, region=-cyl) model = openmc.Model() model.geometry = openmc.Geometry([cell]) @@ -77,19 +70,17 @@ def test_cylindrical_mesh_estimators(run_in_tmpdir): model.settings.inactive = 10 model.settings.batches = 20 - cyl_mesh = openmc.CylindricalMesh( - r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3), - z_grid=[-5., 5.] - ) + cyl_mesh = openmc.CylindricalMesh() + cyl_mesh.r_grid = np.linspace(0.0, 5.0**3, 20)**(1/3) + cyl_mesh.z_grid = [-5., 5.] tally1 = openmc.Tally() tally1.filters = [openmc.MeshFilter(cyl_mesh)] tally1.scores = ['flux'] tally1.estimator = 'collision' - cyl_mesh = openmc.CylindricalMesh( - r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3), - z_grid=[-5., 5.] - ) + cyl_mesh = openmc.CylindricalMesh() + cyl_mesh.r_grid = np.linspace(0.0, 5.0**3, 20)**(1/3) + cyl_mesh.z_grid = [-5., 5.] tally2 = openmc.Tally() tally2.filters = [openmc.MeshFilter(cyl_mesh)] tally2.scores = ['flux'] @@ -116,297 +107,3 @@ def test_cylindrical_mesh_estimators(run_in_tmpdir): diff = unumpy.nominal_values(delta) std_dev = unumpy.std_devs(delta) assert np.all(diff < 3*std_dev) - - -@pytest.mark.parametrize("scale", [0.1, 1.0, 1e2, 1e4, 1e5]) -def test_cylindrical_mesh_coincident(scale, run_in_tmpdir): - """Test for cylindrical mesh boundary being coincident with a cell boundary""" - - fuel = openmc.Material() - fuel.add_nuclide('U235', 1.) - fuel.set_density('g/cm3', 4.5) - - zcyl = openmc.ZCylinder(r=1.25*scale) - box = openmc.model.RectangularPrism(4*scale, 4*scale, boundary_type='reflective') - cell1 = openmc.Cell(fill=fuel, region=-zcyl) - cell2 = openmc.Cell(fill=None, region=+zcyl & -box) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2]) - - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.inactive = 0 - - cyl_mesh = openmc.CylindricalMesh( - r_grid=[0., 1.25*scale], - phi_grid=[0., 2*math.pi], - z_grid=[-1e10, 1e10] - ) - cyl_mesh_filter = openmc.MeshFilter(cyl_mesh) - cell_filter = openmc.CellFilter([cell1]) - - tally1 = openmc.Tally() - tally1.filters = [cyl_mesh_filter] - tally1.scores = ['flux'] - tally2 = openmc.Tally() - tally2.filters = [cell_filter] - tally2.scores = ['flux'] - model.tallies = openmc.Tallies([tally1, tally2]) - - # Run OpenMC - sp_filename = model.run() - - # Get flux for each of the two tallies - with openmc.StatePoint(sp_filename) as sp: - t1 = sp.tallies[tally1.id] - t2 = sp.tallies[tally2.id] - mean1 = t1.mean.ravel()[0] - mean2 = t2.mean.ravel()[0] - - # The two tallies should be exactly the same - assert mean1 == pytest.approx(mean2) - - -@pytest.mark.parametrize("scale", [0.1, 1.0, 1e2, 1e4, 1e5]) -def test_spherical_mesh_coincident(scale, run_in_tmpdir): - """Test for spherical mesh boundary being coincident with a cell boundary""" - - fuel = openmc.Material() - fuel.add_nuclide('U235', 1.) - fuel.set_density('g/cm3', 4.5) - - sph = openmc.Sphere(r=1.25*scale) - rcc = openmc.model.RectangularParallelepiped( - -2*scale, 2*scale, -2*scale, 2*scale, -2*scale, 2*scale, - boundary_type='reflective') - cell1 = openmc.Cell(fill=fuel, region=-sph) - cell2 = openmc.Cell(fill=None, region=+sph & -rcc) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2]) - - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.inactive = 0 - - sph_mesh = openmc.SphericalMesh( - r_grid=[0., 1.25*scale], - phi_grid=[0., 2*math.pi], - theta_grid=[0., math.pi], - ) - - sph_mesh_filter = openmc.MeshFilter(sph_mesh) - cell_filter = openmc.CellFilter([cell1]) - - tally1 = openmc.Tally() - tally1.filters = [sph_mesh_filter] - tally1.scores = ['flux'] - tally2 = openmc.Tally() - tally2.filters = [cell_filter] - tally2.scores = ['flux'] - model.tallies = openmc.Tallies([tally1, tally2]) - - # Run OpenMC - sp_filename = model.run() - - # Get flux for each of the two tallies - with openmc.StatePoint(sp_filename) as sp: - t1 = sp.tallies[tally1.id] - t2 = sp.tallies[tally2.id] - mean1 = t1.mean.ravel()[0] - mean2 = t2.mean.ravel()[0] - - # The two tallies should be exactly the same - assert mean1 == pytest.approx(mean2) - - -def test_get_reshaped_data(run_in_tmpdir): - """Test that expanding MeshFilter dimensions works as expected""" - - mat = openmc.Material() - mat.add_nuclide('U235', 1.0) - mat.set_density('g/cm3', 10.0) - - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.particles = 1_000 - model.settings.inactive = 10 - model.settings.batches = 20 - - sph_mesh = openmc.SphericalMesh( - r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3), - theta_grid=np.linspace(0, math.pi, 4), - phi_grid=np.linspace(0, 2*math.pi, 3) - ) - tally1 = openmc.Tally() - efilter = openmc.EnergyFilter([0, 1e5, 1e8]) - meshfilter = openmc.MeshFilter(sph_mesh) - assert meshfilter.shape == (19, 3, 2) - tally1.filters = [efilter, meshfilter] - tally1.scores = ['flux'] - - model.tallies = openmc.Tallies([tally1]) - - # Run OpenMC - sp_filename = model.run() - - # Get flux tally as reshaped data - with openmc.StatePoint(sp_filename) as sp: - t1 = sp.tallies[tally1.id] - data1 = t1.get_reshaped_data() - data2 = t1.get_reshaped_data(expand_dims=True) - - assert data1.shape == (2, 19*3*2, 1, 1) - assert data2.shape == (2, 19, 3, 2, 1, 1) - -def test_mesh_filter_rotation_roundtrip(run_in_tmpdir): - """Test that MeshFilter rotation works as expected""" - - - mesh = openmc.RegularMesh() - mesh.lower_left = [-10, -10, -10] - mesh.upper_right = [10, 10, 10] - mesh.dimension = [2, 3, 4] - - # check that rotatoin is round-tripped correctly for a set of angles - mesh_filter = openmc.MeshFilter(mesh) - mesh_filter.rotation = [0, 0, 90] # Rotate around z-axis by 90 degrees - - elem = mesh_filter.to_xml_element() - mesh_filter_xml = openmc.MeshFilter.from_xml_element(elem, meshes={mesh.id: mesh}) - assert all(mesh_filter_xml.rotation == mesh_filter.rotation) - - # check that rotation matrix is round-tripped correctly for a rotation matrix - mesh_filter.rotation = np.array([[0.7071, 0, 0.7071], - [0, 1, 0], - [-0.7071, 0, 0.7071]]) - - elem = mesh_filter.to_xml_element() - mesh_filter_xml = openmc.MeshFilter.from_xml_element(elem, meshes={mesh.id: mesh}) - assert np.allclose(mesh_filter_xml.rotation, mesh_filter.rotation) - - -def test_mesh_filter_dataframe_regular_3d(): - """Test MeshFilter.get_pandas_dataframe with a 3D RegularMesh.""" - mesh = openmc.RegularMesh() - mesh.lower_left = [0, 0, 0] - mesh.upper_right = [3, 4, 5] - mesh.dimension = [3, 4, 5] - - f = openmc.MeshFilter(mesh) - data_size = 3 * 4 * 5 - df = f.get_pandas_dataframe(data_size, stride=1) - - mesh_key = f'mesh {mesh.id}' - assert (mesh_key, 'x') in df.columns - assert (mesh_key, 'y') in df.columns - assert (mesh_key, 'z') in df.columns - assert len(df) == data_size - # x varies fastest (stride=1), then y (stride=3), then z (stride=12) - assert list(df[(mesh_key, 'x')][:3]) == [1, 2, 3] - assert df[(mesh_key, 'y')].iloc[0] == 1 - assert df[(mesh_key, 'y')].iloc[3] == 2 - - -def test_mesh_filter_dataframe_regular_2d(): - """Test MeshFilter.get_pandas_dataframe with a 2D RegularMesh.""" - mesh = openmc.RegularMesh() - mesh.lower_left = [0, 0] - mesh.upper_right = [2, 3] - mesh.dimension = [2, 3] - - f = openmc.MeshFilter(mesh) - data_size = 2 * 3 - df = f.get_pandas_dataframe(data_size, stride=1) - - mesh_key = f'mesh {mesh.id}' - assert (mesh_key, 'x') in df.columns - assert (mesh_key, 'y') in df.columns - # Should NOT have a z column for a 2D mesh - assert (mesh_key, 'z') not in df.columns - assert len(df) == data_size - - -def test_mesh_filter_dataframe_regular_1d(): - """Test MeshFilter.get_pandas_dataframe with a 1D RegularMesh.""" - mesh = openmc.RegularMesh() - mesh.lower_left = [0] - mesh.upper_right = [5] - mesh.dimension = [5] - - f = openmc.MeshFilter(mesh) - data_size = 5 - df = f.get_pandas_dataframe(data_size, stride=1) - - mesh_key = f'mesh {mesh.id}' - assert (mesh_key, 'x') in df.columns - assert (mesh_key, 'y') not in df.columns - assert (mesh_key, 'z') not in df.columns - assert len(df) == data_size - assert list(df[(mesh_key, 'x')]) == [1, 2, 3, 4, 5] - - -def test_mesh_filter_dataframe_cylindrical(): - """Test MeshFilter.get_pandas_dataframe with a CylindricalMesh.""" - mesh = openmc.CylindricalMesh( - r_grid=[0.0, 1.0, 2.0], - phi_grid=[0.0, math.pi], - z_grid=[0.0, 5.0, 10.0] - ) - - f = openmc.MeshFilter(mesh) - nr, nphi, nz = mesh.dimension # 2, 1, 2 - data_size = nr * nphi * nz - df = f.get_pandas_dataframe(data_size, stride=1) - - mesh_key = f'mesh {mesh.id}' - assert (mesh_key, 'r') in df.columns - assert (mesh_key, 'phi') in df.columns - assert (mesh_key, 'z') in df.columns - # Should NOT have x, y columns - assert (mesh_key, 'x') not in df.columns - assert (mesh_key, 'y') not in df.columns - assert len(df) == data_size - # r varies fastest - assert list(df[(mesh_key, 'r')][:nr]) == [1, 2] - - -def test_mesh_filter_dataframe_spherical(): - """Test MeshFilter.get_pandas_dataframe with a SphericalMesh.""" - mesh = openmc.SphericalMesh( - r_grid=[0.0, 1.0, 2.0, 3.0], - theta_grid=[0, math.pi], - phi_grid=[0, 2 * math.pi] - ) - - f = openmc.MeshFilter(mesh) - nr, ntheta, nphi = mesh.dimension # 3, 1, 1 - data_size = nr * ntheta * nphi - df = f.get_pandas_dataframe(data_size, stride=1) - - mesh_key = f'mesh {mesh.id}' - assert (mesh_key, 'r') in df.columns - assert (mesh_key, 'theta') in df.columns - assert (mesh_key, 'phi') in df.columns - assert (mesh_key, 'x') not in df.columns - assert len(df) == data_size - - -def test_mesh_filter_dataframe_rectilinear(): - """Test MeshFilter.get_pandas_dataframe with a RectilinearMesh.""" - mesh = openmc.RectilinearMesh() - mesh.x_grid = [0.0, 1.0, 2.0] - mesh.y_grid = [0.0, 1.0, 2.0, 3.0] - mesh.z_grid = [0.0, 5.0] - - f = openmc.MeshFilter(mesh) - nx, ny, nz = mesh.dimension # 2, 3, 1 - data_size = nx * ny * nz - df = f.get_pandas_dataframe(data_size, stride=1) - - mesh_key = f'mesh {mesh.id}' - assert (mesh_key, 'x') in df.columns - assert (mesh_key, 'y') in df.columns - assert (mesh_key, 'z') in df.columns - assert len(df) == data_size diff --git a/tests/unit_tests/test_filter_meshborn.py b/tests/unit_tests/test_filter_meshborn.py deleted file mode 100644 index 62fa1174e..000000000 --- a/tests/unit_tests/test_filter_meshborn.py +++ /dev/null @@ -1,116 +0,0 @@ -"""Test the meshborn filter using a fixed source calculation on a H1 sphere. - -""" - -import numpy as np -from uncertainties import unumpy -import openmc -import pytest - - -@pytest.fixture -def model(): - """Sphere of H1 with one hemisphere containing the source (x>0) and one - hemisphere with no source (x<0). - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # Materials - h1 = openmc.Material() - h1.add_nuclide("H1", 1.0) - h1.set_density("g/cm3", 1.0) - model.materials = openmc.Materials([h1]) - - # Core geometry - r = 10.0 - sphere = openmc.Sphere(r=r, boundary_type="reflective") - core = openmc.Cell(fill=h1, region=-sphere) - model.geometry = openmc.Geometry([core]) - - # Settings - model.settings.run_mode = 'fixed source' - model.settings.particles = 2000 - model.settings.batches = 8 - - distribution = openmc.stats.Box((0., -r, -r), (r, r, r)) - model.settings.source = openmc.IndependentSource(space=distribution) - - # ============================================================================= - # Tallies - # ============================================================================= - - mesh = openmc.RegularMesh() - mesh.dimension = (2, 2, 1) - mesh.lower_left = (-r, -r, -r) - mesh.upper_right = (r, r, r) - - f = openmc.MeshBornFilter(mesh) - t_1 = openmc.Tally(name="scatter-collision") - t_1.filters = [f] - t_1.scores = ["scatter"] - t_1.estimator = "collision" - - t_2 = openmc.Tally(name="scatter-tracklength") - t_2.filters = [f] - t_2.scores = ["scatter"] - t_2.estimator = "tracklength" - - model.tallies = [t_1, t_2] - - return model - - -def test_estimator_consistency(model, run_in_tmpdir): - """Test that resuts obtained from a tracklength estimator are - consistent with results obtained from a collision estimator. - - """ - # Run OpenMC - sp_filename = model.run() - - # Get radial flux distribution - with openmc.StatePoint(sp_filename) as sp: - scatter_collision = sp.get_tally(name="scatter-collision").mean.ravel() - scatter_collision_std_dev = sp.get_tally(name="scatter-collision").std_dev.ravel() - scatter_tracklength = sp.get_tally(name="scatter-tracklength").mean.ravel() - scatter_tracklength_std_dev = sp.get_tally(name="scatter-tracklength").std_dev.ravel() - - collision = unumpy.uarray(scatter_collision, scatter_collision_std_dev) - tracklength = unumpy.uarray(scatter_tracklength, scatter_tracklength_std_dev) - delta = abs(collision - tracklength) - - diff = unumpy.nominal_values(delta) - std_dev = unumpy.std_devs(delta) - assert np.all(diff <= 3 * std_dev) - - -def test_xml_serialization(): - """Test xml serialization of the meshborn filter.""" - openmc.reset_auto_ids() - - mesh = openmc.RegularMesh() - mesh.dimension = (1, 1, 1) - mesh.lower_left = (0.0, 0.0, 0.0) - mesh.upper_right = (1.0, 1.0, 1.0) - - filter = openmc.MeshBornFilter(mesh) - filter.translation = (2.0, 2.0, 2.0) - assert filter.mesh.id == 1 - assert filter.mesh.dimension == (1, 1, 1) - assert filter.mesh.lower_left == (0.0, 0.0, 0.0) - assert filter.mesh.upper_right == (1.0, 1.0, 1.0) - - repr(filter) - - elem = filter.to_xml_element() - assert elem.tag == 'filter' - assert elem.attrib['type'] == 'meshborn' - assert elem[0].text == "1" - assert elem.get("translation") == "2.0 2.0 2.0" - - meshes = {1: mesh} - new_filter = openmc.Filter.from_xml_element(elem, meshes=meshes) - assert new_filter.bins == filter.bins - np.testing.assert_equal(new_filter.translation, [2.0, 2.0, 2.0]) diff --git a/tests/unit_tests/test_filter_meshmaterial.py b/tests/unit_tests/test_filter_meshmaterial.py deleted file mode 100644 index a05ed5a12..000000000 --- a/tests/unit_tests/test_filter_meshmaterial.py +++ /dev/null @@ -1,66 +0,0 @@ -import numpy as np -import openmc -from pytest import approx - - -def test_filter_mesh_material(run_in_tmpdir): - # Create four identical materials - openmc.reset_auto_ids() - materials = [] - for i in range(4): - mat = openmc.Material() - mat.id = 10*(i+1) - mat.add_nuclide('Fe56', 1.0) - materials.append(mat) - - # Create a slab model with four cells - z_values = [-10., -5., 0., 5., 10.] - planes = [openmc.ZPlane(z) for z in z_values] - planes[0].boundary_type = 'vacuum' - planes[-1].boundary_type = 'vacuum' - regions = [+left & -right for left, right in zip(planes[:-1], planes[1:])] - cells = [openmc.Cell(fill=m, region=r) for r, m in zip(regions, materials)] - model = openmc.Model() - model.geometry = openmc.Geometry(cells) - model.settings.particles = 1_000 - model.settings.batches = 5 - model.settings.run_mode = 'fixed source' - - # Create a mesh that does not align with all planar surfaces - mesh = openmc.RegularMesh() - mesh.lower_left = (-1., -1., -10.) - mesh.upper_right = (1., 1., 10.) - mesh.dimension = (1, 1, 5) - - # Determine material volumes in each mesh element and use result to create a - # MeshMaterialFilter with corresponding bins - vols = mesh.material_volumes(model) - mmf = openmc.MeshMaterialFilter.from_volumes(mesh, vols) - expected_bins = [(0, 10), (1, 10), (1, 20), (2, 20), (2, 30), (3, 40), (3, 30), (4, 40)] - np.testing.assert_equal(mmf.bins, expected_bins) - - # Create two tallies, one with a mesh filter and one with mesh-material - mesh_tally = openmc.Tally() - mesh_tally.filters = [openmc.MeshFilter(mesh)] - mesh_tally.scores = ['flux'] - mesh_material_tally = openmc.Tally() - mesh_material_tally.filters = [mmf] - mesh_material_tally.scores = ['flux'] - model.tallies = [mesh_tally, mesh_material_tally] - - # Run model to get results on the two tallies - model.run(apply_tally_results=True) - - # The sum of the flux in each mesh-material combination within a single mesh - # element should be equal to the flux in that mesh element - mesh_mean = mesh_tally.mean.ravel() - meshmat_mean = mesh_material_tally.mean.ravel() - assert mesh_mean[0] == approx(meshmat_mean[0]) - assert mesh_mean[1] == approx(meshmat_mean[1] + meshmat_mean[2]) - assert mesh_mean[2] == approx(meshmat_mean[3] + meshmat_mean[4]) - assert mesh_mean[3] == approx(meshmat_mean[5] + meshmat_mean[6]) - assert mesh_mean[4] == approx(meshmat_mean[7]) - assert mesh_tally.mean.sum() == approx(mesh_material_tally.mean.sum()) - - # Make sure get_pandas_dataframe method works - mesh_material_tally.get_pandas_dataframe() diff --git a/tests/unit_tests/test_filter_musurface.py b/tests/unit_tests/test_filter_musurface.py deleted file mode 100644 index ca0db71f0..000000000 --- a/tests/unit_tests/test_filter_musurface.py +++ /dev/null @@ -1,38 +0,0 @@ -import openmc - - -def test_musurface(run_in_tmpdir): - sphere = openmc.Sphere(r=1.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.particles = 1000 - model.settings.batches = 10 - E = 1.0 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point(), - angle=openmc.stats.Isotropic(), - energy=openmc.stats.delta_function(E), - ) - model.settings.run_mode = "fixed source" - - filter1 = openmc.MuSurfaceFilter(200) - filter2 = openmc.SurfaceFilter(sphere) - tally = openmc.Tally() - tally.filters = [filter1, filter2] - tally.scores = ['current'] - model.tallies = openmc.Tallies([tally]) - - # Run OpenMC - sp_filename = model.run() - - # Get current binned by mu - with openmc.StatePoint(sp_filename) as sp: - current_mu = sp.tallies[tally.id].mean.ravel() - - # All contributions should show up in last bin - assert current_mu[-1] == 1.0 - for element in current_mu[:-1]: - assert element == 0.0 - - diff --git a/tests/unit_tests/test_filter_reaction.py b/tests/unit_tests/test_filter_reaction.py deleted file mode 100644 index df8fc9d7b..000000000 --- a/tests/unit_tests/test_filter_reaction.py +++ /dev/null @@ -1,87 +0,0 @@ -import pytest -import openmc - - -def test_reaction_filter_construction_with_strings(): - f = openmc.ReactionFilter(['(n,elastic)', '(n,gamma)']) - assert len(f.bins) == 2 - assert f.bins[0] == '(n,elastic)' - assert f.bins[1] == '(n,gamma)' - - -def test_reaction_filter_construction_with_mt(): - f = openmc.ReactionFilter([2, 102]) - assert len(f.bins) == 2 - assert f.bins[0] == '(n,elastic)' - assert f.bins[1] == '(n,gamma)' - - -def test_reaction_filter_mixed(): - f = openmc.ReactionFilter([2, '(n,gamma)']) - assert f.bins[0] == '(n,elastic)' - assert f.bins[1] == '(n,gamma)' - - -def test_reaction_filter_single_bin_string(): - f = openmc.ReactionFilter('(n,elastic)') - assert len(f.bins) == 1 - assert f.bins[0] == '(n,elastic)' - - -def test_reaction_filter_single_bin_mt(): - f = openmc.ReactionFilter(2) - assert len(f.bins) == 1 - assert f.bins[0] == '(n,elastic)' - - -def test_reaction_filter_single_bin_naming(): - f = openmc.ReactionFilter('total') - assert len(f.bins) == 1 - assert f.bins[0] == '(n,total)' - - -def test_reaction_filter_invalid_mt(): - with pytest.raises(ValueError, match="No known reaction"): - openmc.ReactionFilter([999999]) - - -def test_reaction_filter_invalid_string(): - with pytest.raises(ValueError, match="Unknown reaction name"): - openmc.ReactionFilter(['not-a-reaction']) - - -def test_reaction_filter_invalid_type(): - with pytest.raises(TypeError, match="Expected str or int"): - openmc.ReactionFilter([3.14]) - - -def test_reaction_filter_xml_roundtrip(): - f = openmc.ReactionFilter([2, 102], filter_id=42) - elem = f.to_xml_element() - f2 = openmc.ReactionFilter.from_xml_element(elem) - assert f2.id == 42 - assert len(f2.bins) == 2 - assert f2.bins[0] == '(n,elastic)' - assert f2.bins[1] == '(n,gamma)' - - -def test_reaction_filter_num_bins(): - f = openmc.ReactionFilter(['(n,elastic)', '(n,fission)', '(n,gamma)']) - assert f.num_bins == 3 - - -def test_reaction_filter_repr(): - f = openmc.ReactionFilter([2, 102]) - r = repr(f) - assert 'ReactionFilter' in r - - -def test_reaction_filter_short_name(): - assert openmc.ReactionFilter.short_name == 'Reaction' - - -def test_reaction_filter_total_warning(): - """Test that using 'total' emits a warning about ambiguity.""" - with pytest.warns(UserWarning, match="ambiguous"): - f = openmc.ReactionFilter(['total']) - assert f.bins[0] == '(n,total)' diff --git a/tests/unit_tests/test_filter_weight.py b/tests/unit_tests/test_filter_weight.py deleted file mode 100644 index 878929ee0..000000000 --- a/tests/unit_tests/test_filter_weight.py +++ /dev/null @@ -1,44 +0,0 @@ -import openmc -import numpy as np - - -def test_weightfilter(run_in_tmpdir): - steel = openmc.Material(name='Stainless Steel') - steel.set_density('g/cm3', 8.00) - steel.add_nuclide('Fe56', 1.0) - - sphere = openmc.Sphere(r=50.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere, fill=steel) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.particles = 100 - model.settings.batches = 10 - - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(14e6), - ) - model.settings.run_mode = "fixed source" - - radius = list(range(1, 50)) - sphere_mesh = openmc.SphericalMesh(radius) - mesh_filter = openmc.MeshFilter(sphere_mesh) - weight_filter = openmc.WeightFilter( - [0.999, 0.9999, 0.99999, 0.999999, 1.0, 1.000001 ,1.00001, 1.0001, 1.001] - ) - - tally = openmc.Tally() - tally.filters = [mesh_filter, weight_filter] - tally.estimator = 'analog' - tally.scores = ['flux'] - model.tallies = openmc.Tallies([tally]) - - # Run OpenMC - model.run(apply_tally_results=True) - - # Get current binned by mu - neutron_flux = tally.mean.reshape(48, 8) - - # All contributions should show up in the fourth bin - assert np.all(neutron_flux[:, 3] != 0.0) - neutron_flux[:, 3] = 0.0 - assert np.all(neutron_flux == 0.0) diff --git a/tests/unit_tests/test_filters.py b/tests/unit_tests/test_filters.py index 2e7481c87..ec051d9fd 100644 --- a/tests/unit_tests/test_filters.py +++ b/tests/unit_tests/test_filters.py @@ -1,6 +1,7 @@ +import math import numpy as np import openmc -from pytest import fixture, approx, raises +from pytest import fixture, approx @fixture(scope='module') @@ -10,23 +11,21 @@ def box_model(): m.add_nuclide('U235', 1.0) m.set_density('g/cm3', 1.0) - box = openmc.model.RectangularPrism(10., 10., boundary_type='vacuum') - c = openmc.Cell(fill=m, region=-box) + box = openmc.model.rectangular_prism(10., 10., boundary_type='vacuum') + c = openmc.Cell(fill=m, region=box) model.geometry.root_universe = openmc.Universe(cells=[c]) model.settings.particles = 100 model.settings.batches = 10 model.settings.inactive = 0 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point()) + model.settings.source = openmc.Source(space=openmc.stats.Point()) return model def test_cell_instance(): c1 = openmc.Cell() c2 = openmc.Cell() - f = openmc.CellInstanceFilter( - [(c1, 0), (c1, 1), (c1, 2), (c2, 0), (c2, 1)]) + f = openmc.CellInstanceFilter([(c1, 0), (c1, 1), (c1, 2), (c2, 0), (c2, 1)]) # Make sure __repr__ works repr(f) @@ -236,8 +235,7 @@ def test_first_moment(run_in_tmpdir, box_model): flux, scatter = sp.tallies[plain_tally.id].mean.ravel() # Check that first moment matches - def first_score(t): - return sp.tallies[t.id].mean.ravel()[0] + first_score = lambda t: sp.tallies[t.id].mean.ravel()[0] assert first_score(leg_tally) == scatter assert first_score(leg_sptl_tally) == scatter assert first_score(sph_scat_tally) == scatter @@ -251,217 +249,9 @@ def test_energy(): assert len(f.values) == 710 -def test_energyfilter_error_handling(): - with raises(ValueError): - openmc.EnergyFilter([1e6]) - - def test_lethargy_bin_width(): f = openmc.EnergyFilter.from_group_structure('VITAMIN-J-175') assert len(f.lethargy_bin_width) == 175 - energy_bins = openmc.mgxs.GROUP_STRUCTURES['VITAMIN-J-175'] - assert f.lethargy_bin_width[0] == np.log10(energy_bins[1]/energy_bins[0]) - assert f.lethargy_bin_width[-1] == np.log10( - energy_bins[-1]/energy_bins[-2]) - - -def test_energyfunc(): - f = openmc.EnergyFunctionFilter( - [0.0, 10.0, 2.0e3, 1.0e6, 20.0e6], - [1.0, 0.9, 0.8, 0.7, 0.6], - 'histogram' - ) - - # Make sure XML roundtrip works - elem = f.to_xml_element() - new_f = openmc.EnergyFunctionFilter.from_xml_element(elem) - np.testing.assert_allclose(f.energy, new_f.energy) - np.testing.assert_allclose(f.y, new_f.y) - assert f.interpolation == new_f.interpolation - - -def test_tabular_from_energyfilter(): - efilter = openmc.EnergyFilter([0.0, 10.0, 20.0, 25.0]) - tab = efilter.get_tabular(values=[5, 10, 10]) - - assert tab.x.tolist() == [0.0, 10.0, 20.0, 25.0] - - # combination of different values passed into get_tabular and different - # width energy bins results in a doubling value for each p value - assert tab.p.tolist() == [0.02, 0.04, 0.08, 0.0] - - # distribution should integrate to unity - assert tab.integral() == approx(1.0) - - # 'histogram' is the default - assert tab.interpolation == 'histogram' - - tab = efilter.get_tabular(values=np.array( - [10, 10, 5]), interpolation='linear-linear') - assert tab.interpolation == 'linear-linear' - - -def test_energy_filter(): - - # testing that bins descending value raises error - msg = "Values 1.0 and 0.5 appear to be out of order" - with raises(ValueError, match=msg): - openmc.EnergyFilter([0.0, 1.0, 0.5]) - - # testing that bins with same value raises error - msg = "Values 0.25 and 0.25 appear to be out of order" - with raises(ValueError, match=msg): - openmc.EnergyFilter([0.0, 0.25, 0.25]) - - # testing that negative bins values raises error - msg = 'Unable to set "filter value" to "-1.2" since it is less than "0.0"' - with raises(ValueError, match=msg): - openmc.EnergyFilter([-1.2, 0.25, 0.5]) - - -def test_particle_production_filter(): - energy_bins = [1e3, 1e4, 1e5, 1e6] - - # --- Single particle with energy bins --- - f = openmc.ParticleProductionFilter('photon', energy_bins) - - # particles getter always returns a list - assert isinstance(f.particles, list) - assert len(f.particles) == 1 - assert f.particles[0] == openmc.ParticleType.PHOTON - - assert f.num_energy_bins == 3 - assert f.num_bins == 3 - assert f.shape == (1, 3) - assert len(f.bins) == 3 - # Each bin is (particle_name, e_low, e_high) - assert f.bins[0] == ('photon', 1e3, 1e4) - assert f.bins[2] == ('photon', 1e5, 1e6) - - # __repr__ check - repr(f) - - # to_xml_element() - elem = f.to_xml_element() - assert elem.tag == 'filter' - assert elem.attrib['type'] == 'particleproduction' - assert elem.find('particles').text == 'photon' - assert elem.find('energies').text.split()[0] == str(energy_bins[0]) - - # from_xml_element() - new_f = openmc.Filter.from_xml_element(elem) - assert new_f.id == f.id - assert new_f.particles == f.particles - assert np.allclose(new_f.energies, f.energies) - - # pandas output (with energy bins -> 3 MultiIndex columns) - df = f.get_pandas_dataframe(data_size=3, stride=1) - assert df.shape[0] == 3 - assert ('particleproduction', 'particle') in df.columns - assert ('particleproduction', 'energy low [eV]') in df.columns - assert ('particleproduction', 'energy high [eV]') in df.columns - - # --- Multiple particles with energy bins --- - f2 = openmc.ParticleProductionFilter(['photon', 'neutron'], energy_bins) - assert len(f2.particles) == 2 - assert f2.num_bins == 6 # 2 particles * 3 energy bins - assert f2.shape == (2, 3) - assert len(f2.bins) == 6 - # First 3 bins are photon, next 3 are neutron - assert f2.bins[0] == ('photon', 1e3, 1e4) - assert f2.bins[3] == ('neutron', 1e3, 1e4) - - df2 = f2.get_pandas_dataframe(data_size=6, stride=1) - assert df2.shape[0] == 6 - assert list(df2[('particleproduction', 'particle')]) == \ - ['photon'] * 3 + ['neutron'] * 3 - - # XML round-trip - elem2 = f2.to_xml_element() - new_f2 = openmc.Filter.from_xml_element(elem2) - assert len(new_f2.particles) == 2 - assert np.allclose(new_f2.energies, energy_bins) - - # --- Multiple particles without energy bins --- - f3 = openmc.ParticleProductionFilter(['photon', 'neutron', 'electron']) - assert f3.energies is None - assert f3.num_bins == 3 - assert f3.num_energy_bins == 1 - assert f3.shape == (3, 1) - assert f3.bins == ['photon', 'neutron', 'electron'] - - repr(f3) - - df3 = f3.get_pandas_dataframe(data_size=3, stride=1) - assert df3.shape[0] == 3 - assert ('particleproduction', 'particle') in df3.columns - # Should not have energy columns - assert ('particleproduction', 'energy low [eV]') not in df3.columns - - # XML round-trip without energies - elem3 = f3.to_xml_element() - assert elem3.find('energies') is None - new_f3 = openmc.Filter.from_xml_element(elem3) - assert new_f3.energies is None - assert len(new_f3.particles) == 3 - - # --- Energies from group structure name --- - f4 = openmc.ParticleProductionFilter('photon', energies='CCFE-709') - expected = openmc.mgxs.GROUP_STRUCTURES['CCFE-709'] - assert np.allclose(f4.energies, expected) - assert f4.num_energy_bins == len(expected) - 1 - assert f4.num_bins == len(expected) - 1 - - -def test_weight(): - f = openmc.WeightFilter([0.01, 0.1, 1.0, 10.0]) - expected_bins = [[0.01, 0.1], [0.1, 1.0], [1.0, 10.0]] - - assert np.allclose(f.bins, expected_bins) - assert len(f.bins) == 3 - - # Make sure __repr__ works - repr(f) - - # to_xml_element() - elem = f.to_xml_element() - assert elem.tag == 'filter' - assert elem.attrib['type'] == 'weight' - - # from_xml_element() - new_f = openmc.Filter.from_xml_element(elem) - assert new_f.id == f.id - assert np.allclose(new_f.bins, f.bins) - - -def test_mesh_material(): - mat1 = openmc.Material() - mat2 = openmc.Material() - - mesh = openmc.RegularMesh() - mesh.lower_left = (-1., -1., -1.) - mesh.upper_right = (1., 1., 1.) - mesh.dimension = (2, 4, 1) - bins = [(0, mat1), (0, mat2), (6, mat1), (7, mat2)] - f = openmc.MeshMaterialFilter(mesh, bins) - - expected_bins = [(0, mat1.id), (0, mat2.id), (6, mat1.id), (7, mat2.id)] - assert np.allclose(f.bins, expected_bins) - assert f.mesh == mesh - assert f.shape == (4,) - - # to_xml_element() - elem = f.to_xml_element() - assert elem.tag == 'filter' - assert elem.attrib['type'] == 'meshmaterial' - - # from_xml_element() - new_f = openmc.Filter.from_xml_element(elem, meshes={mesh.id: mesh}) - assert isinstance(new_f, openmc.MeshMaterialFilter) - assert new_f.id == f.id - assert new_f.mesh == f.mesh - assert np.allclose(new_f.bins, expected_bins) - - # Test hash and str - hash(f) - str(f) + energy_bins = openmc.mgxs.GROUP_STRUCTURES['VITAMIN-J-175'] + assert f.lethargy_bin_width[0] == math.log10(energy_bins[1]/energy_bins[0]) + assert f.lethargy_bin_width[-1] == math.log10(energy_bins[-1]/energy_bins[-2]) diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 6cc577c82..64a97e0a1 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -1,5 +1,4 @@ -import lxml.etree as ET -from pathlib import Path +import xml.etree.ElementTree as ET import numpy as np import openmc @@ -20,7 +19,7 @@ def test_volume(run_in_tmpdir, uo2): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + model.settings.source = openmc.Source(space=openmc.stats.Point()) ll, ur = model.geometry.bounding_box assert ll == pytest.approx((-outer.r, -outer.r, -outer.r)) @@ -160,13 +159,12 @@ def test_get_by_name(): m2 = openmc.Material(name='Zirconium') m2.add_element('Zr', 1.0) - s1 = openmc.Sphere(name='surface1') - c1 = openmc.Cell(fill=m1, region=-s1, name='cell1') + c1 = openmc.Cell(fill=m1, name='cell1') u1 = openmc.Universe(name='Zircaloy universe', cells=[c1]) - s2 = openmc.ZCylinder(name='surface2') - c2 = openmc.Cell(fill=u1, region=-s2, name='cell2') - c3 = openmc.Cell(fill=m2, region=+s2, name='Cell3') + cyl = openmc.ZCylinder() + c2 = openmc.Cell(fill=u1, region=-cyl, name='cell2') + c3 = openmc.Cell(fill=m2, region=+cyl, name='Cell3') root = openmc.Universe(name='root Universe', cells=[c2, c3]) geom = openmc.Geometry(root) @@ -179,13 +177,6 @@ def test_get_by_name(): mats = geom.get_materials_by_name('zirconium', True, True) assert not mats - surfaces = set(geom.get_surfaces_by_name('surface')) - assert not surfaces ^ {s1, s2} - surfaces = set(geom.get_surfaces_by_name('Surface2', False, True)) - assert not surfaces ^ {s2} - surfaces = geom.get_surfaces_by_name('Surface2', True, True) - assert not surfaces - cells = set(geom.get_cells_by_name('cell')) assert not cells ^ {c1, c2, c3} cells = set(geom.get_cells_by_name('cell', True)) @@ -213,27 +204,27 @@ def test_get_by_name(): def test_hex_prism(): - hex_prism = openmc.model.HexagonalPrism(edge_length=5.0, - origin=(0.0, 0.0), - orientation='y') + hex_prism = openmc.model.hexagonal_prism(edge_length=5.0, + origin=(0.0, 0.0), + orientation='y') # clear checks - assert (0.0, 0.0, 0.0) in -hex_prism - assert (10.0, 10.0, 10.0) not in -hex_prism + assert (0.0, 0.0, 0.0) in hex_prism + assert (10.0, 10.0, 10.0) not in hex_prism # edge checks - assert (0.0, 5.01, 0.0) not in -hex_prism - assert (0.0, 4.99, 0.0) in -hex_prism + assert (0.0, 5.01, 0.0) not in hex_prism + assert (0.0, 4.99, 0.0) in hex_prism - rounded_hex_prism = openmc.model.HexagonalPrism(edge_length=5.0, - origin=(0.0, 0.0), - orientation='y', - corner_radius=1.0) + rounded_hex_prism = openmc.model.hexagonal_prism(edge_length=5.0, + origin=(0.0, 0.0), + orientation='y', + corner_radius=1.0) # clear checks - assert (0.0, 0.0, 0.0) in -rounded_hex_prism - assert (10.0, 10.0, 10.0) not in -rounded_hex_prism + assert (0.0, 0.0, 0.0) in rounded_hex_prism + assert (10.0, 10.0, 10.0) not in rounded_hex_prism # edge checks - assert (0.0, 5.01, 0.0) not in -rounded_hex_prism - assert (0.0, 4.99, 0.0) not in -rounded_hex_prism + assert (0.0, 5.01, 0.0) not in rounded_hex_prism + assert (0.0, 4.99, 0.0) not in rounded_hex_prism def test_get_lattice_by_name(cell_with_lattice): @@ -283,22 +274,7 @@ def test_from_xml(run_in_tmpdir, mixed_lattice_model): # Export model mixed_lattice_model.export_to_xml() - mats_from_xml = openmc.Materials.from_xml('materials.xml') - # checking string a Path are both acceptable - for path in ['geometry.xml', Path('geometry.xml')]: - for materials in [mats_from_xml, 'materials.xml']: - # Import geometry from file - geom = openmc.Geometry.from_xml(path=path, materials=materials) - assert isinstance(geom, openmc.Geometry) - ll, ur = geom.bounding_box - assert ll == pytest.approx((-6.0, -6.0, -np.inf)) - assert ur == pytest.approx((6.0, 6.0, np.inf)) - - with pytest.raises(TypeError) as excinfo: - geom = openmc.Geometry.from_xml(path='geometry.xml', materials=None) - assert 'Unable to set "materials" to "None"' in str(excinfo.value) - - # checking that the default args also work + # Import geometry geom = openmc.Geometry.from_xml() assert isinstance(geom, openmc.Geometry) ll, ur = geom.bounding_box @@ -362,44 +338,13 @@ def test_remove_redundant_surfaces(): clad = get_cyl_cell(r1, r2, z1, z2, m2) water = get_cyl_cell(r2, r3, z1, z2, m3) root = openmc.Universe(cells=[fuel, clad, water]) - geom = openmc.Geometry(root=root, merge_surfaces=True, surface_precision=11) - assert geom.merge_surfaces is True - geom.merge_surfaces = False - assert geom.merge_surfaces is False - assert geom.surface_precision == 11 - geom.surface_precision = 10 - assert geom.surface_precision == 10 - model = openmc.model.Model(geometry=geom, - materials=openmc.Materials([m1, m2, m3])) - + geom = openmc.Geometry(root) + # There should be 6 redundant surfaces in this geometry - n_redundant_surfs = len(geom.remove_redundant_surfaces().keys()) + n_redundant_surfs = len(geom.get_redundant_surfaces().keys()) assert n_redundant_surfs == 6 + # Remove redundant surfaces + geom.remove_redundant_surfaces() # There should be 0 remaining redundant surfaces - n_redundant_surfs = len(geom.remove_redundant_surfaces().keys()) + n_redundant_surfs = len(geom.get_redundant_surfaces().keys()) assert n_redundant_surfs == 0 - -def test_get_all_nuclides(): - m1 = openmc.Material() - m1.add_nuclide('Fe56', 1) - m1.add_nuclide('Be9', 1) - m2 = openmc.Material() - m2.add_nuclide('Be9', 1) - s = openmc.Sphere() - c1 = openmc.Cell(fill=m1, region=-s) - c2 = openmc.Cell(fill=m2, region=+s) - geom = openmc.Geometry([c1, c2]) - assert geom.get_all_nuclides() == ['Be9', 'Fe56'] - - -def test_redundant_surfaces(): - # Make sure boundary condition is accounted for - s1 = openmc.Sphere(r=5.0) - s2 = openmc.Sphere(r=5.0, boundary_type="vacuum") - c1 = openmc.Cell(region=-s1) - c2 = openmc.Cell(region=+s1) - u_lower = openmc.Universe(cells=[c1, c2]) - c3 = openmc.Cell(fill=u_lower, region=-s2) - geom = openmc.Geometry([c3]) - redundant_surfs = geom.remove_redundant_surfaces() - assert len(redundant_surfs) == 0 diff --git a/tests/unit_tests/test_ifp.py b/tests/unit_tests/test_ifp.py deleted file mode 100644 index e527f1624..000000000 --- a/tests/unit_tests/test_ifp.py +++ /dev/null @@ -1,88 +0,0 @@ -"""Test the Iterated Fission Probability (IFP) method to compute adjoint-weighted -kinetics parameters using dedicated tallies.""" - -import pytest -import openmc - - -def test_xml_serialization(run_in_tmpdir): - """Check that a simple use case can be written and read in XML.""" - parameter = 5 - settings = openmc.Settings() - settings.ifp_n_generation = parameter - settings.export_to_xml() - - read_settings = openmc.Settings.from_xml() - assert read_settings.ifp_n_generation == parameter - - -@pytest.fixture(scope="module") -def geometry(): - openmc.reset_auto_ids() - material = openmc.Material() - material.add_nuclide("U235", 1.0) - sphere = openmc.Sphere(r=1.0, boundary_type="vacuum") - cell = openmc.Cell(region=-sphere, fill=material) - return openmc.Geometry([cell]) - - -@pytest.mark.parametrize( - "options, error", - [ - ({"ifp_n_generation": 0}, ValueError), - ({"ifp_n_generation": -1}, ValueError), - ({"run_mode": "fixed source"}, RuntimeError), - ({"inactive": 5, "ifp_n_generation": 6}, RuntimeError), - ({"inactive": 9}, RuntimeError) - ], -) -def test_exceptions(options, error, run_in_tmpdir, geometry): - """Test settings configuration that should return an error.""" - with pytest.raises(error): - settings = openmc.Settings(**options) - settings.particles = 100 - settings.batches = 15 - tally = openmc.Tally(name="ifp-scores") - tally.scores = ["ifp-time-numerator", "ifp-beta-numerator", "ifp-denominator"] - tallies = openmc.Tallies([tally]) - model = openmc.Model(geometry=geometry, settings=settings, tallies=tallies) - model.run() - - -@pytest.mark.parametrize( - "num_groups, use_auto_tallies", - [ - (None, True), - (None, False), - (6, True), - (6, False), - ], -) -def test_get_kinetics_parameters(run_in_tmpdir, geometry, num_groups, use_auto_tallies): - # Create basic model - model = openmc.Model(geometry=geometry) - model.settings.particles = 1000 - model.settings.batches = 20 - model.settings.inactive = 5 - model.settings.ifp_n_generation = 5 - - # Add IFP tallies either via the convenience method or manually - if use_auto_tallies: - model.add_kinetics_parameters_tallies(num_groups=num_groups) - else: - for score in ["ifp-time-numerator", "ifp-beta-numerator", "ifp-denominator"]: - tally = openmc.Tally() - tally.scores = [score] - if score == "ifp-beta-numerator" and num_groups is not None: - tally.filters = [openmc.DelayedGroupFilter(list(range(1, num_groups + 1)))] - model.tallies.append(tally) - - # Run and get kinetics parameters - sp_file = model.run() - with openmc.StatePoint(sp_file) as sp: - params = sp.get_kinetics_parameters() - assert isinstance(params, openmc.KineticsParameters) - assert params.generation_time is not None - assert params.beta_effective is not None - if num_groups is not None: - assert len(params.beta_effective) == num_groups diff --git a/tests/unit_tests/test_lattice.py b/tests/unit_tests/test_lattice.py index d72d9c5c3..99bc284b0 100644 --- a/tests/unit_tests/test_lattice.py +++ b/tests/unit_tests/test_lattice.py @@ -1,6 +1,6 @@ from math import sqrt +import xml.etree.ElementTree as ET -import lxml.etree as ET import openmc import pytest @@ -377,46 +377,3 @@ def test_unset_universes(): hex_lattice.pitch = (1.,) with pytest.raises(ValueError): hex_lattice.create_xml_subelement(elem) - - -@pytest.mark.parametrize("orientation", ['x', 'y']) -def test_hex_lattice_roundtrip(orientation): - openmc.reset_auto_ids() - - # ensure that the lattice universes are the same on all axial levels - def check_lattice_universes(og_lattice, xml_lattice): - for axial_og, axial_rt in zip(og_lattice.universes, xml_lattice.universes): - for ring_og, ring_rt in zip(axial_og, axial_rt): - assert [u.id for u in ring_og] == [u.id for u in ring_rt] - - latt = openmc.HexLattice() - latt.pitch = (1.0, 1.0) - latt.center = (0.0, 0.0, 0.0) - latt.orientation = orientation - - # fill the lattice with universes in increasing order and repeat for - # the second actial level - lvl_one_univs = [openmc.Universe(cells=[openmc.Cell()]) for _ in range(19)] - lvl_one_univs = [lvl_one_univs[-12:], lvl_one_univs[1:7], lvl_one_univs[:1]] - latt.universes = [lvl_one_univs, lvl_one_univs] - - geom = openmc.Geometry([openmc.Cell(fill=latt)]) - geom.export_to_xml() - - xml_geom = openmc.Geometry.from_xml(materials=openmc.Materials()) - - xml_latt = xml_geom.get_all_lattices()[latt.id] - - check_lattice_universes(latt, xml_latt) - - # same test but with unique universes for each axial level - lvl_two_univs = [openmc.Universe(cells=[openmc.Cell()]) for _ in range(19)] - lvl_two_univs = [lvl_two_univs[-12:], lvl_two_univs[1:7], lvl_two_univs[:1]] - latt.universes = [lvl_one_univs, lvl_two_univs] - - geom.export_to_xml() - - xml_geom = openmc.Geometry.from_xml(materials=openmc.Materials()) - xml_latt = xml_geom.get_all_lattices()[latt.id] - - check_lattice_universes(latt, xml_latt) diff --git a/tests/unit_tests/test_lattice_discretization.py b/tests/unit_tests/test_lattice_discretization.py index c7779ea8b..b21d7e13e 100644 --- a/tests/unit_tests/test_lattice_discretization.py +++ b/tests/unit_tests/test_lattice_discretization.py @@ -34,8 +34,8 @@ def test_discretization_clone_only_some_materials(rlat2): fuel1 = next(iter(rlat_clone.get_universe((0, 0)).cells.values())).fill rlat_clone.discretize(materials_to_clone=[fuel1]) - assert next(reversed(list(rlat_clone.get_universe((0, 0)).cells.values()))).fill\ - == next(reversed(list(rlat_clone.get_universe((1, 0)).cells.values()))).fill + assert next(reversed(rlat_clone.get_universe((0, 0)).cells.values())).fill\ + == next(reversed(rlat_clone.get_universe((1, 0)).cells.values())).fill assert next(iter(rlat_clone.get_universe((0, 0)).cells.values())).fill\ != next(iter(rlat_clone.get_universe((1, 0)).cells.values())).fill diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 4cfae0df2..5063646f7 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -1,11 +1,9 @@ from collections.abc import Mapping -from math import pi import os import numpy as np import pytest import openmc -from openmc.examples import random_ray_pin_cell import openmc.exceptions as exc import openmc.lib @@ -68,10 +66,8 @@ def uo2_trigger_model(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box([-0.5, -0.5, -1], [0.5, 0.5, 1]), - constraints={'fissionable': True}, - ) + model.settings.source = openmc.Source(space=openmc.stats.Box( + [-0.5, -0.5, -1], [0.5, 0.5, 1], only_fissionable=True)) model.settings.verbosity = 1 model.settings.keff_trigger = {'type': 'std_dev', 'threshold': 0.001} model.settings.trigger_active = True @@ -84,19 +80,6 @@ def uo2_trigger_model(): yield -@pytest.fixture(scope='module') -def random_ray_pincell_model(): - """Set up a random ray model to test with and delete files when done""" - openmc.reset_auto_ids() - # Write XML and MGXS files in tmpdir - with cdtemp(): - model = random_ray_pin_cell() - model.settings.batches = 200 - model.settings.inactive = 50 - model.settings.particles = 50 - model.export_to_xml() - yield - @pytest.fixture(scope='module') def lib_init(pincell_model, mpi_intracomm): openmc.lib.init(intracomm=mpi_intracomm) @@ -143,7 +126,7 @@ def test_cell(lib_init): cell = openmc.lib.cells[1] assert isinstance(cell.fill, openmc.lib.Material) cell.fill = openmc.lib.materials[1] - assert str(cell) == '' + assert str(cell) == 'Cell[0]' assert cell.name == "Fuel" cell.name = "Not fuel" assert cell.name == "Not fuel" @@ -173,34 +156,6 @@ def test_properties_temperature(lib_init): assert cell.get_temperature() == pytest.approx(200.0) -def test_cell_density(lib_init): - cell = openmc.lib.cells[1] - print('density', cell.get_density()) - orig_density = cell.get_density() - try: - cell.set_density(1.5, 0) - assert cell.get_density(0) == pytest.approx(1.5) - cell.set_density(2.0) - assert cell.get_density() == pytest.approx(2.0) - finally: - cell.set_density(orig_density) - - -def test_properties_cell_density(lib_init): - # Cell density should be 2.0 from above test - cell = openmc.lib.cells[1] - orig_density = cell.get_density() - - # Export properties and change density - openmc.lib.export_properties('properties.h5') - cell.set_density(3.0) - assert cell.get_density() == pytest.approx(3.0) - - # Import properties and check that density is restored - openmc.lib.import_properties('properties.h5') - assert cell.get_density() == pytest.approx(orig_density) - - def test_new_cell(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Cell(1) @@ -251,10 +206,6 @@ def test_material(lib_init): m.name = "Not hot borated water" assert m.name == "Not hot borated water" - assert not m.depletable - m.depletable = True - assert m.depletable - def test_properties_density(lib_init): m = openmc.lib.materials[1] @@ -332,11 +283,6 @@ def test_energy_function_filter(lib_init): assert len(efunc.y) == 2 assert (efunc.y == [0.0, 2.0]).all() - # Default should be lin-lin - assert efunc.interpolation == 'linear-linear' - efunc.interpolation = 'histogram' - assert efunc.interpolation == 'histogram' - def test_tally(lib_init): t = openmc.lib.tallies[1] @@ -415,19 +361,6 @@ def test_tally_activate(lib_simulation_init): assert t.active -def test_tally_multiply_density(lib_simulation_init): - # multiply_density is True by default - t = openmc.lib.tallies[1] - assert t.multiply_density - - # Make sure setting multiply_density works - t.multiply_density = False - assert not t.multiply_density - - # Reset to True - t.multiply_density = True - - def test_tally_writable(lib_simulation_init): t = openmc.lib.tallies[1] assert t.writable @@ -510,6 +443,9 @@ def test_set_n_batches(lib_run): for i in range(7): openmc.lib.next_batch() + # Setting n_batches less than current_batch should raise error + with pytest.raises(exc.InvalidArgumentError): + settings.set_batches(6) # n_batches should stay the same assert settings.get_batches() == 10 @@ -607,14 +543,6 @@ def test_regular_mesh(lib_init): assert mesh.upper_right == pytest.approx(ur) assert mesh.width == pytest.approx(width) - np.testing.assert_allclose(mesh.volumes, 1.0) - - # bounding box - mesh.set_parameters(lower_left=ll, upper_right=ur) - bbox = mesh.bounding_box - np.testing.assert_allclose(bbox.lower_left, ll) - np.testing.assert_allclose(bbox.upper_right, ur) - meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) assert len(meshes) == 1 @@ -622,13 +550,6 @@ def test_regular_mesh(lib_init): assert isinstance(mesh, openmc.lib.RegularMesh) assert mesh_id == mesh.id - rotation = (180.0, 0.0, 0.0) - - mf = openmc.lib.MeshFilter(mesh) - assert mf.mesh == mesh - mf.rotation = rotation - assert np.allclose(mf.rotation, rotation) - translation = (1.0, 2.0, 3.0) mf = openmc.lib.MeshFilter(mesh) @@ -641,50 +562,6 @@ def test_regular_mesh(lib_init): msf.translation = translation assert msf.translation == translation - # Test material volumes - mesh = openmc.lib.RegularMesh() - mesh.dimension = (2, 2, 1) - mesh.set_parameters(lower_left=(-0.63, -0.63, -0.5), - upper_right=(0.63, 0.63, 0.5)) - vols = mesh.material_volumes() - assert vols.num_elements == 4 - for i in range(vols.num_elements): - elem_vols = vols.by_element(i) - assert sum(f[1] for f in elem_vols) == pytest.approx(1.26 * 1.26 / 4) - - # If the mesh extends beyond the boundaries of the model, we should get a - # GeometryError - mesh.dimension = (1, 1, 1) - mesh.set_parameters(lower_left=(-1.0, -1.0, -0.5), - upper_right=(1.0, 1.0, 0.5)) - with pytest.raises(exc.GeometryError, match="not fully contained"): - vols = mesh.material_volumes() - - -def test_regular_mesh_get_plot_bins(lib_init): - mesh: openmc.lib.RegularMesh = openmc.lib.meshes[2] - mesh.dimension = (2, 2, 1) - mesh.set_parameters(lower_left=(-1.0, -1.0, -0.5), - upper_right=(1.0, 1.0, 0.5)) - - # Get bins for a plot view covering only a single mesh bin - mesh_bins = mesh.get_plot_bins((-0.5, -0.5, 0.), (0.1, 0.1), 'xy', (20, 20)) - assert (mesh_bins == 0).all() - mesh_bins = mesh.get_plot_bins((0.5, 0.5, 0.), (0.1, 0.1), 'xy', (20, 20)) - assert (mesh_bins == 3).all() - - # Get bins for a plot view covering all mesh bins. Note that the y direction - # (first dimension) is flipped for plotting purposes - mesh_bins = mesh.get_plot_bins((0., 0., 0.), (2., 2.), 'xy', (20, 20)) - assert (mesh_bins[:10, :10] == 2).all() - assert (mesh_bins[:10, 10:] == 3).all() - assert (mesh_bins[10:, :10] == 0).all() - assert (mesh_bins[10:, 10:] == 1).all() - - # Get bins for a plot view outside of the mesh - mesh_bins = mesh.get_plot_bins((100., 100., 0.), (2., 2.), 'xy', (20, 20)) - assert (mesh_bins == -1).all() - def test_rectilinear_mesh(lib_init): mesh = openmc.lib.RectilinearMesh() @@ -700,19 +577,12 @@ def test_rectilinear_mesh(lib_init): for k, diff_z in enumerate(np.diff(z_grid)): assert np.all(mesh.width[i, j, k, :] == (10, 10, 10)) - np.testing.assert_allclose(mesh.volumes, 1000.0) - - # bounding box - bbox = mesh.bounding_box - np.testing.assert_allclose(bbox.lower_left, (-10., 0., 10.)) - np.testing.assert_allclose(bbox.upper_right, (10., 20., 30.)) - with pytest.raises(exc.AllocationError): mesh2 = openmc.lib.RectilinearMesh(mesh.id) meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) - assert len(meshes) == 3 + assert len(meshes) == 2 mesh = meshes[mesh.id] assert isinstance(mesh, openmc.lib.RectilinearMesh) @@ -723,21 +593,8 @@ def test_rectilinear_mesh(lib_init): msf = openmc.lib.MeshSurfaceFilter(mesh) assert msf.mesh == mesh - # Test material volumes - mesh = openmc.lib.RectilinearMesh() - w = 1.26 - mesh.set_grid([-w/2, -w/4, w/2], [-w/2, -w/4, w/2], [-0.5, 0.5]) - - vols = mesh.material_volumes() - assert vols.num_elements == 4 - assert sum(f[1] for f in vols.by_element(0)) == pytest.approx(w/4 * w/4) - assert sum(f[1] for f in vols.by_element(1)) == pytest.approx(w/4 * 3*w/4) - assert sum(f[1] for f in vols.by_element(2)) == pytest.approx(3*w/4 * w/4) - assert sum(f[1] for f in vols.by_element(3)) == pytest.approx(3*w/4 * 3*w/4) - - def test_cylindrical_mesh(lib_init): - deg2rad = lambda deg: deg*pi/180 + deg2rad = lambda deg: deg*np.pi/180 mesh = openmc.lib.CylindricalMesh() r_grid = [0., 5., 10.] phi_grid = np.radians([0., 10., 20.]) @@ -751,20 +608,12 @@ def test_cylindrical_mesh(lib_init): for k, _ in enumerate(np.diff(z_grid)): assert np.allclose(mesh.width[i, j, k, :], (5, deg2rad(10), 10)) - np.testing.assert_allclose(mesh.volumes[::2], 10/360 * pi * 5**2 * 10) - np.testing.assert_allclose(mesh.volumes[1::2], 10/360 * pi * (10**2 - 5**2) * 10) - - # bounding box - bbox = mesh.bounding_box - np.testing.assert_allclose(bbox.lower_left, (-10., -10., 10.)) - np.testing.assert_allclose(bbox.upper_right, (10., 10., 30.)) - with pytest.raises(exc.AllocationError): mesh2 = openmc.lib.CylindricalMesh(mesh.id) meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) - assert len(meshes) == 5 + assert len(meshes) == 3 mesh = meshes[mesh.id] assert isinstance(mesh, openmc.lib.CylindricalMesh) @@ -775,21 +624,6 @@ def test_cylindrical_mesh(lib_init): msf = openmc.lib.MeshSurfaceFilter(mesh) assert msf.mesh == mesh - # Test material volumes - mesh = openmc.lib.CylindricalMesh() - r_grid = (0., 0.25, 0.5) - phi_grid = np.linspace(0., 2.0*pi, 4) - z_grid = (-0.5, 0.5) - mesh.set_grid(r_grid, phi_grid, z_grid) - - vols = mesh.material_volumes() - assert vols.num_elements == 6 - for i in range(0, 6, 2): - assert sum(f[1] for f in vols.by_element(i)) == pytest.approx(pi * 0.25**2 / 3) - for i in range(1, 6, 2): - assert sum(f[1] for f in vols.by_element(i)) == pytest.approx(pi * (0.5**2 - 0.25**2) / 3) - - def test_spherical_mesh(lib_init): deg2rad = lambda deg: deg*np.pi/180 mesh = openmc.lib.SphericalMesh() @@ -805,24 +639,12 @@ def test_spherical_mesh(lib_init): for k, _ in enumerate(np.diff(phi_grid)): assert np.allclose(mesh.width[i, j, k, :], (5, deg2rad(10), deg2rad(10))) - dtheta = lambda d1, d2: np.cos(deg2rad(d1)) - np.cos(deg2rad(d2)) - f = 1/3 * deg2rad(10.) - np.testing.assert_allclose(mesh.volumes[::4], f * 5**3 * dtheta(0., 10.)) - np.testing.assert_allclose(mesh.volumes[1::4], f * (10**3 - 5**3) * dtheta(0., 10.)) - np.testing.assert_allclose(mesh.volumes[2::4], f * 5**3 * dtheta(10., 20.)) - np.testing.assert_allclose(mesh.volumes[3::4], f * (10**3 - 5**3) * dtheta(10., 20.)) - - # bounding box - bbox = mesh.bounding_box - np.testing.assert_allclose(bbox.lower_left, (-10., -10., -10.)) - np.testing.assert_allclose(bbox.upper_right, (10., 10., 10.)) - with pytest.raises(exc.AllocationError): mesh2 = openmc.lib.SphericalMesh(mesh.id) meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) - assert len(meshes) == 7 + assert len(meshes) == 4 mesh = meshes[mesh.id] assert isinstance(mesh, openmc.lib.SphericalMesh) @@ -833,24 +655,6 @@ def test_spherical_mesh(lib_init): msf = openmc.lib.MeshSurfaceFilter(mesh) assert msf.mesh == mesh - # Test material volumes - mesh = openmc.lib.SphericalMesh() - r_grid = (0., 0.25, 0.5) - theta_grid = np.linspace(0., pi, 3) - phi_grid = np.linspace(0., 2.0*pi, 4) - mesh.set_grid(r_grid, theta_grid, phi_grid) - - vols = mesh.material_volumes() - assert vols.num_elements == 12 - d_theta = theta_grid[1] - theta_grid[0] - d_phi = phi_grid[1] - phi_grid[0] - for i in range(0, 12, 2): - assert sum(f[1] for f in vols.by_element(i)) == pytest.approx( - 0.25**3 / 3 * d_theta * d_phi * 2/pi) - for i in range(1, 12, 2): - assert sum(f[1] for f in vols.by_element(i)) == pytest.approx( - (0.5**3 - 0.25**3) / 3 * d_theta * d_phi * 2/pi) - def test_restart(lib_init, mpi_intracomm): # Finalize and re-init to make internal state consistent with XML. @@ -895,23 +699,22 @@ def test_load_nuclide(lib_init): openmc.lib.load_nuclide('Pu3') -class LegacySlicePlot: - origin = (0.0, 0.0, 0.0) - width = 1.26 - height = 1.26 - basis = 'xy' - h_res = 3 - v_res = 3 - level = -1 - - def test_id_map(lib_init): expected_ids = np.array([[(3, 0, 3), (2, 0, 2), (3, 0, 3)], [(2, 0, 2), (1, 0, 1), (2, 0, 2)], [(3, 0, 3), (2, 0, 2), (3, 0, 3)]], dtype='int32') - with pytest.warns(FutureWarning, match="deprecated"): - ids = openmc.lib.id_map(LegacySlicePlot()) + # create a plot object + s = openmc.lib.plot._PlotBase() + s.width = 1.26 + s.height = 1.26 + s.v_res = 3 + s.h_res = 3 + s.origin = (0.0, 0.0, 0.0) + s.basis = 'xy' + s.level = -1 + + ids = openmc.lib.plot.id_map(s) assert np.array_equal(expected_ids, ids) @@ -921,81 +724,20 @@ def test_property_map(lib_init): [ (293.6, 6.55), (293.6, 10.29769), (293.6, 6.55)], [(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)]], dtype='float') - with pytest.warns(FutureWarning, match="deprecated"): - properties = openmc.lib.property_map(LegacySlicePlot()) + # create a plot object + s = openmc.lib.plot._PlotBase() + s.width = 1.26 + s.height = 1.26 + s.v_res = 3 + s.h_res = 3 + s.origin = (0.0, 0.0, 0.0) + s.basis = 'xy' + s.level = -1 + + properties = openmc.lib.plot.property_map(s) assert np.allclose(expected_properties, properties, atol=1e-04) -def test_slice_data(lib_init): - expected_properties = np.array( - [[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)], - [ (293.6, 6.55), (293.6, 10.29769), (293.6, 6.55)], - [(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)]], dtype='float') - origin = (0.0, 0.0, 0.0) - _, properties = openmc.lib.slice_data( - origin, - width=(1.26, 1.26), - basis='xy', - pixels=(3, 3), - include_properties=True - ) - assert np.allclose(expected_properties, properties, atol=1e-04) - - -def test_solid_raytrace_plot(lib_init, pincell_model): - # Ensure plot mapping can be accessed and grows after allocation - n0 = len(openmc.lib.plots) - plot = openmc.lib.SolidRayTracePlot() - assert len(openmc.lib.plots) == n0 + 1 - assert plot.id in openmc.lib.plots - assert openmc.lib.plots[plot.id] is plot - - # Exercise plot property getters/setters - plot.pixels = (8, 6) - assert plot.pixels == (8, 6) - - plot.color_by = openmc.lib.SolidRayTracePlot.COLOR_BY_MATERIAL - assert plot.color_by == openmc.lib.SolidRayTracePlot.COLOR_BY_MATERIAL - - plot.camera_position = (2.0, 0.0, 1.0) - plot.look_at = (0.0, 0.0, 0.0) - plot.up = (0.0, 0.0, 1.0) - plot.light_position = (3.0, 2.0, 4.0) - plot.fov = 60.0 - plot.diffuse_fraction = 0.4 - assert plot.camera_position == pytest.approx((2.0, 0.0, 1.0)) - assert plot.look_at == pytest.approx((0.0, 0.0, 0.0)) - assert plot.up == pytest.approx((0.0, 0.0, 1.0)) - assert plot.light_position == pytest.approx((3.0, 2.0, 4.0)) - assert plot.fov == pytest.approx(60.0) - assert plot.diffuse_fraction == pytest.approx(0.4) - - # Exercise color/visibility CAPI wrappers - plot.set_default_colors() - plot.set_color(1, (12, 34, 56)) - assert plot.get_color(1) == (12, 34, 56) - plot.set_visibility(1, False) - plot.set_visibility(1, True) - - # Confirm image creation path works and dimensions match pixels - plot.update_view() - image = plot.create_image() - assert image.shape == (6, 8, 3) - assert image.dtype == np.uint8 - - # Change some properties and confirm image changes - plot.set_color(1, (255, 0, 0)) - plot.update_view() - image2 = plot.create_image() - assert not np.array_equal(image, image2) - - # Solid raytrace uses Phong/diffuse shading, so rendered RGB values are - # generally modulated and need not exactly match the assigned palette. - changed = np.any(image != image2, axis=2) - assert np.any(changed) - assert np.mean(image2[..., 0][changed]) > np.mean(image[..., 0][changed]) - - def test_position(lib_init): pos = openmc.lib.plot._Position(1.0, 2.0, 3.0) @@ -1089,11 +831,10 @@ def test_sample_external_source(run_in_tmpdir, mpi_intracomm): cell = openmc.Cell(fill=mat, region=-sph) model = openmc.Model() model.geometry = openmc.Geometry([cell]) - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( space=openmc.stats.Box([-5., -5., -5.], [5., 5., 5.]), angle=openmc.stats.Monodirectional((0., 0., 1.)), - energy=openmc.stats.Discrete([1.0e5], [1.0]), - constraints={'fissionable': True} + energy=openmc.stats.Discrete([1.0e5], [1.0]) ) model.settings.particles = 1000 model.settings.batches = 10 @@ -1122,29 +863,4 @@ def test_sample_external_source(run_in_tmpdir, mpi_intracomm): assert p1.time == p2.time assert p1.wgt == p2.wgt - # as_array should return a numpy structured array with matching values - arr = openmc.lib.sample_external_source(10, prn_seed=3, as_array=True) - assert isinstance(arr, np.ndarray) - assert len(arr) == 10 - for p, row in zip(particles, arr): - assert p.r == pytest.approx(row['r']) - assert p.E == pytest.approx(row['E']) - - openmc.lib.finalize() - - # Make sure sampling works in volume calculation mode - openmc.lib.init(["-c"]) - openmc.lib.sample_external_source(100) - openmc.lib.finalize() - - -def test_random_ray(random_ray_pincell_model, mpi_intracomm): - openmc.lib.finalize() - openmc.lib.init(intracomm=mpi_intracomm) - openmc.lib.simulation_init() - openmc.lib.run_random_ray() - keff = openmc.lib.keff() - - assert keff[0]==pytest.approx(1.3236826574065745) - openmc.lib.finalize() diff --git a/tests/unit_tests/test_lost_particles.py b/tests/unit_tests/test_lost_particles.py deleted file mode 100644 index 478ddbaf0..000000000 --- a/tests/unit_tests/test_lost_particles.py +++ /dev/null @@ -1,49 +0,0 @@ -from pathlib import Path - -import openmc -import pytest - -from tests.testing_harness import config - - -@pytest.fixture -def model(): - mat = openmc.Material() - mat.add_nuclide('N14', 1.0) - mat.set_density('g/cm3', 1e-5) - - s1 = openmc.Sphere(r=80.0) - s2 = openmc.Sphere(r=90.0) - s3 = openmc.Sphere(r=100.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=mat, region=-s1) - cell2 = openmc.Cell(fill=mat, region=+s2 & -s3) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2]) - - model.settings.run_mode = 'fixed source' - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 50 - model.settings.max_lost_particles = 1000 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) - - return model - - -def test_max_write_lost_particles(model: openmc.Model, run_in_tmpdir): - # Set maximum number of lost particle restart files - model.settings.max_write_lost_particles = 5 - - # Run OpenMC to generate lost particle files. Use one thread so that we know - # exactly how much will be produced. If running in MPI mode, setup proper - # keyword arguments for run() - kwargs = {'openmc_exec': config['exe']} - if config['mpi']: - kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] - model.run(threads=1, **kwargs) - - # Make sure number of lost particle files is as expected - lost_particle_files = list(Path.cwd().glob('particle*.h5')) - n_procs = int(config['mpi_np']) if config['mpi'] else 1 - assert len(lost_particle_files) == model.settings.max_write_lost_particles * n_procs - diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index 12d363376..451c5308a 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -1,13 +1,8 @@ from collections import defaultdict -from pathlib import Path import pytest -import numpy as np - import openmc -from openmc.data import decay_photon_energy -from openmc.deplete import Chain, Nuclide import openmc.examples import openmc.model import openmc.stats @@ -37,7 +32,6 @@ def test_add_components(): 'O16': 1.0, 'Zr': 1.0, 'O': 1.0, - 'Ag110_m1': 1.0, 'U': {'percent': 1.0, 'enrichment': 4.5}, 'Li': {'percent': 1.0, @@ -78,25 +72,6 @@ def test_add_components(): m.add_components({'H1': 1.0}, percent_type = 'oa') -def test_id(): - openmc.Material(material_id=0) - with pytest.raises(ValueError): - openmc.Material(material_id=-1) - - -def test_nuclides_to_ignore(run_in_tmpdir): - """Test nuclides_to_ignore when exporting a material to XML""" - m = openmc.Material() - m.add_nuclide('U235', 1.0) - m.add_nuclide('H1', 1.0) - m.add_nuclide('O16', 1.0) - - mats = openmc.Materials([m]) - mats.export_to_xml(nuclides_to_ignore=['H1']) - - test_mats = openmc.Materials.from_xml() - assert 'H1' not in test_mats[0].get_nuclides() - def test_remove_nuclide(): """Test removing nuclides.""" m = openmc.Material() @@ -324,23 +299,6 @@ def test_isotropic(): assert m2.isotropic == ['H1'] -def test_get_nuclides(): - mat = openmc.Material() - - mat.add_nuclide('Li6', 1.0) - assert mat.get_nuclides() == ['Li6'] - assert mat.get_nuclides(element='Li') == ['Li6'] - assert mat.get_nuclides(element='Be') == [] - - mat.add_element('Li', 1.0) - assert mat.get_nuclides() == ['Li6', 'Li7'] - assert mat.get_nuclides(element='Be') == [] - - mat.add_element('Be', 1.0) - assert mat.get_nuclides() == ['Li6', 'Li7', 'Be9'] - assert mat.get_nuclides(element='Be') == ['Be9'] - - def test_get_elements(): # test that zero elements exist on creation m = openmc.Material() @@ -381,37 +339,6 @@ def test_get_nuclide_atom_densities(uo2): assert density > 0 -def test_get_nuclide_atom_densities_specific(uo2): - one_nuc = uo2.get_nuclide_atom_densities(nuclide='O16') - assert list(one_nuc.keys()) == ['O16'] - assert list(one_nuc.values())[0] > 0 - - all_nuc = uo2.get_nuclide_atom_densities() - assert all_nuc['O16'] == one_nuc['O16'] - - -def test_get_element_atom_densities(uo2): - for element, density in uo2.get_element_atom_densities().items(): - assert element in ('U', 'O') - assert density > 0 - - -def test_get_element_atom_densities_specific(uo2): - one_nuc = uo2.get_element_atom_densities('O') - assert list(one_nuc.keys()) == ['O'] - assert list(one_nuc.values())[0] > 0 - - one_nuc = uo2.get_element_atom_densities('uranium') - assert list(one_nuc.keys()) == ['U'] - assert list(one_nuc.values())[0] > 0 - - with pytest.raises(ValueError, match='not found'): - uo2.get_element_atom_densities('Li') - - with pytest.raises(ValueError, match='not recognized'): - uo2.get_element_atom_densities('proximium') - - def test_get_nuclide_atoms(): mat = openmc.Material() mat.add_nuclide('Li6', 1.0) @@ -421,9 +348,6 @@ def test_get_nuclide_atoms(): atoms = mat.get_nuclide_atoms() assert atoms['Li6'] == pytest.approx(mat.density * mat.volume) - atoms = mat.get_nuclide_atoms(volume=10.0) - assert atoms['Li6'] == pytest.approx(mat.density * 10.0) - def test_mass(): m = openmc.Material() @@ -441,9 +365,6 @@ def test_mass(): assert m.get_mass() == pytest.approx(20.0) assert m.fissionable_mass == pytest.approx(10.0) - # Test with volume specified as argument - assert m.get_mass('Zr90', volume=1.0) == pytest.approx(1.0) - def test_materials(run_in_tmpdir): m1 = openmc.Material() @@ -488,7 +409,6 @@ def test_borated_water(): # Test the density override m = openmc.model.borated_water(975, 566.5, 15.51, density=0.9) assert m.density == pytest.approx(0.9, 1e-3) - assert m.temperature == pytest.approx(566.5) def test_from_xml(run_in_tmpdir): @@ -544,13 +464,11 @@ def test_mix_materials(): dens4 = 1. / (f0 / m1dens + f1 / m2dens) dens5 = f0*m1dens + f1*m2dens m3 = openmc.Material.mix_materials([m1, m2], [f0, f1], percent_type='ao') - m4 = openmc.Material.mix_materials([m1, m2], [f0, f1], percent_type='wo', material_id=999) - m5 = openmc.Material.mix_materials([m1, m2], [f0, f1], percent_type='vo', name='m5') + m4 = openmc.Material.mix_materials([m1, m2], [f0, f1], percent_type='wo') + m5 = openmc.Material.mix_materials([m1, m2], [f0, f1], percent_type='vo') assert m3.density == pytest.approx(dens3) assert m4.density == pytest.approx(dens4) assert m5.density == pytest.approx(dens5) - assert m4.id == 999 - assert m5.name == 'm5' def test_get_activity(): @@ -561,10 +479,6 @@ def test_get_activity(): m1.add_element("Fe", 0.7) m1.add_element("Li", 0.3) m1.set_density('g/cm3', 1.5) - with pytest.raises(ValueError, match="Volume must be set"): - m1.get_activity(units='Bq') - with pytest.raises(ValueError, match="Volume must be set"): - m1.get_activity(units='Ci') # activity in Bq/cc and Bq/g should not require volume setting assert m1.get_activity(units='Bq/cm3') == 0 assert m1.get_activity(units='Bq/g') == 0 @@ -594,331 +508,9 @@ def test_get_activity(): m4.add_nuclide("H3", 1) m4.set_density('g/cm3', 1.5) assert pytest.approx(m4.get_activity(units='Bq/g')) == 355978108155965.94 # [Bq/g] - assert pytest.approx(m4.get_activity(units='Bq/kg')) == 355978108155965940 # [Bq/kg] assert pytest.approx(m4.get_activity(units='Bq/g', by_nuclide=True)["H3"]) == 355978108155965.94 # [Bq/g] assert pytest.approx(m4.get_activity(units='Bq/cm3')) == 355978108155965.94*3/2 # [Bq/cc] assert pytest.approx(m4.get_activity(units='Bq/cm3', by_nuclide=True)["H3"]) == 355978108155965.94*3/2 # [Bq/cc] - assert pytest.approx(m4.get_activity(units='Bq/m3')) == 355978108155965.94*3/2*1e6 # [Bq/m3] - assert pytest.approx(m4.get_activity(units='Bq/m3', by_nuclide=True)["H3"]) == 355978108155965.94*3/2*1e6 # [Bq/m3] # volume is required to calculate total activity m4.volume = 10. assert pytest.approx(m4.get_activity(units='Bq')) == 355978108155965.94*3/2*10 # [Bq] - - # Test with volume specified as argument - assert pytest.approx(m4.get_activity(units='Bq', volume=1.0)) == 355978108155965.94*3/2 - - # Test units based on Ci - bq = m4.get_activity(units='Bq') - m3 = m4.volume * 1e-6 - assert (ci := m4.get_activity(units='Ci')) == pytest.approx(bq/3.7e10) - assert m4.get_activity(units='Ci/m3') == pytest.approx(ci/m3) - - -def test_get_activity_chain_file(tmp_path): - m = openmc.Material() - m.add_nuclide("H3", 1.0) - m.set_density('g/cm3', 1.0) - - chain = Chain() - h3 = Nuclide("H3") - h3.half_life = 1.0 - chain.add_nuclide(h3) - - atoms_per_bcm = m.get_nuclide_atom_densities()["H3"] - expected = np.log(2.0) * 1e24 * atoms_per_bcm - - assert m.get_activity(chain_file=chain) == pytest.approx(expected) - - chain_path = tmp_path / "chain.xml" - chain.export_to_xml(chain_path) - assert m.get_activity(chain_file=chain_path) == pytest.approx(expected) - - endf_activity = m.get_activity(chain_file=False) - with openmc.config.patch('chain_file', chain_path): - assert m.get_activity() == pytest.approx(expected) - assert m.get_activity(chain_file=False) == pytest.approx(endf_activity) - - stable_chain = Chain() - stable_chain.add_nuclide(Nuclide("H3")) - assert m.get_activity(chain_file=stable_chain) == 0.0 - - -def test_get_decay_heat(): - # Set chain file for testing - openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' - - """Tests the decay heat of stable, metastable and active materials""" - m1 = openmc.Material() - m1.add_nuclide("U235", 0.2) - m1.add_nuclide("U238", 0.8) - m1.set_density('g/cm3', 10.5) - with pytest.raises(ValueError, match="Volume must be set"): - m1.get_decay_heat(units='W') - # decay heat in W/cc and W/g should not require volume setting - assert m1.get_decay_heat(units='W/cm3') == 0 - assert m1.get_decay_heat(units='W/g') == 0 - m1.volume = 1 - assert m1.get_decay_heat(units='W') == 0 - - # Checks that 1g of tritium has the correct decay heat scaling - m2 = openmc.Material() - m2.add_nuclide("I135", 1) - m2.set_density('g/cm3', 1) - m2.volume = 1 - assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193 - m2.set_density('g/cm3', 2) - assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193*2 - m2.volume = 3 - assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193*2*3 - - # Checks that 1 mol of a metastable nuclides has the correct decay heat - m3 = openmc.Material() - m3.add_nuclide("Xe135", 1) - m3.set_density('g/cm3', 1) - m3.volume = 98.9 - assert pytest.approx(m3.get_decay_heat(units='W'), rel=0.001) == 846181.2921143445 - - # Checks that specific and volumetric decay heat of tritium are correct - m4 = openmc.Material() - m4.add_nuclide("I135", 1) - m4.set_density('g/cm3', 1.5) - assert pytest.approx(m4.get_decay_heat(units='W/g')) == 40175.15720273193 # [W/g] - assert pytest.approx(m4.get_decay_heat(units='W/kg')) == 40175157.20273193 # [W/kg] - assert pytest.approx(m4.get_decay_heat(units='W/g', by_nuclide=True)["I135"]) == 40175.15720273193 # [W/g] - assert pytest.approx(m4.get_decay_heat(units='W/cm3')) == 40175.15720273193*3/2 # [W/cc] - assert pytest.approx(m4.get_decay_heat(units='W/cm3', by_nuclide=True)["I135"]) == 40175.15720273193*3/2 #[W/cc] - assert pytest.approx(m4.get_decay_heat(units='W/m3')) == 40175.15720273193*3/2*1e6 # [W/m3] - assert pytest.approx(m4.get_decay_heat(units='W/m3', by_nuclide=True)["I135"]) == 40175.15720273193*3/2*1e6 # [W/m3] - # volume is required to calculate total decay heat - m4.volume = 10. - assert pytest.approx(m4.get_decay_heat(units='W')) == 40175.15720273193*3/2*10 # [W] - - # Test with volume specified as argument - assert pytest.approx(m4.get_decay_heat(units='W', volume=1.0)) == 40175.15720273193*3/2 - - -def test_decay_photon_energy(): - # Set chain file for testing - openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' - - # Material representing single atom of I135 and Cs135 - m = openmc.Material() - m.add_nuclide('I135', 1.0e-24) - m.add_nuclide('Cs135', 1.0e-24) - m.volume = 1.0 - - # Get decay photon source and make sure it's the right type - src = m.get_decay_photon_energy() - assert isinstance(src, openmc.stats.Discrete) - - # Make sure units/volume work as expected - src_v2 = m.get_decay_photon_energy(volume=2.0) - assert src.p * 2.0 == pytest.approx(src_v2.p) - src_per_cm3 = m.get_decay_photon_energy(units='Bq/cm3', volume=100.0) - assert (src.p == src_per_cm3.p).all() - src_per_bqg = m.get_decay_photon_energy(units='Bq/g') - src_per_bqkg = m.get_decay_photon_energy(units='Bq/kg') - assert pytest.approx(src_per_bqg.integral()) == src_per_bqkg.integral() / 1000. - src_per_bqm3 = m.get_decay_photon_energy(units='Bq/m3') - assert pytest.approx(src_per_bqm3.integral()) == src_per_cm3.integral() * 1e6 - - # If we add Xe135 (which has a tabular distribution), the photon source - # should be a mixture distribution - m.add_nuclide('Xe135', 1.0e-24) - src = m.get_decay_photon_energy() - assert isinstance(src, openmc.stats.Mixture) - - # With a single atom of each, the intensity of the photon source should be - # equal to the sum of the intensities for each nuclide - def intensity(src): - return src.integral() if src is not None else 0.0 - - assert src.integral() == pytest.approx(sum( - intensity(decay_photon_energy(nuc)) for nuc in m.get_nuclides() - ), rel=1e-3) - - # When the clipping threshold is zero, the intensities should match exactly - src = m.get_decay_photon_energy(0.0) - assert src.integral() == pytest.approx(sum( - intensity(decay_photon_energy(nuc)) for nuc in m.get_nuclides() - )) - - # A material with no unstable nuclides should have no decay photon source - stable = openmc.Material() - stable.add_nuclide('Gd156', 1.0) - stable.volume = 1.0 - assert stable.get_decay_photon_energy() is None - - -def test_avoid_subnormal(run_in_tmpdir): - # Write a materials.xml with a material that has a nuclide density that is - # represented as a subnormal floating point value - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - mat.add_nuclide('H2', 1.0e-315) - mats = openmc.Materials([mat]) - mats.export_to_xml() - - # When read back in, the density should be zero - mats = openmc.Materials.from_xml() - assert mats[0].get_nuclide_atom_densities()['H2'] == 0.0 - - -def test_material_deplete(): - pristine_material = openmc.Material() - pristine_material.add_nuclide("Ni58", 1.0) - pristine_material.set_density("g/cm3", 7.87) - pristine_material.depletable = True - pristine_material.temperature = 293.6 - pristine_material.volume = 1. - - mg_flux = [0.5e11] * 42 - - chain = Chain.from_xml( - Path(__file__).parents[1] / "chain_ni.xml" - ) - - depleted_material = pristine_material.deplete( - multigroup_flux=mg_flux, - energy_group_structure="VITAMIN-J-42", - timesteps=[10, 70.86], - source_rates=[1e19, 0.0], - timestep_units="d", - chain_file=chain, - ) - - for i_step, material in enumerate(depleted_material): - assert isinstance(material, openmc.Material) - if i_step > 0: - assert len(material.get_nuclides()) > len(pristine_material.get_nuclides()) - - Co58_mat_1_step_0 = depleted_material[0].get_nuclide_atom_densities("Co58").get("Co58", 0.0) - Co58_mat_1_step_1 = depleted_material[1].get_nuclide_atom_densities("Co58")["Co58"] - Co58_mat_1_step_2 = depleted_material[2].get_nuclide_atom_densities("Co58")["Co58"] - - assert Co58_mat_1_step_0 == 0.0 - - # Check that Co58 is produced in the first step - assert Co58_mat_1_step_1 > 0.0 - - # Check that Co58 is halved in the second step which is one halflife later - assert np.allclose(Co58_mat_1_step_1 * 0.5, Co58_mat_1_step_2) - - -def test_mean_free_path(): - - mat1 = openmc.Material() - mat1.add_nuclide('Si28', 1.0) - mat1.set_density('g/cm3', 2.32) - assert mat1.mean_free_path(energy=14e6) == pytest.approx(11.41, abs=1e-2) - - mat2 = openmc.Material() - mat2.add_nuclide('Pb208', 1.0) - mat2.set_density('g/cm3', 11.34) - assert mat2.mean_free_path(energy=14e6) == pytest.approx(5.65, abs=1e-2) - - -def test_material_from_constructor(): - # Test that components and percent_type work in the constructor - components = { - 'Li': {'percent': 0.5, 'enrichment': 60.0, 'enrichment_target': 'Li7'}, - 'O16': 1.0, - 'Be': 0.5 - } - mat = openmc.Material( - material_id=123, - name="test-mat", - components=components, - percent_type="ao" - ) - # Check that nuclides were added - nuclide_names = [nuc.name for nuc in mat.nuclides] - assert 'O16' in nuclide_names - assert 'Be9' in nuclide_names - assert 'Li7' in nuclide_names - assert 'Li6' in nuclide_names - assert mat.id == 123 - assert mat.name == "test-mat" - - mat1 = openmc.Material( - **{ - "material_id": 1, - "name": "neutron_star", - "density": 1e17, - "density_units": "kg/m3", - } - ) - assert mat1.id == 1 - assert mat1.name == "neutron_star" - assert mat1._density == 1e17 - assert mat1._density_units == "kg/m3" - assert mat1.nuclides == [] - - mat2 = openmc.Material( - material_id=42, - name="plasma", - temperature=None, - density=1e-7, - density_units="g/cm3", - ) - assert mat2.id == 42 - assert mat2.name == "plasma" - assert mat2.temperature is None - assert mat2.density == 1e-7 - assert mat2.density_units == "g/cm3" - assert mat2.nuclides == [] - - -def test_get_photon_contact_dose_rate(): - # Set chain file for testing - openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' - - # A purely stable material (Fe) should give zero dose - m_stable = openmc.Material() - m_stable.add_element('Fe', 1.0) - m_stable.set_density('g/cm3', 7.87) - assert m_stable.get_photon_contact_dose_rate('absorbed-air') == 0.0 - assert m_stable.get_photon_contact_dose_rate('effective') == 0.0 - - # I135 has a Discrete photon source (lines) - m_i135 = openmc.Material() - m_i135.add_nuclide('I135', 1.0) - m_i135.set_density('atom/b-cm', 1.0) - - cdr_abs = m_i135.get_photon_contact_dose_rate('absorbed-air') - cdr_eff = m_i135.get_photon_contact_dose_rate('effective') - assert cdr_abs == pytest.approx(6.091547e10, rel=1e-4) # [Gy/h] - assert cdr_eff == pytest.approx(6.102167e10, rel=1e-4) # [Sv/h] - - # Xe135 has a Tabular photon source (continuous distribution) - m_xe135 = openmc.Material() - m_xe135.add_nuclide('Xe135', 1.0) - m_xe135.set_density('atom/b-cm', 1.0) - - cdr_xe_abs = m_xe135.get_photon_contact_dose_rate('absorbed-air') - cdr_xe_eff = m_xe135.get_photon_contact_dose_rate('effective') - assert cdr_xe_abs == pytest.approx(7.886077e8, rel=1e-4) # [Gy/h] - assert cdr_xe_eff == pytest.approx(9.488298e8, rel=1e-4) # [Sv/h] - - # by_nuclide=True should return a dict whose values sum to the total - cdr_by_nuc = m_i135.get_photon_contact_dose_rate('absorbed-air', by_nuclide=True) - assert isinstance(cdr_by_nuc, dict) - assert 'I135' in cdr_by_nuc - assert sum(cdr_by_nuc.values()) == pytest.approx(cdr_abs) - - # For a mixed material the sum over nuclides must equal the total - m_mix = openmc.Material() - m_mix.add_nuclide('I135', 0.5) - m_mix.add_nuclide('Xe135', 0.5) - m_mix.set_density('atom/b-cm', 1.0) - cdr_mix_total = m_mix.get_photon_contact_dose_rate('absorbed-air') - cdr_mix_nuc = m_mix.get_photon_contact_dose_rate('absorbed-air', by_nuclide=True) - assert sum(cdr_mix_nuc.values()) == pytest.approx(cdr_mix_total) - - # Input validation - with pytest.raises(ValueError): - m_i135.get_photon_contact_dose_rate('invalid-quantity') - with pytest.raises(TypeError): - m_i135.get_photon_contact_dose_rate('absorbed-air', build_up='two') - with pytest.raises(ValueError): - m_i135.get_photon_contact_dose_rate('absorbed-air', build_up=-1.0) diff --git a/tests/unit_tests/test_materials.py b/tests/unit_tests/test_materials.py deleted file mode 100644 index 6620402fd..000000000 --- a/tests/unit_tests/test_materials.py +++ /dev/null @@ -1,129 +0,0 @@ -from pathlib import Path - -import pytest - -import openmc -from openmc.deplete import Chain - - -def test_materials_deplete(): - pristine_material_1 = openmc.Material() - pristine_material_1.add_nuclide("Ni58", 1.) - pristine_material_1.set_density("g/cm3", 7.87) - pristine_material_1.depletable = True - pristine_material_1.temperature = 293.6 - pristine_material_1.volume = 1. - - pristine_material_2 = openmc.Material() - pristine_material_2.add_nuclide("Ni60", 1.) - pristine_material_2.set_density("g/cm3", 7.87) - pristine_material_2.depletable = True - pristine_material_2.temperature = 293.6 - pristine_material_2.volume = 1. - - pristine_materials = openmc.Materials([pristine_material_1, pristine_material_2]) - - mg_flux = [0.5e11] * 42 - - chain = Chain.from_xml( - Path(__file__).parents[1] / "chain_ni.xml" - ) - - depleted_material = pristine_materials.deplete( - multigroup_fluxes=[mg_flux, mg_flux], - energy_group_structures=["VITAMIN-J-42", "VITAMIN-J-42"], - timesteps=[100, 100], - source_rates=[1e19, 0.0], - timestep_units="d", - chain_file=chain, - ) - - assert list(depleted_material.keys()) == [pristine_material_1.id, pristine_material_2.id] - for mat_id, materials in depleted_material.items(): - for i_step, material in enumerate(materials): - assert isinstance(material, openmc.Material) - if i_step > 0: - assert len(material.get_nuclides()) > 1 - assert mat_id == material.id - - mats = depleted_material[pristine_material_1.id] - Co58_mat_1_step_0 = mats[0].get_nuclide_atom_densities("Co58").get("Co58", 0.0) - Co58_mat_1_step_1 = mats[1].get_nuclide_atom_densities("Co58")["Co58"] - Co58_mat_1_step_2 = mats[2].get_nuclide_atom_densities("Co58")["Co58"] - - assert Co58_mat_1_step_0 == 0.0 - # Co58 is the main activation product of Ni58 in the first irradiation step. - # It then decays in the second cooling step (flux = 0) - assert Co58_mat_1_step_1 > 0.0 and Co58_mat_1_step_1 > Co58_mat_1_step_2 - - Ni59_mat_1_step_0 = mats[0].get_nuclide_atom_densities("Ni59").get("Ni59", 0.0) - Ni59_mat_1_step_1 = mats[1].get_nuclide_atom_densities("Ni59")["Ni59"] - Ni59_mat_1_step_2 = mats[2].get_nuclide_atom_densities("Ni59")["Ni59"] - - assert Ni59_mat_1_step_0 == 0.0 - # Ni59 is one of the main activation product of Ni60 in the first irradiation - # step. It then decays in the second cooling step (flux = 0) - assert Ni59_mat_1_step_1 > 0.0 and Ni59_mat_1_step_1 > Ni59_mat_1_step_2 - - -def test_export_duplicate_materials_to_xml(run_in_tmpdir): - """ - Test exporting Materials to xml with a duplicate and checking that only - unique entities are exported. - """ - my_mat = openmc.Material(name="my_mat") - my_mat2 = openmc.Material(name="my_mat2") - - materials = openmc.Materials([my_mat, my_mat2, my_mat]) - - materials.export_to_xml("materials.xml") - - materials_in = openmc.Materials.from_xml("materials.xml") - assert len(materials_in) == 2 - - -def test_materials_deplete_length_mismatch(): - mats = openmc.Materials([openmc.Material()]) - - with pytest.raises(ValueError, match="multigroup_fluxes length"): - mats.deplete( - multigroup_fluxes=[], - energy_group_structures=["VITAMIN-J-42"], - timesteps=[1.0], - source_rates=1.0, - ) - - with pytest.raises(ValueError, match="energy_group_structures length"): - mats.deplete( - multigroup_fluxes=[[1.0]], - energy_group_structures=[], - timesteps=[1.0], - source_rates=1.0, - ) - - -def test_materials_deplete_missing_volume(monkeypatch): - mat = openmc.Material() - mat.add_nuclide("Ni58", 1.0) - mat.set_density("g/cm3", 7.87) - - mats = openmc.Materials([mat]) - - class DummySession: - def __enter__(self): - return self - - def __exit__(self, exc_type, exc, tb): - return False - - monkeypatch.setattr(openmc.lib, "TemporarySession", DummySession) - - chain = Path(__file__).parents[1] / "chain_ni.xml" - with pytest.raises(ValueError, match="has no volume"): - mats.deplete( - multigroup_fluxes=[[1.0]], - energy_group_structures=["VITAMIN-J-42"], - timesteps=[1.0], - source_rates=1.0, - chain_file=chain, - ) diff --git a/tests/unit_tests/test_math.py b/tests/unit_tests/test_math.py new file mode 100644 index 000000000..c50057fcd --- /dev/null +++ b/tests/unit_tests/test_math.py @@ -0,0 +1,247 @@ +import numpy as np +import pytest +import scipy as sp +from scipy.stats import shapiro + +import openmc +import openmc.lib + + +def test_t_percentile(): + # Permutations include 1 DoF, 2 DoF, and > 2 DoF + # We will test 5 p-values at 3-DoF values + test_ps = [0.02, 0.4, 0.5, 0.6, 0.98] + test_dfs = [1, 2, 5] + + # The reference solutions come from Scipy + ref_ts = [[sp.stats.t.ppf(p, df) for p in test_ps] for df in test_dfs] + + test_ts = [[openmc.lib.math.t_percentile(p, df) for p in test_ps] + for df in test_dfs] + + # The 5 DoF approximation in openmc.lib.math.t_percentile is off by up to + # 8e-3 from the scipy solution, so test that one separately with looser + # tolerance + assert np.allclose(ref_ts[:-1], test_ts[:-1]) + assert np.allclose(ref_ts[-1], test_ts[-1], atol=1e-2) + + +def test_calc_pn(): + max_order = 10 + test_xs = np.linspace(-1., 1., num=5, endpoint=True) + + # Reference solutions from scipy + ref_vals = np.array([sp.special.eval_legendre(n, test_xs) + for n in range(0, max_order + 1)]) + + test_vals = [] + for x in test_xs: + test_vals.append(openmc.lib.math.calc_pn(max_order, x).tolist()) + + test_vals = np.swapaxes(np.array(test_vals), 0, 1) + + assert np.allclose(ref_vals, test_vals) + + +def test_evaluate_legendre(): + max_order = 10 + # Coefficients are set to 1, but will incorporate the (2l+1)/2 norm factor + # for the reference solution + test_coeffs = [0.5 * (2. * l + 1.) for l in range(max_order + 1)] + test_xs = np.linspace(-1., 1., num=5, endpoint=True) + + ref_vals = np.polynomial.legendre.legval(test_xs, test_coeffs) + + # Set the coefficients back to 1s for the test values since + # evaluate legendre incorporates the (2l+1)/2 term on its own + test_coeffs = [1. for l in range(max_order + 1)] + + test_vals = np.array([openmc.lib.math.evaluate_legendre(test_coeffs, x) + for x in test_xs]) + + assert np.allclose(ref_vals, test_vals) + + +def test_calc_rn(): + max_order = 10 + test_ns = np.array([i for i in range(0, max_order + 1)]) + azi = 0.1 # Longitude + pol = 0.2 # Latitude + test_uvw = np.array([np.sin(pol) * np.cos(azi), + np.sin(pol) * np.sin(azi), + np.cos(pol)]) + + # Reference solutions from the equations + ref_vals = [] + + def coeff(n, m): + return np.sqrt((2. * n + 1) * sp.special.factorial(n - m) / + (sp.special.factorial(n + m))) + + def pnm_bar(n, m, mu): + val = coeff(n, m) + if m != 0: + val *= np.sqrt(2.) + val *= sp.special.lpmv([m], [n], [mu]) + return val[0] + + ref_vals = [] + for n in test_ns: + for m in range(-n, n + 1): + if m < 0: + ylm = pnm_bar(n, np.abs(m), np.cos(pol)) * \ + np.sin(np.abs(m) * azi) + else: + ylm = pnm_bar(n, m, np.cos(pol)) * np.cos(m * azi) + + # Un-normalize for comparison + ylm /= np.sqrt(2. * n + 1.) + ref_vals.append(ylm) + + test_vals = [] + test_vals = openmc.lib.math.calc_rn(max_order, test_uvw) + + assert np.allclose(ref_vals, test_vals) + + +def test_calc_zn(): + n = 10 + rho = 0.5 + phi = 0.5 + + # Reference solution from running the C++ implementation + ref_vals = np.array([ + 1.00000000e+00, 2.39712769e-01, 4.38791281e-01, + 2.10367746e-01, -5.00000000e-01, 1.35075576e-01, + 1.24686873e-01, -2.99640962e-01, -5.48489101e-01, + 8.84215021e-03, 5.68310892e-02, -4.20735492e-01, + -1.25000000e-01, -2.70151153e-01, -2.60091773e-02, + 1.87022545e-02, -3.42888902e-01, 1.49820481e-01, + 2.74244551e-01, -2.43159131e-02, -2.50357380e-02, + 2.20500013e-03, -1.98908812e-01, 4.07587508e-01, + 4.37500000e-01, 2.61708929e-01, 9.10321205e-02, + -1.54686328e-02, -2.74049397e-03, -7.94845816e-02, + 4.75368705e-01, 7.11647284e-02, 1.30266162e-01, + 3.37106977e-02, 1.06401886e-01, -7.31606787e-03, + -2.95625975e-03, -1.10250006e-02, 3.55194307e-01, + -1.44627826e-01, -2.89062500e-01, -9.28644588e-02, + -1.62557358e-01, 7.73431638e-02, -2.55329539e-03, + -1.90923851e-03, 1.57578403e-02, 1.72995854e-01, + -3.66267690e-01, -1.81657333e-01, -3.32521518e-01, + -2.59738162e-02, -2.31580576e-01, 4.20673902e-02, + -4.11710546e-04, -9.36449487e-04, 1.92156884e-02, + 2.82515641e-02, -3.90713738e-01, -1.69280296e-01, + -8.98437500e-02, -1.08693628e-01, 1.78813094e-01, + -1.98191857e-01, 1.65964201e-02, 2.77013853e-04]) + + test_vals = openmc.lib.math.calc_zn(n, rho, phi) + + assert np.allclose(ref_vals, test_vals) + + +def test_calc_zn_rad(): + n = 10 + rho = 0.5 + + # Reference solution from running the C++ implementation + ref_vals = np.array([ + 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, + 4.37500000e-01, -2.89062500e-01,-8.98437500e-02]) + + test_vals = openmc.lib.math.calc_zn_rad(n, rho) + + assert np.allclose(ref_vals, test_vals) + + +def test_rotate_angle(): + uvw0 = np.array([1., 0., 0.]) + phi = 0. + mu = 0. + + # reference: mu of 0 pulls the vector the bottom, so: + ref_uvw = np.array([0., 0., -1.]) + + test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi) + + assert np.array_equal(ref_uvw, test_uvw) + + # Repeat for mu = 1 (no change) + mu = 1. + ref_uvw = np.array([1., 0., 0.]) + + test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi) + + assert np.array_equal(ref_uvw, test_uvw) + + # Now to test phi is None + mu = 0.9 + phi = None + prn_seed = 1 + + # When seed = 1, phi will be sampled as 1.9116495709698769 + # The resultant reference is from hand-calculations given the above + ref_uvw = [0.9, -0.422746750548505, 0.10623175090659095] + test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi, prn_seed) + + assert np.allclose(ref_uvw, test_uvw) + + +def test_maxwell_spectrum(): + prn_seed = 1 + T = 0.5 + ref_val = 0.27767406743161277 + test_val = openmc.lib.math.maxwell_spectrum(T, prn_seed) + + assert ref_val == test_val + + +def test_watt_spectrum(): + prn_seed = 1 + a = 0.5 + b = 0.75 + ref_val = 0.30957476387766697 + test_val = openmc.lib.math.watt_spectrum(a, b, prn_seed) + + assert ref_val == test_val + + +def test_normal_dist(): + # When standard deviation is zero, sampled value should be mean + prn_seed = 1 + mean = 14.08 + stdev = 0.0 + ref_val = 14.08 + test_val = openmc.lib.math.normal_variate(mean, stdev, prn_seed) + assert ref_val == pytest.approx(test_val) + + # Use Shapiro-Wilk test to ensure normality of sampled vairates + stdev = 1.0 + samples = [] + num_samples = 10000 + for _ in range(num_samples): + # sample the normal distribution from openmc + samples.append(openmc.lib.math.normal_variate(mean, stdev, prn_seed)) + prn_seed += 1 + stat, p = shapiro(samples) + assert p > 0.05 + + +def test_broaden_wmp_polynomials(): + # Two branches of the code to worry about, beta > 6 and otherwise + # beta = sqrtE * dopp + # First lets do beta > 6 + test_E = 0.5 + test_dopp = 100. # approximately U235 at room temperature + n = 6 + + ref_val = [2., 1.41421356, 1.0001, 0.70731891, 0.50030001, 0.353907] + test_val = openmc.lib.math.broaden_wmp_polynomials(test_E, test_dopp, n) + + assert np.allclose(ref_val, test_val) + + # now beta < 6 + test_dopp = 5. + ref_val = [1.99999885, 1.41421356, 1.04, 0.79195959, 0.6224, 0.50346003] + test_val = openmc.lib.math.broaden_wmp_polynomials(test_E, test_dopp, n) + + assert np.allclose(ref_val, test_val) diff --git a/tests/unit_tests/test_mcpl_stat_sum.py b/tests/unit_tests/test_mcpl_stat_sum.py deleted file mode 100644 index b69192956..000000000 --- a/tests/unit_tests/test_mcpl_stat_sum.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Test for MCPL stat:sum functionality""" - -from pathlib import Path -import shutil - -import pytest -import openmc - - -@pytest.mark.skipif(shutil.which("mcpl-config") is None, reason="MCPL is not available.") -def test_mcpl_stat_sum_field(run_in_tmpdir): - """Test that MCPL files contain proper stat:sum field with particle count. - - This test verifies that when OpenMC creates MCPL source files, they contain - the stat:sum field. Since MCPL functions are not exposed in the Python API, - this test creates an actual OpenMC simulation to generate MCPL files and - then checks their content. - """ - - mcpl = pytest.importorskip("mcpl") - - # Create a minimal working model that will generate MCPL files - model = openmc.examples.pwr_pin_cell() - model.settings.batches = 5 - model.settings.inactive = 2 - model.settings.particles = 1000 - model.settings.sourcepoint = {'mcpl': True, 'separate': True} - - # Run a short simulation to generate MCPL files - model.run(output=False) - - # Find the generated MCPL file (from the last batch) - mcpl_file = Path('source.5.mcpl') - assert mcpl_file.exists(), "No MCPL files were generated" - - # Open and verify the stat:sum field exists - with mcpl.MCPLFile(mcpl_file) as f: - # Check if stat:sum field exists using convenience property - if hasattr(f, 'stat_sum'): - # Use the convenience .stat_sum property directly - stat_sum_dict = f.stat_sum - assert 'openmc_np1' in stat_sum_dict, "openmc_np1 key not found in stat_sum" - stat_sum_value = int(stat_sum_dict['openmc_np1']) - else: - # Fallback to checking comments for older MCPL versions - comments = f.comments - - # Check for stat:sum in comments (MCPL stores these as comments) - stat_sum_value = None - - for comment in comments: - if 'stat:sum:openmc_np1' in comment: - # Extract the value - parts = comment.split(':') - if len(parts) >= 4: - stat_sum_value = int(parts[3].strip()) - break - else: - pytest.skip("stat:sum field not found - may be running with MCPL < 2.1.0") - - # Verify the stat:sum value is reasonable - assert stat_sum_value != -1, "stat:sum was not updated from initial -1 value" - - # In eigenvalue mode, active batches generate source particles - active_batches = model.settings.batches - model.settings.inactive # 3 active batches - expected_particles = active_batches * model.settings.particles # 3000 total - - assert stat_sum_value == expected_particles, \ - f"stat:sum value {stat_sum_value} doesn't match expected {expected_particles}" diff --git a/tests/unit_tests/test_mesh.py b/tests/unit_tests/test_mesh.py deleted file mode 100644 index 9b1469fc5..000000000 --- a/tests/unit_tests/test_mesh.py +++ /dev/null @@ -1,1156 +0,0 @@ -from math import pi, sqrt -from tempfile import TemporaryDirectory -from pathlib import Path -import itertools -import random - -import h5py -import numpy as np -from scipy.stats import chi2 -import pytest -import openmc -import openmc.lib -from openmc.utility_funcs import change_directory -from uncertainties.unumpy import uarray, nominal_values, std_devs - - -@pytest.mark.parametrize("val_left,val_right", [(0, 0), (-1., -1.), (2.0, 2)]) -def test_raises_error_when_flat(val_left, val_right): - """Checks that an error is raised when a mesh is flat""" - mesh = openmc.RegularMesh() - - # Same X - with pytest.raises(ValueError): - mesh.lower_left = [val_left, -25, -25] - mesh.upper_right = [val_right, 25, 25] - - with pytest.raises(ValueError): - mesh.upper_right = [val_right, 25, 25] - mesh.lower_left = [val_left, -25, -25] - - # Same Y - with pytest.raises(ValueError): - mesh.lower_left = [-25, val_left, -25] - mesh.upper_right = [25, val_right, 25] - - with pytest.raises(ValueError): - mesh.upper_right = [25, val_right, 25] - mesh.lower_left = [-25, val_left, -25] - - # Same Z - with pytest.raises(ValueError): - mesh.lower_left = [-25, -25, val_left] - mesh.upper_right = [25, 25, val_right] - - with pytest.raises(ValueError): - mesh.upper_right = [25, 25, val_right] - mesh.lower_left = [-25, -25, val_left] - - -def test_regular_mesh_bounding_box(): - mesh = openmc.RegularMesh() - mesh.lower_left = [-2, -3, -5] - mesh.upper_right = [2, 3, 5] - bb = mesh.bounding_box - assert isinstance(bb, openmc.BoundingBox) - np.testing.assert_array_equal(bb.lower_left, (-2, -3 ,-5)) - np.testing.assert_array_equal(bb.upper_right, (2, 3, 5)) - - -def test_rectilinear_mesh_bounding_box(): - mesh = openmc.RectilinearMesh() - mesh.x_grid = [0., 1., 5., 10.] - mesh.y_grid = [-10., -5., 0.] - mesh.z_grid = [-100., 0., 100.] - bb = mesh.bounding_box - assert isinstance(bb, openmc.BoundingBox) - np.testing.assert_array_equal(bb.lower_left, (0., -10. ,-100.)) - np.testing.assert_array_equal(bb.upper_right, (10., 0., 100.)) - - -def test_cylindrical_mesh_bounding_box(): - # test with mesh at origin (0, 0, 0) - mesh = openmc.CylindricalMesh( - r_grid=[0.1, 0.2, 0.5, 1.], - z_grid=[0.1, 0.2, 0.4, 0.6, 1.], - origin=(0, 0, 0) - ) - np.testing.assert_array_equal(mesh.upper_right, (1, 1, 1)) - np.testing.assert_array_equal(mesh.lower_left, (-1, -1, 0.1)) - bb = mesh.bounding_box - assert isinstance(bb, openmc.BoundingBox) - np.testing.assert_array_equal(bb.lower_left, (-1, -1, 0.1)) - np.testing.assert_array_equal(bb.upper_right, (1, 1, 1)) - - # test with mesh at origin (3, 5, 7) - mesh.origin = (3, 5, 7) - np.testing.assert_array_equal(mesh.upper_right, (4, 6, 8)) - np.testing.assert_array_equal(mesh.lower_left, (2, 4, 7.1)) - bb = mesh.bounding_box - assert isinstance(bb, openmc.BoundingBox) - np.testing.assert_array_equal(bb.lower_left, (2, 4, 7.1)) - np.testing.assert_array_equal(bb.upper_right, (4, 6, 8)) - - # changing z grid to contain negative numbers - mesh.z_grid = [-10, 0, 10] - np.testing.assert_array_equal(mesh.lower_left, (2, 4, -3)) - np.testing.assert_array_equal(mesh.upper_right, (4, 6, 17)) - - -def test_spherical_mesh_bounding_box(): - # test with mesh at origin (0, 0, 0) - mesh = openmc.SphericalMesh([0.1, 0.2, 0.5, 1.], origin=(0., 0., 0.)) - np.testing.assert_array_equal(mesh.upper_right, (1, 1, 1)) - np.testing.assert_array_equal(mesh.lower_left, (-1, -1, -1)) - bb = mesh.bounding_box - assert isinstance(bb, openmc.BoundingBox) - np.testing.assert_array_equal(bb.lower_left, (-1, -1, -1)) - np.testing.assert_array_equal(bb.upper_right, (1, 1, 1)) - - # test with mesh at origin (3, 5, 7) - mesh.origin = (3, 5, 7) - np.testing.assert_array_equal(mesh.upper_right, (4, 6, 8)) - np.testing.assert_array_equal(mesh.lower_left, (2, 4, 6)) - bb = mesh.bounding_box - assert isinstance(bb, openmc.BoundingBox) - np.testing.assert_array_equal(bb.lower_left, (2, 4, 6)) - np.testing.assert_array_equal(bb.upper_right, (4, 6, 8)) - - -def test_SphericalMesh_initiation(): - # test defaults - mesh = openmc.SphericalMesh(r_grid=(0, 10)) - assert (mesh.origin == np.array([0, 0, 0])).all() - assert (mesh.r_grid == np.array([0, 10])).all() - assert (mesh.theta_grid == np.array([0, pi])).all() - assert (mesh.phi_grid == np.array([0, 2*pi])).all() - - # test setting on creation - mesh = openmc.SphericalMesh( - origin=(1, 2, 3), - r_grid=(0, 2), - theta_grid=(1, 3), - phi_grid=(2, 4) - ) - assert (mesh.origin == np.array([1, 2, 3])).all() - assert (mesh.r_grid == np.array([0., 2.])).all() - assert (mesh.theta_grid == np.array([1, 3])).all() - assert (mesh.phi_grid == np.array([2, 4])).all() - - # test attribute changing - mesh.r_grid = (0, 11) - assert (mesh.r_grid == np.array([0., 11.])).all() - - # test invalid r_grid values - with pytest.raises(ValueError): - openmc.SphericalMesh(r_grid=[1, 1]) - - with pytest.raises(ValueError): - openmc.SphericalMesh(r_grid=[0]) - - # test invalid theta_grid values - with pytest.raises(ValueError): - openmc.SphericalMesh(r_grid=[1, 2], theta_grid=[1, 1]) - - with pytest.raises(ValueError): - openmc.SphericalMesh(r_grid=[1, 2], theta_grid=[0]) - - # test invalid phi_grid values - with pytest.raises(ValueError): - openmc.SphericalMesh(r_grid=[1, 2], phi_grid=[1, 1]) - - with pytest.raises(ValueError): - openmc.SphericalMesh(r_grid=[1, 2], phi_grid=[0]) - - # waffles and pancakes are unfortunately not valid radii - with pytest.raises(TypeError): - openmc.SphericalMesh(('🧇', '🥞')) - - -def test_CylindricalMesh_initiation(): - # test defaults - mesh = openmc.CylindricalMesh(r_grid=(0, 10), z_grid=(0, 10)) - assert (mesh.origin == np.array([0, 0, 0])).all() - assert (mesh.r_grid == np.array([0, 10])).all() - assert (mesh.phi_grid == np.array([0, 2*pi])).all() - assert (mesh.z_grid == np.array([0, 10])).all() - - # test setting on creation - mesh = openmc.CylindricalMesh( - origin=(1, 2, 3), - r_grid=(0, 2), - z_grid=(1, 3), - phi_grid=(2, 4) - ) - assert (mesh.origin == np.array([1, 2, 3])).all() - assert (mesh.r_grid == np.array([0., 2.])).all() - assert (mesh.z_grid == np.array([1, 3])).all() - assert (mesh.phi_grid == np.array([2, 4])).all() - - # test attribute changing - mesh.r_grid = (0., 10.) - assert (mesh.r_grid == np.array([0, 10.])).all() - mesh.z_grid = (0., 4.) - assert (mesh.z_grid == np.array([0, 4.])).all() - - # waffles and pancakes are unfortunately not valid radii - with pytest.raises(TypeError): - openmc.SphericalMesh(('🧇', '🥞')) - - -def test_invalid_cylindrical_mesh_errors(): - # Test invalid r_grid values - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[5, 1], phi_grid=[0, pi], z_grid=[0, 10]) - - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[1, 2, 4, 3], phi_grid=[0, pi], z_grid=[0, 10]) - - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[1], phi_grid=[0, pi], z_grid=[0, 10]) - - # Test invalid phi_grid values - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[0, 1, 2], phi_grid=[-1, 3], z_grid=[0, 10]) - - with pytest.raises(ValueError): - openmc.CylindricalMesh( - r_grid=[0, 1, 2], - phi_grid=[0, 2*pi + 0.1], - z_grid=[0, 10] - ) - - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[0, 1, 2], phi_grid=[pi], z_grid=[0, 10]) - - # Test invalid z_grid values - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[0, 1, 2], phi_grid=[0, pi], z_grid=[5]) - - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[0, 1, 2], phi_grid=[0, pi], z_grid=[5, 1]) - - with pytest.raises(ValueError): - openmc.CylindricalMesh(r_grid=[1, 2, 4, 3], phi_grid=[0, pi], z_grid=[0, 10, 5]) - - -def test_centroids(): - # regular mesh - mesh = openmc.RegularMesh() - mesh.lower_left = (1., 2., 3.) - mesh.upper_right = (11., 12., 13.) - mesh.dimension = (1, 1, 1) - np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [6., 7., 8.]) - - # rectilinear mesh - mesh = openmc.RectilinearMesh() - mesh.x_grid = [1., 11.] - mesh.y_grid = [2., 12.] - mesh.z_grid = [3., 13.] - np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [6., 7., 8.]) - - # cylindrical mesh - mesh = openmc.CylindricalMesh(r_grid=(0, 10), z_grid=(0, 10), phi_grid=(0, np.pi)) - np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [0.0, 5.0, 5.0]) - # ensure that setting an origin is handled correctly - mesh.origin = (5.0, 0, -10) - np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [5.0, 5.0, -5.0]) - - # spherical mesh, single element xyz-positive octant - mesh = openmc.SphericalMesh(r_grid=[0, 10], theta_grid=[0, 0.5*np.pi], phi_grid=[0, np.pi]) - x = 5.*np.cos(0.5*np.pi)*np.sin(0.25*np.pi) - y = 5.*np.sin(0.5*np.pi)*np.sin(0.25*np.pi) - z = 5.*np.sin(0.25*np.pi) - np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [x, y, z]) - - mesh.origin = (-5.0, -5.0, 5.0) - np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [x-5.0, y-5.0, z+5.0]) - - -@pytest.mark.parametrize('mesh_type', ('regular', 'rectilinear', 'cylindrical', 'spherical')) -def test_mesh_vertices(mesh_type): - - ijk = (2, 3, 2) - - # create a new mesh object - if mesh_type == 'regular': - mesh = openmc.RegularMesh() - ll = np.asarray([0.]*3) - width = np.asarray([0.5]*3) - mesh.lower_left = ll - mesh.width = width - mesh.dimension = (5, 7, 9) - - # spot check that an element has the correct vertex coordinates asociated with it - # (using zero-indexing here) - exp_i_j_k = ll + np.asarray(ijk, dtype=float) * width - np.testing.assert_equal(mesh.vertices[ijk], exp_i_j_k) - - # shift the mesh using the llc - shift = np.asarray((3.0, 6.0, 10.0)) - mesh.lower_left += shift - np.testing.assert_equal(mesh.vertices[ijk], exp_i_j_k+shift) - elif mesh_type == 'rectilinear': - mesh = openmc.RectilinearMesh() - w = np.asarray([0.5] * 3) - ll = np.asarray([0.]*3) - dims = (5, 7, 9) - mesh.x_grid = np.linspace(ll[0], w[0]*dims[0], dims[0]) - mesh.y_grid = np.linspace(ll[1], w[1]*dims[1], dims[1]) - mesh.z_grid = np.linspace(ll[2], w[2]*dims[2], dims[2]) - exp_vert = np.asarray((mesh.x_grid[2], mesh.y_grid[3], mesh.z_grid[2])) - np.testing.assert_equal(mesh.vertices[ijk], exp_vert) - elif mesh_type == 'cylindrical': - r_grid = np.linspace(0, 5, 10) - z_grid = np.linspace(-10, 10, 20) - phi_grid = np.linspace(0, 2*np.pi, 8) - mesh = openmc.CylindricalMesh(r_grid=r_grid, z_grid=z_grid, phi_grid=phi_grid) - exp_vert = np.asarray((mesh.r_grid[2], mesh.phi_grid[3], mesh.z_grid[2])) - np.testing.assert_equal(mesh.vertices_cylindrical[ijk], exp_vert) - elif mesh_type == 'spherical': - r_grid = np.linspace(0, 13, 14) - theta_grid = np.linspace(0, np.pi, 11) - phi_grid = np.linspace(0, 2*np.pi, 7) - mesh = openmc.SphericalMesh(r_grid=r_grid, theta_grid=theta_grid, phi_grid=phi_grid) - exp_vert = np.asarray((mesh.r_grid[2], mesh.theta_grid[3], mesh.phi_grid[2])) - np.testing.assert_equal(mesh.vertices_spherical[ijk], exp_vert) - - -def test_CylindricalMesh_get_indices_at_coords(): - # default origin (0, 0, 0) and default phi grid (0, 2*pi) - mesh = openmc.CylindricalMesh(r_grid=(0, 5, 10), z_grid=(0, 5, 10)) - assert mesh.get_indices_at_coords([1, 0, 1]) == (0, 0, 0) - assert mesh.get_indices_at_coords([6, 0, 1]) == (1, 0, 0) - assert mesh.get_indices_at_coords([9, 0, 1]) == (1, 0, 0) - assert mesh.get_indices_at_coords([0, 6, 0]) == (1, 0, 0) - assert mesh.get_indices_at_coords([0, 9, 6]) == (1, 0, 1) - assert mesh.get_indices_at_coords([-2, -2, 9]) == (0, 0, 1) - - with pytest.raises(ValueError): - assert mesh.get_indices_at_coords([8, 8, 1]) # resulting r value to large - with pytest.raises(ValueError): - assert mesh.get_indices_at_coords([-8, -8, 1]) # resulting r value to large - with pytest.raises(ValueError): - assert mesh.get_indices_at_coords([1, 0, -1]) # z value below range - with pytest.raises(ValueError): - assert mesh.get_indices_at_coords([1, 0, 11]) # z value above range - - assert mesh.get_indices_at_coords([1, 1, 1]) == (0, 0, 0) - - # negative range on z grid - mesh = openmc.CylindricalMesh( - r_grid=(0, 5, 10), - phi_grid=(0, 0.5 * pi, pi, 1.5 * pi, 1.9 * pi), - z_grid=(-5, 0, 5, 10), - ) - assert mesh.get_indices_at_coords([1, 1, 1]) == (0, 0, 1) # first angle quadrant - assert mesh.get_indices_at_coords([2, 2, 6]) == (0, 0, 2) # first angle quadrant - assert mesh.get_indices_at_coords([-2, 0.1, -1]) == (0, 1, 0) # second angle quadrant - assert mesh.get_indices_at_coords([-2, -0.1, -1]) == (0, 2, 0) # third angle quadrant - assert mesh.get_indices_at_coords([2, -0.9, -1]) == (0, 3, 0) # forth angle quadrant - - with pytest.raises(ValueError): - assert mesh.get_indices_at_coords([2, -0.1, 1]) # outside of phi range - - # origin of mesh not default - mesh = openmc.CylindricalMesh( - r_grid=(0, 5, 10), - phi_grid=(0, 0.5 * pi, pi, 1.5 * pi, 1.9 * pi), - z_grid=(-5, 0, 5, 10), - origin=(100, 200, 300), - ) - assert mesh.get_indices_at_coords([101, 201, 301]) == (0, 0, 1) # first angle quadrant - assert mesh.get_indices_at_coords([102, 202, 306]) == (0, 0, 2) # first angle quadrant - assert mesh.get_indices_at_coords([98, 200.1, 299]) == (0, 1, 0) # second angle quadrant - assert mesh.get_indices_at_coords([98, 199.9, 299]) == (0, 2, 0) # third angle quadrant - assert mesh.get_indices_at_coords([102, 199.1, 299]) == (0, 3, 0) # forth angle quadrant - - -def test_mesh_name_roundtrip(run_in_tmpdir): - - mesh = openmc.RegularMesh() - mesh.name = 'regular-mesh' - mesh.lower_left = (-1, -1, -1) - mesh.width = (1, 1, 1) - mesh.dimension = (1, 1, 1) - - mesh_filter = openmc.MeshFilter(mesh) - tally = openmc.Tally() - tally.filters = [mesh_filter] - tally.scores = ['flux'] - - openmc.Tallies([tally]).export_to_xml() - - xml_tallies = openmc.Tallies.from_xml() - - mesh = xml_tallies[0].find_filter(openmc.MeshFilter).mesh - assert mesh.name == 'regular-mesh' - - -def test_umesh_roundtrip(run_in_tmpdir, request): - umesh = openmc.UnstructuredMesh(request.path.parent / 'test_mesh_tets.e', 'moab') - umesh.output = True - - # create a tally using this mesh - mf = openmc.MeshFilter(umesh) - tally = openmc.Tally() - tally.filters = [mf] - tally.scores = ['flux'] - - tallies = openmc.Tallies([tally]) - tallies.export_to_xml() - - xml_tallies = openmc.Tallies.from_xml() - xml_tally = xml_tallies[0] - xml_mesh = xml_tally.filters[0].mesh - - assert umesh.id == xml_mesh.id - - -@pytest.fixture(scope='module') -def simple_umesh(request): - """Fixture returning UnstructuredMesh with all attributes""" - surf1 = openmc.Sphere(r=20.0, boundary_type="vacuum") - material1 = openmc.Material() - material1.add_element("H", 1.0) - material1.set_density('g/cm3', 1.0) - - materials = openmc.Materials([material1]) - cell1 = openmc.Cell(region=-surf1, fill=material1) - geometry = openmc.Geometry([cell1]) - - umesh = openmc.UnstructuredMesh( - filename=request.path.parent.parent - / "regression_tests/external_moab/test_mesh_tets.h5m", - library="moab", - mesh_id=1 - ) - # setting ID to make it easier to get the mesh from the statepoint later - mesh_filter = openmc.MeshFilter(umesh) - - # Create flux mesh tally to score alpha production - mesh_tally = openmc.Tally(name="test_tally") - mesh_tally.filters = [mesh_filter] - mesh_tally.scores = ["total"] - - tallies = openmc.Tallies([mesh_tally]) - - settings = openmc.Settings() - settings.run_mode = "fixed source" - settings.batches = 2 - settings.particles = 100 - settings.source = openmc.IndependentSource( - space=openmc.stats.Point((0.1, 0.1, 0.1)) - ) - - model = openmc.Model( - materials=materials, geometry=geometry, settings=settings, tallies=tallies - ) - - with change_directory(tmpdir=True): - statepoint_file = model.run() - with openmc.StatePoint(statepoint_file) as sp: - return sp.meshes[1] - - -@pytest.mark.skipif(not openmc.lib._dagmc_enabled(), reason="DAGMC not enabled.") -@pytest.mark.parametrize('export_type', ('.vtk', '.vtu')) -def test_umesh(run_in_tmpdir, simple_umesh, export_type): - """Performs a minimal UnstructuredMesh simulation, reads in the resulting - statepoint file and writes the mesh data to vtk and vtkhdf files. It is - necessary to read in the unstructured mesh from a statepoint file to ensure - it has all the required attributes - """ - # Get VTK modules - vtkIOLegacy = pytest.importorskip("vtkmodules.vtkIOLegacy") - vtkIOXML = pytest.importorskip("vtkmodules.vtkIOXML") - - # Sample some random data and write to VTK - rng = np.random.default_rng() - ref_data = rng.random(simple_umesh.dimension) - filename = f"test_mesh{export_type}" - simple_umesh.write_data_to_vtk(datasets={"mean": ref_data}, filename=filename) - - assert Path(filename).exists() - - if export_type == ".vtk": - reader = vtkIOLegacy.vtkGenericDataObjectReader() - elif export_type == ".vtu": - reader = vtkIOXML.vtkXMLGenericDataObjectReader() - reader.SetFileName(str(filename)) - reader.Update() - - # Get mean from file and make sure it matches original data - arr = reader.GetOutput().GetCellData().GetArray("mean") - mean = np.array([arr.GetTuple1(i) for i in range(ref_data.size)]) - np.testing.assert_almost_equal(mean, ref_data) - - # attempt to apply a dataset with an improper size to a VTK write - with pytest.raises(ValueError, match='Cannot apply dataset "mean"'): - simple_umesh.write_data_to_vtk(datasets={'mean': ref_data[:-2]}, filename=filename) - - -vtkhdf_tests = [ - ( - Path("test_mesh_dagmc_tets.vtk"), - "moab" - ), - ( - Path("test_mesh_hexes.exo"), - "libmesh" - ) -] -@pytest.mark.parametrize('mesh_file, mesh_library', vtkhdf_tests) -def test_write_vtkhdf(mesh_file, mesh_library, request, run_in_tmpdir): - """Performs a minimal UnstructuredMesh simulation, reads in the resulting - statepoint file and writes the mesh data to vtk and vtkhdf files. It is - necessary to read in the unstructured mesh from a statepoint file to ensure - it has all the required attributes - """ - if mesh_library == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip("DAGMC not enabled.") - if mesh_library == 'libmesh' and not openmc.lib._libmesh_enabled(): - pytest.skip("LibMesh not enabled.") - - model = openmc.Model() - - surf1 = openmc.Sphere(r=1000.0, boundary_type="vacuum") - cell1 = openmc.Cell(region=-surf1) - model.geometry = openmc.Geometry([cell1]) - - umesh = openmc.UnstructuredMesh( - request.path.parent / mesh_file, - mesh_library, - mesh_id = 1 - ) - mesh_filter = openmc.MeshFilter(umesh) - - # Create flux mesh tally to score alpha production - mesh_tally = openmc.Tally(name="test_tally") - mesh_tally.filters = [mesh_filter] - mesh_tally.scores = ["flux"] - if mesh_library == "libmesh": - mesh_tally.estimator = "collision" - - model.tallies = [mesh_tally] - - model.settings.run_mode = "fixed source" - model.settings.batches = 2 - model.settings.particles = 10 - - statepoint_file = model.run() - - with openmc.StatePoint(statepoint_file) as statepoint: - my_tally = statepoint.get_tally(name="test_tally") - - umesh_from_sp = statepoint.meshes[umesh.id] - - datasets={ - "mean": my_tally.mean.flatten(), - "std_dev": my_tally.std_dev.flatten() - } - - umesh_from_sp.write_data_to_vtk(datasets=datasets, filename="test_mesh.vtkhdf") - umesh_from_sp.write_data_to_vtk(datasets=datasets, filename="test_mesh.vtk") - - with pytest.raises(ValueError, match="Unsupported file extension"): - # Supported file extensions are vtk or vtkhdf, not hdf5, so this should raise an error - umesh_from_sp.write_data_to_vtk( - datasets=datasets, - filename="test_mesh.hdf5", - ) - with pytest.raises(ValueError, match="Cannot apply dataset"): - # The shape of the data should match the shape of the mesh, so this should raise an error - umesh_from_sp.write_data_to_vtk( - datasets={'incorrectly_shaped_data': np.array(([1,2,3]))}, - filename="test_mesh_incorrect_shape.vtkhdf", - ) - - assert Path("test_mesh.vtk").exists() - assert Path("test_mesh.vtkhdf").exists() - - # just ensure we can open the file without error - with h5py.File("test_mesh.vtkhdf", "r"): - ... - - import vtk - reader = vtk.vtkHDFReader() - reader.SetFileName("test_mesh.vtkhdf") - reader.Update() - - # Get mean from file and make sure it matches original data - num_elements = reader.GetOutput().GetNumberOfCells() - assert num_elements == umesh_from_sp.n_elements - - num_vertices = reader.GetOutput().GetNumberOfPoints() - assert num_vertices == umesh_from_sp.vertices.shape[0] - - arr = reader.GetOutput().GetCellData().GetArray("mean") - mean = np.array([arr.GetTuple1(i) for i in range(my_tally.mean.size)]) - np.testing.assert_almost_equal(mean, my_tally.mean.flatten()/umesh_from_sp.volumes) - - arr = reader.GetOutput().GetCellData().GetArray("std_dev") - std_dev = np.array([arr.GetTuple1(i) for i in range(my_tally.std_dev.size)]) - np.testing.assert_almost_equal(std_dev, my_tally.std_dev.flatten()/umesh_from_sp.volumes) - - -def test_mesh_get_homogenized_materials(): - """Test the get_homogenized_materials method""" - # Simple model with 1 cm of Fe56 next to 1 cm of H1 - fe = openmc.Material() - fe.add_nuclide('Fe56', 1.0) - fe.set_density('g/cm3', 5.0) - h = openmc.Material() - h.add_nuclide('H1', 1.0) - h.set_density('g/cm3', 1.0) - - x0 = openmc.XPlane(-1.0, boundary_type='vacuum') - x1 = openmc.XPlane(0.0) - x2 = openmc.XPlane(1.0) - x3 = openmc.XPlane(2.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fe, region=+x0 & -x1) - cell2 = openmc.Cell(fill=h, region=+x1 & -x2) - cell_empty = openmc.Cell(region=+x2 & -x3) - model = openmc.Model(geometry=openmc.Geometry([cell1, cell2, cell_empty])) - model.settings.particles = 1000 - model.settings.batches = 10 - - mesh = openmc.RegularMesh() - mesh.lower_left = (-1., -1., -1.) - mesh.upper_right = (1., 1., 1.) - mesh.dimension = (3, 1, 1) - m1, m2, m3 = mesh.get_homogenized_materials(model, n_samples=10_000) - - # Left mesh element should be only Fe56 - assert m1.get_mass_density('Fe56') == pytest.approx(5.0) - - # Middle mesh element should be 50% Fe56 and 50% H1 - assert m2.get_mass_density('Fe56') == pytest.approx(2.5, rel=1e-2) - assert m2.get_mass_density('H1') == pytest.approx(0.5, rel=1e-2) - - # Right mesh element should be only H1 - assert m3.get_mass_density('H1') == pytest.approx(1.0) - - mesh_void = openmc.RegularMesh() - mesh_void.lower_left = (0.5, 0.5, -1.) - mesh_void.upper_right = (1.5, 1.5, 1.) - mesh_void.dimension = (1, 1, 1) - m4, = mesh_void.get_homogenized_materials(model, n_samples=(100, 100, 0)) - - # Mesh element that overlaps void should have half density - assert m4.get_mass_density('H1') == pytest.approx(0.5, rel=1e-2) - - # If not including void, density of homogenized material should be same as - # original material - m5, = mesh_void.get_homogenized_materials( - model, n_samples=1000, include_void=False) - assert m5.get_mass_density('H1') == pytest.approx(1.0) - - -@pytest.fixture -def sphere_model(): - openmc.reset_auto_ids() - # Model with three materials separated by planes x=0 and z=0 - mats = [] - for i in range(3): - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - mat.set_density('g/cm3', float(i + 1)) - mats.append(mat) - - sph = openmc.Sphere(r=25.0, boundary_type='vacuum') - x0 = openmc.XPlane(0.0) - z0 = openmc.ZPlane(0.0) - cell1 = openmc.Cell(fill=mats[0], region=-sph & +x0 & +z0) - cell2 = openmc.Cell(fill=mats[1], region=-sph & -x0 & +z0) - cell3 = openmc.Cell(fill=mats[2], region=-sph & -z0) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2, cell3]) - model.materials = openmc.Materials(mats) - return model - - -@pytest.mark.parametrize("n_rays", [1000, (10, 10, 0), (10, 0, 10), (0, 10, 10)]) -def test_material_volumes_regular_mesh(sphere_model, n_rays): - """Test the material_volumes method on a regular mesh""" - mesh = openmc.RegularMesh() - mesh.lower_left = (-1., -1., -1.) - mesh.upper_right = (1., 1., 1.) - mesh.dimension = (2, 2, 2) - volumes = mesh.material_volumes(sphere_model, n_rays) - mats = sphere_model.materials - np.testing.assert_almost_equal(volumes[mats[0].id], [0., 0., 0., 0., 0., 1., 0., 1.]) - np.testing.assert_almost_equal(volumes[mats[1].id], [0., 0., 0., 0., 1., 0., 1., 0.]) - np.testing.assert_almost_equal(volumes[mats[2].id], [1., 1., 1., 1., 0., 0., 0., 0.]) - assert volumes.by_element(4) == [(mats[1].id, 1.)] - assert volumes.by_element(0) == [(mats[2].id, 1.)] - - -def test_material_volumes_cylindrical_mesh(sphere_model): - """Test the material_volumes method on a cylindrical mesh""" - cyl_mesh = openmc.CylindricalMesh( - [0., 1.], [-1., 0., 1.,], [0.0, pi/4, 3*pi/4, 5*pi/4, 7*pi/4, 2*pi]) - volumes = cyl_mesh.material_volumes(sphere_model, (0, 100, 100)) - mats = sphere_model.materials - np.testing.assert_almost_equal(volumes[mats[0].id], [ - 0., 0., 0., 0., 0., - pi/8, pi/8, 0., pi/8, pi/8 - ]) - np.testing.assert_almost_equal(volumes[mats[1].id], [ - 0., 0., 0., 0., 0., - 0., pi/8, pi/4, pi/8, 0. - ]) - np.testing.assert_almost_equal(volumes[mats[2].id], [ - pi/8, pi/4, pi/4, pi/4, pi/8, - 0., 0., 0., 0., 0. - ]) - - -def test_mesh_material_volumes_serialize(): - materials = np.array([ - [1, -1, -2], - [-1, -2, -2], - [2, 1, -2], - [2, -2, -2] - ]) - volumes = np.array([ - [0.5, 0.5, 0.0], - [1.0, 0.0, 0.0], - [0.5, 0.5, 0.0], - [1.0, 0.0, 0.0] - ]) - volumes = openmc.MeshMaterialVolumes(materials, volumes) - with TemporaryDirectory() as tmpdir: - path = f'{tmpdir}/volumes.npz' - volumes.save(path) - new_volumes = openmc.MeshMaterialVolumes.from_npz(path) - - assert new_volumes.by_element(0) == [(1, 0.5), (None, 0.5)] - assert new_volumes.by_element(1) == [(None, 1.0)] - assert new_volumes.by_element(2) == [(2, 0.5), (1, 0.5)] - assert new_volumes.by_element(3) == [(2, 1.0)] - - -def test_mesh_material_volumes_serialize_with_bboxes(): - materials = np.array([ - [1, -1, -2], - [-1, -2, -2], - [2, 1, -2], - [2, -2, -2] - ]) - volumes = np.array([ - [0.5, 0.5, 0.0], - [1.0, 0.0, 0.0], - [0.5, 0.5, 0.0], - [1.0, 0.0, 0.0] - ]) - - # (xmin, ymin, zmin, xmax, ymax, zmax) - bboxes = np.empty((4, 3, 6)) - bboxes[..., 0:3] = np.inf - bboxes[..., 3:6] = -np.inf - bboxes[0, 0] = [-1.0, -2.0, -3.0, 1.0, 2.0, 3.0] # material 1 - bboxes[0, 1] = [-5.0, -6.0, -7.0, 5.0, 6.0, 7.0] # void - bboxes[1, 0] = [0.0, 0.0, 0.0, 10.0, 1.0, 2.0] # void - bboxes[2, 0] = [-1.0, -1.0, -1.0, 0.0, 0.0, 0.0] # material 2 - bboxes[2, 1] = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0] # material 1 - bboxes[3, 0] = [-2.0, -2.0, -2.0, 2.0, 2.0, 2.0] # material 2 - - mmv = openmc.MeshMaterialVolumes(materials, volumes, bboxes) - with TemporaryDirectory() as tmpdir: - path = f'{tmpdir}/volumes_bboxes.npz' - mmv.save(path) - loaded = openmc.MeshMaterialVolumes.from_npz(path) - - assert loaded.has_bounding_boxes - first = loaded.by_element(0, include_bboxes=True)[0][2] - assert isinstance(first, openmc.BoundingBox) - np.testing.assert_array_equal(first.lower_left, (-1.0, -2.0, -3.0)) - np.testing.assert_array_equal(first.upper_right, (1.0, 2.0, 3.0)) - - second = loaded.by_element(0, include_bboxes=True)[1][2] - assert isinstance(second, openmc.BoundingBox) - np.testing.assert_array_equal(second.lower_left, (-5.0, -6.0, -7.0)) - np.testing.assert_array_equal(second.upper_right, (5.0, 6.0, 7.0)) - - -def test_mesh_material_volumes_boundary_conditions(sphere_model): - """Test the material volumes method using a regular mesh - that overlaps with a vacuum boundary condition.""" - - mesh = openmc.SphericalMesh.from_domain(sphere_model.geometry, dimension=(1, 1, 1)) - # extend mesh beyond the outer sphere surface to test rays crossing the boundary condition - mesh.r_grid[-1] += 5.0 - - # add a new cell to the modelthat occupies the outside of the sphere - sphere_surfaces = list(filter(lambda s: isinstance(s, openmc.Sphere), - sphere_model.geometry.get_all_surfaces().values())) - outer_cell = openmc.Cell(region=+sphere_surfaces[0]) - sphere_model.geometry.root_universe.add_cell(outer_cell) - - volumes = mesh.material_volumes(sphere_model, (0, 100, 100)) - sphere_volume = 4/3*np.pi*25**3 - mats = sphere_model.materials - expected_volumes = [(mats[0].id, 0.25*sphere_volume), - (mats[1].id, 0.25*sphere_volume), - (mats[2].id, 0.5*sphere_volume), - (None, 4/3*np.pi*mesh.r_grid[-1]**3 - sphere_volume)] - - for evaluated, expected in zip(volumes.by_element(0), expected_volumes): - assert evaluated[0] == expected[0] - assert evaluated[1] == pytest.approx(expected[1], rel=1e-2) - - -def test_mesh_material_volumes_bounding_boxes(): - # Create a model with 8 spherical cells at known locations with random radii - box = openmc.model.RectangularParallelepiped( - -10, 10, -10, 10, -10, 10, boundary_type='vacuum') - - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - - sph_cells = [] - for x, y, z in itertools.product((-5., 5.), repeat=3): - mat_i = mat.clone() - sph = openmc.Sphere(x, y, z, r=random.uniform(0.5, 1.5)) - sph_cells.append(openmc.Cell(region=-sph, fill=mat_i)) - background = openmc.Cell(region=-box & openmc.Intersection([~c.region for c in sph_cells])) - - model = openmc.Model() - model.geometry = openmc.Geometry(sph_cells + [background]) - model.settings.particles = 1000 - model.settings.batches = 10 - - # Create a one-element mesh that encompasses the entire geometry - mesh = openmc.RegularMesh() - mesh.lower_left = (-10., -10., -10.) - mesh.upper_right = (10., 10., 10.) - mesh.dimension = (1, 1, 1) - - # Run material volume calculation with bounding boxes - n_samples = (400, 400, 400) - mmv = mesh.material_volumes(model, n_samples, max_materials=10, bounding_boxes=True) - assert mmv.has_bounding_boxes - - # Create a mapping of material ID to bounding box - bbox_by_mat = { - mat_id: bbox - for mat_id, vol, bbox in mmv.by_element(0, include_bboxes=True) - if mat_id is not None and vol > 0.0 - } - - # Match the mesh ray spacing used for the bounding box estimator. - tol = 0.5 * mesh.bounding_box.width[0] / n_samples[0] - for cell in sph_cells: - bbox = bbox_by_mat[cell.fill.id] - cell_bbox = cell.bounding_box - np.testing.assert_allclose(bbox.lower_left, cell_bbox.lower_left, atol=tol) - np.testing.assert_allclose(bbox.upper_right, cell_bbox.upper_right, atol=tol) - - -def test_raytrace_mesh_infinite_loop(run_in_tmpdir): - # Create a model with one large spherical cell - sphere = openmc.Sphere(r=100, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - - # Create a regular mesh and associated tally - mesh_surface = openmc.RegularMesh() - mesh_surface.lower_left = (-30, -30, 30) - mesh_surface.upper_right = (30, 30, 60) - mesh_surface.dimension = (1, 1, 1) - reg_filter = openmc.MeshSurfaceFilter(mesh_surface) - mesh_surface_tally = openmc.Tally() - mesh_surface_tally.filters = [reg_filter] - mesh_surface_tally.scores = ['current'] - model.tallies = [mesh_surface_tally] - - # Define a source such that the z position is on a mesh boundary with a very - # small directional cosine in the z direction - polar = openmc.stats.delta_function(1.75e-7) - azimuthal = openmc.stats.Uniform(0.0, 2.0*pi) - model.settings.source = openmc.IndependentSource( - angle=openmc.stats.PolarAzimuthal(polar, azimuthal) - ) - model.settings.run_mode = 'fixed source' - model.settings.particles = 10 - model.settings.batches = 1 - - # Run the model; this should not cause an infinite loop - model.run() - - -def test_filter_time_mesh(run_in_tmpdir): - """Test combination of TimeFilter and MeshFilter""" - - # Define material - mat = openmc.Material() - mat.add_nuclide('Fe56', 1.0) - mat.set_density('g/cm3', 7.8) - - # Define geometry - surf_Z1 = openmc.XPlane(x0=-1e10, boundary_type="reflective") - surf_Z2 = openmc.XPlane(x0=1e10, boundary_type="reflective") - cell_F = openmc.Cell(fill=mat, region=+surf_Z1 & -surf_Z2) - model = openmc.Model() - model.geometry = openmc.Geometry([cell_F]) - - # Define settings - model.settings.run_mode = "fixed source" - model.settings.particles = 1000 - model.settings.batches = 20 - model.settings.output = {"tallies": False} - model.settings.cutoff = {"time_neutron": 1e-7} - - # Define tallies - - # Create a mesh filter that can be used in a tally - mesh = openmc.RegularMesh() - mesh.dimension = (21, 1, 1) - mesh.lower_left = (-20.5, -1e10, -1e10) - mesh.upper_right = (20.5, 1e10, 1e10) - time_grid = np.linspace(0.0, 1e-7, 21) - - mesh_filter = openmc.MeshFilter(mesh) - time_filter = openmc.TimeFilter(time_grid) - - # Now use the mesh filter in a tally and indicate what scores are desired - tally1 = openmc.Tally(name="collision") - tally1.estimator = "collision" - tally1.filters = [time_filter, mesh_filter] - tally1.scores = ["flux"] - tally2 = openmc.Tally(name="tracklength") - tally2.estimator = "tracklength" - tally2.filters = [time_filter, mesh_filter] - tally2.scores = ["flux"] - model.tallies = openmc.Tallies([tally1, tally2]) - - # Run and post-process - model.run(apply_tally_results=True) - - # Get radial flux distribution - flux_collision = tally1.mean.ravel() - flux_collision_unc = tally1.std_dev.ravel() - flux_tracklength = tally2.mean.ravel() - flux_tracklength_unc = tally2.std_dev.ravel() - - # Construct arrays with uncertainties - collision = uarray(flux_collision, flux_collision_unc) - tracklength = uarray(flux_tracklength, flux_tracklength_unc) - delta = collision - tracklength - - # Compute differences and standard deviations - diff = nominal_values(delta) - std_dev = std_devs(delta) - - # Exclude zero-uncertainty bins - mask = std_dev > 0.0 - dof = int(np.sum(mask)) - - # Global chi-square consistency test between collision and tracklength - # estimators. Target false positive rate ~1e-4 (1 in 10,000) - z = diff[mask] / std_dev[mask] - chi2_stat = np.sum(z * z) - alpha = 1.0e-4 - crit = chi2.ppf(1 - alpha, dof) - assert chi2_stat < crit, ( - f"Collision vs tracklength tallies disagree: chi2={chi2_stat:.2f} " - f">= {crit=:.2f} ({dof=}, {alpha=})" - ) - - -def test_regular_mesh_get_indices_at_coords(): - """Test get_indices_at_coords method for RegularMesh""" - # Create a 10x10x10 mesh from (0,0,0) to (1,1,1) - # Each voxel is 0.1 x 0.1 x 0.1 - mesh = openmc.RegularMesh() - mesh.lower_left = (0, 0, 0) - mesh.upper_right = (1, 1, 1) - mesh.dimension = [10, 10, 10] - - # Test lower-left corner maps to first voxel (0, 0, 0) - assert mesh.get_indices_at_coords([0.0, 0.0, 0.0]) == (0, 0, 0) - - # Test centroid of first voxel - # Voxel 0 spans [0.0, 0.1], so centroid is at 0.05 - assert mesh.get_indices_at_coords([0.05, 0.05, 0.05]) == (0, 0, 0) - - # Test centroid of last voxel maps correctly - # Voxel 9 spans [0.9, 1.0], so centroid is at 0.95 - assert mesh.get_indices_at_coords([0.95, 0.95, 0.95]) == (9, 9, 9) - - # Test a middle voxel - # Voxel 4 spans [0.4, 0.5], so 0.45 should map to it - assert mesh.get_indices_at_coords([0.45, 0.45, 0.45]) == (4, 4, 4) - - # Test mixed indices - assert mesh.get_indices_at_coords([0.05, 0.45, 0.95]) == (0, 4, 9) - assert mesh.get_indices_at_coords([0.95, 0.05, 0.45]) == (9, 0, 4) - - # Test coordinates outside mesh bounds raise ValueError - with pytest.raises(ValueError): - mesh.get_indices_at_coords([-0.5, 0.5, 0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([1.5, 0.5, 0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([0.5, -0.5, 0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([0.5, 1.5, 0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([0.5, 0.5, -0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([0.5, 0.5, 1.5]) - - # Test that results match expected dimensionality (3D mesh returns 3-tuple) - result = mesh.get_indices_at_coords([0.5, 0.5, 0.5]) - assert isinstance(result, tuple) - assert len(result) == 3 - - # Test that indices can be used directly with centroids array - idx = mesh.get_indices_at_coords([0.95, 0.95, 0.95]) - centroid = mesh.centroids[idx] - np.testing.assert_array_almost_equal(centroid, [0.95, 0.95, 0.95]) - - # Test with a 2D mesh - mesh_2d = openmc.RegularMesh() - mesh_2d.lower_left = (0, 0) - mesh_2d.upper_right = (1, 1) - mesh_2d.dimension = [10, 10] - result_2d = mesh_2d.get_indices_at_coords([0.5, 0.5, 999.0]) - assert isinstance(result_2d, tuple) - assert len(result_2d) == 2 - assert result_2d == (5, 5) - - # Test with a 1D mesh - mesh_1d = openmc.RegularMesh() - mesh_1d.lower_left = [0] - mesh_1d.upper_right = [1] - mesh_1d.dimension = [10] - result_1d = mesh_1d.get_indices_at_coords([0.5, 999.0, 999.0]) - assert isinstance(result_1d, tuple) - assert len(result_1d) == 1 - assert result_1d == (5,) - - -def test_rectilinear_mesh_get_indices_at_coords(): - """Test get_indices_at_coords method for RectilinearMesh""" - # Create a 3x2x2 rectilinear mesh with non-uniform spacing - mesh = openmc.RectilinearMesh() - mesh.x_grid = [0., 1., 5., 10.] - mesh.y_grid = [-10., -5., 0.] - mesh.z_grid = [-100., 0., 100.] - - # Test lower-left corner maps to first voxel (0, 0, 0) - assert mesh.get_indices_at_coords([0.0, -10., -100.]) == (0, 0, 0) - - # Test centroid of first voxel - assert mesh.get_indices_at_coords([0.5, -7.5, -50.]) == (0, 0, 0) - - # Test centroid of last voxel maps correctly - assert mesh.get_indices_at_coords([7.5, -2.5, 50.]) == (2, 1, 1) - - # Test upper_right corner maps to last voxel - assert mesh.get_indices_at_coords([10., 0., 100.]) == (2, 1, 1) - - # Test a middle voxel - assert mesh.get_indices_at_coords([2., -5., 0.]) == (1, 1, 1) - - # Test coordinates outside mesh bounds raise ValueError - with pytest.raises(ValueError): - mesh.get_indices_at_coords([-0.5, 0.5, 0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([1.5, 0.5, 0.5]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([0.5, -0.5, 110.]) - with pytest.raises(ValueError): - mesh.get_indices_at_coords([0.5, -20., 110.]) - - -def test_SphericalMesh_get_indices_at_coords(): - """Test get_indices_at_coords method for SphericalMesh""" - - # Basic mesh with default phi and theta grids (single angular bin) - mesh = openmc.SphericalMesh(r_grid=(0, 5, 10)) - - assert mesh.get_indices_at_coords([3, 0, 0]) == (0, 0, 0) - assert mesh.get_indices_at_coords([0, 0, 3]) == (0, 0, 0) - assert mesh.get_indices_at_coords([0, 0, -3]) == (0, 0, 0) - assert mesh.get_indices_at_coords([7, 0, 0]) == (1, 0, 0) - assert mesh.get_indices_at_coords([10, 0, 0]) == (1, 0, 0) - - # Out-of-bounds r - with pytest.raises(ValueError): - mesh.get_indices_at_coords([11, 0, 0]) - - mesh2 = openmc.SphericalMesh(r_grid=(2, 5, 10)) - with pytest.raises(ValueError): - mesh2.get_indices_at_coords([1, 0, 0]) - - # Multi-bin angular grids: use points clearly inside bins - mesh3 = openmc.SphericalMesh( - r_grid=(0, 5, 10), - theta_grid=(0, pi/4, pi/2, pi), - phi_grid=(0, pi/2, pi, 3*pi/2, 2*pi) - ) - - # Near z-axis: theta~0 -> bin 0 - assert mesh3.get_indices_at_coords([0.01, 0, 3]) == (0, 0, 0) - - # theta in (0, pi/4) -> bin 0: [1, 0, 2] theta=arccos(2/sqrt(5))~0.46 - assert mesh3.get_indices_at_coords([1, 0, 2]) == (0, 0, 0) - - # theta in (pi/4, pi/2) -> bin 1: [2, 0, 1] theta=arccos(1/sqrt(5))~1.107 - assert mesh3.get_indices_at_coords([2, 0, 1]) == (0, 1, 0) - - # theta in (pi/2, pi) -> bin 2: [1, 0, -2] theta=arccos(-2/sqrt(5))~2.034 - assert mesh3.get_indices_at_coords([1, 0, -2]) == (0, 2, 0) - - # phi in (pi/2, pi) -> bin 1: [-1, 1, 0.5] - assert mesh3.get_indices_at_coords([-1, 1, 0.5]) == (0, 1, 1) - - # phi in (pi, 3*pi/2) -> bin 2: [-1, -1, 0.5] - assert mesh3.get_indices_at_coords([-1, -1, 0.5]) == (0, 1, 2) - - # phi in (3*pi/2, 2*pi) -> bin 3: [1, -1, 0.5] - assert mesh3.get_indices_at_coords([1, -1, 0.5]) == (0, 1, 3) - - # Non-default origin - mesh4 = openmc.SphericalMesh( - r_grid=(0, 5, 10), - origin=(100, 200, 300) - ) - - assert mesh4.get_indices_at_coords([103, 200, 300]) == (0, 0, 0) - assert mesh4.get_indices_at_coords([100, 200, 307]) == (1, 0, 0) - - with pytest.raises(ValueError): - mesh4.get_indices_at_coords([111, 200, 300]) - - # Degenerate case: point at origin with r_grid starting at 0 - mesh5 = openmc.SphericalMesh(r_grid=(0, 5)) - assert mesh5.get_indices_at_coords([0, 0, 0]) == (0, 0, 0) - - # Out-of-bounds theta: restricted theta grid - mesh6 = openmc.SphericalMesh( - r_grid=(0, 10), - theta_grid=(0, pi/4) - ) - with pytest.raises(ValueError): - mesh6.get_indices_at_coords([5, 0, 0]) # theta=pi/2 > pi/4 - - # Out-of-bounds phi: restricted phi grid - mesh7 = openmc.SphericalMesh( - r_grid=(0, 10), - phi_grid=(0, pi/2) - ) - with pytest.raises(ValueError): - mesh7.get_indices_at_coords([-5, 0, 0]) # phi=pi > pi/2 - - # Diagonal point: verify r, theta, phi all computed correctly - r = 6.0 - val = r / sqrt(3) - result = mesh3.get_indices_at_coords([val, val, val]) - assert result[0] == 1 # r=6 in second bin [5, 10] - assert result[1] == 1 # theta=arccos(1/sqrt(3))~0.955, in (pi/4, pi/2) - assert result[2] == 0 # phi=pi/4, in [0, pi/2) diff --git a/tests/unit_tests/test_mesh_dagmc_tets.vtk b/tests/unit_tests/test_mesh_dagmc_tets.vtk deleted file mode 120000 index 9f7000175..000000000 --- a/tests/unit_tests/test_mesh_dagmc_tets.vtk +++ /dev/null @@ -1 +0,0 @@ -../regression_tests/unstructured_mesh/test_mesh_dagmc_tets.vtk \ No newline at end of file diff --git a/tests/unit_tests/test_mesh_from_domain.py b/tests/unit_tests/test_mesh_from_domain.py deleted file mode 100644 index 46d22f0d2..000000000 --- a/tests/unit_tests/test_mesh_from_domain.py +++ /dev/null @@ -1,198 +0,0 @@ -import numpy as np -import openmc -import pytest - - -def test_reg_mesh_from_cell(): - """Tests a RegularMesh can be made from a Cell and the specified dimensions - are propagated through. Cell is not centralized""" - surface = openmc.Sphere(r=10, x0=2, y0=3, z0=5) - cell = openmc.Cell(region=-surface) - - mesh = openmc.RegularMesh.from_domain(domain=cell, dimension=[7, 11, 13]) - assert isinstance(mesh, openmc.RegularMesh) - assert np.array_equal(mesh.dimension, (7, 11, 13)) - assert np.array_equal(mesh.lower_left, cell.bounding_box[0]) - assert np.array_equal(mesh.upper_right, cell.bounding_box[1]) - - -def test_reg_mesh_from_bounding_box(): - """Tests a RegularMesh can be made from a BoundingBox directly.""" - bb = openmc.BoundingBox([-8, -7, -5], [12, 13, 15]) - - mesh = openmc.RegularMesh.from_domain(domain=bb, dimension=[7, 11, 13]) - assert isinstance(mesh, openmc.RegularMesh) - assert np.array_equal(mesh.dimension, (7, 11, 13)) - assert np.array_equal(mesh.lower_left, bb[0]) - assert np.array_equal(mesh.upper_right, bb[1]) - - -def test_rectilinear_mesh_from_bounding_box(): - """Tests a RectilinearMesh can be made from a BoundingBox directly.""" - bb = openmc.BoundingBox([-8, -7, -5], [12, 13, 15]) - - mesh = openmc.RectilinearMesh.from_bounding_box(bb, dimension=[2, 4, 5]) - assert isinstance(mesh, openmc.RectilinearMesh) - assert np.array_equal(mesh.dimension, (2, 4, 5)) - assert np.array_equal(mesh.lower_left, bb[0]) - assert np.array_equal(mesh.upper_right, bb[1]) - assert np.array_equal(mesh.x_grid, [-8., 2., 12.]) - assert np.array_equal(mesh.y_grid, [-7., -2., 3., 8., 13.]) - assert np.array_equal(mesh.z_grid, [-5., -1., 3., 7., 11., 15.]) - - -def test_cylindrical_mesh_from_cell(): - """Tests a CylindricalMesh can be made from a Cell and the specified - dimensions are propagated through.""" - # Cell is not centralized on Z axis - cy_surface = openmc.ZCylinder(r=50) - z_surface_1 = openmc.ZPlane(z0=40) - z_surface_2 = openmc.ZPlane(z0=10) - cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) - mesh = openmc.CylindricalMesh.from_domain(domain=cell, dimension=[2, 4, 3]) - - assert isinstance(mesh, openmc.CylindricalMesh) - assert np.array_equal(mesh.dimension, (2, 4, 3)) - assert np.array_equal(mesh.r_grid, [0., 25., 50.]) - assert np.array_equal(mesh.phi_grid, [0., 0.5*np.pi, np.pi, 1.5*np.pi, 2.*np.pi]) - assert np.array_equal(mesh.z_grid, [0., 10., 20., 30.]) - assert np.array_equal(mesh.origin, [0., 0., 10.]) - - # Cell is not centralized on Z or X axis - cy_surface = openmc.ZCylinder(r=50, x0=100) - cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) - mesh = openmc.CylindricalMesh.from_domain(domain=cell, dimension=[1, 1, 1]) - - assert isinstance(mesh, openmc.CylindricalMesh) - assert np.array_equal(mesh.dimension, (1, 1, 1)) - assert np.array_equal(mesh.r_grid, [0., 50.]) - assert np.array_equal(mesh.origin, [100., 0., 10.]) - - # Cell is not centralized on Z, X or Y axis - cy_surface = openmc.ZCylinder(r=50, x0=100, y0=170) - cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) - mesh = openmc.CylindricalMesh.from_domain(domain=cell, dimension=[1, 1, 1]) - - assert isinstance(mesh, openmc.CylindricalMesh) - assert np.array_equal(mesh.r_grid, [0., 50.]) - assert np.array_equal(mesh.origin, [100., 170., 10.]) - - -def test_reg_mesh_from_region(): - """Tests a RegularMesh can be made from a Region and the default dimensions - are propagated through. Region is not centralized""" - surface = openmc.Sphere(r=1, x0=-5, y0=-3, z0=-2) - region = -surface - - mesh = openmc.RegularMesh.from_domain(domain=region) - assert isinstance(mesh, openmc.RegularMesh) - assert np.array_equal(mesh.dimension, (10, 10, 10)) # default values - assert np.array_equal(mesh.lower_left, region.bounding_box[0]) - assert np.array_equal(mesh.upper_right, region.bounding_box[1]) - - -def test_cylindrical_mesh_from_region(): - """Tests a CylindricalMesh can be made from a Region and the specified - dimensions and phi_grid_bounds are propagated through. Cell is centralized""" - cy_surface = openmc.ZCylinder(r=6) - z_surface_1 = openmc.ZPlane(z0=30) - z_surface_2 = openmc.ZPlane(z0=-30) - cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) - mesh = openmc.CylindricalMesh.from_domain( - domain=cell, - dimension=(6, 2, 3), - phi_grid_bounds=(0., np.pi) - ) - - assert isinstance(mesh, openmc.CylindricalMesh) - assert np.array_equal(mesh.dimension, (6, 2, 3)) - assert np.array_equal(mesh.r_grid, [0., 1., 2., 3., 4., 5., 6.]) - assert np.array_equal(mesh.phi_grid, [0., 0.5*np.pi, np.pi]) - assert np.array_equal(mesh.z_grid, [0.0, 20., 40., 60]) - assert np.array_equal(mesh.origin, (0.0, 0.0, -30.)) - - -def test_spherical_mesh_from_domain(): - """Tests a SphericalMesh can be made from a Region and the specified - dimensions are propagated through. Cell is not centralized""" - sphere = openmc.Sphere(r=5, x0=2, y0=3, z0=4) - region = -sphere - - geometry = openmc.Geometry(openmc.Universe(cells=[openmc.Cell(region=region)])) - - region_mesh = openmc.SphericalMesh.from_domain( - domain=region, dimension=(4, 3, 4)) - universe_mesh = openmc.SphericalMesh.from_domain( - domain=geometry.root_universe, dimension=(4, 3, 4)) - geometry_mesh = openmc.SphericalMesh.from_domain( - domain=geometry, dimension=(4, 3, 4)) - - - for mesh in (region_mesh, universe_mesh, geometry_mesh): - assert isinstance(mesh, openmc.SphericalMesh) - assert np.array_equal(mesh.dimension, (4, 3, 4)) - assert np.array_equal(mesh.r_grid, [0., 1.25, 2.5, 3.75, 5.0]) - assert np.array_equal(mesh.theta_grid, [0., np.pi/3., 2*np.pi/3., np.pi]) - assert np.array_equal(mesh.phi_grid, [0., np.pi/2., np.pi, 3*np.pi/2., 2*np.pi]) - assert np.array_equal(mesh.origin, (2.0, 3.0, 4.0)) - - for p in mesh.centroids.reshape(-1, 3): - assert p in mesh.bounding_box - - -def test_reg_mesh_from_universe(): - """Tests a RegularMesh can be made from a Universe and the default - dimensions are propagated through. Universe is centralized""" - surface = openmc.Sphere(r=42) - cell = openmc.Cell(region=-surface) - universe = openmc.Universe(cells=[cell]) - - mesh = openmc.RegularMesh.from_domain(universe) - assert isinstance(mesh, openmc.RegularMesh) - assert np.array_equal(mesh.dimension, (10, 10, 10)) # default values - assert np.array_equal(mesh.lower_left, universe.bounding_box[0]) - assert np.array_equal(mesh.upper_right, universe.bounding_box[1]) - - -def test_reg_mesh_from_geometry(): - """Tests a RegularMesh can be made from a Geometry and the default - dimensions are propagated through. Geometry is centralized""" - surface = openmc.Sphere(r=42) - cell = openmc.Cell(region=-surface) - universe = openmc.Universe(cells=[cell]) - geometry = openmc.Geometry(universe) - - mesh = openmc.RegularMesh.from_domain(geometry) - assert isinstance(mesh, openmc.RegularMesh) - assert np.array_equal(mesh.dimension, (10, 10, 10)) # default values - assert np.array_equal(mesh.lower_left, geometry.bounding_box[0]) - assert np.array_equal(mesh.upper_right, geometry.bounding_box[1]) - - -def test_error_from_unsupported_object(): - with pytest.raises(TypeError): - openmc.RegularMesh.from_domain("vacuum energy") - - -def test_regularmesh_from_domain_error_from_small_dimensions(): - surface = openmc.Sphere(r=20) - cell = openmc.Cell(region=-surface) - with pytest.raises( - ValueError, match='Unable to set "dimension" to "-2" since it is less than "1"' - ): - openmc.RegularMesh.from_domain(domain=cell, dimension=-2) - - -def test_dimensions_from_domain_dimensions_from_int(): - region = openmc.model.RectangularParallelepiped( - xmin=-100, - xmax=150, - ymin=-50, - ymax=200, - zmin=300, - zmax=400, - boundary_type="vacuum", - ) - cell = openmc.Cell(region=-region) - mesh = openmc.RegularMesh.from_domain(domain=cell, dimension=1000) - assert mesh.dimension == (14, 14, 5) diff --git a/tests/unit_tests/test_mesh_hexes.exo b/tests/unit_tests/test_mesh_hexes.exo deleted file mode 120000 index 272da92a4..000000000 --- a/tests/unit_tests/test_mesh_hexes.exo +++ /dev/null @@ -1 +0,0 @@ -../regression_tests/unstructured_mesh/test_mesh_hexes.exo \ No newline at end of file diff --git a/tests/unit_tests/test_mesh_tets.e b/tests/unit_tests/test_mesh_tets.e deleted file mode 120000 index 8a6287b4d..000000000 --- a/tests/unit_tests/test_mesh_tets.e +++ /dev/null @@ -1 +0,0 @@ -../regression_tests/unstructured_mesh/test_mesh_tets.e \ No newline at end of file diff --git a/tests/unit_tests/test_mesh_to_vtk.py b/tests/unit_tests/test_mesh_to_vtk.py new file mode 100644 index 000000000..26a393b41 --- /dev/null +++ b/tests/unit_tests/test_mesh_to_vtk.py @@ -0,0 +1,76 @@ +import numpy as np +from pathlib import Path +import pytest + +vtk = pytest.importorskip("vtk") +from vtk.util import numpy_support as nps + +import openmc + + +regular_mesh = openmc.RegularMesh() +regular_mesh.lower_left = (0, 0, 0) +regular_mesh.upper_right = (1, 1, 1) +regular_mesh.dimension = [30, 20, 10] + +rectilinear_mesh = openmc.RectilinearMesh() +rectilinear_mesh.x_grid = np.linspace(1, 2, num=30) +rectilinear_mesh.y_grid = np.linspace(1, 2, num=30) +rectilinear_mesh.z_grid = np.linspace(1, 2, num=30) + +cylinder_mesh = openmc.CylindricalMesh() +cylinder_mesh.r_grid = np.linspace(1, 2, num=30) +cylinder_mesh.phi_grid = np.linspace(0, np.pi, num=50) +cylinder_mesh.z_grid = np.linspace(0, 1, num=30) + +spherical_mesh = openmc.SphericalMesh() +spherical_mesh.r_grid = np.linspace(1, 2, num=30) +spherical_mesh.phi_grid = np.linspace(0, np.pi, num=50) +spherical_mesh.theta_grid = np.linspace(0, np.pi / 2, num=30) + +@pytest.mark.parametrize("mesh", [cylinder_mesh, regular_mesh, rectilinear_mesh, spherical_mesh]) +def test_write_data_to_vtk(mesh, tmpdir): + # BUILD + filename = Path(tmpdir) / "out.vtk" + + data = np.random.random(mesh.num_mesh_cells) + + # RUN + mesh.write_data_to_vtk(filename=filename, datasets={"label1": data, "label2": data}) + + # TEST + assert filename.is_file() + + # read file + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(filename) + reader.Update() + + # check name of datasets + vtk_grid = reader.GetOutput() + array1 = vtk_grid.GetCellData().GetArray(0) + array2 = vtk_grid.GetCellData().GetArray(1) + + assert array1.GetName() == "label1" + assert array2.GetName() == "label2" + + # check size of datasets + assert nps.vtk_to_numpy(array1).size == data.size + assert nps.vtk_to_numpy(array2).size == data.size + +@pytest.mark.parametrize("mesh", [cylinder_mesh, regular_mesh, rectilinear_mesh, spherical_mesh]) +def test_write_data_to_vtk_size_mismatch(mesh): + """Checks that an error is raised when the size of the dataset + doesn't match the mesh number of cells + + Parameters + ---------- + mesh : openmc.StructuredMesh + The mesh to test + """ + right_size = mesh.num_mesh_cells + data = np.random.random(right_size + 1) + + expected_error_msg = "The size of the dataset label should be equal to the number of cells" + with pytest.raises(RuntimeError, match=expected_error_msg): + mesh.write_data_to_vtk(filename="out.vtk", datasets={"label": data}) \ No newline at end of file diff --git a/tests/unit_tests/test_mg_inverse_velocity.py b/tests/unit_tests/test_mg_inverse_velocity.py deleted file mode 100644 index b520e48d1..000000000 --- a/tests/unit_tests/test_mg_inverse_velocity.py +++ /dev/null @@ -1,59 +0,0 @@ -import openmc -import numpy as np -import pytest - -@pytest.fixture -def one_group_lib(): - groups = openmc.mgxs.EnergyGroups([0.0, 20.0e6]) - xsdata = openmc.XSdata('slab_mat', groups) - xsdata.order = 0 - xsdata.set_total([0.0]) - xsdata.set_absorption([0.0]) - xsdata.set_scatter_matrix([[[0.0]]]) - - mg_library = openmc.MGXSLibrary(groups) - mg_library.add_xsdata(xsdata) - name = 'mgxs.h5' - mg_library.export_to_hdf5(name) - yield name - -@pytest.fixture -def slab_model(one_group_lib): - model = openmc.Model() - mat = openmc.Material(name='slab_material') - mat.set_density('macro', 1.0) - mat.add_macroscopic('slab_mat') - - model.materials = openmc.Materials([mat]) - model.materials.cross_sections = one_group_lib - - x_min = openmc.XPlane(x0=0.0, boundary_type='vacuum') - x_max = openmc.XPlane(x0=10.0, boundary_type='vacuum') - - y_min = openmc.YPlane(y0=-10.0, boundary_type='vacuum') - y_max = openmc.YPlane(y0=10.0, boundary_type='vacuum') - z_min = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - z_max = openmc.ZPlane(z0=19.0, boundary_type='vacuum') - - cell = openmc.Cell(fill=mat, region=+z_min & -x_max & +y_min & -y_max & +z_min & -z_max) - model.geometry = openmc.Geometry([cell]) - - model.settings = openmc.Settings() - model.settings.energy_mode = 'multi-group' - model.settings.run_mode = 'fixed source' - model.settings.batches = 3 - model.settings.particles = 10 - - source = openmc.IndependentSource() - source.space = openmc.stats.Point((5.0, 0.0, 0.0)) - model.settings.source = source - return model - -def test_inverse_velocity(run_in_tmpdir, slab_model): - tally = openmc.Tally() - tally.scores = ['flux','inverse-velocity'] - slab_model.tallies = [tally] - slab_model.run(apply_tally_results=True) - inverse_velocity = tally.mean.squeeze()[1]/tally.mean.squeeze()[0] - - assert inverse_velocity == pytest.approx(1.6144e-5, rel=1e-4) diff --git a/tests/unit_tests/test_mgxs_convert_flux.py b/tests/unit_tests/test_mgxs_convert_flux.py deleted file mode 100644 index e235f88e0..000000000 --- a/tests/unit_tests/test_mgxs_convert_flux.py +++ /dev/null @@ -1,62 +0,0 @@ -"""Tests for openmc.mgxs.convert_flux_groups function.""" - -import numpy as np -import pytest -from pytest import approx - -import openmc.mgxs - - -def test_coarse_to_fine(): - """Test coarse to fine conversion with flux conservation.""" - source = openmc.mgxs.EnergyGroups([1.0, 10.0, 100.0]) - target = openmc.mgxs.EnergyGroups([1.0, 5.0, 10.0, 50.0, 100.0]) - flux_source = np.array([1e8, 2e8]) - - flux_target = openmc.mgxs.convert_flux_groups(flux_source, source, target) - - # Check conservation - assert np.sum(flux_target) == approx(np.sum(flux_source)) - assert len(flux_target) == 4 - assert np.all(flux_target >= 0) - - -def test_fine_to_coarse(): - """Test fine to coarse conversion (reverse direction).""" - source = openmc.mgxs.EnergyGroups([1.0, 5.0, 10.0, 50.0, 100.0]) - target = openmc.mgxs.EnergyGroups([1.0, 10.0, 100.0]) - flux_source = np.array([1e7, 2e7, 3e7, 4e7]) - - flux_target = openmc.mgxs.convert_flux_groups(flux_source, source, target) - - assert np.sum(flux_target) == approx(np.sum(flux_source)) - assert len(flux_target) == 2 - - -def test_lethargy_distribution(): - """Test that flux is distributed by lethargy, not linear energy.""" - # Single group from 1 to 100 eV - source = openmc.mgxs.EnergyGroups([1.0, 100.0]) - # Split into two groups: 1-10 eV and 10-100 eV - target = openmc.mgxs.EnergyGroups([1.0, 10.0, 100.0]) - flux_source = np.array([1e8]) - - flux_target = openmc.mgxs.convert_flux_groups(flux_source, source, target) - - # Each target group spans one decade (ln(10) lethargy each) - # So flux should be split 50/50 by lethargy - assert flux_target[0] == approx(5e7) - assert flux_target[1] == approx(5e7) - - -def test_fns_ccfe709_to_ukaea1102(): - """Test CCFE-709 to UKAEA-1102 conversion with real FNS flux spectrum.""" - from pathlib import Path - flux_file = Path(__file__).parent.parent / 'fns_flux_709.npy' - fns_flux_709 = np.load(flux_file) - - flux_1102 = openmc.mgxs.convert_flux_groups(fns_flux_709, 'CCFE-709', 'UKAEA-1102') - - assert len(flux_1102) == 1102 - assert np.sum(flux_1102) == approx(np.sum(fns_flux_709), rel=1e-10) - assert np.all(flux_1102 >= 0) diff --git a/tests/unit_tests/test_model.py b/tests/unit_tests/test_model.py index f60c458b6..9b05ed2a5 100644 --- a/tests/unit_tests/test_model.py +++ b/tests/unit_tests/test_model.py @@ -1,13 +1,11 @@ from math import pi from pathlib import Path -import os import numpy as np import pytest import openmc import openmc.lib -from openmc.plots import id_map_to_rgb @pytest.fixture(scope='function') @@ -36,8 +34,8 @@ def pin_model_attributes(): pitch = 1.25984 fuel_or = openmc.ZCylinder(r=0.39218, name='Fuel OR') clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR') - box = openmc.model.RectangularPrism(pitch, pitch, - boundary_type='reflective') + box = openmc.model.rectangular_prism(pitch, pitch, + boundary_type='reflective') # Define cells fuel_inf_cell = openmc.Cell(cell_id=1, name='inf fuel', fill=uo2) @@ -45,7 +43,7 @@ def pin_model_attributes(): fuel = openmc.Cell(cell_id=2, name='fuel', fill=fuel_inf_univ, region=-fuel_or) clad = openmc.Cell(cell_id=3, fill=zirc, region=+fuel_or & -clad_or) - water = openmc.Cell(cell_id=4, fill=borated_water, region=+clad_or & -box) + water = openmc.Cell(cell_id=4, fill=borated_water, region=+clad_or & box) # Define overall geometry geom = openmc.Geometry([fuel, clad, water]) @@ -58,9 +56,9 @@ def pin_model_attributes(): # Create a uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings.source = openmc.IndependentSource( - space=uniform_dist, constraints={'fissionable': True}) + uniform_dist = openmc.stats.Box( + bounds[:3], bounds[3:], only_fissionable=True) + settings.source = openmc.source.Source(space=uniform_dist) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] @@ -74,13 +72,13 @@ def pin_model_attributes(): tal.scores = ['flux', 'fission'] tals.append(tal) - plot1 = openmc.SlicePlot(plot_id=1) + plot1 = openmc.Plot(plot_id=1) plot1.origin = (0., 0., 0.) plot1.width = (pitch, pitch) plot1.pixels = (300, 300) plot1.color_by = 'material' plot1.filename = 'test' - plot2 = openmc.SlicePlot(plot_id=2) + plot2 = openmc.Plot(plot_id=2) plot2.origin = (0., 0., 0.) plot2.width = (pitch, pitch) plot2.pixels = (300, 300) @@ -252,11 +250,10 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm): model = openmc.examples.pwr_pin_cell() model.init_lib(output=False, intracomm=mpi_intracomm) - # Change cell fuel temperature, density, material density and export properties + # Change fuel temperature and density and export properties cell = openmc.lib.cells[1] cell.set_temperature(600.0) cell.fill.set_density(5.0, 'g/cm3') - cell.set_density(10.0) openmc.lib.export_properties(output=False) # Import properties to existing model @@ -265,12 +262,10 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm): # Check to see that values are assigned to the C and python representations # First python cell = model.geometry.get_all_cells()[1] - assert cell.temperature == 600.0 - assert cell.density == pytest.approx(10.0, 1e-5) + assert cell.temperature == [600.0] assert cell.fill.get_mass_density() == pytest.approx(5.0) # Now C assert openmc.lib.cells[1].get_temperature() == 600. - assert openmc.lib.cells[1].get_density() == pytest.approx(10.0, 1e-5) assert openmc.lib.materials[1].get_density('g/cm3') == pytest.approx(5.0) # Clear the C API @@ -286,8 +281,7 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm): 'with_properties/settings.xml' ) cell = model_with_properties.geometry.get_all_cells()[1] - assert cell.temperature == 600.0 - assert cell.density == pytest.approx(10.0, 1e-5) + assert cell.temperature == [600.0] assert cell.fill.get_mass_density() == pytest.approx(5.0) @@ -453,7 +447,7 @@ def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm): # In this test we first run without pre-initializing the shared library # data and then compare. Then we repeat with the C API already initialized # and make sure we get the same answer - test_model.deplete(timesteps=[1e6], method='predictor', final_step=False, + test_model.deplete([1e6], 'predictor', final_step=False, operator_kwargs=op_kwargs, power=1., output=False) # Get the new Xe136 and U235 atom densities @@ -462,20 +456,6 @@ def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm): assert after_xe + after_u == pytest.approx(initial_u, abs=1e-15) assert test_model.is_initialized is False - # check the tally output - def check_tally_output(): - with openmc.StatePoint('openmc_simulation_n0.h5') as sp: - flux = sp.get_tally(id=1).get_values(scores=['flux'])[0, 0, 0] - fission = sp.get_tally(id=1).get_values( - scores=['fission'])[0, 0, 0] - - # we're mainly just checking that the result was produced, - # so a rough numerical comparison doesn't hurt to have. - assert flux == pytest.approx(13.1, abs=0.2) - assert fission == pytest.approx(0.47, abs=0.2) - - check_tally_output() - # Reset the initial material densities mats[0].nuclides.clear() densities = initial_mat.get_nuclide_atom_densities() @@ -487,7 +467,7 @@ def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm): # Now we can re-run with the pre-initialized API test_model.init_lib(output=False, intracomm=mpi_intracomm) - test_model.deplete(timesteps=[1e6], method='predictor', final_step=False, + test_model.deplete([1e6], 'predictor', final_step=False, operator_kwargs=op_kwargs, power=1., output=False) # Get the new Xe136 and U235 atom densities @@ -500,8 +480,6 @@ def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm): assert after_xe == pytest.approx(after_lib_xe, abs=1e-15) assert after_u == pytest.approx(after_lib_u, abs=1e-15) - check_tally_output() - test_model.finalize_lib() @@ -551,542 +529,3 @@ def test_calc_volumes(run_in_tmpdir, pin_model_attributes, mpi_intracomm): assert openmc.lib.materials[3].volume == mats[2].volume test_model.finalize_lib() - - -def test_model_xml(run_in_tmpdir): - - # load a model from examples - pwr_model = openmc.examples.pwr_core() - - # export to separate XMLs manually - pwr_model.settings.export_to_xml('settings_ref.xml') - pwr_model.materials.export_to_xml('materials_ref.xml') - pwr_model.geometry.export_to_xml('geometry_ref.xml') - - # now write and read a model.xml file - pwr_model.export_to_model_xml() - new_model = openmc.Model.from_model_xml() - - # make sure we can also export this again to separate - # XML files - new_model.export_to_xml() - - -def test_single_xml_exec(run_in_tmpdir): - - pincell_model = openmc.examples.pwr_pin_cell() - - pincell_model.export_to_model_xml('pwr_pincell.xml') - - openmc.run(path_input='pwr_pincell.xml') - - with pytest.raises(RuntimeError, match='ex-em-ell.xml'): - openmc.run(path_input='ex-em-ell.xml') - - # test that a file in a different directory can be used - os.mkdir('inputs') - pincell_model.export_to_model_xml('./inputs/pincell.xml') - openmc.run(path_input='./inputs/pincell.xml') - - with pytest.raises(RuntimeError, match='input_dir'): - openmc.run(path_input='input_dir/pincell.xml') - - # Make sure path can be specified with run - pincell_model.run(path='my_model.xml') - - os.mkdir('subdir') - pincell_model.run(path='subdir') - - -def test_nuclides_to_ignore(run_in_tmpdir, pin_model_attributes): - """Test nuclides_to_ignore when exporting a model XML""" - materials, geometry, settings = pin_model_attributes[:3] - model = openmc.Model(geometry=geometry, settings=settings) - - # grab one of the nuclides present in this model as a test - test_nuclide = list(materials[0].get_nuclides())[0] - - # exclude the test nuclide from the XML file during export - model.export_to_model_xml(nuclides_to_ignore=[test_nuclide]) - - # ensure that the nuclide doesn't appear after reading in - # the resulting XML model - xml_model = openmc.Model.from_model_xml() - for material in xml_model.materials: - assert test_nuclide not in material.get_nuclides() - - -def test_model_plot(): - # plots the geometry with source location and checks the resulting - # matplotlib includes the correct coordinates for the scatter plot for all - # basis. - - surface = openmc.Sphere(r=600, boundary_type="vacuum") - cell = openmc.Cell(region=-surface) - geometry = openmc.Geometry([cell]) - source = openmc.IndependentSource(space=openmc.stats.Point((1, 2, 3))) - settings = openmc.Settings(particles=1, batches=1, source=source) - model = openmc.Model(geometry, settings=settings) - - plot = model.plot(n_samples=1, plane_tolerance=4.0, basis="xy") - coords = plot.axes.collections[0].get_offsets().data.flatten() - assert (coords == np.array([1.0, 2.0])).all() - - plot = model.plot(n_samples=1, plane_tolerance=4.0, basis="xz") - coords = plot.axes.collections[0].get_offsets().data.flatten() - assert (coords == np.array([1.0, 3.0])).all() - - plot = model.plot(n_samples=1, plane_tolerance=4.0, basis="yz") - coords = plot.axes.collections[0].get_offsets().data.flatten() - assert (coords == np.array([2.0, 3.0])).all() - - plot = model.plot(n_samples=1, plane_tolerance=0.1, basis="xy") - coords = plot.axes.collections[0].get_offsets().data.flatten() - assert (coords == np.array([])).all() - - # modify model to include another cell that overlaps the original cell entirely - model.geometry.root_universe.add_cell(openmc.Cell(region=-surface)) - axes = model.plot(show_overlaps=True) - white = np.array((1.0, 1.0, 1.0)) - red = np.array((1.0, 0.0, 0.0)) - axes_image = axes.get_images()[0] - image_data = axes_image.get_array() - # ensure that all of the data in the image data is either white or red - test_mask = (image_data == white) | (image_data == red) - assert np.all(test_mask), "Colors other than white or red found in overlap plot image" - - # Close plots to avoid warning - import matplotlib.pyplot as plt - plt.close('all') - - -def test_model_plot_invalid_inputs(): - surface = openmc.Sphere(r=10.0, boundary_type="vacuum") - cell = openmc.Cell(region=-surface) - model = openmc.Model(openmc.Geometry([cell])) - - with pytest.raises(ValueError): - model.plot(n_samples=-1) - with pytest.raises(TypeError): - model.plot(n_samples=1.5) - with pytest.raises(ValueError): - model.plot(plane_tolerance=0.0) - with pytest.raises(TypeError): - model.plot(plane_tolerance='1') - with pytest.raises(ValueError): - model.plot(pixels=-1) - with pytest.raises(ValueError): - model.plot(pixels=(0, 100)) - with pytest.raises(ValueError): - model.plot(pixels=(100,)) - with pytest.raises(ValueError): - model.slice_data(u_span=(2, 0, 0), v_span=(0, 2, 0), pixels=-1) - - -def test_model_id_map_initialization(run_in_tmpdir): - model = openmc.examples.pwr_assembly() - model.init_lib(output=False) - - id_map = model.id_map( - pixels=(100, 100), - basis='xy', - origin=(0, 0, 0), - width=(10, 10), - ) - - assert id_map.shape == (100, 100, 3) - assert id_map.dtype == np.int32 - - max_cell_id = max(model.geometry.get_all_cells().keys()) - max_material_id = max(model.geometry.get_all_materials().keys()) - - # add some spot checks for the id_map - # Check that the array contains valid cell/material IDs (not all -2) - # The -2 values indicate outside the geometry - assert not np.all(id_map == -2), "All values are -2, indicating no valid geometry found" - - # Check that we have valid cell IDs (first dimension) - valid_cell_ids = id_map[:, :, 0] - assert np.any(valid_cell_ids >= 0), "No valid cell IDs found in the id_map" - - # Check that we have valid material IDs (third dimension) - valid_material_ids = id_map[:, :, 2] - assert np.any(valid_material_ids >= 0), "No valid material IDs found in the id_map" - - # Check that the middle dimension (cell instances) is consistent - # Cell instances should be >= 0 when cell IDs are valid - cell_instances = id_map[:, :, 1] - valid_cells = valid_cell_ids >= 0 - if np.any(valid_cells): - assert np.all(cell_instances[valid_cells] >= 0), "Invalid cell instances found for valid cells" - - # Check that the array contains reasonable ranges of values - # Cell IDs should be within the expected range for the assembly - if np.any(valid_cell_ids >= 0): - max_map_cell_id = np.max(valid_cell_ids) - assert max_map_cell_id <= max_cell_id, \ - f"Cell ID {max_map_cell_id} in the map is greater than the maximum cell ID {max_cell_id}" - - # Material IDs should be within the expected range - if np.any(valid_material_ids >= 0): - max_map_material_id = np.max(valid_material_ids) - assert max_map_material_id <= max_material_id, \ - f"Material ID {max_map_material_id} in the map is greater than the maximum material ID {max_material_id}" - - # Test id_map with pixels outside the model geometry - # Use a plot that's far from the model center to ensure we get -2 values - outside_id_map = model.id_map( - pixels=(50, 50), - basis='xy', - origin=(1000, 1000, 0), # Far from the model center - width=(10, 10), - ) - - assert outside_id_map.shape == (50, 50, 3) - assert outside_id_map.dtype == np.int32 - - # All values should be -2 (outside geometry) for this plot - assert np.all(outside_id_map == -2), "Expected all values to be -2 for plot outside model geometry" - - # Verify that the outside plot has the correct structure - assert np.all(outside_id_map[:, :, 0] == -2), "Cell IDs should all be -2 outside geometry" - assert np.all(outside_id_map[:, :, 1] == -2), "Cell instances should all be -2 outside geometry" - assert np.all(outside_id_map[:, :, 2] == -2), "Material IDs should all be -2 outside geometry" - - # if the model is already initialized, it should not be finalized - # after calling this method - model.id_map( - pixels=(100, 100), - basis='xy', - origin=(0, 0, 0), - width=(10, 10), - ) - assert model.is_initialized - - # if the model is not initialized, it should be finalized - # before exiting this method - model.finalize_lib() - model.id_map( - pixels=(100, 100), - basis='xy', - origin=(0, 0, 0), - width=(10, 10), - ) - assert not model.is_initialized - - -def test_id_map_aligned_model(): - """Test id_map with a 2x2 lattice where pixel boundaries align to cell boundaries""" - # Create materials -- identical compositions, different IDs - mat1 = openmc.Material(material_id=1, name='Material 1') - mat1.set_density('g/cm3', 1.0) - mat1.add_element('H', 1.0) - - mat2 = openmc.Material(material_id=2, name='Material 2') - mat2.set_density('g/cm3', 1.0) - mat2.add_element('H', 1.0) - - mat3 = openmc.Material(material_id=3, name='Material 3') - mat3.set_density('g/cm3', 1.0) - mat3.add_element('H', 1.0) - - mat4 = openmc.Material(material_id=4, name='Material 4') - mat4.set_density('g/cm3', 1.0) - mat4.add_element('H', 1.0) - - outer_mat = openmc.Material(material_id=5, name='Material 5') - outer_mat.set_density('g/cm3', 1.0) - outer_mat.add_element('H', 1.0) - - inner_materials = [mat1, mat2, mat3, mat4] - - # Create square surface that fits inside the lattice cell - # Lattice cell is 1 cm x 1 cm, so square will be 0.6 cm x 0.6 cm centered on the origin - square = openmc.model.RectangularPrism(0.6, 0.6, boundary_type='transmission') - - # Create cells for this universe - inner_cell = openmc.Cell(cell_id=10, region=-square, name='inner_cell') - inner_cell.fill = inner_materials - - outer_cell = openmc.Cell(cell_id=20, region=+square, name='outer_cell') - outer_cell.fill = outer_mat - - # Create universe - universe = openmc.Universe(universe_id=100, cells=[inner_cell, outer_cell]) - - # Create 2x2 lattice - lattice = openmc.RectLattice(lattice_id=1) - lattice.lower_left = [-1.0, -1.0] - lattice.pitch = [1.0, 1.0] - lattice.universes = [[universe, universe], [universe, universe]] - - # Create outer boundary - outer_boundary = openmc.model.RectangularPrism(2.0, 2.0, boundary_type='vacuum') - - # Create root cell - root_cell = openmc.Cell(cell_id=1, name='root', fill=lattice, region=-outer_boundary) - - # Create geometry - geometry = openmc.Geometry([root_cell]) - - # Create settings - settings = openmc.Settings() - settings.particles = 1000 - settings.batches = 10 - - # Create model - model = openmc.Model(settings=settings, geometry=geometry) - - # Generate id_map with pixel boundaries aligned to cell boundaries - # The model is 2 cm x 2 cm, so we'll use 200x200 pixels to get 0.01 cm resolution - # This allows us to align pixels with the squares inside each lattice cell - id_map = model.id_map( - pixels=(200, 200), - basis='xy', - origin=(0.0, 0.0, 0.0), # Align with lattice lower_left - width=(2.0, 2.0), # Align with lattice size - ) - - # Verify id_map properties - assert id_map.shape == (200, 200, 3) - assert id_map.dtype == np.int32 - - cell_id_map = id_map[:, :, 0] - material_ids_map = id_map[:, :, 2] - - # Check that we have valid cell IDs (not all -2) - assert np.any(cell_id_map >= 0), "No valid cell IDs found in the id_map" - - # Check that we have valid material IDs - assert np.any(material_ids_map >= 0), "No valid material IDs found in the id_map" - - # Check that the expected cell IDs are present - expected_cell_ids = [10, 20] # Root cell, inner cell, outer cell - found_cell_ids = np.unique(cell_id_map[cell_id_map >= 0]) - for cell_id in expected_cell_ids: - assert cell_id in found_cell_ids, f"Expected cell ID {cell_id} not found in id_map" - - # Check that the expected material IDs are present - expected_material_ids = [1, 2, 3, 4, 5] # All materials defined above - found_material_ids = np.unique(material_ids_map[material_ids_map >= 0]) - for mat_id in expected_material_ids: - assert mat_id in found_material_ids, f"Expected material ID {mat_id} not found in id_map" - - # Test specific regions to verify lattice structure - # Check center of each lattice cell (should be inner cells) - # Lattice cell centers are at (-0.5, -0.5), (0.5, -0.5), (-0.5, 0.5), (0.5, 0.5) - # With 200x200 pixels over 2x2 units, each pixel is 0.01 units - - # Bottom-left lattice cell center (should be inner cell 10) - bl_cell, bl_instance, bl_material = id_map[-50, 50] - assert bl_cell == 10, f"Expected cell ID 10 at bottom-left center, got {bl_cell}" - assert bl_instance == 0, f"Expected cell instance 0 at bottom-left center, got {bl_instance}" - assert bl_material == 1, f"Expected material ID 1 at bottom-left center, got {bl_material}" - - # Bottom-right lattice cell center (should be inner cell 10) - br_cell, br_instance, br_material = id_map[-50, 150] - assert br_cell == 10, f"Expected cell ID 10 at bottom-right center, got {br_cell}" - assert br_instance == 1, f"Expected cell instance 1 at bottom-right center, got {br_instance}" - assert br_material == 2, f"Expected material ID 2 at bottom-right center, got {br_material}" - - # Top-left lattice cell center (should be inner cell 10) - tl_cell, tl_instance, tl_material = id_map[-150, 50] - assert tl_cell == 10, f"Expected cell ID 10 at top-left center, got {tl_cell}" - assert tl_instance == 2, f"Expected cell instance 2 at top-left center, got {tl_instance}" - assert tl_material == 3, f"Expected material ID 3 at top-left center, got {tl_material}" - - # Top-right lattice cell center (should be inner cell 10) - tr_cell, tr_instance, tr_material = id_map[-150, 150] - assert tr_cell == 10, f"Expected cell ID 10 at top-right center, got {tr_cell}" - assert tr_instance == 3, f"Expected cell instance 3 at top-right center, got {tr_instance}" - assert tr_material == 4, f"Expected material ID 4 at top-right center, got {tr_material}" - - # Check that the model is properly finalized after id_map call - assert not model.is_initialized, "Model should be finalized after id_map call" - - # Check that the values at the corners are correctly set as the outer cell and material - bl_cell, bl_instance, bl_material = id_map[-1, 0] - assert bl_cell == 20, f"Expected cell ID 20 at bottom-left corner, got {bl_cell}" - assert bl_instance == 0, f"Expected cell instance 0 at bottom-left corner, got {bl_instance}" - assert bl_material == 5, f"Expected material ID 5 at bottom-left corner, got {bl_material}" - - br_cell, br_instance, br_material = id_map[-1, -1] - assert br_cell == 20, f"Expected cell ID 20 at bottom-right corner, got {br_cell}" - assert br_instance == 1, f"Expected cell instance 1 at bottom-right corner, got {br_instance}" - assert br_material == 5, f"Expected material ID 5 at bottom-right corner, got {br_material}" - - tl_cell, tl_instance, tl_material = id_map[0, 0] - assert tl_cell == 20, f"Expected cell ID 20 at top-left corner, got {tl_cell}" - assert tl_instance == 2, f"Expected cell instance 2 at top-left corner, got {tl_instance}" - assert tl_material == 5, f"Expected material ID 5 at top-left corner, got {tl_material}" - - tr_cell, tr_instance, tr_material = id_map[0, -1] - assert tr_cell == 20, f"Expected cell ID 20 at top-right corner, got {tr_cell}" - assert tr_instance == 3, f"Expected cell instance 3 at top-right corner, got {tr_instance}" - assert tr_material == 5, f"Expected material ID 5 at top-right corner, got {tr_material}" - - -def test_id_map_model_with_overlaps(): - """Test id_map with a model that has overlaps and color_overlaps option""" - surface1 = openmc.Sphere(r=50, boundary_type="vacuum") - surface2 = openmc.Sphere(r=30) - cell1 = openmc.Cell(region=-surface1) - cell2 = openmc.Cell(region=-surface2) - geometry = openmc.Geometry([cell1, cell2]) - settings = openmc.Settings() - model = openmc.Model(geometry=geometry, settings=settings) - id_slice = model.id_map( - pixels=(10, 10), - basis='xy', - origin=(0, 0, 0), - width=(100, 100), - ) - assert -3 not in id_slice # -3 indicates overlap region - id_slice = model.id_map( - pixels=(10, 10), - basis='xy', - origin=(0, 0, 0), - width=(100, 100), - color_overlaps=True, # enables id_map to return -3 for overlaps - ) - assert -3 in id_slice - - -def test_setter_from_list(): - mat = openmc.Material() - model = openmc.Model(materials=[mat]) - assert isinstance(model.materials, openmc.Materials) - - tally = openmc.Tally() - model = openmc.Model(tallies=[tally]) - assert isinstance(model.tallies, openmc.Tallies) - - plot = openmc.SlicePlot() - model = openmc.Model(plots=[plot]) - assert isinstance(model.plots, openmc.Plots) - - -def test_keff_search(run_in_tmpdir): - """Test the Model.keff_search method""" - - # Create model of a sphere of U235 - mat = openmc.Material() - mat.set_density('g/cm3', 18.9) - mat.add_nuclide('U235', 1.0) - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sphere) - geometry = openmc.Geometry([cell]) - settings = openmc.Settings(particles=1000, inactive=10, batches=30) - model = openmc.Model(geometry=geometry, settings=settings) - - # Define function to modify sphere radius - def modify_radius(radius): - sphere.r = radius - - # Perform keff search - k_tol = 4e-3 - sigma_final = 2e-3 - result = model.keff_search( - func=modify_radius, - x0=6.0, - x1=9.0, - k_tol=k_tol, - sigma_final=sigma_final, - output=True, - ) - - final_keff = result.means[-1] + 1.0 # Add back target since means are (keff - target) - final_sigma = result.stdevs[-1] - - # Check for convergence and that tolerances are met - assert result.converged, "keff_search did not converge" - assert abs(final_keff - 1.0) <= k_tol, \ - f"Final keff {final_keff:.5f} not within k_tol {k_tol}" - assert final_sigma <= sigma_final, \ - f"Final uncertainty {final_sigma:.5f} exceeds sigma_final {sigma_final}" - - # Check type of result - assert isinstance(result, openmc.model.SearchResult) - - # Check that we have function evaluation history - assert len(result.parameters) >= 2 - assert len(result.means) == len(result.parameters) - assert len(result.stdevs) == len(result.parameters) - assert len(result.batches) == len(result.parameters) - - # Check that function_calls property works - assert result.function_calls == len(result.parameters) - - # Check that total_batches property works - assert result.total_batches == sum(result.batches) - assert result.total_batches > 0 - - -def test_id_map_to_rgb(): - """Test conversion of ID map to RGB image array.""" - # Create a simple model - mat = openmc.Material() - mat.set_density('g/cm3', 1.0) - mat.add_nuclide('Li7', 1.0) - - sphere = openmc.Sphere(r=5.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sphere) - geometry = openmc.Geometry([cell]) - settings = openmc.Settings( - batches=10, particles=100, run_mode='fixed source' - ) - model = openmc.Model(geometry, settings=settings) - - id_data = np.zeros((10, 10, 3), dtype=np.int32) - id_data[:, :, 0] = cell.id # Cell IDs - id_data[:, :, 2] = mat.id # Material IDs - - # Test color_by with default colors - for color_by in ['cell', 'material']: - rgb = id_map_to_rgb(id_data, color_by=color_by) - assert rgb.shape == (10, 10, 3) - assert rgb.dtype == float - assert np.all((rgb >= 0) & (rgb <= 1)) # RGB values in [0, 1] - - # Test with custom colors - colors = {cell.id: (255, 0, 0)} # Red - rgb_custom = id_map_to_rgb(id_data, color_by='cell', colors=colors) - assert np.allclose(rgb_custom, [1.0, 0.0, 0.0]) # All pixels should be red - - # Test with overlaps - id_data_overlap = id_data.copy() - id_data_overlap[5:, 5:, 0] = -3 # Mark some pixels as overlaps - rgb_overlap = id_map_to_rgb( - id_data_overlap, overlap_color=(0, 255, 0) - ) - # Check that overlap region is green - assert np.allclose(rgb_overlap[5:, 5:], [0.0, 1.0, 0.0]) - - -def test_convert_to_multigroup_preserves_material_names(run_in_tmpdir): - """convert_to_multigroup leaves the user's material names unchanged and keys - the MGXS library by a unique sanitised name + id, so distinct materials that - share a name do not collapse to a single cross section.""" - a = openmc.Material(name="Steel Plate #1") - a.add_element("Fe", 1.0) - a.set_density("g/cm3", 7.9) - b = openmc.Material(name="Steel Plate #1") # same name, distinct material - b.add_element("Fe", 1.0) - b.set_density("g/cm3", 7.9) - - s1 = openmc.Sphere(r=1.0) - s2 = openmc.Sphere(r=2.0, boundary_type="vacuum") - c1 = openmc.Cell(fill=a, region=-s1) - c2 = openmc.Cell(fill=b, region=+s1 & -s2) - model = openmc.Model(openmc.Geometry([c1, c2]), openmc.Materials([a, b])) - - # Pre-create the library so MGXS generation (and transport) is skipped. - Path("mgxs.h5").touch() - model.convert_to_multigroup(method="material_wise", mgxs_path="mgxs.h5") - - # User names are preserved, not sanitised or de-duplicated. - assert [m.name for m in model.materials] == ["Steel Plate #1", "Steel Plate #1"] - # Each material reads a unique, sanitised library entry (name + id). - macro = [m._macroscopic for m in model.materials] - assert macro == [f"Steel_Plate__1_{a.id}", f"Steel_Plate__1_{b.id}"] - assert len(set(macro)) == 2 diff --git a/tests/unit_tests/test_no_reduce.py b/tests/unit_tests/test_no_reduce.py deleted file mode 100644 index 00ddb5a95..000000000 --- a/tests/unit_tests/test_no_reduce.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Test the settings.no_reduce feature to ensure tallies are correctly -reduced across MPI processes.""" - -import openmc -import pytest - -from tests.testing_harness import config - - -@pytest.mark.parametrize('no_reduce', [True, False]) -def test_no_reduce(no_reduce, run_in_tmpdir): - """Test that tally results are correct with and without no_reduce.""" - - # Create simple sphere model with vacuum - model = openmc.Model() - sphere = openmc.Sphere(r=1.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere) - model.geometry = openmc.Geometry([cell]) - model.settings.run_mode = 'fixed source' - model.settings.batches = 10 - model.settings.particles = 100 - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) - model.settings.no_reduce = no_reduce - - # Tally: surface current on vacuum boundary - surf_filter = openmc.SurfaceFilter(sphere) - tally = openmc.Tally() - tally.filters = [surf_filter] - tally.scores = ['current'] - model.tallies = [tally] - - # Run OpenMC with proper MPI arguments if needed - kwargs = {'apply_tally_results': True, 'openmc_exec': config['exe']} - if config['mpi']: - kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] - model.run(**kwargs) - - # The tally should be ~1.0 (every particle crosses the surface once) - tally_mean = tally.mean.flatten()[0] - assert tally_mean == pytest.approx(1.0) diff --git a/tests/unit_tests/test_no_visible_boundary.py b/tests/unit_tests/test_no_visible_boundary.py deleted file mode 100644 index 7c53e4e3f..000000000 --- a/tests/unit_tests/test_no_visible_boundary.py +++ /dev/null @@ -1,30 +0,0 @@ -import openmc - - -def test_no_visible_boundary(run_in_tmpdir): - copper = openmc.Material() - copper.add_nuclide('Cu63', 1.0) - copper.set_density('g/cm3', 0.3) - air = openmc.Material() - air.add_nuclide('N14', 1.0) - air.set_density('g/cm3', 0.0012) - - # Create a simple model of a neutron source directly impinging on a thin - # disc of copper. Neutrons leaving the back of the disc see no surfaces in - # front of them. - disc = openmc.model.RightCircularCylinder((0., 0., 1.), 0.1, 1.2) - box = openmc.model.RectangularPrism(width=10, height=10, boundary_type='vacuum') - c1 = openmc.Cell(fill=copper, region=-disc) - c2 = openmc.Cell(fill=air, region=+disc & -box) - model = openmc.Model() - model.geometry = openmc.Geometry([c1, c2]) - model.settings.run_mode = 'fixed source' - model.settings.particles = 1000 - model.settings.batches = 5 - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point(), - angle=openmc.stats.Monodirectional((0., 0., 1.)) - ) - - # Run model to ensure it doesn't segfault - model.run() diff --git a/tests/unit_tests/test_nuclide_heating.py b/tests/unit_tests/test_nuclide_heating.py deleted file mode 100644 index e00d57b4f..000000000 --- a/tests/unit_tests/test_nuclide_heating.py +++ /dev/null @@ -1,39 +0,0 @@ -import openmc -from pytest import approx - - -def test_nuclide_heating(run_in_tmpdir): - mat = openmc.Material() - mat.add_nuclide("Li6", 0.5) - mat.add_nuclide("Li7", 0.5) - mat.set_density("g/cm3", 1.0) - - sphere = openmc.Sphere(r=20, boundary_type="reflective") - inside_sphere = openmc.Cell(fill=mat, region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([inside_sphere]) - - model.settings.particles = 1000 - model.settings.batches = 1 - model.settings.photon_transport = True - model.settings.electron_treatment = "ttb" - model.settings.cutoff = {"energy_photon": 1000} - model.settings.run_mode = "fixed source" - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(10.0e6), - particle="photon" - ) - - # Create two tallies, one with heating by nuclide and one with total heating - tally1 = openmc.Tally() - tally1.scores = ["heating"] - tally1.nuclides = mat.get_nuclides() - tally2 = openmc.Tally() - tally2.scores = ["heating"] - model.tallies = [tally1, tally2] - - # Run the model - model.run(apply_tally_results=True) - - # Make sure the heating results are consistent - assert tally1.mean.sum() == approx(tally2.mean.sum()) diff --git a/tests/unit_tests/test_particle_type.py b/tests/unit_tests/test_particle_type.py deleted file mode 100644 index 67e385ea6..000000000 --- a/tests/unit_tests/test_particle_type.py +++ /dev/null @@ -1,298 +0,0 @@ -"""Unit tests for ParticleType class.""" - -import pytest -from openmc import ParticleType - - -# Tests for creating ParticleType instances - -def test_create_from_int(): - """Test creation from PDG number.""" - p = ParticleType(2112) - assert p.pdg_number == 2112 - assert int(p) == 2112 - - -def test_create_from_string_name(): - """Test creation from particle name.""" - p = ParticleType('neutron') - assert p.pdg_number == 2112 - - p = ParticleType('photon') - assert p.pdg_number == 22 - - -def test_create_from_string_aliases(): - """Test creation from particle aliases.""" - assert ParticleType('n').pdg_number == 2112 - assert ParticleType('gamma').pdg_number == 22 - assert ParticleType('p').pdg_number == 2212 - assert ParticleType('proton').pdg_number == 2212 - assert ParticleType('d').pdg_number == 1000010020 - assert ParticleType('t').pdg_number == 1000010030 - - -def test_create_from_string_nuclide(): - """Test creation from GNDS nuclide name.""" - p = ParticleType('He4') - assert p.pdg_number == 1000020040 - - p = ParticleType('U235') - assert p.pdg_number == 1000922350 - - p = ParticleType('Am242_m1') - assert p.pdg_number == 1000952421 - - -def test_create_from_string_pdg_prefix(): - """Test creation with pdg: prefix.""" - p = ParticleType('pdg:2112') - assert p.pdg_number == 2112 - - p = ParticleType('PDG:22') - assert p.pdg_number == 22 - - -def test_create_from_particle_type(): - """Test creation from existing ParticleType.""" - p1 = ParticleType(2112) - p2 = ParticleType(p1) - assert p1 == p2 - assert p1 is not p2 # Different instances - - -def test_legacy_particle_indices(): - """Test backward compatibility with legacy indices 0-3.""" - assert ParticleType(0) == ParticleType.NEUTRON - assert ParticleType(1) == ParticleType.PHOTON - assert ParticleType(2) == ParticleType.ELECTRON - assert ParticleType(3) == ParticleType.POSITRON - - -def test_create_invalid_type(): - """Test creation with invalid type raises TypeError.""" - with pytest.raises(TypeError): - ParticleType([2112]) - - with pytest.raises(TypeError): - ParticleType({'pdg': 2112}) - - -def test_create_invalid_string(): - """Test creation with invalid string raises ValueError.""" - with pytest.raises(ValueError): - ParticleType('') - - with pytest.raises(ValueError): - ParticleType('pdg:invalid') - - -def test_create_case_insensitive(): - """Test that string parsing is case insensitive for aliases.""" - assert ParticleType('NEUTRON').pdg_number == 2112 - assert ParticleType('Neutron').pdg_number == 2112 - assert ParticleType('PHOTON').pdg_number == 22 - - -# Tests for equality and comparison - -def test_equality_same_pdg(): - """Test that instances with same PDG are equal.""" - p1 = ParticleType(2112) - p2 = ParticleType(2112) - assert p1 == p2 - - -def test_equality_int(): - """Test equality comparison with int.""" - p = ParticleType(2112) - assert p == 2112 - assert 2112 == p - - -def test_equality_string(): - """Test equality comparison with string.""" - p = ParticleType(2112) - assert p == 'neutron' - assert p == 'pdg:2112' - assert p == 'n' - - -def test_inequality(): - """Test inequality comparisons.""" - p1 = ParticleType(2112) - p2 = ParticleType(22) - assert p1 != p2 - assert p1 != 22 - assert p1 != 'photon' - - -def test_equality_with_constants(): - """Test equality with class constants.""" - p = ParticleType(2112) - assert p == ParticleType.NEUTRON - assert ParticleType.NEUTRON == p - - -def test_equality_invalid_string(): - """Test equality with invalid string returns False.""" - p = ParticleType(2112) - assert not (p == 'invalid_particle') - assert p != 'invalid_particle' - - -# Tests for hashing behavior - -def test_hash_consistency(): - """Test that equal instances hash to the same value.""" - p1 = ParticleType(2112) - p2 = ParticleType(2112) - assert hash(p1) == hash(p2) - - -def test_set_deduplication(): - """Test that equal instances deduplicate in sets.""" - p1 = ParticleType(2112) - p2 = ParticleType(2112) - s = {p1, p2} - assert len(s) == 1 - - -def test_dict_key(): - """Test use as dictionary key.""" - p1 = ParticleType(2112) - p2 = ParticleType(2112) - d = {p1: 'neutron'} - assert d[p2] == 'neutron' - - -def test_hash_different_particles(): - """Test that different particles have different hashes (usually).""" - p1 = ParticleType(2112) - p2 = ParticleType(22) - # Different PDG numbers should (almost always) have different hashes - assert hash(p1) != hash(p2) - - -# Tests for properties and computed attributes - -def test_pdg_number_property(): - """Test pdg_number property.""" - p = ParticleType(2112) - assert p.pdg_number == 2112 - assert isinstance(p.pdg_number, int) - - -def test_int_conversion(): - """Test __int__ conversion.""" - p = ParticleType(1000020040) - assert int(p) == 1000020040 - - -def test_zam_elementary(): - """Test zam property for elementary particles.""" - assert ParticleType.NEUTRON.zam is None - assert ParticleType.PHOTON.zam is None - assert ParticleType.ELECTRON.zam is None - assert ParticleType.POSITRON.zam is None - - -def test_zam_nucleus(): - """Test zam property for nuclear particles.""" - he4 = ParticleType('He4') - assert he4.zam == (2, 4, 0) - - u235 = ParticleType('U235') - Z, A, m = u235.zam - assert Z == 92 - assert A == 235 - assert m == 0 - - -def test_zam_metastable(): - """Test zam property for metastable nuclei.""" - # Am242m has m=1 - am242m = ParticleType('Am242_m1') - Z, A, m = am242m.zam - assert Z == 95 - assert A == 242 - assert m == 1 - - -def test_is_nucleus_false(): - """Test is_nucleus for elementary particles.""" - assert not ParticleType.NEUTRON.is_nucleus - assert not ParticleType.PHOTON.is_nucleus - assert not ParticleType.ELECTRON.is_nucleus - assert not ParticleType.POSITRON.is_nucleus - - -def test_is_nucleus_true(): - """Test is_nucleus for nuclear particles.""" - assert ParticleType.ALPHA.is_nucleus - assert ParticleType('He4').is_nucleus - assert ParticleType('U235').is_nucleus - assert ParticleType.DEUTERON.is_nucleus - assert ParticleType.TRITON.is_nucleus - - -# Tests for __str__ and __repr__ - -def test_str_elementary(): - """Test string representation of elementary particles.""" - assert str(ParticleType.NEUTRON) == 'neutron' - assert str(ParticleType.PHOTON) == 'photon' - assert str(ParticleType.ELECTRON) == 'electron' - assert str(ParticleType.POSITRON) == 'positron' - assert str(ParticleType.PROTON) == 'H1' - - -def test_str_nucleus(): - """Test string representation of nuclei.""" - assert str(ParticleType.ALPHA) == 'He4' - assert str(ParticleType('U235')) == 'U235' - assert str(ParticleType.DEUTERON) == 'H2' - assert str(ParticleType.TRITON) == 'H3' - - -def test_str_arbitrary_pdg(): - """Test string representation of arbitrary PDG number.""" - # PDG number that doesn't match any known particle - p = ParticleType(12345) - assert str(p) == 'pdg:12345' - - -def test_repr(): - """Test repr includes PDG number.""" - p = ParticleType.NEUTRON - repr_str = repr(p) - assert 'ParticleType' in repr_str - assert 'PDG=2112' in repr_str - assert 'neutron' in repr_str - - -def test_repr_nucleus(): - """Test repr for nuclear particles.""" - p = ParticleType.ALPHA - repr_str = repr(p) - assert 'ParticleType' in repr_str - assert 'PDG=1000020040' in repr_str - assert 'He4' in repr_str - - -def test_create_from_numpy_int(): - """Test creation from numpy integer types.""" - import numpy as np - p = ParticleType(np.int32(2112)) - assert p.pdg_number == 2112 - - p = ParticleType(np.int64(22)) - assert p.pdg_number == 22 - - -def test_equality_numpy_int(): - """Test equality comparison with numpy integer types.""" - import numpy as np - p = ParticleType(2112) - assert p == np.int32(2112) - assert p == np.int64(2112) diff --git a/tests/unit_tests/test_pathlike_simple.py b/tests/unit_tests/test_pathlike_simple.py deleted file mode 100644 index e0116bf01..000000000 --- a/tests/unit_tests/test_pathlike_simple.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Simple test for PathLike filename support""" - -from pathlib import Path - -import pytest -import openmc -from openmc.checkvalue import check_type, PathLike - - -def test_pathlike_type_checking(): - """Test that PathLike type checking works correctly""" - - # Test with string (should work) - check_type('filename', 'test.txt', PathLike) - - # Test with Path object (should work) - path_obj = Path('test.txt') - check_type('filename', path_obj, PathLike) - - # Test with Path object containing subdirectories (should work) - path_with_subdir = Path('subdir') / 'test.txt' - check_type('filename', path_with_subdir, PathLike) - - # Test with invalid type (should raise TypeError) - with pytest.raises(TypeError): - check_type('filename', 123, PathLike) - - -def test_plot_filename_pathlike(): - """Test that plot filename accepts Path objects""" - - plot = openmc.Plot() - - # Test with string (should still work) - plot.filename = "test_plot" - assert plot.filename == "test_plot" - - # Test with Path object - path_obj = Path("test_plot_path") - plot.filename = path_obj - assert plot.filename == path_obj - - # Test with Path object containing subdirectories - path_with_subdir = Path("subdir") / "test_plot" - plot.filename = path_with_subdir - assert plot.filename == path_with_subdir diff --git a/tests/unit_tests/test_periodic_bc.py b/tests/unit_tests/test_periodic_bc.py deleted file mode 100644 index 4cc126abc..000000000 --- a/tests/unit_tests/test_periodic_bc.py +++ /dev/null @@ -1,47 +0,0 @@ -from math import cos, sin, radians -import random - -import openmc -import pytest - - -@pytest.mark.parametrize("angle", [30., 45., 60., 90., 120.]) -def test_rotational_periodic_bc(angle): - # Pick random starting angle - start = random.uniform(0., 360.) - degrees = angle - ang1 = radians(start) - ang2 = radians(start + degrees) - - # Define three points on each plane and then randomly shuffle them - p1_points = [(0., 0., 0.), (cos(ang1), sin(ang1), 0.), (0., 0., 1.)] - p2_points = [(0., 0., 0.), (cos(ang2), sin(ang2), 0.), (0., 0., 1.)] - random.shuffle(p1_points) - random.shuffle(p2_points) - - # Create periodic planes and a cylinder - p1 = openmc.Plane.from_points(*p1_points, boundary_type='periodic') - p2 = openmc.Plane.from_points(*p2_points, boundary_type='periodic') - p1.periodic_surface = p2 - zcyl = openmc.ZCylinder(r=5., boundary_type='vacuum') - - # Figure out which side of planes to use based on a point in the middle - ang_mid = radians(start + degrees/2.) - mid_point = (cos(ang_mid), sin(ang_mid), 0.) - r1 = -p1 if mid_point in -p1 else +p1 - r2 = -p2 if mid_point in -p2 else +p2 - - # Create one cell bounded by the two planes and the cylinder - mat = openmc.Material(density=1.0, density_units='g/cm3', components={'U235': 1.0}) - cell = openmc.Cell(fill=mat, region=r1 & r2 & -zcyl) - - # Make the model complete - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(mid_point)) - model.settings.particles = 1000 - model.settings.batches = 10 - model.settings.inactive = 5 - - # Run the model - model.run() diff --git a/tests/unit_tests/test_photon_heating.py b/tests/unit_tests/test_photon_heating.py deleted file mode 100644 index 05473f5c6..000000000 --- a/tests/unit_tests/test_photon_heating.py +++ /dev/null @@ -1,30 +0,0 @@ -import openmc - - -def test_negative_positron_heating(): - m = openmc.Material() - m.add_element('Li', 1.0) - m.set_density('g/cm3', 10.0) - - surf = openmc.Sphere(r=100.0, boundary_type='reflective') - cell = openmc.Cell(fill=m, region=-surf) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point(), - energy=openmc.stats.Discrete([5.0e6], [1.0]), - particle='photon', - ) - model.settings.particles = 7 - model.settings.batches = 1 - model.settings.electron_treatment = 'led' - model.settings.seed = 513836 - - tally = openmc.Tally() - tally.filters = [openmc.ParticleFilter(['photon', 'electron', 'positron'])] - tally.scores = ['heating'] - model.tallies = openmc.Tallies([tally]) - model.run(apply_tally_results=True) - - assert (tally.mean >= 0.0).all(), "Negative heating detected" diff --git a/tests/unit_tests/test_pin.py b/tests/unit_tests/test_pin.py index 53665b1a6..5496a3b73 100644 --- a/tests/unit_tests/test_pin.py +++ b/tests/unit_tests/test_pin.py @@ -46,6 +46,11 @@ def test_failure(pin_mats, good_radii): with pytest.raises(ValueError, match="length"): pin(good_surfaces[:len(pin_mats) - 2], pin_mats) + # Non-positive radii + rad = [openmc.ZCylinder(r=-0.1)] + good_surfaces[1:] + with pytest.raises(ValueError, match="index 0"): + pin(rad, pin_mats) + # Non-increasing radii surfs = tuple(reversed(good_surfaces)) with pytest.raises(ValueError, match="index 1"): diff --git a/tests/unit_tests/test_plots.py b/tests/unit_tests/test_plots.py index 98a93e44b..2db396cd5 100644 --- a/tests/unit_tests/test_plots.py +++ b/tests/unit_tests/test_plots.py @@ -1,19 +1,16 @@ -from pathlib import Path - import openmc import openmc.examples import pytest -from openmc.plots import _SVG_COLORS - @pytest.fixture(scope='module') def myplot(): - plot = openmc.SlicePlot(name='myplot') + plot = openmc.Plot(name='myplot') plot.width = (100., 100.) plot.origin = (2., 3., -10.) plot.pixels = (500, 500) - plot.filename = './not-a-dir/myplot' + plot.filename = 'myplot' + plot.type = 'slice' plot.basis = 'yz' plot.background = 'black' plot.background = (0, 0, 0) @@ -41,109 +38,15 @@ def myplot(): return plot -@pytest.fixture(scope='module') -def myprojectionplot(): - plot = openmc.WireframeRayTracePlot(name='myprojectionplot') - plot.look_at = (0.0, 0.0, 0.0) - plot.camera_position = (4.0, 3.0, 0.0) - plot.pixels = (500, 500) - plot.filename = 'myprojectionplot' - plot.background = (0, 0, 0) - plot.background = 'black' - - plot.color_by = 'material' - m1, m2 = openmc.Material(), openmc.Material() - plot.colors = {m1: (0, 255, 0), m2: (0, 0, 255)} - plot.colors = {m1: 'green', m2: 'blue'} - plot.xs = {m1: 1.0, m2: 0.01} - - plot.mask_components = [openmc.Material()] - plot.mask_background = (255, 255, 255) - plot.mask_background = 'white' - - plot.overlap_color = (255, 211, 0) - plot.overlap_color = 'yellow' - - plot.wireframe_thickness = 2 - - plot.level = 1 - return plot - - -def test_voxel_plot(run_in_tmpdir): - # attempt to preload VTK and skip this test if unavailable - vtk = pytest.importorskip('vtk') - surf1 = openmc.Sphere(r=500, boundary_type='vacuum') - cell1 = openmc.Cell(region=-surf1) - geometry = openmc.Geometry([cell1]) - geometry.export_to_xml() - materials = openmc.Materials() - materials.export_to_xml() - vox_plot = openmc.VoxelPlot() - vox_plot.id = 12 - vox_plot.width = (1500., 1500., 1500.) - vox_plot.pixels = (200, 200, 200) - vox_plot.color_by = 'cell' - vox_plot.to_vtk('test_voxel_plot.vti') - - assert Path('plot_12.h5').is_file() - assert Path('test_voxel_plot.vti').is_file() - - vox_plot.filename = 'h5_voxel_plot' - vox_plot.to_vtk(Path('another_test_voxel_plot.vti')) - - assert Path('h5_voxel_plot.h5').is_file() - assert Path('another_test_voxel_plot.vti').is_file() - - # SlicePlot should not have to_vtk method - slice_plot = openmc.SlicePlot() - with pytest.raises(AttributeError): - slice_plot.to_vtk('shimmy.vti') - - def test_attributes(myplot): assert myplot.name == 'myplot' -def test_attributes_proj(myprojectionplot): - assert myprojectionplot.name == 'myprojectionplot' - - def test_repr(myplot): r = repr(myplot) assert isinstance(r, str) -def test_repr_proj(myprojectionplot): - r = repr(myprojectionplot) - assert isinstance(r, str) - - -def test_projection_plot_roundtrip(myprojectionplot): - - elem = myprojectionplot.to_xml_element() - - xml_plot = openmc.WireframeRayTracePlot.from_xml_element(elem) - - svg_colors = _SVG_COLORS - - assert xml_plot.name == myprojectionplot.name - assert xml_plot.look_at == myprojectionplot.look_at - assert xml_plot.camera_position == myprojectionplot.camera_position - assert xml_plot.pixels == myprojectionplot.pixels - assert xml_plot.filename == myprojectionplot.filename - assert xml_plot.background == svg_colors[myprojectionplot.background] - assert xml_plot.color_by == myprojectionplot.color_by - expected_colors = {m.id: svg_colors[c] for m, c in myprojectionplot.colors.items()} - assert xml_plot.colors == expected_colors - # TODO: needs geometry information - # assert xml_plot.mask_components == myprojectionplot.mask_components - assert xml_plot.mask_background == svg_colors[myprojectionplot.mask_background] - # assert xml_plot.overlap_color == svg_colors[myprojectionplot.overlap_color] - assert xml_plot.wireframe_thickness == myprojectionplot.wireframe_thickness - assert xml_plot.level == myprojectionplot.level - - def test_from_geometry(): width = 25. s = openmc.Sphere(r=width/2, boundary_type='vacuum') @@ -152,14 +55,14 @@ def test_from_geometry(): geom = openmc.Geometry(univ) for basis in ('xy', 'yz', 'xz'): - plot = openmc.SlicePlot.from_geometry(geom, basis) + plot = openmc.Plot.from_geometry(geom, basis) assert plot.origin == pytest.approx((0., 0., 0.)) assert plot.width == pytest.approx((width, width)) assert plot.basis == basis def test_highlight_domains(): - plot = openmc.SlicePlot() + plot = openmc.Plot() plot.color_by = 'material' plots = openmc.Plots([plot]) @@ -178,127 +81,34 @@ def test_xml_element(myplot): assert elem.find('pixels') is not None assert elem.find('background').text == '0 0 0' - newplot = openmc.SlicePlot.from_xml_element(elem) - attributes = ('id', 'color_by', 'filename', 'basis', 'level', + newplot = openmc.Plot.from_xml_element(elem) + attributes = ('id', 'color_by', 'filename', 'type', 'basis', 'level', 'meshlines', 'show_overlaps', 'origin', 'width', 'pixels', 'background', 'mask_background') for attr in attributes: assert getattr(newplot, attr) == getattr(myplot, attr), attr -def test_to_xml_element_proj(myprojectionplot): - elem = myprojectionplot.to_xml_element() - assert 'id' in elem.attrib - assert 'color_by' in elem.attrib - assert 'type' in elem.attrib - assert elem.find('camera_position') is not None - assert elem.find('wireframe_thickness') is not None - assert elem.find('look_at') is not None - assert elem.find('pixels') is not None - assert elem.find('background').text == '0 0 0' - - def test_plots(run_in_tmpdir): - p1 = openmc.SlicePlot(name='plot1') + p1 = openmc.Plot(name='plot1') p1.origin = (5., 5., 5.) p1.colors = {10: (255, 100, 0)} p1.mask_components = [2, 4, 6] - p2 = openmc.SlicePlot(name='plot2') + p2 = openmc.Plot(name='plot2') p2.origin = (-3., -3., -3.) plots = openmc.Plots([p1, p2]) assert len(plots) == 2 - p3 = openmc.WireframeRayTracePlot(name='plot3') - plots = openmc.Plots([p1, p2, p3]) + p3 = openmc.Plot(name='plot3') + plots.append(p3) assert len(plots) == 3 - p4 = openmc.VoxelPlot(name='plot4') - plots.append(p4) - assert len(plots) == 4 - plots.export_to_xml() # from_xml new_plots = openmc.Plots.from_xml() - assert len(new_plots) - assert new_plots[0].origin == p1.origin - assert new_plots[0].colors == p1.colors - assert new_plots[0].mask_components == p1.mask_components - assert new_plots[1].origin == p2.origin - - -def test_voxel_plot_roundtrip(): - # Define a voxel plot and create XML element - plot = openmc.VoxelPlot(name='my voxel plot') - plot.filename = 'voxel1' - plot.pixels = (50, 50, 50) - plot.origin = (0., 0., 0.) - plot.width = (75., 75., 75.) - plot.color_by = 'material' - elem = plot.to_xml_element() - - # Read back from XML and make sure it hasn't changed - new_plot = plot.from_xml_element(elem) - assert new_plot.name == plot.name - assert new_plot.filename == plot.filename - assert new_plot.pixels == plot.pixels - assert new_plot.origin == plot.origin - assert new_plot.width == plot.width - assert new_plot.color_by == plot.color_by - - -def test_phong_plot_roundtrip(): - plot = openmc.SolidRayTracePlot(name='my phong plot') - plot.id = 2300 - plot.filename = 'phong1' - plot.pixels = (50, 50) - plot.look_at = (11., 12., 13.) - plot.camera_position = (22., 23., 24.) - plot.diffuse_fraction = 0.5 - plot.horizontal_field_of_view = 90.0 - plot.color_by = 'material' - plot.light_position = (8., 9., 10.) - plot.opaque_domains = [6, 7, 8] - - elem = plot.to_xml_element() - - repr(plot) - - new_plot = openmc.SolidRayTracePlot.from_xml_element(elem) - - assert new_plot.name == plot.name - assert new_plot.id == plot.id - assert new_plot.filename == plot.filename - assert new_plot.pixels == plot.pixels - assert new_plot.look_at == plot.look_at - assert new_plot.camera_position == plot.camera_position - assert new_plot.diffuse_fraction == plot.diffuse_fraction - assert new_plot.horizontal_field_of_view == plot.horizontal_field_of_view - assert new_plot.color_by == plot.color_by - assert new_plot.light_position == plot.light_position - assert new_plot.opaque_domains == plot.opaque_domains - - # ensure the new object is valid to re-write to XML - new_elem = new_plot.to_xml_element() - - -def test_plot_directory(run_in_tmpdir): - pwr_pin = openmc.examples.pwr_pin_cell() - - # create a standard slice plot, expected to work - plot = openmc.SlicePlot() - plot.filename = 'plot_1' - plot.pixels = (10, 10) - plot.color_by = 'material' - plot.width = (100., 100.) - pwr_pin.plots = [plot] - pwr_pin.plot_geometry() - - # use current directory, also expected to work - plot.filename = './plot_1' - pwr_pin.plot_geometry() - - # use a non-existent directory, should raise an error - plot.filename = './not-a-dir/plot_1' - with pytest.raises(RuntimeError, match='does not exist'): - pwr_pin.plot_geometry() + assert len(plots) + assert plots[0].origin == p1.origin + assert plots[0].colors == p1.colors + assert plots[0].mask_components == p1.mask_components + assert plots[1].origin == p2.origin diff --git a/tests/unit_tests/test_plotter.py b/tests/unit_tests/test_plotter.py deleted file mode 100644 index 0220cec3e..000000000 --- a/tests/unit_tests/test_plotter.py +++ /dev/null @@ -1,183 +0,0 @@ -import numpy as np -import openmc -import pytest - - -@pytest.fixture(scope='module') -def test_mat(): - mat_1 = openmc.Material() - mat_1.add_element("H", 4.0, "ao") - mat_1.add_element("O", 4.0, "ao") - mat_1.add_element("C", 4.0, "ao") - return mat_1 - - -def test_calculate_cexs_elem_mat_sab(test_mat): - """Checks that sab cross sections are included in the - _calculate_cexs_elem_mat method and have the correct shape""" - - test_mat.add_s_alpha_beta("c_C6H6") - test_mat.set_density("g/cm3", 0.865) - - energy_grid, data = openmc.plotter._calculate_cexs_elem_mat( - test_mat, - ["inelastic"], - sab_name="c_C6H6", - ) - - assert isinstance(energy_grid, np.ndarray) - assert isinstance(data, np.ndarray) - assert len(energy_grid) > 1 - assert len(data) == 1 - assert len(data[0]) == len(energy_grid) - - -@pytest.mark.parametrize("this", ["Li", "Li6"]) -def test_calculate_cexs_with_nuclide_and_element(this): - # single type (reaction) - energy_grid, data = openmc.plotter.calculate_cexs( - this=this, types=[205] - ) - - assert isinstance(energy_grid, np.ndarray) - assert isinstance(data, np.ndarray) - assert len(energy_grid) > 1 - assert len(data) == 1 - assert len(data[0]) == len(energy_grid) - - # two types (reactions) - energy_grid, data = openmc.plotter.calculate_cexs( - this=this, types=[2, "elastic"] - ) - - assert isinstance(energy_grid, np.ndarray) - assert isinstance(data, np.ndarray) - assert len(energy_grid) > 1 - assert len(data) == 2 - assert len(data[0]) == len(energy_grid) - assert len(data[0]) == len(energy_grid) - # reactions are both the same MT number 2 is elastic - assert np.array_equal(data[0], data[1]) - - -def test_calculate_cexs_with_materials(test_mat): - energy_grid, data = openmc.plotter.calculate_cexs( - this=test_mat, types=[205] - ) - - assert isinstance(energy_grid, np.ndarray) - assert isinstance(data, np.ndarray) - assert len(energy_grid) > 1 - assert len(data) == 1 - assert len(data[0]) == len(energy_grid) - - -@pytest.mark.parametrize("this", ["Be", "Be9"]) -def test_plot_xs(this): - from matplotlib.figure import Figure - assert isinstance(openmc.plot_xs({this: ['total', 'elastic', 16, '(n,2n)']}), Figure) - - -def test_plot_xs_mat(test_mat): - from matplotlib.figure import Figure - assert isinstance(openmc.plot_xs({test_mat: ['total']}), Figure) - - -@pytest.mark.parametrize("units", ["eV", "keV", "MeV"]) -def test_plot_xs_energy_axis(units): - plot = openmc.plot_xs({'Be9': ['(n,2n)']}, energy_axis_units=units) - axis_text = plot.get_axes()[0].get_xaxis().get_label().get_text() - assert axis_text == f'Energy [{units}]' - - -def test_plot_axes_labels(): - # just nuclides - axis_label = openmc.plotter._get_yaxis_label( - reactions={ - 'Li6': [205], - 'Li7': [205], - }, divisor_types=False - ) - assert axis_label == 'Microscopic Cross Section [b]' - - # just elements - axis_label = openmc.plotter._get_yaxis_label( - reactions={ - 'Li': [205], - 'Be': [16], - }, divisor_types=False - ) - assert axis_label == 'Microscopic Cross Section [b]' - - # mixed nuclide and element - axis_label = openmc.plotter._get_yaxis_label( - reactions={ - 'Li': [205], - 'Li7': [205], - }, divisor_types=False - ) - assert axis_label == 'Microscopic Cross Section [b]' - - axis_label = openmc.plotter._get_yaxis_label( - reactions={ - "Li": ["heating", "heating-local"], - "Li7": ["heating"], - "Be": ["damage-energy"], - }, - divisor_types=False, - ) - assert axis_label == "Heating Cross Section [eV-barn]" - - with pytest.raises(TypeError): - axis_label = openmc.plotter.plot_xs( - reactions={"Li": ["heating", "heating-local"], "Be9": ["(n,2n)"]} - ) - - # just materials - mat1 = openmc.Material() - mat1.add_nuclide('Fe56', 1) - mat1.set_density('g/cm3', 1) - mat2 = openmc.Material() - mat2.add_element('Fe', 1) - mat2.add_nuclide('Fe55', 1) - mat2.set_density('g/cm3', 1) - axis_label = openmc.plotter._get_yaxis_label( - reactions={ - mat1: [205], - mat2: [16], - }, divisor_types=False - ) - assert axis_label == 'Macroscopic Cross Section [1/cm]' - - # mixed materials and nuclides - with pytest.raises(TypeError): - openmc.plotter._get_yaxis_label( - reactions={'Li6': [205], mat2: [16]}, - divisor_types=False - ) - - # mixed materials and elements - with pytest.raises(TypeError): - openmc.plotter._get_yaxis_label( - reactions={'Li': [205], mat2: [16]}, - divisor_types=False - ) - - -def test_get_title(): - title = openmc.plotter._get_title(reactions={'Li': [205]}) - assert title == 'Cross Section Plot For Li' - title = openmc.plotter._get_title(reactions={'Li6': [205]}) - assert title == 'Cross Section Plot For Li6' - title = openmc.plotter._get_title(reactions={ - 'Li6': [205], - 'Li7': [205] - }) - assert title == 'Cross Section Plot' - - mat1 = openmc.Material() - mat1.add_nuclide('Fe56', 1) - mat1.set_density('g/cm3', 1) - mat1.name = 'my_mat' - title = openmc.plotter._get_title(reactions={mat1: [205]}) - assert title == 'Cross Section Plot For my_mat' diff --git a/tests/unit_tests/test_pulse_height.py b/tests/unit_tests/test_pulse_height.py deleted file mode 100644 index 1f27cc6f2..000000000 --- a/tests/unit_tests/test_pulse_height.py +++ /dev/null @@ -1,59 +0,0 @@ -import numpy as np -import pytest -import openmc - - -@pytest.fixture -def model(): - openmc.reset_auto_ids() - model = openmc.Model() - - # Define materials - NaI = openmc.Material() - NaI.set_density('g/cm3', 3.7) - NaI.add_element('Na', 1.0) - NaI.add_element('I', 1.0) - - # Define geometry: two spheres in each other - s1 = openmc.Sphere(r=1) - s2 = openmc.Sphere(r=2, boundary_type='vacuum') - inner_sphere = openmc.Cell(name='inner sphere', fill=NaI, region=-s1) - outer_sphere = openmc.Cell(name='outer sphere', fill=NaI, region=+s1 & -s2) - model.geometry = openmc.Geometry([inner_sphere, outer_sphere]) - - # Define settings - model.settings.run_mode = 'fixed source' - model.settings.batches = 1 - model.settings.particles = 10000 - model.settings.photon_transport = True - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(1e6), - particle='photon' - ) - - # Define tallies - energy_filter = openmc.EnergyFilter([1e3, 1e7]) - - tally1 = openmc.Tally() - tally1.scores = ['pulse-height'] - cell_filter1 = openmc.CellFilter([inner_sphere, outer_sphere]) - tally1.filters = [cell_filter1, energy_filter] - - tally2 = openmc.Tally() - tally2.scores = ['pulse-height'] - cell_filter2 = openmc.CellFilter([outer_sphere, inner_sphere]) - tally2.filters = [cell_filter2, energy_filter] - - model.tallies = [tally1, tally2] - return model - - -def test_pulse_height(model, run_in_tmpdir): - sp_path = model.run() - sp = openmc.StatePoint(sp_path) - t1 = sp.tallies[1].mean.squeeze() - t2 = sp.tallies[2].mean.squeeze() - - np.testing.assert_array_equal(t1, t2[::-1]) - - diff --git a/tests/unit_tests/test_r2s.py b/tests/unit_tests/test_r2s.py deleted file mode 100644 index 5e617919d..000000000 --- a/tests/unit_tests/test_r2s.py +++ /dev/null @@ -1,325 +0,0 @@ -from pathlib import Path - -import pytest -import openmc -from openmc.deplete import Chain, R2SManager - - -@pytest.fixture -def simple_model_and_mesh(): - # Define two materials: water and Ni - h2o = openmc.Material() - h2o.add_nuclide("H1", 2.0) - h2o.add_nuclide("O16", 1.0) - h2o.set_density("g/cm3", 1.0) - nickel = openmc.Material() - nickel.add_element("Ni", 1.0) - nickel.set_density("g/cm3", 4.0) - - # Geometry: two half-spaces split by x=0 plane - left = openmc.XPlane(0.0) - x_min = openmc.XPlane(-10.0, boundary_type='vacuum') - x_max = openmc.XPlane(10.0, boundary_type='vacuum') - y_min = openmc.YPlane(-10.0, boundary_type='vacuum') - y_max = openmc.YPlane(10.0, boundary_type='vacuum') - z_min = openmc.ZPlane(-10.0, boundary_type='vacuum') - z_max = openmc.ZPlane(10.0, boundary_type='vacuum') - - c1 = openmc.Cell(fill=h2o, region=+x_min & -left & +y_min & -y_max & +z_min & -z_max) - c2 = openmc.Cell(fill=nickel, region=+left & -x_max & +y_min & -y_max & +z_min & -z_max) - c1.volume = 4000.0 - c2.volume = 4000.0 - geometry = openmc.Geometry([c1, c2]) - - # Simple settings with a point source - settings = openmc.Settings() - settings.batches = 2 - settings.particles = 250 - settings.run_mode = 'fixed source' - settings.source = openmc.IndependentSource() - model = openmc.Model(geometry, settings=settings) - - mesh = openmc.RegularMesh() - mesh.lower_left = (-10.0, -10.0, -10.0) - mesh.upper_right = (10.0, 10.0, 10.0) - mesh.dimension = (1, 1, 1) - return model, (c1, c2), mesh - - -@pytest.fixture -def source_stage_manager(simple_model_and_mesh): - model, (c1, c2), _ = simple_model_and_mesh - r2s = R2SManager(model, [c1, c2]) - r2s.results['depletion_results'] = [None, None] - r2s.results['activation_materials'] = [c1.fill, c2.fill] - bounding_boxes = {c1.id: c1.bounding_box, c2.id: c2.bounding_box} - return r2s, bounding_boxes - - -def test_r2s_mesh_expected_output(simple_model_and_mesh, tmp_path): - model, (c1, c2), mesh = simple_model_and_mesh - - # Use mesh-based domains - r2s = R2SManager(model, mesh) - - # Use custom reduced chain file for Ni - chain = Chain.from_xml(Path(__file__).parents[1] / "chain_ni.xml") - - # Run R2S calculation - outdir = r2s.run( - timesteps=[(1.0, 'd')], - source_rates=[1.0], - output_dir=tmp_path, - chain_file=chain, - micro_kwargs={'nuclides': ['Ni58'], 'reactions': ['(n,p)']}, - ) - - # Check directories and files exist - nt = Path(outdir) / 'neutron_transport' - assert (nt / 'fluxes.npy').exists() - assert (nt / 'micros.h5').exists() - assert (nt / 'mesh_material_volumes_0.npz').exists() - act = Path(outdir) / 'activation' - assert (act / 'depletion_results.h5').exists() - pt = Path(outdir) / 'photon_transport' - assert (pt / 'tally_ids.json').exists() - assert not (pt / 'time_0').exists() - assert (pt / 'time_1' / 'statepoint.2.h5').exists() - - # Basic results structure checks - assert len(r2s.results['fluxes']) == 2 - assert len(r2s.results['micros']) == 2 - assert len(r2s.results['mesh_material_volumes']) == 1 - assert len(r2s.results['mesh_material_volumes'][0]) == 2 - assert len(r2s.results['activation_materials']) == 2 - assert len(r2s.results['depletion_results']) == 2 - assert list(r2s.results['photon_sources']) == [1] - assert r2s.results['photon_sources'][1] - - # Check activation materials - amats = r2s.results['activation_materials'] - assert all(m.depletable for m in amats) - # Volumes preserved - assert {m.volume for m in amats} == {c1.volume, c2.volume} - - # Check loading results - r2s_loaded = R2SManager(model, mesh) - r2s_loaded.load_results(outdir) - assert len(r2s_loaded.results['fluxes']) == 2 - assert len(r2s_loaded.results['micros']) == 2 - assert len(r2s_loaded.results['mesh_material_volumes']) == 1 - assert len(r2s_loaded.results['mesh_material_volumes'][0]) == 2 - assert len(r2s_loaded.results['activation_materials']) == 2 - assert len(r2s_loaded.results['depletion_results']) == 2 - - -def test_r2s_multi_mesh(simple_model_and_mesh, tmp_path): - model, _, _ = simple_model_and_mesh - - # Two 1x1x1 meshes that together cover the full domain, split along y. - # Each mesh element spans the full x range [-10, 10], crossing the x=0 - # material boundary, so both meshes contain both materials within their - # single element. - mesh1 = openmc.RegularMesh() - mesh1.lower_left = (-10.0, -10.0, -10.0) - mesh1.upper_right = (10.0, 0.0, 10.0) - mesh1.dimension = (1, 1, 1) - mesh2 = openmc.RegularMesh() - mesh2.lower_left = (-10.0, 0.0, -10.0) - mesh2.upper_right = (10.0, 10.0, 10.0) - mesh2.dimension = (1, 1, 1) - - r2s = R2SManager(model, [mesh1, mesh2]) - chain = Chain.from_xml(Path(__file__).parents[1] / "chain_ni.xml") - - outdir = r2s.run( - timesteps=[(1.0, 'd')], - source_rates=[1.0], - photon_time_indices=[1], - output_dir=tmp_path, - chain_file=chain, - micro_kwargs={'nuclides': ['Ni58'], 'reactions': ['(n,p)']}, - ) - - # Check that per-mesh MMV files were written - nt = Path(outdir) / 'neutron_transport' - assert (nt / 'fluxes.npy').exists() - assert (nt / 'micros.h5').exists() - assert (nt / 'mesh_material_volumes_0.npz').exists() - assert (nt / 'mesh_material_volumes_1.npz').exists() - act = Path(outdir) / 'activation' - assert (act / 'depletion_results.h5').exists() - pt = Path(outdir) / 'photon_transport' - assert (pt / 'tally_ids.json').exists() - assert (pt / 'time_1' / 'statepoint.2.h5').exists() - - # Two meshes, each with 1 element containing both materials → - # 2 element-material combinations per mesh, 4 total - assert len(r2s.results['mesh_material_volumes']) == 2 - assert len(r2s.results['mesh_material_volumes'][0]) == 2 - assert len(r2s.results['mesh_material_volumes'][1]) == 2 - assert len(r2s.results['fluxes']) == 4 - assert len(r2s.results['micros']) == 4 - assert len(r2s.results['activation_materials']) == 4 - assert len(r2s.results['depletion_results']) == 2 - - # Activation material names encode mesh index - amats = r2s.results['activation_materials'] - assert all(m.depletable for m in amats) - assert any('Mesh 0' in m.name for m in amats) - assert any('Mesh 1' in m.name for m in amats) - - # Check loading results - r2s_loaded = R2SManager(model, [mesh1, mesh2]) - r2s_loaded.load_results(outdir) - assert len(r2s_loaded.results['mesh_material_volumes']) == 2 - assert len(r2s_loaded.results['mesh_material_volumes'][0]) == 2 - assert len(r2s_loaded.results['mesh_material_volumes'][1]) == 2 - assert len(r2s_loaded.results['activation_materials']) == 4 - assert len(r2s_loaded.results['depletion_results']) == 2 - - -def test_r2s_cell_expected_output(simple_model_and_mesh, tmp_path): - model, (c1, c2), _ = simple_model_and_mesh - tally = openmc.Tally() - tally.scores = ['flux'] - model.tallies = [tally] - - # Use cell-based domains - r2s = R2SManager(model, [c1, c2]) - - # Use custom reduced chain file for Ni - chain = Chain.from_xml(Path(__file__).parents[1] / "chain_ni.xml") - - # Run R2S calculation - bounding_boxes = {c1.id: c1.bounding_box, c2.id: c2.bounding_box} - outdir = r2s.run( - timesteps=[(1.0, 'd')], - source_rates=[1.0], - photon_time_indices=[1], - by_parent_nuclide=True, - output_dir=tmp_path, - bounding_boxes=bounding_boxes, - chain_file=chain, - micro_kwargs={'nuclides': ['Ni58'], 'reactions': ['(n,p)']}, - ) - - # Check directories and files exist - nt = Path(outdir) / 'neutron_transport' - assert (nt / 'fluxes.npy').exists() - assert (nt / 'micros.h5').exists() - act = Path(outdir) / 'activation' - assert (act / 'depletion_results.h5').exists() - pt = Path(outdir) / 'photon_transport' - assert (pt / 'tally_ids.json').exists() - assert (pt / 'time_1' / 'statepoint.2.h5').exists() - - # Basic results structure checks - assert len(r2s.results['fluxes']) == 2 - assert len(r2s.results['micros']) == 2 - assert len(r2s.results['activation_materials']) == 2 - assert len(r2s.results['depletion_results']) == 2 - assert r2s.photon_model.tallies[0].contains_filter( - openmc.ParentNuclideFilter) - - # Check activation materials - amats = r2s.results['activation_materials'] - assert all(m.depletable for m in amats) - # Names include cell IDs - assert any(f"Cell {c1.id}" in m.name for m in amats) - assert any(f"Cell {c2.id}" in m.name for m in amats) - # Volumes preserved - assert {m.volume for m in amats} == {c1.volume, c2.volume} - - # Check loading results - r2s_loaded = R2SManager(model, [c1, c2]) - r2s_loaded.load_results(outdir) - assert len(r2s_loaded.results['fluxes']) == 2 - assert len(r2s_loaded.results['micros']) == 2 - assert len(r2s_loaded.results['activation_materials']) == 2 - assert len(r2s_loaded.results['depletion_results']) == 2 - - -def test_step4_requires_photon_sources(simple_model_and_mesh, tmp_path): - model, (c1, c2), _ = simple_model_and_mesh - r2s = R2SManager(model, [c1, c2]) - output_dir = tmp_path / 'photon' - - with pytest.raises(RuntimeError, match='step3_photon_source'): - r2s.step4_photon_transport(output_dir) - - r2s.results['photon_sources'] = {} - with pytest.raises(RuntimeError, match='No decay photon sources'): - r2s.step4_photon_transport(output_dir) - - assert not output_dir.exists() - - -def test_default_photon_times_skip_empty_sources( - source_stage_manager, tmp_path, monkeypatch -): - r2s, bounding_boxes = source_stage_manager - source = object() - sources_by_time = {0: [], 1: [source]} - monkeypatch.setattr( - r2s, '_create_photon_sources', - lambda time_index, work_items: sources_by_time[time_index]) - - r2s.step3_photon_source( - bounding_boxes=bounding_boxes, output_dir=tmp_path) - - assert r2s.results['photon_sources'] == {1: [source]} - - -def test_explicit_empty_photon_source_fails( - source_stage_manager, tmp_path, monkeypatch -): - r2s, bounding_boxes = source_stage_manager - source = object() - sources_by_time = {0: [], 1: [source]} - monkeypatch.setattr( - r2s, '_create_photon_sources', - lambda time_index, work_items: sources_by_time[time_index]) - r2s.results['photon_sources'] = {99: [source]} - - with pytest.raises(RuntimeError, match='requested time indices: 0'): - r2s.step3_photon_source( - [0, 1], bounding_boxes, output_dir=tmp_path) - - assert 'photon_sources' not in r2s.results - - -def test_default_photon_times_require_a_source( - source_stage_manager, tmp_path, monkeypatch -): - r2s, bounding_boxes = source_stage_manager - monkeypatch.setattr( - r2s, '_create_photon_sources', - lambda time_index, work_items: []) - - with pytest.raises(RuntimeError, match='at any depletion time'): - r2s.step3_photon_source( - bounding_boxes=bounding_boxes, output_dir=tmp_path) - - assert 'photon_sources' not in r2s.results - - -@pytest.mark.parametrize( - ('time_indices', 'exception'), - [ - ([], ValueError), - ([2], IndexError), - ([-3], IndexError), - ([1.0], TypeError), - ], -) -def test_photon_time_index_validation( - source_stage_manager, tmp_path, time_indices, exception -): - r2s, bounding_boxes = source_stage_manager - - with pytest.raises(exception): - r2s.step3_photon_source( - time_indices, bounding_boxes, output_dir=tmp_path) - - assert 'photon_sources' not in r2s.results diff --git a/tests/unit_tests/test_region.py b/tests/unit_tests/test_region.py index cb9fa171b..086ce6401 100644 --- a/tests/unit_tests/test_region.py +++ b/tests/unit_tests/test_region.py @@ -106,7 +106,7 @@ def test_complement(reset): assert_unbounded(outside_equiv) # string represention - assert str(inside) == '(-1 2 -3)' + assert str(inside) == '~(1 | -2 | 3)' # evaluate method assert (0, 0, 0) in inside @@ -208,8 +208,7 @@ def test_from_expression(reset): # Opening parenthesis immediately after halfspace r = openmc.Region.from_expression('1(2|-3)', surfs) assert str(r) == '(1 (2 | -3))' - r = openmc.Region.from_expression('-1|(1 2(-3))', surfs) - assert str(r) == '(-1 | (1 2 -3))' + def test_translate_inplace(): sph = openmc.Sphere() @@ -223,35 +222,3 @@ def test_translate_inplace(): # Translating a region in-place should *not* produce new surfaces region3 = region.translate((0.5, -6.7, 3.9), inplace=True) assert str(region) == str(region3) - - -def test_invalid_operands(): - s = openmc.Sphere() - z = 3 - - # Intersection with invalid operand - with pytest.raises(ValueError, match='must be of type Region'): - -s & +z - - # Union with invalid operand - with pytest.raises(ValueError, match='must be of type Region'): - -s | +z - - # Complement with invalid operand - with pytest.raises(ValueError, match='must be of type Region'): - openmc.Complement(z) - - -def test_plot(): - # Create region and plot - region = -openmc.Sphere() & +openmc.XPlane() - c_before = openmc.Cell() - region.plot() - - # Close plot to avoid warning - import matplotlib.pyplot as plt - plt.close() - - # Ensure that calling plot doesn't affect cell ID space - c_after = openmc.Cell() - assert c_after.id - 1 == c_before.id diff --git a/tests/unit_tests/test_settings.py b/tests/unit_tests/test_settings.py index bdb3ea8fe..7678711a4 100644 --- a/tests/unit_tests/test_settings.py +++ b/tests/unit_tests/test_settings.py @@ -1,17 +1,8 @@ -from pathlib import Path - -import h5py -import pytest - import openmc -import openmc.lib import openmc.stats def test_export_to_xml(run_in_tmpdir): - - tmp_properties_file = 'properties_test.h5' - s = openmc.Settings(run_mode='fixed source', batches=1000, seed=17) s.generations_per_batch = 10 s.inactive = 100 @@ -22,26 +13,20 @@ def test_export_to_xml(run_in_tmpdir): s.energy_mode = 'continuous-energy' s.max_order = 5 s.max_tracks = 1234 - s.source = openmc.IndependentSource(space=openmc.stats.Point()) + s.source = openmc.Source(space=openmc.stats.Point()) s.output = {'summary': True, 'tallies': False, 'path': 'here'} s.verbosity = 7 s.sourcepoint = {'batches': [50, 150, 500, 1000], 'separate': True, - 'write': True, 'overwrite': True, 'mcpl': True} + 'write': True, 'overwrite': True} s.statepoint = {'batches': [50, 150, 500, 1000]} s.surf_source_read = {'path': 'surface_source_1.h5'} s.surf_source_write = {'surface_ids': [2], 'max_particles': 200} - s.surface_grazing_ratio = 0.7 - s.surface_grazing_cutoff = 0.1 s.confidence_intervals = True s.ptables = True - s.plot_seed = 100 s.survival_biasing = True s.cutoff = {'weight': 0.25, 'weight_avg': 0.5, 'energy_neutron': 1.0e-5, - 'survival_normalization': True, 'energy_photon': 1000.0, 'energy_electron': 1.0e-5, - 'energy_positron': 1.0e-5, 'time_neutron': 1.0e-5, - 'time_photon': 1.0e-5, 'time_electron': 1.0e-5, - 'time_positron': 1.0e-5} + 'energy_positron': 1.0e-5} mesh = openmc.RegularMesh() mesh.lower_left = (-10., -10., -10.) mesh.upper_right = (10., 10., 10.) @@ -54,7 +39,6 @@ def test_export_to_xml(run_in_tmpdir): s.tabular_legendre = {'enable': True, 'num_points': 50} s.temperature = {'default': 293.6, 'method': 'interpolation', 'multipole': True, 'range': (200., 1000.)} - s.properties_file = tmp_properties_file s.trace = (10, 1, 20) s.track = [(1, 1, 1), (2, 1, 1)] s.ufs_mesh = mesh @@ -65,40 +49,14 @@ def test_export_to_xml(run_in_tmpdir): domains=[openmc.Cell()], samples=1000, lower_left=(-10., -10., -10.), upper_right = (10., 10., 10.)) s.create_fission_neutrons = True - s.create_delayed_neutrons = False s.log_grid_bins = 2000 s.photon_transport = False s.electron_treatment = 'led' - s.atomic_relaxation = False s.write_initial_source = True - s.weight_window_checkpoints = {'surface': True, 'collision': False} - source_region_mesh = openmc.RegularMesh() - source_region_mesh.dimension = [2, 2, 2] - source_region_mesh.lower_left = [-2, -2, -2] - source_region_mesh.upper_right = [2, 2, 2] - root_universe = openmc.Universe() - s.random_ray = { - 'distance_inactive': 10.0, - 'distance_active': 100.0, - 'ray_source': openmc.IndependentSource( - space=openmc.stats.Box((-1., -1., -1.), (1., 1., 1.)) - ), - 'source_region_meshes': [(source_region_mesh, [root_universe])], - 'volume_estimator': 'hybrid', - 'source_shape': 'linear', - 'volume_normalized_flux_tallies': True, - 'adjoint': False, - 'sample_method': 'halton' - } - s.max_particle_events = 100 - s.max_secondaries = 1_000_000 - s.source_rejection_fraction = 0.01 - s.free_gas_threshold = 800.0 # Make sure exporting XML works s.export_to_xml() - # Generate settings from XML s = openmc.Settings.from_xml() assert s.run_mode == 'fixed source' @@ -112,32 +70,26 @@ def test_export_to_xml(run_in_tmpdir): assert s.energy_mode == 'continuous-energy' assert s.max_order == 5 assert s.max_tracks == 1234 - assert isinstance(s.source[0], openmc.IndependentSource) + assert isinstance(s.source[0], openmc.Source) assert isinstance(s.source[0].space, openmc.stats.Point) assert s.output == {'summary': True, 'tallies': False, 'path': 'here'} assert s.verbosity == 7 assert s.sourcepoint == {'batches': [50, 150, 500, 1000], 'separate': True, - 'write': True, 'overwrite': True, 'mcpl': True} + 'write': True, 'overwrite': True} assert s.statepoint == {'batches': [50, 150, 500, 1000]} - assert s.surf_source_read['path'].name == 'surface_source_1.h5' + assert s.surf_source_read == {'path': 'surface_source_1.h5'} assert s.surf_source_write == {'surface_ids': [2], 'max_particles': 200} - assert s.surface_grazing_ratio == 0.7 - assert s.surface_grazing_cutoff == 0.1 assert s.confidence_intervals assert s.ptables - assert s.plot_seed == 100 assert s.seed == 17 assert s.survival_biasing assert s.cutoff == {'weight': 0.25, 'weight_avg': 0.5, - 'survival_normalization': True, 'energy_neutron': 1.0e-5, 'energy_photon': 1000.0, - 'energy_electron': 1.0e-5, 'energy_positron': 1.0e-5, - 'time_neutron': 1.0e-5, 'time_photon': 1.0e-5, - 'time_electron': 1.0e-5, 'time_positron': 1.0e-5} + 'energy_electron': 1.0e-5, 'energy_positron': 1.0e-5} assert isinstance(s.entropy_mesh, openmc.RegularMesh) assert s.entropy_mesh.lower_left == [-10., -10., -10.] assert s.entropy_mesh.upper_right == [10., 10., 10.] - assert s.entropy_mesh.dimension == (5, 5, 5) + assert s.entropy_mesh.dimension == [5, 5, 5] assert s.trigger_active assert s.trigger_max_batches == 10000 assert s.trigger_batch_interval == 50 @@ -145,23 +97,20 @@ def test_export_to_xml(run_in_tmpdir): assert s.tabular_legendre == {'enable': True, 'num_points': 50} assert s.temperature == {'default': 293.6, 'method': 'interpolation', 'multipole': True, 'range': [200., 1000.]} - assert s.properties_file == Path(tmp_properties_file) assert s.trace == [10, 1, 20] assert s.track == [(1, 1, 1), (2, 1, 1)] assert isinstance(s.ufs_mesh, openmc.RegularMesh) assert s.ufs_mesh.lower_left == [-10., -10., -10.] assert s.ufs_mesh.upper_right == [10., 10., 10.] - assert s.ufs_mesh.dimension == (5, 5, 5) + assert s.ufs_mesh.dimension == [5, 5, 5] assert s.resonance_scattering == {'enable': True, 'method': 'rvs', 'energy_min': 1.0, 'energy_max': 1000.0, 'nuclides': ['U235', 'U238', 'Pu239']} assert s.create_fission_neutrons - assert not s.create_delayed_neutrons assert s.log_grid_bins == 2000 assert not s.photon_transport assert s.electron_treatment == 'led' - assert not s.atomic_relaxation - assert s.write_initial_source + assert s.write_initial_source == True assert len(s.volume_calculations) == 1 vol = s.volume_calculations[0] assert vol.domain_type == 'cell' @@ -169,80 +118,3 @@ def test_export_to_xml(run_in_tmpdir): assert vol.samples == 1000 assert vol.lower_left == (-10., -10., -10.) assert vol.upper_right == (10., 10., 10.) - assert s.weight_window_checkpoints == {'surface': True, 'collision': False} - assert s.max_particle_events == 100 - assert s.random_ray['distance_inactive'] == 10.0 - assert s.random_ray['distance_active'] == 100.0 - assert s.random_ray['ray_source'].space.lower_left == [-1., -1., -1.] - assert s.random_ray['ray_source'].space.upper_right == [1., 1., 1.] - assert 'source_region_meshes' in s.random_ray - assert len(s.random_ray['source_region_meshes']) == 1 - mesh_and_domains = s.random_ray['source_region_meshes'][0] - recovered_mesh = mesh_and_domains[0] - assert recovered_mesh.dimension == (2, 2, 2) - assert recovered_mesh.lower_left == [-2., -2., -2.] - assert recovered_mesh.upper_right == [2., 2., 2.] - assert s.random_ray['volume_estimator'] == 'hybrid' - assert s.random_ray['source_shape'] == 'linear' - assert s.random_ray['volume_normalized_flux_tallies'] - assert not s.random_ray['adjoint'] - assert s.random_ray['sample_method'] == 'halton' - assert s.max_secondaries == 1_000_000 - assert s.source_rejection_fraction == 0.01 - assert s.free_gas_threshold == 800.0 - - -def test_properties_file_load(tmp_path, mpi_intracomm): - model = openmc.examples.pwr_assembly() - - # Session 1: export a structurally valid properties file via the C++ API, - # then collect the cell/material structure so we can patch it with h5py. - cell_instances = {} # {cell_id: n_instances} — material cells only - mat_densities = {} # {mat_id: original atom/b-cm density} - - props_path = tmp_path / 'properties.h5' - with openmc.lib.TemporarySession(model, intracomm=mpi_intracomm): - openmc.lib.export_properties(str(props_path)) - for cell_id, cell in openmc.lib.cells.items(): - try: - cell.fill # raises NotImplementedError for non-material cells - cell_instances[cell_id] = cell.num_instances - except NotImplementedError: - pass - for mat_id, mat in openmc.lib.materials.items(): - mat_densities[mat_id] = mat.get_density('atom/b-cm') - - assert any(n > 1 for n in cell_instances.values()) - - # Patch the exported properties file overwriting temperatures - # with per-instance values and scale material atom densities. - density_factor = 0.75 - with h5py.File(props_path, 'r+') as f: - cells_grp = f['geometry/cells'] - for cell_id, n in cell_instances.items(): - cell_grp = cells_grp[f'cell {cell_id}'] - del cell_grp['temperature'] - cell_grp.create_dataset( - 'temperature', data=[500.0 + 5.0 * i for i in range(n)] - ) - - for mat_id, orig_density in mat_densities.items(): - f['materials'][f'material {mat_id}'].attrs['atom_density'] = \ - orig_density * density_factor - - # now apply the newly patched properties file using the settings - # and load the model again, checking that the new temperature and - # density values match those in the new file - model.settings.properties_file = props_path - - with openmc.lib.TemporarySession(model, intracomm=mpi_intracomm): - for cell_id, n in cell_instances.items(): - cell = openmc.lib.cells[cell_id] - for i in range(n): - assert cell.get_temperature(i) == pytest.approx(500.0 + 5.0 * i) - - for mat_id, orig_density in mat_densities.items(): - mat = openmc.lib.materials[mat_id] - assert mat.get_density('atom/b-cm') == pytest.approx( - orig_density * density_factor, rel=1e-5 - ) diff --git a/tests/unit_tests/test_slice_data.py b/tests/unit_tests/test_slice_data.py deleted file mode 100644 index cc5fb0474..000000000 --- a/tests/unit_tests/test_slice_data.py +++ /dev/null @@ -1,168 +0,0 @@ -import numpy as np -import openmc -from openmc.examples import pwr_pin_cell - - -def test_slice_data_basic(run_in_tmpdir): - """Test basic slice_data functionality.""" - model = pwr_pin_cell() - geom_data, prop_data = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(100, 100), - basis='xy' - ) - - # Without filter, should have 3 fields - assert geom_data.shape == (100, 100, 3) - assert geom_data.dtype == np.int32 - assert prop_data.shape == (100, 100, 2) - assert prop_data.dtype == np.float64 - - # Check we have valid geometry - assert np.any(geom_data[:, :, 0] >= 0) # Valid cell IDs - assert np.any(prop_data[:, :, 0] > 0) # Valid temperatures - - -def test_slice_data_no_properties(run_in_tmpdir): - """Test slice_data without property data.""" - model = pwr_pin_cell() - geom_data, prop_data = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(50, 50), - include_properties=False - ) - - # Without filter, should have 3 fields - assert geom_data.shape == (50, 50, 3) - assert prop_data is None - - -def test_slice_data_with_filter(run_in_tmpdir): - """Test slice_data with a cell filter.""" - model = pwr_pin_cell() - cell_ids = [c.id for c in model.geometry.get_all_cells().values()] - cell_filter = openmc.CellFilter(cell_ids) - - geom_data, _ = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(50, 50), - filter=cell_filter, - include_properties=False - ) - - # With filter, should have 4 fields - assert geom_data.shape == (50, 50, 4) - - # Filter bin index should be populated where cells exist - filter_bins = geom_data[:, :, 3] - valid_cells = geom_data[:, :, 0] >= 0 - assert np.any(filter_bins[valid_cells] >= 0) - - -def test_slice_data_overlaps(run_in_tmpdir): - """Test slice_data with overlap detection.""" - model = pwr_pin_cell() - geom_data, _ = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(50, 50), - show_overlaps=True, - include_properties=False - ) - - # Without filter, should have 3 fields - assert geom_data.shape == (50, 50, 3) - # Check for overlap markers (-3) if any exist - # Note: This test may pass without finding overlaps if geometry is correct - - -def test_slice_data_overlaps_with_filter(run_in_tmpdir): - """Test that overlaps don't overwrite filter bin data.""" - model = pwr_pin_cell() - cell_ids = [c.id for c in model.geometry.get_all_cells().values()] - cell_filter = openmc.CellFilter(cell_ids) - - geom_data, _ = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(50, 50), - filter=cell_filter, - show_overlaps=True, - include_properties=False - ) - - assert geom_data.shape == (50, 50, 4) - - # If any overlaps exist, verify filter bin is still valid (not -3) - overlap_pixels = geom_data[:, :, 0] == -3 - if np.any(overlap_pixels): - # Filter bins at overlap locations should NOT be -3 - filter_bins_at_overlaps = geom_data[overlap_pixels, 3] - assert not np.all(filter_bins_at_overlaps == -3), \ - "Filter bins should be preserved even where overlaps are detected" - - -def test_slice_data_different_bases(run_in_tmpdir): - """Test slice_data with different basis planes.""" - model = pwr_pin_cell() - - for basis in ['xy', 'xz', 'yz']: - geom_data, prop_data = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(25, 25), - basis=basis - ) - - assert geom_data.shape == (25, 25, 3) - assert prop_data.shape == (25, 25, 2) - - -def test_slice_data_oriented_spans(run_in_tmpdir): - """Test slice_data with oriented span vectors.""" - model = pwr_pin_cell() - - geom_data, prop_data = model.slice_data( - origin=(0, 0, 0), - u_span=(1.0, 0.0, 0.0), - v_span=(0.0, 0.0, 1.0), - pixels=(25, 25) - ) - - assert geom_data.shape == (25, 25, 3) - assert prop_data.shape == (25, 25, 2) - - -def test_slice_data_level(run_in_tmpdir): - """Test slice_data with specific universe level.""" - model = pwr_pin_cell() - geom_data, _ = model.slice_data( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(50, 50), - level=0, # Root universe only - include_properties=False - ) - - assert geom_data.shape == (50, 50, 3) - - -def test_id_map_reverted(run_in_tmpdir): - """Test that id_map returns 3D array without filter support.""" - model = pwr_pin_cell() - id_data = model.id_map( - origin=(0, 0, 0), - width=(1.0, 1.0), - pixels=(50, 50), - basis='xy' - ) - - # Should have 3 fields (cell_id, cell_instance, material_id) - assert id_data.shape == (50, 50, 3) - assert id_data.dtype == np.int32 - - # Check valid data - assert np.any(id_data[:, :, 0] >= 0) # Valid cell IDs diff --git a/tests/unit_tests/test_slice_data_overlap_info.py b/tests/unit_tests/test_slice_data_overlap_info.py deleted file mode 100644 index e5f08245d..000000000 --- a/tests/unit_tests/test_slice_data_overlap_info.py +++ /dev/null @@ -1,89 +0,0 @@ -import pytest -import numpy as np -import openmc -import openmc.lib - -# Sentinel value matching _OVERLAP in plotmodel.py and OVERLAP in plot.cpp -_OVERLAP = -3 - - -@pytest.fixture(scope='module') -def overlap_model(): - openmc.reset_auto_ids() - - # Three cylinders: cyl1 and cyl2 overlap near x=0, cyl2 and cyl3 overlap - # near x=4. This gives us two spatially distinct overlap regions in one model. - mat1 = openmc.Material(components={'H1': 1.0}) - mat2 = openmc.Material(components={'H1': 1.0}) - mat3 = openmc.Material(components={'H1': 1.0}) - - # cyl1 and cyl2 overlap on the left, cyl2 and cyl3 overlap on the right - cyl1 = openmc.ZCylinder(x0=-2.0, r=2.5) - cyl2 = openmc.ZCylinder(x0=0.0, r=2.5) - cyl3 = openmc.ZCylinder(x0=2.0, r=2.5) - boundary = openmc.Sphere(r=20.0, boundary_type='vacuum') - cell1 = openmc.Cell(region=-cyl1, fill=mat1) - cell2 = openmc.Cell(region=-cyl2, fill=mat2) - cell3 = openmc.Cell(region=-cyl3, fill=mat3) - cell_outside = openmc.Cell(region=+cyl1 & +cyl2 & +cyl3 & -boundary) - geometry = openmc.Geometry([cell1, cell2, cell3, cell_outside]) - - settings = openmc.Settings() - settings.run_mode = 'fixed source' - settings.particles = 100 - settings.batches = 1 - model = openmc.Model(geometry=geometry, settings=settings) - - with openmc.lib.TemporarySession(model, args=['-s', '1']): - yield - - -def run_slice(origin=(0.0, 0.0, 0.0), width=(10.0, 6.0), show_overlaps=True): - # Helper that runs a slice over a region covering both overlap zones - geom_data, _ = openmc.lib.slice_data( - origin=origin, - width=width, - basis='xy', - pixels=(100, 60), - show_overlaps=show_overlaps, - include_properties=False, - ) - return geom_data - - -def test_overlaps_enabled(overlap_model): - # Run a single slice with overlap detection enabled and check all - # expected properties in one pass. - geom_data = run_slice() - overlap_info = openmc.lib.slice_data_overlap_info() - n = overlap_info.shape[0] - cell_ids = geom_data[:, :, 0] - - # cell_ids should contain values more negative than _OVERLAP; RasterData - # encodes each unique overlap as OVERLAP - overlap_idx - 1 into slot 2. - assert np.any(cell_ids < _OVERLAP) - - # overlap_keys should have 2 entries for the two distinct overlapping - # cylinder pairs in this model. - assert n == 2, f"Expected exactly 2 overlap entries, got {n}" - - # Each entry is a (universe_id, cell1_id, cell2_id) triple; verify values. - for i in range(n): - universe_id = int(overlap_info[i, 0]) - cell1_id = int(overlap_info[i, 1]) - cell2_id = int(overlap_info[i, 2]) - assert universe_id == 1 - assert cell1_id in {1, 2, 3} - assert cell2_id in {1, 2, 3} - assert cell1_id != cell2_id - - -def test_overlaps_disabled(overlap_model): - # With show_overlaps=False, set_overlap is never called and overlap_keys - # is never written to, so the image and map should both be clean. - geom_data = run_slice(show_overlaps=False) - overlap_info = openmc.lib.slice_data_overlap_info() - n = overlap_info.shape[0] - - assert not np.any(geom_data[:, :, 2] < _OVERLAP) - assert n == 0 diff --git a/tests/unit_tests/test_slice_voxel_plots.py b/tests/unit_tests/test_slice_voxel_plots.py deleted file mode 100644 index 48ca31b7a..000000000 --- a/tests/unit_tests/test_slice_voxel_plots.py +++ /dev/null @@ -1,273 +0,0 @@ -"""Tests for SlicePlot and VoxelPlot classes - -This module tests the functionality of the new SlicePlot and VoxelPlot -classes that replace the legacy Plot class. -""" -import warnings - -import pytest -import openmc - - -def test_slice_plot_initialization(): - """Test SlicePlot initialization with defaults""" - plot = openmc.SlicePlot() - assert plot.width == [4.0, 4.0] - assert plot.pixels == [400, 400] - assert plot.basis == 'xy' - assert plot.origin == [0., 0., 0.] - - -def test_slice_plot_width_validation(): - """Test that SlicePlot only accepts 2 values for width""" - plot = openmc.SlicePlot() - - # Should accept 2 values - plot.width = [10.0, 20.0] - assert plot.width == [10.0, 20.0] - - # Should reject 1 value - with pytest.raises(ValueError, match='must be of length "2"'): - plot.width = [10.0] - - # Should reject 3 values - with pytest.raises(ValueError, match='must be of length "2"'): - plot.width = [10.0, 20.0, 30.0] - - -def test_slice_plot_pixels_validation(): - """Test that SlicePlot only accepts 2 values for pixels""" - plot = openmc.SlicePlot() - - # Should accept 2 values - plot.pixels = [100, 200] - assert plot.pixels == [100, 200] - - # Should reject 1 value - with pytest.raises(ValueError, match='must be of length "2"'): - plot.pixels = [100] - - # Should reject 3 values - with pytest.raises(ValueError, match='must be of length "2"'): - plot.pixels = [100, 200, 300] - - -def test_slice_plot_basis(): - """Test that SlicePlot has basis attribute""" - plot = openmc.SlicePlot() - - # Test all valid basis values - for basis in ['xy', 'xz', 'yz']: - plot.basis = basis - assert plot.basis == basis - - # Test invalid basis - with pytest.raises(ValueError): - plot.basis = 'invalid' - - -def test_slice_plot_meshlines(): - """Test that SlicePlot has meshlines attribute""" - plot = openmc.SlicePlot() - - meshlines = { - 'type': 'tally', - 'id': 1, - 'linewidth': 2, - 'color': (255, 0, 0) - } - plot.meshlines = meshlines - assert plot.meshlines == meshlines - - -def test_slice_plot_xml_roundtrip(): - """Test SlicePlot XML serialization and deserialization""" - plot = openmc.SlicePlot(name='test_slice') - plot.width = [15.0, 25.0] - plot.pixels = [150, 250] - plot.basis = 'xz' - plot.origin = [1.0, 2.0, 3.0] - plot.color_by = 'material' - plot.filename = 'test_plot' - - # Convert to XML and back - elem = plot.to_xml_element() - new_plot = openmc.SlicePlot.from_xml_element(elem) - - # Check all attributes preserved - assert new_plot.name == plot.name - assert new_plot.width == pytest.approx(plot.width) - assert new_plot.pixels == tuple(plot.pixels) - assert new_plot.basis == plot.basis - assert new_plot.origin == pytest.approx(plot.origin) - assert new_plot.color_by == plot.color_by - assert new_plot.filename == plot.filename - - -def test_slice_plot_from_geometry(): - """Test creating SlicePlot from geometry""" - # Create simple geometry - s = openmc.Sphere(r=10.0, boundary_type='vacuum') - c = openmc.Cell(region=-s) - univ = openmc.Universe(cells=[c]) - geom = openmc.Geometry(univ) - - # Test all basis options - for basis in ['xy', 'xz', 'yz']: - plot = openmc.SlicePlot.from_geometry(geom, basis=basis) - assert plot.basis == basis - assert plot.width == pytest.approx([20.0, 20.0]) - assert plot.origin == pytest.approx([0.0, 0.0, 0.0]) - - -def test_voxel_plot_initialization(): - """Test VoxelPlot initialization with defaults""" - plot = openmc.VoxelPlot() - assert plot.width == [4.0, 4.0, 4.0] - assert plot.pixels == [400, 400, 400] - assert plot.origin == [0., 0., 0.] - - -def test_voxel_plot_width_validation(): - """Test that VoxelPlot only accepts 3 values for width""" - plot = openmc.VoxelPlot() - - # Should accept 3 values - plot.width = [10.0, 20.0, 30.0] - assert plot.width == [10.0, 20.0, 30.0] - - # Should reject 2 values - with pytest.raises(ValueError, match='must be of length "3"'): - plot.width = [10.0, 20.0] - - # Should reject 1 value - with pytest.raises(ValueError, match='must be of length "3"'): - plot.width = [10.0] - - -def test_voxel_plot_pixels_validation(): - """Test that VoxelPlot only accepts 3 values for pixels""" - plot = openmc.VoxelPlot() - - # Should accept 3 values - plot.pixels = [100, 200, 300] - assert plot.pixels == [100, 200, 300] - - # Should reject 2 values - with pytest.raises(ValueError, match='must be of length "3"'): - plot.pixels = [100, 200] - - # Should reject 1 value - with pytest.raises(ValueError, match='must be of length "3"'): - plot.pixels = [100] - - -def test_voxel_plot_xml_roundtrip(): - """Test VoxelPlot XML serialization and deserialization""" - plot = openmc.VoxelPlot(name='test_voxel') - plot.width = [10.0, 20.0, 30.0] - plot.pixels = [100, 200, 300] - plot.origin = [1.0, 2.0, 3.0] - plot.color_by = 'cell' - plot.filename = 'voxel_plot' - - # Convert to XML and back - elem = plot.to_xml_element() - new_plot = openmc.VoxelPlot.from_xml_element(elem) - - # Check all attributes preserved - assert new_plot.name == plot.name - assert new_plot.width == pytest.approx(plot.width) - assert new_plot.pixels == tuple(plot.pixels) - assert new_plot.origin == pytest.approx(plot.origin) - assert new_plot.color_by == plot.color_by - assert new_plot.filename == plot.filename - - -def test_plot_deprecation_warning(): - """Test that Plot class raises deprecation warning""" - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - openmc.Plot() - - assert len(w) == 1 - assert issubclass(w[0].category, FutureWarning) - assert "deprecated" in str(w[0].message).lower() - - -def test_plot_returns_slice_plot(): - """Test that Plot() returns a SlicePlot instance""" - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - plot = openmc.Plot() - - # Should be an actual SlicePlot instance - assert isinstance(plot, openmc.SlicePlot) - - -def test_plot_type_setter_raises_error(): - """Test that setting plot.type raises a helpful error""" - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - plot = openmc.Plot() - - with pytest.raises(TypeError, match="no longer supported"): - plot.type = 'voxel' - - with pytest.raises(TypeError, match="no longer supported"): - plot.type = 'slice' - - -def test_plot_type_getter_warns(): - """Test that getting plot.type raises a deprecation warning""" - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - plot = openmc.Plot() - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - plot_type = plot.type - - assert plot_type == 'slice' - assert len(w) == 1 - assert issubclass(w[0].category, FutureWarning) - assert "deprecated" in str(w[0].message).lower() - - -def test_plots_collection_mixed_types(): - """Test Plots collection with different plot types""" - slice_plot = openmc.SlicePlot(name='slice') - voxel_plot = openmc.VoxelPlot(name='voxel') - wireframe_plot = openmc.WireframeRayTracePlot(name='wireframe') - - plots = openmc.Plots([slice_plot, voxel_plot, wireframe_plot]) - - assert len(plots) == 3 - assert isinstance(plots[0], openmc.SlicePlot) - assert isinstance(plots[1], openmc.VoxelPlot) - assert isinstance(plots[2], openmc.WireframeRayTracePlot) - - -def test_plots_collection_xml_roundtrip(run_in_tmpdir): - """Test XML export and import with new plot types""" - s1 = openmc.SlicePlot(name='slice1') - s1.width = [10.0, 20.0] - s1.basis = 'xz' - - v1 = openmc.VoxelPlot(name='voxel1') - v1.width = [10.0, 20.0, 30.0] - - plots = openmc.Plots([s1, v1]) - plots.export_to_xml() - - # Read back - new_plots = openmc.Plots.from_xml() - - assert len(new_plots) == 2 - assert isinstance(new_plots[0], openmc.SlicePlot) - assert isinstance(new_plots[1], openmc.VoxelPlot) - assert new_plots[0].name == 'slice1' - assert new_plots[1].name == 'voxel1' - assert new_plots[0].basis == 'xz' - assert new_plots[0].width == pytest.approx([10.0, 20.0]) - assert new_plots[1].width == pytest.approx([10.0, 20.0, 30.0]) diff --git a/tests/unit_tests/test_source.py b/tests/unit_tests/test_source.py index 394c09e73..dbcf49efc 100644 --- a/tests/unit_tests/test_source.py +++ b/tests/unit_tests/test_source.py @@ -1,23 +1,13 @@ -from collections import Counter -from math import pi -from pathlib import Path - import openmc -import openmc.lib import openmc.stats -import numpy as np -import pytest -from pytest import approx - -from tests.regression_tests import config - +from math import pi def test_source(): space = openmc.stats.Point() energy = openmc.stats.Discrete([1.0e6], [1.0]) angle = openmc.stats.Isotropic() - src = openmc.IndependentSource(space=space, angle=angle, energy=energy) + src = openmc.Source(space=space, angle=angle, energy=energy) assert src.space == space assert src.angle == angle assert src.energy == energy @@ -28,7 +18,7 @@ def test_source(): assert elem.find('angle') is not None assert elem.find('energy') is not None - src = openmc.IndependentSource.from_xml_element(elem) + src = openmc.Source.from_xml_element(elem) assert isinstance(src.angle, openmc.stats.Isotropic) assert src.space.xyz == [0.0, 0.0, 0.0] assert src.energy.x == [1.0e6] @@ -36,134 +26,26 @@ def test_source(): assert src.strength == 1.0 -def test_point_cloud(): - positions = [(1, 0, 2), (0, 1, 0), (0, 0, 3), (4, 9, 2)] - strengths = [1, 2, 3, 4] +def test_spherical_uniform(): + r_outer = 2.0 + r_inner = 1.0 + thetas = (0.0, pi/2) + phis = (0.0, pi) + origin = (0.0, 1.0, 2.0) - space = openmc.stats.PointCloud(positions, strengths) - np.testing.assert_equal(space.positions, positions) - np.testing.assert_equal(space.strengths, strengths) - - src = openmc.IndependentSource(space=space) - assert src.space == space - np.testing.assert_equal(src.space.positions, positions) - np.testing.assert_equal(src.space.strengths, strengths) - - elem = src.to_xml_element() - src = openmc.IndependentSource.from_xml_element(elem) - np.testing.assert_equal(src.space.positions, positions) - np.testing.assert_equal(src.space.strengths, strengths) - - -def test_point_cloud_invalid(): - with pytest.raises(ValueError, match='2D'): - openmc.stats.PointCloud([1, 0, 2, 0, 1, 0]) - - with pytest.raises(ValueError, match='3 values'): - openmc.stats.PointCloud([(1, 0, 2, 3), (4, 5, 2, 3)]) - - with pytest.raises(ValueError, match='1D'): - openmc.stats.PointCloud([(1, 0, 2), (4, 5, 2)], [(1, 2), (3, 4)]) - - with pytest.raises(ValueError, match='same length'): - openmc.stats.PointCloud([(1, 0, 2), (4, 5, 2)], [1, 2, 4]) - - -def test_point_cloud_strengths(run_in_tmpdir, sphere_box_model): - positions = [(1., 0., 2.), (0., 1., 0.), (0., 0., 3.), (-1., -1., 2.)] - strengths = [1, 2, 3, 4] - space = openmc.stats.PointCloud(positions, strengths) - - model = sphere_box_model[0] - model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource(space=space) - - try: - model.init_lib() - n_samples = 50_000 - sites = openmc.lib.sample_external_source(n_samples) - finally: - model.finalize_lib() - - count = Counter(s.r for s in sites) - for i, (strength, position) in enumerate(zip(strengths, positions)): - sampled_strength = count[position] / n_samples - expected_strength = pytest.approx(strength/sum(strengths), abs=0.02) - assert sampled_strength == expected_strength, f'Strength incorrect for {positions[i]}' - - -def test_decay_spectrum_parent_nuclide(run_in_tmpdir): - chain_file = Path('chain_decay_spectrum_parent.xml') - chain_file.write_text(""" - - - - 1000000.0 1.0 - - - - - 2000000.0 1.0 - - - -""") - - inner_sphere = openmc.Sphere(r=10.0) - outer_sphere = openmc.Sphere(r=20.0, boundary_type='vacuum') - - shell_mat = openmc.Material() - shell_mat.add_nuclide('H1', 1.0) - shell_mat.set_density('atom/b-cm', 1.0e-12) - - void_cell = openmc.Cell(region=-inner_sphere) - shell_cell = openmc.Cell(fill=shell_mat, region=+inner_sphere & -outer_sphere) - - model = openmc.Model() - model.geometry = openmc.Geometry([void_cell, shell_cell]) - model.materials = [shell_mat] - model.settings.run_mode = 'fixed source' - model.settings.photon_transport = True - model.settings.particles = 1000 - model.settings.batches = 5 - model.settings.source = openmc.IndependentSource( - particle='photon', - space=openmc.stats.Point((0.0, 0.0, 0.0)), - energy=openmc.stats.DecaySpectrum( - {'ParentA': 1.0, 'ParentB': 1.0}, - volume=1.0 - ) - ) - - tally = openmc.Tally() - tally.filters = [ - openmc.CellFilter([void_cell]), - openmc.ParticleFilter(['photon']), - openmc.EnergyFilter([0.0, 1.5e6, 2.5e6]), - openmc.ParentNuclideFilter(['ParentA', 'ParentB']) - ] - tally.scores = ['flux'] - model.tallies = [tally] - - with openmc.config.patch('chain_file', chain_file): - sp_filename = model.run() - - with openmc.StatePoint(sp_filename) as sp: - tally_out = sp.tallies[tally.id] - mean = tally_out.get_reshaped_data('mean').squeeze() - - assert mean.shape == (2, 2) - assert mean[0, 0] > 0.0 - assert mean[1, 1] > 0.0 - assert mean[0, 1] == 0.0 - assert mean[1, 0] == 0.0 - assert np.count_nonzero(mean) == 2 + sph_indep_function = openmc.stats.spherical_uniform(r_outer, + r_inner, + thetas, + phis, + origin) + assert isinstance(sph_indep_function, openmc.stats.SphericalIndependent) + def test_source_file(): filename = 'source.h5' - src = openmc.FileSource(path=filename) - assert src.path.name == filename + src = openmc.Source(filename=filename) + assert src.file == filename elem = src.to_xml_element() assert 'strength' in elem.attrib @@ -171,201 +53,9 @@ def test_source_file(): def test_source_dlopen(): - library = 'libsource.so' - src = openmc.CompiledSource(library) - assert src.library.name == library + library = './libsource.so' + src = openmc.Source(library=library) + assert src.library == library elem = src.to_xml_element() assert 'library' in elem.attrib - - -def test_source_xml_roundtrip(): - # Create a source and write to an XML element - space = openmc.stats.Box([-5., -5., -5.], [5., 5., 5.]) - energy = openmc.stats.Discrete([1.0e6, 2.0e6, 5.0e6], [0.3, 0.5, 0.2]) - angle = openmc.stats.PolarAzimuthal( - mu=openmc.stats.Uniform(0., 1.), - phi=openmc.stats.Uniform(0., 2*pi), - reference_uvw=(0., 1., 0.) - ) - src = openmc.IndependentSource( - space=space, angle=angle, energy=energy, - particle='photon', strength=100.0 - ) - elem = src.to_xml_element() - - # Read from XML element and make sure data is preserved - new_src = openmc.IndependentSource.from_xml_element(elem) - assert isinstance(new_src.space, openmc.stats.Box) - np.testing.assert_allclose(new_src.space.lower_left, src.space.lower_left) - np.testing.assert_allclose(new_src.space.upper_right, src.space.upper_right) - assert isinstance(new_src.energy, openmc.stats.Discrete) - np.testing.assert_allclose(new_src.energy.x, src.energy.x) - np.testing.assert_allclose(new_src.energy.p, src.energy.p) - assert isinstance(new_src.angle, openmc.stats.PolarAzimuthal) - assert new_src.angle.mu.a == src.angle.mu.a - assert new_src.angle.mu.b == src.angle.mu.b - assert new_src.angle.phi.a == src.angle.phi.a - assert new_src.angle.phi.b == src.angle.phi.b - np.testing.assert_allclose(new_src.angle.reference_uvw, src.angle.reference_uvw) - assert new_src.particle == src.particle - assert new_src.strength == approx(src.strength) - - -@pytest.fixture -def sphere_box_model(): - # Model with two spheres inside a box - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - sph1 = openmc.Sphere(x0=3, r=1.0) - sph2 = openmc.Sphere(x0=-3, r=1.0) - cube = openmc.model.RectangularParallelepiped( - -5., 5., -5., 5., -5., 5., boundary_type='reflective' - ) - cell1 = openmc.Cell(fill=mat, region=-sph1) - cell2 = openmc.Cell(fill=mat, region=-sph2) - non_source_region = +sph1 & +sph2 & -cube - cell3 = openmc.Cell(region=non_source_region) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2, cell3]) - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.run_mode = 'fixed source' - - return model, cell1, cell2, cell3 - - -def test_constraints_independent(sphere_box_model, run_in_tmpdir): - model, cell1, cell2, cell3 = sphere_box_model - - # Set up a box source with rejection on the spherical cell - space = openmc.stats.Box((-4., -1., -1.), (4., 1., 1.)) - model.settings.source = openmc.IndependentSource( - space=space, constraints={'domains': [cell1, cell2]} - ) - - # Load up model via openmc.lib and sample source - model.export_to_model_xml() - openmc.lib.init() - particles = openmc.lib.sample_external_source(1000) - - # Make sure that all sampled sources are within one of the spheres - for p in particles: - assert p.r in (cell1.region | cell2.region) - assert p.r not in cell3.region - - openmc.lib.finalize() - - -def test_constraints_mesh(sphere_box_model, run_in_tmpdir): - model, cell1, cell2, cell3 = sphere_box_model - - bbox = cell3.bounding_box - mesh = openmc.RegularMesh() - mesh.lower_left = bbox.lower_left - mesh.upper_right = bbox.upper_right - mesh.dimension = (2, 1, 1) - - left_source = openmc.IndependentSource() - right_source = openmc.IndependentSource() - model.settings.source = openmc.MeshSource( - mesh, [left_source, right_source], constraints={'domains': [cell1, cell2]} - ) - - # Load up model via openmc.lib and sample source - model.export_to_model_xml() - openmc.lib.init() - particles = openmc.lib.sample_external_source(1000) - - # Make sure that all sampled sources are within one of the spheres - for p in particles: - assert p.r in (cell1.region | cell2.region) - assert p.r not in cell3.region - - openmc.lib.finalize() - - -def test_constraints_file(sphere_box_model, run_in_tmpdir): - model = sphere_box_model[0] - - # Create source file with randomly sampled source sites - rng = np.random.default_rng() - energy = rng.uniform(0., 1e6, 10_000) - time = rng.uniform(0., 1., 10_000) - particles = [openmc.SourceParticle(E=e, time=t) for e, t in zip(energy, time)] - openmc.write_source_file(particles, 'uniform_source.h5') - - # Use source file - model.settings.source = openmc.FileSource( - 'uniform_source.h5', - constraints={ - 'time_bounds': [0.25, 0.75], - 'energy_bounds': [500.e3, 1.0e6], - } - ) - - # Load up model via openmc.lib and sample source - model.export_to_model_xml() - openmc.lib.init() - particles = openmc.lib.sample_external_source(1000) - - # Make sure that all sampled sources are within energy/time bounds - for p in particles: - assert 0.25 <= p.time <= 0.75 - assert 500.e3 <= p.E <= 1.0e6 - - openmc.lib.finalize() - - -@pytest.mark.skipif(config['mpi'], reason='Not compatible with MPI') -def test_rejection_fraction(run_in_tmpdir): - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - w = 0.25 - rpp1 = openmc.model.RectangularParallelepiped( - -w/2, w/2, -w/2, w/2, -w/2, w/2) - rpp2 = openmc.model.RectangularParallelepiped( - -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, boundary_type='vacuum') - cell1 = openmc.Cell(fill=mat, region=-rpp1) - cell2 = openmc.Cell(region=+rpp1 & -rpp2) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2]) - - # Create a box source over a 1 cm³ volume that is constrained to the source - # cell of volume (0.25 cm)³ = 0.0125 cm³, which means the default rejection - # fraction of 0.05 won't work - model.settings.particles = 1000 - model.settings.batches = 1 - model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Box(*(-rpp2).bounding_box), - constraints={'domains': [cell1]} - ) - with pytest.raises(RuntimeError, match='Too few source sites'): - model.run(openmc_exec=config['exe']) - - # With a source rejection fraction below 0.0125, the simulation should run - model.settings.source_rejection_fraction = 0.005 - model.run(openmc_exec=config['exe']) - - -def test_exceptions(): - - with pytest.raises(AttributeError, match=r'Please use the FileSource class'): - s = openmc.IndependentSource() - s.file = 'my_file' - - with pytest.raises(AttributeError, match=r'Please use the CompiledSource class'): - s = openmc.IndependentSource() - s.library = 'my_library' - - with pytest.raises(AttributeError, match=r'Please use the CompiledSource class'): - s = openmc.IndependentSource() - s.parameters = 'my_params' - - with pytest.warns(FutureWarning, match=r'in favor of \'IndependentSource\''): - s = openmc.Source() - - with pytest.raises(AttributeError, match=r'has no attribute \'frisbee\''): - s = openmc.IndependentSource() - s.frisbee diff --git a/tests/unit_tests/test_source_biasing.py b/tests/unit_tests/test_source_biasing.py deleted file mode 100644 index 12588594c..000000000 --- a/tests/unit_tests/test_source_biasing.py +++ /dev/null @@ -1,276 +0,0 @@ -"""Tests for source biasing using C++ sampling routines via openmc.lib - -This test module validates that the C++ distribution sampling implementations -correctly handle both unbiased and biased sampling when used in source -definitions. Each test: - -1. Creates a minimal model with a source using a specific energy distribution -2. Uses model.sample_external_source() to generate samples via openmc.lib -3. Extracts energies from the returned particle list -4. Validates that: - - Unbiased sampling produces the expected mean - - Biased sampling with importance weighting produces the expected mean - - Weights are correctly applied (non-unity for biased case) - -These tests complement the Python-level tests in test_stats.py by exercising -the full C++ sampling codepath that is used during actual simulations. -""" - -import numpy as np -import pytest -import openmc - -from tests.unit_tests import assert_sample_mean - - -@pytest.fixture -def model(): - """Create a minimal model for source sampling tests.""" - sphere = openmc.Sphere(r=100.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere) - geometry = openmc.Geometry([cell]) - settings = openmc.Settings(particles=100, batches=1) - space = openmc.stats.Point() - angle = openmc.stats.Monodirectional((1.0, 0.0, 0.0)) - settings.source = openmc.IndependentSource(space=space, angle=angle) - return openmc.Model(geometry=geometry, settings=settings) - - -@pytest.mark.flaky(reruns=1) -def test_discrete(run_in_tmpdir, model): - """Test Discrete distribution sampling via C++ routines.""" - vals = np.array([1.0, 2.0, 3.0]) - probs = np.array([0.1, 0.7, 0.2]) - exp_mean = (vals * probs).sum() - - # Create source with discrete energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.Discrete(vals, probs) - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample from biased distribution - energy_dist.bias = np.array([0.2, 0.1, 0.7]) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_uniform(run_in_tmpdir, model): - """Test Uniform distribution sampling via C++ routines.""" - a, b = 5.0, 10.0 - exp_mean = 0.5 * (a + b) - - # Create source with uniform energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.Uniform(a, b) - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample from biased distribution - energy_dist.bias = openmc.stats.PowerLaw(a, b, 2) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_powerlaw(run_in_tmpdir, model): - """Test PowerLaw distribution sampling via C++ routines.""" - a, b, n = 1.0, 20.0, 2.0 - - # Determine mean of distribution - exp_mean = (n+1)*(b**(n+2) - a**(n+2))/((n+2)*(b**(n+1) - a**(n+1))) - - # Create source with powerlaw energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.PowerLaw(a, b, n) - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample from biased distribution - energy_dist.bias = openmc.stats.Uniform(a, b) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_maxwell(run_in_tmpdir, model): - """Test Maxwell distribution sampling via C++ routines.""" - theta = 1.2895e6 - exp_mean = 3/2 * theta - - # Create source with Maxwell energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.Maxwell(theta) - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample from biased distribution - energy_dist.bias = openmc.stats.Maxwell(theta * 1.1) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_watt(run_in_tmpdir, model): - """Test Watt distribution sampling via C++ routines.""" - a, b = 0.965e6, 2.29e-6 - exp_mean = 3/2 * a + a**2 * b / 4 - - # Create source with Watt energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.Watt(a, b) - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample from biased distribution - energy_dist.bias = openmc.stats.Watt(a*1.05, b) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_tabular(run_in_tmpdir, model): - """Test Tabular distribution sampling via C++ routines.""" - # Test linear-linear sampling - x = np.array([0.0, 5.0, 7.0, 10.0]) - p = np.array([10.0, 20.0, 5.0, 6.0]) - - # Create tabular distribution and normalize to get expected mean - model.settings.source[0].energy = energy_dist = openmc.stats.Tabular(x, p, 'linear-linear') - energy_dist.normalize() - exp_mean = energy_dist.mean() - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample from biased distribution - energy_dist.bias = openmc.stats.Uniform(x[0], x[-1]) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_mixture(run_in_tmpdir, model): - """Test Mixture distribution sampling via C++ routines.""" - d1 = openmc.stats.Uniform(0, 5) - d2 = openmc.stats.Uniform(3, 7) - p = [0.5, 0.5] - - # Create mixture energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.Mixture(p, [d1, d2]) - exp_mean = (2.5 + 5.0) / 2 - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, exp_mean) - - # Sample using biased sub-distribution - energy_dist.distribution[0].bias = openmc.stats.PowerLaw(0, 5, 2) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, exp_mean) - assert np.any(weights != 1.0) - - -@pytest.mark.flaky(reruns=1) -def test_normal(run_in_tmpdir, model): - """Test Normal distribution sampling via C++ routines.""" - mean_val = 25.0 - std_dev = 2.0 - - # Create source with normal energy distribution - model.settings.source[0].energy = energy_dist = openmc.stats.Normal(mean_val, std_dev) - - # Sample using C++ routines and extract energies - n_samples = 10_000 - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - - # Check unbiased mean - assert_sample_mean(energies, mean_val) - - # Sample from biased distribution - energy_dist.bias = openmc.stats.Normal(mean_val * 1.1, std_dev) - particles = model.sample_external_source(n_samples) - energies = np.array([p.E for p in particles]) - weights = np.array([p.wgt for p in particles]) - - # Check biased weighted mean - weighted_energies = energies * weights - assert_sample_mean(weighted_energies, mean_val) - assert np.any(weights != 1.0) diff --git a/tests/unit_tests/test_source_file.py b/tests/unit_tests/test_source_file.py index f19ea74a6..1398088e5 100644 --- a/tests/unit_tests/test_source_file.py +++ b/tests/unit_tests/test_source_file.py @@ -42,55 +42,7 @@ def test_source_file(run_in_tmpdir): assert np.all(arr['E'] == n - np.arange(n)) assert np.all(arr['wgt'] == 1.0) assert np.all(arr['delayed_group'] == 0) - assert np.all(arr['particle'] == 2112) # PDG number for neutron - - # Ensure sites read in are consistent - sites = openmc.ParticleList.from_hdf5('test_source.h5') - - xs = np.array([site.r[0] for site in sites]) - ys = np.array([site.r[1] for site in sites]) - zs = np.array([site.r[2] for site in sites]) - assert np.all((xs > 0.0) & (xs < 1.0)) - assert np.all(ys == np.arange(1000)) - assert np.all(zs == 0.0) - u = np.array([s.u for s in sites]) - assert np.all(u[..., 0] == 0.0) - assert np.all(u[..., 1] == 0.0) - assert np.all(u[..., 2] == 1.0) - E = np.array([s.E for s in sites]) - assert np.all(E == n - np.arange(n)) - wgt = np.array([s.wgt for s in sites]) - assert np.all(wgt == 1.0) - dgs = np.array([s.delayed_group for s in sites]) - assert np.all(dgs == 0) - p_types = np.array([s.particle for s in sites]) - assert np.all(p_types == 2112) # PDG number for neutron - - # Ensure a ParticleList item is a SourceParticle - site = sites[0] - assert isinstance(site, openmc.SourceParticle) - assert site.E == pytest.approx(n) - - # Ensure site slice read in and exported are consistent - sites_slice = sites[:10] - sites_slice.export_to_hdf5("test_source_slice.h5") - sites_slice = openmc.ParticleList.from_hdf5('test_source_slice.h5') - - assert isinstance(sites_slice, openmc.ParticleList) - assert len(sites_slice) == 10 - E = np.array([s.E for s in sites_slice]) - np.testing.assert_allclose(E, n - np.arange(10)) - - # Ensure site list read in and exported are consistent - df = sites.to_dataframe() - sites_filtered = sites[df[df.E <= 10.0].index.tolist()] - sites_filtered.export_to_hdf5("test_source_filtered.h5") - sites_filtered = openmc.read_source_file('test_source_filtered.h5') - - assert isinstance(sites_filtered, openmc.ParticleList) - assert len(sites_filtered) == 10 - E = np.array([s.E for s in sites_filtered]) - np.testing.assert_allclose(E, np.arange(10, 0, -1)) + assert np.all(arr['particle'] == 0) def test_wrong_source_attributes(run_in_tmpdir): @@ -102,7 +54,7 @@ def test_wrong_source_attributes(run_in_tmpdir): ]) arr = np.array([(1.0, 2.0, 3), (4.0, 5.0, 6), (7.0, 8.0, 9)], dtype=source_dtype) with h5py.File('animal_source.h5', 'w') as fh: - fh.attrs['filetype'] = np.bytes_("source") + fh.attrs['filetype'] = np.string_("source") fh.create_dataset('source_bank', data=arr) # Create a simple model that uses this lovely animal source @@ -115,7 +67,7 @@ def test_wrong_source_attributes(run_in_tmpdir): settings = openmc.Settings() settings.particles = 100 settings.batches = 10 - settings.source = openmc.FileSource(path='animal_source.h5') + settings.source = openmc.Source(filename='animal_source.h5') settings.export_to_xml() # When we run the model, it should error out with a message that includes @@ -123,49 +75,3 @@ def test_wrong_source_attributes(run_in_tmpdir): with pytest.raises(RuntimeError) as excinfo: openmc.run() assert 'platypus, axolotl, narwhal' in str(excinfo.value) - - -def test_source_file_transport(run_in_tmpdir): - # Create a source file with a single particle - particle = openmc.SourceParticle() - openmc.write_source_file([particle], 'source.h5') - - # Created simple model to use source file - model = openmc.Model() - al = openmc.Material() - al.add_element('Al', 1.0) - al.set_density('g/cm3', 2.7) - sph = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=al, region=-sph) - model.geometry = openmc.Geometry([cell]) - model.settings.source = openmc.FileSource(path='source.h5') - model.settings.particles = 10 - model.settings.batches = 3 - model.settings.run_mode = 'fixed source' - - # Try running OpenMC - model.run() - - -def test_source_file_photon_transport(run_in_tmpdir): - # Create a source file containing a photon. Note that photon_transport is - # not explicitly enabled in the settings -- it should be turned on - # automatically because the source file contains a photon. - particle = openmc.SourceParticle(E=1.0e6, particle='photon') - openmc.write_source_file([particle], 'photon_source.h5') - - # Create simple model to use the photon source file - model = openmc.Model() - al = openmc.Material() - al.add_element('Al', 1.0) - al.set_density('g/cm3', 2.7) - sph = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=al, region=-sph) - model.geometry = openmc.Geometry([cell]) - model.settings.source = openmc.FileSource(path='photon_source.h5') - model.settings.particles = 10 - model.settings.batches = 3 - model.settings.run_mode = 'fixed source' - - # Running OpenMC should succeed - model.run() diff --git a/tests/unit_tests/test_source_mesh.py b/tests/unit_tests/test_source_mesh.py deleted file mode 100644 index 2550cb87e..000000000 --- a/tests/unit_tests/test_source_mesh.py +++ /dev/null @@ -1,444 +0,0 @@ -from itertools import product -from pathlib import Path -from math import sqrt -import random - -import pytest -import numpy as np -import openmc -import openmc.lib - -from tests import cdtemp - - -################### -# MeshSpatial Tests -################### -TETS_PER_VOXEL = 12 - -# This test uses a geometry file with cells that match a regular mesh. Each cell -# in the geometry corresponds to 12 tetrahedra in the unstructured mesh file. -@pytest.fixture -def model(): - openmc.reset_auto_ids() - - ### Materials ### - materials = openmc.Materials() - - water_mat = openmc.Material(name="water") - water_mat.add_nuclide("H1", 2.0) - water_mat.add_nuclide("O16", 1.0) - water_mat.set_density("atom/b-cm", 0.07416) - materials.append(water_mat) - - ### Geometry ### - # This test uses a geometry file that resembles a regular mesh. - # 12 tets are used to match each voxel in the geometry. - - # create a regular mesh that matches the superimposed mesh - regular_mesh = openmc.RegularMesh(mesh_id=10) - regular_mesh.lower_left = (-10, -10, -10) - regular_mesh.dimension = (10, 10, 10) - regular_mesh.width = (2, 2, 2) - - root_cell, _ = regular_mesh.build_cells(bc=['vacuum']*6) - - geometry = openmc.Geometry(root=[root_cell]) - - ### Settings ### - settings = openmc.Settings() - settings.run_mode = 'fixed source' - settings.particles = 100 - settings.batches = 2 - - return openmc.Model(geometry=geometry, - materials=materials, - settings=settings) - -### Setup test cases ### -param_values = (['libmesh', 'moab'], # mesh libraries - ['uniform', 'manual']) # Element weighting schemes - -test_cases = [] -for i, (lib, schemes) in enumerate(product(*param_values)): - test_cases.append({'library' : lib, - 'source_strengths' : schemes}) - -def ids(params): - """Test naming function for clarity""" - return f"{params['library']}-{params['source_strengths']}" - -@pytest.mark.parametrize("test_cases", test_cases, ids=ids) -def test_unstructured_mesh_sampling(model, request, test_cases): - # skip the test if the library is not enabled - if test_cases['library'] == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip("DAGMC (and MOAB) mesh not enabled in this build.") - - if test_cases['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): - pytest.skip("LibMesh is not enabled in this build.") - - # setup mesh source ### - mesh_filename = Path(request.fspath).parent / "test_mesh_tets.e" - uscd_mesh = openmc.UnstructuredMesh(mesh_filename, test_cases['library']) - - # subtract one to account for root cell produced by RegularMesh.build_cells - n_cells = len(model.geometry.get_all_cells()) - 1 - - # set source weights according to test case - if test_cases['source_strengths'] == 'uniform': - vol_norm = True - strengths = None - elif test_cases['source_strengths'] == 'manual': - vol_norm = False - # assign random weights - strengths = np.random.rand(n_cells*TETS_PER_VOXEL) - - # create the spatial distribution based on the mesh - space = openmc.stats.MeshSpatial(uscd_mesh, strengths, vol_norm) - - energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.IndependentSource(space=space, energy=energy) - model.settings.source = source - - with cdtemp([mesh_filename]): - model.export_to_xml() - - n_measurements = 100 - n_samples = 1000 - - cell_counts = np.zeros((n_cells, n_measurements)) - - # This model contains 1000 geometry cells. Each cell is a hex - # corresponding to 12 of the tets. This test runs 1000 samples. This - # results in the following average for each cell - openmc.lib.init([]) - - # perform many sets of samples and track counts for each cell - for m in range(n_measurements): - sites = openmc.lib.sample_external_source(n_samples) - cells = [openmc.lib.find_cell(s.r) for s in sites] - - for c in cells: - # subtract one from index to account for root cell - cell_counts[c[0]._index - 1, m] += 1 - - # make sure particle transport is successful - openmc.lib.run() - openmc.lib.finalize() - - # normalize cell counts to get sampling frequency per particle - cell_counts /= n_samples - - # get the mean and std. dev. of the cell counts - mean = cell_counts.mean(axis=1) - std_dev = cell_counts.std(axis=1) - - if test_cases['source_strengths'] == 'uniform': - exp_vals = np.ones(n_cells) / n_cells - else: - # sum up the source strengths for each tet, these are the expected true mean - # of the sampling frequency for that cell - exp_vals = strengths.reshape(-1, 12).sum(axis=1) / sum(strengths) - - diff = np.abs(mean - exp_vals) - assert((diff < 2*std_dev).sum() / diff.size >= 0.95) - assert((diff < 6*std_dev).sum() / diff.size >= 0.997) - - -def test_strengths_size_failure(request, model): - # setup mesh source ### - mesh_filename = Path(request.fspath).parent / "test_mesh_tets.e" - uscd_mesh = openmc.UnstructuredMesh(mesh_filename, 'libmesh') - - # intentionally incorrectly sized to trigger an error - n_cells = len(model.geometry.get_all_cells()) - strengths = np.random.rand(n_cells*TETS_PER_VOXEL) - - # create the spatial distribution based on the mesh - space = openmc.stats.MeshSpatial(uscd_mesh, strengths) - - energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.IndependentSource(space=space, energy=energy) - model.settings.source = source - - # skip the test if unstructured mesh is not available - if not openmc.lib._libmesh_enabled(): - if openmc.lib._dagmc_enabled(): - source.space.mesh.library = 'moab' - else: - pytest.skip("Unstructured mesh support unavailable.") - - # make sure that an incorrrectly sized strengths array causes a failure - source.space.strengths = source.space.strengths[:-1] - - mesh_filename = Path(request.fspath).parent / source.space.mesh.filename - - with pytest.raises(RuntimeError, match=r'strengths array'), cdtemp([mesh_filename]): - model.export_to_xml() - openmc.run() - - -def test_roundtrip(run_in_tmpdir, model, request): - if not openmc.lib._libmesh_enabled() and not openmc.lib._dagmc_enabled(): - pytest.skip("Unstructured mesh is not enabled in this build.") - - mesh_filename = Path(request.fspath).parent / 'test_mesh_tets.e' - ucd_mesh = openmc.UnstructuredMesh(mesh_filename, library='libmesh') - - if not openmc.lib._libmesh_enabled(): - ucd_mesh.library = 'moab' - - n_cells = len(model.geometry.get_all_cells()) - - space_out = openmc.MeshSpatial(ucd_mesh) - space_out.strengths = np.random.rand(n_cells*TETS_PER_VOXEL) - model.settings.source = openmc.IndependentSource(space=space_out) - - # write out the model - model.export_to_xml() - - model_in = openmc.Model.from_xml() - - space_in = model_in.settings.source[0].space - - np.testing.assert_equal(space_out.strengths, space_in.strengths) - - assert space_in.mesh.id == space_out.mesh.id - assert space_in.volume_normalized == space_out.volume_normalized - - -################### -# MeshSource tests -################### -@pytest.fixture -def void_model(): - """ - A void model containing a single box - """ - model = openmc.Model() - - box = openmc.model.RectangularParallelepiped(*[-10, 10]*3, boundary_type='vacuum') - model.geometry = openmc.Geometry([openmc.Cell(region=-box)]) - - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.run_mode = 'fixed source' - - return model - - -@pytest.mark.parametrize('mesh_type', ('rectangular', 'cylindrical')) -def test_mesh_source_independent(run_in_tmpdir, void_model, mesh_type): - """ - A void model containing a single box - """ - model = void_model - - # define a 2 x 2 x 2 mesh - if mesh_type == 'rectangular': - mesh = openmc.RegularMesh.from_domain(model.geometry, (2, 2, 2)) - elif mesh_type == 'cylindrical': - mesh = openmc.CylindricalMesh.from_domain(model.geometry, (1, 4, 2)) - - energy = openmc.stats.Discrete([1.e6], [1.0]) - - # create sources with only one non-zero strength for the source in the mesh - # voxel occupying the lowest octant. Direct source particles straight out of - # the problem from there. This demonstrates that - # 1) particles are only being sourced within the intented mesh voxel based - # on source strength - # 2) particles are respecting the angle distributions assigned to each voxel - sources = np.empty(mesh.dimension, dtype=openmc.SourceBase) - centroids = mesh.centroids - x, y, z = np.swapaxes(mesh.centroids, -1, 0) - for i, j, k in mesh.indices: - # mesh.indices is currently one-indexed, adjust for Python arrays - ijk = (i-1, j-1, k-1) - - # get the centroid of the ijk mesh element and use it to set the - # direction of the source directly out of the problem - centroid = centroids[ijk] - vec = np.sign(centroid, dtype=float) - vec /= np.linalg.norm(vec) - angle = openmc.stats.Monodirectional(vec) - sources[ijk] = openmc.IndependentSource(energy=energy, angle=angle, strength=0.0) - - # create and apply the mesh source - mesh_source = openmc.MeshSource(mesh, sources) - model.settings.source = mesh_source - - # tally the flux on the mesh - mesh_filter = openmc.MeshFilter(mesh) - tally = openmc.Tally() - tally.filters = [mesh_filter] - tally.scores = ['flux'] - - model.tallies = openmc.Tallies([tally]) - - # for each element, set a single-non zero source with particles - # traveling out of the mesh (and geometry) w/o crossing any other - # mesh elements - for flat_index, (i, j, k) in enumerate(mesh.indices): - ijk = (i-1, j-1, k-1) - # zero-out all source strengths and set the strength - # on the element of interest - mesh_source.strength = 0.0 - mesh_source.sources[flat_index].strength = 1.0 - - sp_file = model.run() - - with openmc.StatePoint(sp_file) as sp: - tally_out = sp.get_tally(id=tally.id) - mean = tally_out.get_reshaped_data(expand_dims=True) - - # remove nuclides and scores axes - mean = mean[..., 0, 0] - # the mesh elment with a non-zero source strength should have a value - assert mean[ijk] != 0 - # all other values should be zero - mean[ijk] = 0 - assert np.all(mean == 0), f'Failed on index {ijk} with centroid {mesh.centroids[ijk]}' - - # test roundtrip - xml_model = openmc.Model.from_model_xml() - xml_source = xml_model.settings.source[0] - assert isinstance(xml_source, openmc.MeshSource) - assert xml_source.strength == 1.0 - assert isinstance(xml_source.mesh, type(mesh_source.mesh)) - assert xml_source.mesh.dimension == mesh_source.mesh.dimension - assert xml_source.mesh.id == mesh_source.mesh.id - assert len(xml_source.sources) == len(mesh_source.sources) - - # check strength adjustment methods - assert mesh_source.strength == 1.0 - mesh_source.strength = 100.0 - assert mesh_source.strength == 100.0 - - mesh_source.normalize_source_strengths() - assert mesh_source.strength == 1.0 - - -@pytest.mark.parametrize("library", ('moab', 'libmesh')) -def test_umesh_source_independent(run_in_tmpdir, request, void_model, library): - import openmc.lib - # skip the test if the library is not enabled - if library == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip("DAGMC (and MOAB) mesh not enabled in this build.") - - if library == 'libmesh' and not openmc.lib._libmesh_enabled(): - pytest.skip("LibMesh is not enabled in this build.") - - model = void_model - - mesh_filename = Path(request.fspath).parent / "test_mesh_tets.e" - uscd_mesh = openmc.UnstructuredMesh(mesh_filename, library) - ind_source = openmc.IndependentSource() - n_elements = 12_000 - model.settings.source = openmc.MeshSource(uscd_mesh, n_elements*[ind_source]) - model.export_to_model_xml() - with openmc.lib.run_in_memory(): - openmc.lib.simulation_init() - sites = openmc.lib.sample_external_source(10) - openmc.lib.statepoint_write('statepoint.h5') - - with openmc.StatePoint('statepoint.h5') as sp: - uscd_mesh = sp.meshes[uscd_mesh.id] - - # ensure at least that all sites are inside the mesh - bounding_box = uscd_mesh.bounding_box - for site in sites: - assert site.r in bounding_box - - -def test_mesh_source_constraints(run_in_tmpdir): - """Test application of constraints to underlying mesh element sources""" - - # Create simple model with two cells - m1 = openmc.Material() - m1.add_nuclide('H1', 1.0) - m2 = m1.clone() - sph = openmc.Sphere(r=100, boundary_type='vacuum') - box1 = openmc.model.RectangularParallelepiped(-1, 0, -1, 1, -1, 1) - box2 = openmc.model.RectangularParallelepiped(0, 2, -1, 1, -1, 1) - cell1 = openmc.Cell(fill=m1, region=-box1) - cell2 = openmc.Cell(fill=m2, region=-box2) - outer = openmc.Cell(region=-sph & (+box1 | +box2)) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2, outer]) - - # Define a mesh covering the two cells: the first mesh element contains - # cell1 (-1 < x < 0) and the second element contains cells2 (0 < x < 2) - mesh = openmc.RegularMesh() - mesh.lower_left = (-3., -1., -1.) - mesh.upper_right = (3., 1., 1.) - mesh.dimension = (2, 1, 1) - - # Define a mesh source with a randomly chosen probability - p = random.random() - src1 = openmc.IndependentSource(strength=p, constraints={'domains': [cell1]}) - src2 = openmc.IndependentSource(strength=1 - p, constraints={'domains': [cell2]}) - model.settings.source = openmc.MeshSource(mesh, [src1, src2]) - - # Finish settings and export - model.settings.particles = 100 - model.settings.batches = 1 - model.export_to_model_xml() - - with openmc.lib.run_in_memory(): - # Sample sites from the source - sites = openmc.lib.sample_external_source(N := 1000) - - # Check that all sites are either in cell1 or cell2 - xs = np.array([s.r[0] for s in sites]) - assert (xs >= -1.0).all() - assert (xs <= 2.0).all() - - # Check that the correct percentage of the sites are in cell1 - sigma = sqrt(p*(1- p)/N) - frac = xs[(-1.0 <= xs) & (xs <= 0.0)].size / N - assert frac == pytest.approx(p, abs=5*sigma) - - -@pytest.mark.parametrize("mesh_type", ('rectangular', 'cylindrical', 'spherical')) -def test_mesh_spatial(run_in_tmpdir, mesh_type): - """Test that a spherical mesh source works as expected.""" - model = openmc.Model() - - # Set up geometry, a box that is shifted in x, y, and z - box = openmc.model.RectangularParallelepiped(5.0, 25.0, -20.0, 20.0, -30.0, 30.0, boundary_type='vacuum') - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - model.geometry = openmc.Geometry([openmc.Cell(fill=mat, region=-box)]) - - # Create a mesh of each type in turn - if mesh_type == 'rectangular': - mesh = openmc.RegularMesh.from_domain(model.geometry, (10, 2, 2)) - elif mesh_type == 'cylindrical': - mesh = openmc.CylindricalMesh.from_domain(model.geometry, (10, 2, 2)) - assert max(mesh.r_grid) == 10.0, "Cylindrical mesh radius exceeds geometry bounds" - assert mesh.origin[0] == 15.0, "Cylindrical mesh origin x-coordinate is incorrect" - elif mesh_type == 'spherical': - mesh = openmc.SphericalMesh.from_domain(model.geometry, (10, 2, 2)) - assert max(mesh.r_grid) == 10.0, "Spherical mesh radius exceeds geometry bounds" - assert mesh.origin[0] == 15.0, "Spherical mesh origin x-coordinate is incorrect" - - # Create a mesh source with a single particle - ind_source = openmc.IndependentSource(space=openmc.stats.MeshSpatial(mesh, np.prod(mesh.dimension)*[1.0])) - model.settings.source = ind_source - - model.settings.particles = 100 - model.settings.batches = 10 - model.settings.run_mode = 'fixed source' - - model.export_to_model_xml() - - openmc.lib.init() - openmc.lib.simulation_init() - sites = openmc.lib.sample_external_source(10) - openmc.lib.simulation_finalize() - openmc.lib.finalize() - - # Check that the sites are within the spherical mesh bounds - bbox = mesh.bounding_box - for site in sites: - assert site.r in bbox diff --git a/tests/unit_tests/test_source_tokamak.py b/tests/unit_tests/test_source_tokamak.py deleted file mode 100644 index f926c2007..000000000 --- a/tests/unit_tests/test_source_tokamak.py +++ /dev/null @@ -1,263 +0,0 @@ -import numpy as np -import pytest - -import openmc -import openmc.stats - -from tests.unit_tests import assert_sample_mean - - -def make_source(**kwargs): - """Build a valid TokamakSource, overriding defaults via kwargs.""" - r_over_a = np.linspace(0.0, 1.0, 10) - params = dict( - major_radius=620.0, - minor_radius=200.0, - elongation=1.8, - triangularity=0.45, - shafranov_shift=10.0, - r_over_a=r_over_a, - emission_density=(1.0 - r_over_a**2), - energy=openmc.stats.muir(e0=14.08e6, m_rat=5.0, kt=2.0e4), - ) - params.update(kwargs) - return openmc.TokamakSource(**params) - - -def test_tokamak_source_roundtrip(): - src = make_source( - phi_start=0.1, phi_extent=np.pi, n_alpha=51, vertical_shift=5.0, - strength=2.0, time=openmc.stats.Uniform(0.0, 1e-6)) - - elem = src.to_xml_element() - assert elem.get('type') == 'tokamak' - - new = openmc.SourceBase.from_xml_element(elem) - assert isinstance(new, openmc.TokamakSource) - assert new.major_radius == src.major_radius - assert new.minor_radius == src.minor_radius - assert new.elongation == src.elongation - assert new.triangularity == src.triangularity - assert new.shafranov_shift == src.shafranov_shift - assert new.phi_start == src.phi_start - assert new.phi_extent == src.phi_extent - assert new.n_alpha == src.n_alpha - assert new.vertical_shift == src.vertical_shift - assert new.strength == src.strength - np.testing.assert_allclose(new.r_over_a, src.r_over_a) - np.testing.assert_allclose(new.emission_density, src.emission_density) - assert len(new.energy) == 1 - assert isinstance(new.time, openmc.stats.Uniform) - assert new.time.a == src.time.a - assert new.time.b == src.time.b - - -def test_tokamak_source_default_time(): - src = make_source() - assert src.time is None - - new = openmc.SourceBase.from_xml_element(src.to_xml_element()) - assert new.time is None - - with pytest.raises(TypeError): - make_source(time=1.0) - - -def test_tokamak_source_multiple_energies(): - r_over_a = np.linspace(0.0, 1.0, 5) - energies = [openmc.stats.muir(e0=14.08e6, m_rat=5.0, kt=kt) - for kt in (1.0e4, 1.5e4, 2.0e4, 2.5e4, 3.0e4)] - src = make_source(r_over_a=r_over_a, - emission_density=np.ones_like(r_over_a), - energy=energies) - assert len(src.energy) == len(r_over_a) - - new = openmc.SourceBase.from_xml_element(src.to_xml_element()) - assert len(new.energy) == len(r_over_a) - - -@pytest.mark.parametrize("kwargs, match", [ - (dict(minor_radius=700.0), "smaller than major_radius"), - (dict(shafranov_shift=150.0), "half the minor_radius"), - (dict(emission_density=np.ones(5)), "same length as r_over_a"), - (dict(energy=[openmc.stats.muir(14.08e6, 5.0, 2.0e4)] * 2), - "Number of energy distributions"), - (dict(r_over_a=np.linspace(0.1, 1.0, 10)), "must start at 0"), - (dict(r_over_a=np.linspace(0.0, 0.9, 10)), "must end at 1"), - (dict(emission_density=-np.linspace(0.0, 1.0, 10)), "cannot be negative"), - (dict(emission_density=np.zeros(10)), "must contain a positive value"), -]) -def test_tokamak_source_invalid(kwargs, match): - with pytest.raises(ValueError, match=match): - make_source(**kwargs) - - -@pytest.mark.parametrize("value", [-1.5, 1.5]) -def test_tokamak_source_invalid_triangularity(value): - with pytest.raises(ValueError): - make_source(triangularity=value) - - -def test_tokamak_source_invalid_n_alpha(): - with pytest.raises(ValueError): - make_source(n_alpha=2) - - -@pytest.mark.parametrize(("attribute", "value", "match"), [ - ("minor_radius", 700.0, "smaller than major_radius"), - ("shafranov_shift", 150.0, "half the minor_radius"), - ("emission_density", np.ones(5), "same length as r_over_a"), - ("energy", [openmc.stats.delta_function(1.0)] * 2, - "Number of energy distributions"), -]) -def test_tokamak_source_mutation_validation(attribute, value, match): - src = make_source() - setattr(src, attribute, value) - with pytest.raises(ValueError, match=match): - src.to_xml_element() - - -@pytest.mark.parametrize(("emission_density", "expected_mean"), [ - ([1.0, 1.0], 2.0 / 3.0), - ([1.0, 0.0], 0.5), -]) -def test_tokamak_source_radial_sampling( - run_in_tmpdir, emission_density, expected_mean -): - """Check radial sampling for profiles on the coarsest valid grid.""" - major_radius = 620.0 - minor_radius = 200.0 - src = make_source( - major_radius=major_radius, - minor_radius=minor_radius, - elongation=1.0, - triangularity=0.0, - shafranov_shift=0.0, - r_over_a=[0.0, 1.0], - emission_density=emission_density, - energy=openmc.stats.delta_function(14.07e6), - ) - - sphere = openmc.Sphere(r=2000.0, boundary_type='vacuum') - model = openmc.Model( - geometry=openmc.Geometry([openmc.Cell(region=-sphere)]), - settings=openmc.Settings( - particles=100, batches=1, run_mode='fixed source', source=src), - ) - - sites = model.sample_external_source(20_000) - xyz = np.array([site.r for site in sites]) - major_r = np.hypot(xyz[:, 0], xyz[:, 1]) - r_over_a = np.hypot(major_r - major_radius, xyz[:, 2]) / minor_radius - assert_sample_mean(r_over_a, expected_mean) - - -def test_tokamak_source_poloidal_sampling(run_in_tmpdir): - """Check linear-linear poloidal sampling on a coarse internal grid.""" - major_radius = 620.0 - minor_radius = 200.0 - with pytest.warns(UserWarning, match="below 51"): - src = make_source( - major_radius=major_radius, - minor_radius=minor_radius, - elongation=1.0, - triangularity=0.0, - shafranov_shift=0.0, - emission_density=np.ones(10), - n_alpha=3, - energy=openmc.stats.delta_function(14.07e6), - ) - - sphere = openmc.Sphere(r=2000.0, boundary_type='vacuum') - model = openmc.Model( - geometry=openmc.Geometry([openmc.Cell(region=-sphere)]), - settings=openmc.Settings( - particles=100, batches=1, run_mode='fixed source', source=src), - ) - - sites = model.sample_external_source(100_000) - xyz = np.array([site.r for site in sites]) - major_r = np.hypot(xyz[:, 0], xyz[:, 1]) - - # With three alpha points, linear interpolation of cos(alpha) on [0, pi] - # gives 1 - 2*alpha/pi. Integrating the resulting density gives this mean. - expected_R = ( - major_radius - + 2.0 * minor_radius**2 / (np.pi**2 * major_radius) - ) - assert_sample_mean(major_r, expected_R) - - -@pytest.mark.flaky(reruns=1) -def test_tokamak_source_sampling(run_in_tmpdir): - """Exercise the compiled C++ sampling path and check invariants. - - Sampled moments are compared against direct numerical quadrature of the - exact source density S(r)*R*|J|, where the Jacobian J of the flux-surface - map is computed from analytic partial derivatives. This check is - independent of the Bernstein-mixture factorization used by the - implementation. - """ - R0, a, kappa, delta = 620.0, 200.0, 1.8, -0.5 - shafranov, zshift = 40.0, 25.0 - phi_start, phi_extent = 0.5, np.pi / 2 - - # Fine grids to make discretization error negligible relative to - # statistical uncertainty - r_over_a = np.linspace(0.0, 1.0, 200) - src = make_source( - major_radius=R0, minor_radius=a, elongation=kappa, - triangularity=delta, shafranov_shift=shafranov, vertical_shift=zshift, - r_over_a=r_over_a, emission_density=1.0 - r_over_a**2, - phi_start=phi_start, phi_extent=phi_extent, n_alpha=201, - energy=openmc.stats.delta_function(14.07e6)) - - sphere = openmc.Sphere(r=2000.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere) - settings = openmc.Settings( - particles=100, batches=1, run_mode='fixed source', source=src) - model = openmc.Model(geometry=openmc.Geometry([cell]), settings=settings) - - n_samples = 20_000 - sites = model.sample_external_source(n_samples) - - xyz = np.array([s.r for s in sites]) - R = np.hypot(xyz[:, 0], xyz[:, 1]) - z = xyz[:, 2] - - # Energy, weight, and time invariants - assert np.all([s.E == 14.07e6 for s in sites]) - assert np.all([s.wgt == 1.0 for s in sites]) - assert np.all([s.time == 0.0 for s in sites]) - - # Toroidal angle within the requested sector - phi = np.arctan2(xyz[:, 1], xyz[:, 0]) - assert phi.min() >= phi_start - assert phi.max() <= phi_start + phi_extent - - # Positions bounded by the last closed flux surface - assert R.min() >= R0 - a - assert R.max() <= R0 + a + shafranov - assert np.abs(z - zshift).max() <= kappa * a - - # Up-down symmetry about the vertical shift - assert_sample_mean(z, zshift) - - # Reference moments by 2D quadrature of the exact density - r = np.linspace(0.0, 1.0, 1001)[:, np.newaxis] # r/a - alpha = np.linspace(0.0, 2 * np.pi, 2001)[np.newaxis, :] - psi = alpha + delta * np.sin(alpha) - R_map = R0 + a * r * np.cos(psi) + shafranov * (1.0 - r**2) - Z_map = kappa * a * r * np.sin(alpha) - dR_dr = a * np.cos(psi) - 2.0 * shafranov * r - dR_da = -a * r * np.sin(psi) * (1.0 + delta * np.cos(alpha)) - dZ_dr = kappa * a * np.sin(alpha) * np.ones_like(psi) - dZ_da = kappa * a * r * np.cos(alpha) - jac = np.abs(dR_dr * dZ_da - dR_da * dZ_dr) - dens = (1.0 - r**2) * R_map * jac - norm = dens.sum() - expected_R = (R_map * dens).sum() / norm - expected_z2 = (Z_map**2 * dens).sum() / norm - - assert_sample_mean(R, expected_R) - assert_sample_mean((z - zshift)**2, expected_z2) diff --git a/tests/unit_tests/test_spherical_mesh.py b/tests/unit_tests/test_spherical_mesh.py deleted file mode 100644 index a95a4151a..000000000 --- a/tests/unit_tests/test_spherical_mesh.py +++ /dev/null @@ -1,206 +0,0 @@ -from itertools import product, permutations - -import openmc -import numpy as np - -import pytest - -geom_size = 5 - -@pytest.fixture() -def model(): - openmc.reset_auto_ids() - - water = openmc.Material(name='water') - water.add_element('H', 2.0) - water.add_element('O', 1.0) - water.set_density('g/cc', 1.0) - - rpp = openmc.model.RectangularParallelepiped(*([-geom_size, geom_size] * 3), - boundary_type='vacuum') - - cell = openmc.Cell(region=-rpp, fill=water) - - geom = openmc.Geometry([cell]) - - source = openmc.IndependentSource() - source.space = openmc.stats.Point() - source.energy = openmc.stats.Discrete([10000], [1.0]) - - settings = openmc.Settings() - settings.particles = 2000 - settings.batches = 10 - settings.run_mode = 'fixed source' - - # build - mesh = openmc.SphericalMesh( - phi_grid=np.linspace(0, 2*np.pi, 13), - theta_grid=np.linspace(0, np.pi, 7), - r_grid=np.linspace(0, geom_size, geom_size), - ) - tally = openmc.Tally() - - mesh_filter = openmc.MeshFilter(mesh) - tally.filters.append(mesh_filter) - - tally.scores.append("flux") - - tallies = openmc.Tallies([tally]) - - return openmc.Model(geometry=geom, settings=settings, tallies=tallies) - -def test_origin_read_write_to_xml(run_in_tmpdir, model): - """Tests that the origin attribute can be written and read back to XML - """ - mesh = model.tallies[0].filters[0].mesh - mesh.origin = [0.1, 0.2, 0.3] - model.tallies.export_to_xml() - - # read back - new_tallies = openmc.Tallies.from_xml() - new_tally = new_tallies[0] - new_mesh = new_tally.filters[0].mesh - np.testing.assert_equal(new_mesh.origin, mesh.origin) - -estimators = ('tracklength', 'collision') -offset = geom_size + 0.001 - -origins = set(permutations((-offset, 0, 0))) -origins |= set(permutations((offset, 0, 0))) - -test_cases = product(estimators, origins) - -def label(p): - if isinstance(p, tuple): - return f'origin:{p}' - if isinstance(p, str): - return f'estimator:{p}' - -@pytest.mark.parametrize('estimator,origin', test_cases, ids=label) -def test_offset_mesh(run_in_tmpdir, model, estimator, origin): - """Tests that the mesh has been moved based on tally results - """ - mesh = model.tallies[0].filters[0].mesh - model.tallies[0].estimator = estimator - # move the center of the spherical mesh - mesh.origin = origin - - sp_filename = model.run() - - with openmc.StatePoint(sp_filename) as sp: - tally = sp.tallies[1] - - # we've translated half of the spherical mesh above the model, - # so ensure that half of the bins are populated - assert np.count_nonzero(tally.mean) == tally.mean.size / 2 - - # check that the half of the mesh that is outside of the geometry - # contains the zero values - mean = tally.get_reshaped_data('mean', expand_dims=True) - centroids = mesh.centroids - for ijk in mesh.indices: - i, j, k = np.array(ijk) - 1 - if model.geometry.find(centroids[i, j, k]): - mean[i, j, k] == 0.0 - else: - mean[i, j, k] != 0.0 - -# Some void geometry tests to check our radial intersection methods on -# spherical and cylindrical meshes - -@pytest.fixture() -def void_coincident_geom_model(): - """A model with many geometric boundaries coincident with mesh boundaries - across many scales - """ - openmc.reset_auto_ids() - - model = openmc.Model() - - model.materials = openmc.Materials() - radii = [0.1, 1, 5, 50, 100, 150, 250] - spheres = [openmc.Sphere(r=ri) for ri in radii] - spheres[-1].boundary_type = 'vacuum' - - regions = openmc.model.subdivide(spheres)[:-1] - cells = [openmc.Cell(region=r, fill=None) for r in regions] - geom = openmc.Geometry(cells) - - model.geometry = geom - - settings = openmc.Settings(run_mode='fixed source') - settings.batches = 2 - settings.particles = 5000 - model.settings = settings - - mesh = openmc.SphericalMesh(r_grid=np.linspace(0, 250, 501)) - mesh_filter = openmc.MeshFilter(mesh) - - tally = openmc.Tally() - tally.scores = ['flux'] - tally.filters = [mesh_filter] - - model.tallies = openmc.Tallies([tally]) - - return model - - -# convenience function for checking tally results -# in the following tests -def _check_void_spherical_tally(statepoint_filename): - with openmc.StatePoint(statepoint_filename) as sp: - flux_tally = sp.tallies[1] - mesh = flux_tally.find_filter(openmc.MeshFilter).mesh - neutron_flux = flux_tally.get_reshaped_data().squeeze() - # the flux values for each bin should equal the width - # width of the mesh bins - d_r = mesh.r_grid[1] - mesh.r_grid[0] - assert neutron_flux == pytest.approx(d_r) - - -def test_void_geom_pnt_src(run_in_tmpdir, void_coincident_geom_model): - # add isotropic point source - src = openmc.IndependentSource() - src.space = openmc.stats.Point() - src.energy = openmc.stats.Discrete([14.06e6], [1]) - void_coincident_geom_model.settings.source = src - - # run model and check tally results - sp_filename = void_coincident_geom_model.run() - _check_void_spherical_tally(sp_filename) - - -def test_void_geom_boundary_src(run_in_tmpdir, void_coincident_geom_model): - # update source to a number of points on the outside of the sphere - # with directions pointing toward the origin - n_sources = 20 - phi_vals = np.linspace(0, np.pi, n_sources) - theta_vals = np.linspace(0, 2.0*np.pi, n_sources) - - bbox = void_coincident_geom_model.geometry.bounding_box - # can't source particles directly on the geometry boundary - outer_r = bbox[1][0] - 1e-08 - - sources = [] - - energy = openmc.stats.Discrete([14.06e6], [1]) - - for phi, theta in zip(phi_vals, theta_vals): - - src = openmc.IndependentSource() - src.energy = energy - - pnt = np.array([np.sin(phi)*np.cos(theta), np.sin(phi)*np.sin(theta), np.cos(phi)]) - u = -pnt - src.space = openmc.stats.Point(outer_r*pnt) - src.angle = openmc.stats.Monodirectional(u) - # set source strengths so that we can still expect - # a tally value of 0.5 - src.strength = 0.5/n_sources - - sources.append(src) - - void_coincident_geom_model.settings.source = sources - - sp_filename = void_coincident_geom_model.run() - _check_void_spherical_tally(sp_filename) diff --git a/tests/unit_tests/test_statepoint.py b/tests/unit_tests/test_statepoint.py deleted file mode 100644 index 7ffaf7ec2..000000000 --- a/tests/unit_tests/test_statepoint.py +++ /dev/null @@ -1,65 +0,0 @@ -import openmc - - -def test_get_tally_filter_type(run_in_tmpdir): - """Test various ways of retrieving tallies from a StatePoint object.""" - - mat = openmc.Material() - mat.add_nuclide("H1", 1.0) - mat.set_density("g/cm3", 10.0) - - sphere = openmc.Sphere(r=10.0, boundary_type="vacuum") - cell = openmc.Cell(fill=mat, region=-sphere) - geometry = openmc.Geometry([cell]) - - settings = openmc.Settings() - settings.particles = 10 - settings.batches = 2 - settings.run_mode = "fixed source" - - reg_mesh = openmc.RegularMesh().from_domain(cell) - tally1 = openmc.Tally(tally_id=1) - mesh_filter = openmc.MeshFilter(reg_mesh) - tally1.filters = [mesh_filter] - tally1.scores = ["flux"] - - tally2 = openmc.Tally(tally_id=2, name="heating tally") - cell_filter = openmc.CellFilter(cell) - tally2.filters = [cell_filter] - tally2.scores = ["heating"] - - tallies = openmc.Tallies([tally1, tally2]) - model = openmc.Model( - geometry=geometry, materials=[mat], settings=settings, tallies=tallies - ) - - sp_filename = model.run() - - sp = openmc.StatePoint(sp_filename) - - tally_found = sp.get_tally(filter_type=openmc.MeshFilter) - assert tally_found.id == 1 - - tally_found = sp.get_tally(filter_type=openmc.CellFilter) - assert tally_found.id == 2 - - tally_found = sp.get_tally(filters=[mesh_filter]) - assert tally_found.id == 1 - - tally_found = sp.get_tally(filters=[cell_filter]) - assert tally_found.id == 2 - - tally_found = sp.get_tally(scores=["heating"]) - assert tally_found.id == 2 - - tally_found = sp.get_tally(name="heating tally") - assert tally_found.id == 2 - - tally_found = sp.get_tally(name=None) - assert tally_found.id == 1 - - tally_found = sp.get_tally(id=1) - assert tally_found.id == 1 - - tally_found = sp.get_tally(id=2) - assert tally_found.id == 2 diff --git a/tests/unit_tests/test_statepoint_batches.py b/tests/unit_tests/test_statepoint_batches.py deleted file mode 100644 index bf54e1878..000000000 --- a/tests/unit_tests/test_statepoint_batches.py +++ /dev/null @@ -1,26 +0,0 @@ -from pathlib import Path - -import openmc - - -def test_statepoint_batches(run_in_tmpdir): - # Create a minimal model - mat = openmc.Material() - mat.add_nuclide('U235', 1.0) - mat.set_density('g/cm3', 4.5) - sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sphere) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 100 - - # Specify when statepoints should be written - model.settings.statepoint = {'batches': [3, 6, 9]} - - # Run model and ensure that statepoints are created - model.run() - sp_files = ['statepoint.03.h5', 'statepoint.06.h5', 'statepoint.09.h5'] - for f in sp_files: - assert Path(f).is_file() diff --git a/tests/unit_tests/test_stats.py b/tests/unit_tests/test_stats.py index 2754cf5d0..dbf06d0b5 100644 --- a/tests/unit_tests/test_stats.py +++ b/tests/unit_tests/test_stats.py @@ -1,17 +1,17 @@ from math import pi -from pathlib import Path import numpy as np import pytest import openmc import openmc.stats -from openmc.stats.univariate import _INTERPOLATION_SCHEMES, DecaySpectrum -from scipy.integrate import trapezoid - -from tests.unit_tests import assert_sample_mean -@pytest.mark.flaky(reruns=1) +def assert_sample_mean(samples, expected_mean): + std_dev = samples.std() / np.sqrt(samples.size) + assert np.abs(expected_mean - samples.mean()) < 3*std_dev + + + def test_discrete(): x = [0.0, 1.0, 10.0] p = [0.3, 0.2, 0.5] @@ -40,28 +40,10 @@ def test_discrete(): d3 = openmc.stats.Discrete(vals, probs) # sample discrete distribution and check that the mean of the samples is - # within 4 std. dev. of the expected mean + # within 3 std. dev. of the expected mean n_samples = 1_000_000 - samples, weights = d3.sample(n_samples) + samples = d3.sample(n_samples, seed=100) assert_sample_mean(samples, exp_mean) - assert np.all(weights == 1.0) - - # Test biased distribution - d3.bias = np.array([0.2, 0.1, 0.7]) - bias_elem = d3.to_xml_element('distribution') - d4 = openmc.stats.Univariate.from_xml_element(bias_elem) - np.testing.assert_array_equal(d4.bias, [0.2, 0.1, 0.7]) - samples, weights = d4.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, exp_mean) - assert np.all(weights != 1.0) - - -def test_delta_function(): - d = openmc.stats.delta_function(14.1e6) - assert isinstance(d, openmc.stats.Discrete) - np.testing.assert_array_equal(d.x, [14.1e6]) - np.testing.assert_array_equal(d.p, [1.0]) def test_merge_discrete(): @@ -89,51 +71,6 @@ def test_merge_discrete(): assert triple.integral() == pytest.approx(6.0) -def test_merge_discrete_with_bias(): - # Two discrete distributions with different biases - d1 = openmc.stats.Discrete([1.0, 2.0], [0.5, 0.5]) - d2 = openmc.stats.Discrete([2.0, 3.0], [0.3, 0.7], bias=[0.1, 0.9]) - - merged = openmc.stats.Discrete.merge([d1, d2], [0.6, 0.4]) - exp_mean = 0.6 * d1.mean() + 0.4 * d2.mean() - - # Verify merged distribution has correct x values - assert set(merged.x) == {1.0, 2.0, 3.0} - - # Bias should not be changed in original distributions - assert d1.bias is None - assert np.all(d2.bias == [0.1, 0.9]) - - # Sample and verify bias is applied correctly - samples, weights = merged.sample(10_000) - - # Verify weighted mean matches expected unbiased mean - assert_sample_mean(samples*weights, exp_mean) - - -def test_clip_discrete(): - # Create discrete distribution with two points that are not important, one - # because the x value is very small, and one because the p value is very - # small - d = openmc.stats.Discrete([1e-8, 1.0, 2.0, 1000.0], [3.0, 2.0, 5.0, 1e-12]) - - # Clipping the distribution should result in two points - d_clip = d.clip(1e-6) - assert d_clip.x.size == 2 - assert d_clip.p.size == 2 - - # Make sure inplace returns same object - d_same = d.clip(1e-6, inplace=True) - assert d_same is d - - with pytest.raises(ValueError): - d.clip(-1.) - - with pytest.raises(ValueError): - d.clip(5) - - -@pytest.mark.flaky(reruns=1) def test_uniform(): a, b = 10.0, 20.0 d = openmc.stats.Uniform(a, b) @@ -149,26 +86,14 @@ def test_uniform(): np.testing.assert_array_equal(t.p, [1/(b-a), 1/(b-a)]) assert t.interpolation == 'histogram' - # Sample distribution and check that the mean of the samples is within 4 + # Sample distribution and check that the mean of the samples is within 3 # std. dev. of the expected mean exp_mean = 0.5 * (a + b) n_samples = 1_000_000 - samples, weights = d.sample(n_samples) + samples = d.sample(n_samples, seed=100) assert_sample_mean(samples, exp_mean) - assert np.all(weights == 1.0) - - # Test biased distribution - d.bias = openmc.stats.PowerLaw(a, b, 2) - bias_elem = d.to_xml_element('distribution') - d2 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d2.bias, openmc.stats.PowerLaw) - samples, weights = d2.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, exp_mean) - assert np.all(weights != 1.0) -@pytest.mark.flaky(reruns=1) def test_powerlaw(): a, b, n = 10.0, 100.0, 2.0 d = openmc.stats.PowerLaw(a, b, n) @@ -180,28 +105,15 @@ def test_powerlaw(): assert d.n == n assert len(d) == 3 - # Determine mean of distribution - exp_mean = (n+1)*(b**(n+2) - a**(n+2))/((n+2)*(b**(n+1) - a**(n+1))) + exp_mean = 100.0 * (n+1) / (n+2) # sample power law distribution and check that the mean of the samples is - # within 4 std. dev. of the expected mean + # within 3 std. dev. of the expected mean n_samples = 1_000_000 - samples, weights = d.sample(n_samples) + samples = d.sample(n_samples, seed=100) assert_sample_mean(samples, exp_mean) - assert np.all(weights == 1.0) - - # Test biased distribution - d.bias = openmc.stats.Uniform(a, b) - bias_elem = d.to_xml_element('distribution') - d2 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d2.bias, openmc.stats.Uniform) - samples, weights = d2.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, exp_mean) - assert np.all(weights != 1.0) -@pytest.mark.flaky(reruns=1) def test_maxwell(): theta = 1.2895e6 d = openmc.stats.Maxwell(theta) @@ -214,30 +126,17 @@ def test_maxwell(): exp_mean = 3/2 * theta # sample maxwell distribution and check that the mean of the samples is - # within 4 std. dev. of the expected mean + # within 3 std. dev. of the expected mean n_samples = 1_000_000 - samples, weights = d.sample(n_samples) + samples = d.sample(n_samples, seed=100) assert_sample_mean(samples, exp_mean) - assert np.all(weights == 1.0) - # A second sample starting from a different seed - samples_2, weights_2 = d.sample(n_samples) + # A second sample with a different seed + samples_2 = d.sample(n_samples, seed=200) assert_sample_mean(samples_2, exp_mean) assert samples_2.mean() != samples.mean() - assert np.all(weights_2 == 1) - - # Test biased distribution - d.bias = openmc.stats.Maxwell((theta * 1.1)) - bias_elem = d.to_xml_element('distribution') - d2 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d2.bias, openmc.stats.Maxwell) - samples, weights = d2.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, exp_mean) - assert np.all(weights != 1.0) -@pytest.mark.flaky(reruns=1) def test_watt(): a, b = 0.965e6, 2.29e-6 d = openmc.stats.Watt(a, b) @@ -255,87 +154,15 @@ def test_watt(): exp_mean = 3/2 * a + a**2 * b / 4 # sample Watt distribution and check that the mean of the samples is within - # 4 std. dev. of the expected mean + # 3 std. dev. of the expected mean n_samples = 1_000_000 - samples, weights = d.sample(n_samples) + samples = d.sample(n_samples, seed=100) assert_sample_mean(samples, exp_mean) - assert np.all(weights == 1.0) - - # Test biased distribution with 5 percent higher T_e - d.bias = openmc.stats.Watt(a*1.05, b) - bias_elem = d.to_xml_element('distribution') - d2 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d2.bias, openmc.stats.Watt) - samples, weights = d2.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, exp_mean) - assert np.all(weights != 1.0) -@pytest.mark.flaky(reruns=1) def test_tabular(): - # test linear-linear sampling - x = np.array([0.001, 5.0, 7.0, 10.0]) - p = np.array([10.0, 20.0, 5.0, 6.0]) - d = openmc.stats.Tabular(x, p, 'linear-linear') - n_samples = 100_000 - samples, weights = d.sample(n_samples) - assert_sample_mean(samples, d.mean()) - assert np.all(weights == 1.0) - - for scheme in _INTERPOLATION_SCHEMES: - # test sampling - d = openmc.stats.Tabular(x, p, scheme) - n_samples = 100_000 - samples = d.sample(n_samples)[0] - assert_sample_mean(samples, d.mean()) - - # test histogram sampling - d = openmc.stats.Tabular(x, p, interpolation='histogram') - samples, weights = d.sample(n_samples) - assert_sample_mean(samples, d.mean()) - assert np.all(weights == 1.0) - - # Multiplying the probabilities should preserve the mean but change the integral - d2 = openmc.stats.Tabular(x, p*2, interpolation='histogram') - assert d2.mean() == pytest.approx(d.mean()) - assert d2.integral() == pytest.approx(2.0*d.integral()) - - # Normalizing should result in an integral of 1 - d.normalize() - assert d.integral() == pytest.approx(1.0) - - # ensure that passing a set of probabilities shorter than x works - # for histogram interpolation - d = openmc.stats.Tabular(x, p[:-1], interpolation='histogram') - d.cdf() - d.mean() - assert_sample_mean(d.sample(n_samples)[0], d.mean()) - - # passing a shorter probability set should raise an error for linear-linear - with pytest.raises(ValueError): - d = openmc.stats.Tabular(x, p[:-1], interpolation='linear-linear') - d.cdf() - - # Use probabilities of correct length for linear-linear interpolation and - # call the CDF method - d = openmc.stats.Tabular(x, p, interpolation='linear-linear') - d.cdf() - - # Test biased distribution - d.bias = openmc.stats.Uniform(x[0], x[-1]) - bias_elem = d.to_xml_element('distribution') - d2 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d2.bias, openmc.stats.Uniform) - samples, weights = d2.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, d2.mean()) - assert np.all(weights != 1.0) - - -def test_tabular_from_xml(): - x = np.array([0.0, 5.0, 7.0, 10.0]) - p = np.array([10.0, 20.0, 5.0, 6.0]) + x = np.array([0.0, 5.0, 7.0]) + p = np.array([0.1, 0.2, 0.05]) d = openmc.stats.Tabular(x, p, 'linear-linear') elem = d.to_xml_element('distribution') @@ -345,14 +172,32 @@ def test_tabular_from_xml(): assert d.interpolation == 'linear-linear' assert len(d) == len(x) - # Make sure XML roundtrip works with len(x) == len(p) + 1 - x = np.array([0.0, 5.0, 7.0, 10.0]) - p = np.array([10.0, 20.0, 5.0]) - d = openmc.stats.Tabular(x, p, 'histogram') - elem = d.to_xml_element('distribution') - d = openmc.stats.Tabular.from_xml_element(elem) - assert all(d.x == x) - assert all(d.p == p) + # test linear-linear sampling + d = openmc.stats.Tabular(x, p) + + n_samples = 100_000 + samples = d.sample(n_samples, seed=100) + diff = np.abs(samples - d.mean()) + # within_1_sigma = np.count_nonzero(diff < samples.std()) + # assert within_1_sigma / n_samples >= 0.68 + within_2_sigma = np.count_nonzero(diff < 2*samples.std()) + assert within_2_sigma / n_samples >= 0.95 + within_3_sigma = np.count_nonzero(diff < 3*samples.std()) + assert within_3_sigma / n_samples >= 0.99 + + # test histogram sampling + d = openmc.stats.Tabular(x, p, interpolation='histogram') + d.normalize() + assert d.integral() == pytest.approx(1.0) + + samples = d.sample(n_samples, seed=100) + diff = np.abs(samples - d.mean()) + # within_1_sigma = np.count_nonzero(diff < samples.std()) + # assert within_1_sigma / n_samples >= 0.68 + within_2_sigma = np.count_nonzero(diff < 2*samples.std()) + assert within_2_sigma / n_samples >= 0.95 + within_3_sigma = np.count_nonzero(diff < 3*samples.std()) + assert within_3_sigma / n_samples >= 0.99 def test_legendre(): @@ -364,94 +209,33 @@ def test_legendre(): # Integrating distribution should yield one mu = np.linspace(-1., 1., 1000) - assert trapezoid(d(mu), mu) == pytest.approx(1.0, rel=1e-4) + assert np.trapz(d(mu), mu) == pytest.approx(1.0, rel=1e-4) with pytest.raises(NotImplementedError): d.to_xml_element('distribution') -@pytest.mark.flaky(reruns=1) def test_mixture(): d1 = openmc.stats.Uniform(0, 5) d2 = openmc.stats.Uniform(3, 7) p = [0.5, 0.5] mix = openmc.stats.Mixture(p, [d1, d2]) - np.testing.assert_allclose(mix.probability, p) + assert mix.probability == p assert mix.distribution == [d1, d2] assert len(mix) == 4 # Sample and make sure sample mean is close to expected mean n_samples = 1_000_000 - samples, weights = mix.sample(n_samples) + samples = mix.sample(n_samples) assert_sample_mean(samples, (2.5 + 5.0)/2) - assert np.all(weights == 1.0) elem = mix.to_xml_element('distribution') d = openmc.stats.Mixture.from_xml_element(elem) - np.testing.assert_allclose(d.probability, p) + assert d.probability == p assert d.distribution == [d1, d2] assert len(d) == 4 - # Test biased sub-distribution - d.distribution[0].bias = openmc.stats.PowerLaw(0, 5, 2) - bias_elem = d.to_xml_element('distribution') - d3 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d3.distribution[0].bias, openmc.stats.PowerLaw) - samples, weights = d3.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, (2.5 + 5.0)/2) - - # Test biased meta-probability - d.distribution[0].bias = None - d.bias = [0.25, 0.75] - bias_elem_2 = d.to_xml_element('distribution') - d4 = openmc.stats.Univariate.from_xml_element(bias_elem_2) - assert isinstance (d4.bias, np.ndarray) - samples, weights = d4.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, (2.5 + 5.0)/2) - assert np.all(weights != 1.0) - - -def test_mixture_clip(): - # Create mixture distribution containing a discrete distribution with two - # points that are not important, one because the x value is very small, and - # one because the p value is very small - d1 = openmc.stats.Discrete([1e-8, 1.0, 2.0, 1000.0], [3.0, 2.0, 5.0, 1e-12]) - d2 = openmc.stats.Uniform(0, 5) - mix = openmc.stats.Mixture([0.5, 0.5], [d1, d2]) - - # Clipping should reduce the contained discrete distribution to 2 points - mix_clip = mix.clip(1e-6) - assert mix_clip.distribution[0].x.size == 2 - assert mix_clip.distribution[0].p.size == 2 - - # Make sure inplace returns same object - mix_same = mix.clip(1e-6, inplace=True) - assert mix_same is mix - - # Make sure clip removes low probability distributions - d_small = openmc.stats.Uniform(0., 1.) - d_large = openmc.stats.Uniform(2., 5.) - mix = openmc.stats.Mixture([1e-10, 1.0], [d_small, d_large]) - mix_clip = mix.clip(1e-3) - assert mix_clip.distribution == [d_large] - - # Make sure warning is raised if tolerance is exceeded - d1 = openmc.stats.Discrete([1.0, 1.001], [1.0, 0.7e-6]) - d2 = openmc.stats.Tabular([0.0, 1.0], [0.7e-6], interpolation='histogram') - mix = openmc.stats.Mixture([1.0, 1.0], [d1, d2]) - with pytest.warns(UserWarning): - mix_clip = mix.clip(1e-6) - - # Make sure warning is raised if a biased Discrete is clipped - d3 = openmc.stats.Discrete([1.0, 1.001], [1.0, 0.7e-8]) - d3.bias = [0.9, 0.1] - mix = openmc.stats.Mixture([1.0, 1.0], [d3, d2]) - with pytest.raises(RuntimeError): - mix_clip = mix.clip(1e-6) - def test_polar_azimuthal(): # default polar-azimuthal should be uniform in mu and phi @@ -487,17 +271,12 @@ def test_polar_azimuthal(): def test_isotropic(): d = openmc.stats.Isotropic() - mu = openmc.stats.Uniform(-1.0, 1.0) - phi = openmc.stats.PowerLaw(0., 2*np.pi, 2) - d2 = openmc.stats.PolarAzimuthal(mu, phi) - d.bias = d2 elem = d.to_xml_element() assert elem.tag == 'angle' assert elem.attrib['type'] == 'isotropic' d = openmc.stats.Isotropic.from_xml_element(elem) assert isinstance(d, openmc.stats.Isotropic) - assert isinstance(d.bias, openmc.stats.PolarAzimuthal) def test_monodirectional(): @@ -514,7 +293,6 @@ def test_cartesian(): x = openmc.stats.Uniform(-10., 10.) y = openmc.stats.Uniform(-10., 10.) z = openmc.stats.Uniform(0., 20.) - z.bias = openmc.stats.PowerLaw(0., 20., 3) d = openmc.stats.CartesianIndependent(x, y, z) elem = d.to_xml_element() @@ -530,7 +308,6 @@ def test_cartesian(): d = openmc.stats.Spatial.from_xml_element(elem) assert isinstance(d, openmc.stats.CartesianIndependent) - assert isinstance (d.z.bias, openmc.stats.PowerLaw) def test_box(): @@ -546,6 +323,15 @@ def test_box(): d = openmc.stats.Box.from_xml_element(elem) assert d.lower_left == pytest.approx(lower_left) assert d.upper_right == pytest.approx(upper_right) + assert not d.only_fissionable + + # only fissionable parameter + d2 = openmc.stats.Box(lower_left, upper_right, True) + assert d2.only_fissionable + elem = d2.to_xml_element() + assert elem.attrib['type'] == 'fission' + d = openmc.stats.Spatial.from_xml_element(elem) + assert isinstance(d, openmc.stats.Box) def test_point(): @@ -561,114 +347,6 @@ def test_point(): assert d.xyz == pytest.approx(p) -def test_spherical_uniform(): - r_outer = 2.0 - r_inner = 1.0 - thetas = (0.0, pi/2) - phis = (0.0, pi) - origin = (0.0, 1.0, 2.0) - - sph_indep_function = openmc.stats.spherical_uniform(r_outer, - r_inner, - thetas, - phis, - origin) - - assert isinstance(sph_indep_function, openmc.stats.SphericalIndependent) - - -def test_cylindrical_uniform(): - r_outer = 2.0 - r_inner = 1.0 - height = 1.0 - phis = (0.0, pi) - origin = (0.0, 1.0, 2.0) - - dist = openmc.stats.cylindrical_uniform(r_outer, height, r_inner, phis, - origin=origin) - - assert isinstance(dist, openmc.stats.CylindricalIndependent) - - # Check r distribution (PowerLaw with exponent 1 for uniform area sampling) - assert isinstance(dist.r, openmc.stats.PowerLaw) - assert dist.r.a == pytest.approx(r_inner) - assert dist.r.b == pytest.approx(r_outer) - assert dist.r.n == pytest.approx(1.0) - - # Check phi distribution - assert isinstance(dist.phi, openmc.stats.Uniform) - assert dist.phi.a == pytest.approx(phis[0]) - assert dist.phi.b == pytest.approx(phis[1]) - - # Check z distribution (centered on origin along z_dir) - assert isinstance(dist.z, openmc.stats.Uniform) - assert dist.z.a == pytest.approx(-height / 2) - assert dist.z.b == pytest.approx(height / 2) - - # Check origin and default directions - np.testing.assert_allclose(dist.origin, origin) - np.testing.assert_allclose(dist.r_dir, [1., 0., 0.]) - np.testing.assert_allclose(dist.z_dir, [0., 0., 1.]) - - # XML round-trip preserves all parameters - elem = dist.to_xml_element() - dist2 = openmc.stats.CylindricalIndependent.from_xml_element(elem) - np.testing.assert_allclose(dist2.origin, origin) - np.testing.assert_allclose(dist2.r_dir, dist.r_dir) - np.testing.assert_allclose(dist2.z_dir, dist.z_dir) - - -def test_cylindrical_uniform_tilted(): - # Test with non-default axis orientation (y-axis as cylinder axis) - dist = openmc.stats.cylindrical_uniform( - r_outer=3.0, height=2.0, r_dir=(1., 0., 0.), z_dir=(0., 1., 0.) - ) - np.testing.assert_allclose(dist.z_dir, [0., 1., 0.]) - np.testing.assert_allclose(dist.r_dir, [1., 0., 0.]) - - # XML round-trip preserves tilted directions - elem = dist.to_xml_element() - dist2 = openmc.stats.CylindricalIndependent.from_xml_element(elem) - np.testing.assert_allclose(dist2.z_dir, dist.z_dir) - np.testing.assert_allclose(dist2.r_dir, dist.r_dir) - - -def test_cylindrical_uniform_ring(): - # height=0 should produce a flat ring (delta function at z=0) - r_outer = 2.0 - r_inner = 1.0 - phis = (0.0, pi) - origin = (0.0, 1.0, 2.0) - - dist = openmc.stats.cylindrical_uniform(r_outer, 0.0, r_inner, phis, - origin=origin) - - assert isinstance(dist, openmc.stats.CylindricalIndependent) - - # Check r distribution - assert isinstance(dist.r, openmc.stats.PowerLaw) - assert dist.r.a == pytest.approx(r_inner) - assert dist.r.b == pytest.approx(r_outer) - assert dist.r.n == pytest.approx(1.0) - - # Check phi distribution - assert isinstance(dist.phi, openmc.stats.Uniform) - assert dist.phi.a == pytest.approx(phis[0]) - assert dist.phi.b == pytest.approx(phis[1]) - - # z distribution must be a delta function at 0.0 (local frame) - assert isinstance(dist.z, openmc.stats.Discrete) - assert dist.z.x[0] == pytest.approx(0.0) - - # XML round-trip - elem = dist.to_xml_element() - dist2 = openmc.stats.CylindricalIndependent.from_xml_element(elem) - np.testing.assert_allclose(dist2.origin, origin) - np.testing.assert_allclose(dist2.r_dir, dist.r_dir) - np.testing.assert_allclose(dist2.z_dir, dist.z_dir) - - -@pytest.mark.flaky(reruns=1) def test_normal(): mean = 10.0 std_dev = 2.0 @@ -683,130 +361,44 @@ def test_normal(): assert len(d) == 2 # sample normal distribution - n_samples = 100_000 - samples, weights = d.sample(n_samples) - assert_sample_mean(samples, mean) - assert np.all(weights == 1.0) - - # Test biased distribution - d.bias = openmc.stats.Normal(10.0, 4.0) - bias_elem = d.to_xml_element('distribution') - d2 = openmc.stats.Univariate.from_xml_element(bias_elem) - assert isinstance (d2.bias, openmc.stats.Normal) - samples, weights = d2.sample(n_samples) - weighted_sample = samples * weights - assert_sample_mean(weighted_sample, mean) - assert np.all(weights != 1.0) + n_samples = 10000 + samples = d.sample(n_samples, seed=100) + samples = np.abs(samples - mean) + within_1_sigma = np.count_nonzero(samples < std_dev) + assert within_1_sigma / n_samples >= 0.68 + within_2_sigma = np.count_nonzero(samples < 2*std_dev) + assert within_2_sigma / n_samples >= 0.95 + within_3_sigma = np.count_nonzero(samples < 3*std_dev) + assert within_3_sigma / n_samples >= 0.99 -@pytest.mark.flaky(reruns=1) -def test_normal_truncated(): - mean = 10.0 - std_dev = 2.0 - lower = 6.0 - upper = 14.0 - - d = openmc.stats.Normal(mean, std_dev, lower, upper) - - # Check attributes - assert d.mean_value == pytest.approx(mean) - assert d.std_dev == pytest.approx(std_dev) - assert d.lower == pytest.approx(lower) - assert d.upper == pytest.approx(upper) - assert len(d) == 4 - assert d.support == (lower, upper) - - # Test XML round-trip - elem = d.to_xml_element('distribution') - assert elem.attrib['type'] == 'normal' - params = elem.attrib['parameters'].split() - assert len(params) == 4 - - d2 = openmc.stats.Normal.from_xml_element(elem) - assert d2.mean_value == pytest.approx(mean) - assert d2.std_dev == pytest.approx(std_dev) - assert d2.lower == pytest.approx(lower) - assert d2.upper == pytest.approx(upper) - - # Test PDF evaluation - # PDF should be zero outside bounds - assert d.evaluate(lower - 1.0) == 0.0 - assert d.evaluate(upper + 1.0) == 0.0 - - # PDF should be positive inside bounds - assert d.evaluate(mean) > 0.0 - - # PDF should be higher than untruncated at the mean (due to renormalization) - d_unbounded = openmc.stats.Normal(mean, std_dev) - assert d.evaluate(mean) > d_unbounded.evaluate(mean) - - # Verify that PDF integrates to approximately 1 - x = np.linspace(lower, upper, 1000) - integral = trapezoid(d.evaluate(x), x) - assert integral == pytest.approx(1.0, rel=0.01) - - # Sample truncated distribution - n_samples = 10_000 - samples, weights = d.sample(n_samples) - - # All samples should be within bounds - assert np.all(samples >= lower) - assert np.all(samples <= upper) - - # Weights should all be 1 (no biasing) - assert np.all(weights == 1.0) - - -def test_normal_truncated_one_sided(): - # Test lower-bounded only (positive half-normal centered at 0) - d_lower = openmc.stats.Normal(0.0, 1.0, lower=0.0) - assert d_lower.lower == 0.0 - assert d_lower.upper == np.inf - assert d_lower.evaluate(-1.0) == 0.0 - assert d_lower.evaluate(1.0) > 0.0 - - # PDF at 0 should be approximately 2 * 0.3989 ≈ 0.798 (half-normal) - assert d_lower.evaluate(0.0) == pytest.approx(0.798, rel=0.01) - - # Test upper-bounded only - d_upper = openmc.stats.Normal(0.0, 1.0, upper=0.0) - assert d_upper.lower == -np.inf - assert d_upper.upper == 0.0 - assert d_upper.evaluate(1.0) == 0.0 - assert d_upper.evaluate(-1.0) > 0.0 - - -def test_normal_truncated_errors(): - # Invalid bounds (lower >= upper) - with pytest.raises(ValueError): - openmc.stats.Normal(0.0, 1.0, lower=1.0, upper=0.0) - - with pytest.raises(ValueError): - openmc.stats.Normal(0.0, 1.0, lower=1.0, upper=1.0) - - -@pytest.mark.flaky(reruns=1) def test_muir(): mean = 10.0 mass = 5.0 temp = 20000. - d = openmc.stats.muir(mean, mass, temp) - assert isinstance(d, openmc.stats.Normal) + d = openmc.stats.Muir(mean,mass,temp) elem = d.to_xml_element('energy') - assert elem.attrib['type'] == 'normal' + assert elem.attrib['type'] == 'muir' - d = openmc.stats.Univariate.from_xml_element(elem) - assert isinstance(d, openmc.stats.Normal) + d = openmc.stats.Muir.from_xml_element(elem) + assert d.e0 == pytest.approx(mean) + assert d.m_rat == pytest.approx(mass) + assert d.kt == pytest.approx(temp) + assert len(d) == 3 # sample muir distribution - n_samples = 100_000 - samples, weights = d.sample(n_samples) - assert_sample_mean(samples, mean) - assert np.all(weights == 1.0) + n_samples = 10000 + samples = d.sample(n_samples, seed=100) + samples = np.abs(samples - mean) + within_1_sigma = np.count_nonzero(samples < d.std_dev) + assert within_1_sigma / n_samples >= 0.68 + within_2_sigma = np.count_nonzero(samples < 2*d.std_dev) + assert within_2_sigma / n_samples >= 0.95 + within_3_sigma = np.count_nonzero(samples < 3*d.std_dev) + assert within_3_sigma / n_samples >= 0.99 -@pytest.mark.flaky(reruns=1) def test_combine_distributions(): # Combine two discrete (same data as in test_merge_discrete) x1 = [0.0, 1.0, 10.0] @@ -836,313 +428,17 @@ def test_combine_distributions(): assert isinstance(mixed, openmc.stats.Mixture) assert len(mixed.distribution) == 2 assert len(mixed.probability) == 2 - assert mixed == openmc.stats.combine_distributions([mixed], [1.0]) - - # Mixture combined with another distribution: probabilities should be - # correctly scaled when the Mixture is flattened - d_a = openmc.stats.delta_function(1.0) - d_b = openmc.stats.delta_function(2.0) - m = openmc.stats.Mixture([0.3, 0.7], [d_a, d_b]) - extra = openmc.stats.delta_function(3.0) - result = openmc.stats.combine_distributions([m, extra], [0.5, 0.5]) - assert isinstance(result, openmc.stats.Discrete) - assert result.x == pytest.approx([1.0, 2.0, 3.0]) - assert result.p == pytest.approx([0.5*0.3, 0.5*0.7, 0.5]) - - # Passing a Mixture with a bias should warn that the bias is dropped - biased_m = openmc.stats.Mixture([0.5, 0.5], [d_a, d_b], bias=[0.8, 0.2]) - with pytest.warns(UserWarning, match='bias'): - openmc.stats.combine_distributions([biased_m], [1.0]) - - # Single tabular returns a tabular distribution with scaled probabilities - t_single = openmc.stats.Tabular([0.0, 1.0], [2.0, 0.0]) - scaled = openmc.stats.combine_distributions([t_single], [0.25]) - assert isinstance(scaled, openmc.stats.Tabular) - assert scaled.p == pytest.approx([0.5, 0.0]) - - # Mixture with biased tabular should preserve unbiased mean via weights - bias = openmc.stats.Tabular([0.0, 1.0], [2.0, 0.0]) - t_biased = openmc.stats.Tabular([0.0, 1.0], [1.0, 1.0], bias=bias) - d1 = openmc.stats.delta_function(0.0) - mixed = openmc.stats.combine_distributions([t_biased, d1], [0.5, 0.5]) - assert isinstance(mixed, openmc.stats.Mixture) - samples, weights = mixed.sample(10_000) - assert_sample_mean(samples*weights, 0.25) # Combine 1 discrete and 2 tabular -- the tabular distributions should # combine to produce a uniform distribution with mean 0.5. The combined # distribution should have a mean of 0.25. t1 = openmc.stats.Tabular([0., 1.], [2.0, 0.0]) t2 = openmc.stats.Tabular([0., 1.], [0.0, 2.0]) - d1 = openmc.stats.delta_function(0.0) + d1 = openmc.stats.Discrete([0.0], [1.0]) combined = openmc.stats.combine_distributions([t1, t2, d1], [0.25, 0.25, 0.5]) assert combined.integral() == pytest.approx(1.0) # Sample the combined distribution and make sure the sample mean is within # uncertainty of the expected value - samples, weights = combined.sample(10_000) + samples = combined.sample(10_000) assert_sample_mean(samples, 0.25) - assert np.all(weights == 1.0) - - # If biased/unbiased Discrete distributions are combined, unbiased probability - # should be conserved and points from both original distributions should be - # assigned bias probabilities. - x1 = [0.0, 1.0, 10.0] - p1 = [0.3, 0.2, 0.5] - b1 = [0.2, 0.5, 0.3] - d1 = openmc.stats.Discrete(x1, p1, b1) - x2 = [0.5, 1.0, 5.0] - p2 = [0.4, 0.5, 0.1] - d2 = openmc.stats.Discrete(x2, p2) - combined = openmc.stats.combine_distributions([d1, d2, t1], [0.25, 0.25, 0.5]) - - p3 = [0.075, 0.1, 0.175, 0.025, 0.125] - b3 = [0.05, 0.1, 0.25, 0.025, 0.075] - assert all(combined.distribution[-1].p == p3) - assert all(combined.distribution[-1].bias == b3) - - -def test_reference_vwu_projection(): - """When a non-orthogonal vector is provided, the setter should project out - any component along reference_uvw so the stored vector is orthogonal. - """ - pa = openmc.stats.PolarAzimuthal() # default reference_uvw == (0, 0, 1) - - # Provide a vector that is not orthogonal to (0,0,1) - pa.reference_vwu = (2.0, 0.5, 0.3) - - reference_v = np.asarray(pa.reference_vwu) - reference_u = np.asarray(pa.reference_uvw) - - # reference_v should be orthogonal to reference_u - assert abs(np.dot(reference_v, reference_u)) < 1e-6 - - -def test_reference_vwu_normalization(): - """When a non-normalized vector is provided, the setter should normalize - the projected vector to unit length. - """ - pa = openmc.stats.PolarAzimuthal() # default reference_uvw == (0, 0, 1) - - # Provide a vector that is neither orthogonal to (0,0,1) nor unit-length - pa.reference_vwu = (2.0, 0.5, 0.3) - - reference_v = np.asarray(pa.reference_vwu) - - # reference_v should be unit length - assert np.isclose(np.linalg.norm(reference_v), 1.0, atol=1e-12) - - -def test_fusion_spectrum_dd(): - d = openmc.stats.fusion_neutron_spectrum(10e3, 'DD') - assert isinstance(d, openmc.stats.Normal) - - # E_0 for D(d,n)3He is ~2.45 MeV; thermal shift at 10 keV should be - # several tens of keV, so mean should be noticeably above E_0 - assert d.mean_value > 2.45e6 - assert d.mean_value < 2.6e6 - - # Standard deviation should be positive and on order of ~50-100 keV - assert d.std_dev > 30e3 - assert d.std_dev < 200e3 - - -def test_fusion_spectrum_dt(): - d = openmc.stats.fusion_neutron_spectrum(10e3, 'DT') - assert isinstance(d, openmc.stats.Normal) - - # E_0 for T(d,n)alpha is ~14.02 MeV; with thermal shift mean should be - # above E_0 by several tens of keV - assert d.mean_value > 14.02e6 - assert d.mean_value < 14.2e6 - - # Standard deviation should be on order of ~200-400 keV - assert d.std_dev > 100e3 - assert d.std_dev < 500e3 - - -def test_fusion_spectrum_temp_continuity(): - # Verify the low-T and high-T formulas produce nearly identical results - # at the 40 keV switchover point - d_lo = openmc.stats.fusion_neutron_spectrum(39.99e3, 'DT') - d_hi = openmc.stats.fusion_neutron_spectrum(40.01e3, 'DT') - - assert d_lo.mean_value == pytest.approx(d_hi.mean_value, rel=1e-3) - assert d_lo.std_dev == pytest.approx(d_hi.std_dev, rel=1e-3) - - # Same check for DD - d_lo = openmc.stats.fusion_neutron_spectrum(39.99e3, 'DD') - d_hi = openmc.stats.fusion_neutron_spectrum(40.01e3, 'DD') - - assert d_lo.mean_value == pytest.approx(d_hi.mean_value, rel=1e-3) - assert d_lo.std_dev == pytest.approx(d_hi.std_dev, rel=1e-3) - - -def test_fusion_spectrum_high_temp(): - # At T_i = 80 keV (high-T regime), ensure the function still produces - # reasonable results using Table IV formulas - for reactants in ('DD', 'DT'): - d = openmc.stats.fusion_neutron_spectrum(80e3, reactants) - assert isinstance(d, openmc.stats.Normal) - assert d.mean_value > 0 - assert d.std_dev > 0 - - # DT mean at 80 keV should be higher than at 10 keV - d_10 = openmc.stats.fusion_neutron_spectrum(10e3, 'DT') - d_80 = openmc.stats.fusion_neutron_spectrum(80e3, 'DT') - assert d_80.mean_value > d_10.mean_value - assert d_80.std_dev > d_10.std_dev - - -def test_fusion_spectrum_zero_temp(): - # At very low temperature, mean should approach E_0 and width should - # approach zero - d = openmc.stats.fusion_neutron_spectrum(1.0, 'DT') - assert d.mean_value == pytest.approx(14.049e6, rel=1e-3) - assert d.std_dev < 5e3 # width approaches zero at low temperature - - -def test_fusion_spectrum_invalid(): - # Invalid reactant string should raise an error - with pytest.raises(ValueError): - openmc.stats.fusion_neutron_spectrum(10e3, '🐔🧇') - - # Negative temperature should raise an error - with pytest.raises(ValueError): - openmc.stats.fusion_neutron_spectrum(-10e3, 'DT') - - # Temperature above 100 keV should raise an error - with pytest.raises(ValueError): - openmc.stats.fusion_neutron_spectrum(101e3, 'DT') - - -@pytest.fixture(autouse=False) -def decay_spectrum_chain(): - """Set chain_file for the duration of a test and clear the _photon_integral - cache so results from a different chain don't bleed across tests.""" - CHAIN_FILE = (Path(__file__).parents[1] / 'chain_simple.xml').resolve() - DecaySpectrum._photon_integral.cache_clear() - with openmc.config.patch('chain_file', CHAIN_FILE): - yield - DecaySpectrum._photon_integral.cache_clear() - - -def test_decay_spectrum_construction(): - nuclides = {'I135': 1.5e-3, 'Xe135': 8.2e-4} - d = openmc.stats.DecaySpectrum(nuclides, volume=100.0) - assert d.nuclides == nuclides - assert d.volume == pytest.approx(100.0) - assert len(d) == 2 - - -def test_decay_spectrum_validation(): - # nuclides must be a dict - with pytest.raises(TypeError): - openmc.stats.DecaySpectrum(['I135'], volume=1.0) - - # densities must be > 0 - with pytest.raises(ValueError): - openmc.stats.DecaySpectrum({'I135': -1.0}, volume=1.0) - - # volume must be > 0 - with pytest.raises(ValueError): - openmc.stats.DecaySpectrum({'I135': 1e-3}, volume=-1.0) - - with pytest.raises(ValueError): - openmc.stats.DecaySpectrum({'I135': 1e-3}, volume=0.0) - - -def test_decay_spectrum_xml_roundtrip(): - nuclides = {'I135': 1.5e-3, 'Xe135': 8.2e-4} - d = openmc.stats.DecaySpectrum(nuclides, volume=100.0) - - elem = d.to_xml_element('energy') - assert elem.get('type') == 'decay_spectrum' - assert float(elem.get('volume')) == pytest.approx(100.0) - assert elem.findtext('nuclides').split() == list(nuclides) - assert [float(x) for x in elem.findtext('parameters').split()] == pytest.approx( - list(nuclides.values())) - - # Round-trip via DecaySpectrum.from_xml_element - d2 = openmc.stats.DecaySpectrum.from_xml_element(elem) - assert d2.nuclides == nuclides - assert d2.volume == pytest.approx(100.0) - - # Round-trip via the Univariate dispatcher - d3 = openmc.stats.Univariate.from_xml_element(elem) - assert isinstance(d3, openmc.stats.DecaySpectrum) - assert d3 == d - - -def test_decay_spectrum_to_distribution(decay_spectrum_chain): - # Single emitting nuclide -> concrete distribution, not None - d = openmc.stats.DecaySpectrum({'I135': 1e-3}, volume=10.0) - dist = d.to_distribution() - assert dist is not None - - # Result is cached on second call - dist2 = d.to_distribution() - assert dist2 is dist - - # Nuclide with no photon source -> None - d_stable = openmc.stats.DecaySpectrum({'Xe136': 1e-3}, volume=10.0) - assert d_stable.to_distribution() is None - - # Mixture of emitters -> non-None combined distribution - d_mix = openmc.stats.DecaySpectrum( - {'I135': 1e-3, 'Xe135': 5e-4}, volume=10.0 - ) - dist_mix = d_mix.to_distribution() - assert dist_mix is not None - - -def test_decay_spectrum_integral(decay_spectrum_chain): - # For an emitting nuclide, integral should be > 0 - d = openmc.stats.DecaySpectrum({'I135': 1e-3}, volume=10.0) - assert d.integral() > 0.0 - - # Proportional to density: doubling density doubles integral - d2 = openmc.stats.DecaySpectrum({'I135': 2e-3}, volume=10.0) - assert d2.integral() == pytest.approx(2.0 * d.integral()) - - # Proportional to volume - d3 = openmc.stats.DecaySpectrum({'I135': 1e-3}, volume=20.0) - assert d3.integral() == pytest.approx(2.0 * d.integral()) - - # Pure non-emitter -> 0.0 - d_stable = openmc.stats.DecaySpectrum({'Xe136': 1e-3}, volume=10.0) - assert d_stable.integral() == pytest.approx(0.0) - - -def test_decay_spectrum_clip(decay_spectrum_chain): - # Stable / non-emitting nuclides are removed unconditionally - d = openmc.stats.DecaySpectrum( - {'I135': 1e-3, 'Xe135': 5e-4, 'Xe136': 1.0, 'Cs135': 1.0}, - volume=10.0, - ) - d_clip = d.clip() - assert 'Xe136' not in d_clip.nuclides - assert 'Cs135' not in d_clip.nuclides - assert 'I135' in d_clip.nuclides - assert 'Xe135' in d_clip.nuclides - # Original is unchanged - assert 'Xe136' in d.nuclides - - # inplace=True modifies and returns the same object - d_same = d.clip(inplace=True) - assert d_same is d - assert 'Xe136' not in d.nuclides - - # A nuclide with negligible emission rate is removed by tolerance clipping. - # U235 has a very small integral (~4e-17 Bq/atom) compared with I135 (~4e-5) - d_tight = openmc.stats.DecaySpectrum( - {'I135': 1e-3, 'U235': 1e-3}, volume=10.0 - ) - d_tight_clip = d_tight.clip(tolerance=1e-9) - assert 'U235' not in d_tight_clip.nuclides - assert 'I135' in d_tight_clip.nuclides - - # All non-emitters -> empty nuclides dict - d_empty = openmc.stats.DecaySpectrum({'Xe136': 1e-3}, volume=10.0) - d_empty.clip(inplace=True) - assert d_empty.nuclides == {} diff --git a/tests/unit_tests/test_summary.py b/tests/unit_tests/test_summary.py deleted file mode 100644 index 315ac0ba5..000000000 --- a/tests/unit_tests/test_summary.py +++ /dev/null @@ -1,41 +0,0 @@ -import openmc - - -def test_periodic_surface_roundtrip(run_in_tmpdir): - # Create a simple model with periodic surfaces - mat = openmc.Material() - mat.add_nuclide('H1', 1.0) - mat.set_density('g/cm3', 1.0) - cyl = openmc.ZCylinder(r=1.0) - x0 = openmc.XPlane(-5.0, boundary_type='periodic') - y0 = openmc.YPlane(-5.0, boundary_type='periodic') - z0 = openmc.ZPlane(-5.0, boundary_type='periodic') - x1 = openmc.XPlane(5.0, boundary_type='periodic') - y1 = openmc.YPlane(5.0, boundary_type='periodic') - z1 = openmc.ZPlane(5.0, boundary_type='periodic') - x0.periodic_surface = x1 - y0.periodic_surface = y1 - z0.periodic_surface = z1 - cell1 = openmc.Cell(fill=mat, region=-cyl) - cell2 = openmc.Cell(fill=mat, region=+cyl & +x0 & -x1 & +y0 & -y1 & +z0 & -z1) - model = openmc.Model() - model.geometry = openmc.Geometry([cell1, cell2]) - model.settings.particles = 100 - model.settings.batches = 1 - model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(1.0e4) - ) - - # Run model - model.run() - - # Load summary data and check periodic surfaces - summary = openmc.Summary('summary.h5') - surfs = summary.geometry.get_all_surfaces() - for s in [x0, y0, z0, x1, y1, z1]: - assert surfs[s.id].boundary_type == 'periodic' - pairs = [(x0, x1), (y0, y1), (z0, z1)] - for s0, s1 in pairs: - assert surfs[s0.id].periodic_surface == surfs[s1.id] - assert surfs[s1.id].periodic_surface == surfs[s0.id] diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index f5c0b8f8b..12cd8c9d2 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -7,12 +7,6 @@ import openmc import pytest -def test_id(): - for i in range(-10, 1): - with pytest.raises(ValueError): - openmc.Plane(a=1, b=2, c=-1, d=3, surface_id=i) - - def assert_infinite_bb(s): ll, ur = (-s).bounding_box assert np.all(np.isinf(ll)) @@ -195,12 +189,6 @@ def test_cylinder(): assert s.dy == -1 assert s.dz == 1 assert s.r == 2 - - # Check radius must be positive - with pytest.raises(ValueError): - openmc.Cylinder(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r=0.0) - with pytest.raises(ValueError): - openmc.Cylinder(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r=-1.0) # Check bounding box assert_infinite_bb(s) @@ -250,12 +238,6 @@ def test_xcylinder(): assert s.y0 == y assert s.z0 == z assert s.r == r - - # Check radius must be positive - with pytest.raises(ValueError): - openmc.XCylinder(y0=y, z0=z, r=0.0) - with pytest.raises(ValueError): - openmc.XCylinder(y0=y, z0=z, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -302,12 +284,6 @@ def test_ycylinder(): assert s.x0 == x assert s.z0 == z assert s.r == r - - # Check radius must be positive - with pytest.raises(ValueError): - openmc.YCylinder(x0=x, z0=z, r=0.0) - with pytest.raises(ValueError): - openmc.YCylinder(x0=x, z0=z, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -345,12 +321,6 @@ def test_zcylinder(): assert s.x0 == x assert s.y0 == y assert s.r == r - - # Check radius must be positive - with pytest.raises(ValueError): - openmc.ZCylinder(x0=x, y0=y, r=0.0) - with pytest.raises(ValueError): - openmc.ZCylinder(x0=x, y0=y, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -389,12 +359,6 @@ def test_sphere(): assert s.y0 == y assert s.z0 == z assert s.r == r - - # Check radius must be positive - with pytest.raises(ValueError): - openmc.Sphere(x0=x, y0=y, z0=z, r=0.0) - with pytest.raises(ValueError): - openmc.Sphere(x0=x, y0=y, z0=z, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -434,12 +398,6 @@ def cone_common(apex, r2, cls): assert s.y0 == y assert s.z0 == z assert s.r2 == r2 - - # Check radius must be positive - with pytest.raises(ValueError): - cls(x0=x, y0=y, z0=z, r2=0.0) - with pytest.raises(ValueError): - cls(x0=x, y0=y, z0=z, r2=-1.0) # Check bounding box assert_infinite_bb(s) @@ -478,12 +436,6 @@ def test_cone(): assert s.dy == -1 assert s.dz == 1 assert s.r2 == 4 - - # Check radius must be positive - with pytest.raises(ValueError): - openmc.Cone(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r2=0.0) - with pytest.raises(ValueError): - openmc.Cone(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r2=-1.0) # Check bounding box assert_infinite_bb(s) @@ -664,13 +616,6 @@ def torus_common(center, R, r1, r2, cls): assert s.a == R assert s.b == r1 assert s.c == r2 - - # Check radius must be positive - params = [(0.0, r1, r2), (R, 0.0, r2), (R, r1, 0.0), - (-1.0, r1, r2), (R, -1.0, r2), (R, r1, -1.0)] - for a,b,c in params: - with pytest.raises(ValueError): - cls(x0=x, y0=y, z0=z, a=a, b=b, c=c) # evaluate method assert s.evaluate((x, y, z)) > 0.0 @@ -808,16 +753,3 @@ def test_ztorus(): assert isinstance(sr, openmc.YTorus) sr = s.rotate((0., 90., 0.)) assert isinstance(sr, openmc.XTorus) - - -def test_normalize(): - """Test that equivalent planes give same normalized coefficients""" - p1 = openmc.Plane(a=0.0, b=1.0, c=0.0, d=1.0) - p2 = openmc.Plane(a=0.0, b=2.0, c=0.0, d=2.0) - assert p1.normalize() == p2.normalize() - - p2 = openmc.Plane(a=0.0, b=-1.0, c=0.0, d=-1.0) - assert p1.normalize() == p2.normalize() - - p2 = openmc.YPlane(1.0) - assert p1.normalize() == p2.normalize() diff --git a/tests/unit_tests/test_surface_composite.py b/tests/unit_tests/test_surface_composite.py index a04fc73c5..4d680ae7c 100644 --- a/tests/unit_tests/test_surface_composite.py +++ b/tests/unit_tests/test_surface_composite.py @@ -65,46 +65,42 @@ def test_right_circular_cylinder(axis, indices): x, y, z = 1.0, -2.5, 3.0 h, r = 5.0, 3.0 s = openmc.model.RightCircularCylinder((x, y, z), h, r, axis=axis.lower()) - s_r = openmc.model.RightCircularCylinder((x, y, z), h, r, axis=axis.lower(), - upper_fillet_radius=1.6, - lower_fillet_radius=1.6) - for s in (s, s_r): - assert isinstance(s.cyl, getattr(openmc, axis + "Cylinder")) - assert isinstance(s.top, getattr(openmc, axis + "Plane")) - assert isinstance(s.bottom, getattr(openmc, axis + "Plane")) + assert isinstance(s.cyl, getattr(openmc, axis + "Cylinder")) + assert isinstance(s.top, getattr(openmc, axis + "Plane")) + assert isinstance(s.bottom, getattr(openmc, axis + "Plane")) - # Make sure boundary condition propagates - s.boundary_type = 'reflective' - assert s.boundary_type == 'reflective' - assert s.cyl.boundary_type == 'reflective' - assert s.bottom.boundary_type == 'reflective' - assert s.top.boundary_type == 'reflective' + # Make sure boundary condition propagates + s.boundary_type = 'reflective' + assert s.boundary_type == 'reflective' + assert s.cyl.boundary_type == 'reflective' + assert s.bottom.boundary_type == 'reflective' + assert s.top.boundary_type == 'reflective' - # Check bounding box - ll, ur = (+s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - ll, ur = (-s).bounding_box - assert ll == pytest.approx((x, y, z) + np.roll([0, -r, -r], indices[0])) - assert ur == pytest.approx((x, y, z) + np.roll([h, r, r], indices[0])) + # Check bounding box + ll, ur = (+s).bounding_box + assert np.all(np.isinf(ll)) + assert np.all(np.isinf(ur)) + ll, ur = (-s).bounding_box + assert ll == pytest.approx((x, y, z) + np.roll([0, -r, -r], indices[0])) + assert ur == pytest.approx((x, y, z) + np.roll([h, r, r], indices[0])) - # __contains__ on associated half-spaces - point_pos = (x, y, z) + np.roll([h/2, r+1, r+1], indices[0]) - assert point_pos in +s - assert point_pos not in -s - point_neg = (x, y, z) + np.roll([h/2, 0, 0], indices[0]) - assert point_neg in -s - assert point_neg not in +s + # __contains__ on associated half-spaces + point_pos = (x, y, z) + np.roll([h/2, r+1, r+1], indices[0]) + assert point_pos in +s + assert point_pos not in -s + point_neg = (x, y, z) + np.roll([h/2, 0, 0], indices[0]) + assert point_neg in -s + assert point_neg not in +s - # translate method - t = uniform(-5.0, 5.0) - s_t = s.translate((t, t, t)) - ll_t, ur_t = (-s_t).bounding_box - assert ur_t == pytest.approx(ur + t) - assert ll_t == pytest.approx(ll + t) + # translate method + t = uniform(-5.0, 5.0) + s_t = s.translate((t, t, t)) + ll_t, ur_t = (-s_t).bounding_box + assert ur_t == pytest.approx(ur + t) + assert ll_t == pytest.approx(ll + t) - # Make sure repr works - repr(s) + # Make sure repr works + repr(s) @pytest.mark.parametrize( @@ -158,23 +154,18 @@ def test_cone_one_sided(axis, point_pos, point_neg, ll_true): @pytest.mark.parametrize( - "axis, indices, center", [ - ("X", [2, 0, 1], (0., 0.)), - ("Y", [0, 2, 1], (0., 0.)), - ("Z", [0, 1, 2], (0., 0.)), - ("X", [2, 0, 1], (10., 5.)), - ("Y", [0, 2, 1], (10., 5.)), - ("Z", [0, 1, 2], (10., 5.)), - + "axis, indices", [ + ("X", [0, 1, 2]), + ("Y", [1, 2, 0]), + ("Z", [2, 0, 1]), ] ) -def test_cylinder_sector(axis, indices, center): - c1, c2 = center +def test_cylinder_sector(axis, indices): r1, r2 = 0.5, 1.5 d = (r2 - r1) / 2 phi1 = -60. phi2 = 60 - s = openmc.model.CylinderSector(r1, r2, phi1, phi2, center=center, + s = openmc.model.CylinderSector(r1, r2, phi1, phi2, axis=axis.lower()) assert isinstance(s.outer_cyl, getattr(openmc, axis + "Cylinder")) assert isinstance(s.inner_cyl, getattr(openmc, axis + "Cylinder")) @@ -194,31 +185,16 @@ def test_cylinder_sector(axis, indices, center): assert np.all(np.isinf(ll)) assert np.all(np.isinf(ur)) ll, ur = (-s).bounding_box - test_point_ll = np.array([-r2 + c1, -r2 + c2, -np.inf]) - assert ll == pytest.approx(test_point_ll[indices]) - test_point_ur = np.array([r2 + c1, r2 + c2, np.inf]) - assert ur == pytest.approx(test_point_ur[indices]) + assert ll == pytest.approx(np.roll([-np.inf, -r2, -r2], indices[0])) + assert ur == pytest.approx(np.roll([np.inf, r2, r2], indices[0])) # __contains__ on associated half-spaces - point_pos = np.array([0 + c1, r2 + 1 + c2, 0]) - assert point_pos[indices] in +s - assert point_pos[indices] not in -s - point_neg = np.array([r1 + d + c1, r1 + d + c2, 0]) - assert point_neg[indices] in -s - assert point_neg[indices] not in +s - - # Check __contains__ for sector with reflex angle - s_reflex = openmc.model.CylinderSector( - r1, r2, 0., 270., center=center, axis=axis.lower()) - points = [ - np.array([c1 + r1 + d, c2 + 0.01, 0.]), - np.array([c1, c2 + r1 + d, 0.]), - np.array([c1 - r1 - d, c2, 0.]), - np.array([c1 - 0.01, c2 - r1 - d, 0.]) - ] - for point_neg in points: - assert point_neg[indices] in -s_reflex - assert point_neg[indices] not in +s_reflex + point_pos = np.roll([0, r2 + 1, 0], indices[0]) + assert point_pos in +s + assert point_pos not in -s + point_neg = np.roll([0, r1 + d, r1 + d], indices[0]) + assert point_neg in -s + assert point_neg not in +s # translate method t = uniform(-5.0, 5.0) @@ -268,7 +244,7 @@ def test_cylinder_sector_from_theta_alpha(): @pytest.mark.parametrize( "axis, plane_tb, plane_lr, axis_idx", [ ("x", "Z", "Y", 0), - ("y", "Z", "X", 1), + ("y", "X", "Z", 1), ("z", "Y", "X", 2), ] ) @@ -338,326 +314,3 @@ def test_isogonal_octagon(axis, plane_tb, plane_lr, axis_idx): # Make sure repr works repr(s) - - -def test_polygon(): - # define a 5 pointed star centered on 1, 1 - star = np.array([[1. , 2. ], - [0.70610737, 1.4045085 ], - [0.04894348, 1.30901699], - [0.52447174, 0.8454915 ], - [0.41221475, 0.19098301], - [1. , 0.5 ], - [1.58778525, 0.19098301], - [1.47552826, 0.8454915 ], - [1.95105652, 1.30901699], - [1.29389263, 1.4045085 ], - [1. , 2. ]]) - points_in = [(1, 1, 0), (0, 1, 1), (1, 0, 1), (.707, .707, 1)] - for i, basis in enumerate(('xy', 'yz', 'xz', 'rz')): - star_poly = openmc.model.Polygon(star, basis=basis) - assert points_in[i] in -star_poly - assert any([points_in[i] in reg for reg in star_poly.regions]) - assert points_in[i] not in +star_poly - assert (0, 0, 0) not in -star_poly - if basis != "rz": - for offsets in [0.6, np.array([0.6] * 10), [0.6] * 10]: - offset_star = star_poly.offset(offsets) - assert (0, 0, 0) in -offset_star - assert any([(0, 0, 0) in reg for reg in offset_star.regions]) - with pytest.raises(ValueError): - star_poly.offset([0.6, 0.6]) - - # check invalid Polygon input points - # duplicate points not just at start and end - rz_points = np.array([[6.88, 3.02], - [6.88, 2.72], - [6.88, 3.02], - [7.63, 0.0], - [5.75, 0.0], - [5.75, 1.22], - [7.63, 0.0], - [6.30, 1.22], - [6.30, 3.02], - [6.88, 3.02]]) - with pytest.raises(ValueError): - openmc.model.Polygon(rz_points) - - # segment traces back on previous segment - rz_points = np.array([[6.88, 3.02], - [6.88, 2.72], - [6.88, 2.32], - [6.88, 2.52], - [7.63, 0.0], - [5.75, 0.0], - [6.75, 0.0], - [5.75, 1.22], - [6.30, 1.22], - [6.30, 3.02], - [6.88, 3.02]]) - with pytest.raises(ValueError): - openmc.model.Polygon(rz_points) - - # segments intersect (line-line) - rz_points = np.array([[6.88, 3.02], - [5.88, 2.32], - [7.63, 0.0], - [5.75, 0.0], - [5.75, 1.22], - [6.30, 1.22], - [6.30, 3.02], - [6.88, 3.02]]) - with pytest.raises(ValueError): - openmc.model.Polygon(rz_points) - - # segments intersect (line-point) - rz_points = np.array([[6.88, 3.02], - [6.3, 2.32], - [7.63, 0.0], - [5.75, 0.0], - [5.75, 1.22], - [6.30, 1.22], - [6.30, 3.02], - [6.88, 3.02]]) - with pytest.raises(ValueError): - openmc.model.Polygon(rz_points) - - # Test "M" shaped polygon - points = np.array([[8.5151581, -17.988337], - [10.381711000000001, -17.988337], - [12.744357, -24.288728000000003], - [15.119406000000001, -17.988337], - [16.985959, -17.988337], - [16.985959, -27.246687], - [15.764328, -27.246687], - [15.764328, -19.116951], - [13.376877, -25.466951], - [12.118039, -25.466951], - [9.7305877, -19.116951], - [9.7305877, -27.246687], - [8.5151581, -27.246687]]) - - # Test points inside and outside by using offset method - m_polygon = openmc.model.Polygon(points, basis='xz') - inner_pts = m_polygon.offset(-0.1).points - assert all([(pt[0], 0, pt[1]) in -m_polygon for pt in inner_pts]) - outer_pts = m_polygon.offset(0.1).points - assert all([(pt[0], 0, pt[1]) in +m_polygon for pt in outer_pts]) - - # Offset of -0.2 will cause self-intersection - with pytest.raises(ValueError): - m_polygon.offset(-0.2) - - -@pytest.mark.parametrize("axis", ["x", "y", "z"]) -def test_cruciform_prism(axis): - center = x0, y0 = (3., 4.) - distances = [2., 3., 5.] - s = openmc.model.CruciformPrism(distances, center, axis=axis) - - if axis == 'x': - i1, i2 = 1, 2 - elif axis == 'y': - i1, i2 = 0, 2 - elif axis == 'z': - i1, i2 = 0, 1 - plane_cls = (openmc.XPlane, openmc.YPlane, openmc.ZPlane) - - # Check type of surfaces - for i in range(3): - assert isinstance(getattr(s, f'hmin{i}'), plane_cls[i1]) - assert isinstance(getattr(s, f'hmax{i}'), plane_cls[i1]) - assert isinstance(getattr(s, f'vmin{i}'), plane_cls[i2]) - assert isinstance(getattr(s, f'vmax{i}'), plane_cls[i2]) - - # Make sure boundary condition propagates - s.boundary_type = 'reflective' - for i in range(3): - assert getattr(s, f'hmin{i}').boundary_type == 'reflective' - assert getattr(s, f'hmax{i}').boundary_type == 'reflective' - assert getattr(s, f'vmin{i}').boundary_type == 'reflective' - assert getattr(s, f'vmax{i}').boundary_type == 'reflective' - - # Check bounding box - ll, ur = (+s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - ll, ur = (-s).bounding_box - assert ur[i1] == pytest.approx(x0 + distances[-1]) - assert ur[i2] == pytest.approx(y0 + distances[-1]) - assert ll[i1] == pytest.approx(x0 - distances[-1]) - assert ll[i2] == pytest.approx(y0 - distances[-1]) - - # __contains__ on associated half-spaces - point_pos, point_neg = np.zeros(3), np.zeros(3) - point_pos[i1] = x0 + 3.1 - point_pos[i2] = y0 + 2.05 - point_neg[i1] = x0 + 3.5 - point_neg[i2] = y0 + 1.99 - assert point_pos in +s - assert point_pos not in -s - assert point_neg in -s - assert point_neg not in +s - - # translate method - t = uniform(-5.0, 5.0) - s_t = s.translate((t, t, t)) - ll_t, ur_t = (-s_t).bounding_box - assert ur_t == pytest.approx(ur + t) - assert ll_t == pytest.approx(ll + t) - - # Make sure repr works - repr(s) - - # Check that non-monotonic distances fail - with pytest.raises(ValueError): - openmc.model.CruciformPrism([1.0, 0.5, 2.0, 3.0]) - with pytest.raises(ValueError): - openmc.model.CruciformPrism([3.0, 2.0, 0.5, 1.0]) - - -def test_box(): - v = (-1.0, -1.0, -2.5) - a1 = (2.0, -1.0, 0.0) - a2 = (1.0, 2.0, 0.0) - a3 = (0.0, 0.0, 5.0) - s = openmc.model.OrthogonalBox(v, a1, a2, a3) - for num in (1, 2, 3): - assert isinstance(getattr(s, f'ax{num}_min'), openmc.Plane) - assert isinstance(getattr(s, f'ax{num}_max'), openmc.Plane) - - # Make sure boundary condition propagates - s.boundary_type = 'reflective' - assert s.boundary_type == 'reflective' - for num in (1, 2, 3): - assert getattr(s, f'ax{num}_min').boundary_type == 'reflective' - assert getattr(s, f'ax{num}_max').boundary_type == 'reflective' - - # Check bounding box - ll, ur = (+s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - ll, ur = (-s).bounding_box - assert ll[2] == pytest.approx(-2.5) - assert ur[2] == pytest.approx(2.5) - - # __contains__ on associated half-spaces - assert (0., 0., 0.) in -s - assert (-2., 0., 0.) not in -s - assert (0., 0.9, 0.) in -s - assert (0., 0., -3.) in +s - assert (0., 0., 3.) in +s - - # translate method - s_t = s.translate((1., 1., 0.)) - assert (-0.01, 0., 0.) in +s_t - assert (0.01, 0., 0.) in -s_t - - # Make sure repr works - repr(s) - - # Version with infinite 3rd dimension - s = openmc.model.OrthogonalBox(v, a1, a2) - assert not hasattr(s, 'ax3_min') - assert not hasattr(s, 'ax3_max') - ll, ur = (-s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - assert (0., 0., 0.) in -s - assert (-2., 0., 0.) not in -s - assert (0., 0.9, 0.) in -s - assert (0., 0., -3.) not in +s - assert (0., 0., 3.) not in +s - - -def test_conical_frustum(): - center_base = (0.0, 0.0, -3) - axis = (0., 0., 3.) - r1 = 2.0 - r2 = 0.5 - s = openmc.model.ConicalFrustum(center_base, axis, r1, r2) - assert isinstance(s.cone, openmc.Cone) - assert isinstance(s.plane_bottom, openmc.Plane) - assert isinstance(s.plane_top, openmc.Plane) - - # Make sure boundary condition propagates - s.boundary_type = 'reflective' - assert s.boundary_type == 'reflective' - assert s.cone.boundary_type == 'reflective' - assert s.plane_bottom.boundary_type == 'reflective' - assert s.plane_top.boundary_type == 'reflective' - - # Check bounding box - ll, ur = (+s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - ll, ur = (-s).bounding_box - assert ll[2] == pytest.approx(-3.0) - assert ur[2] == pytest.approx(0.0) - - # __contains__ on associated half-spaces - assert (0., 0., -1.) in -s - assert (0., 0., -4.) not in -s - assert (0., 0., 1.) not in -s - assert (1., 1., -2.99) in -s - assert (1., 1., -0.01) in +s - - # translate method - s_t = s.translate((1., 1., 0.)) - assert (1., 1., -0.01) in -s_t - - # Make sure repr works - repr(s) - - # Denegenerate case with r1 = r2 - s = openmc.model.ConicalFrustum(center_base, axis, r1, r1) - assert (1., 1., -0.01) in -s - - -def test_vessel(): - center = (3.0, 2.0) - r = 1.0 - p1, p2 = -5.0, 5.0 - h1 = h2 = 1.0 - s = openmc.model.Vessel(r, p1, p2, h1, h2, center) - assert isinstance(s.cyl, openmc.Cylinder) - assert isinstance(s.plane_bottom, openmc.Plane) - assert isinstance(s.plane_top, openmc.Plane) - assert isinstance(s.bottom, openmc.Quadric) - assert isinstance(s.top, openmc.Quadric) - - # Make sure boundary condition propagates (but not for planes) - s.boundary_type = 'reflective' - assert s.boundary_type == 'reflective' - assert s.cyl.boundary_type == 'reflective' - assert s.bottom.boundary_type == 'reflective' - assert s.top.boundary_type == 'reflective' - assert s.plane_bottom.boundary_type == 'transmission' - assert s.plane_top.boundary_type == 'transmission' - - # Check bounding box - ll, ur = (+s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - ll, ur = (-s).bounding_box - assert np.all(np.isinf(ll)) - assert np.all(np.isinf(ur)) - - # __contains__ on associated half-spaces - assert (3., 2., 0.) in -s - assert (3., 2., -5.0) in -s - assert (3., 2., 5.0) in -s - assert (3., 2., -5.9) in -s - assert (3., 2., 5.9) in -s - assert (3., 2., -6.1) not in -s - assert (3., 2., 6.1) not in -s - assert (4.5, 2., 0.) in +s - assert (3., 3.2, 0.) in +s - assert (3., 2., 7.) in +s - - # translate method - s_t = s.translate((0., 0., 1.)) - assert (3., 2., 6.1) in -s_t - - # Make sure repr works - repr(s) diff --git a/tests/unit_tests/test_surface_flux.py b/tests/unit_tests/test_surface_flux.py deleted file mode 100644 index e4419252e..000000000 --- a/tests/unit_tests/test_surface_flux.py +++ /dev/null @@ -1,164 +0,0 @@ -"""Tests for surface flux tallying via flux score + SurfaceFilter.""" - -import math -import pytest - -import openmc - - -@pytest.fixture -def two_cell_model(): - """Simple two-cell slab model with a monodirectional fixed source. - - Cell1 occupies x in [-10, 0], cell2 x in [0, 10]. The source fires all - particles from (-5, 0, 0) in the +x direction with weight 1. Every - particle therefore crosses the surface at x=0 from cell1 into cell2 at - mu = 1 (normal incidence). - """ - openmc.reset_auto_ids() - model = openmc.Model() - - xmin = openmc.XPlane(-10.0, boundary_type="vacuum") - xmid = openmc.XPlane(0.0) - xmax = openmc.XPlane(10.0, boundary_type="vacuum") - ymin = openmc.YPlane(-10.0, boundary_type="vacuum") - ymax = openmc.YPlane(10.0, boundary_type="vacuum") - zmin = openmc.ZPlane(-10.0, boundary_type="vacuum") - zmax = openmc.ZPlane(10.0, boundary_type="vacuum") - - cell1 = openmc.Cell(region=+xmin & -xmid & +ymin & -ymax & +zmin & -zmax) - cell2 = openmc.Cell(region=+xmid & -xmax & +ymin & -ymax & +zmin & -zmax) - model.geometry = openmc.Geometry([cell1, cell2]) - - src = openmc.IndependentSource() - src.space = openmc.stats.Point((-5.0, 0.0, 0.0)) - src.angle = openmc.stats.Monodirectional((1.0, 0.0, 0.0)) - - model.settings.run_mode = 'fixed source' - model.settings.batches = 1 - model.settings.particles = 100 - model.settings.source = src - - return model, xmid, cell1, cell2 - - -def test_surface_filter_flux_normal_incidence(two_cell_model, run_in_tmpdir): - """SurfaceFilter + flux at mu=1 gives w/|mu| = 1.0 per source particle.""" - model, xmid, *_ = two_cell_model - - surf_filter = openmc.SurfaceFilter([xmid]) - flux_tally = openmc.Tally() - flux_tally.filters = [surf_filter] - flux_tally.scores = ['flux'] - model.tallies = [flux_tally] - - model.run(apply_tally_results=True) - flux_mean = flux_tally.mean.flat[0] - - # Every particle crosses at mu=1 with weight 1, so flux = 1.0 - assert flux_mean == pytest.approx(1.0, rel=1e-8) - - -def test_surface_filter_current_outward(two_cell_model, run_in_tmpdir): - """SurfaceFilter + current gives +1.0 for purely outward crossings.""" - model, xmid, *_ = two_cell_model - - surf_filter = openmc.SurfaceFilter([xmid]) - current_tally = openmc.Tally() - current_tally.filters = [surf_filter] - current_tally.scores = ['current'] - model.tallies = [current_tally] - - model.run(apply_tally_results=True) - current_mean = current_tally.mean.flat[0] - - # All crossings are outward → net current = +1.0 - assert current_mean == pytest.approx(1.0) - - -def test_surface_filter_flux_angled(two_cell_model, run_in_tmpdir): - """Surface flux at 60-degree incidence gives w/|mu| = 2.0.""" - model, xmid, *_ = two_cell_model - - # Modify source to use 60-degree angle from normal: mu = cos(60°) = 0.5 - mu = ux = 0.5 - uy = math.sqrt(1.0 - ux**2) - model.settings.source[0].angle = openmc.stats.Monodirectional((ux, uy, 0.0)) - - surf_filter = openmc.SurfaceFilter([xmid]) - flux_tally = openmc.Tally() - flux_tally.filters = [surf_filter] - flux_tally.scores = ['flux'] - model.tallies = [flux_tally] - - model.run(apply_tally_results=True) - flux_mean = flux_tally.mean.flat[0] - - # flux = w/|mu| = 1/0.5 = 2.0 - assert flux_mean == pytest.approx(1.0 / mu) - - -def test_surface_tally_during_lattice_crossing(run_in_tmpdir): - openmc.reset_auto_ids() - model = openmc.Model() - - xmin = openmc.XPlane(-1.0, boundary_type="vacuum") - xmax = openmc.XPlane(1.0, boundary_type="vacuum") - ymin = openmc.YPlane(-1.0, boundary_type="vacuum") - ymax = openmc.YPlane(1.0, boundary_type="vacuum") - zmin = openmc.ZPlane(-1.0, boundary_type="vacuum") - zmax = openmc.ZPlane(1.0, boundary_type="vacuum") - - inner_cell = openmc.Cell() - inner_univ = openmc.Universe(cells=[inner_cell]) - - tile_cell = openmc.Cell(fill=inner_univ) - tile_univ = openmc.Universe(cells=[tile_cell]) - - lattice = openmc.RectLattice() - lattice.lower_left = (-1.0, -1.0) - lattice.pitch = (1.0, 2.0) - lattice.universes = [[tile_univ, tile_univ]] - - root_cell = openmc.Cell( - fill=lattice, region=+xmin & -xmax & +ymin & -ymax & +zmin & -zmax) - model.geometry = openmc.Geometry([root_cell]) - - src = openmc.IndependentSource() - src.space = openmc.stats.Point((-0.5, 0.0, 0.0)) - src.angle = openmc.stats.Monodirectional((1.0, 0.0, 0.0)) - - model.settings.run_mode = 'fixed source' - model.settings.batches = 1 - model.settings.particles = 5 - model.settings.source = src - - current_tally = openmc.Tally() - current_tally.filters = [openmc.SurfaceFilter(xmax)] - current_tally.scores = ['current'] - model.tallies = [current_tally] - - model.run(apply_tally_results=True) - assert current_tally.mean.flat[0] == pytest.approx(1.0) - - -def test_cellfrom_filter_flux_directional(two_cell_model, run_in_tmpdir): - """SurfaceFilter + CellFromFilter + flux scores only the correct direction.""" - model, xmid, cell1, cell2 = two_cell_model - - surf_filter = openmc.SurfaceFilter([xmid]) - cellfrom_filter = openmc.CellFromFilter([cell1, cell2]) - - tally = openmc.Tally() - tally.filters = [surf_filter, cellfrom_filter] - tally.scores = ['flux'] - - model.tallies = [tally] - model.run(apply_tally_results=True) - mean_from1 = tally.mean.flat[0] - mean_from2 = tally.mean.flat[1] - - # All particles cross xmid from cell1 at mu=1 → flux = 1.0 - assert mean_from1 == pytest.approx(1.0) - # No particles cross xmid from cell2 → flux = 0 - assert mean_from2 == pytest.approx(0.0) diff --git a/tests/unit_tests/test_surface_source_write.py b/tests/unit_tests/test_surface_source_write.py deleted file mode 100644 index 6f18d32b7..000000000 --- a/tests/unit_tests/test_surface_source_write.py +++ /dev/null @@ -1,301 +0,0 @@ -"""Test the 'surf_source_write' setting used to store particles that cross -surfaces in a file for a given simulation.""" - -from pathlib import Path - -import openmc -import openmc.lib -import pytest -import h5py -import numpy as np - - -@pytest.fixture(scope="module") -def geometry(): - """Simple hydrogen sphere geometry""" - openmc.reset_auto_ids() - material = openmc.Material(name="H1") - material.add_element("H", 1.0) - sphere = openmc.Sphere(r=1.0, boundary_type="vacuum") - cell = openmc.Cell(region=-sphere, fill=material) - return openmc.Geometry([cell]) - - -@pytest.mark.parametrize( - "parameter", - [ - {"max_particles": 200}, - {"max_particles": 200, "cell": 1}, - {"max_particles": 200, "cellto": 1}, - {"max_particles": 200, "cellfrom": 1}, - {"max_particles": 200, "surface_ids": [2]}, - {"max_particles": 200, "surface_ids": [2], "cell": 1}, - {"max_particles": 200, "surface_ids": [2], "cellto": 1}, - {"max_particles": 200, "surface_ids": [2], "cellfrom": 1}, - {"max_particles": 200, "surface_ids": [2], "max_source_files": 1}, - ], -) -def test_xml_serialization(parameter, run_in_tmpdir): - """Check that the different use cases can be written and read in XML.""" - settings = openmc.Settings() - settings.surf_source_write = parameter - settings.export_to_xml() - - read_settings = openmc.Settings.from_xml() - assert read_settings.surf_source_write == parameter - - -@pytest.fixture(scope="module") -def model(): - """Simple hydrogen sphere geometry""" - openmc.reset_auto_ids() - model = openmc.Model() - - # Material - h1 = openmc.Material(name="H1") - h1.add_nuclide("H1", 1.0) - h1.set_density('g/cm3', 1e-7) - - # Geometry - radius = 1.0 - sphere = openmc.Sphere(r=radius, boundary_type="vacuum") - cell = openmc.Cell(region=-sphere, fill=h1) - model.geometry = openmc.Geometry([cell]) - - # Settings - model.settings = openmc.Settings() - model.settings.run_mode = "fixed source" - model.settings.particles = 100 - model.settings.batches = 3 - model.settings.seed = 1 - - distribution = openmc.stats.Point() - model.settings.source = openmc.IndependentSource(space=distribution) - return model - - -@pytest.mark.parametrize( - "max_particles, max_source_files", - [ - (100, 2), - (100, 3), - (100, 1), - ], -) -def test_number_surface_source_file_created(max_particles, max_source_files, - run_in_tmpdir, model): - """Check the number of surface source files written.""" - model.settings.surf_source_write = { - "max_particles": max_particles, - "max_source_files": max_source_files - } - model.run() - should_be_numbered = max_source_files > 1 - for i in range(1, max_source_files + 1): - if should_be_numbered: - assert Path(f"surface_source.{i}.h5").exists() - if not should_be_numbered: - assert Path("surface_source.h5").exists() - -ERROR_MSG_1 = ( - "A maximum number of particles needs to be specified " - "using the 'max_particles' parameter to store surface " - "source points." -) -ERROR_MSG_2 = "'cell', 'cellfrom' and 'cellto' cannot be used at the same time." - - -@pytest.mark.parametrize( - "parameter, error", - [ - ({"cell": 1}, ERROR_MSG_1), - ({"max_particles": 200, "cell": 1, "cellto": 1}, ERROR_MSG_2), - ({"max_particles": 200, "cell": 1, "cellfrom": 1}, ERROR_MSG_2), - ({"max_particles": 200, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2), - ({"max_particles": 200, "cell": 1, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2), - ], -) -def test_exceptions(parameter, error, run_in_tmpdir, geometry): - """Test parameters configuration that should return an error.""" - settings = openmc.Settings(run_mode="fixed source", batches=5, particles=100) - settings.surf_source_write = parameter - model = openmc.Model(geometry=geometry, settings=settings) - with pytest.raises(RuntimeError, match=error): - model.run() - - -@pytest.fixture(scope="module") -def model(): - """Simple hydrogen sphere divided in two hemispheres - by a z-plane to form 2 cells.""" - openmc.reset_auto_ids() - model = openmc.Model() - - # Material - material = openmc.Material(name="H1") - material.add_element("H", 1.0) - - # Geometry - radius = 1.0 - sphere = openmc.Sphere(r=radius, boundary_type="reflective") - plane = openmc.ZPlane(0.0) - cell_1 = openmc.Cell(region=-sphere & -plane, fill=material) - cell_2 = openmc.Cell(region=-sphere & +plane, fill=material) - root = openmc.Universe(cells=[cell_1, cell_2]) - model.geometry = openmc.Geometry(root) - - # Settings - model.settings = openmc.Settings() - model.settings.run_mode = "fixed source" - model.settings.particles = 100 - model.settings.batches = 3 - model.settings.seed = 1 - - bounds = [-radius, -radius, -radius, radius, radius, radius] - distribution = openmc.stats.Box(bounds[:3], bounds[3:]) - model.settings.source = openmc.IndependentSource(space=distribution) - - return model - - -@pytest.mark.parametrize( - "parameter", - [ - {"max_particles": 200, "cellto": 2, "surface_ids": [2]}, - {"max_particles": 200, "cellfrom": 2, "surface_ids": [2]}, - ], -) -def test_particle_direction(parameter, run_in_tmpdir, model): - """Test the direction of particles with the 'cellfrom' and 'cellto' parameters - on a simple model with only one surface of interest. - - Cell 2 is the upper hemisphere and surface 2 is the plane dividing the sphere - into two hemispheres. - - """ - model.settings.surf_source_write = parameter - model.run() - with h5py.File("surface_source.h5", "r") as f: - source = f["source_bank"] - - assert len(source) == 200 - - # We want to verify that the dot product of the surface's normal vector - # and the direction of the particle is either positive or negative - # depending on cellfrom or cellto. In this case, it is equivalent - # to just compare the z component of the direction of the particle. - for point in source: - if "cellto" in parameter.keys(): - assert point["u"]["z"] > 0.0 - elif "cellfrom" in parameter.keys(): - assert point["u"]["z"] < 0.0 - else: - assert False - - -@pytest.fixture -def model_dagmc(request): - """Model based on the mesh file 'dagmc.h5m' available from - tests/regression_tests/dagmc/legacy. - - """ - openmc.reset_auto_ids() - model = openmc.Model() - - # ============================================================================= - # Materials - # ============================================================================= - - u235 = openmc.Material(name="no-void fuel") - u235.add_nuclide("U235", 1.0, "ao") - u235.set_density("g/cc", 11) - u235.id = 40 - - water = openmc.Material(name="water") - water.add_nuclide("H1", 2.0, "ao") - water.add_nuclide("O16", 1.0, "ao") - water.set_density("g/cc", 1.0) - water.add_s_alpha_beta("c_H_in_H2O") - water.id = 41 - - model.materials = openmc.Materials([u235, water]) - - # ============================================================================= - # Geometry - # ============================================================================= - dagmc_path = Path(request.fspath).parent / "../regression_tests/dagmc/legacy/dagmc.h5m" - dagmc_univ = openmc.DAGMCUniverse(dagmc_path) - model.geometry = openmc.Geometry(dagmc_univ) - - # ============================================================================= - # Settings - # ============================================================================= - - model.settings = openmc.Settings() - model.settings.particles = 300 - model.settings.batches = 5 - model.settings.inactive = 1 - model.settings.seed = 1 - - source_box = openmc.stats.Box([-4, -4, -20], [4, 4, 20]) - model.settings.source = openmc.IndependentSource(space=source_box) - - return model - - -@pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled." -) -@pytest.mark.parametrize( - "parameter", - [ - {"max_particles": 200, "cellto": 1}, - {"max_particles": 200, "cellfrom": 1}, - ], -) -def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): - """Test the direction of particles with the 'cellfrom' and 'cellto' parameters - on a DAGMC model.""" - model_dagmc.settings.surf_source_write = parameter - model_dagmc.run() - - r = 7.0 - h = 20.0 - - with h5py.File("surface_source.h5", "r") as f: - source = f["source_bank"] - - assert len(source) == 200 - - for point in source: - - x, y, z = point["r"] - ux, uy, uz = point["u"] - - # If the point is on the upper or lower circle - if np.allclose(abs(z), h): - # If the point is also on the cylindrical surface - if np.allclose(np.sqrt(x**2 + y**2), r): - if "cellfrom" in parameter.keys(): - assert (uz * z > 0) or (ux * x + uy * y > 0) - elif "cellto" in parameter.keys(): - assert (uz * z < 0) or (ux * x + uy * y < 0) - else: - assert False - # If the point is not on the cylindrical surface - else: - if "cellfrom" in parameter.keys(): - assert uz * z > 0 - elif "cellto" in parameter.keys(): - assert uz * z < 0 - else: - assert False - # If the point is not on the upper or lower circle, - # meaning it is on the cylindrical surface - else: - if "cellfrom" in parameter.keys(): - assert ux * x + uy * y > 0 - elif "cellto" in parameter.keys(): - assert ux * x + uy * y < 0 - else: - assert False diff --git a/tests/unit_tests/test_tallies.py b/tests/unit_tests/test_tallies.py index 7b1bf0a2f..14319a0a2 100644 --- a/tests/unit_tests/test_tallies.py +++ b/tests/unit_tests/test_tallies.py @@ -1,8 +1,6 @@ -from math import sqrt import numpy as np -import pytest + import openmc -import scipy.stats as sps def test_xml_roundtrip(run_in_tmpdir): @@ -12,9 +10,8 @@ def test_xml_roundtrip(run_in_tmpdir): mesh.upper_right = (10., 10., 10.,) mesh.dimension = (5, 5, 5) mesh_filter = openmc.MeshFilter(mesh) - meshborn_filter = openmc.MeshBornFilter(mesh) tally = openmc.Tally() - tally.filters = [mesh_filter, meshborn_filter] + tally.filters = [mesh_filter] tally.nuclides = ['U235', 'I135', 'Li6'] tally.scores = ['total', 'fission', 'heating'] tally.derivative = openmc.TallyDerivative( @@ -30,11 +27,9 @@ def test_xml_roundtrip(run_in_tmpdir): assert len(new_tallies) == 1 new_tally = new_tallies[0] assert new_tally.id == tally.id - assert len(new_tally.filters) == 2 + assert len(new_tally.filters) == 1 assert isinstance(new_tally.filters[0], openmc.MeshFilter) assert np.allclose(new_tally.filters[0].mesh.lower_left, mesh.lower_left) - assert isinstance(new_tally.filters[1], openmc.MeshBornFilter) - assert np.allclose(new_tally.filters[1].mesh.lower_left, mesh.lower_left) assert new_tally.nuclides == tally.nuclides assert new_tally.scores == tally.scores assert new_tally.derivative.variable == tally.derivative.variable @@ -43,336 +38,4 @@ def test_xml_roundtrip(run_in_tmpdir): assert len(new_tally.triggers) == 1 assert new_tally.triggers[0].trigger_type == tally.triggers[0].trigger_type assert new_tally.triggers[0].threshold == tally.triggers[0].threshold - assert new_tally.triggers[0].scores == tally.triggers[0].scores - assert new_tally.multiply_density == tally.multiply_density - - -def test_tally_equivalence(): - tally_a = openmc.Tally() - tally_b = openmc.Tally(tally_id=tally_a.id) - - tally_a.name = 'new name' - assert tally_a != tally_b - tally_b.name = tally_a.name - assert tally_a == tally_b - - assert tally_a == tally_b - ef_a = openmc.EnergyFilter([0.0, 0.1, 1.0, 10.0e6]) - ef_b = openmc.EnergyFilter([0.0, 0.1, 1.0, 10.0e6]) - - tally_a.filters = [ef_a] - assert tally_a != tally_b - tally_b.filters = [ef_b] - assert tally_a == tally_b - - tally_a.scores = ['flux', 'absorption', 'fission', 'scatter'] - assert tally_a != tally_b - tally_b.scores = ['flux', 'absorption', 'fission', 'scatter'] - assert tally_a == tally_b - - tally_a.nuclides = [] - tally_b.nuclides = [] - assert tally_a == tally_b - - tally_a.nuclides = ['total'] - assert tally_a == tally_b - - # a tally with an estimator set to None is equal to - # a tally with an estimator specified - tally_a.estimator = 'collision' - assert tally_a == tally_b - tally_b.estimator = 'collision' - assert tally_a == tally_b - - tally_a.multiply_density = False - assert tally_a != tally_b - tally_b.multiply_density = False - assert tally_a == tally_b - - trigger_a = openmc.Trigger('rel_err', 0.025) - trigger_b = openmc.Trigger('rel_err', 0.025) - - tally_a.triggers = [trigger_a] - assert tally_a != tally_b - tally_b.triggers = [trigger_b] - assert tally_a == tally_b - - -def test_figure_of_merit(sphere_model, run_in_tmpdir): - # Run model with a few simple tally scores - tally = openmc.Tally() - tally.scores = ['total', 'absorption', 'scatter'] - sphere_model.tallies = [tally] - sp_path = sphere_model.run(apply_tally_results=True) - - # Get execution time and relative error - with openmc.StatePoint(sp_path) as sp: - time = sp.runtime['simulation'] - rel_err = tally.std_dev / tally.mean - - # Check that figure of merit is calculated correctly - assert tally.figure_of_merit == pytest.approx(1 / (rel_err**2 * time)) - - -def test_tally_application(sphere_model, run_in_tmpdir): - # Create a tally with most possible gizmos - tally = openmc.Tally(name='test tally') - ef = openmc.EnergyFilter([0.0, 0.1, 1.0, 10.0e6]) - mesh = openmc.RegularMesh.from_domain(sphere_model.geometry, (2, 2, 2)) - mf = openmc.MeshFilter(mesh) - tally.filters = [ef, mf] - tally.scores = ['flux', 'absorption', 'fission', 'scatter'] - sphere_model.tallies = [tally] - - # FIRST RUN - # run the simulation and apply results - sp_file = sphere_model.run(apply_tally_results=True) - # before calling for any property requiring results (including the equivalence check below), - # the following internal attributes of the original should be unset - assert tally._mean is None - assert tally._std_dev is None - assert tally._sum is None - assert tally._sum_sq is None - assert tally._num_realizations == 0 - # the statepoint file property should be set, however - assert tally._sp_filename == sp_file - - with openmc.StatePoint(sp_file) as sp: - assert tally in sp.tallies.values() - sp_tally = sp.tallies[tally.id] - - # at this point the tally information regarding results should be the same - assert (sp_tally.std_dev == tally.std_dev).all() - assert (sp_tally.mean == tally.mean).all() - assert sp_tally.nuclides == tally.nuclides - - # SECOND RUN - # change the number of particles and ensure that the results are different - sphere_model.settings.particles += 1 - sp_file = sphere_model.run(apply_tally_results=True) - - assert (sp_tally.std_dev != tally.std_dev).any() - assert (sp_tally.mean != tally.mean).any() - - # now re-read data from the new stateopint file and - # ensure that the new results match those in - # the latest statepoint - with openmc.StatePoint(sp_file) as sp: - assert tally in sp.tallies.values() - sp_tally = sp.tallies[tally.id] - - # at this point the tally information regarding results should be the same - assert (sp_tally.std_dev == tally.std_dev).all() - assert (sp_tally.mean == tally.mean).all() - assert sp_tally.nuclides == tally.nuclides - -def _tally_from_data(x, *, higher_moments=True, normality=True): - t = openmc.Tally() - t.scores = ["flux"] # 1 score - t.nuclides = [openmc.Nuclide("H1")] # 1 nuclide - t._sp_filename = "dummy.h5" # mark "results available" - t._results_read = True # don't try to read from disk - t._num_realizations = int(len(x)) # n - t.higher_moments = bool(higher_moments) - - x = np.asarray(x, dtype=float) - # (num_filter_bins=1, num_nuclides=1, num_scores=1) -> (1,1,1) arrays - t._sum = np.array([[[np.sum(x)]]], dtype=float) - t._sum_sq = np.array([[[np.sum(x**2)]]], dtype=float) - if higher_moments: - t._sum_third = np.array([[[np.sum(x**3)]]], dtype=float) - t._sum_fourth = np.array([[[np.sum(x**4)]]], dtype=float) - return t - -@pytest.mark.parametrize( - "x, skew_true, kurt_true", - [ # Rademacher distribution - (np.array([1.0, -1.0] * 200), 0.0, 1.0), - # Two-point {0,3} with p(0)=3/4, p(3)=1/4 - (np.concatenate([np.zeros(600), np.full(200, 3.0)]), 2.0 / sqrt(3.0), 7.0 / 3.0), - # Bernoulli distribution - (np.concatenate([np.ones(300), np.zeros(700)]), (1 - 2 * 0.3) / sqrt(0.3 * 0.7), (1 - 3 * 0.3 + 3 * 0.3**2) / (0.3 * 0.7)), - ], -) -def test_b1_b2_analytical_against_tally(x, skew_true, kurt_true): - t = _tally_from_data(x, higher_moments=True, normality=False) - - g1 = t.skew(bias=True)[0, 0, 0] - b2 = t.kurtosis(bias=True, fisher=False)[0, 0, 0] - - assert np.isclose(g1, skew_true, rtol=0, atol=1e-12) - assert np.isclose(b2, kurt_true, rtol=0, atol=1e-12) - -@pytest.mark.parametrize( - "draw, skew_true, kurt_true", - [(lambda rng, n: rng.normal(0, 1, n), 0.0, 3.0), # Normal - (lambda rng, n: rng.random(n), 0.0, 1.8), # Uniform(0,1) - (lambda rng, n: rng.exponential(1.0, n), 2.0, 9.0), # Exp(1) - (lambda rng, n: (rng.random(n) < 0.3).astype(float), - (1 - 2 * 0.3) / sqrt(0.3 * 0.7), - (1 - 3 * 0.3 + 3 * 0.3**2) / (0.3 * 0.7),),],) - -def test_b1_b2_scipy_and_theory(draw, skew_true, kurt_true): - rng = np.random.default_rng(12345) - N = 200_000 - x = draw(rng, N) - - # Tally outputs - t = _tally_from_data(x, higher_moments=True, normality=False) - g1_t = t.skew(bias=True)[0, 0, 0] - b2_t = t.kurtosis(bias=True, fisher=False)[0, 0, 0] - - # SciPy (population, bias=True to match population-moment style) - skew_sp = sps.skew(x, bias=True) - kurt_sp = sps.kurtosis(x, fisher=False, bias=True) - - # Compare to SciPy numerically - assert np.isclose(g1_t, skew_sp, rtol=0, atol=5e-3) - assert np.isclose(b2_t, kurt_sp, rtol=0, atol=5e-3) - - # Compare to analytical targets with size-dependent tolerances - tol_skew = 0.02 if abs(skew_true) < 0.5 else 0.05 - tol_kurt = 0.03 if kurt_true < 4 else 0.1 - assert abs(g1_t - skew_true) < tol_skew - assert abs(b2_t - kurt_true) < tol_kurt - - -def test_kurtosis_bias_fisher_combinations(): - """Test that all combinations of bias and fisher match scipy.stats.kurtosis""" - rng = np.random.default_rng(42) - x = rng.normal(0, 1, 10000) - - t = _tally_from_data(x, higher_moments=True, normality=False) # Test all four combinations - # 1. bias=True, fisher=False (Pearson's kurtosis, b2) - b2_tally = t.kurtosis(bias=True, fisher=False)[0, 0, 0] - b2_scipy = sps.kurtosis(x, fisher=False, bias=True) - assert np.isclose(b2_tally, b2_scipy, rtol=0, atol=1e-10) - assert np.isclose(b2_tally, 3.0, rtol=0.05, atol=0.1) # Should be ~3 for normal - - # 2. bias=True, fisher=True (excess kurtosis, g2) - g2_tally = t.kurtosis(bias=True, fisher=True)[0, 0, 0] - g2_scipy = sps.kurtosis(x, fisher=True, bias=True) - assert np.isclose(g2_tally, g2_scipy, rtol=0, atol=1e-10) - assert np.isclose(g2_tally, 0.0, rtol=0, atol=0.1) # Should be ~0 for normal - assert np.isclose(g2_tally, b2_tally - 3.0, rtol=0, atol=1e-10) # g2 = b2 - 3 - - # 3. bias=False, fisher=True (adjusted excess kurtosis, G2) - G2_tally = t.kurtosis(bias=False, fisher=True)[0, 0, 0] - G2_tally_default = t.kurtosis()[0, 0, 0] # Should be same as default - G2_scipy = sps.kurtosis(x, fisher=True, bias=False) - assert np.isclose(G2_tally, G2_tally_default, rtol=0, atol=1e-10) - assert np.isclose(G2_tally, G2_scipy, rtol=0, atol=1e-10) - assert np.isclose(G2_tally, 0.0, rtol=0, atol=0.1) # Should be ~0 for normal - - # 4. bias=False, fisher=False (adjusted Pearson's kurtosis) - adj_b2_tally = t.kurtosis(bias=False, fisher=False)[0, 0, 0] - adj_b2_scipy = sps.kurtosis(x, fisher=False, bias=False) - assert np.isclose(adj_b2_tally, adj_b2_scipy, rtol=0, atol=1e-10) - assert np.isclose(adj_b2_tally, 3.0, rtol=0.05, atol=0.1) # Should be ~3 for normal - assert np.isclose(adj_b2_tally, G2_tally + 3.0, rtol=0, atol=1e-10) # adj_b2 = G2 + 3 - - -def test_ztests_scipy_comparison(): - rng = np.random.default_rng(987) - x_norm = rng.normal(size=50_000) - x_exp = rng.exponential(size=50_000) - - # -------- Normal dataset (should not reject) -------- - t0 = _tally_from_data(x_norm, higher_moments=True, normality=True) - Zb1_0, p_skew_0 = t0.skewtest(alternative="two-sided") - Zb2_0, p_kurt_0 = t0.kurtosistest(alternative="two-sided") - K2_0, p_omni_0 = t0.normaltest(alternative="two-sided") - - Zb1_0 = Zb1_0.ravel()[0] - p_skew_0 = p_skew_0.ravel()[0] - Zb2_0 = Zb2_0.ravel()[0] - p_kurt_0 = p_kurt_0.ravel()[0] - K2_0 = K2_0.ravel()[0] - p_omni_0 = p_omni_0.ravel()[0] - - z_skew_sp0, p_skew_sp0 = sps.skewtest(x_norm) - z_kurt_sp0, p_kurt_sp0 = sps.kurtosistest(x_norm) - k2_sp0, p_omni_sp0 = sps.normaltest(x_norm) - - assert np.isclose(Zb1_0, z_skew_sp0, atol=0.15) - assert np.isclose(Zb2_0, z_kurt_sp0, atol=0.15) - assert np.isclose(K2_0, k2_sp0, atol=0.30) - assert np.isclose(p_skew_0, p_skew_sp0, atol=5e-3) - assert np.isclose(p_kurt_0, p_kurt_sp0, atol=5e-3) - assert np.isclose(p_omni_0, p_omni_sp0, atol=5e-3) - - # -------- Exponential dataset (should strongly reject) -------- - t1 = _tally_from_data(x_exp, higher_moments=True, normality=True) - - Zb1_1, p_skew_1 = t1.skewtest(alternative="two-sided") - Zb2_1, p_kurt_1 = t1.kurtosistest(alternative="two-sided") - K2_1, p_omni_1 = t1.normaltest(alternative="two-sided") - - Zb1_1 = Zb1_1.ravel()[0] - p_skew_1 = p_skew_1.ravel()[0] - Zb2_1 = Zb2_1.ravel()[0] - p_kurt_1 = p_kurt_1.ravel()[0] - K2_1 = K2_1.ravel()[0] - p_omni_1 = p_omni_1.ravel()[0] - - z_skew_sp1, p_skew_sp1 = sps.skewtest(x_exp) - z_kurt_sp1, p_kurt_sp1 = sps.kurtosistest(x_exp) - k2_sp1, p_omni_sp1 = sps.normaltest(x_exp) - - # Both pipelines should reject very strongly - assert p_skew_1 < 1e-6 and p_skew_sp1 < 1e-6 - assert p_kurt_1 < 1e-6 and p_kurt_sp1 < 1e-6 - assert p_omni_1 < 1e-6 and p_omni_sp1 < 1e-6 - - # Right-skewed and heavy-tailed → large positive Z-statistics - assert Zb1_1 > 30 and z_skew_sp1 > 30 - assert Zb2_1 > 30 and z_kurt_sp1 > 30 - assert K2_1 > 2000 and k2_sp1 > 2000 - -def test_vov_stochastic(sphere_model, run_in_tmpdir): - tally = openmc.Tally(name="test tally") - ef = openmc.EnergyFilter([0.0, 0.1, 1.0, 10.0e6]) - mesh = openmc.RegularMesh.from_domain(sphere_model.geometry, (2, 2, 2)) - mf = openmc.MeshFilter(mesh) - tally.filters = [ef, mf] - tally.scores = ["flux", "absorption", "fission", "scatter"] - tally.higher_moments = True - sphere_model.tallies = [tally] - - sp_file = sphere_model.run(apply_tally_results=True) - - assert tally._mean is None - assert tally._std_dev is None - assert tally._sum is None - assert tally._sum_sq is None - assert tally._sum_third is None - assert tally._sum_fourth is None - assert tally._num_realizations == 0 - assert tally._sp_filename == sp_file - - with openmc.StatePoint(sp_file) as sp: - assert tally in sp.tallies.values() - sp_tally = sp.tallies[tally.id] - - assert np.all(sp_tally.std_dev == tally.std_dev) - assert np.all(sp_tally.mean == tally.mean) - assert np.all(sp_tally.vov == tally.vov) - assert sp_tally.nuclides == tally.nuclides - - n = sp_tally.num_realizations - mean = sp_tally.mean - sum_ = sp_tally._sum - sum_sq = sp_tally._sum_sq - sum_third = sp_tally._sum_third - sum_fourth = sp_tally._sum_fourth - - expected_vov = np.zeros_like(mean) - nonzero = np.abs(mean) > 0 - - num = (sum_fourth - (4.0*sum_third*sum_)/n + (6.0*sum_sq*sum_**2)/(n**2) - - (3.0*sum_**4)/(n**3)) - den = (sum_sq - (1.0/n)*sum_**2)**2 - - expected_vov[nonzero] = num[nonzero]/den[nonzero] - 1.0/n - - assert np.allclose(expected_vov, sp_tally.vov, rtol=1e-7, atol=0.0) + assert new_tally.triggers[0].scores == tally.triggers[0].scores \ No newline at end of file diff --git a/tests/unit_tests/test_tally.py b/tests/unit_tests/test_tally.py deleted file mode 100644 index 7136a621b..000000000 --- a/tests/unit_tests/test_tally.py +++ /dev/null @@ -1,63 +0,0 @@ -import openmc - - -def test_tally_init_args(): - """Test that Tally constructor kwargs are applied correctly.""" - filter = openmc.EnergyFilter([0.0, 1.0, 20.0e6]) - tally = openmc.Tally( - name='my tally', - scores=['flux', 'fission'], - filters=[filter], - nuclides=['U235'], - estimator='tracklength', - ) - - assert tally.name == 'my tally' - assert tally.scores == ['flux', 'fission'] - assert tally.filters == [filter] - assert tally.nuclides == ['U235'] - assert tally.estimator == 'tracklength' - - -def test_heating_estimator_with_photon_transport(run_in_tmpdir): - """Test that a neutron-only heating tally uses the tracklength estimator - even when photon transport is enabled. - - Without a neutron particle filter, photon heating requires the collision - estimator (analog energy balance). But neutron heating has kerma - coefficients that support tracklength scoring, so a neutron-only tally - should keep the tracklength estimator. - """ - mat = openmc.Material() - mat.add_nuclide('Si28', 1.0) - mat.set_density('g/cm3', 2.3) - sph = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sph) - - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.run_mode = 'fixed source' - model.settings.particles = 100 - model.settings.batches = 1 - model.settings.photon_transport = True - model.settings.source = openmc.IndependentSource( - space=openmc.stats.Point() - ) - - neutron_filter = openmc.ParticleFilter(['neutron']) - - # Neutron-only heating — should get tracklength estimator - t_neutron = openmc.Tally(name='heating_neutron') - t_neutron.filters = [neutron_filter] - t_neutron.scores = ['heating'] - - # No particle filter — should get collision estimator - t_all = openmc.Tally(name='heating_all') - t_all.scores = ['heating'] - - model.tallies = [t_neutron, t_all] - - sp_filename = model.run() - with openmc.StatePoint(sp_filename) as sp: - assert sp.tallies[t_neutron.id].estimator == 'tracklength' - assert sp.tallies[t_all.id].estimator == 'collision' diff --git a/tests/unit_tests/test_tally_multiply_density.py b/tests/unit_tests/test_tally_multiply_density.py deleted file mode 100644 index 552d76bd5..000000000 --- a/tests/unit_tests/test_tally_multiply_density.py +++ /dev/null @@ -1,50 +0,0 @@ -import numpy as np -import openmc -import pytest - - -def test_micro_macro_compare(run_in_tmpdir): - # Create simple sphere model with H1 and H2 - mat = openmc.Material() - mat.add_components({'H1': 1.0, 'H2': 1.0}) - mat.set_density('g/cm3', 1.0) - sph = openmc.Sphere(r=10.0, boundary_type='vacuum') - cell = openmc.Cell(fill=mat, region=-sph) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - model.settings.run_mode = 'fixed source' - model.settings.particles = 1000 - model.settings.batches = 10 - - # Set up two reaction rate tallies, one that multplies by density and the - # other that doesn't - tally_macro = openmc.Tally() - tally_macro.nuclides = ['H1', 'H2', 'H3'] - tally_macro.scores = ['total', 'elastic'] - tally_micro = openmc.Tally() - tally_micro.nuclides = ['H1', 'H2', 'H3'] - tally_micro.scores = ['total', 'elastic'] - tally_micro.multiply_density = False - model.tallies = [tally_macro, tally_micro] - - sp_filename = model.run() - with openmc.StatePoint(sp_filename) as sp: - tally_macro = sp.tallies[tally_macro.id] - tally_micro = sp.tallies[tally_micro.id] - - # Make sure multply_density attribute from statepoint is set correctly - assert tally_macro.multiply_density - assert not tally_micro.multiply_density - - # Dividing macro by density should give micro - density = mat.get_nuclide_atom_densities() - for nuc in ('H1', 'H2'): - micro_derived = tally_macro.get_values(nuclides=[nuc]) / density[nuc] - micro = tally_micro.get_values(nuclides=[nuc]) - assert micro_derived == pytest.approx(micro) - - # For macro tally, H3 scores should be zero - assert np.all(tally_macro.get_values(nuclides=['H3']) == 0.0) - - # For micro tally, H3 scores should be positive - assert np.all(tally_micro.get_values(nuclides=['H3']) > 0.0) diff --git a/tests/unit_tests/test_temp_interp.py b/tests/unit_tests/test_temp_interp.py index 4566070cf..f87d52961 100644 --- a/tests/unit_tests/test_temp_interp.py +++ b/tests/unit_tests/test_temp_interp.py @@ -10,7 +10,7 @@ import pytest def make_fake_cross_section(): - """Create fake U235 nuclide with a fake thermal scattering library attached + """Create fake U235 nuclide This nuclide is designed to have k_inf=1 at 300 K, k_inf=2 at 600 K, and k_inf=1 at 900 K. The absorption cross section is also constant with @@ -81,62 +81,8 @@ def make_fake_cross_section(): # Export HDF5 file u235_fake.export_to_hdf5('U235_fake.h5', 'w') - # Create a fake thermal scattering library attached to the fake U235 data - c_U_fake = openmc.data.ThermalScattering("c_U_fake", 1.9968, 4.9, [0.0253]) - c_U_fake.nuclides = ['U235'] - - # Create elastic reaction - bragg_edges = [0.00370672, 0.00494229] - factors = [0.00375735, 0.01386287] - coherent_xs = openmc.data.CoherentElastic(bragg_edges, factors) - incoherent_xs_294 = openmc.data.Tabulated1D([0.00370672, 0.00370672], [0.00370672, 0.00370672]) - elastic_xs_base = openmc.data.Sum((coherent_xs, incoherent_xs_294)) - elastic_xs = {'294K': elastic_xs_base, '600K': elastic_xs_base} - coherent_dist = openmc.data.CoherentElasticAE(coherent_xs) - incoherent_dist_294 = openmc.data.IncoherentElasticAEDiscrete([ - [-0.6, -0.18, 0.18, 0.6], [-0.6, -0.18, 0.18, 0.6] - ]) - incoherent_dist_600 = openmc.data.IncoherentElasticAEDiscrete([ - [-0.1, -0.2, 0.2, 0.1], [-0.1, -0.2, 0.2, 0.1] - ]) - elastic_dist = { - '294K': openmc.data.MixedElasticAE(coherent_dist, incoherent_dist_294), - '600K': openmc.data.MixedElasticAE(coherent_dist, incoherent_dist_600) - } - c_U_fake.elastic = openmc.data.ThermalScatteringReaction(elastic_xs, elastic_dist) - - # Create inelastic reaction - inelastic_xs = { - '294K': openmc.data.Tabulated1D([1.0e-5, 4.9], [13.4, 3.35]), - '600K': openmc.data.Tabulated1D([1.0e-2, 10], [1.4, 5]) - } - breakpoints = [3] - interpolation = [2] - energy = [1.0e-5, 4.3e-2, 4.9] - energy_out = [ - openmc.data.Tabular([0.0002, 0.067, 0.146, 0.366], [0.25, 0.25, 0.25, 0.25]), - openmc.data.Tabular([0.0001, 0.009, 0.137, 0.277], [0.25, 0.25, 0.25, 0.25]), - openmc.data.Tabular([0.0579, 4.555, 4.803, 4.874], [0.25, 0.25, 0.25, 0.25]), - ] - for eout in energy_out: - eout.normalize() - eout.c = eout.cdf() - discrete = openmc.stats.Discrete([-0.9, -0.6, -0.3, -0.1, 0.1, 0.3, 0.6, 0.9], [1/8]*8) - discrete.c = discrete.cdf()[1:] - mu = [[discrete]*4]*3 - dist = openmc.data.IncoherentInelasticAE( - breakpoints, interpolation, energy, energy_out, mu) - inelastic_dist = {'294K': dist, '600K': dist} - inelastic = openmc.data.ThermalScatteringReaction(inelastic_xs, inelastic_dist) - c_U_fake.inelastic = inelastic - - # Export HDF5 file - c_U_fake.export_to_hdf5("c_U_fake.h5") - - # Create a data library of the fake nuclide and its thermal scattering data lib = openmc.data.DataLibrary() lib.register_file('U235_fake.h5') - lib.register_file("c_U_fake.h5") lib.export_to_xml('cross_sections_fake.xml') @@ -152,7 +98,7 @@ def model(tmp_path_factory): mat = openmc.Material() mat.add_nuclide('U235', 1.0) model.materials.append(mat) - model.materials.cross_sections = 'cross_sections_fake.xml' + model.materials.cross_sections = str(Path('cross_sections_fake.xml').resolve()) sph = openmc.Sphere(r=100.0, boundary_type='reflective') cell = openmc.Cell(fill=mat, region=-sph) @@ -173,23 +119,21 @@ def model(tmp_path_factory): @pytest.mark.parametrize( - ["method", "temperature", "fission_expected", "tolerance"], + ["method", "temperature", "fission_expected"], [ - ("nearest", 300.0, 0.5, 10), - ("nearest", 600.0, 1.0, 10), - ("nearest", 900.0, 0.5, 10), - ("interpolation", 360.0, 0.6, 10), - ("interpolation", 450.0, 0.75, 10), - ("interpolation", 540.0, 0.9, 10), - ("interpolation", 660.0, 0.9, 10), - ("interpolation", 750.0, 0.75, 10), - ("interpolation", 840.0, 0.6, 10), - ("interpolation", 295.0, 0.5, 10), - ("interpolation", 990.0, 0.5, 100), + ("nearest", 300.0, 0.5), + ("nearest", 600.0, 1.0), + ("nearest", 900.0, 0.5), + ("interpolation", 360.0, 0.6), + ("interpolation", 450.0, 0.75), + ("interpolation", 540.0, 0.9), + ("interpolation", 660.0, 0.9), + ("interpolation", 750.0, 0.75), + ("interpolation", 840.0, 0.6), ] ) -def test_interpolation(model, method, temperature, fission_expected, tolerance): - model.settings.temperature = {'method': method, 'default': temperature, "tolerance": tolerance} +def test_interpolation(model, method, temperature, fission_expected): + model.settings.temperature = {'method': method, 'default': temperature} sp_filename = model.run() with openmc.StatePoint(sp_filename) as sp: t = sp.tallies[model.tallies[0].id] @@ -208,68 +152,3 @@ def test_interpolation(model, method, temperature, fission_expected, tolerance): assert k.n == pytest.approx(nu*fission_expected) else: assert abs(k.n - nu*fission_expected) <= 3*k.s - - -def test_temperature_interpolation_tolerance(model): - """Test applying global and cell temperatures with thermal scattering libraries - """ - model.materials[0].add_s_alpha_beta("c_U_fake") - - # Default k-effective, using the thermal scattering data's minimum available temperature - model.settings.temperature = {'method': "nearest", 'default': 294, "tolerance": 50} - sp_filename = model.run() - with openmc.StatePoint(sp_filename) as sp: - default_k = sp.keff.n - - # Get k-effective with temperature below the minimum but in interpolation mode - model.settings.temperature = {'method': "interpolation", 'default': 255, "tolerance": 50} - sp_filename = model.run() - with openmc.StatePoint(sp_filename) as sp: - interpolated_k = sp.keff.n - - # Get the k-effective with the temperature applied to the cell, instead of globally - model.settings.temperature = {'method': "interpolation", 'default': 500, "tolerance": 50} - for cell in model.geometry.get_all_cells().values(): - cell.temperature = 275 - sp_filename = model.run() - with openmc.StatePoint(sp_filename) as sp: - cell_k = sp.keff.n - - # All calculated k-effectives should be equal - assert default_k == pytest.approx(interpolated_k) - assert interpolated_k == pytest.approx(cell_k) - - -def test_temperature_slightly_above(run_in_tmpdir): - """In this test, we have two materials at temperatures close to actual data - temperatures. However, one is slightly above the highest temperature which - invokes separate logic. The k-effective value should be somewhere between - k=2 (if the temperature were only 600 K) and k=1 (if the temperature were - only 900 K).""" - - make_fake_cross_section() - - model = openmc.Model() - mat1 = openmc.Material() - mat1.add_nuclide('U235', 1.0) - mat1.temperature = 900.1 - mat2 = openmc.Material() - mat2.add_nuclide('U235', 1.0) - mat2.temperature = 600.0 - model.materials.extend([mat1, mat2]) - model.materials.cross_sections = 'cross_sections_fake.xml' - - sph1 = openmc.Sphere(r=1.0) - sph2 = openmc.Sphere(r=4.0, boundary_type='reflective') - cell1 = openmc.Cell(fill=mat1, region=-sph1) - cell2 = openmc.Cell(fill=mat2, region=+sph1 & -sph2) - model.geometry = openmc.Geometry([cell1, cell2]) - - model.settings.particles = 1000 - model.settings.inactive = 0 - model.settings.batches = 10 - model.settings.temperature = {'method': 'interpolation'} - - sp_filename = model.run() - with openmc.StatePoint(sp_filename) as sp: - assert 1.1 < sp.keff.n < 1.9 diff --git a/tests/unit_tests/test_time_filter.py b/tests/unit_tests/test_time_filter.py index b57c80a97..45fabc544 100644 --- a/tests/unit_tests/test_time_filter.py +++ b/tests/unit_tests/test_time_filter.py @@ -59,7 +59,7 @@ def model(request): model.settings.particles = 1000 model.settings.batches = 20 particle = request.param - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( space=openmc.stats.Point((x, 0., 0.)), angle=openmc.stats.Monodirectional([-1., 0., 0.]), energy=openmc.stats.Discrete([E], [1.0]), @@ -100,7 +100,7 @@ def model_surf(request): model.settings.particles = 1000 model.settings.batches = 20 particle = request.param - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( space=openmc.stats.Point((0., 0., 0.)), angle=openmc.stats.Monodirectional([1., 0., 0.]), energy=openmc.stats.Discrete([E], [1.0]), @@ -165,7 +165,7 @@ def test_small_time_interval(run_in_tmpdir): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.IndependentSource( + model.settings.source = openmc.Source( time=openmc.stats.Discrete([1.0e8], [1.0]), particle='photon' ) diff --git a/tests/unit_tests/test_torus.py b/tests/unit_tests/test_torus.py index 8c413ffe0..ba92860e7 100644 --- a/tests/unit_tests/test_torus.py +++ b/tests/unit_tests/test_torus.py @@ -17,7 +17,7 @@ def get_torus_keff(cls, R, r, center=(0, 0, 0)): outer_cell = openmc.Cell(region=+torus & -sphere) model.geometry = openmc.Geometry([torus_cell, outer_cell]) - model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(center)) + model.settings.source = openmc.Source(space=openmc.stats.Point(center)) model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 1000 diff --git a/tests/unit_tests/test_tracks.py b/tests/unit_tests/test_tracks.py index 74da83552..be75c6f88 100644 --- a/tests/unit_tests/test_tracks.py +++ b/tests/unit_tests/test_tracks.py @@ -1,6 +1,5 @@ from pathlib import Path -import h5py import numpy as np import openmc import pytest @@ -49,7 +48,7 @@ def test_tracks(sphere_model, particle, run_in_tmpdir): sphere_model.settings.track = [(1, 1, 1), (1, 1, 10), (2, 1, 15)] # Set source particle - sphere_model.settings.source = openmc.IndependentSource(particle=particle) + sphere_model.settings.source = openmc.Source(particle=particle) # Run OpenMC to generate tracks.h5 file generate_track_file(sphere_model) @@ -70,7 +69,7 @@ def test_tracks(sphere_model, particle, run_in_tmpdir): particle_track = track.particle_tracks[0] assert isinstance(particle_track, openmc.ParticleTrack) - assert str(particle_track.particle).lower() == particle + assert particle_track.particle.name.lower() == particle assert isinstance(particle_track.states, np.ndarray) # Sanity checks on actual data @@ -140,10 +139,8 @@ def test_filter(sphere_model, run_in_tmpdir): assert matches == tracks matches = tracks.filter(state_filter=lambda s: s['E'] > 0.0) assert matches == tracks - matches = tracks.filter(particle='proton') + matches = tracks.filter(particle='bunnytron') assert matches == [] - with pytest.raises(ValueError): - tracks.filter(particle='bunnytron') def test_write_to_vtk(sphere_model): @@ -160,35 +157,3 @@ def test_write_to_vtk(sphere_model): assert isinstance(polydata, vtk.vtkPolyData) assert Path('tracks.vtp').is_file() - - -def test_restart_track(run_in_tmpdir, sphere_model): - # cut the sphere model in half with an improper boundary condition - plane = openmc.XPlane(x0=-1.0) - for cell in sphere_model.geometry.get_all_cells().values(): - cell.region &= +plane - - # generate lost particle files - with pytest.raises(RuntimeError, match='Maximum number of lost particles has been reached.'): - sphere_model.run(output=False, threads=1) - - lost_particle_files = list(Path.cwd().glob('particle_*.h5')) - assert len(lost_particle_files) > 0 - particle_file = lost_particle_files[0] - # restart the lost particle with tracks enabled - sphere_model.run(tracks=True, restart_file=particle_file) - tracks_file = Path('tracks.h5') - assert tracks_file.is_file() - - # check that the last track of the file matches the lost particle file - tracks = openmc.Tracks(tracks_file) - initial_state = tracks[0].particle_tracks[0].states[0] - restart_r = np.array(initial_state['r']) - restart_u = np.array(initial_state['u']) - - with h5py.File(particle_file, 'r') as lost_particle_file: - lost_r = np.array(lost_particle_file['xyz'][()]) - lost_u = np.array(lost_particle_file['uvw'][()]) - - pytest.approx(restart_r, lost_r) - pytest.approx(restart_u, lost_u) diff --git a/tests/unit_tests/test_triggers.py b/tests/unit_tests/test_triggers.py deleted file mode 100644 index 14bda0cce..000000000 --- a/tests/unit_tests/test_triggers.py +++ /dev/null @@ -1,146 +0,0 @@ - -import openmc - -def test_tally_trigger(run_in_tmpdir): - pincell = openmc.examples.pwr_pin_cell() - - # create a tally filter on the materials - mat_filter = openmc.MaterialFilter(pincell.materials) - - # create a tally with triggers applied - tally = openmc.Tally() - tally.filters = [mat_filter] - tally.scores = ['scatter'] - - trigger = openmc.Trigger('rel_err', 0.05) - trigger.scores = ['scatter'] - - tally.triggers = [trigger] - - pincell.tallies = [tally] - - pincell.settings.trigger_active = True - pincell.settings.trigger_max_batches = 100 - pincell.settings.trigger_batch_interval = 5 - - sp_file = pincell.run() - with openmc.StatePoint(sp_file) as sp: - expected_realizations = sp.n_realizations - - # adding other scores to the tally should not change the - # number of batches required to satisfy the trigger - tally.scores = ['total', 'absorption', 'scatter'] - - sp_file = pincell.run() - - with openmc.StatePoint(sp_file) as sp: - realizations = sp.n_realizations - - assert realizations == expected_realizations - - -def test_tally_trigger_null_score(run_in_tmpdir): - pincell = openmc.examples.pwr_pin_cell() - - # create a tally filter on the materials - mat_filter = openmc.MaterialFilter(pincell.materials) - - # apply a tally with a score that be tallied in this model - tally = openmc.Tally() - tally.filters = [mat_filter] - tally.scores = ['pair-production'] - - trigger = openmc.Trigger('rel_err', 0.05) - trigger.scores = ['pair-production'] - - tally.triggers = [trigger] - - pincell.tallies = [tally] - - pincell.settings.trigger_active = True - pincell.settings.trigger_max_batches = 50 - pincell.settings.trigger_batch_interval = 5 - - sp_file = pincell.run() - - with openmc.StatePoint(sp_file) as sp: - # verify that the tally mean is zero - tally_out = sp.get_tally(id=tally.id) - assert all(tally_out.mean == 0.0) - - # we expect that this simulation will run - # up to the max allowed batches - total_batches = sp.n_realizations + sp.n_inactive - assert total_batches == pincell.settings.trigger_max_batches - - -def test_tally_trigger_zero_ignored(run_in_tmpdir): - pincell = openmc.examples.pwr_pin_cell() - - # create an energy filter below and around the O-16(n,p) threshold (1.02e7 eV) - e_filter = openmc.EnergyFilter([0.0, 1e7, 2e7]) - - # create a tally with triggers applied - tally = openmc.Tally() - tally.filters = [e_filter] - tally.scores = ['(n,p)'] - tally.nuclides = ["O16"] - - # 100% relative error: should be immediately satisfied in nonzero bin - trigger = openmc.Trigger('rel_err', 1.0) - trigger.scores = ['(n,p)'] - trigger.ignore_zeros = True - - tally.triggers = [trigger] - - pincell.tallies = [tally] - - pincell.settings.particles = 1000 # we need a few more particles for this - pincell.settings.trigger_active = True - pincell.settings.trigger_max_batches = 50 - pincell.settings.trigger_batch_interval = 20 - - sp_file = pincell.run() - - with openmc.StatePoint(sp_file) as sp: - # verify that the first bin is zero and the second is nonzero - tally_out = sp.get_tally(id=tally.id) - below, above = tally_out.mean.squeeze() - assert below == 0.0, "Tally events observed below expected threshold" - assert above > 0, "No tally events observed. Test with more particles." - - # we expect that the trigger fires before max batches are hit - total_batches = sp.n_realizations + sp.n_inactive - assert total_batches < pincell.settings.trigger_max_batches - - - -def test_trigger_he3_production(run_in_tmpdir): - li6 = openmc.Material() - li6.set_density('g/cm3', 1.0) - li6.add_nuclide('Li6', 1.0) - - sph = openmc.Sphere(r=20, boundary_type='vacuum') - outer_cell = openmc.Cell(fill=li6, region=-sph) - model = openmc.Model() - model.geometry = openmc.Geometry([outer_cell]) - model.settings.source = openmc.IndependentSource( - energy=openmc.stats.delta_function(14.1e6) - ) - model.settings.batches = 10 - model.settings.particles = 100 - model.settings.run_mode = 'fixed source' - model.settings.trigger_active = True - model.settings.trigger_batch_interval = 10 - model.settings.trigger_max_batches = 30 - - # Define tally with trigger - trigger = openmc.Trigger(trigger_type='rel_err', threshold=0.0001) - trigger.scores = ['He3-production'] - he3_production_tally = openmc.Tally() - he3_production_tally.scores = ['He3-production'] - he3_production_tally.triggers = [trigger] - model.tallies = openmc.Tallies([he3_production_tally]) - - # Run model to verify that trigger works - model.run() diff --git a/tests/unit_tests/test_uniform_source_sampling.py b/tests/unit_tests/test_uniform_source_sampling.py deleted file mode 100644 index 0d1930328..000000000 --- a/tests/unit_tests/test_uniform_source_sampling.py +++ /dev/null @@ -1,82 +0,0 @@ -import openmc -import pytest - - -@pytest.fixture -def sphere_model(): - mat = openmc.Material() - mat.add_nuclide('Li6', 1.0) - mat.set_density('g/cm3', 1.0) - sphere = openmc.Sphere(r=1.0, boundary_type='vacuum') - cell = openmc.Cell(region=-sphere, fill=mat) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - - model.settings.particles = 100 - model.settings.batches = 1 - src1 = openmc.IndependentSource( - energy=openmc.stats.delta_function(1.0e3), - strength=75.0 - ) - src2 = openmc.IndependentSource( - energy=openmc.stats.delta_function(1.0e3), - strength=25.0 - ) - model.settings.source = [src1, src2] - model.settings.run_mode = "fixed source" - model.settings.surf_source_write = { - "max_particles": 100, - } - - tally = openmc.Tally() - tally.scores = ['flux'] - model.tallies = [tally] - return model - - -def test_source_weight(run_in_tmpdir, sphere_model): - # Run OpenMC without uniform source sampling and check that banked particles - # have weight 1 - sphere_model.settings.uniform_source_sampling = False - sphere_model.run() - particles = openmc.ParticleList.from_hdf5('surface_source.h5') - assert set(p.wgt for p in particles) == {1.0} - - # Run with uniform source sampling and check that banked particles have - # weight == strength - sphere_model.settings.uniform_source_sampling = True - sphere_model.run() - particles = openmc.ParticleList.from_hdf5('surface_source.h5') - assert set(p.wgt for p in particles) == {0.5, 1.5} - - -def test_tally_mean(run_in_tmpdir, sphere_model): - # Use only one source - sphere_model.settings.source.pop() - - # Run without uniform source sampling - sphere_model.settings.uniform_source_sampling = False - sp_file = sphere_model.run() - with openmc.StatePoint(sp_file) as sp: - reference_mean = sp.tallies[sphere_model.tallies[0].id].mean - - # Run with uniform source sampling - sphere_model.settings.uniform_source_sampling = True - sp_file = sphere_model.run() - with openmc.StatePoint(sp_file) as sp: - mean = sp.tallies[sphere_model.tallies[0].id].mean - - # Check that tally means match - assert mean == pytest.approx(reference_mean) - - -def test_multiple_sources(sphere_model): - low_strength_src = openmc.IndependentSource( - energy=openmc.stats.delta_function(1.0e6), strength=1e-7) - sphere_model.settings.source.append(low_strength_src) - sphere_model.settings.uniform_source_sampling = True - - # Sample particles from source and make sure 1 MeV shows up despite - # negligible strength - particles = sphere_model.sample_external_source(100) - assert {p.E for p in particles} == {1.0e3, 1.0e6} diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py index 0955347f7..ab3fd6e33 100644 --- a/tests/unit_tests/test_universe.py +++ b/tests/unit_tests/test_universe.py @@ -1,6 +1,5 @@ -from pathlib import Path +import xml.etree.ElementTree as ET -import lxml.etree as ET import numpy as np import openmc import pytest @@ -49,105 +48,19 @@ def test_bounding_box(): assert_unbounded(u) -def test_id(): - openmc.Universe(universe_id=0) - with pytest.raises(ValueError): - openmc.Universe(universe_id=-1) - - def test_plot(run_in_tmpdir, sphere_model): - - # model with -inf and inf in the bounding box - pincell = openmc.examples.pwr_pin_cell() - materials = pincell.materials - - mat_colors = { - materials[0]: (200, 1, 1), - materials[1]: "gray", - materials[2]: "limegreen" - } - - for basis in ('xy', 'yz', 'xz'): - plot = pincell.geometry.root_universe.plot( - colors=mat_colors, - color_by="material", - legend=True, - pixels=(10, 10), - basis=basis, - outline=True, - axis_units='m' - ) - assert plot.xaxis.get_label().get_text() == f'{basis[0]} [m]' - assert plot.yaxis.get_label().get_text() == f'{basis[1]} [m]' - - # model with no inf values in bounding box m = sphere_model.materials[0] univ = sphere_model.geometry.root_universe colors = {m: 'limegreen'} - for basis in ('xy', 'yz', 'xz'): - plot = univ.plot( - colors=colors, - color_by="cell", - legend=False, - pixels=100, - basis=basis, - outline=False - ) - assert plot.xaxis.get_label().get_text() == f'{basis[0]} [cm]' - assert plot.yaxis.get_label().get_text() == f'{basis[1]} [cm]' - - msg = "Must pass 'colors' dictionary if you are adding a legend via legend=True." - # This plot call should fail as legend is True but colors is None - with pytest.raises(ValueError, match=msg): univ.plot( - color_by="cell", - legend=True, - pixels=100, + basis=basis, + pixels=(10, 10), + color_by='material', + colors=colors, ) - # Close plots to avoid warning - import matplotlib.pyplot as plt - plt.close('all') - - -def test_mg_plot(run_in_tmpdir): - # Create a simple universe with macroscopic data - h2o_data = openmc.Macroscopic('LWTR') - water = openmc.Material(name='Water') - water.set_density('macro', 1.0) - water.add_macroscopic(h2o_data) - sph = openmc.Sphere(r=10, boundary_type="vacuum") - cell = openmc.Cell(region=-sph, fill=water) - univ = openmc.Universe(cells=[cell]) - - # Create MGXS library and export to HDF5 - groups = openmc.mgxs.EnergyGroups([1e-5, 20.0e6]) - h2o_xsdata = openmc.XSdata('LWTR', groups) - h2o_xsdata.order = 0 - h2o_xsdata.set_total([1.0]) - h2o_xsdata.set_absorption([0.5]) - scatter_matrix = np.array([[[0.5]]]) - scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) - h2o_xsdata.set_scatter_matrix(scatter_matrix) - mg_library = openmc.MGXSLibrary(groups) - mg_library.add_xsdatas([h2o_xsdata]) - mgxs_path = Path.cwd() / 'mgxs.h5' - mg_library.export_to_hdf5(mgxs_path) - - # Set MG cross sections in config and plot - with openmc.config.patch('mg_cross_sections', mgxs_path): - univ.plot(width=(200, 200), basis='yz', color_by='cell') - univ.plot(width=(200, 200), basis='yz', color_by='material') - - with pytest.raises(RuntimeError): - univ.plot(width=(200, 200), basis='yz', color_by='cell') - - # Close plots to avoid warning - import matplotlib.pyplot as plt - plt.close('all') - def test_get_nuclides(uo2): c = openmc.Cell(fill=uo2) @@ -180,12 +93,10 @@ def test_get_all_universes(): u2 = openmc.Universe(cells=[c2]) c3 = openmc.Cell(fill=u1) c4 = openmc.Cell(fill=u2) - u3 = openmc.DAGMCUniverse(filename="") - c5 = openmc.Cell(fill=u3) - u4 = openmc.Universe(cells=[c3, c4, c5]) + u3 = openmc.Universe(cells=[c3, c4]) - univs = set(u4.get_all_universes().values()) - assert not (univs ^ {u1, u2, u3}) + univs = set(u3.get_all_universes().values()) + assert not (univs ^ {u1, u2}) def test_clone(): @@ -196,13 +107,11 @@ def test_clone(): c2.fill = openmc.Material() c3 = openmc.Cell() u1 = openmc.Universe(name='cool', cells=(c1, c2, c3)) - u1.volume = 1. u2 = u1.clone() assert u2.name == u1.name assert u2.cells != u1.cells assert u2.get_all_materials() != u1.get_all_materials() - assert u2.volume == u1.volume u2 = u1.clone(clone_materials=False) assert u2.get_all_materials() == u1.get_all_materials() @@ -211,33 +120,6 @@ def test_clone(): assert next(iter(u3.cells.values())).region ==\ next(iter(u1.cells.values())).region - # Change attributes, make sure clone stays intact - u1.volume = 2. - u1.name = "different name" - assert u3.volume != u1.volume - assert u3.name != u1.name - - # Test cloning a DAGMC universe - dagmc_u = openmc.DAGMCUniverse(filename="", name="DAGMC universe") - dagmc_u.volume = 1. - dagmc_u.auto_geom_ids = True - dagmc_u.auto_mat_ids = True - dagmc_u1 = dagmc_u.clone() - assert dagmc_u1.name == dagmc_u.name - assert dagmc_u1.volume == dagmc_u.volume - assert dagmc_u1.auto_geom_ids == dagmc_u.auto_geom_ids - assert dagmc_u1.auto_mat_ids == dagmc_u.auto_mat_ids - - # Change attributes, check the clone remained intact - dagmc_u.name = "another name" - dagmc_u.auto_geom_ids = False - dagmc_u.auto_mat_ids = False - dagmc_u.volume = 2. - assert dagmc_u1.name != dagmc_u.name - assert dagmc_u1.volume != dagmc_u.volume - assert dagmc_u1.auto_geom_ids != dagmc_u.auto_geom_ids - assert dagmc_u1.auto_mat_ids != dagmc_u.auto_mat_ids - def test_create_xml(cell_with_lattice): cells = [openmc.Cell() for i in range(5)] @@ -250,14 +132,3 @@ def test_create_xml(cell_with_lattice): assert all(c.get('universe') == str(u.id) for c in cell_elems) assert not (set(c.get('id') for c in cell_elems) ^ set(str(c.id) for c in cells)) - - -def test_get_nuclide_densities(): - surf = openmc.Sphere() - material = openmc.Material() - material.add_elements_from_formula("H2O") - material.set_density("g/cm3", 1) - cell = openmc.Cell(region=-surf, fill=material) - universe = openmc.Universe(cells=[cell]) - with pytest.raises(RuntimeError): - universe.get_nuclide_densities() diff --git a/tests/unit_tests/test_urr_capture.py b/tests/unit_tests/test_urr_capture.py index 34b518e9d..745d62cef 100644 --- a/tests/unit_tests/test_urr_capture.py +++ b/tests/unit_tests/test_urr_capture.py @@ -19,7 +19,7 @@ def th232_model(): model.settings.batches = 10 model.settings.run_mode = 'fixed source' energies = openmc.stats.Uniform(e_min, e_max) - model.settings.source = openmc.IndependentSource(energy=energies) + model.settings.source = openmc.Source(energy=energies) tally = openmc.Tally(name='rates') tally.filters = [openmc.EnergyFilter([e_min, e_max])] diff --git a/tests/unit_tests/test_vectfit.py b/tests/unit_tests/test_vectfit.py deleted file mode 100644 index f7b2e905d..000000000 --- a/tests/unit_tests/test_vectfit.py +++ /dev/null @@ -1,224 +0,0 @@ -""" -Initially from Jingang Liang: https://github.com/mit-crpg/vectfit.git -""" - -import numpy as np -import pytest -from openmc.data.vectfit import evaluate, vectfit - - -@pytest.fixture -def ref_poles(): - """Reference poles for real-pole test.""" - return np.array( - [ - 9.709261771920490e02 + 0.0j, - -1.120960794075339e03 + 0.0j, - 1.923889557426567e00 + 7.543700246109742e01j, - 1.923889557426567e00 - 7.543700246109742e01j, - 1.159741300380281e02 + 3.595650922556496e-02j, - 1.159741300380281e02 - 3.595650922556496e-02j, - 1.546932165729394e02 + 8.728391144940301e-02j, - 1.546932165729394e02 - 8.728391144940301e-02j, - 2.280349190818197e02 + 2.814037559718684e-01j, - 2.280349190818197e02 - 2.814037559718684e-01j, - 2.313004772627853e02 + 3.004628477692201e-01j, - 2.313004772627853e02 - 3.004628477692201e-01j, - 2.787470098364861e02 + 3.414179169920170e-01j, - 2.787470098364861e02 - 3.414179169920170e-01j, - 3.570711338764254e02 + 4.485587371149193e-01j, - 3.570711338764254e02 - 4.485587371149193e-01j, - 4.701059001346060e02 + 6.598089307174224e-01j, - 4.701059001346060e02 - 6.598089307174224e-01j, - 7.275819506342254e02 + 1.189678974845038e03j, - 7.275819506342254e02 - 1.189678974845038e03j, - ] - ) - - -@pytest.fixture -def ref_residues(): - """Reference residues for real-pole test.""" - return np.array( - [ - [ - -3.269879776751686e07 + 0.0j, - 1.131087935798761e09 + 0.0j, - 1.634151281869857e04 + 2.251103589277891e05j, - 1.634151281869857e04 - 2.251103589277891e05j, - 3.281792303833561e03 - 1.756079516325274e04j, - 3.281792303833561e03 + 1.756079516325274e04j, - 1.110800880243503e04 - 4.324813594540043e04j, - 1.110800880243503e04 + 4.324813594540043e04j, - 8.812700704117636e04 - 2.256520243571103e05j, - 8.812700704117636e04 + 2.256520243571103e05j, - 5.842090495551535e04 - 1.442159380741478e05j, - 5.842090495551535e04 + 1.442159380741478e05j, - 1.339410514130921e05 - 2.640767909713812e05j, - 1.339410514130921e05 + 2.640767909713812e05j, - 2.211245633333130e05 - 3.222447758311512e05j, - 2.211245633333130e05 + 3.222447758311512e05j, - 4.124430059785149e05 - 4.076023108323907e05j, - 4.124430059785149e05 + 4.076023108323907e05j, - 1.607378314999252e09 - 1.401163320110452e08j, - 1.607378314999252e09 + 1.401163320110452e08j, - ] - ] - ) - - -@pytest.fixture -def vector_test_data(): - """Simple 2-signal test with known poles and residues.""" - Ns = 101 - s = np.linspace(3.0, 7.0, Ns) - poles = [5.0 + 0.1j, 5.0 - 0.1j] - residues = [[0.5 - 11.0j, 0.5 + 11.0j], [1.5 - 20.0j, 1.5 + 20.0j]] - f = np.zeros((2, Ns)) - for i in range(2): - f[i, :] = np.real( - residues[i][0] / (s - poles[0]) + residues[i][1] / (s - poles[1]) - ) - weight = 1.0 / f - init_poles = [3.5 + 0.035j, 3.5 - 0.035j] - return s, poles, residues, f, weight, init_poles - - -@pytest.fixture -def poly_test_data(): - """Test data with rational function plus polynomial terms.""" - Ns = 201 - s = np.linspace(0.0, 5.0, Ns) - poles = [-20.0 + 30.0j, -20.0 - 30.0j] - residues = [[5.0 + 10.0j, 5.0 - 10.0j]] - polys = [[1.0, 2.0, 0.3]] - f = evaluate(s, poles, residues, polys) - weight = 1.0 / f - init_poles = [2.5 + 0.025j, 2.5 - 0.025j] - return s, poles, residues, polys, f, weight, init_poles - - -@pytest.fixture -def real_poles_data(ref_poles, ref_residues): - """Large-scale signal using complex and real poles.""" - Ns = 2000 - s = np.linspace(1.0e-2, 5.0e3, Ns) - f = np.zeros((1, Ns)) - for p, r in zip(ref_poles, ref_residues[0]): - f[0] += (r / (s - p)).real - weight = 1.0 / f - poles = np.linspace(1.1e-2, 4.8e3, 10) - poles = poles + poles * 0.01j - poles = np.sort(np.append(poles, np.conj(poles))) - return s, f, weight, poles - - -@pytest.fixture -def large_test_data(): - """Stress test data with thousands of poles and samples.""" - Ns = 3000 - N = 200 - s = np.linspace(1.0e-2, 5.0e3, Ns) - poles = np.linspace(1.1e-2, 4.8e3, N // 2) + 0.01j * np.linspace( - 1.1e-2, 4.8e3, N // 2 - ) - poles = np.sort(np.append(poles, np.conj(poles))) - residues = np.linspace(1e2, 1e6, N // 2) + 0.5j * np.linspace(1e2, 1e6, N // 2) - residues = np.sort(np.append(residues, np.conj(residues))).reshape((1, N)) - f = np.zeros((1, Ns)) - for p, r in zip(poles, residues[0]): - f[0] += (r / (s - p)).real - weight = 1.0 / f - init_poles = np.linspace(1.2e-2, 4.7e3, N // 2) + 0.01j * np.linspace( - 1.2e-2, 4.7e3, N // 2 - ) - init_poles = np.sort(np.append(init_poles, np.conj(init_poles))) - return s, f, weight, init_poles - - -@pytest.fixture -def eval_test_data(): - """Reference data for evaluating rational + polynomial models.""" - Ns = 101 - s = np.linspace(-5.0, 5.0, Ns) - poles = [-2.0 + 30.0j, -2.0 - 30.0j] - residues = [5.0 + 10.0j, 5.0 - 10.0j] - polys = [1.0, 2.0, 0.3] - return s, poles, residues, polys - - -def test_vector(vector_test_data): - """Test vectfit with vector samples and simple poles. - It is expected to get exact results with one iteration. - """ - s, expected_poles, expected_residues, f, weight, init_poles = vector_test_data - poles, residues, _, fit, _ = vectfit(f, s, init_poles, weight) - assert np.allclose( - np.sort_complex(poles), np.sort_complex(expected_poles), rtol=1e-7 - ) - assert np.allclose(f, evaluate(s, poles, residues), rtol=1e-7) - assert np.allclose(f, fit, rtol=1e-5) - - -def test_poly(poly_test_data): - """Test vectfit with polynomials.""" - s, expected_poles, expected_residues, expected_polys, f, weight, init_poles = ( - poly_test_data - ) - poles, residues, cf, fit, _ = vectfit(f, s, init_poles, weight, n_polys=3) - poles, residues, cf, fit, _ = vectfit(f, s, poles, weight, n_polys=3) - assert np.allclose( - np.sort_complex(poles), np.sort_complex(expected_poles), rtol=1e-5 - ) - assert np.allclose(f, evaluate(s, poles, residues, cf), rtol=1e-5) - assert np.allclose(cf, expected_polys, rtol=1e-5) - assert np.allclose(f, fit, rtol=1e-4) - - -def test_real_poles(real_poles_data, ref_poles, ref_residues): - """Test vectfit with more poles including real poles""" - s, f, weight, poles = real_poles_data - for _ in range(6): - poles, residues, _, fit, _ = vectfit(f, s, poles, weight) - assert np.allclose( - np.sort_complex(poles), np.sort_complex(ref_poles), rtol=1e-5, atol=1e-8 - ) - assert np.allclose(f, evaluate(s, poles, residues), rtol=1e-4) - assert np.allclose(f, fit, rtol=1e-3) - - -def test_large(large_test_data): - """Test vectfit with a large set of poles and samples""" - s, f, weight, init_poles = large_test_data - poles_fit, residues_fit, _, f_fit, _ = vectfit(f, s, init_poles, weight) - assert np.allclose(f, f_fit, rtol=1e-3) - - -def test_evaluate(eval_test_data): - """Test evaluate function""" - s, poles, residues, polys = eval_test_data - - # Single signal, no polynomial - f_ref = np.real(residues[0] / (s - poles[0]) + residues[1] / (s - poles[1])) - f = evaluate(s, poles, residues) - assert np.allclose(f[0], f_ref) - - # Single signal, with polynomial - for n, c in enumerate(polys): - f_ref += c * np.power(s, n) - f = evaluate(s, poles, residues, polys) - assert np.allclose(f[0], f_ref) - - # Multi-signal, multi-residue, multi-poly - poles = [5.0 + 0.1j, 5.0 - 0.1j] - residues = [[0.5 - 11.0j, 0.5 + 11.0j], [1.5 - 20.0j, 1.5 + 20.0j]] - polys = [[1.0, 2.0, 0.3], [4.0, -2.0, -10.0]] - f_ref = np.zeros((2, len(s))) - for i in range(2): - f_ref[i, :] = np.real( - residues[i][0] / (s - poles[0]) + residues[i][1] / (s - poles[1]) - ) - for n, c in enumerate(polys[i]): - f_ref[i, :] += c * np.power(s, n) - f = evaluate(s, poles, residues, polys) - assert np.allclose(f, f_ref) diff --git a/tests/unit_tests/test_void.py b/tests/unit_tests/test_void.py deleted file mode 100644 index 8713d4b0b..000000000 --- a/tests/unit_tests/test_void.py +++ /dev/null @@ -1,42 +0,0 @@ -import numpy as np -import openmc -import pytest - - -@pytest.fixture -def empty_sphere(): - openmc.reset_auto_ids() - model = openmc.Model() - surf = openmc.Sphere(r=10, boundary_type='vacuum') - cell = openmc.Cell(region=-surf) - model.geometry = openmc.Geometry([cell]) - - model.settings.run_mode = 'fixed source' - model.settings.batches = 3 - model.settings.particles = 1000 - - tally = openmc.Tally() - tally.scores = ['total', 'elastic'] - tally.nuclides = ['U235'] - tally.multiply_density = False - model.tallies.append(tally) - - return model - - -def test_equivalent_microxs(empty_sphere, run_in_tmpdir): - sp_file = empty_sphere.run() - with openmc.StatePoint(sp_file) as sp: - tally1 = sp.tallies[1] - - mat = openmc.Material() - mat.add_nuclide('H1', 1e-16) - - empty_sphere.geometry.get_all_cells()[1].fill = mat - - sp_file = empty_sphere.run() - with openmc.StatePoint(sp_file) as sp: - tally2 = sp.tallies[1] - - assert np.isclose(tally1.mean.sum(), tally2.mean.sum(), rtol=1e-10, atol=0) - assert tally1.mean.sum() > 0 diff --git a/tests/unit_tests/test_volume.py b/tests/unit_tests/test_volume.py deleted file mode 100644 index 0993cb66a..000000000 --- a/tests/unit_tests/test_volume.py +++ /dev/null @@ -1,45 +0,0 @@ -import numpy as np -import pytest - -import openmc - - -def test_infinity_handling(): - surf1 = openmc.Sphere(boundary_type="vacuum") - cell1 = openmc.Cell(region=-surf1) - - lower_left = (-2, -np.inf, -2) - upper_right = (np.inf, 2, 2) - - with pytest.raises(ValueError, match="must be finite"): - openmc.VolumeCalculation([cell1], 100, lower_left, upper_right) - - -@pytest.mark.parametrize('cls', [openmc.Cell, openmc.Material, openmc.Universe]) -def test_invalid_id(run_in_tmpdir, cls): - m = openmc.Material() - m.add_nuclide('U235', 0.02) - sph = openmc.Sphere(boundary_type='vacuum') - cell = openmc.Cell(fill=m, region=-sph) - model = openmc.Model(geometry=openmc.Geometry([cell])) - - # Apply volume calculation with unused domains - model.settings.volume_calculations = openmc.VolumeCalculation( - [cls()], 10000, *model.geometry.bounding_box) - - with pytest.raises(RuntimeError): - model.calculate_volumes() - - -def test_no_bcs(run_in_tmpdir): - """Ensure that a model without boundary conditions can be used in a volume calculation""" - model = openmc.examples.pwr_pin_cell() - for surface in model.geometry.get_all_surfaces().values(): - surface.boundary_type = 'transmission' - - bbox = openmc.BoundingBox([-1.]*3, [1.]*3) - cells = list(model.geometry.get_all_cells().values()) - vc = openmc.VolumeCalculation(cells, samples=10, lower_left=bbox[0], upper_right=bbox[1]) - - model.settings.volume_calculations = [vc] - model.calculate_volumes() diff --git a/tests/unit_tests/test_waste_classification.py b/tests/unit_tests/test_waste_classification.py deleted file mode 100644 index 072590df9..000000000 --- a/tests/unit_tests/test_waste_classification.py +++ /dev/null @@ -1,102 +0,0 @@ -import random - -import openmc -import pytest - - -@pytest.mark.parametrize("metal", [False, True]) -def test_waste_classification_long(metal): - """Test classification when determined by long-lived radionuclides""" - f = 10.0 if metal else 1.0 - limit = 8.0*f - mat = openmc.Material() - mat.add_nuclide('C14', 1e-9*f) - assert mat.get_activity('Ci/m3') < 0.1 * limit - assert mat.waste_classification(metal=metal) == 'Class A' - - mat = openmc.Material() - mat.add_nuclide('C14', 1e-8*f) - assert 0.1 * limit < mat.get_activity('Ci/m3') < limit - assert mat.waste_classification(metal=metal) == 'Class C' - - mat = openmc.Material() - mat.add_nuclide('C14', 1e-7*f) - assert mat.get_activity('Ci/m3') > limit - assert mat.waste_classification(metal=metal) == 'GTCC' - - -@pytest.mark.parametrize("metal", [False, True]) -def test_waste_classification_short(metal): - """Test classification when determined by short-lived radionuclides""" - f = 10.0 if metal else 1.0 - col1, col2, col3 = 3.5*f, 70.0*f, 700.0*f - - mat = openmc.Material() - mat.add_nuclide('Ni63', 1e-10*f) - assert mat.get_activity('Ci/m3') < col1 - assert mat.waste_classification(metal=metal) == 'Class A' - - mat = openmc.Material() - mat.add_nuclide('Ni63', 1e-10*10*f) - assert col1 < mat.get_activity('Ci/m3') < col2 - assert mat.waste_classification(metal=metal) == 'Class B' - - mat = openmc.Material() - mat.add_nuclide('Ni63', 1e-10*200*f) - assert col2 < mat.get_activity('Ci/m3') < col3 - assert mat.waste_classification(metal=metal) == 'Class C' - - mat = openmc.Material() - mat.add_nuclide('Ni63', 1e-10*2000*f) - assert mat.get_activity('Ci/m3') > col3 - assert mat.waste_classification(metal=metal) == 'GTCC' - - -def test_waste_classification_mix(): - """Test classification when determined by a mix of radionuclides""" - # Check example from 10 CFR 61.55 with mix of Sr90 and Cs137 - mat = openmc.Material() - mat.add_nuclide('Sr90', 2.425e-9) - mat.add_nuclide('Cs137', 1.115e-9) - - # In example, activity of Sr90 is 50.0 Ci/m3 and Cs137 is 22.0 Ci/m3 - activity = mat.get_activity(units='Ci/m3', by_nuclide=True) - assert activity['Sr90'] == pytest.approx(50.0, 0.01) - assert activity['Cs137'] == pytest.approx(22.0, 0.01) - - # According to example, the waste should be class B - assert mat.waste_classification() == 'Class B' - - -def test_waste_rating_fetter(): - """Test waste classification using the Fetter limits""" - # For Tc99, Fetter has a more strict limit. Here, we create a material with - # Tc99 at 1 Ci/m3 which exceeds Fetter but not NRC - density = 3.5561e-7 - mat = openmc.Material() - mat.add_nuclide('Tc99', density) - assert mat.get_activity('Ci/m3') == pytest.approx(1.0, 1e-3) - assert mat.waste_disposal_rating(limits='NRC_short_C') < 1.0 - assert mat.waste_disposal_rating(limits='Fetter') > 1.0 - - # With a lower density, it should be Class C under Fetter limits and Class A - # under NRC limits - mat = openmc.Material() - mat.add_nuclide('Tc99', 5.0e-2*density) - assert mat.waste_disposal_rating(limits='NRC_short_A') < 1.0 - assert mat.waste_disposal_rating(limits='Fetter') < 1.0 - - -def test_waste_disposal_rating(): - """Test waste_disposal_rating method""" - mat = openmc.Material() - mat.add_nuclide('K40', random.random()) - - # Check for correct classification based on actual activity - ci_m3 = mat.get_activity('Ci/m3') - assert mat.waste_disposal_rating(limits={'K40': 2*ci_m3}) < 1.0 - assert mat.waste_disposal_rating(limits={'K40': 0.5*ci_m3}) > 1.0 - - wdr = mat.waste_disposal_rating(limits={'K40': 4*ci_m3}, by_nuclide=True) - assert isinstance(wdr, dict) - assert wdr['K40'] == pytest.approx(1/4) diff --git a/tests/unit_tests/weightwindows/dagmc/__init__.py b/tests/unit_tests/weightwindows/dagmc/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/unit_tests/weightwindows/dagmc/nested_shell_geometry.h5m b/tests/unit_tests/weightwindows/dagmc/nested_shell_geometry.h5m deleted file mode 100644 index af1d5563d..000000000 Binary files a/tests/unit_tests/weightwindows/dagmc/nested_shell_geometry.h5m and /dev/null differ diff --git a/tests/unit_tests/weightwindows/dagmc/test.py b/tests/unit_tests/weightwindows/dagmc/test.py deleted file mode 100644 index ed01a93ed..000000000 --- a/tests/unit_tests/weightwindows/dagmc/test.py +++ /dev/null @@ -1,98 +0,0 @@ -import pytest - -import openmc -import openmc.lib - -pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), - reason="DAGMC CAD geometry is not enabled.", -) - - -def test_dagmc_weight_windows_near_boundary(run_in_tmpdir, request): - """Ensure splitting near a boundary doesn't lose particles due to - a stale DAGMC history on the particle object.""" - - # DAGMC model overview: - # * Three nested cubes; innermost cube contains a fusion neutron source. - # * Two outer cubes filled with tungsten. Weight windows defined on a mesh - # cause particles to split moving outward. - # Outer cubes are similar in size (outer slightly larger) so particles - # frequently cross the problem boundary immediately after splitting. No lost - # particles are allowed to the correct DAGMC history after splitting is used. - model = openmc.Model() - - dagmc_file = request.path.parent / 'nested_shell_geometry.h5m' - dagmc_univ = openmc.DAGMCUniverse(dagmc_file) - model.geometry = openmc.Geometry(dagmc_univ) - - tungsten = openmc.Material(name='shell') - tungsten.add_element('W', 1.0) - tungsten.set_density('g/cm3', 7.8) - materials = openmc.Materials([tungsten]) - model.materials = materials - - settings = openmc.Settings() - settings.output = {'tallies': False, 'summary': False} - - source = openmc.IndependentSource() - source.space = openmc.stats.Point((0.0, 0.0, 0.0)) - source.angle = openmc.stats.Isotropic() - source.energy = openmc.stats.Discrete([14.1e6], [1.0]) - settings.source = source - - settings.batches = 2 - settings.particles = 500 - settings.run_mode = 'fixed source' - settings.survival_biasing = False - settings.max_lost_particles = 1 - settings.max_history_splits = 10_000_000 - - settings.weight_window_checkpoints = { - 'surface': True, - 'collision': True, - } - - mesh = openmc.RegularMesh() - mesh.lower_left = (-60.0, -60.0, -60.0) - mesh.upper_right = (60.0, 60.0, 60.0) - mesh.dimension = (24, 1, 1) - - weight_windows_lower = [ - 0.030750733294361156, - 0.056110505674355333, - 0.08187875047968339, - 0.1101743496347699, - 0.13982370013053508, - 0.17443799246829372, - 0.21576286623367483, - 0.26416659508033646, - 0.318574932646899, - 0.3804031702117963, - 0.42899359749256355, - 0.4954283294279403, - 0.49999999999999994, - 0.43432341070872266, - 0.38302303850488206, - 0.32148375935490886, - 0.2637416945702018, - 0.21498369367288853, - 0.17163611765361744, - 0.13832102142074995, - 0.10717772257151495, - 0.07986176041282561, - 0.05499644859408233, - 0.03058023506703803, - ] - - weight_windows = openmc.WeightWindows( - mesh, - lower_ww_bounds=weight_windows_lower, - upper_bound_ratio=5.0, - ) - weight_windows.max_lower_bound_ratio = 1.0 - settings.weight_windows = weight_windows - settings.weight_windows_on = True - model.settings = settings - - model.run() \ No newline at end of file diff --git a/tests/unit_tests/weightwindows/test.py b/tests/unit_tests/weightwindows/test.py index efa203b51..d065ef6d2 100644 --- a/tests/unit_tests/weightwindows/test.py +++ b/tests/unit_tests/weightwindows/test.py @@ -4,54 +4,12 @@ from pathlib import Path import numpy as np import pytest from uncertainties import ufloat + import openmc -import openmc.lib from openmc.stats import Discrete, Point from tests import cdtemp - -@pytest.fixture -def wws(): - - # weight windows - ww_files = ('ww_n.txt', 'ww_p.txt') - cwd = Path(__file__).parent.absolute() - ww_n_file, ww_p_file = [cwd / Path(f) for f in ww_files] - - # load pre-generated weight windows - # (created using the same tally as above) - ww_n_lower_bnds = np.loadtxt(ww_n_file) - ww_p_lower_bnds = np.loadtxt(ww_p_file) - - # create a mesh matching the one used - # to generate the weight windows - ww_mesh = openmc.RegularMesh() - ww_mesh.lower_left = (-240, -240, -240) - ww_mesh.upper_right = (240, 240, 240) - ww_mesh.dimension = (5, 6, 7) - - # energy bounds matching those of the - # generated weight windows - e_bnds = [0.0, 0.5, 2E7] - - ww_n = openmc.WeightWindows(ww_mesh, - ww_n_lower_bnds, - None, - 10.0, - e_bnds, - survival_ratio=1.01) - - ww_p = openmc.WeightWindows(ww_mesh, - ww_p_lower_bnds, - None, - 10.0, - e_bnds, - survival_ratio=1.01) - - return [ww_n, ww_p] - - @pytest.fixture def model(): openmc.reset_auto_ids() @@ -93,12 +51,12 @@ def model(): settings.run_mode = 'fixed source' settings.particles = 500 settings.batches = 2 - settings.max_history_splits = 100 + settings.max_splits = 100 settings.photon_transport = True space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) - settings.source = openmc.IndependentSource(space=space, energy=energy) + settings.source = openmc.Source(space=space, energy=energy) # tally mesh = openmc.RegularMesh() @@ -122,8 +80,7 @@ def model(): return model -@pytest.mark.parametrize("shared_secondary", [False, True]) -def test_weightwindows(model, wws, shared_secondary): +def test_weightwindows(model): ww_files = ('ww_n.txt', 'ww_p.txt') cwd = Path(__file__).parent.absolute() @@ -132,11 +89,42 @@ def test_weightwindows(model, wws, shared_secondary): with cdtemp(filepaths): # run once with variance reduction off model.settings.weight_windows_on = False - model.settings.shared_secondary_bank = shared_secondary analog_sp = model.run() os.rename(analog_sp, 'statepoint.analog.h5') - model.settings.weight_windows = wws + # weight windows + + # load pre-generated weight windows + # (created using the same tally as above) + ww_n_lower_bnds = np.loadtxt('ww_n.txt') + ww_p_lower_bnds = np.loadtxt('ww_p.txt') + + # create a mesh matching the one used + # to generate the weight windows + ww_mesh = openmc.RegularMesh() + ww_mesh.lower_left = (-240, -240, -240) + ww_mesh.upper_right = (240, 240, 240) + ww_mesh.dimension = (5, 6, 7) + + # energy bounds matching those of the + # generated weight windows + e_bnds = [0.0, 0.5, 2E7] + + ww_n = openmc.WeightWindows(ww_mesh, + ww_n_lower_bnds, + None, + 10.0, + e_bnds, + survival_ratio=1.01) + + ww_p = openmc.WeightWindows(ww_mesh, + ww_p_lower_bnds, + None, + 10.0, + e_bnds, + survival_ratio=1.01) + + model.settings.weight_windows = [ww_n, ww_p] # check that string form of the class can be created for ww in model.settings.weight_windows: @@ -207,177 +195,3 @@ def test_weightwindows(model, wws, shared_secondary): compare_results('neutron', analog_tally, ww_tally) compare_results('photon', analog_tally, ww_tally) - - -def test_lower_ww_bounds_shape(): - """checks that lower_ww_bounds is reshaped to the mesh dimension when set""" - ww_mesh = openmc.RegularMesh() - ww_mesh.lower_left = (-10, -10, -10) - ww_mesh.upper_right = (10, 10, 10) - ww_mesh.dimension = (2, 3, 4) - - ww = openmc.WeightWindows( - mesh=ww_mesh, - lower_ww_bounds=[1]*24, - upper_bound_ratio=5, - energy_bounds=(1, 1e40) - ) - assert ww.lower_ww_bounds.shape == (2, 3, 4, 1) - - -@pytest.mark.parametrize("shared_secondary", [False, True]) -def test_photon_heating(run_in_tmpdir, shared_secondary): - water = openmc.Material() - water.add_nuclide('H1', 1.0) - water.add_nuclide('O16', 2.0) - water.set_density('g/cm3', 1.0) - - box = openmc.model.RectangularParallelepiped( - -300, 300, -300, 300, -300, 300, boundary_type='reflective') - cell = openmc.Cell(region=-box, fill=water) - model = openmc.Model() - model.geometry = openmc.Geometry([cell]) - - mesh = openmc.RegularMesh.from_domain(model.geometry, dimension=(5, 5, 5)) - wwg = openmc.WeightWindowGenerator(mesh, particle_type='photon') - model.settings.weight_window_generators = [wwg] - - space = openmc.stats.Point((0, 0, 0)) - energy = openmc.stats.delta_function(5e6) - model.settings.source = openmc.IndependentSource( - space=space, energy=energy, particle='photon') - - model.settings.run_mode = 'fixed source' - model.settings.batches = 5 - model.settings.particles = 101 - model.settings.shared_secondary_bank = shared_secondary - - tally = openmc.Tally() - tally.scores = ['heating'] - tally.filters = [ - openmc.ParticleFilter(['photon']), - openmc.MeshFilter(mesh) - ] - model.tallies = [tally] - - sp_file = model.run() - with openmc.StatePoint(sp_file) as sp: - tally_mean = sp.tallies[tally.id].mean - - # Note: Our current physics model actually does allow this tally to - # occasionally go slightly negative. However, larger bugs can - # make this more common. We have selected a particle count for - # this test that happens to produce no negative tallies for both - # the shared and non-shared secondary PRNG streams. - assert np.all(tally_mean >= 0) - - -def test_roundtrip(run_in_tmpdir, model, wws): - model.settings.weight_windows = wws - - # write the model with weight windows to XML - model.export_to_xml() - - # ensure that they can be read successfully from XML and that they match the input values - model_read = openmc.Model.from_xml() - - zipped_wws = zip(model.settings.weight_windows, - model_read.settings.weight_windows) - - # ensure the lower bounds read in from the XML match those of the - for ww_out, ww_in in zipped_wws: - assert(ww_out == ww_in) - - -def test_ww_attrs_python(model): - mesh = openmc.RegularMesh.from_domain(model.geometry) - lower_bounds = np.ones(mesh.dimension) - - # ensure that creation of weight window objects with default arg values - # is successful - wws = openmc.WeightWindows(mesh, lower_bounds, upper_bound_ratio=10.0) - - assert wws.energy_bounds is None - - wwg = openmc.WeightWindowGenerator(mesh) - - assert wwg.energy_bounds is None - -def test_ww_attrs_capi(run_in_tmpdir, model): - model.export_to_xml() - - openmc.lib.init() - - tally = openmc.lib.tallies[model.tallies[0].id] - - wws = openmc.lib.WeightWindows.from_tally(tally) - - # this is the first weight window object created - assert wws.id == 1 - - with pytest.raises(ValueError): - tally.find_filter(openmc.lib.AzimuthalFilter) - - mesh_filter = tally.find_filter(openmc.lib.MeshFilter) - mesh = mesh_filter.mesh - - assert wws.mesh.id == mesh.id - - assert wws.particle == openmc.ParticleType.NEUTRON - - wws.particle = 1 - assert wws.particle == openmc.ParticleType.PHOTON - wws.particle = 'photon' - assert wws.particle == openmc.ParticleType.PHOTON - - with pytest.raises(ValueError): - wws.particle = '🌠' - - energy_filter = tally.find_filter(openmc.lib.EnergyFilter) - np.testing.assert_allclose(np.unique(energy_filter.bins), wws.energy_bounds) - - # at this point the weight window bounds are uninitialized - assert all(wws.bounds[0] == -1) - assert all(wws.bounds[1] == -1) - - wws = openmc.lib.WeightWindows.from_tally(tally, particle='photon') - assert wws.id == 2 - assert wws.particle == openmc.ParticleType.PHOTON - - openmc.lib.finalize() - - -@pytest.mark.parametrize('library', ('libmesh', 'moab')) -def test_unstructured_mesh_applied_wws(request, run_in_tmpdir, library): - """ - Ensure that weight windows on unstructured mesh work when - they aren't part of a tally or weight window generator - """ - - if library == 'libmesh' and not openmc.lib._libmesh_enabled(): - pytest.skip('LibMesh not enabled in this build.') - if library == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip('DAGMC (and MOAB) mesh not enabled in this build.') - - water = openmc.Material(name='water') - water.add_nuclide('H1', 2.0) - water.add_nuclide('O16', 1.0) - water.set_density('g/cc', 1.0) - box = openmc.model.RectangularParallelepiped(*(3*[-10, 10]), boundary_type='vacuum') - cell = openmc.Cell(region=-box, fill=water) - - geometry = openmc.Geometry([cell]) - mesh_file = str(request.fspath.dirpath() / 'test_mesh_tets.exo') - mesh = openmc.UnstructuredMesh(mesh_file, library) - - dummy_wws = np.ones((12_000,)) - - wws = openmc.WeightWindows(mesh, dummy_wws, upper_bound_ratio=5.0) - - model = openmc.Model(geometry) - model.settings.weight_windows = wws - model.settings.weight_windows_on = True - model.settings.run_mode = 'fixed source' - model.settings.particles = 100 - model.settings.batches = 2 - model.run() diff --git a/tests/unit_tests/weightwindows/test_mesh_tets.exo b/tests/unit_tests/weightwindows/test_mesh_tets.exo deleted file mode 120000 index 5bf23b369..000000000 --- a/tests/unit_tests/weightwindows/test_mesh_tets.exo +++ /dev/null @@ -1 +0,0 @@ -../../regression_tests/unstructured_mesh/test_mesh_tets.e \ No newline at end of file diff --git a/tests/unit_tests/weightwindows/test_ww_gen.py b/tests/unit_tests/weightwindows/test_ww_gen.py deleted file mode 100644 index a4456e680..000000000 --- a/tests/unit_tests/weightwindows/test_ww_gen.py +++ /dev/null @@ -1,404 +0,0 @@ -import copy -from itertools import permutations -from pathlib import Path - -import numpy as np -import openmc -import openmc.lib -import pytest - - -@pytest.fixture -def model(): - openmc.reset_auto_ids() - - # create a simple spherical shell shielding model - - ### Materials ### - water = openmc.Material() - water.set_density('g/cc', 1.0) - water.add_nuclide("H1", 2) - water.add_nuclide("O16", 1) - - steel = openmc.Material() - steel.set_density('g/cc', 8.0) - steel.add_nuclide("Fe56", 1.0) - - air = openmc.Material() - air.set_density('g/cc', 0.001205) - air.add_nuclide("N14", 0.781557629247) - air.add_nuclide("O16", 0.210668126508) - - boron = openmc.Material() - boron.set_density('g/cc', 2.52) - boron.add_nuclide("B10", 0.15856) - boron.add_nuclide("B11", 0.64144) - boron.add_nuclide("C0", 0.2) - - ### Geometry ### - radii = [5.0, 10.0, 30.0, 31.0, 50.0] - - surfs = [openmc.Sphere(r=r) for r in radii] - - surfs[-1].boundary_type = 'vacuum' - - regions = openmc.model.subdivide(surfs) - - mats = [air, water, steel, boron, air] - - cells = [openmc.Cell(fill=m, region=r) for r, m in zip(regions, mats)] - - geometry = openmc.Geometry(cells) - - ### Settings ### - - settings = openmc.Settings( - run_mode='fixed source', - particles=100, - batches=10, - max_history_splits=10, - survival_biasing=False - ) - - # 10 keV neutron point source at the origin - space = openmc.stats.Point() - energy = openmc.stats.Discrete(x=[1e4], p=[1.0]) - settings.source = openmc.IndependentSource(space=space, energy=energy) - - return openmc.Model(geometry=geometry, settings=settings) - - -# create a tally used for weight window generation -mesh = openmc.RegularMesh() -mesh.lower_left = [-50.0] * 3 -mesh.upper_right = [50.0] * 3 -# use un-equal mesh widths in each dimension to more robustly check -# use of tally data -mesh.dimension = (19, 20, 21) - -mf = openmc.MeshFilter(mesh) - -ef = openmc.EnergyFilter([0.0, 1e7]) - -pf = openmc.ParticleFilter(['neutron', 'photon']) - -filters = [mf, ef, pf] - -test_cases = list(permutations(filters)) -test_cases += list(permutations(filters[:-1])) -test_cases += list(permutations(filters[::2])) - - -def labels(params): - out = [] - for p in params: - if isinstance(p, openmc.ParticleFilter): - out.append('particle') - elif isinstance(p, openmc.MeshFilter): - out.append('mesh') - elif isinstance(p, openmc.EnergyFilter): - out.append('energy') - return "filters:" + '-'.join(out) - - -@pytest.mark.parametrize("filters", test_cases, ids=labels) -def test_ww_gen(filters, run_in_tmpdir, model): - - tally = openmc.Tally() - tally.filters = list(filters) - tally.scores = ['flux'] - model.tallies = openmc.Tallies([tally]) - - model.export_to_model_xml() - - ref_lower = None - ref_upper = None - # test weight window generation capability - with openmc.lib.run_in_memory(): - - # retrieve the tally we created above in memory - lib_tally = openmc.lib.tallies[tally.id] - - # create a new weight windows object - ww = openmc.lib.WeightWindows.from_tally(lib_tally) - - # run particle transport - openmc.lib.run() - - # capture analog data - analog_mean = np.copy(lib_tally.mean) - - # update the weight window values using tally results - ww.update_magic(lib_tally) - - assert any(ww.bounds[0] != -1) - assert any(ww.bounds[1] != -1) - - # make sure that the weight window update doesn't change tally values - np.testing.assert_equal(lib_tally.mean, analog_mean) - - # check against weight windows from the previous iteration - # the order of filters should not change the weight window values - if ref_lower is None: - ref_lower = ww.bounds[0].copy() - else: - np.testing.assert_equal(ref_lower, ww.bounds[0]) - - if ref_upper is None: - ref_upper = ww.bounds[1].copy() - else: - np.testing.assert_equal(ref_upper, ww.bounds[1]) - - # turn on weight windows for the subsequent run - openmc.lib.settings.weight_windows_on = True - - openmc.lib.hard_reset() - - openmc.lib.run() - - ww_mean = np.copy(lib_tally.mean) - - # we expect that the application of weight windows will populate more tally - # bins than the analog run for the meshes in this test model - assert any(ww_mean != analog_mean) - assert np.count_nonzero(ww_mean) > np.count_nonzero(analog_mean) - - -def test_ww_import_export(run_in_tmpdir, model): - # create a tally for weight windows - mesh = openmc.RegularMesh() - mesh.lower_left = [-50.0] * 3 - mesh.upper_right = [50.0] * 3 - # use un-equal mesh widths in each dimension to more robustly check - # use of tally data - mesh.dimension = (3, 4, 5) - - mf = openmc.MeshFilter(mesh) - - e_groups = np.logspace(0, 7, 8) - ef = openmc.EnergyFilter(e_groups) - - pf = openmc.ParticleFilter(['neutron', 'photon']) - - tally = openmc.Tally() - tally.filters = [mf, ef, pf] - tally.scores = ['flux'] - - model.tallies = openmc.Tallies([tally]) - - # first, generate some weight windows - model.export_to_model_xml() - - openmc.lib.init() - - tally = openmc.lib.tallies[tally.id] - - ww = openmc.lib.WeightWindows.from_tally(tally) - - openmc.lib.run() - - mean_before = np.array(tally.mean) - - ww.update_magic(tally) - - mean_after = np.array(tally.mean) - - assert (mean_before == mean_after).all() - - lb_before, up_before = ww.bounds - - # set some additional weight windows properties after transport - ww.survival_ratio = 0.7 - assert ww.survival_ratio == 0.7 - - ww.weight_cutoff = 1e-10 - assert ww.weight_cutoff == 1e-10 - - ww.max_lower_bound_ratio = 200.0 - assert ww.max_lower_bound_ratio == 200.0 - - ww.max_split = 26000 - assert ww.max_split == 26000 - - openmc.lib.export_weight_windows() - - assert Path('weight_windows.h5').exists() - - openmc.lib.import_weight_windows('weight_windows.h5') - - imported_ww = openmc.lib.weight_windows[2] - - lb_after, up_after = imported_ww.bounds - - assert np.allclose(lb_before, lb_after) - assert np.allclose(up_before, up_after) - - assert ww.survival_ratio == imported_ww.survival_ratio - assert ww.max_lower_bound_ratio == imported_ww.max_lower_bound_ratio - assert ww.weight_cutoff == imported_ww.weight_cutoff - assert ww.max_split == imported_ww.max_split - - openmc.lib.finalize() - - -def test_ww_gen_roundtrip(run_in_tmpdir, model): - - mesh = openmc.RegularMesh.from_domain(model.geometry.root_universe) - energy_bounds = np.linspace(0.0, 1e8, 11) - particle_type = 'neutron' - - wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle_type) - wwg.update_parameters = {'ratio' : 5.0, - 'threshold': 0.8, - 'value' : 'mean'} - - model.settings.weight_window_generators = wwg - model.export_to_xml() - - model_in = openmc.Model.from_xml() - - assert len(model_in.settings.weight_window_generators) == 1 - - wwg_in = model.settings.weight_window_generators[0] - - # rountrip tests - model_in = openmc.Model.from_xml() - assert len(model_in.settings.weight_window_generators) == 1 - wwg_in = model_in.settings.weight_window_generators[0] - assert wwg_in.max_realizations == 1 - assert wwg_in.on_the_fly == True - assert wwg_in.update_interval == 1 - assert wwg_in.update_parameters == wwg.update_parameters - - with pytest.raises(ValueError): - wwg.method = '🦍🐒' - - with pytest.raises(TypeError): - wwg.update_parameters = {'ratio' : 'one-to-one'} - - with pytest.raises(ValueError): - wwg.max_realizations = -1 - - -def test_python_hdf5_roundtrip(run_in_tmpdir, model): - - # add a tally to the model - mesh = openmc.RegularMesh.from_domain(model.geometry) - - # some arbitrary energy groups - e_groups = np.logspace(0, 6, 4) - energy_filter = openmc.EnergyFilter(e_groups) - - bounds = np.arange(energy_filter.num_bins * np.prod(mesh.dimension)) - - wws = openmc.WeightWindows(mesh, bounds, bounds, energy_bounds=e_groups) - - model.settings.weight_windows = [wws] - - model.export_to_xml() - - # initialize and export wws to HDF5 - openmc.lib.init() - - openmc.lib.export_weight_windows() - - openmc.lib.finalize() - - wws_hdf5 = openmc.WeightWindowsList.from_hdf5()[0] - - # ensure - assert all(wws.energy_bounds == wws_hdf5.energy_bounds) - assert wws.id == wws_hdf5.id - assert wws.mesh.id == wws_hdf5.mesh.id - np.testing.assert_array_equal(wws.lower_ww_bounds, wws_hdf5.lower_ww_bounds) - np.testing.assert_array_equal(wws.upper_ww_bounds, wws_hdf5.upper_ww_bounds) - - -def test_ww_bounds_set_in_memory(run_in_tmpdir, model): - tally = openmc.Tally() - tally.filters = filters - tally.scores = ['flux'] - model.tallies = [tally] - - bounds = np.arange(ef.num_bins * np.prod(mf.mesh.dimension)) - - model.export_to_xml() - - openmc.lib.init() - - lib_tally = openmc.lib.tallies[tally.id] - - wws = openmc.lib.WeightWindows.from_tally(lib_tally) - - wws.bounds = (bounds, bounds) - - openmc.lib.finalize() - - -@pytest.mark.skipif(not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") -def test_ww_generation_with_dagmc(run_in_tmpdir): - mat1 = openmc.Material(name="1") - mat1.add_nuclide("H1", 1, percent_type="ao") - mat1.set_density("g/cm3", 0.001) - - materials = openmc.Materials([mat1]) - dag_univ = openmc.DAGMCUniverse( - Path(__file__).parent.parent / "dagmc" / "dagmc_tetrahedral_no_graveyard.h5m") - bound_dag_univ = dag_univ.bounded_universe(padding_distance=1) - geometry = openmc.Geometry(bound_dag_univ) - - settings = openmc.Settings() - settings.batches = 6 - settings.particles = 30 - settings.run_mode = "fixed source" - - # Create a point source which are supported by random ray mode - my_source = openmc.IndependentSource() - my_source.space = openmc.stats.Point((0.25, 0.25, 0.25)) - my_source.energy = openmc.stats.delta_function(14e6) - settings.source = my_source - - model = openmc.Model(geometry, materials, settings) - - rr_model = copy.deepcopy(model) - rr_model.settings.inactive = 3 - - rr_model.convert_to_multigroup( - method="stochastic_slab", - overwrite_mgxs_library=True, - nparticles=10, - groups="CASMO-2" - ) - - rr_model.convert_to_random_ray() - - mesh = openmc.RegularMesh.from_domain(rr_model, dimension=(4, 4, 4)) - - # avoid writing files we don't make use of - rr_model.settings.output = {"summary": False, "tallies": False} - - # Subdivide random ray source regions - rr_model.settings.random_ray["source_region_meshes"] = [ - (mesh, [rr_model.geometry.root_universe]) - ] - - # less likely to get negative values in the weight window - rr_model.settings.random_ray["volume_estimator"] = "naive" - - # Add a weight window generator to the model - rr_model.settings.weight_window_generators = openmc.WeightWindowGenerator( - method="fw_cadis", - mesh=mesh, - max_realizations=42, - particle_type='neutron', - energy_bounds=[0.0, 100e6] - ) - - rr_model.run() - - model.settings.weight_windows_on = True - model.settings.weight_window_checkpoints = {"collision": True, "surface": True} - model.settings.survival_biasing = False - model.settings.weight_windows = openmc.WeightWindowsList.from_hdf5() - - model.run() diff --git a/tests/unit_tests/weightwindows/test_ww_list.py b/tests/unit_tests/weightwindows/test_ww_list.py deleted file mode 100644 index d148f382a..000000000 --- a/tests/unit_tests/weightwindows/test_ww_list.py +++ /dev/null @@ -1,23 +0,0 @@ -import openmc - - -def test_ww_roundtrip(request, run_in_tmpdir): - # Load weight windows from a wwinp file - wwinp_file = request.path.with_name('wwinp_n') - wws = openmc.WeightWindowsList.from_wwinp(wwinp_file) - - # Roundtrip them, writing to HDF5 and reading back in - wws.export_to_hdf5('ww.h5') - wws_new = openmc.WeightWindowsList.from_hdf5('ww.h5') - - # Check that the new weight windows are the same as the original - assert len(wws) == len(wws_new) - for ww, ww_new in zip(wws, wws_new): - assert ww.particle_type == ww_new.particle_type - assert (ww.lower_ww_bounds == ww_new.lower_ww_bounds).all() - assert (ww.upper_ww_bounds == ww_new.upper_ww_bounds).all() - assert ww.survival_ratio == ww_new.survival_ratio - assert ww.num_energy_bins == ww_new.num_energy_bins - assert ww.max_split == ww_new.max_split - assert ww.weight_cutoff == ww_new.weight_cutoff - assert ww.mesh.id == ww_new.mesh.id diff --git a/tests/unit_tests/weightwindows/test_ww_mg.py b/tests/unit_tests/weightwindows/test_ww_mg.py deleted file mode 100644 index 23e09ea0c..000000000 --- a/tests/unit_tests/weightwindows/test_ww_mg.py +++ /dev/null @@ -1,51 +0,0 @@ -import numpy as np -import openmc - - -def test_weight_windows_mg(request, run_in_tmpdir): - # import basic random ray model - model = openmc.examples.random_ray_three_region_cube() - - # create a mesh tally - mesh = openmc.RegularMesh.from_domain(model.geometry, (3, 3, 3)) - mesh_tally = openmc.Tally() - mesh_tally.filters = [openmc.MeshFilter(mesh)] - mesh_tally.scores = ['flux'] - model.tallies = [mesh_tally] - - # replace random ray settings with fixed source settings - settings = openmc.Settings() - settings.particles = 5000 - settings.batches = 10 - settings.energy_mode = 'multi-group' - settings.run_mode = 'fixed source' - space = openmc.stats.Point((1, 1, 1)) - energy = openmc.stats.delta_function(1e6) - settings.source = openmc.IndependentSource(space=space, energy=energy) - model.settings = settings - - # perform analog simulation - statepoint = model.run() - - # extract flux from analog simulation - with openmc.StatePoint(statepoint) as sp: - tally_out = sp.get_tally(id=mesh_tally.id) - flux_analog = tally_out.mean - - # load the weight windows for this problem and apply them - ww_lower_bnds = np.loadtxt(request.path.parent / 'ww_mg.txt') - weight_windows = openmc.WeightWindows(mesh, lower_ww_bounds=ww_lower_bnds, upper_bound_ratio=5.0) - model.settings.weight_windows = weight_windows - model.settings.weight_windows_on = True - - # re-run with weight windows - statepoint = model.run() - with openmc.StatePoint(statepoint) as sp: - tally_out = sp.get_tally(id=mesh_tally.id) - flux_ww = tally_out.mean - - # the sum of the fluxes should approach the same value (no bias introduced) - analog_sum = flux_analog.sum() - ww_sum = flux_ww.sum() - assert np.allclose(analog_sum, ww_sum, rtol=1e-2) - diff --git a/tests/unit_tests/weightwindows/test_wwinp_reader.py b/tests/unit_tests/weightwindows/test_wwinp_reader.py index 601517d47..434a36753 100644 --- a/tests/unit_tests/weightwindows/test_wwinp_reader.py +++ b/tests/unit_tests/weightwindows/test_wwinp_reader.py @@ -52,7 +52,7 @@ n_mesh.z_grid = np.array([-100.0, n_e_bounds = (np.array([0.0, 100000.0, 146780.0]),) -n_particles = [openmc.ParticleType.NEUTRON] +n_particles = ('neutron',) # expected results - neutron and photon data np_mesh = openmc.RectilinearMesh() @@ -63,7 +63,7 @@ np_mesh.z_grid = n_mesh.z_grid np_e_bounds = (np.array([0.0, 100000.0, 146780.0, 215440.0]), np.array([0.0, 1.0E8])) -np_particles = [openmc.ParticleType.NEUTRON, openmc.ParticleType.PHOTON] +np_particles = ('neutron', 'photon') # expected results - photon data only p_mesh = openmc.RectilinearMesh() @@ -74,7 +74,7 @@ p_mesh.y_grid = np_mesh.y_grid p_mesh.z_grid = np.array([-50.0, 50.0]) p_e_bounds = (np.array([0.0, 100000.0, 146780.0, 215440.0, 316230.0]),) -p_particles = [openmc.ParticleType.PHOTON] +p_particles = ('photon',) expected_results = [('wwinp_n', n_mesh, n_particles, n_e_bounds), ('wwinp_np', np_mesh, np_particles, np_e_bounds), @@ -96,7 +96,7 @@ def id_fn(params): def test_wwinp_reader(wwinp_data, request): wwinp_file, mesh, particle_types, energy_bounds = wwinp_data - wws = openmc.WeightWindowsList.from_wwinp(request.node.path.parent / wwinp_file) + wws = openmc.wwinp_to_wws(request.node.path.parent / wwinp_file) for i, ww in enumerate(wws): e_bounds = energy_bounds[i] @@ -140,4 +140,4 @@ def test_wwinp_reader_failures(wwinp_data, request): filename, expected_failure = wwinp_data with pytest.raises(expected_failure): - _ = openmc.WeightWindowsList.from_wwinp(request.node.path.parent / filename) + _ = openmc.wwinp_to_wws(request.node.path.parent / filename) diff --git a/tests/unit_tests/weightwindows/ww_mg.txt b/tests/unit_tests/weightwindows/ww_mg.txt deleted file mode 100644 index 7bcc59d97..000000000 --- a/tests/unit_tests/weightwindows/ww_mg.txt +++ /dev/null @@ -1,27 +0,0 @@ -5.000000000000000278e-02 -1.023184121346435924e-02 -3.006624096325660397e-03 -1.030178532774538719e-02 -6.058877789444589400e-03 -2.216914234856166583e-03 -3.061186967456217597e-03 -2.148267952185671601e-03 -1.026171712186230980e-03 -1.040022203443005666e-02 -6.040633813799485378e-03 -2.364143118752318716e-03 -6.119726639841410569e-03 -4.329097093078606955e-03 -1.873104469085542763e-03 -2.246957229279350661e-03 -1.851165248260521617e-03 -7.825824911598703530e-04 -3.021300894848398706e-03 -2.286420236345795311e-03 -9.318583473482396160e-04 -2.234702678114806364e-03 -1.813664566119888152e-03 -7.969287848384389462e-04 -1.017895970086981662e-03 -7.707144532950136471e-04 -3.386087166633241791e-04 diff --git a/tests/unit_tests/weightwindows/wwinp_cyl b/tests/unit_tests/weightwindows/wwinp_cyl index aac9d46f2..890844b87 100644 --- a/tests/unit_tests/weightwindows/wwinp_cyl +++ b/tests/unit_tests/weightwindows/wwinp_cyl @@ -14,35 +14,35 @@ 1.00000E+00 0.00000E+01 1.00000E+00 3.14159E+00 1.00000E+00 1.00000E-01 1.46780E-01 2.15440E-01 3.16230E-01 - 1.92000E+02 1.60000E+02 1.28000E+02 9.60000E+01 6.40000E+01 3.20000E+01 - 1.88000E+02 1.56000E+02 1.24000E+02 9.20000E+01 6.00000E+01 2.80000E+01 - 1.84000E+02 1.52000E+02 1.20000E+02 8.80000E+01 5.60000E+01 2.40000E+01 - 1.80000E+02 1.48000E+02 1.16000E+02 8.40000E+01 5.20000E+01 2.00000E+01 - 1.76000E+02 1.44000E+02 1.12000E+02 8.00000E+01 4.80000E+01 1.60000E+01 - 1.72000E+02 1.40000E+02 1.08000E+02 7.60000E+01 4.40000E+01 1.20000E+01 - 1.68000E+02 1.36000E+02 1.04000E+02 7.20000E+01 4.00000E+01 8.00000E+00 - 1.64000E+02 1.32000E+02 1.00000E+02 6.80000E+01 3.60000E+01 4.00000E+00 - 1.91000E+02 1.59000E+02 1.27000E+02 9.50000E+01 6.30000E+01 3.10000E+01 - 1.87000E+02 1.55000E+02 1.23000E+02 9.10000E+01 5.90000E+01 2.70000E+01 - 1.83000E+02 1.51000E+02 1.19000E+02 8.70000E+01 5.50000E+01 2.30000E+01 - 1.79000E+02 1.47000E+02 1.15000E+02 8.30000E+01 5.10000E+01 1.90000E+01 - 1.75000E+02 1.43000E+02 1.11000E+02 7.90000E+01 4.70000E+01 1.50000E+01 - 1.71000E+02 1.39000E+02 1.07000E+02 7.50000E+01 4.30000E+01 1.10000E+01 - 1.67000E+02 1.35000E+02 1.03000E+02 7.10000E+01 3.90000E+01 7.00000E+00 - 1.63000E+02 1.31000E+02 9.90000E+01 6.70000E+01 3.50000E+01 3.00000E+00 - 1.90000E+02 1.58000E+02 1.26000E+02 9.40000E+01 6.20000E+01 3.00000E+01 - 1.86000E+02 1.54000E+02 1.22000E+02 9.00000E+01 5.80000E+01 2.60000E+01 - 1.82000E+02 1.50000E+02 1.18000E+02 8.60000E+01 5.40000E+01 2.20000E+01 - 1.78000E+02 1.46000E+02 1.14000E+02 8.20000E+01 5.00000E+01 1.80000E+01 - 1.74000E+02 1.42000E+02 1.10000E+02 7.80000E+01 4.60000E+01 1.40000E+01 - 1.70000E+02 1.38000E+02 1.06000E+02 7.40000E+01 4.20000E+01 1.00000E+01 - 1.66000E+02 1.34000E+02 1.02000E+02 7.00000E+01 3.80000E+01 6.00000E+00 - 1.62000E+02 1.30000E+02 9.80000E+01 6.60000E+01 3.40000E+01 2.00000E+00 - 1.89000E+02 1.57000E+02 1.25000E+02 9.30000E+01 6.10000E+01 2.90000E+01 - 1.85000E+02 1.53000E+02 1.21000E+02 8.90000E+01 5.70000E+01 2.50000E+01 - 1.81000E+02 1.49000E+02 1.17000E+02 8.50000E+01 5.30000E+01 2.10000E+01 - 1.77000E+02 1.45000E+02 1.13000E+02 8.10000E+01 4.90000E+01 1.70000E+01 - 1.73000E+02 1.41000E+02 1.09000E+02 7.70000E+01 4.50000E+01 1.30000E+01 - 1.69000E+02 1.37000E+02 1.05000E+02 7.30000E+01 4.10000E+01 9.00000E+00 - 1.65000E+02 1.33000E+02 1.01000E+02 6.90000E+01 3.70000E+01 5.00000E+00 - 1.61000E+02 1.29000E+02 9.70000E+01 6.50000E+01 3.30000E+01 1.00000E+00 + 1.92000E+02 1.91000E+02 1.90000E+02 1.89000E+02 1.60000E+02 1.59000E+02 + 1.58000E+02 1.57000E+02 1.28000E+02 1.27000E+02 1.26000E+02 1.25000E+02 + 9.60000E+01 9.50000E+01 9.40000E+01 9.30000E+01 6.40000E+01 6.30000E+01 + 6.20000E+01 6.10000E+01 3.20000E+01 3.10000E+01 3.00000E+01 2.90000E+01 + 1.88000E+02 1.87000E+02 1.86000E+02 1.85000E+02 1.56000E+02 1.55000E+02 + 1.54000E+02 1.53000E+02 1.24000E+02 1.23000E+02 1.22000E+02 1.21000E+02 + 9.20000E+01 9.10000E+01 9.00000E+01 8.90000E+01 6.00000E+01 5.90000E+01 + 5.80000E+01 5.70000E+01 2.80000E+01 2.70000E+01 2.60000E+01 2.50000E+01 + 1.84000E+02 1.83000E+02 1.82000E+02 1.81000E+02 1.52000E+02 1.51000E+02 + 1.50000E+02 1.49000E+02 1.20000E+02 1.19000E+02 1.18000E+02 1.17000E+02 + 8.80000E+01 8.70000E+01 8.60000E+01 8.50000E+01 5.60000E+01 5.50000E+01 + 5.40000E+01 5.30000E+01 2.40000E+01 2.30000E+01 2.20000E+01 2.10000E+01 + 1.80000E+02 1.79000E+02 1.78000E+02 1.77000E+02 1.48000E+02 1.47000E+02 + 1.46000E+02 1.45000E+02 1.16000E+02 1.15000E+02 1.14000E+02 1.13000E+02 + 8.40000E+01 8.30000E+01 8.20000E+01 8.10000E+01 5.20000E+01 5.10000E+01 + 5.00000E+01 4.90000E+01 2.00000E+01 1.90000E+01 1.80000E+01 1.70000E+01 + 1.76000E+02 1.75000E+02 1.74000E+02 1.73000E+02 1.44000E+02 1.43000E+02 + 1.42000E+02 1.41000E+02 1.12000E+02 1.11000E+02 1.10000E+02 1.09000E+02 + 8.00000E+01 7.90000E+01 7.80000E+01 7.70000E+01 4.80000E+01 4.70000E+01 + 4.60000E+01 4.50000E+01 1.60000E+01 1.50000E+01 1.40000E+01 1.30000E+01 + 1.72000E+02 1.71000E+02 1.70000E+02 1.69000E+02 1.40000E+02 1.39000E+02 + 1.38000E+02 1.37000E+02 1.08000E+02 1.07000E+02 1.06000E+02 1.05000E+02 + 7.60000E+01 7.50000E+01 7.40000E+01 7.30000E+01 4.40000E+01 4.30000E+01 + 4.20000E+01 4.10000E+01 1.20000E+01 1.10000E+01 1.00000E+01 9.00000E+00 + 1.68000E+02 1.67000E+02 1.66000E+02 1.65000E+02 1.36000E+02 1.35000E+02 + 1.34000E+02 1.33000E+02 1.04000E+02 1.03000E+02 1.02000E+02 1.01000E+02 + 7.20000E+01 7.10000E+01 7.00000E+01 6.90000E+01 4.00000E+01 3.90000E+01 + 3.80000E+01 3.70000E+01 8.00000E+00 7.00000E+00 6.00000E+00 5.00000E+00 + 1.64000E+02 1.63000E+02 1.62000E+02 1.61000E+02 1.32000E+02 1.31000E+02 + 1.30000E+02 1.29000E+02 1.00000E+02 9.90000E+01 9.80000E+01 9.70000E+01 + 6.80000E+01 6.70000E+01 6.60000E+01 6.50000E+01 3.60000E+01 3.50000E+01 + 3.40000E+01 3.30000E+01 4.00000E+00 3.00000E+00 2.00000E+00 1.00000E+00 diff --git a/tests/unit_tests/weightwindows/wwinp_n b/tests/unit_tests/weightwindows/wwinp_n index 73a4fc496..b9611e945 100644 --- a/tests/unit_tests/weightwindows/wwinp_n +++ b/tests/unit_tests/weightwindows/wwinp_n @@ -20,244 +20,244 @@ 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 1.00000E+00 1.00000E-01 1.46780E-01 - 1.44000E+03 1.34400E+03 1.24800E+03 1.15200E+03 1.05600E+03 9.60000E+02 - 8.64000E+02 7.68000E+02 6.72000E+02 5.76000E+02 4.80000E+02 3.84000E+02 - 2.88000E+02 1.92000E+02 9.60000E+01 1.42800E+03 1.33200E+03 1.23600E+03 - 1.14000E+03 1.04400E+03 9.48000E+02 8.52000E+02 7.56000E+02 6.60000E+02 - 5.64000E+02 4.68000E+02 3.72000E+02 2.76000E+02 1.80000E+02 8.40000E+01 - 1.41600E+03 1.32000E+03 1.22400E+03 1.12800E+03 1.03200E+03 9.36000E+02 - 8.40000E+02 7.44000E+02 6.48000E+02 5.52000E+02 4.56000E+02 3.60000E+02 - 2.64000E+02 1.68000E+02 7.20000E+01 1.40400E+03 1.30800E+03 1.21200E+03 - 1.11600E+03 1.02000E+03 9.24000E+02 8.28000E+02 7.32000E+02 6.36000E+02 - 5.40000E+02 4.44000E+02 3.48000E+02 2.52000E+02 1.56000E+02 6.00000E+01 - 1.39200E+03 1.29600E+03 1.20000E+03 1.10400E+03 1.00800E+03 9.12000E+02 - 8.16000E+02 7.20000E+02 6.24000E+02 5.28000E+02 4.32000E+02 3.36000E+02 - 2.40000E+02 1.44000E+02 4.80000E+01 1.38000E+03 1.28400E+03 1.18800E+03 - 1.09200E+03 9.96000E+02 9.00000E+02 8.04000E+02 7.08000E+02 6.12000E+02 - 5.16000E+02 4.20000E+02 3.24000E+02 2.28000E+02 1.32000E+02 3.60000E+01 - 1.36800E+03 1.27200E+03 1.17600E+03 1.08000E+03 9.84000E+02 8.88000E+02 - 7.92000E+02 6.96000E+02 6.00000E+02 5.04000E+02 4.08000E+02 3.12000E+02 - 2.16000E+02 1.20000E+02 2.40000E+01 1.35600E+03 1.26000E+03 1.16400E+03 - 1.06800E+03 9.72000E+02 8.76000E+02 7.80000E+02 6.84000E+02 5.88000E+02 - 4.92000E+02 3.96000E+02 3.00000E+02 2.04000E+02 1.08000E+02 1.20000E+01 - 1.43800E+03 1.34200E+03 1.24600E+03 1.15000E+03 1.05400E+03 9.58000E+02 - 8.62000E+02 7.66000E+02 6.70000E+02 5.74000E+02 4.78000E+02 3.82000E+02 - 2.86000E+02 1.90000E+02 9.40000E+01 1.42600E+03 1.33000E+03 1.23400E+03 - 1.13800E+03 1.04200E+03 9.46000E+02 8.50000E+02 7.54000E+02 6.58000E+02 - 5.62000E+02 4.66000E+02 3.70000E+02 2.74000E+02 1.78000E+02 8.20000E+01 - 1.41400E+03 1.31800E+03 1.22200E+03 1.12600E+03 1.03000E+03 9.34000E+02 - 8.38000E+02 7.42000E+02 6.46000E+02 5.50000E+02 4.54000E+02 3.58000E+02 - 2.62000E+02 1.66000E+02 7.00000E+01 1.40200E+03 1.30600E+03 1.21000E+03 - 1.11400E+03 1.01800E+03 9.22000E+02 8.26000E+02 7.30000E+02 6.34000E+02 - 5.38000E+02 4.42000E+02 3.46000E+02 2.50000E+02 1.54000E+02 5.80000E+01 - 1.39000E+03 1.29400E+03 1.19800E+03 1.10200E+03 1.00600E+03 9.10000E+02 - 8.14000E+02 7.18000E+02 6.22000E+02 5.26000E+02 4.30000E+02 3.34000E+02 - 2.38000E+02 1.42000E+02 4.60000E+01 1.37800E+03 1.28200E+03 1.18600E+03 - 1.09000E+03 9.94000E+02 8.98000E+02 8.02000E+02 7.06000E+02 6.10000E+02 - 5.14000E+02 4.18000E+02 3.22000E+02 2.26000E+02 1.30000E+02 3.40000E+01 - 1.36600E+03 1.27000E+03 1.17400E+03 1.07800E+03 9.82000E+02 8.86000E+02 - 7.90000E+02 6.94000E+02 5.98000E+02 5.02000E+02 4.06000E+02 3.10000E+02 - 2.14000E+02 1.18000E+02 2.20000E+01 1.35400E+03 1.25800E+03 1.16200E+03 - 1.06600E+03 9.70000E+02 8.74000E+02 7.78000E+02 6.82000E+02 5.86000E+02 - 4.90000E+02 3.94000E+02 2.98000E+02 2.02000E+02 1.06000E+02 1.00000E+01 - 1.43600E+03 1.34000E+03 1.24400E+03 1.14800E+03 1.05200E+03 9.56000E+02 - 8.60000E+02 7.64000E+02 6.68000E+02 5.72000E+02 4.76000E+02 3.80000E+02 - 2.84000E+02 1.88000E+02 9.20000E+01 1.42400E+03 1.32800E+03 1.23200E+03 - 1.13600E+03 1.04000E+03 9.44000E+02 8.48000E+02 7.52000E+02 6.56000E+02 - 5.60000E+02 4.64000E+02 3.68000E+02 2.72000E+02 1.76000E+02 8.00000E+01 - 1.41200E+03 1.31600E+03 1.22000E+03 1.12400E+03 1.02800E+03 9.32000E+02 - 8.36000E+02 7.40000E+02 6.44000E+02 5.48000E+02 4.52000E+02 3.56000E+02 - 2.60000E+02 1.64000E+02 6.80000E+01 1.40000E+03 1.30400E+03 1.20800E+03 - 1.11200E+03 1.01600E+03 9.20000E+02 8.24000E+02 7.28000E+02 6.32000E+02 - 5.36000E+02 4.40000E+02 3.44000E+02 2.48000E+02 1.52000E+02 5.60000E+01 - 1.38800E+03 1.29200E+03 1.19600E+03 1.10000E+03 1.00400E+03 9.08000E+02 - 8.12000E+02 7.16000E+02 6.20000E+02 5.24000E+02 4.28000E+02 3.32000E+02 - 2.36000E+02 1.40000E+02 4.40000E+01 1.37600E+03 1.28000E+03 1.18400E+03 - 1.08800E+03 9.92000E+02 8.96000E+02 8.00000E+02 7.04000E+02 6.08000E+02 - 5.12000E+02 4.16000E+02 3.20000E+02 2.24000E+02 1.28000E+02 3.20000E+01 - 1.36400E+03 1.26800E+03 1.17200E+03 1.07600E+03 9.80000E+02 8.84000E+02 - 7.88000E+02 6.92000E+02 5.96000E+02 5.00000E+02 4.04000E+02 3.08000E+02 - 2.12000E+02 1.16000E+02 2.00000E+01 1.35200E+03 1.25600E+03 1.16000E+03 - 1.06400E+03 9.68000E+02 8.72000E+02 7.76000E+02 6.80000E+02 5.84000E+02 - 4.88000E+02 3.92000E+02 2.96000E+02 2.00000E+02 1.04000E+02 8.00000E+00 - 1.43400E+03 1.33800E+03 1.24200E+03 1.14600E+03 1.05000E+03 9.54000E+02 - 8.58000E+02 7.62000E+02 6.66000E+02 5.70000E+02 4.74000E+02 3.78000E+02 - 2.82000E+02 1.86000E+02 9.00000E+01 1.42200E+03 1.32600E+03 1.23000E+03 - 1.13400E+03 1.03800E+03 9.42000E+02 8.46000E+02 7.50000E+02 6.54000E+02 - 5.58000E+02 4.62000E+02 3.66000E+02 2.70000E+02 1.74000E+02 7.80000E+01 - 1.41000E+03 1.31400E+03 1.21800E+03 1.12200E+03 1.02600E+03 9.30000E+02 - 8.34000E+02 7.38000E+02 6.42000E+02 5.46000E+02 4.50000E+02 3.54000E+02 - 2.58000E+02 1.62000E+02 6.60000E+01 1.39800E+03 1.30200E+03 1.20600E+03 - 1.11000E+03 1.01400E+03 9.18000E+02 8.22000E+02 7.26000E+02 6.30000E+02 - 5.34000E+02 4.38000E+02 3.42000E+02 2.46000E+02 1.50000E+02 5.40000E+01 - 1.38600E+03 1.29000E+03 1.19400E+03 1.09800E+03 1.00200E+03 9.06000E+02 - 8.10000E+02 7.14000E+02 6.18000E+02 5.22000E+02 4.26000E+02 3.30000E+02 - 2.34000E+02 1.38000E+02 4.20000E+01 1.37400E+03 1.27800E+03 1.18200E+03 - 1.08600E+03 9.90000E+02 8.94000E+02 7.98000E+02 7.02000E+02 6.06000E+02 - 5.10000E+02 4.14000E+02 3.18000E+02 2.22000E+02 1.26000E+02 3.00000E+01 - 1.36200E+03 1.26600E+03 1.17000E+03 1.07400E+03 9.78000E+02 8.82000E+02 - 7.86000E+02 6.90000E+02 5.94000E+02 4.98000E+02 4.02000E+02 3.06000E+02 - 2.10000E+02 1.14000E+02 1.80000E+01 1.35000E+03 1.25400E+03 1.15800E+03 - 1.06200E+03 9.66000E+02 8.70000E+02 7.74000E+02 6.78000E+02 5.82000E+02 - 4.86000E+02 3.90000E+02 2.94000E+02 1.98000E+02 1.02000E+02 6.00000E+00 - 1.43200E+03 1.33600E+03 1.24000E+03 1.14400E+03 1.04800E+03 9.52000E+02 - 8.56000E+02 7.60000E+02 6.64000E+02 5.68000E+02 4.72000E+02 3.76000E+02 - 2.80000E+02 1.84000E+02 8.80000E+01 1.42000E+03 1.32400E+03 1.22800E+03 - 1.13200E+03 1.03600E+03 9.40000E+02 8.44000E+02 7.48000E+02 6.52000E+02 - 5.56000E+02 4.60000E+02 3.64000E+02 2.68000E+02 1.72000E+02 7.60000E+01 - 1.40800E+03 1.31200E+03 1.21600E+03 1.12000E+03 1.02400E+03 9.28000E+02 - 8.32000E+02 7.36000E+02 6.40000E+02 5.44000E+02 4.48000E+02 3.52000E+02 - 2.56000E+02 1.60000E+02 6.40000E+01 1.39600E+03 1.30000E+03 1.20400E+03 - 1.10800E+03 1.01200E+03 9.16000E+02 8.20000E+02 7.24000E+02 6.28000E+02 - 5.32000E+02 4.36000E+02 3.40000E+02 2.44000E+02 1.48000E+02 5.20000E+01 - 1.38400E+03 1.28800E+03 1.19200E+03 1.09600E+03 1.00000E+03 9.04000E+02 - 8.08000E+02 7.12000E+02 6.16000E+02 5.20000E+02 4.24000E+02 3.28000E+02 - 2.32000E+02 1.36000E+02 4.00000E+01 1.37200E+03 1.27600E+03 1.18000E+03 - 1.08400E+03 9.88000E+02 8.92000E+02 7.96000E+02 7.00000E+02 6.04000E+02 - 5.08000E+02 4.12000E+02 3.16000E+02 2.20000E+02 1.24000E+02 2.80000E+01 - 1.36000E+03 1.26400E+03 1.16800E+03 1.07200E+03 9.76000E+02 8.80000E+02 - 7.84000E+02 6.88000E+02 5.92000E+02 4.96000E+02 4.00000E+02 3.04000E+02 - 2.08000E+02 1.12000E+02 1.60000E+01 1.34800E+03 1.25200E+03 1.15600E+03 - 1.06000E+03 9.64000E+02 8.68000E+02 7.72000E+02 6.76000E+02 5.80000E+02 - 4.84000E+02 3.88000E+02 2.92000E+02 1.96000E+02 1.00000E+02 4.00000E+00 - 1.43000E+03 1.33400E+03 1.23800E+03 1.14200E+03 1.04600E+03 9.50000E+02 - 8.54000E+02 7.58000E+02 6.62000E+02 5.66000E+02 4.70000E+02 3.74000E+02 - 2.78000E+02 1.82000E+02 8.60000E+01 1.41800E+03 1.32200E+03 1.22600E+03 - 1.13000E+03 1.03400E+03 9.38000E+02 8.42000E+02 7.46000E+02 6.50000E+02 - 5.54000E+02 4.58000E+02 3.62000E+02 2.66000E+02 1.70000E+02 7.40000E+01 - 1.40600E+03 1.31000E+03 1.21400E+03 1.11800E+03 1.02200E+03 9.26000E+02 - 8.30000E+02 7.34000E+02 6.38000E+02 5.42000E+02 4.46000E+02 3.50000E+02 - 2.54000E+02 1.58000E+02 6.20000E+01 1.39400E+03 1.29800E+03 1.20200E+03 - 1.10600E+03 1.01000E+03 9.14000E+02 8.18000E+02 7.22000E+02 6.26000E+02 - 5.30000E+02 4.34000E+02 3.38000E+02 2.42000E+02 1.46000E+02 5.00000E+01 - 1.38200E+03 1.28600E+03 1.19000E+03 1.09400E+03 9.98000E+02 9.02000E+02 - 8.06000E+02 7.10000E+02 6.14000E+02 5.18000E+02 4.22000E+02 3.26000E+02 - 2.30000E+02 1.34000E+02 3.80000E+01 1.37000E+03 1.27400E+03 1.17800E+03 - 1.08200E+03 9.86000E+02 8.90000E+02 7.94000E+02 6.98000E+02 6.02000E+02 - 5.06000E+02 4.10000E+02 3.14000E+02 2.18000E+02 1.22000E+02 2.60000E+01 - 1.35800E+03 1.26200E+03 1.16600E+03 1.07000E+03 9.74000E+02 8.78000E+02 - 7.82000E+02 6.86000E+02 5.90000E+02 4.94000E+02 3.98000E+02 3.02000E+02 - 2.06000E+02 1.10000E+02 1.40000E+01 1.34600E+03 1.25000E+03 1.15400E+03 - 1.05800E+03 9.62000E+02 8.66000E+02 7.70000E+02 6.74000E+02 5.78000E+02 - 4.82000E+02 3.86000E+02 2.90000E+02 1.94000E+02 9.80000E+01 2.00000E+00 - 1.43900E+03 1.34300E+03 1.24700E+03 1.15100E+03 1.05500E+03 9.59000E+02 - 8.63000E+02 7.67000E+02 6.71000E+02 5.75000E+02 4.79000E+02 3.83000E+02 - 2.87000E+02 1.91000E+02 9.50000E+01 1.42700E+03 1.33100E+03 1.23500E+03 - 1.13900E+03 1.04300E+03 9.47000E+02 8.51000E+02 7.55000E+02 6.59000E+02 - 5.63000E+02 4.67000E+02 3.71000E+02 2.75000E+02 1.79000E+02 8.30000E+01 - 1.41500E+03 1.31900E+03 1.22300E+03 1.12700E+03 1.03100E+03 9.35000E+02 - 8.39000E+02 7.43000E+02 6.47000E+02 5.51000E+02 4.55000E+02 3.59000E+02 - 2.63000E+02 1.67000E+02 7.10000E+01 1.40300E+03 1.30700E+03 1.21100E+03 - 1.11500E+03 1.01900E+03 9.23000E+02 8.27000E+02 7.31000E+02 6.35000E+02 - 5.39000E+02 4.43000E+02 3.47000E+02 2.51000E+02 1.55000E+02 5.90000E+01 - 1.39100E+03 1.29500E+03 1.19900E+03 1.10300E+03 1.00700E+03 9.11000E+02 - 8.15000E+02 7.19000E+02 6.23000E+02 5.27000E+02 4.31000E+02 3.35000E+02 - 2.39000E+02 1.43000E+02 4.70000E+01 1.37900E+03 1.28300E+03 1.18700E+03 - 1.09100E+03 9.95000E+02 8.99000E+02 8.03000E+02 7.07000E+02 6.11000E+02 - 5.15000E+02 4.19000E+02 3.23000E+02 2.27000E+02 1.31000E+02 3.50000E+01 - 1.36700E+03 1.27100E+03 1.17500E+03 1.07900E+03 9.83000E+02 8.87000E+02 - 7.91000E+02 6.95000E+02 5.99000E+02 5.03000E+02 4.07000E+02 3.11000E+02 - 2.15000E+02 1.19000E+02 2.30000E+01 1.35500E+03 1.25900E+03 1.16300E+03 - 1.06700E+03 9.71000E+02 8.75000E+02 7.79000E+02 6.83000E+02 5.87000E+02 - 4.91000E+02 3.95000E+02 2.99000E+02 2.03000E+02 1.07000E+02 1.10000E+01 - 1.43700E+03 1.34100E+03 1.24500E+03 1.14900E+03 1.05300E+03 9.57000E+02 - 8.61000E+02 7.65000E+02 6.69000E+02 5.73000E+02 4.77000E+02 3.81000E+02 - 2.85000E+02 1.89000E+02 9.30000E+01 1.42500E+03 1.32900E+03 1.23300E+03 - 1.13700E+03 1.04100E+03 9.45000E+02 8.49000E+02 7.53000E+02 6.57000E+02 - 5.61000E+02 4.65000E+02 3.69000E+02 2.73000E+02 1.77000E+02 8.10000E+01 - 1.41300E+03 1.31700E+03 1.22100E+03 1.12500E+03 1.02900E+03 9.33000E+02 - 8.37000E+02 7.41000E+02 6.45000E+02 5.49000E+02 4.53000E+02 3.57000E+02 - 2.61000E+02 1.65000E+02 6.90000E+01 1.40100E+03 1.30500E+03 1.20900E+03 - 1.11300E+03 1.01700E+03 9.21000E+02 8.25000E+02 7.29000E+02 6.33000E+02 - 5.37000E+02 4.41000E+02 3.45000E+02 2.49000E+02 1.53000E+02 5.70000E+01 - 1.38900E+03 1.29300E+03 1.19700E+03 1.10100E+03 1.00500E+03 9.09000E+02 - 8.13000E+02 7.17000E+02 6.21000E+02 5.25000E+02 4.29000E+02 3.33000E+02 - 2.37000E+02 1.41000E+02 4.50000E+01 1.37700E+03 1.28100E+03 1.18500E+03 - 1.08900E+03 9.93000E+02 8.97000E+02 8.01000E+02 7.05000E+02 6.09000E+02 - 5.13000E+02 4.17000E+02 3.21000E+02 2.25000E+02 1.29000E+02 3.30000E+01 - 1.36500E+03 1.26900E+03 1.17300E+03 1.07700E+03 9.81000E+02 8.85000E+02 - 7.89000E+02 6.93000E+02 5.97000E+02 5.01000E+02 4.05000E+02 3.09000E+02 - 2.13000E+02 1.17000E+02 2.10000E+01 1.35300E+03 1.25700E+03 1.16100E+03 - 1.06500E+03 9.69000E+02 8.73000E+02 7.77000E+02 6.81000E+02 5.85000E+02 - 4.89000E+02 3.93000E+02 2.97000E+02 2.01000E+02 1.05000E+02 9.00000E+00 - 1.43500E+03 1.33900E+03 1.24300E+03 1.14700E+03 1.05100E+03 9.55000E+02 - 8.59000E+02 7.63000E+02 6.67000E+02 5.71000E+02 4.75000E+02 3.79000E+02 - 2.83000E+02 1.87000E+02 9.10000E+01 1.42300E+03 1.32700E+03 1.23100E+03 - 1.13500E+03 1.03900E+03 9.43000E+02 8.47000E+02 7.51000E+02 6.55000E+02 - 5.59000E+02 4.63000E+02 3.67000E+02 2.71000E+02 1.75000E+02 7.90000E+01 - 1.41100E+03 1.31500E+03 1.21900E+03 1.12300E+03 1.02700E+03 9.31000E+02 - 8.35000E+02 7.39000E+02 6.43000E+02 5.47000E+02 4.51000E+02 3.55000E+02 - 2.59000E+02 1.63000E+02 6.70000E+01 1.39900E+03 1.30300E+03 1.20700E+03 - 1.11100E+03 1.01500E+03 9.19000E+02 8.23000E+02 7.27000E+02 6.31000E+02 - 5.35000E+02 4.39000E+02 3.43000E+02 2.47000E+02 1.51000E+02 5.50000E+01 - 1.38700E+03 1.29100E+03 1.19500E+03 1.09900E+03 1.00300E+03 9.07000E+02 - 8.11000E+02 7.15000E+02 6.19000E+02 5.23000E+02 4.27000E+02 3.31000E+02 - 2.35000E+02 1.39000E+02 4.30000E+01 1.37500E+03 1.27900E+03 1.18300E+03 - 1.08700E+03 9.91000E+02 8.95000E+02 7.99000E+02 7.03000E+02 6.07000E+02 - 5.11000E+02 4.15000E+02 3.19000E+02 2.23000E+02 1.27000E+02 3.10000E+01 - 1.36300E+03 1.26700E+03 1.17100E+03 1.07500E+03 9.79000E+02 8.83000E+02 - 7.87000E+02 6.91000E+02 5.95000E+02 4.99000E+02 4.03000E+02 3.07000E+02 - 2.11000E+02 1.15000E+02 1.90000E+01 1.35100E+03 1.25500E+03 1.15900E+03 - 1.06300E+03 9.67000E+02 8.71000E+02 7.75000E+02 6.79000E+02 5.83000E+02 - 4.87000E+02 3.91000E+02 2.95000E+02 1.99000E+02 1.03000E+02 7.00000E+00 - 1.43300E+03 1.33700E+03 1.24100E+03 1.14500E+03 1.04900E+03 9.53000E+02 - 8.57000E+02 7.61000E+02 6.65000E+02 5.69000E+02 4.73000E+02 3.77000E+02 - 2.81000E+02 1.85000E+02 8.90000E+01 1.42100E+03 1.32500E+03 1.22900E+03 - 1.13300E+03 1.03700E+03 9.41000E+02 8.45000E+02 7.49000E+02 6.53000E+02 - 5.57000E+02 4.61000E+02 3.65000E+02 2.69000E+02 1.73000E+02 7.70000E+01 - 1.40900E+03 1.31300E+03 1.21700E+03 1.12100E+03 1.02500E+03 9.29000E+02 - 8.33000E+02 7.37000E+02 6.41000E+02 5.45000E+02 4.49000E+02 3.53000E+02 - 2.57000E+02 1.61000E+02 6.50000E+01 1.39700E+03 1.30100E+03 1.20500E+03 - 1.10900E+03 1.01300E+03 9.17000E+02 8.21000E+02 7.25000E+02 6.29000E+02 - 5.33000E+02 4.37000E+02 3.41000E+02 2.45000E+02 1.49000E+02 5.30000E+01 - 1.38500E+03 1.28900E+03 1.19300E+03 1.09700E+03 1.00100E+03 9.05000E+02 - 8.09000E+02 7.13000E+02 6.17000E+02 5.21000E+02 4.25000E+02 3.29000E+02 - 2.33000E+02 1.37000E+02 4.10000E+01 1.37300E+03 1.27700E+03 1.18100E+03 - 1.08500E+03 9.89000E+02 8.93000E+02 7.97000E+02 7.01000E+02 6.05000E+02 - 5.09000E+02 4.13000E+02 3.17000E+02 2.21000E+02 1.25000E+02 2.90000E+01 - 1.36100E+03 1.26500E+03 1.16900E+03 1.07300E+03 9.77000E+02 8.81000E+02 - 7.85000E+02 6.89000E+02 5.93000E+02 4.97000E+02 4.01000E+02 3.05000E+02 - 2.09000E+02 1.13000E+02 1.70000E+01 1.34900E+03 1.25300E+03 1.15700E+03 - 1.06100E+03 9.65000E+02 8.69000E+02 7.73000E+02 6.77000E+02 5.81000E+02 - 4.85000E+02 3.89000E+02 2.93000E+02 1.97000E+02 1.01000E+02 5.00000E+00 - 1.43100E+03 1.33500E+03 1.23900E+03 1.14300E+03 1.04700E+03 9.51000E+02 - 8.55000E+02 7.59000E+02 6.63000E+02 5.67000E+02 4.71000E+02 3.75000E+02 - 2.79000E+02 1.83000E+02 8.70000E+01 1.41900E+03 1.32300E+03 1.22700E+03 - 1.13100E+03 1.03500E+03 9.39000E+02 8.43000E+02 7.47000E+02 6.51000E+02 - 5.55000E+02 4.59000E+02 3.63000E+02 2.67000E+02 1.71000E+02 7.50000E+01 - 1.40700E+03 1.31100E+03 1.21500E+03 1.11900E+03 1.02300E+03 9.27000E+02 - 8.31000E+02 7.35000E+02 6.39000E+02 5.43000E+02 4.47000E+02 3.51000E+02 - 2.55000E+02 1.59000E+02 6.30000E+01 1.39500E+03 1.29900E+03 1.20300E+03 - 1.10700E+03 1.01100E+03 9.15000E+02 8.19000E+02 7.23000E+02 6.27000E+02 - 5.31000E+02 4.35000E+02 3.39000E+02 2.43000E+02 1.47000E+02 5.10000E+01 - 1.38300E+03 1.28700E+03 1.19100E+03 1.09500E+03 9.99000E+02 9.03000E+02 - 8.07000E+02 7.11000E+02 6.15000E+02 5.19000E+02 4.23000E+02 3.27000E+02 - 2.31000E+02 1.35000E+02 3.90000E+01 1.37100E+03 1.27500E+03 1.17900E+03 - 1.08300E+03 9.87000E+02 8.91000E+02 7.95000E+02 6.99000E+02 6.03000E+02 - 5.07000E+02 4.11000E+02 3.15000E+02 2.19000E+02 1.23000E+02 2.70000E+01 - 1.35900E+03 1.26300E+03 1.16700E+03 1.07100E+03 9.75000E+02 8.79000E+02 - 7.83000E+02 6.87000E+02 5.91000E+02 4.95000E+02 3.99000E+02 3.03000E+02 - 2.07000E+02 1.11000E+02 1.50000E+01 1.34700E+03 1.25100E+03 1.15500E+03 - 1.05900E+03 9.63000E+02 8.67000E+02 7.71000E+02 6.75000E+02 5.79000E+02 - 4.83000E+02 3.87000E+02 2.91000E+02 1.95000E+02 9.90000E+01 3.00000E+00 - 1.42900E+03 1.33300E+03 1.23700E+03 1.14100E+03 1.04500E+03 9.49000E+02 - 8.53000E+02 7.57000E+02 6.61000E+02 5.65000E+02 4.69000E+02 3.73000E+02 - 2.77000E+02 1.81000E+02 8.50000E+01 1.41700E+03 1.32100E+03 1.22500E+03 - 1.12900E+03 1.03300E+03 9.37000E+02 8.41000E+02 7.45000E+02 6.49000E+02 - 5.53000E+02 4.57000E+02 3.61000E+02 2.65000E+02 1.69000E+02 7.30000E+01 - 1.40500E+03 1.30900E+03 1.21300E+03 1.11700E+03 1.02100E+03 9.25000E+02 - 8.29000E+02 7.33000E+02 6.37000E+02 5.41000E+02 4.45000E+02 3.49000E+02 - 2.53000E+02 1.57000E+02 6.10000E+01 1.39300E+03 1.29700E+03 1.20100E+03 - 1.10500E+03 1.00900E+03 9.13000E+02 8.17000E+02 7.21000E+02 6.25000E+02 - 5.29000E+02 4.33000E+02 3.37000E+02 2.41000E+02 1.45000E+02 4.90000E+01 - 1.38100E+03 1.28500E+03 1.18900E+03 1.09300E+03 9.97000E+02 9.01000E+02 - 8.05000E+02 7.09000E+02 6.13000E+02 5.17000E+02 4.21000E+02 3.25000E+02 - 2.29000E+02 1.33000E+02 3.70000E+01 1.36900E+03 1.27300E+03 1.17700E+03 - 1.08100E+03 9.85000E+02 8.89000E+02 7.93000E+02 6.97000E+02 6.01000E+02 - 5.05000E+02 4.09000E+02 3.13000E+02 2.17000E+02 1.21000E+02 2.50000E+01 - 1.35700E+03 1.26100E+03 1.16500E+03 1.06900E+03 9.73000E+02 8.77000E+02 - 7.81000E+02 6.85000E+02 5.89000E+02 4.93000E+02 3.97000E+02 3.01000E+02 - 2.05000E+02 1.09000E+02 1.30000E+01 1.34500E+03 1.24900E+03 1.15300E+03 - 1.05700E+03 9.61000E+02 8.65000E+02 7.69000E+02 6.73000E+02 5.77000E+02 - 4.81000E+02 3.85000E+02 2.89000E+02 1.93000E+02 9.70000E+01 1.00000E+00 + 1.44000E+03 1.43900E+03 1.34400E+03 1.34300E+03 1.24800E+03 1.24700E+03 + 1.15200E+03 1.15100E+03 1.05600E+03 1.05500E+03 9.60000E+02 9.59000E+02 + 8.64000E+02 8.63000E+02 7.68000E+02 7.67000E+02 6.72000E+02 6.71000E+02 + 5.76000E+02 5.75000E+02 4.80000E+02 4.79000E+02 3.84000E+02 3.83000E+02 + 2.88000E+02 2.87000E+02 1.92000E+02 1.91000E+02 9.60000E+01 9.50000E+01 + 1.42800E+03 1.42700E+03 1.33200E+03 1.33100E+03 1.23600E+03 1.23500E+03 + 1.14000E+03 1.13900E+03 1.04400E+03 1.04300E+03 9.48000E+02 9.47000E+02 + 8.52000E+02 8.51000E+02 7.56000E+02 7.55000E+02 6.60000E+02 6.59000E+02 + 5.64000E+02 5.63000E+02 4.68000E+02 4.67000E+02 3.72000E+02 3.71000E+02 + 2.76000E+02 2.75000E+02 1.80000E+02 1.79000E+02 8.40000E+01 8.30000E+01 + 1.41600E+03 1.41500E+03 1.32000E+03 1.31900E+03 1.22400E+03 1.22300E+03 + 1.12800E+03 1.12700E+03 1.03200E+03 1.03100E+03 9.36000E+02 9.35000E+02 + 8.40000E+02 8.39000E+02 7.44000E+02 7.43000E+02 6.48000E+02 6.47000E+02 + 5.52000E+02 5.51000E+02 4.56000E+02 4.55000E+02 3.60000E+02 3.59000E+02 + 2.64000E+02 2.63000E+02 1.68000E+02 1.67000E+02 7.20000E+01 7.10000E+01 + 1.40400E+03 1.40300E+03 1.30800E+03 1.30700E+03 1.21200E+03 1.21100E+03 + 1.11600E+03 1.11500E+03 1.02000E+03 1.01900E+03 9.24000E+02 9.23000E+02 + 8.28000E+02 8.27000E+02 7.32000E+02 7.31000E+02 6.36000E+02 6.35000E+02 + 5.40000E+02 5.39000E+02 4.44000E+02 4.43000E+02 3.48000E+02 3.47000E+02 + 2.52000E+02 2.51000E+02 1.56000E+02 1.55000E+02 6.00000E+01 5.90000E+01 + 1.39200E+03 1.39100E+03 1.29600E+03 1.29500E+03 1.20000E+03 1.19900E+03 + 1.10400E+03 1.10300E+03 1.00800E+03 1.00700E+03 9.12000E+02 9.11000E+02 + 8.16000E+02 8.15000E+02 7.20000E+02 7.19000E+02 6.24000E+02 6.23000E+02 + 5.28000E+02 5.27000E+02 4.32000E+02 4.31000E+02 3.36000E+02 3.35000E+02 + 2.40000E+02 2.39000E+02 1.44000E+02 1.43000E+02 4.80000E+01 4.70000E+01 + 1.38000E+03 1.37900E+03 1.28400E+03 1.28300E+03 1.18800E+03 1.18700E+03 + 1.09200E+03 1.09100E+03 9.96000E+02 9.95000E+02 9.00000E+02 8.99000E+02 + 8.04000E+02 8.03000E+02 7.08000E+02 7.07000E+02 6.12000E+02 6.11000E+02 + 5.16000E+02 5.15000E+02 4.20000E+02 4.19000E+02 3.24000E+02 3.23000E+02 + 2.28000E+02 2.27000E+02 1.32000E+02 1.31000E+02 3.60000E+01 3.50000E+01 + 1.36800E+03 1.36700E+03 1.27200E+03 1.27100E+03 1.17600E+03 1.17500E+03 + 1.08000E+03 1.07900E+03 9.84000E+02 9.83000E+02 8.88000E+02 8.87000E+02 + 7.92000E+02 7.91000E+02 6.96000E+02 6.95000E+02 6.00000E+02 5.99000E+02 + 5.04000E+02 5.03000E+02 4.08000E+02 4.07000E+02 3.12000E+02 3.11000E+02 + 2.16000E+02 2.15000E+02 1.20000E+02 1.19000E+02 2.40000E+01 2.30000E+01 + 1.35600E+03 1.35500E+03 1.26000E+03 1.25900E+03 1.16400E+03 1.16300E+03 + 1.06800E+03 1.06700E+03 9.72000E+02 9.71000E+02 8.76000E+02 8.75000E+02 + 7.80000E+02 7.79000E+02 6.84000E+02 6.83000E+02 5.88000E+02 5.87000E+02 + 4.92000E+02 4.91000E+02 3.96000E+02 3.95000E+02 3.00000E+02 2.99000E+02 + 2.04000E+02 2.03000E+02 1.08000E+02 1.07000E+02 1.20000E+01 1.10000E+01 + 1.43800E+03 1.43700E+03 1.34200E+03 1.34100E+03 1.24600E+03 1.24500E+03 + 1.15000E+03 1.14900E+03 1.05400E+03 1.05300E+03 9.58000E+02 9.57000E+02 + 8.62000E+02 8.61000E+02 7.66000E+02 7.65000E+02 6.70000E+02 6.69000E+02 + 5.74000E+02 5.73000E+02 4.78000E+02 4.77000E+02 3.82000E+02 3.81000E+02 + 2.86000E+02 2.85000E+02 1.90000E+02 1.89000E+02 9.40000E+01 9.30000E+01 + 1.42600E+03 1.42500E+03 1.33000E+03 1.32900E+03 1.23400E+03 1.23300E+03 + 1.13800E+03 1.13700E+03 1.04200E+03 1.04100E+03 9.46000E+02 9.45000E+02 + 8.50000E+02 8.49000E+02 7.54000E+02 7.53000E+02 6.58000E+02 6.57000E+02 + 5.62000E+02 5.61000E+02 4.66000E+02 4.65000E+02 3.70000E+02 3.69000E+02 + 2.74000E+02 2.73000E+02 1.78000E+02 1.77000E+02 8.20000E+01 8.10000E+01 + 1.41400E+03 1.41300E+03 1.31800E+03 1.31700E+03 1.22200E+03 1.22100E+03 + 1.12600E+03 1.12500E+03 1.03000E+03 1.02900E+03 9.34000E+02 9.33000E+02 + 8.38000E+02 8.37000E+02 7.42000E+02 7.41000E+02 6.46000E+02 6.45000E+02 + 5.50000E+02 5.49000E+02 4.54000E+02 4.53000E+02 3.58000E+02 3.57000E+02 + 2.62000E+02 2.61000E+02 1.66000E+02 1.65000E+02 7.00000E+01 6.90000E+01 + 1.40200E+03 1.40100E+03 1.30600E+03 1.30500E+03 1.21000E+03 1.20900E+03 + 1.11400E+03 1.11300E+03 1.01800E+03 1.01700E+03 9.22000E+02 9.21000E+02 + 8.26000E+02 8.25000E+02 7.30000E+02 7.29000E+02 6.34000E+02 6.33000E+02 + 5.38000E+02 5.37000E+02 4.42000E+02 4.41000E+02 3.46000E+02 3.45000E+02 + 2.50000E+02 2.49000E+02 1.54000E+02 1.53000E+02 5.80000E+01 5.70000E+01 + 1.39000E+03 1.38900E+03 1.29400E+03 1.29300E+03 1.19800E+03 1.19700E+03 + 1.10200E+03 1.10100E+03 1.00600E+03 1.00500E+03 9.10000E+02 9.09000E+02 + 8.14000E+02 8.13000E+02 7.18000E+02 7.17000E+02 6.22000E+02 6.21000E+02 + 5.26000E+02 5.25000E+02 4.30000E+02 4.29000E+02 3.34000E+02 3.33000E+02 + 2.38000E+02 2.37000E+02 1.42000E+02 1.41000E+02 4.60000E+01 4.50000E+01 + 1.37800E+03 1.37700E+03 1.28200E+03 1.28100E+03 1.18600E+03 1.18500E+03 + 1.09000E+03 1.08900E+03 9.94000E+02 9.93000E+02 8.98000E+02 8.97000E+02 + 8.02000E+02 8.01000E+02 7.06000E+02 7.05000E+02 6.10000E+02 6.09000E+02 + 5.14000E+02 5.13000E+02 4.18000E+02 4.17000E+02 3.22000E+02 3.21000E+02 + 2.26000E+02 2.25000E+02 1.30000E+02 1.29000E+02 3.40000E+01 3.30000E+01 + 1.36600E+03 1.36500E+03 1.27000E+03 1.26900E+03 1.17400E+03 1.17300E+03 + 1.07800E+03 1.07700E+03 9.82000E+02 9.81000E+02 8.86000E+02 8.85000E+02 + 7.90000E+02 7.89000E+02 6.94000E+02 6.93000E+02 5.98000E+02 5.97000E+02 + 5.02000E+02 5.01000E+02 4.06000E+02 4.05000E+02 3.10000E+02 3.09000E+02 + 2.14000E+02 2.13000E+02 1.18000E+02 1.17000E+02 2.20000E+01 2.10000E+01 + 1.35400E+03 1.35300E+03 1.25800E+03 1.25700E+03 1.16200E+03 1.16100E+03 + 1.06600E+03 1.06500E+03 9.70000E+02 9.69000E+02 8.74000E+02 8.73000E+02 + 7.78000E+02 7.77000E+02 6.82000E+02 6.81000E+02 5.86000E+02 5.85000E+02 + 4.90000E+02 4.89000E+02 3.94000E+02 3.93000E+02 2.98000E+02 2.97000E+02 + 2.02000E+02 2.01000E+02 1.06000E+02 1.05000E+02 1.00000E+01 9.00000E+00 + 1.43600E+03 1.43500E+03 1.34000E+03 1.33900E+03 1.24400E+03 1.24300E+03 + 1.14800E+03 1.14700E+03 1.05200E+03 1.05100E+03 9.56000E+02 9.55000E+02 + 8.60000E+02 8.59000E+02 7.64000E+02 7.63000E+02 6.68000E+02 6.67000E+02 + 5.72000E+02 5.71000E+02 4.76000E+02 4.75000E+02 3.80000E+02 3.79000E+02 + 2.84000E+02 2.83000E+02 1.88000E+02 1.87000E+02 9.20000E+01 9.10000E+01 + 1.42400E+03 1.42300E+03 1.32800E+03 1.32700E+03 1.23200E+03 1.23100E+03 + 1.13600E+03 1.13500E+03 1.04000E+03 1.03900E+03 9.44000E+02 9.43000E+02 + 8.48000E+02 8.47000E+02 7.52000E+02 7.51000E+02 6.56000E+02 6.55000E+02 + 5.60000E+02 5.59000E+02 4.64000E+02 4.63000E+02 3.68000E+02 3.67000E+02 + 2.72000E+02 2.71000E+02 1.76000E+02 1.75000E+02 8.00000E+01 7.90000E+01 + 1.41200E+03 1.41100E+03 1.31600E+03 1.31500E+03 1.22000E+03 1.21900E+03 + 1.12400E+03 1.12300E+03 1.02800E+03 1.02700E+03 9.32000E+02 9.31000E+02 + 8.36000E+02 8.35000E+02 7.40000E+02 7.39000E+02 6.44000E+02 6.43000E+02 + 5.48000E+02 5.47000E+02 4.52000E+02 4.51000E+02 3.56000E+02 3.55000E+02 + 2.60000E+02 2.59000E+02 1.64000E+02 1.63000E+02 6.80000E+01 6.70000E+01 + 1.40000E+03 1.39900E+03 1.30400E+03 1.30300E+03 1.20800E+03 1.20700E+03 + 1.11200E+03 1.11100E+03 1.01600E+03 1.01500E+03 9.20000E+02 9.19000E+02 + 8.24000E+02 8.23000E+02 7.28000E+02 7.27000E+02 6.32000E+02 6.31000E+02 + 5.36000E+02 5.35000E+02 4.40000E+02 4.39000E+02 3.44000E+02 3.43000E+02 + 2.48000E+02 2.47000E+02 1.52000E+02 1.51000E+02 5.60000E+01 5.50000E+01 + 1.38800E+03 1.38700E+03 1.29200E+03 1.29100E+03 1.19600E+03 1.19500E+03 + 1.10000E+03 1.09900E+03 1.00400E+03 1.00300E+03 9.08000E+02 9.07000E+02 + 8.12000E+02 8.11000E+02 7.16000E+02 7.15000E+02 6.20000E+02 6.19000E+02 + 5.24000E+02 5.23000E+02 4.28000E+02 4.27000E+02 3.32000E+02 3.31000E+02 + 2.36000E+02 2.35000E+02 1.40000E+02 1.39000E+02 4.40000E+01 4.30000E+01 + 1.37600E+03 1.37500E+03 1.28000E+03 1.27900E+03 1.18400E+03 1.18300E+03 + 1.08800E+03 1.08700E+03 9.92000E+02 9.91000E+02 8.96000E+02 8.95000E+02 + 8.00000E+02 7.99000E+02 7.04000E+02 7.03000E+02 6.08000E+02 6.07000E+02 + 5.12000E+02 5.11000E+02 4.16000E+02 4.15000E+02 3.20000E+02 3.19000E+02 + 2.24000E+02 2.23000E+02 1.28000E+02 1.27000E+02 3.20000E+01 3.10000E+01 + 1.36400E+03 1.36300E+03 1.26800E+03 1.26700E+03 1.17200E+03 1.17100E+03 + 1.07600E+03 1.07500E+03 9.80000E+02 9.79000E+02 8.84000E+02 8.83000E+02 + 7.88000E+02 7.87000E+02 6.92000E+02 6.91000E+02 5.96000E+02 5.95000E+02 + 5.00000E+02 4.99000E+02 4.04000E+02 4.03000E+02 3.08000E+02 3.07000E+02 + 2.12000E+02 2.11000E+02 1.16000E+02 1.15000E+02 2.00000E+01 1.90000E+01 + 1.35200E+03 1.35100E+03 1.25600E+03 1.25500E+03 1.16000E+03 1.15900E+03 + 1.06400E+03 1.06300E+03 9.68000E+02 9.67000E+02 8.72000E+02 8.71000E+02 + 7.76000E+02 7.75000E+02 6.80000E+02 6.79000E+02 5.84000E+02 5.83000E+02 + 4.88000E+02 4.87000E+02 3.92000E+02 3.91000E+02 2.96000E+02 2.95000E+02 + 2.00000E+02 1.99000E+02 1.04000E+02 1.03000E+02 8.00000E+00 7.00000E+00 + 1.43400E+03 1.43300E+03 1.33800E+03 1.33700E+03 1.24200E+03 1.24100E+03 + 1.14600E+03 1.14500E+03 1.05000E+03 1.04900E+03 9.54000E+02 9.53000E+02 + 8.58000E+02 8.57000E+02 7.62000E+02 7.61000E+02 6.66000E+02 6.65000E+02 + 5.70000E+02 5.69000E+02 4.74000E+02 4.73000E+02 3.78000E+02 3.77000E+02 + 2.82000E+02 2.81000E+02 1.86000E+02 1.85000E+02 9.00000E+01 8.90000E+01 + 1.42200E+03 1.42100E+03 1.32600E+03 1.32500E+03 1.23000E+03 1.22900E+03 + 1.13400E+03 1.13300E+03 1.03800E+03 1.03700E+03 9.42000E+02 9.41000E+02 + 8.46000E+02 8.45000E+02 7.50000E+02 7.49000E+02 6.54000E+02 6.53000E+02 + 5.58000E+02 5.57000E+02 4.62000E+02 4.61000E+02 3.66000E+02 3.65000E+02 + 2.70000E+02 2.69000E+02 1.74000E+02 1.73000E+02 7.80000E+01 7.70000E+01 + 1.41000E+03 1.40900E+03 1.31400E+03 1.31300E+03 1.21800E+03 1.21700E+03 + 1.12200E+03 1.12100E+03 1.02600E+03 1.02500E+03 9.30000E+02 9.29000E+02 + 8.34000E+02 8.33000E+02 7.38000E+02 7.37000E+02 6.42000E+02 6.41000E+02 + 5.46000E+02 5.45000E+02 4.50000E+02 4.49000E+02 3.54000E+02 3.53000E+02 + 2.58000E+02 2.57000E+02 1.62000E+02 1.61000E+02 6.60000E+01 6.50000E+01 + 1.39800E+03 1.39700E+03 1.30200E+03 1.30100E+03 1.20600E+03 1.20500E+03 + 1.11000E+03 1.10900E+03 1.01400E+03 1.01300E+03 9.18000E+02 9.17000E+02 + 8.22000E+02 8.21000E+02 7.26000E+02 7.25000E+02 6.30000E+02 6.29000E+02 + 5.34000E+02 5.33000E+02 4.38000E+02 4.37000E+02 3.42000E+02 3.41000E+02 + 2.46000E+02 2.45000E+02 1.50000E+02 1.49000E+02 5.40000E+01 5.30000E+01 + 1.38600E+03 1.38500E+03 1.29000E+03 1.28900E+03 1.19400E+03 1.19300E+03 + 1.09800E+03 1.09700E+03 1.00200E+03 1.00100E+03 9.06000E+02 9.05000E+02 + 8.10000E+02 8.09000E+02 7.14000E+02 7.13000E+02 6.18000E+02 6.17000E+02 + 5.22000E+02 5.21000E+02 4.26000E+02 4.25000E+02 3.30000E+02 3.29000E+02 + 2.34000E+02 2.33000E+02 1.38000E+02 1.37000E+02 4.20000E+01 4.10000E+01 + 1.37400E+03 1.37300E+03 1.27800E+03 1.27700E+03 1.18200E+03 1.18100E+03 + 1.08600E+03 1.08500E+03 9.90000E+02 9.89000E+02 8.94000E+02 8.93000E+02 + 7.98000E+02 7.97000E+02 7.02000E+02 7.01000E+02 6.06000E+02 6.05000E+02 + 5.10000E+02 5.09000E+02 4.14000E+02 4.13000E+02 3.18000E+02 3.17000E+02 + 2.22000E+02 2.21000E+02 1.26000E+02 1.25000E+02 3.00000E+01 2.90000E+01 + 1.36200E+03 1.36100E+03 1.26600E+03 1.26500E+03 1.17000E+03 1.16900E+03 + 1.07400E+03 1.07300E+03 9.78000E+02 9.77000E+02 8.82000E+02 8.81000E+02 + 7.86000E+02 7.85000E+02 6.90000E+02 6.89000E+02 5.94000E+02 5.93000E+02 + 4.98000E+02 4.97000E+02 4.02000E+02 4.01000E+02 3.06000E+02 3.05000E+02 + 2.10000E+02 2.09000E+02 1.14000E+02 1.13000E+02 1.80000E+01 1.70000E+01 + 1.35000E+03 1.34900E+03 1.25400E+03 1.25300E+03 1.15800E+03 1.15700E+03 + 1.06200E+03 1.06100E+03 9.66000E+02 9.65000E+02 8.70000E+02 8.69000E+02 + 7.74000E+02 7.73000E+02 6.78000E+02 6.77000E+02 5.82000E+02 5.81000E+02 + 4.86000E+02 4.85000E+02 3.90000E+02 3.89000E+02 2.94000E+02 2.93000E+02 + 1.98000E+02 1.97000E+02 1.02000E+02 1.01000E+02 6.00000E+00 5.00000E+00 + 1.43200E+03 1.43100E+03 1.33600E+03 1.33500E+03 1.24000E+03 1.23900E+03 + 1.14400E+03 1.14300E+03 1.04800E+03 1.04700E+03 9.52000E+02 9.51000E+02 + 8.56000E+02 8.55000E+02 7.60000E+02 7.59000E+02 6.64000E+02 6.63000E+02 + 5.68000E+02 5.67000E+02 4.72000E+02 4.71000E+02 3.76000E+02 3.75000E+02 + 2.80000E+02 2.79000E+02 1.84000E+02 1.83000E+02 8.80000E+01 8.70000E+01 + 1.42000E+03 1.41900E+03 1.32400E+03 1.32300E+03 1.22800E+03 1.22700E+03 + 1.13200E+03 1.13100E+03 1.03600E+03 1.03500E+03 9.40000E+02 9.39000E+02 + 8.44000E+02 8.43000E+02 7.48000E+02 7.47000E+02 6.52000E+02 6.51000E+02 + 5.56000E+02 5.55000E+02 4.60000E+02 4.59000E+02 3.64000E+02 3.63000E+02 + 2.68000E+02 2.67000E+02 1.72000E+02 1.71000E+02 7.60000E+01 7.50000E+01 + 1.40800E+03 1.40700E+03 1.31200E+03 1.31100E+03 1.21600E+03 1.21500E+03 + 1.12000E+03 1.11900E+03 1.02400E+03 1.02300E+03 9.28000E+02 9.27000E+02 + 8.32000E+02 8.31000E+02 7.36000E+02 7.35000E+02 6.40000E+02 6.39000E+02 + 5.44000E+02 5.43000E+02 4.48000E+02 4.47000E+02 3.52000E+02 3.51000E+02 + 2.56000E+02 2.55000E+02 1.60000E+02 1.59000E+02 6.40000E+01 6.30000E+01 + 1.39600E+03 1.39500E+03 1.30000E+03 1.29900E+03 1.20400E+03 1.20300E+03 + 1.10800E+03 1.10700E+03 1.01200E+03 1.01100E+03 9.16000E+02 9.15000E+02 + 8.20000E+02 8.19000E+02 7.24000E+02 7.23000E+02 6.28000E+02 6.27000E+02 + 5.32000E+02 5.31000E+02 4.36000E+02 4.35000E+02 3.40000E+02 3.39000E+02 + 2.44000E+02 2.43000E+02 1.48000E+02 1.47000E+02 5.20000E+01 5.10000E+01 + 1.38400E+03 1.38300E+03 1.28800E+03 1.28700E+03 1.19200E+03 1.19100E+03 + 1.09600E+03 1.09500E+03 1.00000E+03 9.99000E+02 9.04000E+02 9.03000E+02 + 8.08000E+02 8.07000E+02 7.12000E+02 7.11000E+02 6.16000E+02 6.15000E+02 + 5.20000E+02 5.19000E+02 4.24000E+02 4.23000E+02 3.28000E+02 3.27000E+02 + 2.32000E+02 2.31000E+02 1.36000E+02 1.35000E+02 4.00000E+01 3.90000E+01 + 1.37200E+03 1.37100E+03 1.27600E+03 1.27500E+03 1.18000E+03 1.17900E+03 + 1.08400E+03 1.08300E+03 9.88000E+02 9.87000E+02 8.92000E+02 8.91000E+02 + 7.96000E+02 7.95000E+02 7.00000E+02 6.99000E+02 6.04000E+02 6.03000E+02 + 5.08000E+02 5.07000E+02 4.12000E+02 4.11000E+02 3.16000E+02 3.15000E+02 + 2.20000E+02 2.19000E+02 1.24000E+02 1.23000E+02 2.80000E+01 2.70000E+01 + 1.36000E+03 1.35900E+03 1.26400E+03 1.26300E+03 1.16800E+03 1.16700E+03 + 1.07200E+03 1.07100E+03 9.76000E+02 9.75000E+02 8.80000E+02 8.79000E+02 + 7.84000E+02 7.83000E+02 6.88000E+02 6.87000E+02 5.92000E+02 5.91000E+02 + 4.96000E+02 4.95000E+02 4.00000E+02 3.99000E+02 3.04000E+02 3.03000E+02 + 2.08000E+02 2.07000E+02 1.12000E+02 1.11000E+02 1.60000E+01 1.50000E+01 + 1.34800E+03 1.34700E+03 1.25200E+03 1.25100E+03 1.15600E+03 1.15500E+03 + 1.06000E+03 1.05900E+03 9.64000E+02 9.63000E+02 8.68000E+02 8.67000E+02 + 7.72000E+02 7.71000E+02 6.76000E+02 6.75000E+02 5.80000E+02 5.79000E+02 + 4.84000E+02 4.83000E+02 3.88000E+02 3.87000E+02 2.92000E+02 2.91000E+02 + 1.96000E+02 1.95000E+02 1.00000E+02 9.90000E+01 4.00000E+00 3.00000E+00 + 1.43000E+03 1.42900E+03 1.33400E+03 1.33300E+03 1.23800E+03 1.23700E+03 + 1.14200E+03 1.14100E+03 1.04600E+03 1.04500E+03 9.50000E+02 9.49000E+02 + 8.54000E+02 8.53000E+02 7.58000E+02 7.57000E+02 6.62000E+02 6.61000E+02 + 5.66000E+02 5.65000E+02 4.70000E+02 4.69000E+02 3.74000E+02 3.73000E+02 + 2.78000E+02 2.77000E+02 1.82000E+02 1.81000E+02 8.60000E+01 8.50000E+01 + 1.41800E+03 1.41700E+03 1.32200E+03 1.32100E+03 1.22600E+03 1.22500E+03 + 1.13000E+03 1.12900E+03 1.03400E+03 1.03300E+03 9.38000E+02 9.37000E+02 + 8.42000E+02 8.41000E+02 7.46000E+02 7.45000E+02 6.50000E+02 6.49000E+02 + 5.54000E+02 5.53000E+02 4.58000E+02 4.57000E+02 3.62000E+02 3.61000E+02 + 2.66000E+02 2.65000E+02 1.70000E+02 1.69000E+02 7.40000E+01 7.30000E+01 + 1.40600E+03 1.40500E+03 1.31000E+03 1.30900E+03 1.21400E+03 1.21300E+03 + 1.11800E+03 1.11700E+03 1.02200E+03 1.02100E+03 9.26000E+02 9.25000E+02 + 8.30000E+02 8.29000E+02 7.34000E+02 7.33000E+02 6.38000E+02 6.37000E+02 + 5.42000E+02 5.41000E+02 4.46000E+02 4.45000E+02 3.50000E+02 3.49000E+02 + 2.54000E+02 2.53000E+02 1.58000E+02 1.57000E+02 6.20000E+01 6.10000E+01 + 1.39400E+03 1.39300E+03 1.29800E+03 1.29700E+03 1.20200E+03 1.20100E+03 + 1.10600E+03 1.10500E+03 1.01000E+03 1.00900E+03 9.14000E+02 9.13000E+02 + 8.18000E+02 8.17000E+02 7.22000E+02 7.21000E+02 6.26000E+02 6.25000E+02 + 5.30000E+02 5.29000E+02 4.34000E+02 4.33000E+02 3.38000E+02 3.37000E+02 + 2.42000E+02 2.41000E+02 1.46000E+02 1.45000E+02 5.00000E+01 4.90000E+01 + 1.38200E+03 1.38100E+03 1.28600E+03 1.28500E+03 1.19000E+03 1.18900E+03 + 1.09400E+03 1.09300E+03 9.98000E+02 9.97000E+02 9.02000E+02 9.01000E+02 + 8.06000E+02 8.05000E+02 7.10000E+02 7.09000E+02 6.14000E+02 6.13000E+02 + 5.18000E+02 5.17000E+02 4.22000E+02 4.21000E+02 3.26000E+02 3.25000E+02 + 2.30000E+02 2.29000E+02 1.34000E+02 1.33000E+02 3.80000E+01 3.70000E+01 + 1.37000E+03 1.36900E+03 1.27400E+03 1.27300E+03 1.17800E+03 1.17700E+03 + 1.08200E+03 1.08100E+03 9.86000E+02 9.85000E+02 8.90000E+02 8.89000E+02 + 7.94000E+02 7.93000E+02 6.98000E+02 6.97000E+02 6.02000E+02 6.01000E+02 + 5.06000E+02 5.05000E+02 4.10000E+02 4.09000E+02 3.14000E+02 3.13000E+02 + 2.18000E+02 2.17000E+02 1.22000E+02 1.21000E+02 2.60000E+01 2.50000E+01 + 1.35800E+03 1.35700E+03 1.26200E+03 1.26100E+03 1.16600E+03 1.16500E+03 + 1.07000E+03 1.06900E+03 9.74000E+02 9.73000E+02 8.78000E+02 8.77000E+02 + 7.82000E+02 7.81000E+02 6.86000E+02 6.85000E+02 5.90000E+02 5.89000E+02 + 4.94000E+02 4.93000E+02 3.98000E+02 3.97000E+02 3.02000E+02 3.01000E+02 + 2.06000E+02 2.05000E+02 1.10000E+02 1.09000E+02 1.40000E+01 1.30000E+01 + 1.34600E+03 1.34500E+03 1.25000E+03 1.24900E+03 1.15400E+03 1.15300E+03 + 1.05800E+03 1.05700E+03 9.62000E+02 9.61000E+02 8.66000E+02 8.65000E+02 + 7.70000E+02 7.69000E+02 6.74000E+02 6.73000E+02 5.78000E+02 5.77000E+02 + 4.82000E+02 4.81000E+02 3.86000E+02 3.85000E+02 2.90000E+02 2.89000E+02 + 1.94000E+02 1.93000E+02 9.80000E+01 9.70000E+01 2.00000E+00 1.00000E+00 diff --git a/tests/unit_tests/weightwindows/wwinp_np b/tests/unit_tests/weightwindows/wwinp_np index ed2073cf9..6d77afc3e 100644 --- a/tests/unit_tests/weightwindows/wwinp_np +++ b/tests/unit_tests/weightwindows/wwinp_np @@ -13,30 +13,30 @@ 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 1.00000E+00 1.00000E-01 1.46780E-01 2.15440E-01 - 1.44000E+02 1.26000E+02 1.08000E+02 9.00000E+01 7.20000E+01 5.40000E+01 - 3.60000E+01 1.80000E+01 1.41000E+02 1.23000E+02 1.05000E+02 8.70000E+01 - 6.90000E+01 5.10000E+01 3.30000E+01 1.50000E+01 1.38000E+02 1.20000E+02 - 1.02000E+02 8.40000E+01 6.60000E+01 4.80000E+01 3.00000E+01 1.20000E+01 - 1.35000E+02 1.17000E+02 9.90000E+01 8.10000E+01 6.30000E+01 4.50000E+01 - 2.70000E+01 9.00000E+00 1.32000E+02 1.14000E+02 9.60000E+01 7.80000E+01 - 6.00000E+01 4.20000E+01 2.40000E+01 6.00000E+00 1.29000E+02 1.11000E+02 - 9.30000E+01 7.50000E+01 5.70000E+01 3.90000E+01 2.10000E+01 3.00000E+00 - 1.43000E+02 1.25000E+02 1.07000E+02 8.90000E+01 7.10000E+01 5.30000E+01 - 3.50000E+01 1.70000E+01 1.40000E+02 1.22000E+02 1.04000E+02 8.60000E+01 - 6.80000E+01 5.00000E+01 3.20000E+01 1.40000E+01 1.37000E+02 1.19000E+02 - 1.01000E+02 8.30000E+01 6.50000E+01 4.70000E+01 2.90000E+01 1.10000E+01 - 1.34000E+02 1.16000E+02 9.80000E+01 8.00000E+01 6.20000E+01 4.40000E+01 - 2.60000E+01 8.00000E+00 1.31000E+02 1.13000E+02 9.50000E+01 7.70000E+01 - 5.90000E+01 4.10000E+01 2.30000E+01 5.00000E+00 1.28000E+02 1.10000E+02 - 9.20000E+01 7.40000E+01 5.60000E+01 3.80000E+01 2.00000E+01 2.00000E+00 - 1.42000E+02 1.24000E+02 1.06000E+02 8.80000E+01 7.00000E+01 5.20000E+01 - 3.40000E+01 1.60000E+01 1.39000E+02 1.21000E+02 1.03000E+02 8.50000E+01 - 6.70000E+01 4.90000E+01 3.10000E+01 1.30000E+01 1.36000E+02 1.18000E+02 - 1.00000E+02 8.20000E+01 6.40000E+01 4.60000E+01 2.80000E+01 1.00000E+01 - 1.33000E+02 1.15000E+02 9.70000E+01 7.90000E+01 6.10000E+01 4.30000E+01 - 2.50000E+01 7.00000E+00 1.30000E+02 1.12000E+02 9.40000E+01 7.60000E+01 - 5.80000E+01 4.00000E+01 2.20000E+01 4.00000E+00 1.27000E+02 1.09000E+02 - 9.10000E+01 7.30000E+01 5.50000E+01 3.70000E+01 1.90000E+01 1.00000E+00 + 1.44000E+02 1.43000E+02 1.42000E+02 1.26000E+02 1.25000E+02 1.24000E+02 + 1.08000E+02 1.07000E+02 1.06000E+02 9.00000E+01 8.90000E+01 8.80000E+01 + 7.20000E+01 7.10000E+01 7.00000E+01 5.40000E+01 5.30000E+01 5.20000E+01 + 3.60000E+01 3.50000E+01 3.40000E+01 1.80000E+01 1.70000E+01 1.60000E+01 + 1.41000E+02 1.40000E+02 1.39000E+02 1.23000E+02 1.22000E+02 1.21000E+02 + 1.05000E+02 1.04000E+02 1.03000E+02 8.70000E+01 8.60000E+01 8.50000E+01 + 6.90000E+01 6.80000E+01 6.70000E+01 5.10000E+01 5.00000E+01 4.90000E+01 + 3.30000E+01 3.20000E+01 3.10000E+01 1.50000E+01 1.40000E+01 1.30000E+01 + 1.38000E+02 1.37000E+02 1.36000E+02 1.20000E+02 1.19000E+02 1.18000E+02 + 1.02000E+02 1.01000E+02 1.00000E+02 8.40000E+01 8.30000E+01 8.20000E+01 + 6.60000E+01 6.50000E+01 6.40000E+01 4.80000E+01 4.70000E+01 4.60000E+01 + 3.00000E+01 2.90000E+01 2.80000E+01 1.20000E+01 1.10000E+01 1.00000E+01 + 1.35000E+02 1.34000E+02 1.33000E+02 1.17000E+02 1.16000E+02 1.15000E+02 + 9.90000E+01 9.80000E+01 9.70000E+01 8.10000E+01 8.00000E+01 7.90000E+01 + 6.30000E+01 6.20000E+01 6.10000E+01 4.50000E+01 4.40000E+01 4.30000E+01 + 2.70000E+01 2.60000E+01 2.50000E+01 9.00000E+00 8.00000E+00 7.00000E+00 + 1.32000E+02 1.31000E+02 1.30000E+02 1.14000E+02 1.13000E+02 1.12000E+02 + 9.60000E+01 9.50000E+01 9.40000E+01 7.80000E+01 7.70000E+01 7.60000E+01 + 6.00000E+01 5.90000E+01 5.80000E+01 4.20000E+01 4.10000E+01 4.00000E+01 + 2.40000E+01 2.30000E+01 2.20000E+01 6.00000E+00 5.00000E+00 4.00000E+00 + 1.29000E+02 1.28000E+02 1.27000E+02 1.11000E+02 1.10000E+02 1.09000E+02 + 9.30000E+01 9.20000E+01 9.10000E+01 7.50000E+01 7.40000E+01 7.30000E+01 + 5.70000E+01 5.60000E+01 5.50000E+01 3.90000E+01 3.80000E+01 3.70000E+01 + 2.10000E+01 2.00000E+01 1.90000E+01 3.00000E+00 2.00000E+00 1.00000E+00 1.00000E+02 4.80000E+01 4.20000E+01 3.60000E+01 3.00000E+01 2.40000E+01 1.80000E+01 1.20000E+01 6.00000E+00 4.70000E+01 4.10000E+01 3.50000E+01 2.90000E+01 @@ -46,4 +46,3 @@ 9.00000E+00 3.00000E+00 4.40000E+01 3.80000E+01 3.20000E+01 2.60000E+01 2.00000E+01 1.40000E+01 8.00000E+00 2.00000E+00 4.30000E+01 3.70000E+01 3.10000E+01 2.50000E+01 1.90000E+01 1.30000E+01 7.00000E+00 1.00000E+00 - diff --git a/tests/unit_tests/weightwindows/wwinp_p b/tests/unit_tests/weightwindows/wwinp_p index a9f9f98df..95315692f 100644 --- a/tests/unit_tests/weightwindows/wwinp_p +++ b/tests/unit_tests/weightwindows/wwinp_p @@ -13,36 +13,36 @@ 1.00000E+00 -5.00000E+01 1.00000E+00 5.00000E+01 1.00000E+00 1.00000E-01 1.46780E-01 2.15440E-01 3.16230E-01 - 1.92000E+02 1.60000E+02 1.28000E+02 9.60000E+01 6.40000E+01 3.20000E+01 - 1.88000E+02 1.56000E+02 1.24000E+02 9.20000E+01 6.00000E+01 2.80000E+01 - 1.84000E+02 1.52000E+02 1.20000E+02 8.80000E+01 5.60000E+01 2.40000E+01 - 1.80000E+02 1.48000E+02 1.16000E+02 8.40000E+01 5.20000E+01 2.00000E+01 - 1.76000E+02 1.44000E+02 1.12000E+02 8.00000E+01 4.80000E+01 1.60000E+01 - 1.72000E+02 1.40000E+02 1.08000E+02 7.60000E+01 4.40000E+01 1.20000E+01 - 1.68000E+02 1.36000E+02 1.04000E+02 7.20000E+01 4.00000E+01 8.00000E+00 - 1.64000E+02 1.32000E+02 1.00000E+02 6.80000E+01 3.60000E+01 4.00000E+00 - 1.91000E+02 1.59000E+02 1.27000E+02 9.50000E+01 6.30000E+01 3.10000E+01 - 1.87000E+02 1.55000E+02 1.23000E+02 9.10000E+01 5.90000E+01 2.70000E+01 - 1.83000E+02 1.51000E+02 1.19000E+02 8.70000E+01 5.50000E+01 2.30000E+01 - 1.79000E+02 1.47000E+02 1.15000E+02 8.30000E+01 5.10000E+01 1.90000E+01 - 1.75000E+02 1.43000E+02 1.11000E+02 7.90000E+01 4.70000E+01 1.50000E+01 - 1.71000E+02 1.39000E+02 1.07000E+02 7.50000E+01 4.30000E+01 1.10000E+01 - 1.67000E+02 1.35000E+02 1.03000E+02 7.10000E+01 3.90000E+01 7.00000E+00 - 1.63000E+02 1.31000E+02 9.90000E+01 6.70000E+01 3.50000E+01 3.00000E+00 - 1.90000E+02 1.58000E+02 1.26000E+02 9.40000E+01 6.20000E+01 3.00000E+01 - 1.86000E+02 1.54000E+02 1.22000E+02 9.00000E+01 5.80000E+01 2.60000E+01 - 1.82000E+02 1.50000E+02 1.18000E+02 8.60000E+01 5.40000E+01 2.20000E+01 - 1.78000E+02 1.46000E+02 1.14000E+02 8.20000E+01 5.00000E+01 1.80000E+01 - 1.74000E+02 1.42000E+02 1.10000E+02 7.80000E+01 4.60000E+01 1.40000E+01 - 1.70000E+02 1.38000E+02 1.06000E+02 7.40000E+01 4.20000E+01 1.00000E+01 - 1.66000E+02 1.34000E+02 1.02000E+02 7.00000E+01 3.80000E+01 6.00000E+00 - 1.62000E+02 1.30000E+02 9.80000E+01 6.60000E+01 3.40000E+01 2.00000E+00 - 1.89000E+02 1.57000E+02 1.25000E+02 9.30000E+01 6.10000E+01 2.90000E+01 - 1.85000E+02 1.53000E+02 1.21000E+02 8.90000E+01 5.70000E+01 2.50000E+01 - 1.81000E+02 1.49000E+02 1.17000E+02 8.50000E+01 5.30000E+01 2.10000E+01 - 1.77000E+02 1.45000E+02 1.13000E+02 8.10000E+01 4.90000E+01 1.70000E+01 - 1.73000E+02 1.41000E+02 1.09000E+02 7.70000E+01 4.50000E+01 1.30000E+01 - 1.69000E+02 1.37000E+02 1.05000E+02 7.30000E+01 4.10000E+01 9.00000E+00 - 1.65000E+02 1.33000E+02 1.01000E+02 6.90000E+01 3.70000E+01 5.00000E+00 - 1.61000E+02 1.29000E+02 9.70000E+01 6.50000E+01 3.30000E+01 1.00000E+00 + 1.92000E+02 1.91000E+02 1.90000E+02 1.89000E+02 1.60000E+02 1.59000E+02 + 1.58000E+02 1.57000E+02 1.28000E+02 1.27000E+02 1.26000E+02 1.25000E+02 + 9.60000E+01 9.50000E+01 9.40000E+01 9.30000E+01 6.40000E+01 6.30000E+01 + 6.20000E+01 6.10000E+01 3.20000E+01 3.10000E+01 3.00000E+01 2.90000E+01 + 1.88000E+02 1.87000E+02 1.86000E+02 1.85000E+02 1.56000E+02 1.55000E+02 + 1.54000E+02 1.53000E+02 1.24000E+02 1.23000E+02 1.22000E+02 1.21000E+02 + 9.20000E+01 9.10000E+01 9.00000E+01 8.90000E+01 6.00000E+01 5.90000E+01 + 5.80000E+01 5.70000E+01 2.80000E+01 2.70000E+01 2.60000E+01 2.50000E+01 + 1.84000E+02 1.83000E+02 1.82000E+02 1.81000E+02 1.52000E+02 1.51000E+02 + 1.50000E+02 1.49000E+02 1.20000E+02 1.19000E+02 1.18000E+02 1.17000E+02 + 8.80000E+01 8.70000E+01 8.60000E+01 8.50000E+01 5.60000E+01 5.50000E+01 + 5.40000E+01 5.30000E+01 2.40000E+01 2.30000E+01 2.20000E+01 2.10000E+01 + 1.80000E+02 1.79000E+02 1.78000E+02 1.77000E+02 1.48000E+02 1.47000E+02 + 1.46000E+02 1.45000E+02 1.16000E+02 1.15000E+02 1.14000E+02 1.13000E+02 + 8.40000E+01 8.30000E+01 8.20000E+01 8.10000E+01 5.20000E+01 5.10000E+01 + 5.00000E+01 4.90000E+01 2.00000E+01 1.90000E+01 1.80000E+01 1.70000E+01 + 1.76000E+02 1.75000E+02 1.74000E+02 1.73000E+02 1.44000E+02 1.43000E+02 + 1.42000E+02 1.41000E+02 1.12000E+02 1.11000E+02 1.10000E+02 1.09000E+02 + 8.00000E+01 7.90000E+01 7.80000E+01 7.70000E+01 4.80000E+01 4.70000E+01 + 4.60000E+01 4.50000E+01 1.60000E+01 1.50000E+01 1.40000E+01 1.30000E+01 + 1.72000E+02 1.71000E+02 1.70000E+02 1.69000E+02 1.40000E+02 1.39000E+02 + 1.38000E+02 1.37000E+02 1.08000E+02 1.07000E+02 1.06000E+02 1.05000E+02 + 7.60000E+01 7.50000E+01 7.40000E+01 7.30000E+01 4.40000E+01 4.30000E+01 + 4.20000E+01 4.10000E+01 1.20000E+01 1.10000E+01 1.00000E+01 9.00000E+00 + 1.68000E+02 1.67000E+02 1.66000E+02 1.65000E+02 1.36000E+02 1.35000E+02 + 1.34000E+02 1.33000E+02 1.04000E+02 1.03000E+02 1.02000E+02 1.01000E+02 + 7.20000E+01 7.10000E+01 7.00000E+01 6.90000E+01 4.00000E+01 3.90000E+01 + 3.80000E+01 3.70000E+01 8.00000E+00 7.00000E+00 6.00000E+00 5.00000E+00 + 1.64000E+02 1.63000E+02 1.62000E+02 1.61000E+02 1.32000E+02 1.31000E+02 + 1.30000E+02 1.29000E+02 1.00000E+02 9.90000E+01 9.80000E+01 9.70000E+01 + 6.80000E+01 6.70000E+01 6.60000E+01 6.50000E+01 3.60000E+01 3.50000E+01 + 3.40000E+01 3.30000E+01 4.00000E+00 3.00000E+00 2.00000E+00 1.00000E+00 diff --git a/tests/unit_tests/weightwindows/wwinp_t b/tests/unit_tests/weightwindows/wwinp_t index a12668aa4..f1aa26d6d 100644 --- a/tests/unit_tests/weightwindows/wwinp_t +++ b/tests/unit_tests/weightwindows/wwinp_t @@ -15,35 +15,35 @@ 1.00000E+02 -5.00000E+01 1.00000E+00 5.00000E+01 1.00000E+00 1.00000E-01 1.46780E-01 2.15440E-01 3.16230E-01 - 1.92000E+02 1.60000E+02 1.28000E+02 9.60000E+01 6.40000E+01 3.20000E+01 - 1.88000E+02 1.56000E+02 1.24000E+02 9.20000E+01 6.00000E+01 2.80000E+01 - 1.84000E+02 1.52000E+02 1.20000E+02 8.80000E+01 5.60000E+01 2.40000E+01 - 1.80000E+02 1.48000E+02 1.16000E+02 8.40000E+01 5.20000E+01 2.00000E+01 - 1.76000E+02 1.44000E+02 1.12000E+02 8.00000E+01 4.80000E+01 1.60000E+01 - 1.72000E+02 1.40000E+02 1.08000E+02 7.60000E+01 4.40000E+01 1.20000E+01 - 1.68000E+02 1.36000E+02 1.04000E+02 7.20000E+01 4.00000E+01 8.00000E+00 - 1.64000E+02 1.32000E+02 1.00000E+02 6.80000E+01 3.60000E+01 4.00000E+00 - 1.91000E+02 1.59000E+02 1.27000E+02 9.50000E+01 6.30000E+01 3.10000E+01 - 1.87000E+02 1.55000E+02 1.23000E+02 9.10000E+01 5.90000E+01 2.70000E+01 - 1.83000E+02 1.51000E+02 1.19000E+02 8.70000E+01 5.50000E+01 2.30000E+01 - 1.79000E+02 1.47000E+02 1.15000E+02 8.30000E+01 5.10000E+01 1.90000E+01 - 1.75000E+02 1.43000E+02 1.11000E+02 7.90000E+01 4.70000E+01 1.50000E+01 - 1.71000E+02 1.39000E+02 1.07000E+02 7.50000E+01 4.30000E+01 1.10000E+01 - 1.67000E+02 1.35000E+02 1.03000E+02 7.10000E+01 3.90000E+01 7.00000E+00 - 1.63000E+02 1.31000E+02 9.90000E+01 6.70000E+01 3.50000E+01 3.00000E+00 - 1.90000E+02 1.58000E+02 1.26000E+02 9.40000E+01 6.20000E+01 3.00000E+01 - 1.86000E+02 1.54000E+02 1.22000E+02 9.00000E+01 5.80000E+01 2.60000E+01 - 1.82000E+02 1.50000E+02 1.18000E+02 8.60000E+01 5.40000E+01 2.20000E+01 - 1.78000E+02 1.46000E+02 1.14000E+02 8.20000E+01 5.00000E+01 1.80000E+01 - 1.74000E+02 1.42000E+02 1.10000E+02 7.80000E+01 4.60000E+01 1.40000E+01 - 1.70000E+02 1.38000E+02 1.06000E+02 7.40000E+01 4.20000E+01 1.00000E+01 - 1.66000E+02 1.34000E+02 1.02000E+02 7.00000E+01 3.80000E+01 6.00000E+00 - 1.62000E+02 1.30000E+02 9.80000E+01 6.60000E+01 3.40000E+01 2.00000E+00 - 1.89000E+02 1.57000E+02 1.25000E+02 9.30000E+01 6.10000E+01 2.90000E+01 - 1.85000E+02 1.53000E+02 1.21000E+02 8.90000E+01 5.70000E+01 2.50000E+01 - 1.81000E+02 1.49000E+02 1.17000E+02 8.50000E+01 5.30000E+01 2.10000E+01 - 1.77000E+02 1.45000E+02 1.13000E+02 8.10000E+01 4.90000E+01 1.70000E+01 - 1.73000E+02 1.41000E+02 1.09000E+02 7.70000E+01 4.50000E+01 1.30000E+01 - 1.69000E+02 1.37000E+02 1.05000E+02 7.30000E+01 4.10000E+01 9.00000E+00 - 1.65000E+02 1.33000E+02 1.01000E+02 6.90000E+01 3.70000E+01 5.00000E+00 - 1.61000E+02 1.29000E+02 9.70000E+01 6.50000E+01 3.30000E+01 1.00000E+00 + 1.92000E+02 1.91000E+02 1.90000E+02 1.89000E+02 1.60000E+02 1.59000E+02 + 1.58000E+02 1.57000E+02 1.28000E+02 1.27000E+02 1.26000E+02 1.25000E+02 + 9.60000E+01 9.50000E+01 9.40000E+01 9.30000E+01 6.40000E+01 6.30000E+01 + 6.20000E+01 6.10000E+01 3.20000E+01 3.10000E+01 3.00000E+01 2.90000E+01 + 1.88000E+02 1.87000E+02 1.86000E+02 1.85000E+02 1.56000E+02 1.55000E+02 + 1.54000E+02 1.53000E+02 1.24000E+02 1.23000E+02 1.22000E+02 1.21000E+02 + 9.20000E+01 9.10000E+01 9.00000E+01 8.90000E+01 6.00000E+01 5.90000E+01 + 5.80000E+01 5.70000E+01 2.80000E+01 2.70000E+01 2.60000E+01 2.50000E+01 + 1.84000E+02 1.83000E+02 1.82000E+02 1.81000E+02 1.52000E+02 1.51000E+02 + 1.50000E+02 1.49000E+02 1.20000E+02 1.19000E+02 1.18000E+02 1.17000E+02 + 8.80000E+01 8.70000E+01 8.60000E+01 8.50000E+01 5.60000E+01 5.50000E+01 + 5.40000E+01 5.30000E+01 2.40000E+01 2.30000E+01 2.20000E+01 2.10000E+01 + 1.80000E+02 1.79000E+02 1.78000E+02 1.77000E+02 1.48000E+02 1.47000E+02 + 1.46000E+02 1.45000E+02 1.16000E+02 1.15000E+02 1.14000E+02 1.13000E+02 + 8.40000E+01 8.30000E+01 8.20000E+01 8.10000E+01 5.20000E+01 5.10000E+01 + 5.00000E+01 4.90000E+01 2.00000E+01 1.90000E+01 1.80000E+01 1.70000E+01 + 1.76000E+02 1.75000E+02 1.74000E+02 1.73000E+02 1.44000E+02 1.43000E+02 + 1.42000E+02 1.41000E+02 1.12000E+02 1.11000E+02 1.10000E+02 1.09000E+02 + 8.00000E+01 7.90000E+01 7.80000E+01 7.70000E+01 4.80000E+01 4.70000E+01 + 4.60000E+01 4.50000E+01 1.60000E+01 1.50000E+01 1.40000E+01 1.30000E+01 + 1.72000E+02 1.71000E+02 1.70000E+02 1.69000E+02 1.40000E+02 1.39000E+02 + 1.38000E+02 1.37000E+02 1.08000E+02 1.07000E+02 1.06000E+02 1.05000E+02 + 7.60000E+01 7.50000E+01 7.40000E+01 7.30000E+01 4.40000E+01 4.30000E+01 + 4.20000E+01 4.10000E+01 1.20000E+01 1.10000E+01 1.00000E+01 9.00000E+00 + 1.68000E+02 1.67000E+02 1.66000E+02 1.65000E+02 1.36000E+02 1.35000E+02 + 1.34000E+02 1.33000E+02 1.04000E+02 1.03000E+02 1.02000E+02 1.01000E+02 + 7.20000E+01 7.10000E+01 7.00000E+01 6.90000E+01 4.00000E+01 3.90000E+01 + 3.80000E+01 3.70000E+01 8.00000E+00 7.00000E+00 6.00000E+00 5.00000E+00 + 1.64000E+02 1.63000E+02 1.62000E+02 1.61000E+02 1.32000E+02 1.31000E+02 + 1.30000E+02 1.29000E+02 1.00000E+02 9.90000E+01 9.80000E+01 9.70000E+01 + 6.80000E+01 6.70000E+01 6.60000E+01 6.50000E+01 3.60000E+01 3.50000E+01 + 3.40000E+01 3.30000E+01 4.00000E+00 3.00000E+00 2.00000E+00 1.00000E+00 diff --git a/tools/ci/gha-install-dagmc.sh b/tools/ci/gha-install-dagmc.sh index 8d0648a50..82759c9bc 100755 --- a/tools/ci/gha-install-dagmc.sh +++ b/tools/ci/gha-install-dagmc.sh @@ -3,7 +3,7 @@ set -ex # MOAB Variables -MOAB_BRANCH='5.5.1' +MOAB_BRANCH='Version5.1.0' MOAB_REPO='https://bitbucket.org/fathomteam/moab/' MOAB_INSTALL_DIR=$HOME/MOAB/ @@ -19,7 +19,7 @@ cd $HOME mkdir MOAB && cd MOAB git clone -b $MOAB_BRANCH $MOAB_REPO mkdir build && cd build -cmake ../moab -DENABLE_HDF5=ON -DENABLE_NETCDF=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=$MOAB_INSTALL_DIR +cmake ../moab -DENABLE_HDF5=ON -DENABLE_NETCDF=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=$MOAB_INSTALL_DIR -DENABLE_BLASLAPACK=OFF make -j && make -j install rm -rf $HOME/MOAB/moab $HOME/MOAB/build diff --git a/tools/ci/gha-install-libmesh.sh b/tools/ci/gha-install-libmesh.sh index d4557d2d3..132963820 100755 --- a/tools/ci/gha-install-libmesh.sh +++ b/tools/ci/gha-install-libmesh.sh @@ -5,7 +5,7 @@ set -ex # libMESH install pushd $HOME mkdir LIBMESH && cd LIBMESH -git clone https://github.com/libmesh/libmesh -b v1.7.1 --recurse-submodules +git clone https://github.com/libmesh/libmesh -b v1.6.0 --recurse-submodules mkdir build && cd build export METHODS="opt" @@ -16,6 +16,7 @@ else ../libmesh/configure --prefix=$HOME/LIBMESH --enable-exodus --disable-netcdf-4 --disable-eigen --disable-lapack --disable-mpi fi make -j4 install +export LIBMESH_PC=$HOME/LIBMESH/lib/pkgconfig/ rm -rf $HOME/LIBMESH/build popd diff --git a/tools/ci/gha-install-njoy.sh b/tools/ci/gha-install-njoy.sh index 168fcd4a7..8255ffea8 100755 --- a/tools/ci/gha-install-njoy.sh +++ b/tools/ci/gha-install-njoy.sh @@ -1,7 +1,7 @@ #!/bin/bash set -ex cd $HOME -git clone -b 2016.78 https://github.com/njoy/NJOY2016 +git clone https://github.com/njoy/NJOY2016 cd NJOY2016 mkdir build && cd build cmake -Dstatic=on .. && make 2>/dev/null && sudo make install diff --git a/tools/ci/gha-install-vectfit.sh b/tools/ci/gha-install-vectfit.sh new file mode 100755 index 000000000..5884c6fac --- /dev/null +++ b/tools/ci/gha-install-vectfit.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -ex + +PYBIND_BRANCH='master' +PYBIND_REPO='https://github.com/pybind/pybind11' + +XTL_BRANCH='0.6.13' +XTL_REPO='https://github.com/xtensor-stack/xtl' + +XTENSOR_BRANCH='0.21.3' +XTENSOR_REPO='https://github.com/xtensor-stack/xtensor' + +XTENSOR_PYTHON_BRANCH='0.24.1' +XTENSOR_PYTHON_REPO='https://github.com/xtensor-stack/xtensor-python' + +XTENSOR_BLAS_BRANCH='0.17.1' +XTENSOR_BLAS_REPO='https://github.com/xtensor-stack/xtensor-blas' + +sudo apt-get install -y libblas-dev liblapack-dev + +cd $HOME +git clone -b $PYBIND_BRANCH $PYBIND_REPO +cd pybind11 && mkdir build && cd build && cmake .. && sudo make install +pip install $HOME/pybind11 + +cd $HOME +git clone -b $XTL_BRANCH $XTL_REPO +cd xtl && mkdir build && cd build && cmake .. && sudo make install + +cd $HOME +git clone -b $XTENSOR_BRANCH $XTENSOR_REPO +cd xtensor && mkdir build && cd build && cmake .. && sudo make install + +cd $HOME +git clone -b $XTENSOR_PYTHON_BRANCH $XTENSOR_PYTHON_REPO +cd xtensor-python && mkdir build && cd build && cmake .. && sudo make install + +cd $HOME +git clone -b $XTENSOR_BLAS_BRANCH $XTENSOR_BLAS_REPO +cd xtensor-blas && mkdir build && cd build && cmake .. && sudo make install + +# Install vectfit +cd $HOME +git clone https://github.com/liangjg/vectfit.git +pip install ./vectfit diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 5488b9547..4c69ba70b 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -2,6 +2,22 @@ import os import shutil import subprocess +def which(program): + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + return None + def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): # Create build directory and change to it @@ -9,8 +25,8 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): os.mkdir('build') os.chdir('build') - # Build in RelWithDebInfo mode by default with support for MCPL - cmake_cmd = ['cmake', '-DCMAKE_BUILD_TYPE=RelWithDebInfo', '-DOPENMC_USE_MCPL=on'] + # Build in debug mode by default + cmake_cmd = ['cmake', '-DCMAKE_BUILD_TYPE=Debug'] # Turn off OpenMP if specified if not omp: @@ -31,9 +47,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): if dagmc: cmake_cmd.append('-DOPENMC_USE_DAGMC=ON') - cmake_cmd.append('-DOPENMC_USE_UWUW=ON') - dagmc_path = os.environ.get('HOME') + '/DAGMC' - cmake_cmd.append('-DCMAKE_PREFIX_PATH=' + dagmc_path) + cmake_cmd.append('-DCMAKE_PREFIX_PATH=~/DAGMC') if libmesh: cmake_cmd.append('-DOPENMC_USE_LIBMESH=ON') @@ -43,9 +57,6 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): # Build in coverage mode for coverage testing cmake_cmd.append('-DOPENMC_ENABLE_COVERAGE=on') - # Enable strict FP for cross-platform reproducibility in CI - cmake_cmd.append('-DOPENMC_ENABLE_STRICT_FP=on') - # Build and install cmake_cmd.append('..') print(' '.join(cmake_cmd)) diff --git a/tools/ci/gha-install.sh b/tools/ci/gha-install.sh index 4cf62afbb..aa40eb90b 100755 --- a/tools/ci/gha-install.sh +++ b/tools/ci/gha-install.sh @@ -2,9 +2,12 @@ set -ex # Upgrade pip, pytest, numpy before doing anything else. +# TODO: numpy 1.22 results in several failing tests, so we force a lower version +# for now (similar change made in pyproject.toml). When this is removed, those +# tests will need to be updated. pip install --upgrade pip pip install --upgrade pytest -pip install --upgrade numpy +pip install --upgrade "numpy<1.22" # Install NJOY 2016 ./tools/ci/gha-install-njoy.sh @@ -14,18 +17,16 @@ if [[ $DAGMC = 'y' ]]; then ./tools/ci/gha-install-dagmc.sh fi -# Install NCrystal and verify installation -pip install 'ncrystal>=4.1.0' -nctool --test +# Install vectfit for WMP generation if needed +if [[ $VECTFIT = 'y' ]]; then + ./tools/ci/gha-install-vectfit.sh +fi # Install libMesh if needed if [[ $LIBMESH = 'y' ]]; then ./tools/ci/gha-install-libmesh.sh fi -# Install MCPL -pip install mcpl - # For MPI configurations, make sure mpi4py and h5py are built against the # correct version of MPI if [[ $MPI == 'y' ]]; then @@ -34,13 +35,17 @@ if [[ $MPI == 'y' ]]; then export CC=mpicc export HDF5_MPI=ON export HDF5_DIR=/usr/lib/x86_64-linux-gnu/hdf5/mpich - # Install h5py without build isolation to pick up already installed mpi4py - pip install setuptools Cython pkgconfig - pip install --no-build-isolation --no-binary=h5py h5py + pip install --no-binary=h5py h5py fi # Build and install OpenMC executable python tools/ci/gha-install.py # Install Python API in editable mode -pip install -e .[test,vtk,ci] +pip install -e .[test,vtk] + +# For coverage testing of the C++ source files +pip install cpp-coveralls + +# For coverage testing of the Python source files +pip install coveralls diff --git a/tools/ci/gha-script.sh b/tools/ci/gha-script.sh index b40238ffb..c791167e9 100755 --- a/tools/ci/gha-script.sh +++ b/tools/ci/gha-script.sh @@ -8,14 +8,11 @@ args=" " if [[ $MPI == 'y' ]]; then args="${args} --mpi " fi - + # Check for event-based if [[ $EVENT == 'y' ]]; then args="${args} --event " fi -# Run unit tests and then regression tests -pytest -v $args \ - tests/test_matplotlib_import.py \ - tests/unit_tests \ - tests/regression_tests +# Run regression and unit tests +pytest --cov=openmc -v $args tests diff --git a/tools/dev/generate_release_notes.py b/tools/dev/generate_release_notes.py deleted file mode 100644 index dee46ac49..000000000 --- a/tools/dev/generate_release_notes.py +++ /dev/null @@ -1,17 +0,0 @@ -import argparse -import re -import subprocess - -parser = argparse.ArgumentParser() -parser.add_argument('tag') -args = parser.parse_args() - -proc = subprocess.run(["git", "log", "--format=%s", f"{args.tag}.."], capture_output=True, text=True) -data = [] -for line in proc.stdout.rstrip().split('\n'): - m = re.match(r'(.*) \(\#(\d+)\)', line) - if m is not None: - data.append(m.groups()) - -for comment, num in sorted(data, key=lambda x: int(x[1])): - print(f'- {comment} (`#{num} `_)') diff --git a/vendor/Catch2 b/vendor/Catch2 deleted file mode 160000 index 5a40b2275..000000000 --- a/vendor/Catch2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5a40b2275caa05cf809bf04df848764a9d7df2e2 diff --git a/vendor/fmt b/vendor/fmt index 0c9fce2ff..d141cdbeb 160000 --- a/vendor/fmt +++ b/vendor/fmt @@ -1 +1 @@ -Subproject commit 0c9fce2ffefecfdce794e1859584e25877b7b592 +Subproject commit d141cdbeb0fb422a3fb7173b285fd38e0d1772dc diff --git a/vendor/gsl-lite b/vendor/gsl-lite new file mode 160000 index 000000000..913e86d49 --- /dev/null +++ b/vendor/gsl-lite @@ -0,0 +1 @@ +Subproject commit 913e86d49c6a1acca980f4e325378f9dc393493a diff --git a/vendor/pugixml b/vendor/pugixml index ee86beb30..41b6ff21c 160000 --- a/vendor/pugixml +++ b/vendor/pugixml @@ -1 +1 @@ -Subproject commit ee86beb30e4973f5feffe3ce63bfa4fbadf72f38 +Subproject commit 41b6ff21c455865bb8ef67c5952b7f895b62bacc diff --git a/vendor/xtensor b/vendor/xtensor new file mode 160000 index 000000000..31acec1e9 --- /dev/null +++ b/vendor/xtensor @@ -0,0 +1 @@ +Subproject commit 31acec1e90bbea6d4bc17af0710a123bd5da6689 diff --git a/vendor/xtl b/vendor/xtl new file mode 160000 index 000000000..c19750fb1 --- /dev/null +++ b/vendor/xtl @@ -0,0 +1 @@ +Subproject commit c19750fb1488369dc41f6069bc2b8446fc093e75