Skip to main content

outram_foam_basic_lib/fv_options/
selection.rs

1// SPDX-License-Identifier: GPL-3.0-only
2// Copyright (C) 2026 OUTRAM PARK contributors
3// Derived from OpenFOAM (www.openfoam.com)
4// Copyright (C) 2004-2023 OpenFOAM Foundation
5// Copyright (C) 2016-2023 OpenCFD Ltd.
6//
7// This file is part of OUTRAM PARK. See `src/lib.rs` for the full licence
8// notice.
9
10// Upstream source: src/finiteVolume/cfdTools/general/fvCellZone/ and the
11// `cellSetOption` base of src/fvModels/.
12
13//! Which cells a source term applies over.
14
15use std::sync::Arc;
16
17/// The set of cells a source term acts on.
18///
19/// Upstream's `fvCellZone` / `cellSetOption`. A source is almost never global:
20/// a heat source occupies one component, a porous drag one region, a melting
21/// model one material. This is how that restriction is expressed.
22///
23/// # Sharing
24///
25/// The cell list is held behind an `Arc`, per the workspace rule against
26/// lifetime parameters, so several models can share one selection without
27/// copying it.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum CellSelection {
30    /// Every cell in the mesh.
31    All,
32    /// An explicit list of cell indices.
33    ///
34    /// Indices are not validated against a mesh here, because a selection is
35    /// built before it meets one. An out-of-range index will panic on use,
36    /// which is the correct outcome for what is a case-setup error.
37    Zone(Arc<Vec<usize>>),
38}
39
40impl CellSelection {
41    /// A selection from an explicit list of cell indices.
42    #[must_use]
43    pub fn zone(cells: Vec<usize>) -> Self {
44        Self::Zone(Arc::new(cells))
45    }
46
47    /// The selected cells, given a mesh cell count.
48    ///
49    /// `n_cells` is used only to expand [`CellSelection::All`].
50    #[must_use]
51    pub fn cells(&self, n_cells: usize) -> Vec<usize> {
52        match self {
53            Self::All => (0..n_cells).collect(),
54            Self::Zone(c) => c.as_ref().clone(),
55        }
56    }
57
58    /// Number of selected cells, given a mesh cell count.
59    #[must_use]
60    pub fn len(&self, n_cells: usize) -> usize {
61        match self {
62            Self::All => n_cells,
63            Self::Zone(c) => c.len(),
64        }
65    }
66
67    /// Whether the selection is empty.
68    ///
69    /// An empty selection is legal — it contributes nothing — but is usually a
70    /// case-setup mistake worth reporting.
71    #[must_use]
72    pub fn is_empty(&self, n_cells: usize) -> bool {
73        self.len(n_cells) == 0
74    }
75}